From bde54bdd13e1ecd0ed1e5d9a371faae43408e398 Mon Sep 17 00:00:00 2001 From: Xiliang Chen Date: Wed, 19 Jun 2024 21:38:46 +1200 Subject: [PATCH] add some scale codec support (#21) * add some scale codec support * implements codec --- .../Types/AvailabilitySpecifications.swift | 19 ++++ .../Sources/Blockchain/Types/Block.swift | 15 +++ .../Sources/Blockchain/Types/Extrinsic.swift | 21 +++++ .../Types/ExtrinsicAvailability.swift | 69 +++++++++++--- .../Types/ExtrinsicGuarantees.swift | 69 ++++++++++++-- .../Blockchain/Types/ExtrinsicJudgement.swift | 92 ++++++++++++++++--- .../Blockchain/Types/ExtrinsicPreimages.swift | 41 ++++++++- .../Blockchain/Types/ExtrinsicTickets.swift | 46 +++++++++- .../Sources/Blockchain/Types/Header.swift | 81 +++++++++++++--- .../Blockchain/Types/JudgementsState.swift | 17 ++++ .../Blockchain/Types/RefinementContext.swift | 17 ++++ .../Blockchain/Types/SafroleState.swift | 19 ++++ .../Blockchain/Types/ServiceAccount.swift | 54 ++++++++++- .../Sources/Blockchain/Types/State.swift | 89 ++++++++++++++---- .../Sources/Blockchain/Types/Ticket.swift | 27 ++++++ .../Blockchain/Types/ValidatorKey.swift | 19 ++++ .../Sources/Blockchain/Types/WorkReport.swift | 21 +++++ .../Sources/Blockchain/Types/WorkResult.swift | 28 ++++-- .../Blockchain/Types/WorkResultError.swift | 8 ++ .../Sources/Blockchain/Types/primitives.swift | 1 - Utils/Package.resolved | 24 +++++ Utils/Package.swift | 12 ++- Utils/Sources/Utils/Either.swift | 27 ++++++ Utils/Sources/Utils/FixedSizeData.swift | 11 +++ Utils/Sources/Utils/LimitedSizeArray.swift | 24 +++++ Utils/Sources/Utils/Ref.swift | 12 +++ 26 files changed, 773 insertions(+), 90 deletions(-) create mode 100644 Blockchain/Sources/Blockchain/Types/Ticket.swift create mode 100644 Blockchain/Sources/Blockchain/Types/WorkResultError.swift create mode 100644 Utils/Package.resolved diff --git a/Blockchain/Sources/Blockchain/Types/AvailabilitySpecifications.swift b/Blockchain/Sources/Blockchain/Types/AvailabilitySpecifications.swift index edf4432a..0153aa68 100644 --- a/Blockchain/Sources/Blockchain/Types/AvailabilitySpecifications.swift +++ b/Blockchain/Sources/Blockchain/Types/AvailabilitySpecifications.swift @@ -1,3 +1,4 @@ +import ScaleCodec import Utils public struct AvailabilitySpecifications { @@ -36,3 +37,21 @@ extension AvailabilitySpecifications: Dummy { ) } } + +extension AvailabilitySpecifications: ScaleCodec.Codable { + public init(from decoder: inout some ScaleCodec.Decoder) throws { + try self.init( + workPackageHash: decoder.decode(), + length: decoder.decode(), + erasureRoot: decoder.decode(), + segmentRoot: decoder.decode() + ) + } + + public func encode(in encoder: inout some ScaleCodec.Encoder) throws { + try encoder.encode(workPackageHash) + try encoder.encode(length) + try encoder.encode(erasureRoot) + try encoder.encode(segmentRoot) + } +} diff --git a/Blockchain/Sources/Blockchain/Types/Block.swift b/Blockchain/Sources/Blockchain/Types/Block.swift index 82d16b20..eb17e903 100644 --- a/Blockchain/Sources/Blockchain/Types/Block.swift +++ b/Blockchain/Sources/Blockchain/Types/Block.swift @@ -1,3 +1,4 @@ +import ScaleCodec import Utils public struct Block { @@ -20,3 +21,17 @@ extension Block: Dummy { ) } } + +extension Block: ScaleCodec.Codable { + public init(from decoder: inout some ScaleCodec.Decoder) throws { + try self.init( + header: decoder.decode(), + extrinsic: decoder.decode() + ) + } + + public func encode(in encoder: inout some ScaleCodec.Encoder) throws { + try encoder.encode(header) + try encoder.encode(extrinsic) + } +} diff --git a/Blockchain/Sources/Blockchain/Types/Extrinsic.swift b/Blockchain/Sources/Blockchain/Types/Extrinsic.swift index 3ba1f685..f6f91937 100644 --- a/Blockchain/Sources/Blockchain/Types/Extrinsic.swift +++ b/Blockchain/Sources/Blockchain/Types/Extrinsic.swift @@ -1,3 +1,4 @@ +import ScaleCodec import Utils public struct Extrinsic { @@ -44,3 +45,23 @@ extension Extrinsic: Dummy { ) } } + +extension Extrinsic: ScaleCodec.Codable { + public init(from decoder: inout some ScaleCodec.Decoder) throws { + try self.init( + tickets: decoder.decode(), + judgements: decoder.decode(), + preimages: decoder.decode(), + availability: decoder.decode(), + reports: decoder.decode() + ) + } + + public func encode(in encoder: inout some ScaleCodec.Encoder) throws { + try encoder.encode(tickets) + try encoder.encode(judgements) + try encoder.encode(preimages) + try encoder.encode(availability) + try encoder.encode(reports) + } +} diff --git a/Blockchain/Sources/Blockchain/Types/ExtrinsicAvailability.swift b/Blockchain/Sources/Blockchain/Types/ExtrinsicAvailability.swift index 57fbd472..b0b3c08d 100644 --- a/Blockchain/Sources/Blockchain/Types/ExtrinsicAvailability.swift +++ b/Blockchain/Sources/Blockchain/Types/ExtrinsicAvailability.swift @@ -1,22 +1,10 @@ import Foundation +import ScaleCodec import Utils public struct ExtrinsicAvailability { public typealias AssurancesList = LimitedSizeArray< - ( - // a - parentHash: H256, - - // f - assurance: Data, // bit string with length of Constants.TotalNumberOfCores - // TODO: use a BitString type - - // v - validatorIndex: ValidatorIndex, - - // s - signature: Ed25519Signature - ), + AssuranceItem, ConstInt0, Constants.TotalNumberOfValidators > @@ -35,3 +23,56 @@ extension ExtrinsicAvailability: Dummy { ExtrinsicAvailability(assurances: []) } } + +extension ExtrinsicAvailability: ScaleCodec.Codable { + public init(from decoder: inout some ScaleCodec.Decoder) throws { + try self.init( + assurances: decoder.decode() + ) + } + + public func encode(in encoder: inout some ScaleCodec.Encoder) throws { + try encoder.encode(assurances) + } +} + +public struct AssuranceItem { + // a + public var parentHash: H256 + // f + public var assurance: Data // bit string with length of Constants.TotalNumberOfCores TODO: use a BitString type + // v + public var validatorIndex: ValidatorIndex + // s + public var signature: Ed25519Signature + + public init( + parentHash: H256, + assurance: Data, + validatorIndex: ValidatorIndex, + signature: Ed25519Signature + ) { + self.parentHash = parentHash + self.assurance = assurance + self.validatorIndex = validatorIndex + self.signature = signature + } +} + +extension AssuranceItem: ScaleCodec.Codable { + public init(from decoder: inout some ScaleCodec.Decoder) throws { + try self.init( + parentHash: decoder.decode(), + assurance: decoder.decode(), + validatorIndex: decoder.decode(), + signature: decoder.decode() + ) + } + + public func encode(in encoder: inout some ScaleCodec.Encoder) throws { + try encoder.encode(parentHash) + try encoder.encode(assurance) + try encoder.encode(validatorIndex) + try encoder.encode(signature) + } +} diff --git a/Blockchain/Sources/Blockchain/Types/ExtrinsicGuarantees.swift b/Blockchain/Sources/Blockchain/Types/ExtrinsicGuarantees.swift index 16179690..02ef4832 100644 --- a/Blockchain/Sources/Blockchain/Types/ExtrinsicGuarantees.swift +++ b/Blockchain/Sources/Blockchain/Types/ExtrinsicGuarantees.swift @@ -1,17 +1,9 @@ +import ScaleCodec import Utils public struct ExtrinsicGuarantees { public typealias GuaranteesList = LimitedSizeArray< - ( - coreIndex: CoreIndex, - workReport: WorkReport, - timeslot: TimeslotIndex, - credential: LimitedSizeArray< - Ed25519Signature, - ConstInt2, - ConstInt3 - > - ), + GuaranteeItem, ConstInt0, Constants.TotalNumberOfCores > @@ -30,3 +22,60 @@ extension ExtrinsicGuarantees: Dummy { ExtrinsicGuarantees(guarantees: []) } } + +extension ExtrinsicGuarantees: ScaleCodec.Codable { + public init(from decoder: inout some ScaleCodec.Decoder) throws { + try self.init( + guarantees: decoder.decode() + ) + } + + public func encode(in encoder: inout some ScaleCodec.Encoder) throws { + try encoder.encode(guarantees) + } +} + +public struct GuaranteeItem { + public var coreIndex: CoreIndex + public var workReport: WorkReport + public var timeslot: TimeslotIndex + public var credential: LimitedSizeArray< + Ed25519Signature, + ConstInt2, + ConstInt3 + > + + public init( + coreIndex: CoreIndex, + workReport: WorkReport, + timeslot: TimeslotIndex, + credential: LimitedSizeArray< + Ed25519Signature, + ConstInt2, + ConstInt3 + > + ) { + self.coreIndex = coreIndex + self.workReport = workReport + self.timeslot = timeslot + self.credential = credential + } +} + +extension GuaranteeItem: ScaleCodec.Codable { + public init(from decoder: inout some ScaleCodec.Decoder) throws { + try self.init( + coreIndex: decoder.decode(), + workReport: decoder.decode(), + timeslot: decoder.decode(), + credential: decoder.decode() + ) + } + + public func encode(in encoder: inout some ScaleCodec.Encoder) throws { + try encoder.encode(coreIndex) + try encoder.encode(workReport) + try encoder.encode(timeslot) + try encoder.encode(credential) + } +} diff --git a/Blockchain/Sources/Blockchain/Types/ExtrinsicJudgement.swift b/Blockchain/Sources/Blockchain/Types/ExtrinsicJudgement.swift index 7bb0e6f0..ff763a2a 100644 --- a/Blockchain/Sources/Blockchain/Types/ExtrinsicJudgement.swift +++ b/Blockchain/Sources/Blockchain/Types/ExtrinsicJudgement.swift @@ -1,19 +1,8 @@ +import ScaleCodec import Utils public struct ExtrinsicJudgement { - public typealias JudgementsList = [ - ( - reportHash: H256, - signatures: FixedSizeArray< - ( - isValid: Bool, - validatorIndex: ValidatorIndex, - signature: BandersnatchSignature - ), - Constants.TwoThirdValidatorsPlusOne - > - ) - ] + public typealias JudgementsList = [JudgementItem] public var judgements: JudgementsList @@ -29,3 +18,80 @@ extension ExtrinsicJudgement: Dummy { ExtrinsicJudgement(judgements: []) } } + +extension ExtrinsicJudgement: ScaleCodec.Codable { + public init(from decoder: inout some ScaleCodec.Decoder) throws { + try self.init( + judgements: decoder.decode() + ) + } + + public func encode(in encoder: inout some ScaleCodec.Encoder) throws { + try encoder.encode(judgements) + } +} + +public struct JudgementItem { + public var reportHash: H256 + public var signatures: FixedSizeArray< + SignatureItem, + Constants.TwoThirdValidatorsPlusOne + > + + public init( + reportHash: H256, + signatures: FixedSizeArray< + SignatureItem, + Constants.TwoThirdValidatorsPlusOne + > + ) { + self.reportHash = reportHash + self.signatures = signatures + } + + public struct SignatureItem { + public var isValid: Bool + public var validatorIndex: ValidatorIndex + public var signature: BandersnatchSignature + + public init( + isValid: Bool, + validatorIndex: ValidatorIndex, + signature: BandersnatchSignature + ) { + self.isValid = isValid + self.validatorIndex = validatorIndex + self.signature = signature + } + } +} + +extension JudgementItem: ScaleCodec.Codable { + public init(from decoder: inout some ScaleCodec.Decoder) throws { + try self.init( + reportHash: decoder.decode(), + signatures: decoder.decode() + ) + } + + public func encode(in encoder: inout some ScaleCodec.Encoder) throws { + try encoder.encode(reportHash) + try encoder.encode(signatures) + } +} + +extension JudgementItem.SignatureItem: ScaleCodec.Codable { + public init(from decoder: inout some ScaleCodec.Decoder) throws { + try self.init( + isValid: decoder.decode(), + validatorIndex: decoder.decode(), + signature: decoder.decode() + ) + } + + public func encode(in encoder: inout some ScaleCodec.Encoder) throws { + try encoder.encode(isValid) + try encoder.encode(validatorIndex) + try encoder.encode(signature) + } +} diff --git a/Blockchain/Sources/Blockchain/Types/ExtrinsicPreimages.swift b/Blockchain/Sources/Blockchain/Types/ExtrinsicPreimages.swift index 3718ff9b..36762d48 100644 --- a/Blockchain/Sources/Blockchain/Types/ExtrinsicPreimages.swift +++ b/Blockchain/Sources/Blockchain/Types/ExtrinsicPreimages.swift @@ -1,11 +1,12 @@ import Foundation +import ScaleCodec import Utils public struct ExtrinsicPreimages { - public var preimages: [(size: DataLength, data: Data)] + public var preimages: [SizeAndData] public init( - preimages: [(size: DataLength, data: Data)] + preimages: [SizeAndData] ) { self.preimages = preimages } @@ -16,3 +17,39 @@ extension ExtrinsicPreimages: Dummy { ExtrinsicPreimages(preimages: []) } } + +extension ExtrinsicPreimages: ScaleCodec.Codable { + public init(from decoder: inout some ScaleCodec.Decoder) throws { + try self.init( + preimages: decoder.decode() + ) + } + + public func encode(in encoder: inout some ScaleCodec.Encoder) throws { + try encoder.encode(preimages) + } +} + +public struct SizeAndData { + public var size: DataLength + public var data: Data + + public init(size: DataLength, data: Data) { + self.size = size + self.data = data + } +} + +extension SizeAndData: ScaleCodec.Codable { + public init(from decoder: inout some ScaleCodec.Decoder) throws { + try self.init( + size: decoder.decode(), + data: decoder.decode() + ) + } + + public func encode(in encoder: inout some ScaleCodec.Encoder) throws { + try encoder.encode(size) + try encoder.encode(data) + } +} diff --git a/Blockchain/Sources/Blockchain/Types/ExtrinsicTickets.swift b/Blockchain/Sources/Blockchain/Types/ExtrinsicTickets.swift index 7d256149..e8da418e 100644 --- a/Blockchain/Sources/Blockchain/Types/ExtrinsicTickets.swift +++ b/Blockchain/Sources/Blockchain/Types/ExtrinsicTickets.swift @@ -1,12 +1,24 @@ +import ScaleCodec import Utils public struct ExtrinsicTickets { - public var tickets: [ - (ticketIndex: TicketIndex, proof: BandersnatchRintVRFProof) - ] + public struct TicketItem { + public var ticketIndex: TicketIndex + public var proof: BandersnatchRintVRFProof + + public init( + ticketIndex: TicketIndex, + proof: BandersnatchRintVRFProof + ) { + self.ticketIndex = ticketIndex + self.proof = proof + } + } + + public var tickets: [TicketItem] public init( - tickets: [(ticketIndex: TicketIndex, proof: BandersnatchRintVRFProof)] + tickets: [TicketItem] ) { self.tickets = tickets } @@ -17,3 +29,29 @@ extension ExtrinsicTickets: Dummy { ExtrinsicTickets(tickets: []) } } + +extension ExtrinsicTickets.TicketItem: ScaleCodec.Codable { + public init(from decoder: inout some ScaleCodec.Decoder) throws { + try self.init( + ticketIndex: decoder.decode(), + proof: decoder.decode() + ) + } + + public func encode(in encoder: inout some ScaleCodec.Encoder) throws { + try encoder.encode(ticketIndex) + try encoder.encode(proof) + } +} + +extension ExtrinsicTickets: ScaleCodec.Codable { + public init(from decoder: inout some ScaleCodec.Decoder) throws { + try self.init( + tickets: decoder.decode() + ) + } + + public func encode(in encoder: inout some ScaleCodec.Encoder) throws { + try encoder.encode(tickets) + } +} diff --git a/Blockchain/Sources/Blockchain/Types/Header.swift b/Blockchain/Sources/Blockchain/Types/Header.swift index 3e407c5e..fb0abe7e 100644 --- a/Blockchain/Sources/Blockchain/Types/Header.swift +++ b/Blockchain/Sources/Blockchain/Types/Header.swift @@ -1,6 +1,26 @@ +import ScaleCodec import Utils public struct Header { + public struct EpochMarker { + public var randomness: H256 + public var keys: FixedSizeArray< + BandersnatchPublicKey, + Constants.TotalNumberOfValidators + > + + public init( + randomness: H256, + keys: FixedSizeArray< + BandersnatchPublicKey, + Constants.TotalNumberOfValidators + > + ) { + self.randomness = randomness + self.keys = keys + } + } + // Hp: parent hash public var parentHash: H256 @@ -17,13 +37,7 @@ public struct Header { // 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: ( - randomness: H256, - keys: FixedSizeArray< - BandersnatchPublicKey, - Constants.TotalNumberOfValidators - > - )? + public var epoch: EpochMarker? // Hw: winning-tickets // The winning-tickets marker Hw is either empty or, @@ -52,14 +66,7 @@ public struct Header { priorStateRoot: H256, extrinsicsRoot: H256, timeslotIndex: TimeslotIndex, - epoch: ( - randomness: H256, - keys: LimitedSizeArray< - BandersnatchPublicKey, - Constants.TotalNumberOfValidators, - Constants.TotalNumberOfValidators - > - )?, + epoch: EpochMarker?, winningTickets: LimitedSizeArray< Ticket, Constants.EpochLength, @@ -100,6 +107,50 @@ extension Header: Dummy { } } +extension Header: ScaleCodec.Codable { + public init(from decoder: inout some ScaleCodec.Decoder) throws { + try self.init( + parentHash: decoder.decode(), + priorStateRoot: decoder.decode(), + extrinsicsRoot: decoder.decode(), + timeslotIndex: decoder.decode(), + epoch: decoder.decode(), + winningTickets: decoder.decode(), + judgementsMarkers: decoder.decode(), + authorKey: decoder.decode(), + vrfSignature: decoder.decode(), + seal: decoder.decode() + ) + } + + public func encode(in encoder: inout some ScaleCodec.Encoder) throws { + try encoder.encode(parentHash) + try encoder.encode(priorStateRoot) + try encoder.encode(extrinsicsRoot) + try encoder.encode(timeslotIndex) + try encoder.encode(epoch) + try encoder.encode(winningTickets) + try encoder.encode(judgementsMarkers) + try encoder.encode(authorKey) + try encoder.encode(vrfSignature) + try encoder.encode(seal) + } +} + +extension Header.EpochMarker: ScaleCodec.Codable { + public init(from decoder: inout some ScaleCodec.Decoder) throws { + try self.init( + randomness: decoder.decode(), + keys: decoder.decode() + ) + } + + public func encode(in encoder: inout some ScaleCodec.Encoder) throws { + try encoder.encode(randomness) + try encoder.encode(keys) + } +} + public extension Header { var hash: H256 { H256() // TODO: implement this diff --git a/Blockchain/Sources/Blockchain/Types/JudgementsState.swift b/Blockchain/Sources/Blockchain/Types/JudgementsState.swift index 6d693b67..dc56f04d 100644 --- a/Blockchain/Sources/Blockchain/Types/JudgementsState.swift +++ b/Blockchain/Sources/Blockchain/Types/JudgementsState.swift @@ -1,3 +1,4 @@ +import ScaleCodec import Utils public struct JudgementsState { @@ -32,3 +33,19 @@ extension JudgementsState: Dummy { ) } } + +extension JudgementsState: ScaleCodec.Codable { + public init(from decoder: inout some ScaleCodec.Decoder) throws { + try self.init( + allowSet: decoder.decode(), + banSet: decoder.decode(), + punishSet: decoder.decode() + ) + } + + public func encode(in encoder: inout some ScaleCodec.Encoder) throws { + try encoder.encode(allowSet) + try encoder.encode(banSet) + try encoder.encode(punishSet) + } +} diff --git a/Blockchain/Sources/Blockchain/Types/RefinementContext.swift b/Blockchain/Sources/Blockchain/Types/RefinementContext.swift index 121f3df5..3d076254 100644 --- a/Blockchain/Sources/Blockchain/Types/RefinementContext.swift +++ b/Blockchain/Sources/Blockchain/Types/RefinementContext.swift @@ -1,3 +1,4 @@ +import ScaleCodec import Utils // A refinement context, denoted by the set X, describes the context of the chain @@ -50,3 +51,19 @@ extension RefinementContext: Dummy { ) } } + +extension RefinementContext: ScaleCodec.Codable { + public init(from decoder: inout some ScaleCodec.Decoder) throws { + try self.init( + anchor: decoder.decode(), + lokupAnchor: decoder.decode(), + prerequistieWorkPackage: decoder.decode() + ) + } + + public func encode(in encoder: inout some ScaleCodec.Encoder) throws { + try encoder.encode(anchor) + try encoder.encode(lokupAnchor) + try encoder.encode(prerequistieWorkPackage) + } +} diff --git a/Blockchain/Sources/Blockchain/Types/SafroleState.swift b/Blockchain/Sources/Blockchain/Types/SafroleState.swift index 4ba508c5..3048fb08 100644 --- a/Blockchain/Sources/Blockchain/Types/SafroleState.swift +++ b/Blockchain/Sources/Blockchain/Types/SafroleState.swift @@ -1,3 +1,4 @@ +import ScaleCodec import Utils public struct SafroleState { @@ -66,3 +67,21 @@ extension SafroleState: Dummy { ) } } + +extension SafroleState: ScaleCodec.Codable { + public init(from decoder: inout some ScaleCodec.Decoder) throws { + try self.init( + pendingValidators: decoder.decode(), + epochRoot: decoder.decode(), + slotSealerSeries: decoder.decode(), + ticketAccumulator: decoder.decode() + ) + } + + public func encode(in encoder: inout some ScaleCodec.Encoder) throws { + try encoder.encode(pendingValidators) + try encoder.encode(epochRoot) + try encoder.encode(slotSealerSeries) + try encoder.encode(ticketAccumulator) + } +} diff --git a/Blockchain/Sources/Blockchain/Types/ServiceAccount.swift b/Blockchain/Sources/Blockchain/Types/ServiceAccount.swift index fcf31957..447b11e2 100644 --- a/Blockchain/Sources/Blockchain/Types/ServiceAccount.swift +++ b/Blockchain/Sources/Blockchain/Types/ServiceAccount.swift @@ -1,7 +1,18 @@ import Foundation +import ScaleCodec import Utils public struct ServiceAccount { + public struct HashAndLength: Hashable { + public var hash: H256 + public var length: DataLength + + public init(hash: H256, length: DataLength) { + self.hash = hash + self.length = length + } + } + // s public var storage: [H256: Data] @@ -44,11 +55,6 @@ public struct ServiceAccount { } } -public struct HashAndLength: Hashable { - public var hash: H256 - public var length: DataLength -} - extension ServiceAccount: Dummy { public static var dummy: ServiceAccount { ServiceAccount( @@ -62,3 +68,41 @@ extension ServiceAccount: Dummy { ) } } + +extension ServiceAccount.HashAndLength: ScaleCodec.Codable { + public init(from decoder: inout some ScaleCodec.Decoder) throws { + try self.init( + hash: decoder.decode(), + length: decoder.decode() + ) + } + + public func encode(in encoder: inout some ScaleCodec.Encoder) throws { + try encoder.encode(hash) + try encoder.encode(length) + } +} + +extension ServiceAccount: ScaleCodec.Codable { + public init(from decoder: inout some ScaleCodec.Decoder) throws { + try self.init( + storage: decoder.decode(), + preimages: decoder.decode(), + preimageInfos: decoder.decode(), + codeHash: decoder.decode(), + balance: decoder.decode(), + accumlateGasLimit: decoder.decode(), + onTransferGasLimit: decoder.decode() + ) + } + + public func encode(in encoder: inout some ScaleCodec.Encoder) throws { + try encoder.encode(storage) + try encoder.encode(preimages) + try encoder.encode(preimageInfos) + try encoder.encode(codeHash) + try encoder.encode(balance) + try encoder.encode(accumlateGasLimit) + try encoder.encode(onTransferGasLimit) + } +} diff --git a/Blockchain/Sources/Blockchain/Types/State.swift b/Blockchain/Sources/Blockchain/Types/State.swift index fab9d0d3..145002fd 100644 --- a/Blockchain/Sources/Blockchain/Types/State.swift +++ b/Blockchain/Sources/Blockchain/Types/State.swift @@ -1,6 +1,23 @@ +import ScaleCodec import Utils public struct State { + public struct ReportItem { + public var workReport: WorkReport + public var guarantors: LimitedSizeArray + public var timestamp: TimeslotIndex + + public init( + workReport: WorkReport, + guarantors: LimitedSizeArray, + timestamp: TimeslotIndex + ) { + self.workReport = workReport + self.guarantors = guarantors + self.timestamp = timestamp + } + } + // α: The core αuthorizations pool. public var coreAuthorizationPool: FixedSizeArray< LimitedSizeArray< @@ -40,15 +57,7 @@ public struct State { // ρ: The ρending reports, per core, which are being made available prior to accumulation. public var reports: FixedSizeArray< - ( - workReport: WorkReport, - guarantors: LimitedSizeArray< - Ed25519PublicKey, - ConstInt2, - ConstInt3 - >, - timestamp: TimeslotIndex - )?, + ReportItem?, Constants.TotalNumberOfCores > @@ -97,15 +106,7 @@ public struct State { ValidatorKey, Constants.TotalNumberOfValidators >, reports: FixedSizeArray< - ( - workReport: WorkReport, - guarantors: LimitedSizeArray< - Ed25519PublicKey, - ConstInt2, - ConstInt3 - >, - timestamp: TimeslotIndex - )?, + ReportItem?, Constants.TotalNumberOfCores >, timestamp: TimeslotIndex, @@ -165,6 +166,58 @@ extension State: Dummy { } } +extension State.ReportItem: ScaleCodec.Codable { + public init(from decoder: inout some ScaleCodec.Decoder) throws { + try self.init( + workReport: decoder.decode(), + guarantors: decoder.decode(), + timestamp: decoder.decode() + ) + } + + public func encode(in encoder: inout some ScaleCodec.Encoder) throws { + try encoder.encode(workReport) + try encoder.encode(guarantors) + try encoder.encode(timestamp) + } +} + +extension State: ScaleCodec.Codable { + public init(from decoder: inout some ScaleCodec.Decoder) throws { + try self.init( + coreAuthorizationPool: decoder.decode(), + lastBlock: decoder.decode(), + safroleState: decoder.decode(), + serviceAccounts: decoder.decode(), + entropyPool: decoder.decode(), + validatorQueue: decoder.decode(), + currentValidators: decoder.decode(), + previousValidators: decoder.decode(), + reports: decoder.decode(), + timestamp: decoder.decode(), + authorizationQueue: decoder.decode(), + privilegedServiceIndices: decoder.decode(), + judgements: decoder.decode() + ) + } + + public func encode(in encoder: inout some ScaleCodec.Encoder) throws { + try encoder.encode(coreAuthorizationPool) + try encoder.encode(lastBlock) + try encoder.encode(safroleState) + try encoder.encode(serviceAccounts) + try encoder.encode(entropyPool) + try encoder.encode(validatorQueue) + try encoder.encode(currentValidators) + try encoder.encode(previousValidators) + try encoder.encode(reports) + try encoder.encode(timestamp) + try encoder.encode(authorizationQueue) + try encoder.encode(privilegedServiceIndices) + try encoder.encode(judgements) + } +} + public extension State { func update(with block: Block) -> State { let state = State( diff --git a/Blockchain/Sources/Blockchain/Types/Ticket.swift b/Blockchain/Sources/Blockchain/Types/Ticket.swift new file mode 100644 index 00000000..842d9712 --- /dev/null +++ b/Blockchain/Sources/Blockchain/Types/Ticket.swift @@ -0,0 +1,27 @@ +import ScaleCodec +import Utils + +public struct Ticket { + public var identifier: H256 + public var entryIndex: TicketIndex +} + +extension Ticket: Dummy { + public static var dummy: Ticket { + Ticket(identifier: H256(), entryIndex: 0) + } +} + +extension Ticket: ScaleCodec.Codable { + public init(from decoder: inout some ScaleCodec.Decoder) throws { + try self.init( + identifier: decoder.decode(), + entryIndex: decoder.decode() + ) + } + + public func encode(in encoder: inout some ScaleCodec.Encoder) throws { + try encoder.encode(identifier) + try encoder.encode(entryIndex) + } +} diff --git a/Blockchain/Sources/Blockchain/Types/ValidatorKey.swift b/Blockchain/Sources/Blockchain/Types/ValidatorKey.swift index d9e962d4..dd9d5ed7 100644 --- a/Blockchain/Sources/Blockchain/Types/ValidatorKey.swift +++ b/Blockchain/Sources/Blockchain/Types/ValidatorKey.swift @@ -1,3 +1,4 @@ +import ScaleCodec import Utils public struct ValidatorKey { @@ -29,3 +30,21 @@ extension ValidatorKey: Dummy { ) } } + +extension ValidatorKey: ScaleCodec.Codable { + public init(from decoder: inout some ScaleCodec.Decoder) throws { + try self.init( + bandersnatchKey: decoder.decode(), + ed25519Key: decoder.decode(), + blsKey: decoder.decode(), + metadata: decoder.decode() + ) + } + + public func encode(in encoder: inout some ScaleCodec.Encoder) throws { + try encoder.encode(bandersnatchKey) + try encoder.encode(ed25519Key) + try encoder.encode(blsKey) + try encoder.encode(metadata) + } +} diff --git a/Blockchain/Sources/Blockchain/Types/WorkReport.swift b/Blockchain/Sources/Blockchain/Types/WorkReport.swift index a002574e..9ff7136e 100644 --- a/Blockchain/Sources/Blockchain/Types/WorkReport.swift +++ b/Blockchain/Sources/Blockchain/Types/WorkReport.swift @@ -1,4 +1,5 @@ import Foundation +import ScaleCodec import Utils public struct WorkReport { @@ -51,3 +52,23 @@ extension WorkReport: Dummy { ) } } + +extension WorkReport: ScaleCodec.Codable { + public init(from decoder: inout some ScaleCodec.Decoder) throws { + try self.init( + authorizerHash: decoder.decode(), + output: decoder.decode(), + refinementContext: decoder.decode(), + packageSpecification: decoder.decode(), + results: decoder.decode() + ) + } + + public func encode(in encoder: inout some ScaleCodec.Encoder) throws { + try encoder.encode(authorizerHash) + try encoder.encode(output) + try encoder.encode(refinementContext) + try encoder.encode(packageSpecification) + try encoder.encode(results) + } +} diff --git a/Blockchain/Sources/Blockchain/Types/WorkResult.swift b/Blockchain/Sources/Blockchain/Types/WorkResult.swift index 0b32080d..05b61ae8 100644 --- a/Blockchain/Sources/Blockchain/Types/WorkResult.swift +++ b/Blockchain/Sources/Blockchain/Types/WorkResult.swift @@ -1,4 +1,5 @@ import Foundation +import ScaleCodec import Utils public struct WorkResult { @@ -34,13 +35,6 @@ public struct WorkResult { } } -public enum WorkResultError: Error { - case outofGas - case panic - case invalidCode - case codeTooLarge // code larger than MaxServiceCodeSize -} - extension WorkResult: Dummy { public static var dummy: WorkResult { WorkResult( @@ -52,3 +46,23 @@ extension WorkResult: Dummy { ) } } + +extension WorkResult: ScaleCodec.Codable { + public init(from decoder: inout some ScaleCodec.Decoder) throws { + try self.init( + serviceIdentifier: decoder.decode(), + codeHash: decoder.decode(), + payloadHash: decoder.decode(), + gas: decoder.decode(), + output: decoder.decode() + ) + } + + public func encode(in encoder: inout some ScaleCodec.Encoder) throws { + try encoder.encode(serviceIdentifier) + try encoder.encode(codeHash) + try encoder.encode(payloadHash) + try encoder.encode(gas) + try encoder.encode(output) + } +} diff --git a/Blockchain/Sources/Blockchain/Types/WorkResultError.swift b/Blockchain/Sources/Blockchain/Types/WorkResultError.swift new file mode 100644 index 00000000..3e29f96a --- /dev/null +++ b/Blockchain/Sources/Blockchain/Types/WorkResultError.swift @@ -0,0 +1,8 @@ +import ScaleCodec + +public enum WorkResultError: Error, CaseIterable, ScaleCodec.Codable { + case outofGas + case panic + case invalidCode + case codeTooLarge // code larger than MaxServiceCodeSize +} diff --git a/Blockchain/Sources/Blockchain/Types/primitives.swift b/Blockchain/Sources/Blockchain/Types/primitives.swift index bf1fcf13..2dc82520 100644 --- a/Blockchain/Sources/Blockchain/Types/primitives.swift +++ b/Blockchain/Sources/Blockchain/Types/primitives.swift @@ -4,7 +4,6 @@ public typealias Balances = UInt64 public typealias H256 = Data32 public typealias ServiceIdentifier = H256 public typealias TimeslotIndex = UInt32 -public typealias Ticket = (identifier: H256, entryIndex: TicketIndex) public typealias Gas = UInt64 public typealias DataLength = UInt32 public typealias ValidatorIndex = UInt32 // TODO: confirm this diff --git a/Utils/Package.resolved b/Utils/Package.resolved new file mode 100644 index 00000000..52ec90a0 --- /dev/null +++ b/Utils/Package.resolved @@ -0,0 +1,24 @@ +{ + "originHash" : "7e6e33157836e05375f90c70184331ac5884a4dc78788ca4ae9e201bcdf8dfed", + "pins" : [ + { + "identity" : "scalecodec.swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/tesseract-one/ScaleCodec.swift.git", + "state" : { + "revision" : "af241cfa8491ac0312ff89ff0389c09879d41a74", + "version" : "0.3.1" + } + }, + { + "identity" : "tuples.swift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/tesseract-one/Tuples.swift.git", + "state" : { + "revision" : "4d2cf7c64443cdf4df833d0bedd767bf9dbc49d9", + "version" : "0.1.3" + } + } + ], + "version" : 3 +} diff --git a/Utils/Package.swift b/Utils/Package.swift index e4de0d29..8daa1c93 100644 --- a/Utils/Package.swift +++ b/Utils/Package.swift @@ -5,6 +5,9 @@ import PackageDescription let package = Package( name: "Utils", + platforms: [ + .macOS(.v14), + ], products: [ // Products define the executables and libraries a package produces, making them visible to other packages. .library( @@ -12,11 +15,18 @@ let package = Package( targets: ["Utils"] ), ], + dependencies: [ + .package(url: "https://github.com/tesseract-one/ScaleCodec.swift.git", from: "0.3.0"), + ], targets: [ // Targets are the basic building blocks of a package, defining a module or a test suite. // Targets can depend on other targets in this package and products from dependencies. .target( - name: "Utils"), + name: "Utils", + dependencies: [ + .product(name: "ScaleCodec", package: "ScaleCodec.swift"), + ] + ), .testTarget( name: "UtilsTests", dependencies: ["Utils"] diff --git a/Utils/Sources/Utils/Either.swift b/Utils/Sources/Utils/Either.swift index c5927845..09ecf79a 100644 --- a/Utils/Sources/Utils/Either.swift +++ b/Utils/Sources/Utils/Either.swift @@ -1,3 +1,5 @@ +import ScaleCodec + public enum Either { case left(A) case right(B) @@ -15,3 +17,28 @@ extension Either: CustomStringConvertible where A: CustomStringConvertible, B: C } } } + +extension Either: ScaleCodec.Codable where A: ScaleCodec.Codable, B: ScaleCodec.Codable { + public init(from decoder: inout some ScaleCodec.Decoder) throws { + let id = try decoder.decode(.enumCaseId) + switch id { + case 0: + self = try .left(A(from: &decoder)) + case 1: + self = try .right(B(from: &decoder)) + default: + throw decoder.enumCaseError(for: id) + } + } + + public func encode(in encoder: inout some ScaleCodec.Encoder) throws { + switch self { + case let .left(a): + try encoder.encode(0, .enumCaseId) + try a.encode(in: &encoder) + case let .right(b): + try encoder.encode(1, .enumCaseId) + try b.encode(in: &encoder) + } + } +} diff --git a/Utils/Sources/Utils/FixedSizeData.swift b/Utils/Sources/Utils/FixedSizeData.swift index 40308472..ed511b2f 100644 --- a/Utils/Sources/Utils/FixedSizeData.swift +++ b/Utils/Sources/Utils/FixedSizeData.swift @@ -1,4 +1,5 @@ import Foundation +import ScaleCodec public struct FixedSizeData { public private(set) var data: Data @@ -27,6 +28,16 @@ extension FixedSizeData: CustomStringConvertible, CustomDebugStringConvertible { } } +extension FixedSizeData: ScaleCodec.Codable { + public init(from decoder: inout some ScaleCodec.Decoder) throws { + try self.init(decoder.decode(Data.self, .fixed(UInt(T.value))))! + } + + public func encode(in encoder: inout some ScaleCodec.Encoder) throws { + try encoder.encode(data, .fixed(UInt(T.value))) + } +} + public typealias Data32 = FixedSizeData public typealias Data64 = FixedSizeData public typealias Data96 = FixedSizeData diff --git a/Utils/Sources/Utils/LimitedSizeArray.swift b/Utils/Sources/Utils/LimitedSizeArray.swift index b9f97ec0..281983c8 100644 --- a/Utils/Sources/Utils/LimitedSizeArray.swift +++ b/Utils/Sources/Utils/LimitedSizeArray.swift @@ -1,3 +1,5 @@ +import ScaleCodec + // TODO: add tests public struct LimitedSizeArray { @@ -115,3 +117,25 @@ public extension LimitedSizeArray { } public typealias FixedSizeArray = LimitedSizeArray + +extension LimitedSizeArray: ScaleCodec.Codable where T: ScaleCodec.Codable { + public init(from decoder: inout some ScaleCodec.Decoder) throws { + if TMinLength.value == TMaxLength.value { + // fixed size array + try self.init(decoder.decode(.fixed(UInt(TMinLength.value)))) + } else { + // variable size array + try self.init(decoder.decode()) + } + } + + public func encode(in encoder: inout some ScaleCodec.Encoder) throws { + if TMinLength.value == TMaxLength.value { + // fixed size array + try encoder.encode(array, .fixed(UInt(TMinLength.value))) + } else { + // variable size array + try encoder.encode(array) + } + } +} diff --git a/Utils/Sources/Utils/Ref.swift b/Utils/Sources/Utils/Ref.swift index 275527f0..34643b5a 100644 --- a/Utils/Sources/Utils/Ref.swift +++ b/Utils/Sources/Utils/Ref.swift @@ -1,3 +1,5 @@ +import ScaleCodec + public final class Ref { public let value: T @@ -35,3 +37,13 @@ extension Ref: Dummy where T: Dummy { Ref(T.dummy) } } + +extension Ref: ScaleCodec.Codable where T: ScaleCodec.Codable { + public convenience init(from decoder: inout some ScaleCodec.Decoder) throws { + try self.init(decoder.decode()) + } + + public func encode(in encoder: inout some ScaleCodec.Encoder) throws { + try encoder.encode(value) + } +}