diff --git a/Blockchain/Sources/Blockchain/Config/ProtocolConfig.swift b/Blockchain/Sources/Blockchain/Config/ProtocolConfig.swift index 193f0cdf..988cbe63 100644 --- a/Blockchain/Sources/Blockchain/Config/ProtocolConfig.swift +++ b/Blockchain/Sources/Blockchain/Config/ProtocolConfig.swift @@ -64,7 +64,7 @@ public struct ProtocolConfig: Sendable, Codable, Equatable { // P = 6: The slot period, in seconds. public var slotPeriodSeconds: Int - // Q = 80: The maximum number of items in the authorizations queue. + // Q = 80: The number of items in the authorizations queue. public var maxAuthorizationsQueueItems: Int // R = 10: The rotation period of validator-core assignments, in timeslots. @@ -107,7 +107,7 @@ public struct ProtocolConfig: Sendable, Codable, Equatable { // ZI = 2^24: The standard pvm program initialization input data size. public var pvmProgramInitInputDataSize: Int - // ZP = 2^14: The standard pvm program initialization page size. + // ZG = 2^14: The standard pvm program initialization page size. public var pvmProgramInitPageSize: Int // ZQ = 2^16: The standard pvm program initialization segment size. diff --git a/Blockchain/Sources/Blockchain/RuntimeProtocols/Accumulation.swift b/Blockchain/Sources/Blockchain/RuntimeProtocols/Accumulation.swift index d5190e81..6cf55f9b 100644 --- a/Blockchain/Sources/Blockchain/RuntimeProtocols/Accumulation.swift +++ b/Blockchain/Sources/Blockchain/RuntimeProtocols/Accumulation.swift @@ -186,7 +186,7 @@ extension Accumulation { } switch service { - case privilegedServices.empower: + case privilegedServices.blessed: newPrivilegedServices = singleOutput.state.privilegedServices case privilegedServices.assign: newAuthorizationQueue = singleOutput.state.authorizationQueue diff --git a/Blockchain/Sources/Blockchain/RuntimeProtocols/Runtime.swift b/Blockchain/Sources/Blockchain/RuntimeProtocols/Runtime.swift index eb50be6f..f08814ed 100644 --- a/Blockchain/Sources/Blockchain/RuntimeProtocols/Runtime.swift +++ b/Blockchain/Sources/Blockchain/RuntimeProtocols/Runtime.swift @@ -60,10 +60,7 @@ public final class Runtime { throw Error.invalidHeaderStateRoot } - let expectedExtrinsicHash = try Result { try JamEncoder.encode(block.extrinsic).blake2b256hash() } - .mapError(Error.encodeError).get() - - guard block.header.extrinsicsHash == expectedExtrinsicHash else { + guard block.header.extrinsicsHash == block.extrinsic.hash() else { throw Error.invalidExtrinsicHash } @@ -297,7 +294,7 @@ public final class Runtime { } public func updateDisputes(block: BlockRef, state newState: inout State) throws { - let (posState, offenders) = try newState.update(config: config, disputes: block.extrinsic.judgements) + let (posState, offenders) = try newState.update(config: config, disputes: block.extrinsic.disputes) newState.mergeWith(postState: posState) guard offenders == block.header.offendersMarkers else { @@ -379,7 +376,7 @@ public final class Runtime { return availableReports } - public func updatePreimages(block: BlockRef, state newState: inout State) async throws { + public func updatePreimages(block: BlockRef, state newState: inout State, prevState: StateRef) async throws { let preimages = block.extrinsic.preimages.preimages guard preimages.isSortedAndUnique() else { @@ -388,14 +385,26 @@ public final class Runtime { for preimage in preimages { let hash = preimage.data.blake2b256hash() + + // check prior state + let prevPreimageData: Data? = try await prevState.value.get(serviceAccount: preimage.serviceIndex, preimageHash: hash) + let prevInfo = try await prevState.value.get( + serviceAccount: preimage.serviceIndex, preimageHash: hash, length: UInt32(preimage.data.count) + ) + guard prevPreimageData == nil, prevInfo == nil else { + throw Error.duplicatedPreimage + } + + // disregard no longer useful ones in new state let preimageData: Data? = try await newState.get(serviceAccount: preimage.serviceIndex, preimageHash: hash) let info = try await newState.get( serviceAccount: preimage.serviceIndex, preimageHash: hash, length: UInt32(preimage.data.count) ) - guard preimageData == nil, info == nil else { - throw Error.duplicatedPreimage + if preimageData != nil || info != nil { + continue } + // update state newState[serviceAccount: preimage.serviceIndex, preimageHash: hash] = preimage.data newState[ serviceAccount: preimage.serviceIndex, preimageHash: hash, length: UInt32(preimage.data.count) diff --git a/Blockchain/Sources/Blockchain/State/State.swift b/Blockchain/Sources/Blockchain/State/State.swift index 6295ae5e..e1284322 100644 --- a/Blockchain/Sources/Blockchain/State/State.swift +++ b/Blockchain/Sources/Blockchain/State/State.swift @@ -274,7 +274,7 @@ extension State: Dummy { let authorizationQueue: StateKeys.AuthorizationQueueKey.Value = try! ConfigFixedSizeArray(config: config, defaultValue: ConfigFixedSizeArray(config: config, defaultValue: Data32())) let privilegedServices: StateKeys.PrivilegedServicesKey.Value = PrivilegedServices( - empower: ServiceIndex(), + blessed: ServiceIndex(), assign: ServiceIndex(), designate: ServiceIndex(), basicGas: [:] diff --git a/Blockchain/Sources/Blockchain/State/StateKeys.swift b/Blockchain/Sources/Blockchain/State/StateKeys.swift index df80ebbe..743f3759 100644 --- a/Blockchain/Sources/Blockchain/State/StateKeys.swift +++ b/Blockchain/Sources/Blockchain/State/StateKeys.swift @@ -33,23 +33,23 @@ private func constructKey(_ idx: UInt8, _ service: ServiceIndex) -> Data32 { return Data32(data)! } -private func constructKey(_ service: ServiceIndex, _ val: UInt32, _: Data) -> Data32 { - var data = Data(capacity: 32) +private func constructKey(_ service: ServiceIndex, _ val: UInt32, _ data: Data) -> Data32 { + var stateKey = Data(capacity: 32) withUnsafeBytes(of: service) { servicePtr in withUnsafeBytes(of: val) { valPtr in - data.append(servicePtr.load(as: UInt8.self)) - data.append(valPtr.load(as: UInt8.self)) - data.append(servicePtr.load(fromByteOffset: 1, as: UInt8.self)) - data.append(valPtr.load(fromByteOffset: 1, as: UInt8.self)) - data.append(servicePtr.load(fromByteOffset: 2, as: UInt8.self)) - data.append(valPtr.load(fromByteOffset: 2, as: UInt8.self)) - data.append(servicePtr.load(fromByteOffset: 3, as: UInt8.self)) - data.append(valPtr.load(fromByteOffset: 3, as: UInt8.self)) + stateKey.append(servicePtr.load(as: UInt8.self)) + stateKey.append(valPtr.load(as: UInt8.self)) + stateKey.append(servicePtr.load(fromByteOffset: 1, as: UInt8.self)) + stateKey.append(valPtr.load(fromByteOffset: 1, as: UInt8.self)) + stateKey.append(servicePtr.load(fromByteOffset: 2, as: UInt8.self)) + stateKey.append(valPtr.load(fromByteOffset: 2, as: UInt8.self)) + stateKey.append(servicePtr.load(fromByteOffset: 3, as: UInt8.self)) + stateKey.append(valPtr.load(fromByteOffset: 3, as: UInt8.self)) } } - data.append(contentsOf: data[relative: 0 ..< 24]) - return Data32(data)! + stateKey.append(contentsOf: data[relative: 0 ..< 24]) + return Data32(stateKey)! } public enum StateKeys { @@ -316,7 +316,7 @@ public enum StateKeys { } public func encode() -> Data32 { - constructKey(index, length, hash.blake2b256hash().data) + constructKey(index, length, hash.blake2b256hash().data[2...]) } } } diff --git a/Blockchain/Sources/Blockchain/Types/AvailabilitySpecifications.swift b/Blockchain/Sources/Blockchain/Types/AvailabilitySpecifications.swift index 0013f9c8..14e6af0d 100644 --- a/Blockchain/Sources/Blockchain/Types/AvailabilitySpecifications.swift +++ b/Blockchain/Sources/Blockchain/Types/AvailabilitySpecifications.swift @@ -14,16 +14,21 @@ public struct AvailabilitySpecifications: Sendable, Equatable, Codable { // e public var segmentRoot: Data32 + // n + public var segmentCount: UInt16 + public init( workPackageHash: Data32, length: DataLength, erasureRoot: Data32, - segmentRoot: Data32 + segmentRoot: Data32, + segmentCount: UInt16 ) { self.workPackageHash = workPackageHash self.length = length self.erasureRoot = erasureRoot self.segmentRoot = segmentRoot + self.segmentCount = segmentCount } } @@ -34,14 +39,15 @@ extension AvailabilitySpecifications: Dummy { workPackageHash: Data32(), length: 0, erasureRoot: Data32(), - segmentRoot: Data32() + segmentRoot: Data32(), + segmentCount: 0 ) } } extension AvailabilitySpecifications: EncodedSize { public var encodedSize: Int { - workPackageHash.encodedSize + length.encodedSize + erasureRoot.encodedSize + segmentRoot.encodedSize + workPackageHash.encodedSize + length.encodedSize + erasureRoot.encodedSize + segmentRoot.encodedSize + segmentCount.encodedSize } public static var encodeedSizeHint: Int? { diff --git a/Blockchain/Sources/Blockchain/Types/Extrinsic.swift b/Blockchain/Sources/Blockchain/Types/Extrinsic.swift index 62dbabef..21ed6be4 100644 --- a/Blockchain/Sources/Blockchain/Types/Extrinsic.swift +++ b/Blockchain/Sources/Blockchain/Types/Extrinsic.swift @@ -9,28 +9,28 @@ public struct Extrinsic: Sendable, Equatable, Codable { // permissioning of block authoring public var tickets: ExtrinsicTickets - // ED: Votes, by validators, on dispute(s) arising between them presently taking place - public var judgements: ExtrinsicDisputes - // EP: Static data which is presently being requested to be available for workloads to be able to fetch on demand public var preimages: ExtrinsicPreimages + // EG: Reports of newly completed workloads whose accuracy is guaranteed by specific validators + public var reports: ExtrinsicGuarantees + // EA: Assurances by each validator concerning which of the input data of workloads they have // correctly received and are storing locally public var availability: ExtrinsicAvailability - // EG: Reports of newly completed workloads whose accuracy is guaranteed by specific validators - public var reports: ExtrinsicGuarantees + // ED: Votes, by validators, on dispute(s) arising between them presently taking place + public var disputes: ExtrinsicDisputes public init( tickets: ExtrinsicTickets, - judgements: ExtrinsicDisputes, + disputes: ExtrinsicDisputes, preimages: ExtrinsicPreimages, availability: ExtrinsicAvailability, reports: ExtrinsicGuarantees ) { self.tickets = tickets - self.judgements = judgements + self.disputes = disputes self.preimages = preimages self.availability = availability self.reports = reports @@ -42,7 +42,7 @@ extension Extrinsic: Dummy { public static func dummy(config: Config) -> Extrinsic { Extrinsic( tickets: ExtrinsicTickets.dummy(config: config), - judgements: ExtrinsicDisputes.dummy(config: config), + disputes: ExtrinsicDisputes.dummy(config: config), preimages: ExtrinsicPreimages.dummy(config: config), availability: ExtrinsicAvailability.dummy(config: config), reports: ExtrinsicGuarantees.dummy(config: config) @@ -55,7 +55,15 @@ extension Extrinsic: Validate {} extension Extrinsic { public func hash() -> Data32 { do { - return try JamEncoder.encode(self).blake2b256hash() + return try JamEncoder.encode([ + JamEncoder.encode(tickets).blake2b256hash(), + JamEncoder.encode(preimages).blake2b256hash(), + JamEncoder.encode(reports.guarantees.array.map { item in + try JamEncoder.encode(item.workReport.hash()) + JamEncoder.encode(item.timeslot) + JamEncoder.encode(item.credential) + }).blake2b256hash(), + JamEncoder.encode(availability).blake2b256hash(), + JamEncoder.encode(disputes).blake2b256hash(), + ]).blake2b256hash() } catch { logger.error("Failed to encode extrinsic, returning empty hash", metadata: ["error": "\(error)"]) return Data32() diff --git a/Blockchain/Sources/Blockchain/Types/PrivilegedServices.swift b/Blockchain/Sources/Blockchain/Types/PrivilegedServices.swift index 30061f48..a0850284 100644 --- a/Blockchain/Sources/Blockchain/Types/PrivilegedServices.swift +++ b/Blockchain/Sources/Blockchain/Types/PrivilegedServices.swift @@ -3,7 +3,7 @@ import Utils public struct PrivilegedServices: Sendable, Equatable, Codable { // m - public var empower: ServiceIndex + public var blessed: ServiceIndex // a public var assign: ServiceIndex // v @@ -11,8 +11,8 @@ public struct PrivilegedServices: Sendable, Equatable, Codable { // g @CodingAs> public var basicGas: [ServiceIndex: Gas] - public init(empower: ServiceIndex, assign: ServiceIndex, designate: ServiceIndex, basicGas: [ServiceIndex: Gas]) { - self.empower = empower + public init(blessed: ServiceIndex, assign: ServiceIndex, designate: ServiceIndex, basicGas: [ServiceIndex: Gas]) { + self.blessed = blessed self.assign = assign self.designate = designate self.basicGas = basicGas diff --git a/Blockchain/Sources/Blockchain/VMInvocations/HostCall/HostCalls.swift b/Blockchain/Sources/Blockchain/VMInvocations/HostCall/HostCalls.swift index ea414bdd..5ba7e920 100644 --- a/Blockchain/Sources/Blockchain/VMInvocations/HostCall/HostCalls.swift +++ b/Blockchain/Sources/Blockchain/VMInvocations/HostCall/HostCalls.swift @@ -242,7 +242,7 @@ public class Empower: HostCall { if basicGas.count != 0 { state.writeRegister(Registers.Index(raw: 7), HostCallResultCode.OK.rawValue) - x.accumulateState.privilegedServices.empower = regs[0] + x.accumulateState.privilegedServices.blessed = regs[0] x.accumulateState.privilegedServices.assign = regs[1] x.accumulateState.privilegedServices.designate = regs[2] x.accumulateState.privilegedServices.basicGas = basicGas diff --git a/Blockchain/Sources/Blockchain/VMInvocations/Invocations/AccumulateInvocation.swift b/Blockchain/Sources/Blockchain/VMInvocations/Invocations/AccumulateInvocation.swift index d65f7596..f129f0aa 100644 --- a/Blockchain/Sources/Blockchain/VMInvocations/Invocations/AccumulateInvocation.swift +++ b/Blockchain/Sources/Blockchain/VMInvocations/Invocations/AccumulateInvocation.swift @@ -40,7 +40,7 @@ extension AccumulateFunction { let (exitReason, gas, output) = await invokePVM( config: config, blob: accumulatingAccountDetails.codeHash.data, - pc: 10, + pc: 5, gas: gas, argumentData: argument, ctx: ctx diff --git a/Blockchain/Sources/Blockchain/VMInvocations/Invocations/OnTransferInvocation.swift b/Blockchain/Sources/Blockchain/VMInvocations/Invocations/OnTransferInvocation.swift index 6271b5e2..fedc57e4 100644 --- a/Blockchain/Sources/Blockchain/VMInvocations/Invocations/OnTransferInvocation.swift +++ b/Blockchain/Sources/Blockchain/VMInvocations/Invocations/OnTransferInvocation.swift @@ -28,7 +28,7 @@ extension OnTransferFunction { _ = await invokePVM( config: config, blob: account.codeHash.data, - pc: 15, + pc: 10, gas: gasLimitSum, argumentData: argument, ctx: ctx diff --git a/Blockchain/Sources/Blockchain/Validator/BlockAuthor.swift b/Blockchain/Sources/Blockchain/Validator/BlockAuthor.swift index 785a027f..a55f72e8 100644 --- a/Blockchain/Sources/Blockchain/Validator/BlockAuthor.swift +++ b/Blockchain/Sources/Blockchain/Validator/BlockAuthor.swift @@ -75,7 +75,7 @@ public final class BlockAuthor: ServiceBase2, @unchecked Sendable { let extrinsic = try Extrinsic( tickets: ExtrinsicTickets(tickets: ConfigLimitedSizeArray(config: config, array: Array(tickets))), - judgements: ExtrinsicDisputes.dummy(config: config), // TODO: + disputes: ExtrinsicDisputes.dummy(config: config), // TODO: preimages: ExtrinsicPreimages.dummy(config: config), // TODO: availability: ExtrinsicAvailability.dummy(config: config), // TODO: reports: ExtrinsicGuarantees.dummy(config: config) // TODO: diff --git a/Blockchain/Tests/BlockchainTests/ExtrinsicPoolServiceTests.swift b/Blockchain/Tests/BlockchainTests/ExtrinsicPoolServiceTests.swift index 9c993ea0..e9a17aa4 100644 --- a/Blockchain/Tests/BlockchainTests/ExtrinsicPoolServiceTests.swift +++ b/Blockchain/Tests/BlockchainTests/ExtrinsicPoolServiceTests.swift @@ -144,7 +144,7 @@ struct ExtrinsicPoolServiceTests { let blockTickets = Array(tickets[0 ..< 2]) let extrinsic = try Extrinsic( tickets: ExtrinsicTickets(tickets: ConfigLimitedSizeArray(config: config, array: blockTickets.map(\.ticket))), - judgements: ExtrinsicDisputes.dummy(config: config), + disputes: ExtrinsicDisputes.dummy(config: config), preimages: ExtrinsicPreimages.dummy(config: config), availability: ExtrinsicAvailability.dummy(config: config), reports: ExtrinsicGuarantees.dummy(config: config) diff --git a/JAMTests/Tests/JAMTests/CodecTests.swift b/JAMTests/Tests/JAMTests/CodecTests.swift index adf9b875..0938afa4 100644 --- a/JAMTests/Tests/JAMTests/CodecTests.swift +++ b/JAMTests/Tests/JAMTests/CodecTests.swift @@ -102,11 +102,11 @@ struct CodecTests { if value is RefinementContext { return [ "anchor": json["anchor"]!["headerHash"]!, + "state_root": json["anchor"]!["stateRoot"]!, "beefy_root": json["anchor"]!["beefyRoot"]!, "lookup_anchor": json["lookupAnchor"]!["headerHash"]!, "lookup_anchor_slot": json["lookupAnchor"]!["timeslot"]!, - "prerequisite": json["prerequisiteWorkPackages"] ?? .null, - "state_root": json["anchor"]!["stateRoot"]!, + "prerequisites": json["prerequisiteWorkPackages"] ?? .null, ].json } if value is ExtrinsicTickets { @@ -122,7 +122,7 @@ struct CodecTests { "code_hash": json["codeHash"]!, "gas": json["gasRatio"]!, "payload_hash": json["payloadHash"]!, - "service": json["serviceIndex"]!, + "service_id": json["serviceIndex"]!, "result": json["output"]!["success"] == nil ? json["output"]! : [ "ok": json["output"]!["success"]!, ].json, @@ -175,9 +175,10 @@ struct CodecTests { if value is AvailabilitySpecifications { return [ "hash": json["workPackageHash"]!, - "len": json["length"]!, + "length": json["length"]!, "erasure_root": json["erasureRoot"]!, "exports_root": json["segmentRoot"]!, + "exports_count": json["segmentCount"]!, ].json } if let value = value as? ExtrinsicGuarantees { @@ -197,10 +198,10 @@ struct CodecTests { if let value = value as? Extrinsic { return [ "tickets": transform(json["tickets"]!, value: value.tickets), - "disputes": transform(json["judgements"]!, value: value.judgements), "preimages": transform(json["preimages"]!, value: value.preimages), - "assurances": transform(json["availability"]!, value: value.availability), "guarantees": transform(json["reports"]!, value: value.reports), + "assurances": transform(json["availability"]!, value: value.availability), + "disputes": transform(json["disputes"]!, value: value.disputes), ].json } if let value = value as? Header { @@ -242,10 +243,8 @@ struct CodecTests { @Test func block() throws { - withKnownIssue("waiting for refine_context.prerequisite updates", isIntermittent: true) { - let (actual, expected) = try Self.test(Block.self, path: "block") - #expect(actual == expected) - } + let (actual, expected) = try Self.test(Block.self, path: "block") + #expect(actual == expected) } @Test @@ -256,18 +255,14 @@ struct CodecTests { @Test func extrinsic() throws { - withKnownIssue("waiting for refine_context.prerequisite updates", isIntermittent: true) { - let (actual, expected) = try Self.test(Extrinsic.self, path: "extrinsic") - #expect(actual == expected) - } + let (actual, expected) = try Self.test(Extrinsic.self, path: "extrinsic") + #expect(actual == expected) } @Test func guarantees_extrinsic() throws { - withKnownIssue("waiting for refine_context.prerequisite updates", isIntermittent: true) { - let (actual, expected) = try Self.test(ExtrinsicGuarantees.self, path: "guarantees_extrinsic") - #expect(actual == expected) - } + let (actual, expected) = try Self.test(ExtrinsicGuarantees.self, path: "guarantees_extrinsic") + #expect(actual == expected) } @Test @@ -290,10 +285,8 @@ struct CodecTests { @Test func refine_context() throws { - withKnownIssue("waiting for refine_context.prerequisite updates", isIntermittent: true) { - let (actual, expected) = try Self.test(RefinementContext.self, path: "refine_context") - #expect(actual == expected) - } + let (actual, expected) = try Self.test(RefinementContext.self, path: "refine_context") + #expect(actual == expected) } @Test @@ -310,18 +303,14 @@ struct CodecTests { @Test func work_package() throws { - withKnownIssue("waiting for refine_context.prerequisite updates", isIntermittent: true) { - let (actual, expected) = try Self.test(WorkPackage.self, path: "work_package") - #expect(actual == expected) - } + let (actual, expected) = try Self.test(WorkPackage.self, path: "work_package") + #expect(actual == expected) } @Test func work_report() throws { - withKnownIssue("waiting for refine_context.prerequisite updates", isIntermittent: true) { - let (actual, expected) = try Self.test(WorkReport.self, path: "work_report") - #expect(actual == expected) - } + let (actual, expected) = try Self.test(WorkReport.self, path: "work_report") + #expect(actual == expected) } @Test diff --git a/JAMTests/jamtestvectors b/JAMTests/jamtestvectors index a46c3539..41809243 160000 --- a/JAMTests/jamtestvectors +++ b/JAMTests/jamtestvectors @@ -1 +1 @@ -Subproject commit a46c3539d79188a499fbdde933c50a82ac98a0f1 +Subproject commit 418092431e14b1da52dd8040d12ba246cc351f99