diff --git a/.swiftformat b/.swiftformat index 0b06b483..ae8569ff 100644 --- a/.swiftformat +++ b/.swiftformat @@ -2,3 +2,4 @@ --maxwidth 140 --asynccapturing debugCheck --closurevoid preserve +--disable typeSugar diff --git a/Blockchain/Sources/Blockchain/AuxDataStore/DataStore.swift b/Blockchain/Sources/Blockchain/AuxDataStore/DataStore.swift new file mode 100644 index 00000000..1a10df18 --- /dev/null +++ b/Blockchain/Sources/Blockchain/AuxDataStore/DataStore.swift @@ -0,0 +1,47 @@ +import Utils + +enum DataStoreError: Error { + case invalidPackageHash(Data32) + case invalidSegmentRoot(Data32) +} + +public final class DataStore: Sendable { + private let impl: DataStoreProtocol + private let network: DataStoreNetworkProtocol + + public init(_ impl: DataStoreProtocol, _ network: DataStoreNetworkProtocol) { + self.impl = impl + self.network = network + } + + public func fetchSegment(segments: [WorkItem.ImportedDataSegment]) async throws -> [Data4104] { + var result: [Data4104] = [] + + for segment in segments { + let segmentRoot = switch segment.root { + case let .segmentRoot(root): + root + case let .workPackageHash(hash): + try await impl.getSegmentRoot(forWorkPackageHash: hash).unwrap(orError: DataStoreError.invalidPackageHash(hash)) + } + let erasureRoot = try await impl.getEasureRoot(forSegmentRoot: segmentRoot) + .unwrap(orError: DataStoreError.invalidSegmentRoot(segmentRoot)) + + if let localData = try await impl.get(erasureRoot: erasureRoot, index: segment.index) { + result.append(localData) + } else { + // TODO: use network for fetch shards and reconstruct the segment + fatalError("not implemented") + } + } + + return result + } + + public func set(data: Data4104, erasureRoot: Data32, index: UInt16) async throws { + try await impl.set(data: data, erasureRoot: erasureRoot, index: index) + + // TODO; erasure code the data and store each chunk + // so assurer can query them later with CE137 + } +} diff --git a/Blockchain/Sources/Blockchain/AuxDataStore/DataStoreProtocol.swift b/Blockchain/Sources/Blockchain/AuxDataStore/DataStoreProtocol.swift new file mode 100644 index 00000000..3c213567 --- /dev/null +++ b/Blockchain/Sources/Blockchain/AuxDataStore/DataStoreProtocol.swift @@ -0,0 +1,22 @@ +import Utils + +public protocol DataStoreProtocol: Sendable { + // segment root => erasure root + func getEasureRoot(forSegmentRoot: Data32) async throws -> Data32? + func set(erasureRoot: Data32, forSegmentRoot: Data32) async throws + func delete(erasureRoot: Data32) async throws + + // work package hash => segment root + func getSegmentRoot(forWorkPackageHash: Data32) async throws -> Data32? + func set(segmentRoot: Data32, forWorkPackageHash: Data32) async throws + func delete(segmentRoot: Data32) async throws + + // erasure root + index => segment data + func get(erasureRoot: Data32, index: UInt16) async throws -> Data4104? + func set(data: Data4104, erasureRoot: Data32, index: UInt16) async throws +} + +public protocol DataStoreNetworkProtocol: Sendable { + // Use CE139/CE140 to fetch remote chunk + func fetchRemoteChunk(erasureRoot: Data32, shardIndex: UInt16, segmentIndices: [UInt16]) async throws -> Data12? +} diff --git a/Blockchain/Sources/Blockchain/AuxDataStore/InMemoryDataStoreBackend.swift b/Blockchain/Sources/Blockchain/AuxDataStore/InMemoryDataStoreBackend.swift new file mode 100644 index 00000000..1d6e6151 --- /dev/null +++ b/Blockchain/Sources/Blockchain/AuxDataStore/InMemoryDataStoreBackend.swift @@ -0,0 +1,54 @@ +import Utils + +public actor InMemoryDataStoreBackend { + // segment root => erasure root + private var erasureRootBySegmentRoot: [Data32: Data32] = [:] + + // work package hash => segment root + private var segmentRootByWorkPackageHash: [Data32: Data32] = [:] + + // erasure root + index => segment data + private var chunks: [Data32: [UInt16: Data4104]] = [:] + + public init() {} +} + +extension InMemoryDataStoreBackend: DataStoreProtocol { + public func getEasureRoot(forSegmentRoot: Data32) async throws -> Data32? { + erasureRootBySegmentRoot[forSegmentRoot] + } + + public func set(erasureRoot: Data32, forSegmentRoot: Data32) async throws { + erasureRootBySegmentRoot[forSegmentRoot] = erasureRoot + } + + public func delete(erasureRoot: Data32) async throws { + erasureRootBySegmentRoot.removeValue(forKey: erasureRoot) + } + + public func getSegmentRoot(forWorkPackageHash: Data32) async throws -> Data32? { + segmentRootByWorkPackageHash[forWorkPackageHash] + } + + public func set(segmentRoot: Data32, forWorkPackageHash: Data32) async throws { + segmentRootByWorkPackageHash[forWorkPackageHash] = segmentRoot + } + + public func delete(segmentRoot: Data32) async throws { + segmentRootByWorkPackageHash.removeValue(forKey: segmentRoot) + } + + public func get(erasureRoot: Data32, index: UInt16) async throws -> Data4104? { + chunks[erasureRoot]?[index] + } + + public func set(data: Data4104, erasureRoot: Data32, index: UInt16) async throws { + chunks[erasureRoot, default: [:]][index] = data + } +} + +extension InMemoryDataStoreBackend: DataStoreNetworkProtocol { + public func fetchRemoteChunk(erasureRoot _: Data32, shardIndex _: UInt16, segmentIndices _: [UInt16]) async throws -> Data12? { + nil + } +} diff --git a/Blockchain/Sources/Blockchain/BlockchainServices.swift b/Blockchain/Sources/Blockchain/BlockchainServices.swift index e182fe90..b71cc456 100644 --- a/Blockchain/Sources/Blockchain/BlockchainServices.swift +++ b/Blockchain/Sources/Blockchain/BlockchainServices.swift @@ -32,7 +32,8 @@ public class BlockchainServices { self.genesisBlock = genesisBlock self.genesisState = genesisState dataProvider = try! await BlockchainDataProvider(InMemoryDataProvider(genesisState: genesisState, genesisBlock: genesisBlock)) - dataStore = DataStore(InMemoryDataStore(), basePath: URL(fileURLWithPath: "/tmp/boka-test-data")) + let dataStoreBackend = InMemoryDataStoreBackend() + dataStore = DataStore(dataStoreBackend, dataStoreBackend) storeMiddleware = StoreMiddleware() eventBus = EventBus(eventMiddleware: .serial(Middleware(storeMiddleware), .noError), handlerMiddleware: .noError) @@ -82,7 +83,7 @@ public class BlockchainServices { eventBus: eventBus, keystore: keystore, scheduler: scheduler, - extrinsicPool: ExtrinsicPoolService(config: config, dataProvider: dataProvider, eventBus: eventBus) + safroleTicketPool: SafroleTicketPoolService(config: config, dataProvider: dataProvider, eventBus: eventBus) ) _blockAuthorRef = _blockAuthor return _blockAuthor! diff --git a/Blockchain/Sources/Blockchain/Config/ProtocolConfig.swift b/Blockchain/Sources/Blockchain/Config/ProtocolConfig.swift index 997e4548..fde01a0e 100644 --- a/Blockchain/Sources/Blockchain/Config/ProtocolConfig.swift +++ b/Blockchain/Sources/Blockchain/Config/ProtocolConfig.swift @@ -85,8 +85,7 @@ public struct ProtocolConfig: Sendable, Codable, Equatable { /// WM = 2^11: The maximum number of entries in a work-package manifest. public var maxWorkPackageManifestEntries: Int - /// WB = 12 * 2^20: The maximum size of an encoded work-package together with its extrinsic data and import impli- - /// cations, in octets. + /// WB = 12 * 2^20: The maximum size of an encoded work-package together with its extrinsic data and import implications, in octets. public var maxEncodedWorkPackageSize: Int /// WG = WP*WE = 4104: The size of a segment in octets. diff --git a/Blockchain/Sources/Blockchain/DataStore/DataStore.swift b/Blockchain/Sources/Blockchain/DataStore/DataStore.swift deleted file mode 100644 index ff1a3c1d..00000000 --- a/Blockchain/Sources/Blockchain/DataStore/DataStore.swift +++ /dev/null @@ -1,46 +0,0 @@ -import Foundation - -public protocol DataStoreProtocol: Sendable { - func read(path: URL) async throws -> Data? - func write(path: URL, value: Data) async throws - func delete(path: URL) async throws -} - -public final class DataStore: Sendable { - private let impl: DataStoreProtocol - private let basePath: URL - - public init(_ impl: DataStoreProtocol, basePath: URL) { - self.impl = impl - self.basePath = basePath - } - - // partitioning files so that we won't have too many files in a single directory - private func getPath(path: String, name: String) -> URL { - var ret = basePath - ret.append(component: path) - var name = name[...] - if let first = name.first { - ret.append(component: String(first), directoryHint: .isDirectory) - name = name.dropFirst() - } - if let second = name.first { - ret.append(component: String(second), directoryHint: .isDirectory) - name = name.dropFirst() - } - ret.append(component: String(name), directoryHint: .notDirectory) - return ret - } - - public func read(path: String, name: String) async throws -> Data? { - try await impl.read(path: getPath(path: path, name: name)) - } - - public func write(path: String, name: String, value: Data) async throws { - try await impl.write(path: getPath(path: path, name: name), value: value) - } - - public func delete(path: String, name: String) async throws { - try await impl.delete(path: getPath(path: path, name: name)) - } -} diff --git a/Blockchain/Sources/Blockchain/DataStore/FilesystemDataStore.swift b/Blockchain/Sources/Blockchain/DataStore/FilesystemDataStore.swift deleted file mode 100644 index 04d49585..00000000 --- a/Blockchain/Sources/Blockchain/DataStore/FilesystemDataStore.swift +++ /dev/null @@ -1,23 +0,0 @@ -import Foundation - -public actor FilesystemDataStore: DataStoreProtocol { - private let fileManager: FileManager - - public init(fileManager: FileManager = .default) { - self.fileManager = fileManager - } - - public func read(path: URL) async throws -> Data? { - try Data(contentsOf: path) - } - - public func write(path: URL, value: Data) async throws { - let base = path.deletingLastPathComponent() - try fileManager.createDirectory(at: base, withIntermediateDirectories: true) - try value.write(to: path) - } - - public func delete(path: URL) async throws { - try fileManager.removeItem(at: path) - } -} diff --git a/Blockchain/Sources/Blockchain/DataStore/InMemoryDataStore.swift b/Blockchain/Sources/Blockchain/DataStore/InMemoryDataStore.swift deleted file mode 100644 index 9880c381..00000000 --- a/Blockchain/Sources/Blockchain/DataStore/InMemoryDataStore.swift +++ /dev/null @@ -1,19 +0,0 @@ -import Foundation - -public actor InMemoryDataStore: DataStoreProtocol { - private var store: [URL: Data] = [:] - - public init() {} - - public func read(path: URL) async throws -> Data? { - store[path] - } - - public func write(path: URL, value: Data) async throws { - store[path] = value - } - - public func delete(path: URL) async throws { - store[path] = nil - } -} diff --git a/Blockchain/Sources/Blockchain/Types/WorkPackageBundle.swift b/Blockchain/Sources/Blockchain/Types/WorkPackageBundle.swift index 4644898a..cf5ad932 100644 --- a/Blockchain/Sources/Blockchain/Types/WorkPackageBundle.swift +++ b/Blockchain/Sources/Blockchain/Types/WorkPackageBundle.swift @@ -5,6 +5,6 @@ import Utils public struct WorkPackageBundle: Sendable, Equatable, Codable { public var workPackage: WorkPackage public var extrinsic: [Data] - public var importSegments: [[Data]] - public var justifications: [[Data]] + public var importSegments: [Data4104] + public var justifications: [Data] } diff --git a/Blockchain/Sources/Blockchain/VMInvocations/HostCall/HostCalls.swift b/Blockchain/Sources/Blockchain/VMInvocations/HostCall/HostCalls.swift index 70ab4c5f..61934246 100644 --- a/Blockchain/Sources/Blockchain/VMInvocations/HostCall/HostCalls.swift +++ b/Blockchain/Sources/Blockchain/VMInvocations/HostCall/HostCalls.swift @@ -743,9 +743,9 @@ public class Import: HostCall { public static var identifier: UInt8 { 18 } public let context: RefineContext.ContextType - public let importSegments: [Data] + public let importSegments: [Data4104] - public init(context: RefineContext.ContextType, importSegments: [Data]) { + public init(context: RefineContext.ContextType, importSegments: [Data4104]) { self.context = context self.importSegments = importSegments } @@ -762,7 +762,7 @@ public class Import: HostCall { let isWritable = state.isMemoryWritable(address: startAddr, length: Int(length)) if let segment, isWritable { - try state.writeMemory(address: startAddr, values: segment) + try state.writeMemory(address: startAddr, values: segment.data) } if !isWritable { @@ -803,13 +803,15 @@ public class Export: HostCall { segment = data } - if segment == nil { - state.writeRegister(Registers.Index(raw: 7), HostCallResultCode.OOB.rawValue) - } else if exportSegmentOffset + UInt64(segment!.count) >= UInt64(config.value.maxWorkPackageManifestEntries) { - state.writeRegister(Registers.Index(raw: 7), HostCallResultCode.FULL.rawValue) + if let segment { + if exportSegmentOffset + UInt64(segment.count) >= UInt64(config.value.maxWorkPackageManifestEntries) { + state.writeRegister(Registers.Index(raw: 7), HostCallResultCode.FULL.rawValue) + } else { + state.writeRegister(Registers.Index(raw: 7), exportSegmentOffset + UInt64(segment.count)) + context.exports.append(Data4104(segment)!) + } } else { - state.writeRegister(Registers.Index(raw: 7), exportSegmentOffset + UInt64(segment!.count)) - context.exports.append(segment!) + state.writeRegister(Registers.Index(raw: 7), HostCallResultCode.OOB.rawValue) } } } diff --git a/Blockchain/Sources/Blockchain/VMInvocations/InvocationContexts/RefineContext.swift b/Blockchain/Sources/Blockchain/VMInvocations/InvocationContexts/RefineContext.swift index a4fecb31..7f4e79b5 100644 --- a/Blockchain/Sources/Blockchain/VMInvocations/InvocationContexts/RefineContext.swift +++ b/Blockchain/Sources/Blockchain/VMInvocations/InvocationContexts/RefineContext.swift @@ -1,6 +1,7 @@ import Foundation import PolkaVM import TracingUtils +import Utils private let logger = Logger(label: "RefineContext") @@ -13,12 +14,12 @@ public struct InnerPvm { public class RefineContext: InvocationContext { public typealias ContextType = ( pvms: [UInt64: InnerPvm], - exports: [Data] + exports: [Data4104] ) public let config: ProtocolConfigRef public var context: ContextType - public let importSegments: [Data] + public let importSegments: [Data4104] public let exportSegmentOffset: UInt64 public let service: ServiceIndex public let serviceAccounts: ServiceAccounts @@ -27,7 +28,7 @@ public class RefineContext: InvocationContext { public init( config: ProtocolConfigRef, context: ContextType, - importSegments: [Data], + importSegments: [Data4104], exportSegmentOffset: UInt64, service: ServiceIndex, serviceAccounts: some ServiceAccounts, diff --git a/Blockchain/Sources/Blockchain/VMInvocations/Invocations/RefineInvocation.swift b/Blockchain/Sources/Blockchain/VMInvocations/Invocations/RefineInvocation.swift index e603d1bb..20ab5973 100644 --- a/Blockchain/Sources/Blockchain/VMInvocations/Invocations/RefineInvocation.swift +++ b/Blockchain/Sources/Blockchain/VMInvocations/Invocations/RefineInvocation.swift @@ -15,10 +15,10 @@ public protocol RefineInvocation { refinementCtx: RefinementContext, // c authorizerHash: Data32, authorizationOutput: Data, - importSegments: [Data], + importSegments: [Data4104], extrinsicDataBlobs: [Data], exportSegmentOffset: UInt64 - ) async throws -> (result: Result, exports: [Data]) + ) async throws -> (result: Result, exports: [Data4104]) } extension RefineInvocation { @@ -33,10 +33,10 @@ extension RefineInvocation { refinementCtx: RefinementContext, // c authorizerHash: Data32, authorizationOutput: Data, - importSegments: [Data], + importSegments: [Data4104], extrinsicDataBlobs: [Data], exportSegmentOffset: UInt64 - ) async throws -> (result: Result, exports: [Data]) { + ) async throws -> (result: Result, exports: [Data4104]) { let codeBlob = try await serviceAccounts.historicalLookup( serviceAccount: service, timeslot: refinementCtx.lookupAnchor.timeslot, diff --git a/Blockchain/Sources/Blockchain/Validator/BlockAuthor.swift b/Blockchain/Sources/Blockchain/Validator/BlockAuthor.swift index 75baa9d3..787461f9 100644 --- a/Blockchain/Sources/Blockchain/Validator/BlockAuthor.swift +++ b/Blockchain/Sources/Blockchain/Validator/BlockAuthor.swift @@ -7,7 +7,7 @@ import Utils public final class BlockAuthor: ServiceBase2, @unchecked Sendable { private let dataProvider: BlockchainDataProvider private let keystore: KeyStore - private let extrinsicPool: ExtrinsicPoolService + private let safroleTicketPool: SafroleTicketPoolService private let tickets: ThreadSafeContainer<[RuntimeEvents.SafroleTicketsGenerated]> = .init([]) @@ -17,11 +17,11 @@ public final class BlockAuthor: ServiceBase2, @unchecked Sendable { eventBus: EventBus, keystore: KeyStore, scheduler: Scheduler, - extrinsicPool: ExtrinsicPoolService + safroleTicketPool: SafroleTicketPoolService ) async { self.dataProvider = dataProvider self.keystore = keystore - self.extrinsicPool = extrinsicPool + self.safroleTicketPool = safroleTicketPool super.init(id: "BlockAuthor", config: config, eventBus: eventBus, scheduler: scheduler) @@ -57,7 +57,7 @@ public final class BlockAuthor: ServiceBase2, @unchecked Sendable { let stateRoot = await state.value.stateRoot let epoch = timeslot.timeslotToEpochIndex(config: config) - let pendingTickets = await extrinsicPool.getPendingTickets(epoch: epoch) + let pendingTickets = await safroleTicketPool.getPendingTickets(epoch: epoch) let existingTickets = SortedArray(sortedUnchecked: state.value.safroleState.ticketsAccumulator.array.map(\.id)) let tickets = pendingTickets.array .lazy diff --git a/Blockchain/Sources/Blockchain/Validator/DataAvailability.swift b/Blockchain/Sources/Blockchain/Validator/DataAvailability.swift index 8d731c37..57b42a87 100644 --- a/Blockchain/Sources/Blockchain/Validator/DataAvailability.swift +++ b/Blockchain/Sources/Blockchain/Validator/DataAvailability.swift @@ -1,3 +1,4 @@ +import Codec import Foundation import TracingUtils import Utils @@ -39,16 +40,28 @@ public final class DataAvailability: ServiceBase2, @unchecked Sendable { // of 28 days (672 complete epochs) following the reporting of the work-report. } - public func fetchSegment(root _: Data32, index _: UInt16) async throws -> Data? { - // TODO: fetch segment - nil + public func fetchSegment(segments: [WorkItem.ImportedDataSegment]) async throws -> [Data4104] { + try await dataStore.fetchSegment(segments: segments) } - public func exportSegments(data _: [Data]) async throws { - // TODO: export segments + public func exportSegments(data: [Data4104], erasureRoot: Data32) async throws -> Data32 { + let segmentRoot = Merklization.constantDepthMerklize(data.map(\.data)) + + for (index, data) in data.enumerated() { + try await dataStore.set(data: data, erasureRoot: erasureRoot, index: UInt16(index)) + } + + return segmentRoot } - public func distributeWorkpackageBundle(bundle _: WorkPackageBundle) async throws { + public func exportWorkpackageBundle(bundle: WorkPackageBundle) async throws -> (erasureRoot: Data32, length: DataLength) { // TODO: distribute workpackage bundle to audits DA + // and correctly generate the erasure root + + // This is just a mock implementation + let data = try JamEncoder.encode(bundle) + let erasureRoot = data.blake2b256hash() + + return (erasureRoot, DataLength(data.count)) } } diff --git a/Blockchain/Sources/Blockchain/Validator/ExtrinsicPoolService.swift b/Blockchain/Sources/Blockchain/Validator/ExtrinsicPools/SafroleTicketPoolService.swift similarity index 96% rename from Blockchain/Sources/Blockchain/Validator/ExtrinsicPoolService.swift rename to Blockchain/Sources/Blockchain/Validator/ExtrinsicPools/SafroleTicketPoolService.swift index 604afb04..9f5db608 100644 --- a/Blockchain/Sources/Blockchain/Validator/ExtrinsicPoolService.swift +++ b/Blockchain/Sources/Blockchain/Validator/ExtrinsicPools/SafroleTicketPoolService.swift @@ -69,7 +69,7 @@ private actor ServiceStorage { } } -public final class ExtrinsicPoolService: ServiceBase, @unchecked Sendable { +public final class SafroleTicketPoolService: ServiceBase, @unchecked Sendable { private var storage: ServiceStorage private let dataProvider: BlockchainDataProvider @@ -83,7 +83,7 @@ public final class ExtrinsicPoolService: ServiceBase, @unchecked Sendable { let ringContext = try! Bandersnatch.RingContext(size: UInt(config.value.totalNumberOfValidators)) storage = ServiceStorage(ringContext: ringContext) - super.init(id: "ExtrinsicPoolService", config: config, eventBus: eventBus) + super.init(id: "SafroleTicketPoolService", config: config, eventBus: eventBus) await storage.setLogger(logger) diff --git a/Blockchain/Sources/Blockchain/Validator/WorkPackagePoolService.swift b/Blockchain/Sources/Blockchain/Validator/ExtrinsicPools/WorkPackagePoolService.swift similarity index 100% rename from Blockchain/Sources/Blockchain/Validator/WorkPackagePoolService.swift rename to Blockchain/Sources/Blockchain/Validator/ExtrinsicPools/WorkPackagePoolService.swift diff --git a/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift b/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift index 30e1a709..05923d75 100644 --- a/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift +++ b/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift @@ -6,6 +6,9 @@ import Utils public enum GuaranteeingServiceError: Error { case invalidValidatorIndex case customValidatorNotFound + case noAuthorizerHash + case invalidCoreIndex + case invalidExports } struct GuaranteeingAuthorizationFunction: IsAuthorizedFunction {} @@ -15,7 +18,7 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable { private let dataProvider: BlockchainDataProvider private let keystore: KeyStore private let runtime: Runtime - private let extrinsicPool: ExtrinsicPoolService + private let safroleTicketPool: SafroleTicketPoolService private let workPackagePool: WorkPackagePoolService private let guarantees: ThreadSafeContainer<[RuntimeEvents.GuaranteeGenerated]> = .init([]) private let authorizationFunction: GuaranteeingAuthorizationFunction @@ -29,13 +32,13 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable { dataProvider: BlockchainDataProvider, keystore: KeyStore, runtime: Runtime, - extrinsicPool: ExtrinsicPoolService, + safroleTicketPool: SafroleTicketPoolService, dataStore: DataStore ) async { self.dataProvider = dataProvider self.keystore = keystore self.runtime = runtime - self.extrinsicPool = extrinsicPool + self.safroleTicketPool = safroleTicketPool authorizationFunction = GuaranteeingAuthorizationFunction() refineInvocation = GuaranteeingRefineInvocation() workPackagePool = await WorkPackagePoolService(config: config, dataProvider: dataProvider, eventBus: eventBus) @@ -75,7 +78,11 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable { logger.error("AuthorIndex not found") throw GuaranteeingServiceError.invalidValidatorIndex } - let coreIndex = CoreIndex(currentCoreAssignment[Int(authorIndex)]) + let coreIndex = currentCoreAssignment[Int(authorIndex)] + guard coreIndex < CoreIndex(config.value.totalNumberOfCores) else { + throw GuaranteeingServiceError.invalidCoreIndex + } + let workPackages = await workPackagePool.getWorkPackages() for workPackage in workPackages.array { if try validate(workPackage: workPackage) { @@ -94,10 +101,9 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable { private func createWorkReport(for workPackage: WorkPackage, coreIndex: CoreIndex) async throws -> WorkReport { let state = try await dataProvider.getState(hash: dataProvider.bestHead.hash) let packageHash = workPackage.hash() - let corePool = state.value.coreAuthorizationPool[UInt16(coreIndex)] - // TODO: fix empty data - let authorizerHash = corePool.array.first ?? Data32() - var exportSegmentOffset: UInt64 = 0 + let corePool = state.value.coreAuthorizationPool[coreIndex] + let authorizerHash = try corePool.array.first.unwrap(orError: GuaranteeingServiceError.noAuthorizerHash) + var exportSegmentOffset: UInt16 = 0 // B.2. the authorization output, the result of the Is-Authorized function // TODO: waiting for authorizationFunction done Mock a result // let res = try await authorizationFunction.invoke(config: config, serviceAccounts: state.value, package: workPackage, coreIndex: @@ -107,21 +113,16 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable { // authorizationFunction -> authorizationOutput case let .success(authorizationOutput): var workResults = [WorkResult]() + + var exportSegments = [Data4104]() + for item in workPackage.workItems { - var importSegments = [Data]() - for importSegment in item.inputs { - switch importSegment.root { - case let .segmentRoot(data): - importSegments.append(data.data) - case let .workPackageHash(data): - importSegments.append(data.data) - } - } + // TODO: make this lazy. only fetch when needed by PVM + let importSegments = try await dataAvailability.fetchSegment(segments: item.inputs) - // TODO: generally by the work-package builder. + // TODO: generated by the work-package builder. let extrinsicDataBlobs = [Data]() - // TODO: fix exportSegments func - try await dataAvailability.exportSegments(data: importSegments) + // RefineInvocation invoke up data to workresult let refineRes = try await refineInvocation .invoke( @@ -137,10 +138,10 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable { authorizationOutput: authorizationOutput, importSegments: importSegments, extrinsicDataBlobs: extrinsicDataBlobs, - exportSegmentOffset: exportSegmentOffset + exportSegmentOffset: UInt64(exportSegmentOffset) ) // Export -> DA or exportSegmentOffset + outputDataSegmentsCount ? - exportSegmentOffset += UInt64(item.outputDataSegmentsCount) + exportSegmentOffset += item.outputDataSegmentsCount let workResult = WorkResult( serviceIndex: item.serviceIndex, codeHash: workPackage.authorizationCodeHash, @@ -149,14 +150,30 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable { output: WorkOutput(refineRes.result) ) workResults.append(workResult) + + guard item.outputDataSegmentsCount == refineRes.exports.count else { + throw GuaranteeingServiceError.invalidExports + } + + exportSegments.append(contentsOf: refineRes.exports) } + + let (erasureRoot, length) = try await dataAvailability.exportWorkpackageBundle(bundle: WorkPackageBundle( + workPackage: workPackage, + extrinsic: [], // TODO: get extrinsic data + importSegments: [], + justifications: [] + )) + + let segmentRoot = try await dataAvailability.exportSegments(data: exportSegments, erasureRoot: erasureRoot) + // TODO: generate or find AvailabilitySpecifications 14.4.1 work-package bundle let packageSpecification = AvailabilitySpecifications( workPackageHash: packageHash, - length: 0, - erasureRoot: Data32(), - segmentRoot: Data32(), - segmentCount: UInt16(exportSegmentOffset) + length: length, + erasureRoot: erasureRoot, + segmentRoot: segmentRoot, + segmentCount: exportSegmentOffset ) // The historical lookup function, Λ, is defined in equation 9.7. var oldLookups = [Data32: Data32]() diff --git a/Blockchain/Sources/Blockchain/Validator/ValidatorService.swift b/Blockchain/Sources/Blockchain/Validator/ValidatorService.swift index cffde517..387ffa01 100644 --- a/Blockchain/Sources/Blockchain/Validator/ValidatorService.swift +++ b/Blockchain/Sources/Blockchain/Validator/ValidatorService.swift @@ -5,7 +5,7 @@ public final class ValidatorService: Sendable { private let blockchain: Blockchain private let keystore: KeyStore private let safrole: SafroleService - private let extrinsicPool: ExtrinsicPoolService + private let safroleTicketPool: SafroleTicketPoolService private let blockAuthor: BlockAuthor private let dataAvailability: DataAvailability @@ -26,7 +26,7 @@ public final class ValidatorService: Sendable { keystore: keystore ) - extrinsicPool = await ExtrinsicPoolService( + safroleTicketPool = await SafroleTicketPoolService( config: blockchain.config, dataProvider: dataProvider, eventBus: eventBus @@ -38,7 +38,7 @@ public final class ValidatorService: Sendable { eventBus: eventBus, keystore: keystore, scheduler: scheduler, - extrinsicPool: extrinsicPool + safroleTicketPool: safroleTicketPool ) dataAvailability = await DataAvailability( diff --git a/Blockchain/Sources/Blockchain/typealias.swift b/Blockchain/Sources/Blockchain/typealias.swift new file mode 100644 index 00000000..85720853 --- /dev/null +++ b/Blockchain/Sources/Blockchain/typealias.swift @@ -0,0 +1,5 @@ +import Foundation +import Utils + +public typealias Data32 = Utils.Data32 +public typealias Data = Foundation.Data diff --git a/Blockchain/Tests/BlockchainTests/GuaranteeingServiceTests.swift b/Blockchain/Tests/BlockchainTests/GuaranteeingServiceTests.swift index 878489a4..ac7d9a1f 100644 --- a/Blockchain/Tests/BlockchainTests/GuaranteeingServiceTests.swift +++ b/Blockchain/Tests/BlockchainTests/GuaranteeingServiceTests.swift @@ -17,7 +17,7 @@ struct GuaranteeingServiceTests { keysCount: keysCount ) - let extrinsicPoolService = await ExtrinsicPoolService( + let SafroleTicketPoolService = await SafroleTicketPoolService( config: config, dataProvider: services.dataProvider, eventBus: services.eventBus @@ -32,7 +32,7 @@ struct GuaranteeingServiceTests { dataProvider: services.dataProvider, keystore: services.keystore, runtime: runtime, - extrinsicPool: extrinsicPoolService, + safroleTicketPool: SafroleTicketPoolService, dataStore: services.dataStore ) return (services, guaranteeingService) diff --git a/Blockchain/Tests/BlockchainTests/SafroleServiceTests.swift b/Blockchain/Tests/BlockchainTests/SafroleServiceTests.swift index 268db2d5..474eb048 100644 --- a/Blockchain/Tests/BlockchainTests/SafroleServiceTests.swift +++ b/Blockchain/Tests/BlockchainTests/SafroleServiceTests.swift @@ -62,7 +62,7 @@ struct SafroleServiceTests { headerHash: newBlock.hash, mmr: MMR([]), stateRoot: Data32(), - lookup: [Data32: Data32]() + lookup: .init() )) } @@ -91,7 +91,7 @@ struct SafroleServiceTests { headerHash: newBlock.hash, mmr: MMR([]), stateRoot: Data32(), - lookup: [Data32: Data32]() + lookup: .init() )) } diff --git a/Blockchain/Tests/BlockchainTests/ExtrinsicPoolServiceTests.swift b/Blockchain/Tests/BlockchainTests/SafroleTicketPoolServiceTests.swift similarity index 89% rename from Blockchain/Tests/BlockchainTests/ExtrinsicPoolServiceTests.swift rename to Blockchain/Tests/BlockchainTests/SafroleTicketPoolServiceTests.swift index e9a17aa4..15b838b6 100644 --- a/Blockchain/Tests/BlockchainTests/ExtrinsicPoolServiceTests.swift +++ b/Blockchain/Tests/BlockchainTests/SafroleTicketPoolServiceTests.swift @@ -5,14 +5,14 @@ import Utils @testable import Blockchain -struct ExtrinsicPoolServiceTests { +struct SafroleTicketPoolServiceTests { let config: ProtocolConfigRef let timeProvider: MockTimeProvider let dataProvider: BlockchainDataProvider let eventBus: EventBus let keystore: KeyStore let storeMiddleware: StoreMiddleware - let extrinsicPoolService: ExtrinsicPoolService + let poolService: SafroleTicketPoolService let ringContext: Bandersnatch.RingContext init() async throws { @@ -29,7 +29,7 @@ struct ExtrinsicPoolServiceTests { keystore = try await DevKeyStore(devKeysCount: config.value.totalNumberOfValidators) - extrinsicPoolService = await ExtrinsicPoolService(config: config, dataProvider: dataProvider, eventBus: eventBus) + poolService = await SafroleTicketPoolService(config: config, dataProvider: dataProvider, eventBus: eventBus) ringContext = try Bandersnatch.RingContext(size: UInt(config.value.totalNumberOfValidators)) @@ -66,7 +66,7 @@ struct ExtrinsicPoolServiceTests { // Wait for the event to be processed await storeMiddleware.wait() - let pendingTickets = await extrinsicPoolService + let pendingTickets = await poolService .getPendingTickets(epoch: state.value.timeslot.timeslotToEpochIndex(config: config)) #expect(pendingTickets == allTickets) } @@ -110,7 +110,7 @@ struct ExtrinsicPoolServiceTests { // Wait for the event to be processed await storeMiddleware.wait() - let pendingTickets = await extrinsicPoolService.getPendingTickets(epoch: state.value.timeslot.timeslotToEpochIndex(config: config)) + let pendingTickets = await poolService.getPendingTickets(epoch: state.value.timeslot.timeslotToEpochIndex(config: config)) #expect(pendingTickets == allTickets) } @@ -164,7 +164,7 @@ struct ExtrinsicPoolServiceTests { await storeMiddleware.wait() // Check that the tickets in the block have been removed from the pool - let pendingTickets = await extrinsicPoolService.getPendingTickets(epoch: state.value.timeslot.timeslotToEpochIndex(config: config)) + let pendingTickets = await poolService.getPendingTickets(epoch: state.value.timeslot.timeslotToEpochIndex(config: config)) #expect(pendingTickets.array == Array(tickets[2 ..< 4]).sorted()) } @@ -194,8 +194,8 @@ struct ExtrinsicPoolServiceTests { let epoch = state.value.timeslot.timeslotToEpochIndex(config: config) - #expect(await extrinsicPoolService.getPendingTickets(epoch: epoch).count == 4) - #expect(await extrinsicPoolService.getPendingTickets(epoch: epoch + 1).count == 0) + #expect(await poolService.getPendingTickets(epoch: epoch).count == 4) + #expect(await poolService.getPendingTickets(epoch: epoch + 1).count == 0) // Simulate an epoch change with new entropy let nextTimeslot = state.value.timeslot + TimeslotIndex(config.value.epochLength) @@ -215,7 +215,7 @@ struct ExtrinsicPoolServiceTests { headerHash: newBlock.hash, mmr: MMR([]), stateRoot: Data32(), - lookup: [Data32: Data32]() + lookup: .init() )) } @@ -240,10 +240,10 @@ struct ExtrinsicPoolServiceTests { await eventBus.publish(newAddEvent) await storeMiddleware.wait() - let finalPendingTickets = await extrinsicPoolService.getPendingTickets(epoch: epoch + 1) + let finalPendingTickets = await poolService.getPendingTickets(epoch: epoch + 1) #expect(finalPendingTickets.array == newTickets.sorted()) - #expect(await extrinsicPoolService.getPendingTickets(epoch: epoch).count == 0) - #expect(await extrinsicPoolService.getPendingTickets(epoch: epoch + 2).count == 0) + #expect(await poolService.getPendingTickets(epoch: epoch).count == 0) + #expect(await poolService.getPendingTickets(epoch: epoch + 2).count == 0) } } diff --git a/Blockchain/Tests/BlockchainTests/StateTrieTests.swift b/Blockchain/Tests/BlockchainTests/StateTrieTests.swift index 7b090ce0..ea937943 100644 --- a/Blockchain/Tests/BlockchainTests/StateTrieTests.swift +++ b/Blockchain/Tests/BlockchainTests/StateTrieTests.swift @@ -5,7 +5,7 @@ import Utils @testable import Blockchain private func merklize(_ data: some Sequence<(key: Data32, value: Data)>) -> Data32 { - var dict = [Data32: Data]() + var dict: [Data32: Data] = [:] for (key, value) in data { dict[key] = value } diff --git a/Boka/Sources/Boka.swift b/Boka/Sources/Boka.swift index d5442815..e5d13943 100644 --- a/Boka/Sources/Boka.swift +++ b/Boka/Sources/Boka.swift @@ -122,12 +122,6 @@ struct Boka: AsyncParsableCommand { return .rocksDB(path: path) } ?? .inMemory - let dataStore: DataStoreKind = basePath.map { - var path = URL(fileURLWithPath: $0) - path.append(path: "da") - return .filesystem(path: path) - } ?? .inMemory - logger.info("Peers: \(peers)") if validator { @@ -177,8 +171,7 @@ struct Boka: AsyncParsableCommand { peers: peers, local: local, name: name, - database: database, - dataStore: dataStore + database: database ) let node: Node = if validator { diff --git a/Database/Sources/Database/RocksDBBackend.swift b/Database/Sources/Database/RocksDBBackend.swift index 172cd4a5..54396e37 100644 --- a/Database/Sources/Database/RocksDBBackend.swift +++ b/Database/Sources/Database/RocksDBBackend.swift @@ -236,7 +236,7 @@ extension RocksDBBackend: StateBackendProtocol { let iterator = db.createIterator(column: .state, readOptions: readOptions) iterator.seek(to: startKey ?? prefix) - var ret = [(key: Data, value: Data)]() + var ret: [(key: Data, value: Data)] = [] if let limit { ret.reserveCapacity(Int(limit)) } diff --git a/Networking/Sources/Networking/Connection.swift b/Networking/Sources/Networking/Connection.swift index 44a3e693..8d951c2f 100644 --- a/Networking/Sources/Networking/Connection.swift +++ b/Networking/Sources/Networking/Connection.swift @@ -28,6 +28,7 @@ enum ConnectionState { case connecting(continuations: [CheckedContinuation]) case connected(publicKey: Data) case closed + case closing case reconnect(publicKey: Data) } @@ -51,7 +52,7 @@ public final class Connection: Sendable, ConnectionInfoP nil case let .connected(publicKey): publicKey - case .closed: + case .closed, .closing: nil case let .reconnect(publicKey): publicKey @@ -99,19 +100,28 @@ public final class Connection: Sendable, ConnectionInfoP for continuation in continuations { continuation.resume(throwing: ConnectionError.closed) } - state = .closed } state = .closed } } + func closing() { + state.write { state in + if case let .connecting(continuations) = state { + for continuation in continuations { + continuation.resume(throwing: ConnectionError.closed) + } + } + state = .closing + } + } + func reconnect(publicKey: Data) { state.write { state in if case let .connecting(continuations) = state { for continuation in continuations { continuation.resume(throwing: ConnectionError.reconnect) } - state = .reconnect(publicKey: publicKey) } state = .reconnect(publicKey: publicKey) } @@ -119,10 +129,12 @@ public final class Connection: Sendable, ConnectionInfoP public var isClosed: Bool { state.read { - if case .closed = $0 { - return true + switch $0 { + case .closed, .closing: + true + case .connected, .reconnect, .connecting: + false } - return false } } @@ -140,11 +152,7 @@ public final class Connection: Sendable, ConnectionInfoP switch $0 { case .connecting: false - case .connected: - true - case .closed: - true - case .reconnect: + case .connected, .closed, .closing, .reconnect: true } } @@ -165,6 +173,7 @@ public final class Connection: Sendable, ConnectionInfoP } public func close(abort: Bool = false) { + closing() try? connection.shutdown(errorCode: abort ? 1 : 0) // TODO: define some error code } diff --git a/Networking/Sources/Networking/Peer.swift b/Networking/Sources/Networking/Peer.swift index c83fbc85..8180d4c2 100644 --- a/Networking/Sources/Networking/Peer.swift +++ b/Networking/Sources/Networking/Peer.swift @@ -177,14 +177,17 @@ public final class Peer: Sendable { public func broadcast( kind: Handler.PresistentHandler.StreamKind, message: Handler.PresistentHandler.Message ) { - let connections = impl.connections.read { connections in - connections.byId.values - } guard let messageData = try? message.encode() else { impl.logger.warning("Failed to encode message: \(message)") return } + let connections = impl.connections.read { connections in + connections.byId.values + } for connection in connections { + if connection.isClosed { + continue + } if let stream = try? connection.createPreistentStream(kind: kind) { Task { let res = await Result { @@ -210,8 +213,9 @@ public final class Peer: Sendable { } // there should be only one connection per peer + // exlcude closed connections public var peersCount: Int { - impl.connections.read { $0.byId.count } + impl.connections.read { $0.byId.count { $0.value.isClosed == false } } } public var peersRole: PeerRole { diff --git a/Networking/Tests/NetworkingTests/PeerTests.swift b/Networking/Tests/NetworkingTests/PeerTests.swift index 555113d0..e9c0853e 100644 --- a/Networking/Tests/NetworkingTests/PeerTests.swift +++ b/Networking/Tests/NetworkingTests/PeerTests.swift @@ -166,8 +166,9 @@ struct PeerTests { let con = try peer.connect(to: centerPeer.listenAddress(), role: .builder) try await con.ready() } - // Simulate close connections 1~3s - try? await Task.sleep(for: .milliseconds(1000)) + + #expect(centerPeer.peersCount == 3) + centerPeer.broadcast(kind: .uniqueA, message: .init(kind: .uniqueA, data: Data("connection rotation strategy".utf8))) try? await Task.sleep(for: .milliseconds(100)) var receivedCount = 0 @@ -313,7 +314,7 @@ struct PeerTests { peer1.broadcast( kind: .uniqueA, message: .init(kind: .uniqueA, data: messageData) ) - try? await Task.sleep(for: .milliseconds(100)) + try? await Task.sleep(for: .milliseconds(500)) let lastReceivedData = await handler2.lastReceivedData #expect(lastReceivedData == messageData) @@ -372,7 +373,7 @@ struct PeerTests { peer1.broadcast( kind: .uniqueA, message: .init(kind: .uniqueA, data: messageData) ) - try? await Task.sleep(for: .milliseconds(100)) + try? await Task.sleep(for: .milliseconds(500)) let lastReceivedData = await handler2.lastReceivedData #expect(lastReceivedData == messageData) @@ -546,7 +547,7 @@ struct PeerTests { #expect(receivedData == messageData + Data(" response".utf8)) try? await Task.sleep(for: .milliseconds(100)) // Simulate abnormal shutdown of connections - connection.close(abort: true) + try connection.connection.shutdown(errorCode: 1) // Wait to simulate downtime & reconnected 3~5s try? await Task.sleep(for: .milliseconds(3000)) peer1.broadcast( @@ -650,7 +651,7 @@ struct PeerTests { #expect(receivedData == messageData + Data(" response".utf8)) try? await Task.sleep(for: .milliseconds(100)) // Simulate a peer failure by disconnecting one peer - connection.close(abort: false) + try connection.connection.shutdown() // Wait to simulate downtime try? await Task.sleep(for: .milliseconds(200)) // Reconnect the failing peer diff --git a/Node/Sources/Node/ChainSpec.swift b/Node/Sources/Node/ChainSpec.swift index b5e8bed5..d84cef7d 100644 --- a/Node/Sources/Node/ChainSpec.swift +++ b/Node/Sources/Node/ChainSpec.swift @@ -72,7 +72,7 @@ public struct ChainSpec: Codable, Equatable { try decoder.setConfig(mergeConfig(preset: preset, config: config)) block = try container.decode(Data.self, forKey: .block) - state = try container.decode([String: Data].self, forKey: .state) + state = try container.decode(Dictionary.self, forKey: .state) } public func getConfig() throws -> ProtocolConfigRef { @@ -84,7 +84,7 @@ public struct ChainSpec: Codable, Equatable { } public func getState() throws -> [Data32: Data] { - var output = [Data32: Data]() + var output: [Data32: Data] = [:] for (key, value) in state { try output[Data32(fromHexString: key).unwrap()] = value } diff --git a/Node/Sources/Node/Config.swift b/Node/Sources/Node/Config.swift index 958d6fe1..4f88cba7 100644 --- a/Node/Sources/Node/Config.swift +++ b/Node/Sources/Node/Config.swift @@ -15,7 +15,7 @@ public enum Database { case inMemory case rocksDB(path: URL) - public func open(chainspec: ChainSpec) async throws -> BlockchainDataProvider { + public func open(chainspec: ChainSpec) async throws -> (BlockchainDataProvider, DataStore) { switch self { case let .rocksDB(path): logger.debug("Using RocksDB backend at \(path.absoluteString)") @@ -25,7 +25,10 @@ public enum Database { genesisBlock: chainspec.getBlock(), genesisStateData: chainspec.getState() ) - return try await BlockchainDataProvider(backend) + let dataProvider = try await BlockchainDataProvider(backend) + // TODO: implement RocksDBDataStoreBackend + let dataStore = DataStore(InMemoryDataStoreBackend(), InMemoryDataStoreBackend()) + return (dataProvider, dataStore) case .inMemory: logger.debug("Using in-memory backend") let genesisBlock = try chainspec.getBlock() @@ -34,24 +37,12 @@ public enum Database { try await backend.writeRaw(Array(genesisStateData)) let genesisState = try await State(backend: backend) let genesisStateRef = StateRef(genesisState) - return try await BlockchainDataProvider(InMemoryDataProvider(genesisState: genesisStateRef, genesisBlock: genesisBlock)) - } - } -} - -public enum DataStoreKind { - case inMemory - case filesystem(path: URL) - - func create() -> DataStore { - switch self { - case let .filesystem(path): - logger.info("Using filesystem data store at \(path.absoluteString)") - let dataStore = FilesystemDataStore() - return DataStore(dataStore, basePath: path) - case .inMemory: - logger.info("Using in-memory data store") - return DataStore(InMemoryDataStore(), basePath: URL(filePath: "/tmp/boka")) + let dataProvider = try await BlockchainDataProvider(InMemoryDataProvider( + genesisState: genesisStateRef, + genesisBlock: genesisBlock + )) + let dataStore = DataStore(InMemoryDataStoreBackend(), InMemoryDataStoreBackend()) + return (dataProvider, dataStore) } } } @@ -63,7 +54,6 @@ public struct Config { public var local: Bool public var name: String? public var database: Database - public var dataStore: DataStoreKind public init( rpc: RPCConfig?, @@ -71,8 +61,7 @@ public struct Config { peers: [NetAddr] = [], local: Bool = false, name: String? = nil, - database: Database = .inMemory, - dataStore: DataStoreKind = .inMemory + database: Database = .inMemory ) { self.rpc = rpc self.network = network @@ -80,6 +69,5 @@ public struct Config { self.local = local self.name = name self.database = database - self.dataStore = dataStore } } diff --git a/Node/Sources/Node/Genesis.swift b/Node/Sources/Node/Genesis.swift index 2de32f90..9a161618 100644 --- a/Node/Sources/Node/Genesis.swift +++ b/Node/Sources/Node/Genesis.swift @@ -44,7 +44,7 @@ extension Genesis { case let .preset(preset): let config = preset.config let (state, block) = try State.devGenesis(config: config) - var kv = [String: Data]() + var kv: [String: Data] = [:] for (key, value) in state.value.layer.toKV() { if let value { kv[key.toHexString()] = try JamEncoder.encode(value) diff --git a/Node/Sources/Node/Node.swift b/Node/Sources/Node/Node.swift index e622e73f..fc6186a0 100644 --- a/Node/Sources/Node/Node.swift +++ b/Node/Sources/Node/Node.swift @@ -14,6 +14,7 @@ public class Node { public let rpcServer: Server? public let scheduler: Scheduler public let dataProvider: BlockchainDataProvider + public let dataStore: DataStore public let keystore: KeyStore public let network: NetworkManager @@ -29,7 +30,7 @@ public class Node { let chainspec = try await genesis.load() let protocolConfig = try chainspec.getConfig() - dataProvider = try await config.database.open(chainspec: chainspec) + (dataProvider, dataStore) = try await config.database.open(chainspec: chainspec) logger.info("Genesis: \(dataProvider.genesisBlockHash)") diff --git a/Node/Sources/Node/ValidatorNode.swift b/Node/Sources/Node/ValidatorNode.swift index b91a850d..5088e84c 100644 --- a/Node/Sources/Node/ValidatorNode.swift +++ b/Node/Sources/Node/ValidatorNode.swift @@ -29,7 +29,7 @@ public class ValidatorNode: Node { eventBus: eventBus, scheduler: scheduler, dataProvider: dataProvider, - dataStore: config.dataStore.create() + dataStore: dataStore ) self.validator = validator diff --git a/PolkaVM/Sources/PolkaVM/Instructions/Instructions+Helpers.swift b/PolkaVM/Sources/PolkaVM/Instructions/Instructions+Helpers.swift index d434de6f..8eadae4b 100644 --- a/PolkaVM/Sources/PolkaVM/Instructions/Instructions+Helpers.swift +++ b/PolkaVM/Sources/PolkaVM/Instructions/Instructions+Helpers.swift @@ -70,7 +70,7 @@ extension Instructions { } var targetAlignedData = jumpTable[relative: start ..< end] - logger.trace("djump target data (\(targetAlignedData.map { $0 }))") + logger.trace("djump target data (\(targetAlignedData.map(\.self)))") var targetAligned: any UnsignedInteger diff --git a/Utils/Sources/Utils/ConstValue.swift b/Utils/Sources/Utils/ConstValue.swift index 558feec6..3beb4207 100644 --- a/Utils/Sources/Utils/ConstValue.swift +++ b/Utils/Sources/Utils/ConstValue.swift @@ -31,9 +31,9 @@ public enum ConstInt3: ConstInt { } } -public enum ConstIntMax: ConstInt { +public enum ConstInt12: ConstInt { public static var value: Int { - Int.max + 12 } } @@ -55,32 +55,44 @@ public enum ConstInt64: ConstInt { } } -public enum ConstUInt96: ConstInt { +public enum ConstInt96: ConstInt { public static var value: Int { 96 } } -public enum ConstUInt128: ConstInt { +public enum ConstInt128: ConstInt { public static var value: Int { 128 } } -public enum ConstUInt144: ConstInt { +public enum ConstInt144: ConstInt { public static var value: Int { 144 } } -public enum ConstUInt384: ConstInt { +public enum ConstInt384: ConstInt { public static var value: Int { 384 } } -public enum ConstUInt784: ConstInt { +public enum ConstInt784: ConstInt { public static var value: Int { 784 } } + +public enum ConstInt4104: ConstInt { + public static var value: Int { + 4104 + } +} + +public enum ConstIntMax: ConstInt { + public static var value: Int { + Int.max + } +} diff --git a/Utils/Sources/Utils/FixedSizeData.swift b/Utils/Sources/Utils/FixedSizeData.swift index 8503b8e9..8449006b 100644 --- a/Utils/Sources/Utils/FixedSizeData.swift +++ b/Utils/Sources/Utils/FixedSizeData.swift @@ -106,11 +106,13 @@ extension FixedSizeData { } } +public typealias Data12 = FixedSizeData public typealias Data32 = FixedSizeData public typealias Data48 = FixedSizeData public typealias Data64 = FixedSizeData -public typealias Data96 = FixedSizeData -public typealias Data128 = FixedSizeData -public typealias Data144 = FixedSizeData -public typealias Data384 = FixedSizeData -public typealias Data784 = FixedSizeData +public typealias Data96 = FixedSizeData +public typealias Data128 = FixedSizeData +public typealias Data144 = FixedSizeData +public typealias Data384 = FixedSizeData +public typealias Data784 = FixedSizeData +public typealias Data4104 = FixedSizeData diff --git a/Utils/Tests/UtilsTests/ConstValueTests.swift b/Utils/Tests/UtilsTests/ConstValueTests.swift index d440ead0..e0268c1c 100644 --- a/Utils/Tests/UtilsTests/ConstValueTests.swift +++ b/Utils/Tests/UtilsTests/ConstValueTests.swift @@ -9,14 +9,16 @@ struct ConstIntTests { #expect(ConstInt1.value == 1) #expect(ConstInt2.value == 2) #expect(ConstInt3.value == 3) - #expect(ConstIntMax.value == Int.max) + #expect(ConstInt12.value == 12) #expect(ConstInt32.value == 32) #expect(ConstInt48.value == 48) #expect(ConstInt64.value == 64) - #expect(ConstUInt96.value == 96) - #expect(ConstUInt128.value == 128) - #expect(ConstUInt144.value == 144) - #expect(ConstUInt384.value == 384) - #expect(ConstUInt784.value == 784) + #expect(ConstInt96.value == 96) + #expect(ConstInt128.value == 128) + #expect(ConstInt144.value == 144) + #expect(ConstInt384.value == 384) + #expect(ConstInt784.value == 784) + #expect(ConstInt4104.value == 4104) + #expect(ConstIntMax.value == Int.max) } }