From 13569f4bfc47853e97b73d63aaa2d706584c93bc Mon Sep 17 00:00:00 2001 From: Xiliang Chen Date: Mon, 16 Dec 2024 15:35:06 +1300 Subject: [PATCH 1/2] update work item (#250) * update work item * fix build --- .../Sources/Blockchain/Types/WorkItem.swift | 52 ++++++++++++++++--- JAMTests/Tests/JAMTests/CodecTests.swift | 12 +++-- Utils/Sources/Utils/AnyCodable.swift | 6 +-- 3 files changed, 57 insertions(+), 13 deletions(-) diff --git a/Blockchain/Sources/Blockchain/Types/WorkItem.swift b/Blockchain/Sources/Blockchain/Types/WorkItem.swift index a2383ccd..ce45879d 100644 --- a/Blockchain/Sources/Blockchain/Types/WorkItem.swift +++ b/Blockchain/Sources/Blockchain/Types/WorkItem.swift @@ -4,13 +4,47 @@ import Utils // I public struct WorkItem: Sendable, Equatable, Codable { public struct ImportedDataSegment: Sendable, Equatable, Codable { - public var root: Data32 + public enum DataSegmentRootKind: Sendable, Equatable { + case segmentRoot(Data32) + case workPackageHash(Data32) + } + + public var root: DataSegmentRootKind public var index: UInt16 - public init(root: Data32, index: UInt16) { + public init(root: DataSegmentRootKind, index: UInt16) { self.root = root self.index = index } + + // Encodable + public func encode(to encoder: Encoder) throws { + var container = encoder.unkeyedContainer() + var indexValue = index + switch root { + case let .segmentRoot(root): + try container.encode(root) + case let .workPackageHash(hash): + try container.encode(hash) + indexValue |= 1 << 15 + } + try container.encode(indexValue) + } + + // Decodable + public init(from decoder: Decoder) throws { + var container = try decoder.unkeyedContainer() + let root = try container.decode(Data32.self) + let index = try container.decode(UInt16.self) + let flag = index >> 15 + if flag == 0 { + self.root = .segmentRoot(root) + self.index = index + } else { + self.root = .workPackageHash(root) + self.index = index & 0x7FFF + } + } } // s @@ -23,7 +57,10 @@ public struct WorkItem: Sendable, Equatable, Codable { public var payloadBlob: Data // g - public var gasLimit: Gas + public var refineGasLimit: Gas + + // a + public var accumulateGasLimit: Gas // i: a sequence of imported data segments which identify a prior exported segment through an index public var inputs: [ImportedDataSegment] @@ -38,7 +75,8 @@ public struct WorkItem: Sendable, Equatable, Codable { serviceIndex: ServiceIndex, codeHash: Data32, payloadBlob: Data, - gasLimit: Gas, + refineGasLimit: Gas, + accumulateGasLimit: Gas, inputs: [ImportedDataSegment], outputs: [HashAndLength], outputDataSegmentsCount: UInt16 @@ -46,7 +84,8 @@ public struct WorkItem: Sendable, Equatable, Codable { self.serviceIndex = serviceIndex self.codeHash = codeHash self.payloadBlob = payloadBlob - self.gasLimit = gasLimit + self.refineGasLimit = refineGasLimit + self.accumulateGasLimit = accumulateGasLimit self.inputs = inputs self.outputs = outputs self.outputDataSegmentsCount = outputDataSegmentsCount @@ -60,7 +99,8 @@ extension WorkItem: Dummy { serviceIndex: 0, codeHash: Data32(), payloadBlob: Data(), - gasLimit: Gas(0), + refineGasLimit: Gas(0), + accumulateGasLimit: Gas(0), inputs: [], outputs: [], outputDataSegmentsCount: 0 diff --git a/JAMTests/Tests/JAMTests/CodecTests.swift b/JAMTests/Tests/JAMTests/CodecTests.swift index 0938afa4..d3a1ecc7 100644 --- a/JAMTests/Tests/JAMTests/CodecTests.swift +++ b/JAMTests/Tests/JAMTests/CodecTests.swift @@ -297,14 +297,18 @@ struct CodecTests { @Test func work_item() throws { - let (actual, expected) = try Self.test(WorkItem.self, path: "work_item") - #expect(actual == expected) + withKnownIssue("need bump test vectors") { + let (actual, expected) = try Self.test(WorkItem.self, path: "work_item") + #expect(actual == expected) + } } @Test func work_package() throws { - let (actual, expected) = try Self.test(WorkPackage.self, path: "work_package") - #expect(actual == expected) + withKnownIssue("need bump test vectors") { + let (actual, expected) = try Self.test(WorkPackage.self, path: "work_package") + #expect(actual == expected) + } } @Test diff --git a/Utils/Sources/Utils/AnyCodable.swift b/Utils/Sources/Utils/AnyCodable.swift index b181de5a..4bd53b94 100644 --- a/Utils/Sources/Utils/AnyCodable.swift +++ b/Utils/Sources/Utils/AnyCodable.swift @@ -13,12 +13,12 @@ /// A type-erased codable value. /// /// An `AnyCodable` value forwards encoding and decoding operations to the underlying base. -public struct AnyCodable: Codable, CustomDebugStringConvertible { +public struct AnyCodable: Codable, CustomDebugStringConvertible, Sendable { /// The base encodable value. - public var value: Encodable + public var value: Encodable & Sendable /// Creates a codable value that wraps the given base. - public init(_ encodable: Encodable) { + public init(_ encodable: Encodable & Sendable) { value = encodable } From 25e6b5ab84fd8eeb7ab900b16d896e629c79f985 Mon Sep 17 00:00:00 2001 From: Xiliang Chen Date: Tue, 17 Dec 2024 15:15:56 +1300 Subject: [PATCH 2/2] encoder cleanup (#251) --- .../Sources/Blockchain/Types/Extrinsic.swift | 8 ++++---- .../VMInvocations/HostCall/HostCalls.swift | 2 +- .../Invocations/AccumulateInvocation.swift | 2 +- .../Invocations/IsAuthorizedInvocation.swift | 10 ++++++---- .../Invocations/OnTransferInvocation.swift | 2 +- .../Invocations/RefineInvocation.swift | 16 +++++++++------- Codec/Sources/Codec/JamEncoder.swift | 8 ++++++++ 7 files changed, 30 insertions(+), 18 deletions(-) diff --git a/Blockchain/Sources/Blockchain/Types/Extrinsic.swift b/Blockchain/Sources/Blockchain/Types/Extrinsic.swift index 21ed6be4..5a690b36 100644 --- a/Blockchain/Sources/Blockchain/Types/Extrinsic.swift +++ b/Blockchain/Sources/Blockchain/Types/Extrinsic.swift @@ -55,15 +55,15 @@ extension Extrinsic: Validate {} extension Extrinsic { public func hash() -> Data32 { do { - return try JamEncoder.encode([ + 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) + try JamEncoder.encode(item.workReport.hash(), item.timeslot, item.credential) }).blake2b256hash(), JamEncoder.encode(availability).blake2b256hash(), - JamEncoder.encode(disputes).blake2b256hash(), - ]).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/VMInvocations/HostCall/HostCalls.swift b/Blockchain/Sources/Blockchain/VMInvocations/HostCall/HostCalls.swift index 8d1170c9..d09455a3 100644 --- a/Blockchain/Sources/Blockchain/VMInvocations/HostCall/HostCalls.swift +++ b/Blockchain/Sources/Blockchain/VMInvocations/HostCall/HostCalls.swift @@ -943,7 +943,7 @@ public class Invoke: HostCall { let engine = Engine(config: DefaultPvmConfig()) let exitReason = await engine.execute(program: program, state: vm) - try state.writeMemory(address: startAddr, values: JamEncoder.encode(vm.getGas()) + JamEncoder.encode(vm.getRegisters())) + try state.writeMemory(address: startAddr, values: JamEncoder.encode(vm.getGas(), vm.getRegisters())) context.pvms[pvmIndex]?.memory = vm.getMemoryUnsafe() switch exitReason { diff --git a/Blockchain/Sources/Blockchain/VMInvocations/Invocations/AccumulateInvocation.swift b/Blockchain/Sources/Blockchain/VMInvocations/Invocations/AccumulateInvocation.swift index caba9677..0b35c913 100644 --- a/Blockchain/Sources/Blockchain/VMInvocations/Invocations/AccumulateInvocation.swift +++ b/Blockchain/Sources/Blockchain/VMInvocations/Invocations/AccumulateInvocation.swift @@ -34,7 +34,7 @@ extension AccumulateFunction { y: resultCtx ) let ctx = AccumulateContext(context: &contextContent, config: config, timeslot: timeslot) - let argument = try JamEncoder.encode(timeslot) + JamEncoder.encode(serviceIndex) + JamEncoder.encode(arguments) + let argument = try JamEncoder.encode(timeslot, serviceIndex, arguments) let (exitReason, gas, output) = await invokePVM( config: config, diff --git a/Blockchain/Sources/Blockchain/VMInvocations/Invocations/IsAuthorizedInvocation.swift b/Blockchain/Sources/Blockchain/VMInvocations/Invocations/IsAuthorizedInvocation.swift index cbf1dde7..51bbda0d 100644 --- a/Blockchain/Sources/Blockchain/VMInvocations/Invocations/IsAuthorizedInvocation.swift +++ b/Blockchain/Sources/Blockchain/VMInvocations/Invocations/IsAuthorizedInvocation.swift @@ -11,10 +11,12 @@ public protocol IsAuthorizedFunction { } extension IsAuthorizedFunction { - public func invoke(config: ProtocolConfigRef, package: WorkPackage, - coreIndex: CoreIndex) async throws -> Result - { - let args = try JamEncoder.encode(package) + JamEncoder.encode(coreIndex) + public func invoke( + config: ProtocolConfigRef, + package: WorkPackage, + coreIndex: CoreIndex + ) async throws -> Result { + let args = try JamEncoder.encode(package, coreIndex) let ctx = IsAuthorizedContext(config: config) let (exitReason, _, output) = await invokePVM( diff --git a/Blockchain/Sources/Blockchain/VMInvocations/Invocations/OnTransferInvocation.swift b/Blockchain/Sources/Blockchain/VMInvocations/Invocations/OnTransferInvocation.swift index 64b5004c..451d5226 100644 --- a/Blockchain/Sources/Blockchain/VMInvocations/Invocations/OnTransferInvocation.swift +++ b/Blockchain/Sources/Blockchain/VMInvocations/Invocations/OnTransferInvocation.swift @@ -24,7 +24,7 @@ extension OnTransferFunction { var contextContent = OnTransferContext.ContextType(service, serviceAccounts) let ctx = OnTransferContext(context: &contextContent, config: config) let gasLimitSum = transfers.reduce(Balance(0)) { $0 + $1.gasLimit } - let argument = try JamEncoder.encode(timeslot) + JamEncoder.encode(service) + JamEncoder.encode(transfers) + let argument = try JamEncoder.encode(timeslot, service, transfers) _ = await invokePVM( config: config, diff --git a/Blockchain/Sources/Blockchain/VMInvocations/Invocations/RefineInvocation.swift b/Blockchain/Sources/Blockchain/VMInvocations/Invocations/RefineInvocation.swift index 2906dd4c..722e1c85 100644 --- a/Blockchain/Sources/Blockchain/VMInvocations/Invocations/RefineInvocation.swift +++ b/Blockchain/Sources/Blockchain/VMInvocations/Invocations/RefineInvocation.swift @@ -51,13 +51,15 @@ extension RefineInvocation { return (.failure(.codeTooLarge), []) } - let argumentData = try JamEncoder.encode(service) + - JamEncoder.encode(workPayload) + - JamEncoder.encode(workPackageHash) + - JamEncoder.encode(refinementCtx) + - JamEncoder.encode(authorizerHash) + - JamEncoder.encode(authorizationOutput) + - JamEncoder.encode(extrinsicDataBlobs) + let argumentData = try JamEncoder.encode( + service, + workPayload, + workPackageHash, + refinementCtx, + authorizerHash, + authorizationOutput, + extrinsicDataBlobs + ) let ctx = RefineContext( config: config, context: (pvms: [:], exports: []), diff --git a/Codec/Sources/Codec/JamEncoder.swift b/Codec/Sources/Codec/JamEncoder.swift index 59796f1e..36bee04e 100644 --- a/Codec/Sources/Codec/JamEncoder.swift +++ b/Codec/Sources/Codec/JamEncoder.swift @@ -25,6 +25,14 @@ public class JamEncoder { return encoder.data } + public static func encode(_ values: any Encodable...) throws -> Data { + let encoder = JamEncoder() + for value in values { + try encoder.encode(value) + } + return encoder.data + } + public var data: Data { encoder.data }