diff --git a/.swiftformat b/.swiftformat new file mode 100644 index 00000000..03a75a59 --- /dev/null +++ b/.swiftformat @@ -0,0 +1,2 @@ +--extensionacl on-declarations +--maxwidth 150 diff --git a/.swiftlint.yml b/.swiftlint.yml index 53e4ad07..24cff430 100644 --- a/.swiftlint.yml +++ b/.swiftlint.yml @@ -2,9 +2,17 @@ disabled_rules: - trailing_comma - todo - large_tuple + - file_length + - nesting + - opening_brace excluded: - "**/.build" identifier_name: min_length: 1 + +line_length: + warning: 140 + error: 140 + ignores_function_declarations: true diff --git a/Blockchain/Sources/Blockchain/BlockAuthor.swift b/Blockchain/Sources/Blockchain/BlockAuthor.swift new file mode 100644 index 00000000..a77993ad --- /dev/null +++ b/Blockchain/Sources/Blockchain/BlockAuthor.swift @@ -0,0 +1 @@ +public class BlockAuthor {} diff --git a/Blockchain/Sources/Blockchain/Blockchain.swift b/Blockchain/Sources/Blockchain/Blockchain.swift index ed16e611..08af4939 100644 --- a/Blockchain/Sources/Blockchain/Blockchain.swift +++ b/Blockchain/Sources/Blockchain/Blockchain.swift @@ -39,12 +39,12 @@ public class Blockchain { } } -public extension Blockchain { - subscript(hash: H256) -> StateRef? { +extension Blockchain { + public subscript(hash: H256) -> StateRef? { stateByBlockHash[hash] } - subscript(index: TimeslotIndex) -> [StateRef]? { + public subscript(index: TimeslotIndex) -> [StateRef]? { stateByTimeslot[index] } } diff --git a/Blockchain/Sources/Blockchain/Config/ProtocolConfig+Preset.swift b/Blockchain/Sources/Blockchain/Config/ProtocolConfig+Preset.swift new file mode 100644 index 00000000..dc249393 --- /dev/null +++ b/Blockchain/Sources/Blockchain/Config/ProtocolConfig+Preset.swift @@ -0,0 +1,78 @@ +import Utils + +extension Ref where T == ProtocolConfig { + // TODO: pick some good numbers for dev env + public static let dev = Ref(ProtocolConfig( + auditTranchePeriod: 8, + additionalMinBalancePerStateItem: 10, + additionalMinBalancePerStateByte: 1, + serviceMinBalance: 100, + totalNumberOfCores: 341, + preimagePurgePeriod: 28800, + epochLength: 600, + auditBiasFactor: 2, + coreAccumulationGas: 10_000_000, // TODO: check this + workPackageAuthorizerGas: 10_000_000, // TODO: check this + workPackageRefineGas: 10_000_000, // TODO: check this + recentHistorySize: 8, + maxWorkItems: 4, + maxTicketsPerExtrinsic: 16, + maxLookupAnchorAge: 14400, + transferMemoSize: 128, + ticketEntriesPerValidator: 2, + maxAuthorizationsPoolItems: 8, + slotPeriodSeconds: 6, + maxAuthorizationsQueueItems: 80, + coreAssignmentRotationPeriod: 10, + maxServiceCodeSize: 4_000_000, + preimageReplacementPeriod: 5, + totalNumberOfValidators: 1023, + erasureCodedPieceSize: 684, + maxWorkPackageManifestEntries: 1 << 11, + maxEncodedWorkPackageSize: 12 * 1 << 20, + maxEncodedWorkReportSize: 96 * 1 << 10, + erasureCodedSegmentSize: 6, + ticketSubmissionEndSlot: 500, + pvmDynamicAddressAlignmentFactor: 4, + pvmProgramInitInputDataSize: 1 << 24, + pvmProgramInitPageSize: 1 << 14, + pvmProgramInitSegmentSize: 1 << 16 + )) + + public static let mainnet = Ref(ProtocolConfig( + auditTranchePeriod: 8, + additionalMinBalancePerStateItem: 10, + additionalMinBalancePerStateByte: 1, + serviceMinBalance: 100, + totalNumberOfCores: 341, + preimagePurgePeriod: 28800, + epochLength: 600, + auditBiasFactor: 2, + coreAccumulationGas: 10_000_000, // TODO: check this + workPackageAuthorizerGas: 10_000_000, // TODO: check this + workPackageRefineGas: 10_000_000, // TODO: check this + recentHistorySize: 8, + maxWorkItems: 4, + maxTicketsPerExtrinsic: 16, + maxLookupAnchorAge: 14400, + transferMemoSize: 128, + ticketEntriesPerValidator: 2, + maxAuthorizationsPoolItems: 8, + slotPeriodSeconds: 6, + maxAuthorizationsQueueItems: 80, + coreAssignmentRotationPeriod: 10, + maxServiceCodeSize: 4_000_000, + preimageReplacementPeriod: 5, + totalNumberOfValidators: 1023, + erasureCodedPieceSize: 684, + maxWorkPackageManifestEntries: 1 << 11, + maxEncodedWorkPackageSize: 12 * 1 << 20, + maxEncodedWorkReportSize: 96 * 1 << 10, + erasureCodedSegmentSize: 6, + ticketSubmissionEndSlot: 500, + pvmDynamicAddressAlignmentFactor: 4, + pvmProgramInitInputDataSize: 1 << 24, + pvmProgramInitPageSize: 1 << 14, + pvmProgramInitSegmentSize: 1 << 16 + )) +} diff --git a/Blockchain/Sources/Blockchain/Config/ProtocolConfig.swift b/Blockchain/Sources/Blockchain/Config/ProtocolConfig.swift new file mode 100644 index 00000000..1fa829db --- /dev/null +++ b/Blockchain/Sources/Blockchain/Config/ProtocolConfig.swift @@ -0,0 +1,431 @@ +import Utils + +// constants defined in the graypaper +public struct ProtocolConfig { + // A = 8: The period, in seconds, between audit tranches. + public var auditTranchePeriod: Int + + // BI = 10: The additional minimum balance required per item of elective service state. + public var additionalMinBalancePerStateItem: Int + + // BL = 1: The additional minimum balance required per octet of elective service state. + public var additionalMinBalancePerStateByte: Int + + // BS = 100: The basic minimum balance which all services require. + public var serviceMinBalance: Int + + // C = 341: The total number of cores. + public var totalNumberOfCores: Int + + // D = 28, 800: The period in timeslots after which an unreferenced preimage may be expunged. + public var preimagePurgePeriod: Int + + // E = 600: The length of an epoch in timeslots. + public var epochLength: Int + + // F = 2: The audit bias factor, the expected number of additional validators who will audit a work-report in the + // following tranche for each no-show in the previous. + public var auditBiasFactor: Int + + // GA: The total gas allocated to a core for Accumulation. + public var coreAccumulationGas: Int + + // GI: The gas allocated to invoke a work-package’s Is-Authorized logic. + public var workPackageAuthorizerGas: Int + + // GR: The total gas allocated for a work-package’s Refine logic. + public var workPackageRefineGas: Int + + // H = 8: The size of recent history, in blocks. + public var recentHistorySize: Int + + // I = 4: The maximum amount of work items in a package. + public var maxWorkItems: Int + + // K = 16: The maximum number of tickets which may be submitted in a single extrinsic. + public var maxTicketsPerExtrinsic: Int + + // L = 14, 400: The maximum age in timeslots of the lookup anchor. + public var maxLookupAnchorAge: Int + + // M = 128: The size of a transfer memo in octets. + public var transferMemoSize: Int + + // N = 2: The number of ticket entries per validator. + public var ticketEntriesPerValidator: Int + + // O = 8: The maximum number of items in the authorizations pool. + public var maxAuthorizationsPoolItems: Int + + // P = 6: The slot period, in seconds. + public var slotPeriodSeconds: Int + + // Q = 80: The maximum number of items in the authorizations queue. + public var maxAuthorizationsQueueItems: Int + + // R = 10: The rotation period of validator-core assignments, in timeslots. + public var coreAssignmentRotationPeriod: Int + + // S = 4,000,000: The maximum size of service code in octets. + public var maxServiceCodeSize: Int + + // U = 5: The period in timeslots after which reported but unavailable work may be replaced. + public var preimageReplacementPeriod: Int + + // V = 1023: The total number of validators. + public var totalNumberOfValidators: Int + + // WC = 684: The basic size of our erasure-coded pieces. + public var erasureCodedPieceSize: Int + + // WM = 2^11: The maximum number of entries in a work-package manifest. + public var maxWorkPackageManifestEntries: Int + + // WP = 12 * 2^20: The maximum size of an encoded work-package together with its extrinsic data and import impli- + // cations, in octets. + public var maxEncodedWorkPackageSize: Int + + // WR = 96 * 2^10: The maximum size of an encoded work-report in octets. + public var maxEncodedWorkReportSize: Int + + // WS = 6: The size of an exported segment in erasure-coded pieces. + public var erasureCodedSegmentSize: Int + + // Y = 500: The number of slots into an epoch at which ticket-submission ends. + public var ticketSubmissionEndSlot: Int + + // ZA = 4: The pvm dynamic address alignment factor. + public var pvmDynamicAddressAlignmentFactor: Int + + // ZI = 2^24: The standard pvm program initialization input data size. + public var pvmProgramInitInputDataSize: Int + + // ZP = 2^14: The standard pvm program initialization page size. + public var pvmProgramInitPageSize: Int + + // ZQ = 2^16: The standard pvm program initialization segment size. + public var pvmProgramInitSegmentSize: Int + + public init( + auditTranchePeriod: Int, + additionalMinBalancePerStateItem: Int, + additionalMinBalancePerStateByte: Int, + serviceMinBalance: Int, + totalNumberOfCores: Int, + preimagePurgePeriod: Int, + epochLength: Int, + auditBiasFactor: Int, + coreAccumulationGas: Int, + workPackageAuthorizerGas: Int, + workPackageRefineGas: Int, + recentHistorySize: Int, + maxWorkItems: Int, + maxTicketsPerExtrinsic: Int, + maxLookupAnchorAge: Int, + transferMemoSize: Int, + ticketEntriesPerValidator: Int, + maxAuthorizationsPoolItems: Int, + slotPeriodSeconds: Int, + maxAuthorizationsQueueItems: Int, + coreAssignmentRotationPeriod: Int, + maxServiceCodeSize: Int, + preimageReplacementPeriod: Int, + totalNumberOfValidators: Int, + erasureCodedPieceSize: Int, + maxWorkPackageManifestEntries: Int, + maxEncodedWorkPackageSize: Int, + maxEncodedWorkReportSize: Int, + erasureCodedSegmentSize: Int, + ticketSubmissionEndSlot: Int, + pvmDynamicAddressAlignmentFactor: Int, + pvmProgramInitInputDataSize: Int, + pvmProgramInitPageSize: Int, + pvmProgramInitSegmentSize: Int + ) { + self.auditTranchePeriod = auditTranchePeriod + self.additionalMinBalancePerStateItem = additionalMinBalancePerStateItem + self.additionalMinBalancePerStateByte = additionalMinBalancePerStateByte + self.serviceMinBalance = serviceMinBalance + self.totalNumberOfCores = totalNumberOfCores + self.preimagePurgePeriod = preimagePurgePeriod + self.epochLength = epochLength + self.auditBiasFactor = auditBiasFactor + self.coreAccumulationGas = coreAccumulationGas + self.workPackageAuthorizerGas = workPackageAuthorizerGas + self.workPackageRefineGas = workPackageRefineGas + self.recentHistorySize = recentHistorySize + self.maxWorkItems = maxWorkItems + self.maxTicketsPerExtrinsic = maxTicketsPerExtrinsic + self.maxLookupAnchorAge = maxLookupAnchorAge + self.transferMemoSize = transferMemoSize + self.ticketEntriesPerValidator = ticketEntriesPerValidator + self.maxAuthorizationsPoolItems = maxAuthorizationsPoolItems + self.slotPeriodSeconds = slotPeriodSeconds + self.maxAuthorizationsQueueItems = maxAuthorizationsQueueItems + self.coreAssignmentRotationPeriod = coreAssignmentRotationPeriod + self.maxServiceCodeSize = maxServiceCodeSize + self.preimageReplacementPeriod = preimageReplacementPeriod + self.totalNumberOfValidators = totalNumberOfValidators + self.erasureCodedPieceSize = erasureCodedPieceSize + self.maxWorkPackageManifestEntries = maxWorkPackageManifestEntries + self.maxEncodedWorkPackageSize = maxEncodedWorkPackageSize + self.maxEncodedWorkReportSize = maxEncodedWorkReportSize + self.erasureCodedSegmentSize = erasureCodedSegmentSize + self.ticketSubmissionEndSlot = ticketSubmissionEndSlot + self.pvmDynamicAddressAlignmentFactor = pvmDynamicAddressAlignmentFactor + self.pvmProgramInitInputDataSize = pvmProgramInitInputDataSize + self.pvmProgramInitPageSize = pvmProgramInitPageSize + self.pvmProgramInitSegmentSize = pvmProgramInitSegmentSize + } +} + +public typealias ProtocolConfigRef = Ref + +extension ProtocolConfig { + public enum AuditTranchePeriod: ReadInt { + public typealias TConfig = ProtocolConfigRef + public static func read(config: ProtocolConfigRef) -> Int { + config.value.auditTranchePeriod + } + } + + public enum AdditionalMinBalancePerStateItem: ReadInt { + public typealias TConfig = ProtocolConfigRef + public static func read(config: ProtocolConfigRef) -> Int { + config.value.additionalMinBalancePerStateItem + } + } + + public enum AdditionalMinBalancePerStateByte: ReadInt { + public typealias TConfig = ProtocolConfigRef + public static func read(config: ProtocolConfigRef) -> Int { + config.value.additionalMinBalancePerStateByte + } + } + + public enum ServiceMinBalance: ReadInt { + public typealias TConfig = ProtocolConfigRef + public static func read(config: ProtocolConfigRef) -> Int { + config.value.serviceMinBalance + } + } + + public enum TotalNumberOfCores: ReadInt { + public typealias TConfig = ProtocolConfigRef + public static func read(config: ProtocolConfigRef) -> Int { + config.value.totalNumberOfCores + } + } + + public enum PreimagePurgePeriod: ReadInt { + public typealias TConfig = ProtocolConfigRef + public static func read(config: ProtocolConfigRef) -> Int { + config.value.preimagePurgePeriod + } + } + + public enum EpochLength: ReadInt { + public typealias TConfig = ProtocolConfigRef + public static func read(config: ProtocolConfigRef) -> Int { + config.value.epochLength + } + } + + public enum AuditBiasFactor: ReadInt { + public typealias TConfig = ProtocolConfigRef + public static func read(config: ProtocolConfigRef) -> Int { + config.value.auditBiasFactor + } + } + + public enum CoreAccumulationGas: ReadInt { + public typealias TConfig = ProtocolConfigRef + public static func read(config: ProtocolConfigRef) -> Int { + config.value.coreAccumulationGas + } + } + + public enum WorkPackageAuthorizerGas: ReadInt { + public typealias TConfig = ProtocolConfigRef + public static func read(config: ProtocolConfigRef) -> Int { + config.value.workPackageAuthorizerGas + } + } + + public enum WorkPackageRefineGas: ReadInt { + public typealias TConfig = ProtocolConfigRef + public static func read(config: ProtocolConfigRef) -> Int { + config.value.workPackageRefineGas + } + } + + public enum RecentHistorySize: ReadInt { + public typealias TConfig = ProtocolConfigRef + public static func read(config: ProtocolConfigRef) -> Int { + config.value.recentHistorySize + } + } + + public enum MaxWorkItems: ReadInt { + public typealias TConfig = ProtocolConfigRef + public static func read(config: ProtocolConfigRef) -> Int { + config.value.maxWorkItems + } + } + + public enum MaxTicketsPerExtrinsic: ReadInt { + public typealias TConfig = ProtocolConfigRef + public static func read(config: ProtocolConfigRef) -> Int { + config.value.maxTicketsPerExtrinsic + } + } + + public enum MaxLookupAnchorAge: ReadInt { + public typealias TConfig = ProtocolConfigRef + public static func read(config: ProtocolConfigRef) -> Int { + config.value.maxLookupAnchorAge + } + } + + public enum TransferMemoSize: ReadInt { + public typealias TConfig = ProtocolConfigRef + public static func read(config: ProtocolConfigRef) -> Int { + config.value.transferMemoSize + } + } + + public enum TicketEntriesPerValidator: ReadInt { + public typealias TConfig = ProtocolConfigRef + public static func read(config: ProtocolConfigRef) -> Int { + config.value.ticketEntriesPerValidator + } + } + + public enum MaxAuthorizationsPoolItems: ReadInt { + public typealias TConfig = ProtocolConfigRef + public static func read(config: ProtocolConfigRef) -> Int { + config.value.maxAuthorizationsPoolItems + } + } + + public enum SlotPeriodSeconds: ReadInt { + public typealias TConfig = ProtocolConfigRef + public static func read(config: ProtocolConfigRef) -> Int { + config.value.slotPeriodSeconds + } + } + + public enum MaxAuthorizationsQueueItems: ReadInt { + public typealias TConfig = ProtocolConfigRef + public static func read(config: ProtocolConfigRef) -> Int { + config.value.maxAuthorizationsQueueItems + } + } + + public enum CoreAssignmentRotationPeriod: ReadInt { + public typealias TConfig = ProtocolConfigRef + public static func read(config: ProtocolConfigRef) -> Int { + config.value.coreAssignmentRotationPeriod + } + } + + public enum MaxServiceCodeSize: ReadInt { + public typealias TConfig = ProtocolConfigRef + public static func read(config: ProtocolConfigRef) -> Int { + config.value.maxServiceCodeSize + } + } + + public enum PreimageReplacementPeriod: ReadInt { + public typealias TConfig = ProtocolConfigRef + public static func read(config: ProtocolConfigRef) -> Int { + config.value.preimageReplacementPeriod + } + } + + public enum TotalNumberOfValidators: ReadInt { + public typealias TConfig = ProtocolConfigRef + public static func read(config: ProtocolConfigRef) -> Int { + config.value.totalNumberOfValidators + } + } + + public enum ErasureCodedPieceSize: ReadInt { + public typealias TConfig = ProtocolConfigRef + public static func read(config: ProtocolConfigRef) -> Int { + config.value.erasureCodedPieceSize + } + } + + public enum MaxWorkPackageManifestEntries: ReadInt { + public typealias TConfig = ProtocolConfigRef + public static func read(config: ProtocolConfigRef) -> Int { + config.value.maxWorkPackageManifestEntries + } + } + + public enum MaxEncodedWorkPackageSize: ReadInt { + public typealias TConfig = ProtocolConfigRef + public static func read(config: ProtocolConfigRef) -> Int { + config.value.maxEncodedWorkPackageSize + } + } + + public enum MaxEncodedWorkReportSize: ReadInt { + public typealias TConfig = ProtocolConfigRef + public static func read(config: ProtocolConfigRef) -> Int { + config.value.maxEncodedWorkReportSize + } + } + + public enum ErasureCodedSegmentSize: ReadInt { + public typealias TConfig = ProtocolConfigRef + public static func read(config: ProtocolConfigRef) -> Int { + config.value.erasureCodedSegmentSize + } + } + + public enum TicketSubmissionEndSlot: ReadInt { + public typealias TConfig = ProtocolConfigRef + public static func read(config: ProtocolConfigRef) -> Int { + config.value.ticketSubmissionEndSlot + } + } + + public enum PvmDynamicAddressAlignmentFactor: ReadInt { + public typealias TConfig = ProtocolConfigRef + public static func read(config: ProtocolConfigRef) -> Int { + config.value.pvmDynamicAddressAlignmentFactor + } + } + + public enum PvmProgramInitInputDataSize: ReadInt { + public typealias TConfig = ProtocolConfigRef + public static func read(config: ProtocolConfigRef) -> Int { + config.value.pvmProgramInitInputDataSize + } + } + + public enum TwoThirdValidatorsPlusOne: ReadInt { + public typealias TConfig = ProtocolConfigRef + public static func read(config: ProtocolConfigRef) -> Int { + config.value.totalNumberOfValidators * 2 / 3 + 1 + } + } +} + +extension ProtocolConfig { + public enum Int0: ReadInt { + public typealias TConfig = ProtocolConfigRef + public static func read(config _: ProtocolConfigRef) -> Int { + 0 + } + } + + public enum Int1: ReadInt { + public typealias TConfig = ProtocolConfigRef + public static func read(config _: ProtocolConfigRef) -> Int { + 1 + } + } +} diff --git a/Blockchain/Sources/Blockchain/Constants.swift b/Blockchain/Sources/Blockchain/Constants.swift deleted file mode 100644 index df609541..00000000 --- a/Blockchain/Sources/Blockchain/Constants.swift +++ /dev/null @@ -1,65 +0,0 @@ -import Utils - -public enum Constants { - // C: The total number of cores. - public enum TotalNumberOfCores: ConstInt { - public static var value: Int { - 341 - } - } - - // E: The length of an epoch in timeslots. - public enum EpochLength: ConstInt { - public static var value: Int { - 600 - } - } - - // I: The maximum amount of work items in a package. - public enum MaxWorkItems: ConstInt { - public static var value: Int { - 4 - } - } - - // N: The number of ticket entries per validator. - public enum ValidatorTicketEntriesCount: ConstInt { - public static var value: Int { - 2 - } - } - - // O: The maximum number of items in the authorizations pool. - public enum MaxAuthorizationsPoolItems: ConstInt { - public static var value: Int { - 8 - } - } - - // Q: The maximum number of items in the authorizations queue. - public enum MaxAuthorizationsQueueItems: ConstInt { - public static var value: Int { - 80 - } - } - - // S: The maximum size of service code in octets. - public enum MaxServiceCodeSize: ConstInt { - public static var value: Int { - 4_000_000 - } - } - - // V: The total number of validators. - public enum TotalNumberOfValidators: ConstInt { - public static var value: Int { - 1023 - } - } - - public enum TwoThirdValidatorsPlusOne: ConstInt { - public static var value: Int { - Constants.TotalNumberOfValidators.value * 2 / 3 + 1 - } - } -} diff --git a/Blockchain/Sources/Blockchain/Types/AvailabilitySpecifications.swift b/Blockchain/Sources/Blockchain/Types/AvailabilitySpecifications.swift index 0153aa68..8222c789 100644 --- a/Blockchain/Sources/Blockchain/Types/AvailabilitySpecifications.swift +++ b/Blockchain/Sources/Blockchain/Types/AvailabilitySpecifications.swift @@ -28,7 +28,8 @@ public struct AvailabilitySpecifications { } extension AvailabilitySpecifications: Dummy { - public static var dummy: AvailabilitySpecifications { + public typealias Config = ProtocolConfigRef + public static func dummy(withConfig _: Config) -> AvailabilitySpecifications { AvailabilitySpecifications( workPackageHash: H256(), length: 0, diff --git a/Blockchain/Sources/Blockchain/Types/Block.swift b/Blockchain/Sources/Blockchain/Types/Block.swift index eb17e903..f740b4da 100644 --- a/Blockchain/Sources/Blockchain/Types/Block.swift +++ b/Blockchain/Sources/Blockchain/Types/Block.swift @@ -14,19 +14,20 @@ public struct Block { public typealias BlockRef = Ref extension Block: Dummy { - public static var dummy: Block { + public typealias Config = ProtocolConfigRef + public static func dummy(withConfig config: Config) -> Block { Block( - header: Header.dummy, - extrinsic: Extrinsic.dummy + header: Header.dummy(withConfig: config), + extrinsic: Extrinsic.dummy(withConfig: config) ) } } -extension Block: ScaleCodec.Codable { - public init(from decoder: inout some ScaleCodec.Decoder) throws { +extension Block: ScaleCodec.Encodable { + public init(withConfig config: ProtocolConfigRef, from decoder: inout some ScaleCodec.Decoder) throws { try self.init( - header: decoder.decode(), - extrinsic: decoder.decode() + header: Header(withConfig: config, from: &decoder), + extrinsic: Extrinsic(withConfig: config, from: &decoder) ) } diff --git a/Blockchain/Sources/Blockchain/Types/Extrinsic.swift b/Blockchain/Sources/Blockchain/Types/Extrinsic.swift index f6f91937..2277ca02 100644 --- a/Blockchain/Sources/Blockchain/Types/Extrinsic.swift +++ b/Blockchain/Sources/Blockchain/Types/Extrinsic.swift @@ -35,25 +35,26 @@ public struct Extrinsic { } extension Extrinsic: Dummy { - public static var dummy: Extrinsic { + public typealias Config = ProtocolConfigRef + public static func dummy(withConfig config: Config) -> Extrinsic { Extrinsic( - tickets: ExtrinsicTickets.dummy, - judgements: ExtrinsicJudgement.dummy, - preimages: ExtrinsicPreimages.dummy, - availability: ExtrinsicAvailability.dummy, - reports: ExtrinsicGuarantees.dummy + tickets: ExtrinsicTickets.dummy(withConfig: config), + judgements: ExtrinsicJudgement.dummy(withConfig: config), + preimages: ExtrinsicPreimages.dummy(withConfig: config), + availability: ExtrinsicAvailability.dummy(withConfig: config), + reports: ExtrinsicGuarantees.dummy(withConfig: config) ) } } -extension Extrinsic: ScaleCodec.Codable { - public init(from decoder: inout some ScaleCodec.Decoder) throws { +extension Extrinsic: ScaleCodec.Encodable { + public init(withConfig config: ProtocolConfigRef, from decoder: inout some ScaleCodec.Decoder) throws { try self.init( tickets: decoder.decode(), - judgements: decoder.decode(), + judgements: ExtrinsicJudgement(withConfig: config, from: &decoder), preimages: decoder.decode(), - availability: decoder.decode(), - reports: decoder.decode() + availability: ExtrinsicAvailability(withConfig: config, from: &decoder), + reports: ExtrinsicGuarantees(withConfig: config, from: &decoder) ) } diff --git a/Blockchain/Sources/Blockchain/Types/ExtrinsicAvailability.swift b/Blockchain/Sources/Blockchain/Types/ExtrinsicAvailability.swift index b0b3c08d..c2812726 100644 --- a/Blockchain/Sources/Blockchain/Types/ExtrinsicAvailability.swift +++ b/Blockchain/Sources/Blockchain/Types/ExtrinsicAvailability.swift @@ -3,10 +3,33 @@ import ScaleCodec import Utils public struct ExtrinsicAvailability { - public typealias AssurancesList = LimitedSizeArray< + 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 + } + } + + public typealias AssurancesList = ConfigLimitedSizeArray< AssuranceItem, - ConstInt0, - Constants.TotalNumberOfValidators + ProtocolConfig.Int0, + ProtocolConfig.TotalNumberOfValidators > public var assurances: AssurancesList @@ -19,15 +42,16 @@ public struct ExtrinsicAvailability { } extension ExtrinsicAvailability: Dummy { - public static var dummy: ExtrinsicAvailability { - ExtrinsicAvailability(assurances: []) + public typealias Config = ProtocolConfigRef + public static func dummy(withConfig config: Config) -> ExtrinsicAvailability { + ExtrinsicAvailability(assurances: ConfigLimitedSizeArray(withConfig: config)) } } -extension ExtrinsicAvailability: ScaleCodec.Codable { - public init(from decoder: inout some ScaleCodec.Decoder) throws { +extension ExtrinsicAvailability: ScaleCodec.Encodable { + public init(withConfig config: ProtocolConfigRef, from decoder: inout some ScaleCodec.Decoder) throws { try self.init( - assurances: decoder.decode() + assurances: ConfigLimitedSizeArray(withConfig: config, from: &decoder) ) } @@ -36,30 +60,7 @@ extension ExtrinsicAvailability: ScaleCodec.Codable { } } -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 { +extension ExtrinsicAvailability.AssuranceItem: ScaleCodec.Codable { public init(from decoder: inout some ScaleCodec.Decoder) throws { try self.init( parentHash: decoder.decode(), diff --git a/Blockchain/Sources/Blockchain/Types/ExtrinsicGuarantees.swift b/Blockchain/Sources/Blockchain/Types/ExtrinsicGuarantees.swift index 02ef4832..630a4477 100644 --- a/Blockchain/Sources/Blockchain/Types/ExtrinsicGuarantees.swift +++ b/Blockchain/Sources/Blockchain/Types/ExtrinsicGuarantees.swift @@ -2,10 +2,37 @@ import ScaleCodec import Utils public struct ExtrinsicGuarantees { - public typealias GuaranteesList = LimitedSizeArray< + 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 + } + } + + public typealias GuaranteesList = ConfigLimitedSizeArray< GuaranteeItem, - ConstInt0, - Constants.TotalNumberOfCores + ProtocolConfig.Int0, + ProtocolConfig.TotalNumberOfCores > public var guarantees: GuaranteesList @@ -15,18 +42,23 @@ public struct ExtrinsicGuarantees { ) { self.guarantees = guarantees } + + public init(withConfig config: ProtocolConfigRef) { + guarantees = ConfigLimitedSizeArray(withConfig: config) + } } extension ExtrinsicGuarantees: Dummy { - public static var dummy: ExtrinsicGuarantees { - ExtrinsicGuarantees(guarantees: []) + public typealias Config = ProtocolConfigRef + public static func dummy(withConfig config: Config) -> ExtrinsicGuarantees { + ExtrinsicGuarantees(withConfig: config) } } -extension ExtrinsicGuarantees: ScaleCodec.Codable { - public init(from decoder: inout some ScaleCodec.Decoder) throws { +extension ExtrinsicGuarantees: ScaleCodec.Encodable { + public init(withConfig config: ProtocolConfigRef, from decoder: inout some ScaleCodec.Decoder) throws { try self.init( - guarantees: decoder.decode() + guarantees: ConfigLimitedSizeArray(withConfig: config, from: &decoder) { try GuaranteeItem(withConfig: config, from: &$0) } ) } @@ -35,38 +67,11 @@ extension ExtrinsicGuarantees: ScaleCodec.Codable { } } -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 { +extension ExtrinsicGuarantees.GuaranteeItem: ScaleCodec.Encodable { + public init(withConfig config: ProtocolConfigRef, from decoder: inout some ScaleCodec.Decoder) throws { try self.init( coreIndex: decoder.decode(), - workReport: decoder.decode(), + workReport: WorkReport(withConfig: config, from: &decoder), timeslot: decoder.decode(), credential: decoder.decode() ) diff --git a/Blockchain/Sources/Blockchain/Types/ExtrinsicJudgement.swift b/Blockchain/Sources/Blockchain/Types/ExtrinsicJudgement.swift index ff763a2a..b55eaa69 100644 --- a/Blockchain/Sources/Blockchain/Types/ExtrinsicJudgement.swift +++ b/Blockchain/Sources/Blockchain/Types/ExtrinsicJudgement.swift @@ -2,6 +2,41 @@ import ScaleCodec import Utils public struct ExtrinsicJudgement { + public struct JudgementItem { + 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 + } + } + + public var reportHash: H256 + public var signatures: ConfigFixedSizeArray< + SignatureItem, + ProtocolConfig.TwoThirdValidatorsPlusOne + > + + public init( + reportHash: H256, + signatures: ConfigFixedSizeArray< + SignatureItem, + ProtocolConfig.TwoThirdValidatorsPlusOne + > + ) { + self.reportHash = reportHash + self.signatures = signatures + } + } + public typealias JudgementsList = [JudgementItem] public var judgements: JudgementsList @@ -14,15 +49,16 @@ public struct ExtrinsicJudgement { } extension ExtrinsicJudgement: Dummy { - public static var dummy: ExtrinsicJudgement { + public typealias Config = ProtocolConfigRef + public static func dummy(withConfig _: Config) -> ExtrinsicJudgement { ExtrinsicJudgement(judgements: []) } } -extension ExtrinsicJudgement: ScaleCodec.Codable { - public init(from decoder: inout some ScaleCodec.Decoder) throws { +extension ExtrinsicJudgement: ScaleCodec.Encodable { + public init(withConfig config: ProtocolConfigRef, from decoder: inout some ScaleCodec.Decoder) throws { try self.init( - judgements: decoder.decode() + judgements: decoder.decode(.array { try JudgementItem(withConfig: config, from: &$0) }) ) } @@ -31,46 +67,11 @@ extension ExtrinsicJudgement: ScaleCodec.Codable { } } -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 { +extension ExtrinsicJudgement.JudgementItem: ScaleCodec.Encodable { + public init(withConfig config: ProtocolConfigRef, from decoder: inout some ScaleCodec.Decoder) throws { try self.init( reportHash: decoder.decode(), - signatures: decoder.decode() + signatures: ConfigFixedSizeArray(withConfig: config, from: &decoder) ) } @@ -80,7 +81,7 @@ extension JudgementItem: ScaleCodec.Codable { } } -extension JudgementItem.SignatureItem: ScaleCodec.Codable { +extension ExtrinsicJudgement.JudgementItem.SignatureItem: ScaleCodec.Codable { public init(from decoder: inout some ScaleCodec.Decoder) throws { try self.init( isValid: decoder.decode(), diff --git a/Blockchain/Sources/Blockchain/Types/ExtrinsicPreimages.swift b/Blockchain/Sources/Blockchain/Types/ExtrinsicPreimages.swift index 36762d48..1b82ab8e 100644 --- a/Blockchain/Sources/Blockchain/Types/ExtrinsicPreimages.swift +++ b/Blockchain/Sources/Blockchain/Types/ExtrinsicPreimages.swift @@ -13,7 +13,8 @@ public struct ExtrinsicPreimages { } extension ExtrinsicPreimages: Dummy { - public static var dummy: ExtrinsicPreimages { + public typealias Config = ProtocolConfigRef + public static func dummy(withConfig _: Config) -> ExtrinsicPreimages { ExtrinsicPreimages(preimages: []) } } diff --git a/Blockchain/Sources/Blockchain/Types/ExtrinsicTickets.swift b/Blockchain/Sources/Blockchain/Types/ExtrinsicTickets.swift index e8da418e..d8b8c0e5 100644 --- a/Blockchain/Sources/Blockchain/Types/ExtrinsicTickets.swift +++ b/Blockchain/Sources/Blockchain/Types/ExtrinsicTickets.swift @@ -25,7 +25,8 @@ public struct ExtrinsicTickets { } extension ExtrinsicTickets: Dummy { - public static var dummy: ExtrinsicTickets { + public typealias Config = ProtocolConfigRef + public static func dummy(withConfig _: Config) -> ExtrinsicTickets { ExtrinsicTickets(tickets: []) } } diff --git a/Blockchain/Sources/Blockchain/Types/Header.swift b/Blockchain/Sources/Blockchain/Types/Header.swift index fb0abe7e..b359124a 100644 --- a/Blockchain/Sources/Blockchain/Types/Header.swift +++ b/Blockchain/Sources/Blockchain/Types/Header.swift @@ -4,16 +4,16 @@ import Utils public struct Header { public struct EpochMarker { public var randomness: H256 - public var keys: FixedSizeArray< + public var keys: ConfigFixedSizeArray< BandersnatchPublicKey, - Constants.TotalNumberOfValidators + ProtocolConfig.TotalNumberOfValidators > public init( randomness: H256, - keys: FixedSizeArray< + keys: ConfigFixedSizeArray< BandersnatchPublicKey, - Constants.TotalNumberOfValidators + ProtocolConfig.TotalNumberOfValidators > ) { self.randomness = randomness @@ -43,9 +43,9 @@ public struct Header { // 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: FixedSizeArray< + public var winningTickets: ConfigFixedSizeArray< Ticket, - Constants.EpochLength + ProtocolConfig.EpochLength >? // Hj: The judgement marker must contain exactly the sequence of report hashes judged not as @@ -67,10 +67,9 @@ public struct Header { extrinsicsRoot: H256, timeslotIndex: TimeslotIndex, epoch: EpochMarker?, - winningTickets: LimitedSizeArray< + winningTickets: ConfigFixedSizeArray< Ticket, - Constants.EpochLength, - Constants.EpochLength + ProtocolConfig.EpochLength >?, judgementsMarkers: [H256], authorKey: BandersnatchPublicKey, @@ -91,7 +90,8 @@ public struct Header { } extension Header: Dummy { - public static var dummy: Header { + public typealias Config = ProtocolConfigRef + public static func dummy(withConfig _: Config) -> Header { Header( parentHash: H256(), priorStateRoot: H256(), @@ -107,15 +107,15 @@ extension Header: Dummy { } } -extension Header: ScaleCodec.Codable { - public init(from decoder: inout some ScaleCodec.Decoder) throws { +extension Header: ScaleCodec.Encodable { + public init(withConfig config: ProtocolConfigRef, 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(), + epoch: EpochMarker(withConfig: config, from: &decoder), + winningTickets: ConfigFixedSizeArray(withConfig: config, from: &decoder), judgementsMarkers: decoder.decode(), authorKey: decoder.decode(), vrfSignature: decoder.decode(), @@ -137,11 +137,11 @@ extension Header: ScaleCodec.Codable { } } -extension Header.EpochMarker: ScaleCodec.Codable { - public init(from decoder: inout some ScaleCodec.Decoder) throws { +extension Header.EpochMarker: ScaleCodec.Encodable { + public init(withConfig config: ProtocolConfigRef, from decoder: inout some ScaleCodec.Decoder) throws { try self.init( randomness: decoder.decode(), - keys: decoder.decode() + keys: ConfigFixedSizeArray(withConfig: config, from: &decoder) ) } @@ -151,8 +151,8 @@ extension Header.EpochMarker: ScaleCodec.Codable { } } -public extension Header { - var hash: H256 { +extension Header { + public var hash: H256 { H256() // TODO: implement this } } diff --git a/Blockchain/Sources/Blockchain/Types/JudgementsState.swift b/Blockchain/Sources/Blockchain/Types/JudgementsState.swift index dc56f04d..7be79c43 100644 --- a/Blockchain/Sources/Blockchain/Types/JudgementsState.swift +++ b/Blockchain/Sources/Blockchain/Types/JudgementsState.swift @@ -25,7 +25,8 @@ public struct JudgementsState { } extension JudgementsState: Dummy { - public static var dummy: JudgementsState { + public typealias Config = ProtocolConfigRef + public static func dummy(withConfig _: Config) -> JudgementsState { JudgementsState( allowSet: [], banSet: [], diff --git a/Blockchain/Sources/Blockchain/Types/RefinementContext.swift b/Blockchain/Sources/Blockchain/Types/RefinementContext.swift index 3d076254..cd8ee7a1 100644 --- a/Blockchain/Sources/Blockchain/Types/RefinementContext.swift +++ b/Blockchain/Sources/Blockchain/Types/RefinementContext.swift @@ -36,7 +36,8 @@ public struct RefinementContext { } extension RefinementContext: Dummy { - public static var dummy: RefinementContext { + public typealias Config = ProtocolConfigRef + public static func dummy(withConfig _: Config) -> RefinementContext { RefinementContext( anchor: ( headerHash: H256(), diff --git a/Blockchain/Sources/Blockchain/Types/SafroleState.swift b/Blockchain/Sources/Blockchain/Types/SafroleState.swift index 3048fb08..c7ab4b3e 100644 --- a/Blockchain/Sources/Blockchain/Types/SafroleState.swift +++ b/Blockchain/Sources/Blockchain/Types/SafroleState.swift @@ -3,8 +3,8 @@ import Utils public struct SafroleState { // γk - public var pendingValidators: FixedSizeArray< - ValidatorKey, Constants.TotalNumberOfValidators + public var pendingValidators: ConfigFixedSizeArray< + ValidatorKey, ProtocolConfig.TotalNumberOfValidators > // γz @@ -12,42 +12,42 @@ public struct SafroleState { // γs public var slotSealerSeries: Either< - FixedSizeArray< + ConfigFixedSizeArray< Ticket, - Constants.EpochLength + ProtocolConfig.EpochLength >, - FixedSizeArray< + ConfigFixedSizeArray< BandersnatchPublicKey, - Constants.EpochLength + ProtocolConfig.EpochLength > > // γa - public var ticketAccumulator: LimitedSizeArray< + public var ticketAccumulator: ConfigLimitedSizeArray< Ticket, - ConstInt0, - Constants.EpochLength + ProtocolConfig.Int0, + ProtocolConfig.EpochLength > public init( - pendingValidators: FixedSizeArray< - ValidatorKey, Constants.TotalNumberOfValidators + pendingValidators: ConfigFixedSizeArray< + ValidatorKey, ProtocolConfig.TotalNumberOfValidators >, epochRoot: BandersnatchRingVRFRoot, slotSealerSeries: Either< - FixedSizeArray< + ConfigFixedSizeArray< Ticket, - Constants.EpochLength + ProtocolConfig.EpochLength >, - FixedSizeArray< + ConfigFixedSizeArray< BandersnatchPublicKey, - Constants.EpochLength + ProtocolConfig.EpochLength > >, - ticketAccumulator: LimitedSizeArray< + ticketAccumulator: ConfigLimitedSizeArray< Ticket, - ConstInt0, - Constants.EpochLength + ProtocolConfig.Int0, + ProtocolConfig.EpochLength > ) { self.pendingValidators = pendingValidators @@ -58,23 +58,28 @@ public struct SafroleState { } extension SafroleState: Dummy { - public static var dummy: SafroleState { + public typealias Config = ProtocolConfigRef + public static func dummy(withConfig config: Config) -> SafroleState { SafroleState( - pendingValidators: FixedSizeArray(defaultValue: ValidatorKey.dummy), + pendingValidators: ConfigFixedSizeArray(withConfig: config, defaultValue: ValidatorKey.dummy(withConfig: config)), epochRoot: BandersnatchRingVRFRoot(), - slotSealerSeries: .right(FixedSizeArray(defaultValue: BandersnatchPublicKey())), - ticketAccumulator: [] + slotSealerSeries: .right(ConfigFixedSizeArray(withConfig: config, defaultValue: BandersnatchPublicKey())), + ticketAccumulator: ConfigLimitedSizeArray(withConfig: config) ) } } -extension SafroleState: ScaleCodec.Codable { - public init(from decoder: inout some ScaleCodec.Decoder) throws { +extension SafroleState: ScaleCodec.Encodable { + public init(withConfig config: ProtocolConfigRef, from decoder: inout some ScaleCodec.Decoder) throws { try self.init( - pendingValidators: decoder.decode(), + pendingValidators: ConfigFixedSizeArray(withConfig: config, from: &decoder), epochRoot: decoder.decode(), - slotSealerSeries: decoder.decode(), - ticketAccumulator: decoder.decode() + slotSealerSeries: Either( + from: &decoder, + decodeLeft: { try ConfigFixedSizeArray(withConfig: config, from: &$0) }, + decodeRight: { try ConfigFixedSizeArray(withConfig: config, from: &$0) } + ), + ticketAccumulator: ConfigLimitedSizeArray(withConfig: config, from: &decoder) ) } diff --git a/Blockchain/Sources/Blockchain/Types/ServiceAccount.swift b/Blockchain/Sources/Blockchain/Types/ServiceAccount.swift index 447b11e2..e8d1a652 100644 --- a/Blockchain/Sources/Blockchain/Types/ServiceAccount.swift +++ b/Blockchain/Sources/Blockchain/Types/ServiceAccount.swift @@ -56,7 +56,8 @@ public struct ServiceAccount { } extension ServiceAccount: Dummy { - public static var dummy: ServiceAccount { + public typealias Config = ProtocolConfigRef + public static func dummy(withConfig _: Config) -> ServiceAccount { ServiceAccount( storage: [:], preimages: [:], diff --git a/Blockchain/Sources/Blockchain/Types/State.swift b/Blockchain/Sources/Blockchain/Types/State.swift index 145002fd..efb1c9ce 100644 --- a/Blockchain/Sources/Blockchain/Types/State.swift +++ b/Blockchain/Sources/Blockchain/Types/State.swift @@ -19,13 +19,13 @@ public struct State { } // α: The core αuthorizations pool. - public var coreAuthorizationPool: FixedSizeArray< - LimitedSizeArray< + public var coreAuthorizationPool: ConfigFixedSizeArray< + ConfigLimitedSizeArray< H256, - ConstInt0, - Constants.MaxAuthorizationsPoolItems + ProtocolConfig.Int0, + ProtocolConfig.MaxAuthorizationsPoolItems >, - Constants.TotalNumberOfCores + ProtocolConfig.TotalNumberOfCores > // β: Information on the most recent βlocks. @@ -41,36 +41,36 @@ public struct State { public var entropyPool: (H256, H256, H256, H256) // ι: The validator keys and metadata to be drawn from next. - public var validatorQueue: FixedSizeArray< - ValidatorKey, Constants.TotalNumberOfValidators + public var validatorQueue: ConfigFixedSizeArray< + ValidatorKey, ProtocolConfig.TotalNumberOfValidators > // κ: The validator κeys and metadata currently active. - public var currentValidators: FixedSizeArray< - ValidatorKey, Constants.TotalNumberOfValidators + public var currentValidators: ConfigFixedSizeArray< + ValidatorKey, ProtocolConfig.TotalNumberOfValidators > // λ: The validator keys and metadata which were active in the prior epoch. - public var previousValidators: FixedSizeArray< - ValidatorKey, Constants.TotalNumberOfValidators + public var previousValidators: ConfigFixedSizeArray< + ValidatorKey, ProtocolConfig.TotalNumberOfValidators > // ρ: The ρending reports, per core, which are being made available prior to accumulation. - public var reports: FixedSizeArray< + public var reports: ConfigFixedSizeArray< ReportItem?, - Constants.TotalNumberOfCores + ProtocolConfig.TotalNumberOfCores > // τ: The most recent block’s τimeslot. public var timestamp: TimeslotIndex // φ: The authorization queue. - public var authorizationQueue: FixedSizeArray< - FixedSizeArray< + public var authorizationQueue: ConfigFixedSizeArray< + ConfigFixedSizeArray< H256, - Constants.MaxAuthorizationsQueueItems + ProtocolConfig.MaxAuthorizationsQueueItems >, - Constants.TotalNumberOfCores + ProtocolConfig.TotalNumberOfCores > // χ: The privileged service indices. @@ -84,38 +84,38 @@ public struct State { public var judgements: JudgementsState public init( - coreAuthorizationPool: FixedSizeArray< - LimitedSizeArray< + coreAuthorizationPool: ConfigFixedSizeArray< + ConfigLimitedSizeArray< H256, - ConstInt0, - Constants.MaxAuthorizationsPoolItems + ProtocolConfig.Int0, + ProtocolConfig.MaxAuthorizationsPoolItems >, - Constants.TotalNumberOfCores + ProtocolConfig.TotalNumberOfCores >, lastBlock: Block, safroleState: SafroleState, serviceAccounts: [ServiceIdentifier: ServiceAccount], entropyPool: (H256, H256, H256, H256), - validatorQueue: FixedSizeArray< - ValidatorKey, Constants.TotalNumberOfValidators + validatorQueue: ConfigFixedSizeArray< + ValidatorKey, ProtocolConfig.TotalNumberOfValidators >, - currentValidators: FixedSizeArray< - ValidatorKey, Constants.TotalNumberOfValidators + currentValidators: ConfigFixedSizeArray< + ValidatorKey, ProtocolConfig.TotalNumberOfValidators >, - previousValidators: FixedSizeArray< - ValidatorKey, Constants.TotalNumberOfValidators + previousValidators: ConfigFixedSizeArray< + ValidatorKey, ProtocolConfig.TotalNumberOfValidators >, - reports: FixedSizeArray< + reports: ConfigFixedSizeArray< ReportItem?, - Constants.TotalNumberOfCores + ProtocolConfig.TotalNumberOfCores >, timestamp: TimeslotIndex, - authorizationQueue: FixedSizeArray< - FixedSizeArray< + authorizationQueue: ConfigFixedSizeArray< + ConfigFixedSizeArray< H256, - Constants.MaxAuthorizationsQueueItems + ProtocolConfig.MaxAuthorizationsQueueItems >, - Constants.TotalNumberOfCores + ProtocolConfig.TotalNumberOfCores >, privilegedServiceIndices: ( empower: ServiceIdentifier, @@ -143,33 +143,37 @@ public struct State { public typealias StateRef = Ref extension State: Dummy { - public static var dummy: State { + public typealias Config = ProtocolConfigRef + public static func dummy(withConfig config: Config) -> State { State( - coreAuthorizationPool: FixedSizeArray(defaultValue: []), - lastBlock: Block.dummy, - safroleState: SafroleState.dummy, + coreAuthorizationPool: ConfigFixedSizeArray(withConfig: config, defaultValue: ConfigLimitedSizeArray(withConfig: config)), + lastBlock: Block.dummy(withConfig: config), + safroleState: SafroleState.dummy(withConfig: config), serviceAccounts: [:], entropyPool: (H256(), H256(), H256(), H256()), - validatorQueue: FixedSizeArray(defaultValue: ValidatorKey.dummy), - currentValidators: FixedSizeArray(defaultValue: ValidatorKey.dummy), - previousValidators: FixedSizeArray(defaultValue: ValidatorKey.dummy), - reports: FixedSizeArray(defaultValue: nil), + validatorQueue: ConfigFixedSizeArray(withConfig: config, defaultValue: ValidatorKey.dummy(withConfig: config)), + currentValidators: ConfigFixedSizeArray(withConfig: config, defaultValue: ValidatorKey.dummy(withConfig: config)), + previousValidators: ConfigFixedSizeArray(withConfig: config, defaultValue: ValidatorKey.dummy(withConfig: config)), + reports: ConfigFixedSizeArray(withConfig: config, defaultValue: nil), timestamp: 0, - authorizationQueue: FixedSizeArray(defaultValue: FixedSizeArray(defaultValue: H256())), + authorizationQueue: ConfigFixedSizeArray( + withConfig: config, + defaultValue: ConfigFixedSizeArray(withConfig: config, defaultValue: H256()) + ), privilegedServiceIndices: ( empower: ServiceIdentifier(), assign: ServiceIdentifier(), designate: ServiceIdentifier() ), - judgements: JudgementsState.dummy + judgements: JudgementsState.dummy(withConfig: config) ) } } -extension State.ReportItem: ScaleCodec.Codable { - public init(from decoder: inout some ScaleCodec.Decoder) throws { +extension State.ReportItem: ScaleCodec.Encodable { + public init(withConfig config: ProtocolConfigRef, from decoder: inout some ScaleCodec.Decoder) throws { try self.init( - workReport: decoder.decode(), + workReport: WorkReport(withConfig: config, from: &decoder), guarantors: decoder.decode(), timestamp: decoder.decode() ) @@ -182,20 +186,24 @@ extension State.ReportItem: ScaleCodec.Codable { } } -extension State: ScaleCodec.Codable { - public init(from decoder: inout some ScaleCodec.Decoder) throws { +extension State: ScaleCodec.Encodable { + public init(withConfig config: ProtocolConfigRef, from decoder: inout some ScaleCodec.Decoder) throws { try self.init( - coreAuthorizationPool: decoder.decode(), - lastBlock: decoder.decode(), - safroleState: decoder.decode(), + coreAuthorizationPool: ConfigFixedSizeArray(withConfig: config, from: &decoder) { + try ConfigLimitedSizeArray(withConfig: config, from: &$0) { try $0.decode() } + }, + lastBlock: Block(withConfig: config, from: &decoder), + safroleState: SafroleState(withConfig: config, from: &decoder), serviceAccounts: decoder.decode(), entropyPool: decoder.decode(), - validatorQueue: decoder.decode(), - currentValidators: decoder.decode(), - previousValidators: decoder.decode(), - reports: decoder.decode(), + validatorQueue: ConfigFixedSizeArray(withConfig: config, from: &decoder), + currentValidators: ConfigFixedSizeArray(withConfig: config, from: &decoder), + previousValidators: ConfigFixedSizeArray(withConfig: config, from: &decoder), + reports: ConfigFixedSizeArray(withConfig: config, from: &decoder) { try ReportItem(withConfig: config, from: &$0) }, timestamp: decoder.decode(), - authorizationQueue: decoder.decode(), + authorizationQueue: ConfigFixedSizeArray(withConfig: config, from: &decoder) { + try ConfigFixedSizeArray(withConfig: config, from: &$0) + }, privilegedServiceIndices: decoder.decode(), judgements: decoder.decode() ) @@ -218,8 +226,8 @@ extension State: ScaleCodec.Codable { } } -public extension State { - func update(with block: Block) -> State { +extension State { + public func update(with block: Block) -> State { let state = State( coreAuthorizationPool: coreAuthorizationPool, lastBlock: block, diff --git a/Blockchain/Sources/Blockchain/Types/Ticket.swift b/Blockchain/Sources/Blockchain/Types/Ticket.swift index 842d9712..0fc95ffe 100644 --- a/Blockchain/Sources/Blockchain/Types/Ticket.swift +++ b/Blockchain/Sources/Blockchain/Types/Ticket.swift @@ -7,7 +7,8 @@ public struct Ticket { } extension Ticket: Dummy { - public static var dummy: Ticket { + public typealias Config = ProtocolConfigRef + public static func dummy(withConfig _: Config) -> Ticket { Ticket(identifier: H256(), entryIndex: 0) } } diff --git a/Blockchain/Sources/Blockchain/Types/ValidatorKey.swift b/Blockchain/Sources/Blockchain/Types/ValidatorKey.swift index dd9d5ed7..33ea9467 100644 --- a/Blockchain/Sources/Blockchain/Types/ValidatorKey.swift +++ b/Blockchain/Sources/Blockchain/Types/ValidatorKey.swift @@ -21,7 +21,8 @@ public struct ValidatorKey { } extension ValidatorKey: Dummy { - public static var dummy: ValidatorKey { + public typealias Config = ProtocolConfigRef + public static func dummy(withConfig _: Config) -> ValidatorKey { ValidatorKey( bandersnatchKey: BandersnatchPublicKey(), ed25519Key: Ed25519PublicKey(), diff --git a/Blockchain/Sources/Blockchain/Types/WorkReport.swift b/Blockchain/Sources/Blockchain/Types/WorkReport.swift index 9ff7136e..f30b9571 100644 --- a/Blockchain/Sources/Blockchain/Types/WorkReport.swift +++ b/Blockchain/Sources/Blockchain/Types/WorkReport.swift @@ -16,10 +16,10 @@ public struct WorkReport { public var packageSpecification: AvailabilitySpecifications // r: the results of the evaluation of each of the items in the package - public var results: LimitedSizeArray< + public var results: ConfigLimitedSizeArray< WorkResult, - ConstInt1, - Constants.MaxWorkItems + ProtocolConfig.Int1, + ProtocolConfig.MaxWorkItems > public init( @@ -27,10 +27,10 @@ public struct WorkReport { output: Data, refinementContext: RefinementContext, packageSpecification: AvailabilitySpecifications, - results: LimitedSizeArray< + results: ConfigLimitedSizeArray< WorkResult, - ConstInt1, - Constants.MaxWorkItems + ProtocolConfig.Int1, + ProtocolConfig.MaxWorkItems > ) { self.authorizerHash = authorizerHash @@ -42,25 +42,26 @@ public struct WorkReport { } extension WorkReport: Dummy { - public static var dummy: WorkReport { + public typealias Config = ProtocolConfigRef + public static func dummy(withConfig config: Config) -> WorkReport { WorkReport( authorizerHash: H256(), output: Data(), - refinementContext: RefinementContext.dummy, - packageSpecification: AvailabilitySpecifications.dummy, - results: [] + refinementContext: RefinementContext.dummy(withConfig: config), + packageSpecification: AvailabilitySpecifications.dummy(withConfig: config), + results: ConfigLimitedSizeArray(withConfig: config, defaultValue: WorkResult.dummy(withConfig: config)) ) } } -extension WorkReport: ScaleCodec.Codable { - public init(from decoder: inout some ScaleCodec.Decoder) throws { +extension WorkReport: ScaleCodec.Encodable { + public init(withConfig config: Config, 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() + results: ConfigLimitedSizeArray(withConfig: config, from: &decoder) ) } diff --git a/Blockchain/Sources/Blockchain/Types/WorkResult.swift b/Blockchain/Sources/Blockchain/Types/WorkResult.swift index 05b61ae8..0c93156e 100644 --- a/Blockchain/Sources/Blockchain/Types/WorkResult.swift +++ b/Blockchain/Sources/Blockchain/Types/WorkResult.swift @@ -36,7 +36,8 @@ public struct WorkResult { } extension WorkResult: Dummy { - public static var dummy: WorkResult { + public typealias Config = ProtocolConfigRef + public static func dummy(withConfig _: Config) -> WorkResult { WorkResult( serviceIdentifier: ServiceIdentifier(), codeHash: H256(), diff --git a/Boka/Sources/Boka.swift b/Boka/Sources/Boka.swift index 1e0c42b9..42f8d733 100644 --- a/Boka/Sources/Boka.swift +++ b/Boka/Sources/Boka.swift @@ -10,7 +10,7 @@ import Node @main struct Boka: ParsableCommand { mutating func run() throws { - let node = try Node(genesis: .dev) + let node = try Node(genesis: .dev, config: .dev) node.sayHello() } } diff --git a/Database/Package.swift b/Database/Package.swift index 05e3c208..2cd6d3d8 100644 --- a/Database/Package.swift +++ b/Database/Package.swift @@ -16,7 +16,8 @@ let package = Package( // 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: "Database"), + name: "Database" + ), .testTarget( name: "DatabaseTests", dependencies: ["Database"] diff --git a/Node/Sources/Node/Genesis.swift b/Node/Sources/Node/Genesis.swift index a9ffdfe4..36431fc7 100644 --- a/Node/Sources/Node/Genesis.swift +++ b/Node/Sources/Node/Genesis.swift @@ -6,13 +6,13 @@ public enum Genesis { case file(path: String) } -public extension Genesis { - func toState() throws -> StateRef { +extension Genesis { + public func toState(withConfig config: ProtocolConfigRef) throws -> StateRef { switch self { case .file: fatalError("TODO: not implemented") case .dev: - StateRef.dummy + StateRef.dummy(withConfig: config) } } } diff --git a/Node/Sources/Node/Node.swift b/Node/Sources/Node/Node.swift index a586f944..367215f4 100644 --- a/Node/Sources/Node/Node.swift +++ b/Node/Sources/Node/Node.swift @@ -3,8 +3,8 @@ import Blockchain public class Node { public private(set) var blockchain: Blockchain - public init(genesis: Genesis) throws { - let genesisState = try genesis.toState() + public init(genesis: Genesis, config: ProtocolConfigRef) throws { + let genesisState = try genesis.toState(withConfig: config) blockchain = Blockchain(heads: [genesisState], finalizedHead: genesisState) } diff --git a/Utils/Sources/Utils/ConfigLimitedSizeArray.swift b/Utils/Sources/Utils/ConfigLimitedSizeArray.swift new file mode 100644 index 00000000..7335cc4a --- /dev/null +++ b/Utils/Sources/Utils/ConfigLimitedSizeArray.swift @@ -0,0 +1,164 @@ +import ScaleCodec + +// TODO: add tests + +public struct ConfigLimitedSizeArray + where TMinLength.TConfig == TMaxLength.TConfig +{ + private var array: [T] + + public let minLength: Int + public let maxLength: Int + + public init(withConfig config: TMinLength.TConfig, defaultValue: T) { + let minLength = TMinLength.read(config: config) + let maxLength = TMaxLength.read(config: config) + + self.init(Array(repeating: defaultValue, count: minLength), minLength: minLength, maxLength: maxLength) + } + + // require minLength to be zero + public init(withConfig config: TMinLength.TConfig) { + let minLength = TMinLength.read(config: config) + let maxLength = TMaxLength.read(config: config) + + self.init([], minLength: minLength, maxLength: maxLength) + } + + public init(_ array: [T], minLength: Int, maxLength: Int) { + assert(minLength >= 0) + assert(maxLength >= minLength) + + self.array = array + self.minLength = minLength + self.maxLength = maxLength + + validate() + } + + private func validate() { + assert(array.count >= minLength) + assert(array.count <= maxLength) + } +} + +extension ConfigLimitedSizeArray: RandomAccessCollection { + public typealias Element = T + public typealias Index = Int + + public var startIndex: Int { + 0 + } + + public var endIndex: Int { + array.count + } + + public subscript(position: Int) -> T { + get { + array[position] + } + set { + array[position] = newValue + validate() + } + } + + public func index(after i: Int) -> Int { + i + 1 + } + + public func index(before i: Int) -> Int { + i - 1 + } + + public func index(_ i: Int, offsetBy distance: Int) -> Int { + i + distance + } + + public func index(_ i: Int, offsetBy distance: Int, limitedBy limit: Int) -> Int? { + i + distance < limit ? i + distance : nil + } + + public func distance(from start: Int, to end: Int) -> Int { + end - start + } + + public func index(from start: Int) -> Int { + start + } + + public func formIndex(after i: inout Int) { + i += 1 + } + + public func formIndex(before i: inout Int) { + i -= 1 + } +} + +extension ConfigLimitedSizeArray { + public mutating func append(_ newElement: T) { + array.append(newElement) + validate() + } + + public mutating func insert(_ newElement: T, at i: Int) { + array.insert(newElement, at: i) + validate() + } + + public mutating func remove(at i: Int) -> T { + defer { validate() } + return array.remove(at: i) + } +} + +public typealias ConfigFixedSizeArray = ConfigLimitedSizeArray + +extension ConfigLimitedSizeArray { + public init( + withConfig config: TMinLength.TConfig, + from decoder: inout D, + decodeItem: @escaping (inout D) throws -> T + ) throws { + let minLength = TMinLength.read(config: config) + let maxLength = TMaxLength.read(config: config) + + if minLength == maxLength { + // fixed size array + try self.init(decoder.decode(.fixed(UInt(minLength), decodeItem)), minLength: minLength, maxLength: maxLength) + } else { + // variable size array + try self.init(decoder.decode(.array(decodeItem)), minLength: minLength, maxLength: maxLength) + } + } +} + +// not ScaleCodec.Decodable because we need to have the config to know the size limit +extension ConfigLimitedSizeArray where T: ScaleCodec.Decodable { + public init(withConfig config: TMinLength.TConfig, from decoder: inout some ScaleCodec.Decoder) throws { + let minLength = TMinLength.read(config: config) + let maxLength = TMaxLength.read(config: config) + + if minLength == maxLength { + // fixed size array + try self.init(decoder.decode(.fixed(UInt(minLength))), minLength: minLength, maxLength: maxLength) + } else { + // variable size array + try self.init(decoder.decode(), minLength: minLength, maxLength: maxLength) + } + } +} + +extension ConfigLimitedSizeArray: ScaleCodec.Encodable where T: ScaleCodec.Encodable { + public func encode(in encoder: inout some ScaleCodec.Encoder) throws { + if minLength == maxLength { + // fixed size array + try encoder.encode(array, .fixed(UInt(minLength))) + } else { + // variable size array + try encoder.encode(array) + } + } +} diff --git a/Utils/Sources/Utils/Dummy.swift b/Utils/Sources/Utils/Dummy.swift index c8b7a25a..a9944b3b 100644 --- a/Utils/Sources/Utils/Dummy.swift +++ b/Utils/Sources/Utils/Dummy.swift @@ -2,5 +2,6 @@ /// this is mostly used during initial development or testing /// should be avoided in production code public protocol Dummy { - static var dummy: Self { get } + associatedtype Config + static func dummy(withConfig config: Config) -> Self } diff --git a/Utils/Sources/Utils/Either.swift b/Utils/Sources/Utils/Either.swift index 09ecf79a..92e04bb6 100644 --- a/Utils/Sources/Utils/Either.swift +++ b/Utils/Sources/Utils/Either.swift @@ -18,7 +18,21 @@ extension Either: CustomStringConvertible where A: CustomStringConvertible, B: C } } -extension Either: ScaleCodec.Codable where A: ScaleCodec.Codable, B: ScaleCodec.Codable { +extension Either { + public init(from decoder: inout D, decodeLeft: (inout D) throws -> A, decodeRight: (inout D) throws -> B) throws { + let id = try decoder.decode(.enumCaseId) + switch id { + case 0: + self = try .left(decodeLeft(&decoder)) + case 1: + self = try .right(decodeRight(&decoder)) + default: + throw decoder.enumCaseError(for: id) + } + } +} + +extension Either: ScaleCodec.Decodable where A: ScaleCodec.Decodable, B: ScaleCodec.Decodable { public init(from decoder: inout some ScaleCodec.Decoder) throws { let id = try decoder.decode(.enumCaseId) switch id { @@ -30,7 +44,9 @@ extension Either: ScaleCodec.Codable where A: ScaleCodec.Codable, B: ScaleCodec. throw decoder.enumCaseError(for: id) } } +} +extension Either: ScaleCodec.Encodable where A: ScaleCodec.Encodable, B: ScaleCodec.Encodable { public func encode(in encoder: inout some ScaleCodec.Encoder) throws { switch self { case let .left(a): diff --git a/Utils/Sources/Utils/LimitedSizeArray.swift b/Utils/Sources/Utils/LimitedSizeArray.swift index 281983c8..a9c3e8b7 100644 --- a/Utils/Sources/Utils/LimitedSizeArray.swift +++ b/Utils/Sources/Utils/LimitedSizeArray.swift @@ -99,18 +99,18 @@ extension LimitedSizeArray: RandomAccessCollection { } } -public extension LimitedSizeArray { - mutating func append(_ newElement: T) { +extension LimitedSizeArray { + public mutating func append(_ newElement: T) { array.append(newElement) validate() } - mutating func insert(_ newElement: T, at i: Int) { + public mutating func insert(_ newElement: T, at i: Int) { array.insert(newElement, at: i) validate() } - mutating func remove(at i: Int) -> T { + public mutating func remove(at i: Int) -> T { defer { validate() } return array.remove(at: i) } diff --git a/Utils/Sources/Utils/ReadInt.swift b/Utils/Sources/Utils/ReadInt.swift new file mode 100644 index 00000000..cdf66e9a --- /dev/null +++ b/Utils/Sources/Utils/ReadInt.swift @@ -0,0 +1,4 @@ +public protocol ReadInt { + associatedtype TConfig + static func read(config: TConfig) -> Int +} diff --git a/Utils/Sources/Utils/Ref.swift b/Utils/Sources/Utils/Ref.swift index 34643b5a..d06cbb3a 100644 --- a/Utils/Sources/Utils/Ref.swift +++ b/Utils/Sources/Utils/Ref.swift @@ -1,22 +1,21 @@ import ScaleCodec -public final class Ref { - public let value: T +public class Ref { + public internal(set) var value: T - public init(_ value: T) { + public required init(_ value: T) { self.value = value } } -public final class RefMut { - public var value: T - - public init(_ value: T) { - self.value = value - } - - public func asRef() -> Ref { - Ref(value) +public class RefMut: Ref { + override public var value: T { + get { + super.value + } + set { + super.value = newValue + } } } @@ -33,17 +32,8 @@ extension Ref: Hashable where T: Hashable { } extension Ref: Dummy where T: Dummy { - public static var dummy: Ref { - 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) + public typealias Config = T.Config + public static func dummy(withConfig config: Config) -> Self { + Self(T.dummy(withConfig: config)) } } diff --git a/Utils/Sources/Utils/ScaleCodec.swift b/Utils/Sources/Utils/ScaleCodec.swift new file mode 100644 index 00000000..feb947c5 --- /dev/null +++ b/Utils/Sources/Utils/ScaleCodec.swift @@ -0,0 +1,17 @@ +import ScaleCodec + +extension CustomDecoderFactory where T: ArrayInitializable { + public static func array( + _ decodeItem: @escaping (inout D) throws -> T.IElement + ) -> CustomDecoderFactory { + CustomDecoderFactory { decoder in + var array: [T.IElement] = [] + let size = try decoder.decode(UInt32.self, .compact) + array.reserveCapacity(Int(size)) + for _ in 0 ..< size { + try array.append(decodeItem(&decoder)) + } + return T(array: array) + } + } +}