From 890b4ec68756d7794069e63f299be9daee29f049 Mon Sep 17 00:00:00 2001 From: Bryan Chen Date: Thu, 22 Aug 2024 16:08:06 +1200 Subject: [PATCH 1/4] confirm to the block serlization section --- .../Blockchain/Types/ExtrinsicDisputes.swift | 3 + .../Types/ExtrinsicGuarantees.swift | 7 +- .../Blockchain/Types/ExtrinsicPreimages.swift | 6 +- .../Sources/Blockchain/Types/Header.swift | 164 ++++++++++-------- .../Blockchain/Types/RefinementContext.swift | 6 + .../Sources/Blockchain/Types/State.swift | 20 +-- .../Sources/Blockchain/Types/WorkOutput.swift | 112 ++++++++++++ .../Sources/Blockchain/Types/WorkReport.swift | 36 ++-- .../Sources/Blockchain/Types/WorkResult.swift | 15 +- .../Blockchain/Types/WorkResultError.swift | 4 +- .../Sources/Blockchain/Types/primitives.swift | 5 +- .../Utils/ConfigLimitedSizeArray.swift | 10 ++ 12 files changed, 273 insertions(+), 115 deletions(-) create mode 100644 Blockchain/Sources/Blockchain/Types/WorkOutput.swift diff --git a/Blockchain/Sources/Blockchain/Types/ExtrinsicDisputes.swift b/Blockchain/Sources/Blockchain/Types/ExtrinsicDisputes.swift index dbb293f8..04e90002 100644 --- a/Blockchain/Sources/Blockchain/Types/ExtrinsicDisputes.swift +++ b/Blockchain/Sources/Blockchain/Types/ExtrinsicDisputes.swift @@ -74,8 +74,11 @@ public struct ExtrinsicDisputes: Sendable, Equatable, Codable { } } + // v public var verdicts: [VerdictItem] + // c public var culprits: [CulpritItem] + // f public var faults: [FaultItem] public init( diff --git a/Blockchain/Sources/Blockchain/Types/ExtrinsicGuarantees.swift b/Blockchain/Sources/Blockchain/Types/ExtrinsicGuarantees.swift index 4cf4f7bd..d571054a 100644 --- a/Blockchain/Sources/Blockchain/Types/ExtrinsicGuarantees.swift +++ b/Blockchain/Sources/Blockchain/Types/ExtrinsicGuarantees.swift @@ -2,11 +2,11 @@ import Utils public struct ExtrinsicGuarantees: Sendable, Equatable, Codable { public struct IndexAndSignature: Sendable, Equatable, Codable { - public var index: UInt32 + public var index: ValidatorIndex public var signature: Ed25519Signature public init( - index: UInt32, + index: ValidatorIndex, signature: Ed25519Signature ) { self.index = index @@ -15,7 +15,6 @@ public struct ExtrinsicGuarantees: Sendable, Equatable, Codable { } public struct GuaranteeItem: Sendable, Equatable, Codable { - public var coreIndex: CoreIndex public var workReport: WorkReport public var timeslot: TimeslotIndex public var credential: LimitedSizeArray< @@ -25,7 +24,6 @@ public struct ExtrinsicGuarantees: Sendable, Equatable, Codable { > public init( - coreIndex: CoreIndex, workReport: WorkReport, timeslot: TimeslotIndex, credential: LimitedSizeArray< @@ -34,7 +32,6 @@ public struct ExtrinsicGuarantees: Sendable, Equatable, Codable { ConstInt3 > ) { - self.coreIndex = coreIndex self.workReport = workReport self.timeslot = timeslot self.credential = credential diff --git a/Blockchain/Sources/Blockchain/Types/ExtrinsicPreimages.swift b/Blockchain/Sources/Blockchain/Types/ExtrinsicPreimages.swift index f4ceb53a..9587aa21 100644 --- a/Blockchain/Sources/Blockchain/Types/ExtrinsicPreimages.swift +++ b/Blockchain/Sources/Blockchain/Types/ExtrinsicPreimages.swift @@ -3,11 +3,11 @@ import Utils public struct ExtrinsicPreimages: Sendable, Equatable, Codable { public struct PreimageItem: Sendable, Equatable, Codable { - public var serviceIndices: ServiceIndices + public var serviceIndex: ServiceIndex public var data: Data - public init(serviceIndices: ServiceIndices, data: Data) { - self.serviceIndices = serviceIndices + public init(serviceIndex: ServiceIndex, data: Data) { + self.serviceIndex = serviceIndex self.data = data } } diff --git a/Blockchain/Sources/Blockchain/Types/Header.swift b/Blockchain/Sources/Blockchain/Types/Header.swift index 26e3d6fe..db799f21 100644 --- a/Blockchain/Sources/Blockchain/Types/Header.swift +++ b/Blockchain/Sources/Blockchain/Types/Header.swift @@ -2,75 +2,83 @@ import Codec import Utils public struct Header: Sendable, Equatable, Codable { - // Hp: parent hash - public var parentHash: Data32 - - // Hr: prior state root - public var priorStateRoot: Data32 // state root of the after parent block execution - - // Hx: extrinsic hash - public var extrinsicsRoot: Data32 - - // Ht: timeslot index - public var timeslotIndex: TimeslotIndex - - // He: the epoch - // the header’s epoch marker He is either empty or, if the block is the first in a new epoch, - // then a tuple of the epoch randomness and a sequence of Bandersnatch keys - // defining the Bandersnatch validator keys (kb) beginning in the next epoch - public var epoch: EpochMarker? - - // Hw: winning-tickets - // The winning-tickets marker Hw is either empty or, - // if the block is the first after the end of the submission period - // for tickets and if the ticket accumulator is saturated, then the final sequence of ticket identifiers - public var winningTickets: ConfigFixedSizeArray< - Ticket, - ProtocolConfig.EpochLength - >? - - // Hj: The verdicts markers must contain exactly the sequence of report hashes of all new - // bad & wonky verdicts. - public var judgementsMarkers: [Data32] - - // Ho: The offenders markers must contain exactly the sequence of keys of all new offenders. - public var offendersMarkers: [Ed25519PublicKey] - - // Hi: block author index - public var authorIndex: ValidatorIndex + public struct Unsigned: Sendable, Equatable, Codable { + // Hp: parent hash + public var parentHash: Data32 + + // Hr: prior state root + public var priorStateRoot: Data32 // state root of the after parent block execution + + // Hx: extrinsic hash + public var extrinsicsRoot: Data32 + + // Ht: timeslot index + public var timeslotIndex: TimeslotIndex + + // He: the epoch + // the header’s epoch marker He is either empty or, if the block is the first in a new epoch, + // then a tuple of the epoch randomness and a sequence of Bandersnatch keys + // defining the Bandersnatch validator keys (kb) beginning in the next epoch + public var epoch: EpochMarker? + + // Hw: winning-tickets + // The winning-tickets marker Hw is either empty or, + // if the block is the first after the end of the submission period + // for tickets and if the ticket accumulator is saturated, then the final sequence of ticket identifiers + public var winningTickets: + ConfigFixedSizeArray< + Ticket, + ProtocolConfig.EpochLength + >? + + // Hj: The verdicts markers must contain exactly the sequence of report hashes of all new + // bad & wonky verdicts. + public var judgementsMarkers: [Data32] + + // Ho: The offenders markers must contain exactly the sequence of keys of all new offenders. + public var offendersMarkers: [Ed25519PublicKey] + + // Hi: block author index + public var authorIndex: ValidatorIndex + + // Hv: the entropy-yielding vrf signature + public var vrfSignature: BandersnatchSignature + + public init( + parentHash: Data32, + priorStateRoot: Data32, + extrinsicsRoot: Data32, + timeslotIndex: TimeslotIndex, + epoch: EpochMarker?, + winningTickets: ConfigFixedSizeArray< + Ticket, + ProtocolConfig.EpochLength + >?, + judgementsMarkers: [Data32], + offendersMarkers: [Ed25519PublicKey], + authorIndex: ValidatorIndex, + vrfSignature: BandersnatchSignature + ) { + self.parentHash = parentHash + self.priorStateRoot = priorStateRoot + self.extrinsicsRoot = extrinsicsRoot + self.timeslotIndex = timeslotIndex + self.epoch = epoch + self.winningTickets = winningTickets + self.judgementsMarkers = judgementsMarkers + self.offendersMarkers = offendersMarkers + self.authorIndex = authorIndex + self.vrfSignature = vrfSignature + } + } - // Hv: the entropy-yielding vrf signature - public var vrfSignature: BandersnatchSignature + public var unsigned: Unsigned // Hs: block seal public var seal: BandersnatchSignature - public init( - parentHash: Data32, - priorStateRoot: Data32, - extrinsicsRoot: Data32, - timeslotIndex: TimeslotIndex, - epoch: EpochMarker?, - winningTickets: ConfigFixedSizeArray< - Ticket, - ProtocolConfig.EpochLength - >?, - judgementsMarkers: [Data32], - offendersMarkers: [Ed25519PublicKey], - authorIndex: UInt32, - vrfSignature: BandersnatchSignature, - seal: BandersnatchSignature - ) { - self.parentHash = parentHash - self.priorStateRoot = priorStateRoot - self.extrinsicsRoot = extrinsicsRoot - self.timeslotIndex = timeslotIndex - self.epoch = epoch - self.winningTickets = winningTickets - self.judgementsMarkers = judgementsMarkers - self.offendersMarkers = offendersMarkers - self.authorIndex = authorIndex - self.vrfSignature = vrfSignature + public init(unsigned: Unsigned, seal: BandersnatchSignature) { + self.unsigned = unsigned self.seal = seal } } @@ -83,10 +91,10 @@ extension Header { public typealias HeaderRef = Ref
-extension Header: Dummy { +extension Header.Unsigned: Dummy { public typealias Config = ProtocolConfigRef - public static func dummy(config _: Config) -> Header { - Header( + public static func dummy(config _: Config) -> Header.Unsigned { + Header.Unsigned( parentHash: Data32(), priorStateRoot: Data32(), extrinsicsRoot: Data32(), @@ -96,7 +104,16 @@ extension Header: Dummy { judgementsMarkers: [], offendersMarkers: [], authorIndex: 0, - vrfSignature: BandersnatchSignature(), + vrfSignature: BandersnatchSignature() + ) + } +} + +extension Header: Dummy { + public typealias Config = ProtocolConfigRef + public static func dummy(config: Config) -> Header { + Header( + unsigned: Header.Unsigned.dummy(config: config), seal: BandersnatchSignature() ) } @@ -110,4 +127,15 @@ extension Header { fatalError("Failed to hash header: \(e)") } } + + public var parentHash: Data32 { unsigned.parentHash } + public var priorStateRoot: Data32 { unsigned.priorStateRoot } + public var extrinsicsRoot: Data32 { unsigned.extrinsicsRoot } + public var timeslotIndex: TimeslotIndex { unsigned.timeslotIndex } + public var epoch: EpochMarker? { unsigned.epoch } + public var winningTickets: ConfigFixedSizeArray? { unsigned.winningTickets } + public var judgementsMarkers: [Data32] { unsigned.judgementsMarkers } + public var offendersMarkers: [Ed25519PublicKey] { unsigned.offendersMarkers } + public var authorIndex: ValidatorIndex { unsigned.authorIndex } + public var vrfSignature: BandersnatchSignature { unsigned.vrfSignature } } diff --git a/Blockchain/Sources/Blockchain/Types/RefinementContext.swift b/Blockchain/Sources/Blockchain/Types/RefinementContext.swift index 618215fa..a185e16f 100644 --- a/Blockchain/Sources/Blockchain/Types/RefinementContext.swift +++ b/Blockchain/Sources/Blockchain/Types/RefinementContext.swift @@ -4,8 +4,11 @@ import Utils // at the point that the report’s corresponding work-package was evaluated. public struct RefinementContext: Sendable, Equatable, Codable { public struct Anchor: Sendable, Equatable, Codable { + // a public var headerHash: Data32 + // s public var stateRoot: Data32 + // b public var beefyRoot: Data32 public init( @@ -20,7 +23,9 @@ public struct RefinementContext: Sendable, Equatable, Codable { } public struct LokupAnchor: Sendable, Equatable, Codable { + // l public var headerHash: Data32 + // t public var timeslot: TimeslotIndex public init( @@ -36,6 +41,7 @@ public struct RefinementContext: Sendable, Equatable, Codable { public var lokupAnchor: LokupAnchor + // p public var prerequistieWorkPackage: Data32? public init(anchor: Anchor, lokupAnchor: LokupAnchor, prerequistieWorkPackage: Data32?) { diff --git a/Blockchain/Sources/Blockchain/Types/State.swift b/Blockchain/Sources/Blockchain/Types/State.swift index df31fbd0..a6196ad5 100644 --- a/Blockchain/Sources/Blockchain/Types/State.swift +++ b/Blockchain/Sources/Blockchain/Types/State.swift @@ -16,11 +16,11 @@ public struct State: Sendable { } public struct PrivilegedServiceIndices: Sendable, Equatable, Codable { - public var empower: ServiceIdentifier - public var assign: ServiceIdentifier - public var designate: ServiceIdentifier + public var empower: ServiceIndex + public var assign: ServiceIndex + public var designate: ServiceIndex - public init(empower: ServiceIdentifier, assign: ServiceIdentifier, designate: ServiceIdentifier) { + public init(empower: ServiceIndex, assign: ServiceIndex, designate: ServiceIndex) { self.empower = empower self.assign = assign self.designate = designate @@ -46,7 +46,7 @@ public struct State: Sendable { public var safroleState: SafroleState // δ: The (prior) state of the service accounts. - public var serviceAccounts: [ServiceIdentifier: ServiceAccount] + public var serviceAccounts: [ServiceIndex: ServiceAccount] // η: The eηtropy accumulator and epochal raηdomness. public var entropyPool: EntropyPool @@ -105,7 +105,7 @@ public struct State: Sendable { >, lastBlock: BlockRef, safroleState: SafroleState, - serviceAccounts: [ServiceIdentifier: ServiceAccount], + serviceAccounts: [ServiceIndex: ServiceAccount], entropyPool: EntropyPool, validatorQueue: ConfigFixedSizeArray< ValidatorKey, ProtocolConfig.TotalNumberOfValidators @@ -192,7 +192,7 @@ extension State: Codable { ), lastBlock: container.decode(BlockRef.self, forKey: .lastBlock), safroleState: container.decode(SafroleState.self, forKey: .safroleState), - serviceAccounts: container.decode([ServiceIdentifier: ServiceAccount].self, forKey: .serviceAccounts), + serviceAccounts: container.decode([ServiceIndex: ServiceAccount].self, forKey: .serviceAccounts), entropyPool: container.decode(EntropyPool.self, forKey: .entropyPool), validatorQueue: container.decode( ConfigFixedSizeArray< @@ -296,9 +296,9 @@ extension State: Dummy { defaultValue: ConfigFixedSizeArray(config: config, defaultValue: Data32()) ), privilegedServiceIndices: PrivilegedServiceIndices( - empower: ServiceIdentifier(), - assign: ServiceIdentifier(), - designate: ServiceIdentifier() + empower: ServiceIndex(), + assign: ServiceIndex(), + designate: ServiceIndex() ), judgements: JudgementsState.dummy(config: config), activityStatistics: ValidatorActivityStatistics.dummy(config: config) diff --git a/Blockchain/Sources/Blockchain/Types/WorkOutput.swift b/Blockchain/Sources/Blockchain/Types/WorkOutput.swift new file mode 100644 index 00000000..3ddc9db7 --- /dev/null +++ b/Blockchain/Sources/Blockchain/Types/WorkOutput.swift @@ -0,0 +1,112 @@ +import Codec +import Foundation + +public enum WorkResultError: Error, CaseIterable { + case outOfGas + case panic + case invalidCode + case codeTooLarge // code larger than MaxServiceCodeSize +} + +public struct WorkOutput: Sendable, Equatable { + public var result: Result + + public init(_ result: Result) { + self.result = result + } +} + +extension WorkOutput: Codable { + enum CodingKeys: String, CodingKey { + case success + case outOfGas + case panic + case invalidCode + case codeTooLarge + } + + public init(from decoder: Decoder) throws { + if decoder.isJamCodec { + var container = try decoder.unkeyedContainer() + let variant = try container.decode(UInt8.self) + switch variant { + case 0: + self = try .init(.success(container.decode(Data.self))) + case 1: + self = .init(.failure(.outOfGas)) + case 2: + self = .init(.failure(.panic)) + case 3: + self = .init(.failure(.invalidCode)) + case 4: + self = .init(.failure(.codeTooLarge)) + default: + throw DecodingError.dataCorrupted( + DecodingError.Context( + codingPath: decoder.codingPath, + debugDescription: "Invalid WorkResultError: unknown variant \(variant)" + ) + ) + } + } else { + let container = try decoder.container(keyedBy: CodingKeys.self) + if container.contains(.success) { + self = try .init(.success(container.decode(Data.self, forKey: .success))) + } else if container.contains(.outOfGas) { + self = .init(.failure(.outOfGas)) + } else if container.contains(.panic) { + self = .init(.failure(.panic)) + } else if container.contains(.invalidCode) { + self = .init(.failure(.invalidCode)) + } else if container.contains(.codeTooLarge) { + self = .init(.failure(.codeTooLarge)) + } else { + throw DecodingError.dataCorrupted( + DecodingError.Context( + codingPath: container.codingPath, + debugDescription: "Not valid key founded" + ) + ) + } + } + } + + public func encode(to encoder: Encoder) throws { + if encoder.isJamCodec { + var container = encoder.unkeyedContainer() + switch result { + case let .success(success): + try container.encode(0) + try container.encode(success) + case let .failure(failure): + switch failure { + case .outOfGas: + try container.encode(1) + case .panic: + try container.encode(2) + case .invalidCode: + try container.encode(3) + case .codeTooLarge: + try container.encode(4) + } + } + } else { + var container = encoder.container(keyedBy: CodingKeys.self) + switch result { + case let .success(success): + try container.encode(success, forKey: .success) + case let .failure(failure): + switch failure { + case .outOfGas: + try container.encodeNil(forKey: .outOfGas) + case .panic: + try container.encodeNil(forKey: .panic) + case .invalidCode: + try container.encodeNil(forKey: .invalidCode) + case .codeTooLarge: + try container.encodeNil(forKey: .codeTooLarge) + } + } + } + } +} diff --git a/Blockchain/Sources/Blockchain/Types/WorkReport.swift b/Blockchain/Sources/Blockchain/Types/WorkReport.swift index 5580846f..e80180af 100644 --- a/Blockchain/Sources/Blockchain/Types/WorkReport.swift +++ b/Blockchain/Sources/Blockchain/Types/WorkReport.swift @@ -2,18 +2,21 @@ import Foundation import Utils public struct WorkReport: Sendable, Equatable, Codable { + // s: package specification + public var packageSpecification: AvailabilitySpecifications + + // x: refinement context + public var refinementContext: RefinementContext + + // c: the core-index + public var coreIndex: CoreIndex + // a: authorizer hash public var authorizerHash: Data32 // o: output public var output: Data - // x: refinement context - public var refinementContext: RefinementContext - - // s: package specification - public var packageSpecification: AvailabilitySpecifications - // r: the results of the evaluation of each of the items in the package public var results: ConfigLimitedSizeArray< WorkResult, @@ -22,20 +25,18 @@ public struct WorkReport: Sendable, Equatable, Codable { > public init( + packageSpecification: AvailabilitySpecifications, + refinementContext: RefinementContext, + coreIndex: CoreIndex, authorizerHash: Data32, output: Data, - refinementContext: RefinementContext, - packageSpecification: AvailabilitySpecifications, - results: ConfigLimitedSizeArray< - WorkResult, - ProtocolConfig.Int1, - ProtocolConfig.MaxWorkItems - > + results: ConfigLimitedSizeArray ) { + self.packageSpecification = packageSpecification + self.refinementContext = refinementContext + self.coreIndex = coreIndex self.authorizerHash = authorizerHash self.output = output - self.refinementContext = refinementContext - self.packageSpecification = packageSpecification self.results = results } } @@ -44,10 +45,11 @@ extension WorkReport: Dummy { public typealias Config = ProtocolConfigRef public static func dummy(config: Config) -> WorkReport { WorkReport( + packageSpecification: AvailabilitySpecifications.dummy(config: config), + refinementContext: RefinementContext.dummy(config: config), + coreIndex: 0, authorizerHash: Data32(), output: Data(), - refinementContext: RefinementContext.dummy(config: config), - packageSpecification: AvailabilitySpecifications.dummy(config: config), results: try! ConfigLimitedSizeArray(config: config, defaultValue: WorkResult.dummy(config: config)) ) } diff --git a/Blockchain/Sources/Blockchain/Types/WorkResult.swift b/Blockchain/Sources/Blockchain/Types/WorkResult.swift index 1ab543c8..4b9f3cc3 100644 --- a/Blockchain/Sources/Blockchain/Types/WorkResult.swift +++ b/Blockchain/Sources/Blockchain/Types/WorkResult.swift @@ -2,9 +2,10 @@ import Codec import Foundation import Utils +// L public struct WorkResult: Sendable, Equatable, Codable { // s: the index of the service whose state is to be altered and thus whose refine code was already executed - public var serviceIdentifier: ServiceIdentifier + public var serviceIndex: ServiceIndex // c: the hash of the code of the service at the time of being reported public var codeHash: Data32 @@ -18,16 +19,16 @@ public struct WorkResult: Sendable, Equatable, Codable { // o: there is the output or error of the execution of the code o // which may be either an octet sequence in case it was successful, or a member of the set J, if not - public var output: Result + public var output: WorkOutput public init( - serviceIdentifier: ServiceIdentifier, + serviceIndex: ServiceIndex, codeHash: Data32, payloadHash: Data32, gas: Gas, - output: Result + output: WorkOutput ) { - self.serviceIdentifier = serviceIdentifier + self.serviceIndex = serviceIndex self.codeHash = codeHash self.payloadHash = payloadHash self.gas = gas @@ -39,11 +40,11 @@ extension WorkResult: Dummy { public typealias Config = ProtocolConfigRef public static func dummy(config _: Config) -> WorkResult { WorkResult( - serviceIdentifier: ServiceIdentifier(), + serviceIndex: 0, codeHash: Data32(), payloadHash: Data32(), gas: 0, - output: .success(Data()) + output: .init(.success(Data())) ) } } diff --git a/Blockchain/Sources/Blockchain/Types/WorkResultError.swift b/Blockchain/Sources/Blockchain/Types/WorkResultError.swift index a1e9c860..a85cca53 100644 --- a/Blockchain/Sources/Blockchain/Types/WorkResultError.swift +++ b/Blockchain/Sources/Blockchain/Types/WorkResultError.swift @@ -1,11 +1,11 @@ -public enum WorkResultError: Error, CaseIterable { +public enum WorkResultError1: Error, CaseIterable { case outofGas case panic case invalidCode case codeTooLarge // code larger than MaxServiceCodeSize } -extension WorkResultError: Codable { +extension WorkResultError1: Codable { enum CodingKeys: String, CodingKey { case outofGas case panic diff --git a/Blockchain/Sources/Blockchain/Types/primitives.swift b/Blockchain/Sources/Blockchain/Types/primitives.swift index 6880a6da..fa4e96ae 100644 --- a/Blockchain/Sources/Blockchain/Types/primitives.swift +++ b/Blockchain/Sources/Blockchain/Types/primitives.swift @@ -1,13 +1,12 @@ import Utils public typealias Balances = UInt64 -public typealias ServiceIdentifier = Data32 +public typealias ServiceIndex = UInt32 public typealias TimeslotIndex = UInt32 public typealias Gas = UInt64 -public typealias ServiceIndices = UInt32 public typealias DataLength = UInt32 -public typealias ValidatorIndex = UInt32 // TODO: confirm this +public typealias ValidatorIndex = UInt16 public typealias CoreIndex = UInt32 // TODO: confirm this public typealias TicketIndex = UInt8 public typealias EpochIndex = UInt32 diff --git a/Utils/Sources/Utils/ConfigLimitedSizeArray.swift b/Utils/Sources/Utils/ConfigLimitedSizeArray.swift index 990ece91..e2241519 100644 --- a/Utils/Sources/Utils/ConfigLimitedSizeArray.swift +++ b/Utils/Sources/Utils/ConfigLimitedSizeArray.swift @@ -104,6 +104,16 @@ extension ConfigLimitedSizeArray: RandomAccessCollection { } } + public subscript(position: UInt16) -> T { + get { + array[Int(position)] + } + set { + array[Int(position)] = newValue + validate() + } + } + public func index(after i: Int) -> Int { i + 1 } From ad64b411944df06d29e110e109b3781bd310170c Mon Sep 17 00:00:00 2001 From: Bryan Chen Date: Thu, 22 Aug 2024 16:29:03 +1200 Subject: [PATCH 2/4] add work item and work package --- .../Blockchain/Types/HashAndLength.swift | 21 ++++++ .../Blockchain/Types/ServiceAccount.swift | 10 --- .../Sources/Blockchain/Types/WorkItem.swift | 69 +++++++++++++++++++ .../Blockchain/Types/WorkPackage.swift | 61 ++++++++++++++++ .../Sources/Blockchain/Types/WorkReport.swift | 36 +++++----- 5 files changed, 170 insertions(+), 27 deletions(-) create mode 100644 Blockchain/Sources/Blockchain/Types/HashAndLength.swift create mode 100644 Blockchain/Sources/Blockchain/Types/WorkItem.swift create mode 100644 Blockchain/Sources/Blockchain/Types/WorkPackage.swift diff --git a/Blockchain/Sources/Blockchain/Types/HashAndLength.swift b/Blockchain/Sources/Blockchain/Types/HashAndLength.swift new file mode 100644 index 00000000..677b4370 --- /dev/null +++ b/Blockchain/Sources/Blockchain/Types/HashAndLength.swift @@ -0,0 +1,21 @@ +import Utils + +public struct HashAndLength: Sendable, Codable { + public var hash: Data32 + public var length: DataLength + + public init(hash: Data32, length: DataLength) { + self.hash = hash + self.length = length + } +} + +extension HashAndLength: Hashable { + public func hash(into hasher: inout Hasher) { + // we assume hash is alraedy a high quality hash + // and we know the output is 32 bytes + // so we can just take the first 4 bytes and should be good enough + // NOTE: we will never use the Hashable protocol for any critical operations + hasher.combine(hash.data[0 ..< 4]) + } +} diff --git a/Blockchain/Sources/Blockchain/Types/ServiceAccount.swift b/Blockchain/Sources/Blockchain/Types/ServiceAccount.swift index 7b856e6d..d11bad02 100644 --- a/Blockchain/Sources/Blockchain/Types/ServiceAccount.swift +++ b/Blockchain/Sources/Blockchain/Types/ServiceAccount.swift @@ -2,16 +2,6 @@ import Foundation import Utils public struct ServiceAccount: Sendable, Equatable, Codable { - public struct HashAndLength: Sendable, Hashable, Codable { - public var hash: Data32 - public var length: DataLength - - public init(hash: Data32, length: DataLength) { - self.hash = hash - self.length = length - } - } - // s public var storage: [Data32: Data] diff --git a/Blockchain/Sources/Blockchain/Types/WorkItem.swift b/Blockchain/Sources/Blockchain/Types/WorkItem.swift new file mode 100644 index 00000000..b50020d1 --- /dev/null +++ b/Blockchain/Sources/Blockchain/Types/WorkItem.swift @@ -0,0 +1,69 @@ +import Foundation +import Utils + +// I +public struct WorkItem: Sendable, Equatable, Codable { + public struct ImportedDataSegment: Sendable, Equatable, Codable { + public var root: Data32 + public var index: UInt16 + + public init(root: Data32, index: UInt16) { + self.root = root + self.index = index + } + } + + // s + public var serviceIndex: ServiceIndex + + // c + public var codeHash: Data32 + + // y + public var payloadBlob: Data + + // g + public var gasLimit: Gas + + // i: a sequence of imported data segments i identified by the root of the segments tree and an index into it + public var inputs: [ImportedDataSegment] + + // x: a sequence of hashed of blob hashes and lengths to be introduced in this block + public var outputs: [HashAndLength] + + // e: the number of data segments exported by this work item + public var outputDataSegmentsCount: UInt16 + + public init( + serviceIndex: ServiceIndex, + codeHash: Data32, + payloadBlob: Data, + gasLimit: Gas, + inputs: [ImportedDataSegment], + outputs: [HashAndLength], + outputDataSegmentsCount: UInt16 + ) { + self.serviceIndex = serviceIndex + self.codeHash = codeHash + self.payloadBlob = payloadBlob + self.gasLimit = gasLimit + self.inputs = inputs + self.outputs = outputs + self.outputDataSegmentsCount = outputDataSegmentsCount + } +} + +extension WorkItem: Dummy { + public typealias Config = ProtocolConfigRef + public static func dummy(config _: Config) -> WorkItem { + WorkItem( + serviceIndex: 0, + codeHash: Data32(), + payloadBlob: Data(), + gasLimit: 0, + inputs: [], + outputs: [], + outputDataSegmentsCount: 0 + ) + } +} diff --git a/Blockchain/Sources/Blockchain/Types/WorkPackage.swift b/Blockchain/Sources/Blockchain/Types/WorkPackage.swift new file mode 100644 index 00000000..620bf788 --- /dev/null +++ b/Blockchain/Sources/Blockchain/Types/WorkPackage.swift @@ -0,0 +1,61 @@ +import Foundation +import Utils + +// P +public struct WorkPackage: Sendable, Equatable, Codable { + // j + public var authorizationToken: Data + + // h + public var authorizationServiceIndex: ServiceIndex + + // c + public var authorizationCodeHash: Data32 + + // p + public var parameterizationBlob: Data + + // x + public var context: RefinementContext + + // w + public var workItems: ConfigLimitedSizeArray< + WorkItem, + ProtocolConfig.Int1, + ProtocolConfig.MaxWorkItems + > + + public init( + authorizationToken: Data, + authorizationServiceIndex: ServiceIndex, + authorizationCodeHash: Data32, + parameterizationBlob: Data, + context: RefinementContext, + workItems: ConfigLimitedSizeArray< + WorkItem, + ProtocolConfig.Int1, + ProtocolConfig.MaxWorkItems + > + ) { + self.authorizationToken = authorizationToken + self.authorizationServiceIndex = authorizationServiceIndex + self.authorizationCodeHash = authorizationCodeHash + self.parameterizationBlob = parameterizationBlob + self.context = context + self.workItems = workItems + } +} + +extension WorkPackage: Dummy { + public typealias Config = ProtocolConfigRef + public static func dummy(config: Config) -> WorkPackage { + WorkPackage( + authorizationToken: Data(), + authorizationServiceIndex: 0, + authorizationCodeHash: Data32(), + parameterizationBlob: Data(), + context: RefinementContext.dummy(config: config), + workItems: try! ConfigLimitedSizeArray(config: config, defaultValue: WorkItem.dummy(config: config)) + ) + } +} diff --git a/Blockchain/Sources/Blockchain/Types/WorkReport.swift b/Blockchain/Sources/Blockchain/Types/WorkReport.swift index e80180af..bf2b0ab5 100644 --- a/Blockchain/Sources/Blockchain/Types/WorkReport.swift +++ b/Blockchain/Sources/Blockchain/Types/WorkReport.swift @@ -2,21 +2,23 @@ import Foundation import Utils public struct WorkReport: Sendable, Equatable, Codable { - // s: package specification - public var packageSpecification: AvailabilitySpecifications + // the order is based on the Block Serialization section - // x: refinement context - public var refinementContext: RefinementContext + // a: authorizer hash + public var authorizerHash: Data32 // c: the core-index public var coreIndex: CoreIndex - // a: authorizer hash - public var authorizerHash: Data32 - // o: output public var output: Data + // x: refinement context + public var refinementContext: RefinementContext + + // s: package specification + public var packageSpecification: AvailabilitySpecifications + // r: the results of the evaluation of each of the items in the package public var results: ConfigLimitedSizeArray< WorkResult, @@ -25,18 +27,18 @@ public struct WorkReport: Sendable, Equatable, Codable { > public init( - packageSpecification: AvailabilitySpecifications, - refinementContext: RefinementContext, - coreIndex: CoreIndex, authorizerHash: Data32, + coreIndex: CoreIndex, output: Data, + refinementContext: RefinementContext, + packageSpecification: AvailabilitySpecifications, results: ConfigLimitedSizeArray ) { - self.packageSpecification = packageSpecification - self.refinementContext = refinementContext - self.coreIndex = coreIndex self.authorizerHash = authorizerHash + self.coreIndex = coreIndex self.output = output + self.refinementContext = refinementContext + self.packageSpecification = packageSpecification self.results = results } } @@ -45,12 +47,12 @@ extension WorkReport: Dummy { public typealias Config = ProtocolConfigRef public static func dummy(config: Config) -> WorkReport { WorkReport( - packageSpecification: AvailabilitySpecifications.dummy(config: config), - refinementContext: RefinementContext.dummy(config: config), - coreIndex: 0, authorizerHash: Data32(), + coreIndex: 0, output: Data(), - results: try! ConfigLimitedSizeArray(config: config, defaultValue: WorkResult.dummy(config: config)) + refinementContext: RefinementContext.dummy(config: config), + packageSpecification: AvailabilitySpecifications.dummy(config: config), + results: try! ConfigLimitedSizeArray(config: config, defaultValue: WorkResult.dummy(config: config)), ) } } From c863e5b89c41e4ed42fa7d5bd7087549cfec5652 Mon Sep 17 00:00:00 2001 From: Bryan Chen Date: Thu, 22 Aug 2024 16:32:27 +1200 Subject: [PATCH 3/4] remove old file --- .../Blockchain/Types/WorkResultError.swift | 84 ------------------- 1 file changed, 84 deletions(-) delete mode 100644 Blockchain/Sources/Blockchain/Types/WorkResultError.swift diff --git a/Blockchain/Sources/Blockchain/Types/WorkResultError.swift b/Blockchain/Sources/Blockchain/Types/WorkResultError.swift deleted file mode 100644 index a85cca53..00000000 --- a/Blockchain/Sources/Blockchain/Types/WorkResultError.swift +++ /dev/null @@ -1,84 +0,0 @@ -public enum WorkResultError1: Error, CaseIterable { - case outofGas - case panic - case invalidCode - case codeTooLarge // code larger than MaxServiceCodeSize -} - -extension WorkResultError1: Codable { - enum CodingKeys: String, CodingKey { - case outofGas - case panic - case invalidCode - case codeTooLarge - } - - public init(from decoder: Decoder) throws { - if decoder.isJamCodec { - let variant = try decoder.singleValueContainer().decode(UInt8.self) - switch variant { - case 0: - self = .outofGas - case 1: - self = .panic - case 2: - self = .invalidCode - case 3: - self = .codeTooLarge - default: - throw DecodingError.dataCorrupted( - DecodingError.Context( - codingPath: decoder.codingPath, - debugDescription: "Invalid WorkResultError: unknown variant \(variant)" - ) - ) - } - } else { - let container = try decoder.container(keyedBy: CodingKeys.self) - if container.contains(.outofGas) { - self = .outofGas - } else if container.contains(.panic) { - self = .panic - } else if container.contains(.invalidCode) { - self = .invalidCode - } else if container.contains(.codeTooLarge) { - self = .codeTooLarge - } else { - throw DecodingError.dataCorrupted( - DecodingError.Context( - codingPath: container.codingPath, - debugDescription: "Invalid WorkResultError: must contain either outofGas or panic" - ) - ) - } - } - } - - public func encode(to encoder: Encoder) throws { - if encoder.isJamCodec { - var container = encoder.unkeyedContainer() - switch self { - case .outofGas: - try container.encode(0) - case .panic: - try container.encode(1) - case .invalidCode: - try container.encode(2) - case .codeTooLarge: - try container.encode(3) - } - } else { - var container = encoder.container(keyedBy: CodingKeys.self) - switch self { - case .outofGas: - try container.encodeNil(forKey: .outofGas) - case .panic: - try container.encodeNil(forKey: .panic) - case .invalidCode: - try container.encodeNil(forKey: .invalidCode) - case .codeTooLarge: - try container.encodeNil(forKey: .codeTooLarge) - } - } - } -} From 158c7c1f0ff88f9e710eedf8c9721451d8ce6bec Mon Sep 17 00:00:00 2001 From: Bryan Chen Date: Thu, 22 Aug 2024 16:58:26 +1200 Subject: [PATCH 4/4] some more refactor --- Blockchain/Sources/Blockchain/Runtime.swift | 2 +- Blockchain/Sources/Blockchain/Safrole.swift | 5 +- .../Sources/Blockchain/Types/State.swift | 131 +----------------- .../Sources/Blockchain/Types/WorkReport.swift | 2 +- JAMTests/Tests/JAMTests/SafroleTests.swift | 100 ++++--------- 5 files changed, 32 insertions(+), 208 deletions(-) diff --git a/Blockchain/Sources/Blockchain/Runtime.swift b/Blockchain/Sources/Blockchain/Runtime.swift index 95b5a9f2..3f271b9b 100644 --- a/Blockchain/Sources/Blockchain/Runtime.swift +++ b/Blockchain/Sources/Blockchain/Runtime.swift @@ -40,7 +40,7 @@ public final class Runtime { newState.lastBlock = block let res = newState.updateSafrole( - slot: block.header.timeslotIndex, entropy: newState.entropyPool.t0, extrinsics: block.extrinsic.tickets + config: config, slot: block.header.timeslotIndex, entropy: newState.entropyPool.t0, extrinsics: block.extrinsic.tickets ) switch res { case let .success((state: postState, epochMark: _, ticketsMark: _)): diff --git a/Blockchain/Sources/Blockchain/Safrole.swift b/Blockchain/Sources/Blockchain/Safrole.swift index aa750590..2e638d86 100644 --- a/Blockchain/Sources/Blockchain/Safrole.swift +++ b/Blockchain/Sources/Blockchain/Safrole.swift @@ -120,7 +120,6 @@ public struct SafrolePostState: Sendable, Equatable { } public protocol Safrole { - var config: ProtocolConfigRef { get } var timeslot: TimeslotIndex { get } var entropyPool: EntropyPool { get } var previousValidators: ConfigFixedSizeArray< @@ -152,7 +151,7 @@ public protocol Safrole { > { get } var ticketsVerifier: BandersnatchRingVRFRoot { get } - func updateSafrole(slot: TimeslotIndex, entropy: Data32, extrinsics: ExtrinsicTickets) + func updateSafrole(config: ProtocolConfigRef, slot: TimeslotIndex, entropy: Data32, extrinsics: ExtrinsicTickets) -> Result< ( state: SafrolePostState, @@ -211,7 +210,7 @@ func pickFallbackValidators( } extension Safrole { - public func updateSafrole(slot: TimeslotIndex, entropy: Data32, extrinsics: ExtrinsicTickets) + public func updateSafrole(config: ProtocolConfigRef, slot: TimeslotIndex, entropy: Data32, extrinsics: ExtrinsicTickets) -> Result< ( state: SafrolePostState, diff --git a/Blockchain/Sources/Blockchain/Types/State.swift b/Blockchain/Sources/Blockchain/Types/State.swift index a6196ad5..c661ee30 100644 --- a/Blockchain/Sources/Blockchain/Types/State.swift +++ b/Blockchain/Sources/Blockchain/Types/State.swift @@ -1,7 +1,7 @@ import Codec import Utils -public struct State: Sendable { +public struct State: Sendable, Equatable, Codable { public struct ReportItem: Sendable, Equatable, Codable { public var workReport: WorkReport public var timeslot: TimeslotIndex @@ -27,8 +27,6 @@ public struct State: Sendable { } } - public let config: ProtocolConfigRef - // α: The core αuthorizations pool. public var coreAuthorizationPool: ConfigFixedSizeArray< ConfigLimitedSizeArray< @@ -94,7 +92,6 @@ public struct State: Sendable { public var activityStatistics: ValidatorActivityStatistics public init( - config: ProtocolConfigRef, coreAuthorizationPool: ConfigFixedSizeArray< ConfigLimitedSizeArray< Data32, @@ -132,7 +129,6 @@ public struct State: Sendable { judgements: JudgementsState, activityStatistics: ValidatorActivityStatistics ) { - self.config = config self.coreAuthorizationPool = coreAuthorizationPool self.lastBlock = lastBlock self.safroleState = safroleState @@ -150,137 +146,12 @@ public struct State: Sendable { } } -extension State: Codable { - enum CodingKeys: String, CodingKey { - case coreAuthorizationPool - case lastBlock - case safroleState - case serviceAccounts - case entropyPool - case validatorQueue - case currentValidators - case previousValidators - case reports - case timeslot - case authorizationQueue - case privilegedServiceIndices - case judgements - case activityStatistics - } - - enum CodingError: Error { - case missingConfig - } - - public init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - guard let config = decoder.getConfig(ProtocolConfigRef.self) else { - throw CodingError.missingConfig - } - try self.init( - config: config, - coreAuthorizationPool: container.decode( - ConfigFixedSizeArray< - ConfigLimitedSizeArray< - Data32, - ProtocolConfig.Int0, - ProtocolConfig.MaxAuthorizationsPoolItems - >, - ProtocolConfig.TotalNumberOfCores - >.self, - forKey: .coreAuthorizationPool - ), - lastBlock: container.decode(BlockRef.self, forKey: .lastBlock), - safroleState: container.decode(SafroleState.self, forKey: .safroleState), - serviceAccounts: container.decode([ServiceIndex: ServiceAccount].self, forKey: .serviceAccounts), - entropyPool: container.decode(EntropyPool.self, forKey: .entropyPool), - validatorQueue: container.decode( - ConfigFixedSizeArray< - ValidatorKey, ProtocolConfig.TotalNumberOfValidators - >.self, - forKey: .validatorQueue - ), - currentValidators: container.decode( - ConfigFixedSizeArray< - ValidatorKey, ProtocolConfig.TotalNumberOfValidators - >.self, - forKey: .currentValidators - ), - previousValidators: container.decode( - ConfigFixedSizeArray< - ValidatorKey, ProtocolConfig.TotalNumberOfValidators - >.self, - forKey: .previousValidators - ), - reports: container.decode( - ConfigFixedSizeArray< - ReportItem?, - ProtocolConfig.TotalNumberOfCores - >.self, - forKey: .reports - ), - timeslot: container.decode(TimeslotIndex.self, forKey: .timeslot), - authorizationQueue: container.decode( - ConfigFixedSizeArray< - ConfigFixedSizeArray< - Data32, - ProtocolConfig.MaxAuthorizationsQueueItems - >, - ProtocolConfig.TotalNumberOfCores - >.self, - forKey: .authorizationQueue - ), - privilegedServiceIndices: container.decode(PrivilegedServiceIndices.self, forKey: .privilegedServiceIndices), - judgements: container.decode(JudgementsState.self, forKey: .judgements), - activityStatistics: container.decode(ValidatorActivityStatistics.self, forKey: .activityStatistics) - ) - } - - public func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(coreAuthorizationPool, forKey: .coreAuthorizationPool) - try container.encode(lastBlock, forKey: .lastBlock) - try container.encode(safroleState, forKey: .safroleState) - try container.encode(serviceAccounts, forKey: .serviceAccounts) - try container.encode(entropyPool, forKey: .entropyPool) - try container.encode(validatorQueue, forKey: .validatorQueue) - try container.encode(currentValidators, forKey: .currentValidators) - try container.encode(previousValidators, forKey: .previousValidators) - try container.encode(reports, forKey: .reports) - try container.encode(timeslot, forKey: .timeslot) - try container.encode(authorizationQueue, forKey: .authorizationQueue) - try container.encode(privilegedServiceIndices, forKey: .privilegedServiceIndices) - try container.encode(judgements, forKey: .judgements) - try container.encode(activityStatistics, forKey: .activityStatistics) - } -} - public typealias StateRef = Ref -extension State: Equatable { - public static func == (lhs: State, rhs: State) -> Bool { - lhs.coreAuthorizationPool == rhs.coreAuthorizationPool && - lhs.lastBlock == rhs.lastBlock && - lhs.safroleState == rhs.safroleState && - lhs.serviceAccounts == rhs.serviceAccounts && - lhs.entropyPool == rhs.entropyPool && - lhs.validatorQueue == rhs.validatorQueue && - lhs.currentValidators == rhs.currentValidators && - lhs.previousValidators == rhs.previousValidators && - lhs.reports == rhs.reports && - lhs.timeslot == rhs.timeslot && - lhs.authorizationQueue == rhs.authorizationQueue && - lhs.privilegedServiceIndices == rhs.privilegedServiceIndices && - lhs.judgements == rhs.judgements && - lhs.activityStatistics == rhs.activityStatistics - } -} - extension State: Dummy { public typealias Config = ProtocolConfigRef public static func dummy(config: Config) -> State { try! State( - config: config, coreAuthorizationPool: ConfigFixedSizeArray(config: config, defaultValue: ConfigLimitedSizeArray(config: config)), lastBlock: BlockRef.dummy(config: config), safroleState: SafroleState.dummy(config: config), diff --git a/Blockchain/Sources/Blockchain/Types/WorkReport.swift b/Blockchain/Sources/Blockchain/Types/WorkReport.swift index bf2b0ab5..2768bdc7 100644 --- a/Blockchain/Sources/Blockchain/Types/WorkReport.swift +++ b/Blockchain/Sources/Blockchain/Types/WorkReport.swift @@ -52,7 +52,7 @@ extension WorkReport: Dummy { output: Data(), refinementContext: RefinementContext.dummy(config: config), packageSpecification: AvailabilitySpecifications.dummy(config: config), - results: try! ConfigLimitedSizeArray(config: config, defaultValue: WorkResult.dummy(config: config)), + results: try! ConfigLimitedSizeArray(config: config, defaultValue: WorkResult.dummy(config: config)) ) } } diff --git a/JAMTests/Tests/JAMTests/SafroleTests.swift b/JAMTests/Tests/JAMTests/SafroleTests.swift index 3ccc0482..eac9a25d 100644 --- a/JAMTests/Tests/JAMTests/SafroleTests.swift +++ b/JAMTests/Tests/JAMTests/SafroleTests.swift @@ -33,8 +33,6 @@ struct SafroleState: Equatable, Safrole, Codable { case ticketsVerifier } - let config: ProtocolConfigRef - // tau var timeslot: UInt32 // eta @@ -75,18 +73,6 @@ struct SafroleState: Equatable, Safrole, Codable { // gammaZ var ticketsVerifier: BandersnatchRingVRFRoot - public static func == (lhs: SafroleState, rhs: SafroleState) -> Bool { - lhs.timeslot == rhs.timeslot && - lhs.entropyPool == rhs.entropyPool && - lhs.previousValidators == rhs.previousValidators && - lhs.currentValidators == rhs.currentValidators && - lhs.nextValidators == rhs.nextValidators && - lhs.validatorQueue == rhs.validatorQueue && - lhs.ticketsAccumulator == rhs.ticketsAccumulator && - lhs.ticketsOrKeys == rhs.ticketsOrKeys && - lhs.ticketsVerifier == rhs.ticketsVerifier - } - public mutating func mergeWith(postState: SafrolePostState) { timeslot = postState.timeslot entropyPool = postState.entropyPool @@ -98,58 +84,20 @@ struct SafroleState: Equatable, Safrole, Codable { ticketsOrKeys = postState.ticketsOrKeys ticketsVerifier = postState.ticketsVerifier } - - public init(from decoder: Decoder) throws { - let container = try decoder.container(keyedBy: CodingKeys.self) - config = decoder.getConfig(ProtocolConfigRef.self)! - timeslot = try container.decode(UInt32.self, forKey: .timeslot) - entropyPool = try container.decode(EntropyPool.self, forKey: .entropyPool) - previousValidators = try container.decode(ConfigFixedSizeArray< - ValidatorKey, ProtocolConfig.TotalNumberOfValidators - >.self, forKey: .previousValidators) - currentValidators = try container.decode(ConfigFixedSizeArray< - ValidatorKey, ProtocolConfig.TotalNumberOfValidators - >.self, forKey: .currentValidators) - nextValidators = try container.decode(ConfigFixedSizeArray< - ValidatorKey, ProtocolConfig.TotalNumberOfValidators - >.self, forKey: .nextValidators) - validatorQueue = try container.decode(ConfigFixedSizeArray< - ValidatorKey, ProtocolConfig.TotalNumberOfValidators - >.self, forKey: .validatorQueue) - ticketsAccumulator = try container.decode(ConfigLimitedSizeArray< - Ticket, - ProtocolConfig.Int0, - ProtocolConfig.EpochLength - >.self, forKey: .ticketsAccumulator) - ticketsOrKeys = try container.decode(Either< - ConfigFixedSizeArray< - Ticket, - ProtocolConfig.EpochLength - >, - ConfigFixedSizeArray< - BandersnatchPublicKey, - ProtocolConfig.EpochLength - > - >.self, forKey: .ticketsOrKeys) - ticketsVerifier = try container.decode(BandersnatchRingVRFRoot.self, forKey: .ticketsVerifier) - } } -struct SafroleTestcase: CustomStringConvertible, Codable { - enum CodingKeys: String, CodingKey { - case input - case preState - case output - case postState - } - - var description: String = "" +struct SafroleTestcase: Codable { var input: SafroleInput var preState: SafroleState var output: Either var postState: SafroleState } +struct Testcase: CustomStringConvertible { + var description: String + var data: Data +} + enum SafroleTestVariants: String, CaseIterable { case tiny case full @@ -174,18 +122,20 @@ enum SafroleTestVariants: String, CaseIterable { } struct SafroleTests { - static func loadTests(variant: SafroleTestVariants) throws -> [SafroleTestcase] { + static func loadTests(variant: SafroleTestVariants) throws -> [Testcase] { let tests = try TestLoader.getTestFiles(path: "safrole/\(variant)", extension: "scale") - return try tests.map { - let data = try Data(contentsOf: URL(fileURLWithPath: $0.path)) - var testcase = try JamDecoder.decode(SafroleTestcase.self, from: data, withConfig: variant.config) - testcase.description = $0.description - return testcase + return try tests.map { path, description in + let data = try Data(contentsOf: URL(fileURLWithPath: path)) + return Testcase(description: description, data: data) } } - func safroleTests(_ testcase: SafroleTestcase) throws { + func safroleTests(_ input: Testcase, variant: SafroleTestVariants) throws { + let config = variant.config + let testcase = try JamDecoder.decode(SafroleTestcase.self, from: input.data, withConfig: config) + let result = testcase.preState.updateSafrole( + config: config, slot: testcase.input.slot, entropy: testcase.input.entropy, extrinsics: testcase.input.extrinsics @@ -213,13 +163,17 @@ struct SafroleTests { } } - // @Test(arguments: try SafroleTests.loadTests(variant: .tiny)) - // func tinyTests(_ testcase: SafroleTestcase) throws { - // try safroleTests(testcase) - // } + @Test(arguments: try SafroleTests.loadTests(variant: .tiny)) + func tinyTests(_ testcase: Testcase) throws { + withKnownIssue("wait for test vectors to be updated", isIntermittent: true) { + try safroleTests(testcase, variant: .tiny) + } + } - // @Test(arguments: try SafroleTests.loadTests(variant: .full)) - // func fullTests(_ testcase: SafroleTestcase) throws { - // try safroleTests(testcase) - // } + @Test(arguments: try SafroleTests.loadTests(variant: .full)) + func fullTests(_ testcase: Testcase) throws { + withKnownIssue("wait for test vectors to be updated", isIntermittent: true) { + try safroleTests(testcase, variant: .full) + } + } }