From 3defaa1b1aff228863cf443743a51f74b2b8cc4d Mon Sep 17 00:00:00 2001 From: MacOMNI <414294494@qq.com> Date: Sat, 15 Feb 2025 11:49:55 +0800 Subject: [PATCH 01/26] update issue 278 --- .../RuntimeProtocols/RuntimeEvents.swift | 9 +++++++++ .../Blockchain/Types/RefinementContext.swift | 10 ++++++++-- .../Sources/Blockchain/Types/WorkItem.swift | 6 +++--- .../Blockchain/Types/WorkPackage.swift | 12 +++++++++++ .../Validator/WorkPackagePoolService.swift | 10 +++++++++- .../CommonEphemeral/CERequest.swift | 10 ++++++++++ .../CommonEphemeral/WorkPackage.swift | 20 +++++++++++++++++++ .../NetworkingProtocol/NetworkManager.swift | 7 +++++++ Utils/Sources/Utils/SaturatingNumber.swift | 2 +- 9 files changed, 79 insertions(+), 7 deletions(-) create mode 100644 Node/Sources/Node/NetworkingProtocol/CommonEphemeral/WorkPackage.swift diff --git a/Blockchain/Sources/Blockchain/RuntimeProtocols/RuntimeEvents.swift b/Blockchain/Sources/Blockchain/RuntimeProtocols/RuntimeEvents.swift index 41d5422f..f18dad4d 100644 --- a/Blockchain/Sources/Blockchain/RuntimeProtocols/RuntimeEvents.swift +++ b/Blockchain/Sources/Blockchain/RuntimeProtocols/RuntimeEvents.swift @@ -52,6 +52,15 @@ public enum RuntimeEvents { public let block: BlockRef } + // New WorkPackagesReceived from network + public struct WorkPackagesReceived: Event { + public let items: [WorkPackage] + + public init(items: [WorkPackage]) { + self.items = items + } + } + // New WorkPackagesGenerated by Guaranteeing Service public struct WorkPackagesGenerated: Event { public let items: [WorkPackage] diff --git a/Blockchain/Sources/Blockchain/Types/RefinementContext.swift b/Blockchain/Sources/Blockchain/Types/RefinementContext.swift index 7c3fd890..feca6ce0 100644 --- a/Blockchain/Sources/Blockchain/Types/RefinementContext.swift +++ b/Blockchain/Sources/Blockchain/Types/RefinementContext.swift @@ -3,8 +3,8 @@ import Utils // A refinement context, denoted by the set X, describes the context of the chain // at the point that the report’s corresponding work-package was evaluated. -public struct RefinementContext: Comparable, Sendable, Equatable, Codable { - public struct Anchor: Comparable, Sendable, Equatable, Codable { +public struct RefinementContext: Comparable, Sendable, Equatable, Codable, Hashable { + public struct Anchor: Comparable, Sendable, Equatable, Codable, Hashable { // a public var headerHash: Data32 // s @@ -74,6 +74,12 @@ public struct RefinementContext: Comparable, Sendable, Equatable, Codable { } return lhs.lookupAnchor < rhs.lookupAnchor } + + public func hash(into hasher: inout Hasher) { + hasher.combine(anchor) + hasher.combine(lookupAnchor) + hasher.combine(prerequisiteWorkPackages) + } } extension RefinementContext: Dummy { diff --git a/Blockchain/Sources/Blockchain/Types/WorkItem.swift b/Blockchain/Sources/Blockchain/Types/WorkItem.swift index 9f2eb3e6..3609659c 100644 --- a/Blockchain/Sources/Blockchain/Types/WorkItem.swift +++ b/Blockchain/Sources/Blockchain/Types/WorkItem.swift @@ -2,9 +2,9 @@ import Foundation import Utils // I -public struct WorkItem: Sendable, Equatable, Codable { - public struct ImportedDataSegment: Sendable, Equatable, Codable { - public enum DataSegmentRootKind: Sendable, Equatable { +public struct WorkItem: Sendable, Equatable, Codable, Hashable { + public struct ImportedDataSegment: Sendable, Equatable, Codable, Hashable { + public enum DataSegmentRootKind: Sendable, Equatable, Hashable { case segmentRoot(Data32) case workPackageHash(Data32) } diff --git a/Blockchain/Sources/Blockchain/Types/WorkPackage.swift b/Blockchain/Sources/Blockchain/Types/WorkPackage.swift index 7b12782c..6eb1b051 100644 --- a/Blockchain/Sources/Blockchain/Types/WorkPackage.swift +++ b/Blockchain/Sources/Blockchain/Types/WorkPackage.swift @@ -60,6 +60,18 @@ public struct WorkPackage: Comparable, Sendable, Equatable, Codable { } } +extension WorkPackage: Hashable { + public func hash(into hasher: inout Hasher) { + hasher.combine(authorizationToken) + hasher.combine(authorizationServiceIndex) + hasher.combine(authorizationCodeHash) + hasher.combine(parameterizationBlob) + hasher.combine(context) + hasher.combine(workItems.count) + workItems.forEach { hasher.combine($0) } + } +} + extension WorkPackage { public func hash() -> Data32 { try! JamEncoder.encode(self).blake2b256hash() diff --git a/Blockchain/Sources/Blockchain/Validator/WorkPackagePoolService.swift b/Blockchain/Sources/Blockchain/Validator/WorkPackagePoolService.swift index 9ae18586..7cdc8ab0 100644 --- a/Blockchain/Sources/Blockchain/Validator/WorkPackagePoolService.swift +++ b/Blockchain/Sources/Blockchain/Validator/WorkPackagePoolService.swift @@ -64,8 +64,10 @@ public final class WorkPackagePoolService: ServiceBase, @unchecked Sendable { await subscribe(RuntimeEvents.WorkPackagesGenerated.self, id: "WorkPackagePool.WorkPackagesGenerated") { [weak self] event in try await self?.on(workPackagesGenerated: event) } + await subscribe(RuntimeEvents.WorkPackagesReceived.self, id: "WorkPackagePool.WorkPackagesReceived") { [weak self] event in + try await self?.on(workPackagesReceived: event) + } // TODO: add remove subscribe - // TODO: add receive subscribe? } private func on(workPackagesGenerated event: RuntimeEvents.WorkPackagesGenerated) async throws { @@ -74,6 +76,12 @@ public final class WorkPackagePoolService: ServiceBase, @unchecked Sendable { await storage.add(packages: event.items, config: config) } + private func on(workPackagesReceived event: RuntimeEvents.WorkPackagesReceived) async throws { + let state = try await dataProvider.getBestState() + try await storage.update(state: state, config: config) + await storage.add(packages: event.items, config: config) + } + public func update(state: StateRef, config: ProtocolConfigRef) async throws { try await storage.update(state: state, config: config) } diff --git a/Node/Sources/Node/NetworkingProtocol/CommonEphemeral/CERequest.swift b/Node/Sources/Node/NetworkingProtocol/CommonEphemeral/CERequest.swift index d3b9a5cc..f3b162e9 100644 --- a/Node/Sources/Node/NetworkingProtocol/CommonEphemeral/CERequest.swift +++ b/Node/Sources/Node/NetworkingProtocol/CommonEphemeral/CERequest.swift @@ -7,6 +7,7 @@ public enum CERequest: Sendable, Equatable, Hashable { case blockRequest(BlockRequest) case safroleTicket1(SafroleTicketMessage) case safroleTicket2(SafroleTicketMessage) + case workPackageSubmission(WorkPackageMessage) } extension CERequest: RequestProtocol { @@ -20,6 +21,8 @@ extension CERequest: RequestProtocol { try JamEncoder.encode(message) case let .safroleTicket2(message): try JamEncoder.encode(message) + case let .workPackageSubmission(message): + try JamEncoder.encode(message) } } @@ -31,6 +34,8 @@ extension CERequest: RequestProtocol { .safroleTicket1 case .safroleTicket2: .safroleTicket2 + case .workPackageSubmission: + .workPackageSubmission } } @@ -42,6 +47,8 @@ extension CERequest: RequestProtocol { SafroleTicketMessage.self case .safroleTicket2: SafroleTicketMessage.self + case .workPackageSubmission: + WorkPackageMessage.self default: fatalError("unimplemented") } @@ -64,6 +71,9 @@ extension CERequest: RequestProtocol { return nil } return .safroleTicket2(message) + case .workPackageSubmission: + guard let message = data as? WorkPackageMessage else { return nil } + return .workPackageSubmission(message) default: fatalError("unimplemented") } diff --git a/Node/Sources/Node/NetworkingProtocol/CommonEphemeral/WorkPackage.swift b/Node/Sources/Node/NetworkingProtocol/CommonEphemeral/WorkPackage.swift new file mode 100644 index 00000000..04b4e5c7 --- /dev/null +++ b/Node/Sources/Node/NetworkingProtocol/CommonEphemeral/WorkPackage.swift @@ -0,0 +1,20 @@ +import Blockchain +import Codec +import Foundation + +public struct WorkPackageMessage: Codable, Sendable, Equatable, Hashable { + /// The core index associated with the work-package. + public var coreIndex: CoreIndex + + /// The work-package data. + public var workPackage: WorkPackage + + /// The extrinsic data referenced by the work-package. + public var extrinsics: [Data] + + public init(coreIndex: CoreIndex, workPackage: WorkPackage, extrinsics: [Data]) { + self.coreIndex = coreIndex + self.workPackage = workPackage + self.extrinsics = extrinsics + } +} diff --git a/Node/Sources/Node/NetworkingProtocol/NetworkManager.swift b/Node/Sources/Node/NetworkingProtocol/NetworkManager.swift index be0c949b..b0ba076e 100644 --- a/Node/Sources/Node/NetworkingProtocol/NetworkManager.swift +++ b/Node/Sources/Node/NetworkingProtocol/NetworkManager.swift @@ -226,6 +226,13 @@ struct HandlerImpl: NetworkProtocolHandler { ] )) return [] + case let .workPackageSubmission(message): + blockchain.publish(event: RuntimeEvents.WorkPackagesReceived( + items: [ + message.workPackage, + ] + )) + return [] } } diff --git a/Utils/Sources/Utils/SaturatingNumber.swift b/Utils/Sources/Utils/SaturatingNumber.swift index 8d0e0db8..4b3147e1 100644 --- a/Utils/Sources/Utils/SaturatingNumber.swift +++ b/Utils/Sources/Utils/SaturatingNumber.swift @@ -1,7 +1,7 @@ import Codec import Numerics -public struct SaturatingNumber: Sendable { +public struct SaturatingNumber: Sendable, Hashable { public private(set) var value: T public static var max: SaturatingNumber { From f2809a60885f4bcc303b0173bfe34ba368cb81f8 Mon Sep 17 00:00:00 2001 From: MacOMNI <414294494@qq.com> Date: Sun, 16 Feb 2025 10:45:11 +0800 Subject: [PATCH 02/26] update issues 279 --- .../Blockchain/Types/WorkPackage.swift | 6 + .../Validator/WorkPackagePoolService.swift | 212 ++++++++++++++++++ 2 files changed, 218 insertions(+) diff --git a/Blockchain/Sources/Blockchain/Types/WorkPackage.swift b/Blockchain/Sources/Blockchain/Types/WorkPackage.swift index 6eb1b051..9b7ff782 100644 --- a/Blockchain/Sources/Blockchain/Types/WorkPackage.swift +++ b/Blockchain/Sources/Blockchain/Types/WorkPackage.swift @@ -2,6 +2,12 @@ import Codec import Foundation import Utils +public enum WorkPackageError: Error { + case invalidWorkPackage + case invalidBundle + case segmentsRootNotFound +} + // P public struct WorkPackage: Comparable, Sendable, Equatable, Codable { // j diff --git a/Blockchain/Sources/Blockchain/Validator/WorkPackagePoolService.swift b/Blockchain/Sources/Blockchain/Validator/WorkPackagePoolService.swift index 7cdc8ab0..fcf18849 100644 --- a/Blockchain/Sources/Blockchain/Validator/WorkPackagePoolService.swift +++ b/Blockchain/Sources/Blockchain/Validator/WorkPackagePoolService.swift @@ -1,3 +1,4 @@ +import Foundation import TracingUtils import Utils @@ -44,6 +45,85 @@ private actor WorkPackageStorage { } } +public struct SegmentsRootMapping: Codable { + public let workPackageHash: Data32 + public let segmentsRoot: SegmentsRoot +} + +public typealias SegmentsRoot = Data32 +public typealias SegmentsRootMappings = [SegmentsRootMapping] + +public struct Guarantor: Codable, Identifiable { + public let id: Data32 // Unique identifier for the guarantor (e.g., public key hash) + public let coreIndex: CoreIndex // The core index to which the guarantor is assigned + + // Method to receive a work package bundle + public func receiveWorkPackageBundle( + coreIndex _: CoreIndex, + segmentsRootMappings: SegmentsRootMappings, + bundle: WorkPackageBundle + ) async throws -> (Data32, Data) { + // 1. Perform basic verification + guard try validateWorkPackageBundle(bundle, segmentsRootMappings: segmentsRootMappings) else { + throw WorkPackageError.invalidBundle + } + + // 2. Execute refine logic + let workReportHash = try await refineWorkPackageBundle(bundle) + + // 3. Sign the work report hash + let signature = try await signData(workReportHash) + + return (workReportHash, signature) + } + + private func validateWorkPackageBundle( + _ bundle: WorkPackageBundle, + segmentsRootMappings: SegmentsRootMappings + ) throws -> Bool { + // 1. Validate the work package authorization + guard try validateAuthorization(bundle.workPackage) else { + return false + } + + // 2. Validate the segments-root mappings + for mapping in segmentsRootMappings { + guard try validateSegmentsRootMapping(mapping, for: bundle.workPackage) else { + return false + } + } + + return true + } + + private func validateSegmentsRootMapping( + _: SegmentsRootMapping, + for _: WorkPackage + ) throws -> Bool { + // Implement logic to validate the segments-root mapping + true // Placeholder + } + + private func validateAuthorization(_: WorkPackage) throws -> Bool { + // Implement logic to validate the work package authorization + true // Placeholder + } + + private func refineWorkPackageBundle(_: WorkPackageBundle) async throws -> Data32 { + // Implement refine logic here + // For example, execute the work items and generate a work report +// let workReportHash = try await refineLogic.execute(bundle) + Data32() + } + + private func signData(_: Data32) async throws -> Data { + // Implement signing logic here + // For example, use the guarantor's private key to sign the data +// let signature = try await keystore.sign(data: data, with: privateKey) + Data() + } +} + public final class WorkPackagePoolService: ServiceBase, @unchecked Sendable { private var storage: WorkPackageStorage private let dataProvider: BlockchainDataProvider @@ -94,6 +174,138 @@ public final class WorkPackagePoolService: ServiceBase, @unchecked Sendable { await storage.removeWorkPackages(packages) } + public func createWorkPackageBundle(_ workPackage: WorkPackage) async throws -> WorkPackageBundle { + // 1. Retrieve the necessary data for the bundle + let extrinsicData = try await retrieveExtrinsicData(for: workPackage) + let importSegments = try await retrieveImportSegments(for: workPackage) + let justifications = try await retrieveJustifications(for: workPackage) + + // 2. Construct the work package bundle + return WorkPackageBundle( + workPackage: workPackage, + extrinsic: extrinsicData, + importSegments: importSegments, + justifications: justifications + ) + } + +// public func retrieveSegmentsRootMappings(for workPackage: WorkPackage) async throws -> SegmentsRootMappings { +// // 1. Get the import segments from the work package +// let importSegments = try await retrieveImportSegments(for: workPackage) +// +// // 2. Map work-package hashes to segments-roots +// var mappings: SegmentsRootMappings = [] +// for segment in importSegments { +// // 2.1. Get the work-package hash from the segment ?? +// let workPackageHash = workPackage.hash() +// +// // 2.2. Retrieve the segments-root from the blockchain or data availability layer +// let segmentsRoot = try await retrieveSegmentsRoot(for: workPackageHash) +// +// // 2.3. Create a mapping and add it to the array +// let mapping = SegmentsRootMapping(workPackageHash: workPackageHash, segmentsRoot: segmentsRoot) +// mappings.append(mapping) +// } +// +// return mappings +// } + +// private func retrieveSegmentsRoot(for workPackageHash: Data32) async throws -> SegmentsRoot { +// // 1. Query the blockchain or data availability layer to get the segments-root +// // For example, use a blockchain data provider to fetch the segments-root +// let segmentsRoot = try await dataProvider.getSegmentsRoot(for: workPackageHash) +// +// // 2. If the segments-root is not found, throw an error +// guard let segmentsRoot = segmentsRoot else { +// throw WorkPackageError.segmentsRootNotFound +// } +// +// return segmentsRoot +// } + + public func shareWorkPackage(_ workPackage: WorkPackage, coreIndex: CoreIndex) async throws { + // 1. Get other guarantors assigned to the same core + let guarantors = try await getGuarantors(for: coreIndex) + + // 2. Validate the work package + guard try validate(workPackage: workPackage) else { + logger.error("Invalid work package: \(workPackage)") + throw WorkPackageError.invalidWorkPackage + } + // 3. Create WorkPackageBundle + + let bundle = try await createWorkPackageBundle(workPackage) + + // 4. Send the bundle to other guarantors + // 5. Map work-package hashes to segments-roots + var mappings: SegmentsRootMappings = [] + for guarantor in guarantors { + let (workReportHash, signature) = try await guarantor.receiveWorkPackageBundle( + coreIndex: coreIndex, + segmentsRootMappings: mappings, + bundle: bundle + ) + + // 5. Publish the work report hash and signature +// let event = RuntimeEvents.WorkReportGenerated(hash: workReportHash, signature: signature) +// publish(event) + } + } + + public func getGuarantors(for coreIndex: CoreIndex) async throws -> [Guarantor] { + // 1. Get the current blockchain state + let state = try await dataProvider.getState(hash: dataProvider.bestHead.hash) + + // 2. Get the core assignment for the current timeslot + let coreAssignment: [CoreIndex] = state.value.getCoreAssignment( + config: config, + randomness: state.value.entropyPool.t2, + timeslot: state.value.timeslot + ) + + // 3. Ensure the core index is valid + guard coreIndex < coreAssignment.count else { + logger.error("Invalid core index: \(coreIndex)") + throw GuaranteeingServiceError.invalidValidatorIndex + } + + // 4. Get the validator index assigned to the core + let validatorIndex = coreAssignment[Int(coreIndex)] + + let validator = state.value.currentValidators[Int(validatorIndex)] +// state.value.currentValidators[Int(authorIndex)].ed25519 + // 5. Create a Guarantor object for the validator + let guarantor = Guarantor( + id: validator.ed25519.blake2b256hash(), // Use the validator's public key hash as the ID + coreIndex: coreIndex + ) + + return [guarantor] + } + + private func retrieveExtrinsicData(for _: WorkPackage) async throws -> [Data] { + // Implement logic to retrieve extrinsic data associated with the work package + // For example, fetch from the blockchain or local storage + [] // Placeholder + } + + private func retrieveImportSegments(for _: WorkPackage) async throws -> [[Data]] { + // Implement logic to retrieve imported data segments + // For example, fetch from the data availability layer + [] // Placeholder + } + + private func retrieveJustifications(for _: WorkPackage) async throws -> [[Data]] { + // Implement logic to retrieve justifications for the imported segments + // For example, fetch proofs from the data availability layer + [] // Placeholder + } + + private func validate(workPackage _: WorkPackage) throws -> Bool { + // TODO: Add validate func + true + } + public func getWorkPackages() async -> SortedUniqueArray { await storage.getWorkPackages() } From d1e1d169139a9b18511fb99b3472bfc6a80e6f26 Mon Sep 17 00:00:00 2001 From: MacOMNI <414294494@qq.com> Date: Mon, 17 Feb 2025 15:11:33 +0800 Subject: [PATCH 03/26] Work-package submission --- .../WorkPackagePoolServiceTests.swift | 15 ++++++++- .../Tests/NodeTests/NetworkManagerTests.swift | 32 +++++++++++++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/Blockchain/Tests/BlockchainTests/WorkPackagePoolServiceTests.swift b/Blockchain/Tests/BlockchainTests/WorkPackagePoolServiceTests.swift index dae7729a..7384256b 100644 --- a/Blockchain/Tests/BlockchainTests/WorkPackagePoolServiceTests.swift +++ b/Blockchain/Tests/BlockchainTests/WorkPackagePoolServiceTests.swift @@ -40,11 +40,24 @@ struct WorkPackagePoolServiceTests { allWorkPackages.append(workpackage) } await services.eventBus.publish(RuntimeEvents.WorkPackagesGenerated(items: allWorkPackages)) - let workPackages = await workPackagecPoolService.getWorkPackages() + var workPackages = await workPackagecPoolService.getWorkPackages() #expect(workPackages.array == Array(allWorkPackages).sorted()) let workpackage = WorkPackage.dummy(config: services.config) try await workPackagecPoolService.addWorkPackages(packages: [workpackage]) try await workPackagecPoolService.removeWorkPackages(packages: [workpackage]) #expect(workPackages.array.count == services.config.value.totalNumberOfCores) + let event = RuntimeEvents.WorkPackagesReceived(items: [workpackage]) + await services.eventBus.publish(event) + await services.eventBus.publish(event) // duplicate + // Wait for the event to be processed + await services.storeMiddleware.wait() + workPackages = await workPackagecPoolService.getWorkPackages() + #expect(workPackages.array.count > services.config.value.totalNumberOfCores) + await services.blockchain.publish(event: RuntimeEvents.WorkPackagesReceived( + items: [ + workpackage, + ] + )) + await services.storeMiddleware.wait() } } diff --git a/Node/Tests/NodeTests/NetworkManagerTests.swift b/Node/Tests/NodeTests/NetworkManagerTests.swift index 76365162..55a442dd 100644 --- a/Node/Tests/NodeTests/NetworkManagerTests.swift +++ b/Node/Tests/NodeTests/NetworkManagerTests.swift @@ -74,6 +74,38 @@ struct NetworkManagerTests { ) } + @Test + func testWorkPackagesReceived() async throws { + // Create dummy work packages + let workPackages = [ + WorkPackage.dummy(config: services.config), + WorkPackage.dummy(config: services.config), + ] + + // Publish WorkPackagesReceived event + await services.eventBus.publish(RuntimeEvents.WorkPackagesReceived(items: workPackages)) + + // Wait for event processing + await storeMiddleware.wait() + + // Verify network calls + #expect( + network.contain(calls: [ + .init(function: "connect", parameters: ["address": devPeers.first!, "role": PeerRole.validator]), + .init(function: "sendToPeer", parameters: [ + "message": CERequest.workPackageSubmission( + WorkPackageMessage(coreIndex: 0, workPackage: workPackages[0], extrinsics: []) + ), + ]), + .init(function: "sendToPeer", parameters: [ + "message": CERequest.workPackageSubmission( + WorkPackageMessage(coreIndex: 0, workPackage: workPackages[1], extrinsics: []) + ), + ]), + ]) + ) + } + @Test func testBlockBroadcast() async throws { // Import a block From 0f5c6ffe3100f2f28efc8f1af9bd4124818f3842 Mon Sep 17 00:00:00 2001 From: MacOMNI <414294494@qq.com> Date: Mon, 17 Feb 2025 15:25:14 +0800 Subject: [PATCH 04/26] update networkmanager --- Node/Tests/NodeTests/NetworkManagerTests.swift | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Node/Tests/NodeTests/NetworkManagerTests.swift b/Node/Tests/NodeTests/NetworkManagerTests.swift index 55a442dd..6c8cfda0 100644 --- a/Node/Tests/NodeTests/NetworkManagerTests.swift +++ b/Node/Tests/NodeTests/NetworkManagerTests.swift @@ -79,7 +79,6 @@ struct NetworkManagerTests { // Create dummy work packages let workPackages = [ WorkPackage.dummy(config: services.config), - WorkPackage.dummy(config: services.config), ] // Publish WorkPackagesReceived event @@ -97,11 +96,6 @@ struct NetworkManagerTests { WorkPackageMessage(coreIndex: 0, workPackage: workPackages[0], extrinsics: []) ), ]), - .init(function: "sendToPeer", parameters: [ - "message": CERequest.workPackageSubmission( - WorkPackageMessage(coreIndex: 0, workPackage: workPackages[1], extrinsics: []) - ), - ]), ]) ) } From a17d2b62179a07186dfca38015017b5d7fb25b5f Mon Sep 17 00:00:00 2001 From: MacOMNI <414294494@qq.com> Date: Mon, 17 Feb 2025 15:34:30 +0800 Subject: [PATCH 05/26] update more test --- .../Tests/BlockchainTests/WorkPackagePoolServiceTests.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Blockchain/Tests/BlockchainTests/WorkPackagePoolServiceTests.swift b/Blockchain/Tests/BlockchainTests/WorkPackagePoolServiceTests.swift index 7384256b..89e3b7e8 100644 --- a/Blockchain/Tests/BlockchainTests/WorkPackagePoolServiceTests.swift +++ b/Blockchain/Tests/BlockchainTests/WorkPackagePoolServiceTests.swift @@ -59,5 +59,7 @@ struct WorkPackagePoolServiceTests { ] )) await services.storeMiddleware.wait() + workPackages = await workPackagecPoolService.getWorkPackages() + #expect(workPackages.array.count > services.config.value.totalNumberOfCores) } } From 1dbb9201ed327df5dba13d08f386ced9bc70370a Mon Sep 17 00:00:00 2001 From: MacOMNI <414294494@qq.com> Date: Mon, 17 Feb 2025 16:15:24 +0800 Subject: [PATCH 06/26] update workpackage hash --- Node/Tests/NodeTests/NetworkManagerTests.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Node/Tests/NodeTests/NetworkManagerTests.swift b/Node/Tests/NodeTests/NetworkManagerTests.swift index 6c8cfda0..86a8d256 100644 --- a/Node/Tests/NodeTests/NetworkManagerTests.swift +++ b/Node/Tests/NodeTests/NetworkManagerTests.swift @@ -87,6 +87,7 @@ struct NetworkManagerTests { // Wait for event processing await storeMiddleware.wait() + #expect(workPackages.first?.hash() != nil) // Verify network calls #expect( network.contain(calls: [ From 4389630ce239dbb663c857f8b92c979a7b83bc1b Mon Sep 17 00:00:00 2001 From: MacOMNI <414294494@qq.com> Date: Mon, 17 Feb 2025 17:24:59 +0800 Subject: [PATCH 07/26] update networkmanager --- Node/Tests/NodeTests/NetworkManagerTests.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/Node/Tests/NodeTests/NetworkManagerTests.swift b/Node/Tests/NodeTests/NetworkManagerTests.swift index 86a8d256..931e2dd4 100644 --- a/Node/Tests/NodeTests/NetworkManagerTests.swift +++ b/Node/Tests/NodeTests/NetworkManagerTests.swift @@ -88,6 +88,7 @@ struct NetworkManagerTests { await storeMiddleware.wait() #expect(workPackages.first?.hash() != nil) + #expect(workPackages.first?.hashValue != nil) // Verify network calls #expect( network.contain(calls: [ From 2cd9a24dc6f25698cf5f88e43673c86a6406e795 Mon Sep 17 00:00:00 2001 From: MacOMNI <414294494@qq.com> Date: Tue, 18 Feb 2025 10:38:05 +0800 Subject: [PATCH 08/26] update workpackage --- .../Sources/Blockchain/Types/RefinementContext.swift | 10 +++++++--- Blockchain/Sources/Blockchain/Types/WorkPackage.swift | 8 +------- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/Blockchain/Sources/Blockchain/Types/RefinementContext.swift b/Blockchain/Sources/Blockchain/Types/RefinementContext.swift index feca6ce0..10149f43 100644 --- a/Blockchain/Sources/Blockchain/Types/RefinementContext.swift +++ b/Blockchain/Sources/Blockchain/Types/RefinementContext.swift @@ -76,9 +76,13 @@ public struct RefinementContext: Comparable, Sendable, Equatable, Codable, Hasha } public func hash(into hasher: inout Hasher) { - hasher.combine(anchor) - hasher.combine(lookupAnchor) - hasher.combine(prerequisiteWorkPackages) + hasher.combine(hash()) + } +} + +extension RefinementContext { + public func hash() -> Data32 { + try! JamEncoder.encode(self).blake2b256hash() } } diff --git a/Blockchain/Sources/Blockchain/Types/WorkPackage.swift b/Blockchain/Sources/Blockchain/Types/WorkPackage.swift index 6eb1b051..4f985243 100644 --- a/Blockchain/Sources/Blockchain/Types/WorkPackage.swift +++ b/Blockchain/Sources/Blockchain/Types/WorkPackage.swift @@ -62,13 +62,7 @@ public struct WorkPackage: Comparable, Sendable, Equatable, Codable { extension WorkPackage: Hashable { public func hash(into hasher: inout Hasher) { - hasher.combine(authorizationToken) - hasher.combine(authorizationServiceIndex) - hasher.combine(authorizationCodeHash) - hasher.combine(parameterizationBlob) - hasher.combine(context) - hasher.combine(workItems.count) - workItems.forEach { hasher.combine($0) } + hasher.combine(hash()) } } From 8bd1d43eff3ef067141bc3a33f6c30f64a59da85 Mon Sep 17 00:00:00 2001 From: MacOMNI <414294494@qq.com> Date: Tue, 18 Feb 2025 20:47:04 +0800 Subject: [PATCH 09/26] update workpackpool --- .../Sources/Blockchain/Types/RefinementContext.swift | 8 ++------ .../Validator/ExtrinsicPools/WorkPackagePoolService.swift | 6 ------ 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/Blockchain/Sources/Blockchain/Types/RefinementContext.swift b/Blockchain/Sources/Blockchain/Types/RefinementContext.swift index 10149f43..b5092de0 100644 --- a/Blockchain/Sources/Blockchain/Types/RefinementContext.swift +++ b/Blockchain/Sources/Blockchain/Types/RefinementContext.swift @@ -3,7 +3,7 @@ import Utils // A refinement context, denoted by the set X, describes the context of the chain // at the point that the report’s corresponding work-package was evaluated. -public struct RefinementContext: Comparable, Sendable, Equatable, Codable, Hashable { +public struct RefinementContext: Comparable, Sendable, Equatable, Codable { public struct Anchor: Comparable, Sendable, Equatable, Codable, Hashable { // a public var headerHash: Data32 @@ -74,13 +74,9 @@ public struct RefinementContext: Comparable, Sendable, Equatable, Codable, Hasha } return lhs.lookupAnchor < rhs.lookupAnchor } - - public func hash(into hasher: inout Hasher) { - hasher.combine(hash()) - } } -extension RefinementContext { +extension RefinementContext: Hashable32 { public func hash() -> Data32 { try! JamEncoder.encode(self).blake2b256hash() } diff --git a/Blockchain/Sources/Blockchain/Validator/ExtrinsicPools/WorkPackagePoolService.swift b/Blockchain/Sources/Blockchain/Validator/ExtrinsicPools/WorkPackagePoolService.swift index ac9e1f15..53787c66 100644 --- a/Blockchain/Sources/Blockchain/Validator/ExtrinsicPools/WorkPackagePoolService.swift +++ b/Blockchain/Sources/Blockchain/Validator/ExtrinsicPools/WorkPackagePoolService.swift @@ -29,8 +29,6 @@ private actor WorkPackageStorage { self.logger = logger } - func update(state _: StateRef, config _: ProtocolConfigRef) throws {} - func add(packages: [WorkPackageRef], config: ProtocolConfigRef) { for package in packages { guard validatePackage(package, config: config) else { @@ -89,10 +87,6 @@ public final class WorkPackagePoolService: ServiceBase, @unchecked Sendable { await storage.add(packages: event.items, config: config) } - public func update(state: StateRef, config: ProtocolConfigRef) async throws { - try await storage.update(state: state, config: config) - } - private func on(workPackagesGenerated event: RuntimeEvents.WorkReportGenerated) async throws { await storage.packageRefined(packageHashes: event.items.map(\.packageSpecification.workPackageHash)) } From 9a5d23848ff0913ef810a2bc7ae1fc9dd36af41c Mon Sep 17 00:00:00 2001 From: MacOMNI <414294494@qq.com> Date: Wed, 19 Feb 2025 10:34:07 +0800 Subject: [PATCH 10/26] update NetworkManagerTest --- Node/Tests/NodeTests/NetworkManagerTests.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Node/Tests/NodeTests/NetworkManagerTests.swift b/Node/Tests/NodeTests/NetworkManagerTests.swift index 45924583..86b9cf58 100644 --- a/Node/Tests/NodeTests/NetworkManagerTests.swift +++ b/Node/Tests/NodeTests/NetworkManagerTests.swift @@ -88,7 +88,9 @@ struct NetworkManagerTests { await storeMiddleware.wait() #expect(workPackages.first?.value.hash() != nil) + #expect(workPackages.first?.value.context.hash() != nil) #expect(workPackages.first?.hashValue != nil) + // Verify network calls #expect( network.contain(calls: [ From a93a95b7a7807d18f6d2b28a7e6b601b300e0a29 Mon Sep 17 00:00:00 2001 From: MacOMNI <414294494@qq.com> Date: Thu, 20 Feb 2025 10:37:29 +0800 Subject: [PATCH 11/26] update workpackagepoolserver --- .../ExtrinsicPools/WorkPackagePoolService.swift | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Blockchain/Sources/Blockchain/Validator/ExtrinsicPools/WorkPackagePoolService.swift b/Blockchain/Sources/Blockchain/Validator/ExtrinsicPools/WorkPackagePoolService.swift index b02d61ab..08b84853 100644 --- a/Blockchain/Sources/Blockchain/Validator/ExtrinsicPools/WorkPackagePoolService.swift +++ b/Blockchain/Sources/Blockchain/Validator/ExtrinsicPools/WorkPackagePoolService.swift @@ -111,24 +111,24 @@ public struct Guarantor: Codable, Identifiable { _: SegmentsRootMapping, for _: WorkPackage ) throws -> Bool { - // Implement logic to validate the segments-root mapping + // TODO: Implement logic to validate the segments-root mapping true // Placeholder } private func validateAuthorization(_: WorkPackage) throws -> Bool { - // Implement logic to validate the work package authorization + // TODO: Implement logic to validate the work package authorization true // Placeholder } private func refineWorkPackageBundle(_: WorkPackageBundle) async throws -> Data32 { - // Implement refine logic here + // TODO: Implement refine logic here // For example, execute the work items and generate a work report // let workReportHash = try await refineLogic.execute(bundle) Data32() } private func signData(_: Data32) async throws -> Data { - // Implement signing logic here + // TODO: Implement signing logic here // For example, use the guarantor's private key to sign the data // let signature = try await keystore.sign(data: data, with: privateKey) Data() @@ -285,18 +285,21 @@ public final class WorkPackagePoolService: ServiceBase, @unchecked Sendable { } private func retrieveExtrinsicData(for _: WorkPackage) async throws -> [Data] { + // TODO: Implement retrieveExtrinsicData // Implement logic to retrieve extrinsic data associated with the work package // For example, fetch from the blockchain or local storage [] // Placeholder } private func retrieveImportSegments(for _: WorkPackage) async throws -> [Data4104] { + // TODO: Implement retrieveImportSegments // Implement logic to retrieve imported data segments // For example, fetch from the data availability layer [] // Placeholder } private func retrieveJustifications(for _: WorkPackage) async throws -> [Data] { + // TODO: Implement retrieveJustifications // Implement logic to retrieve justifications for the imported segments // For example, fetch proofs from the data availability layer [] // Placeholder From 3c217ac16179c5098ba3c35d20f5c7bb1c63921a Mon Sep 17 00:00:00 2001 From: MacOMNI <414294494@qq.com> Date: Fri, 21 Feb 2025 14:47:58 +0800 Subject: [PATCH 12/26] update SegmentsRootMapping --- .../Validator/GuaranteeingService.swift | 213 ++++++++++++++++++ 1 file changed, 213 insertions(+) diff --git a/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift b/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift index ca925dc2..3de49458 100644 --- a/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift +++ b/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift @@ -11,6 +11,85 @@ public enum GuaranteeingServiceError: Error { struct GuaranteeingAuthorizationFunction: IsAuthorizedFunction {} struct GuaranteeingRefineInvocation: RefineInvocation {} +public struct SegmentsRootMapping: Codable { + public let workPackageHash: Data32 + public let segmentsRoot: SegmentsRoot +} + +public typealias SegmentsRoot = Data32 +public typealias SegmentsRootMappings = [SegmentsRootMapping] + +public struct Guarantor: Codable, Identifiable { + public let id: Data32 // Unique identifier for the guarantor (e.g., public key hash) + public let coreIndex: CoreIndex // The core index to which the guarantor is assigned + + // Method to receive a work package bundle + public func receiveWorkPackageBundle( + coreIndex _: CoreIndex, + segmentsRootMappings: SegmentsRootMappings, + bundle: WorkPackageBundle + ) async throws -> (Data32, Data) { + // 1. Perform basic verification + guard try validateWorkPackageBundle(bundle, segmentsRootMappings: segmentsRootMappings) else { + throw WorkPackageError.invalidBundle + } + + // 2. Execute refine logic + let workReportHash = try await refineWorkPackageBundle(bundle) + + // 3. Sign the work report hash + let signature = try await signData(workReportHash) + + return (workReportHash, signature) + } + + private func validateWorkPackageBundle( + _ bundle: WorkPackageBundle, + segmentsRootMappings: SegmentsRootMappings + ) throws -> Bool { + // 1. Validate the work package authorization + guard try validateAuthorization(bundle.workPackage) else { + return false + } + + // 2. Validate the segments-root mappings + for mapping in segmentsRootMappings { + guard try validateSegmentsRootMapping(mapping, for: bundle.workPackage) else { + return false + } + } + + return true + } + + private func validateSegmentsRootMapping( + _: SegmentsRootMapping, + for _: WorkPackage + ) throws -> Bool { + // TODO: Implement logic to validate the segments-root mapping + true // Placeholder + } + + private func validateAuthorization(_: WorkPackage) throws -> Bool { + // TODO: Implement logic to validate the work package authorization + true // Placeholder + } + + private func refineWorkPackageBundle(_: WorkPackageBundle) async throws -> Data32 { + // TODO: Implement refine logic here + // For example, execute the work items and generate a work report + // let workReportHash = try await refineLogic.execute(bundle) + Data32() + } + + private func signData(_: Data32) async throws -> Data { + // TODO: Implement signing logic here + // For example, use the guarantor's private key to sign the data + // let signature = try await keystore.sign(data: data, with: privateKey) + Data() + } +} + public final class GuaranteeingService: ServiceBase2, @unchecked Sendable { private let dataProvider: BlockchainDataProvider private let keystore: KeyStore @@ -116,6 +195,140 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable { publish(event) } + public func createWorkPackageBundle(_ workPackage: WorkPackage) async throws -> WorkPackageBundle { + // 1. Retrieve the necessary data for the bundle + let extrinsicData = try await retrieveExtrinsicData(for: workPackage) + let importSegments = try await retrieveImportSegments(for: workPackage) + let justifications = try await retrieveJustifications(for: workPackage) + + // 2. Construct the work package bundle + return WorkPackageBundle( + workPackage: workPackage, + extrinsic: extrinsicData, + importSegments: importSegments, + justifications: justifications + ) + } + + public func retrieveSegmentsRootMappings(for workPackage: WorkPackage) async throws -> SegmentsRootMappings { + // 1. Get the import segments from the work package + let importSegments = try await retrieveImportSegments(for: workPackage) + + // 2. Map work-package hashes to segments-roots + var mappings: SegmentsRootMappings = [] + for segment in importSegments { + // 2.1. Get the work-package hash from the segment ?? + let workPackageHash = workPackage.hash() + + // 2.2. Retrieve the segments-root from the blockchain or data availability layer + let segmentsRoot = try await retrieveSegmentsRoot(for: workPackageHash) + + // 2.3. Create a mapping and add it to the array + let mapping = SegmentsRootMapping(workPackageHash: workPackageHash, segmentsRoot: segmentsRoot) + mappings.append(mapping) + } + + return mappings + } + + private func retrieveSegmentsRoot(for _: Data32) async throws -> SegmentsRoot { + // 1. Query the blockchain or data availability layer to get the segments-root + // For example, use a blockchain data provider to fetch the segments-root + // let segmentsRoot = try await dataProvider.getSegmentsRoot(for: workPackageHash) + let segmentsRoot = SegmentsRoot() + // 2. If the segments-root is not found, throw an error + // guard let segmentsRoot = segmentsRoot else { + // throw WorkPackageError.segmentsRootNotFound + // } + + return segmentsRoot + } + + public func shareWorkPackage(_ workPackage: WorkPackage, coreIndex: CoreIndex) async throws { + // 1. Get other guarantors assigned to the same core + let guarantors = try await getGuarantors(for: coreIndex) + + // 2. Validate the work package + guard try validate(workPackage: workPackage) else { + logger.error("Invalid work package: \(workPackage)") + throw WorkPackageError.invalidWorkPackage + } + // 3. Create WorkPackageBundle + + let bundle = try await createWorkPackageBundle(workPackage) + + // 4. Send the bundle to other guarantors + // 5. Map work-package hashes to segments-roots + var mappings: SegmentsRootMappings = [] + for guarantor in guarantors { + let (workReportHash, signature) = try await guarantor.receiveWorkPackageBundle( + coreIndex: coreIndex, + segmentsRootMappings: mappings, + bundle: bundle + ) + + // 6. Publish the work report hash and signature + // let event = RuntimeEvents.WorkReportGenerated(hash: workReportHash, signature: signature) + // publish(event) + } + } + + public func getGuarantors(for coreIndex: CoreIndex) async throws -> [Guarantor] { + // 1. Get the current blockchain state + let state = try await dataProvider.getState(hash: dataProvider.bestHead.hash) + + // 2. Get the core assignment for the current timeslot + let coreAssignment: [CoreIndex] = state.value.getCoreAssignment( + config: config, + randomness: state.value.entropyPool.t2, + timeslot: state.value.timeslot + ) + + // 3. Ensure the core index is valid + guard coreIndex < coreAssignment.count else { + logger.error("Invalid core index: \(coreIndex)") + try throwUnreachable("invalid validator index/core assignment") + } + + // 4. Get the validator index assigned to the core + let validatorIndex = coreAssignment[Int(coreIndex)] + + let validator = state.value.currentValidators[Int(validatorIndex)] + // 5. Create a Guarantor object for the validator + let guarantor = Guarantor( + id: validator.ed25519.blake2b256hash(), // Use the validator's public key hash as the ID + coreIndex: coreIndex + ) + + return [guarantor] + } + + private func validate(workPackage _: WorkPackage) throws -> Bool { + // TODO: Add validate func + true + } + + private func retrieveExtrinsicData(for _: WorkPackage) async throws -> [Data] { + // TODO: Implement retrieveExtrinsicData + // Implement logic to retrieve extrinsic data associated with the work package + // For example, fetch from the blockchain or local storage + [] // Placeholder + } + + private func retrieveImportSegments(for _: WorkPackage) async throws -> [Data4104] { + // TODO: Implement retrieveImportSegments + // Implement logic to retrieve imported data segments + // For example, fetch from the data availability layer + [] // Placeholder + } + + private func retrieveJustifications(for _: WorkPackage) async throws -> [Data] { + // TODO: Implement retrieveJustifications + // Implement logic to retrieve justifications for the imported segments + // For example, fetch proofs from the data availability layer + [] // Placeholder + } + // workpackage -> workresult -> workreport private func createWorkReport(for workPackage: WorkPackageRef, coreIndex: CoreIndex) async throws -> WorkReport { let state = try await dataProvider.getState(hash: dataProvider.bestHead.hash) From 818dc23cdd696f2ebe9354d9fdf29b74d6b76883 Mon Sep 17 00:00:00 2001 From: MacOMNI <414294494@qq.com> Date: Fri, 21 Feb 2025 16:27:08 +0800 Subject: [PATCH 13/26] update Guaranteeing --- .../Sources/Blockchain/Validator/GuaranteeingService.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift b/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift index 3de49458..5adff4e1 100644 --- a/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift +++ b/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift @@ -167,10 +167,10 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable { } private func on(workPackagesReceived event: RuntimeEvents.WorkPackagesReceived) async throws { - try await refine(package: event.workPackageRef) + try await refine(coreIndex: event.coreIndex, package: event.workPackageRef, extrinsics: event.extrinsics) } - private func refine(package: WorkPackageRef) async throws { + private func refine(coreIndex _: CoreIndex, package: WorkPackageRef, extrinsics _: [Data]) async throws { guard let (validatorIndex, signingKey) = signingKey.value else { logger.debug("not in current validator set, skipping refine") return From 1843edde71126bf74b2b608e4a96cb568793ff43 Mon Sep 17 00:00:00 2001 From: MacOMNI <414294494@qq.com> Date: Mon, 24 Feb 2025 17:20:54 +0800 Subject: [PATCH 14/26] udpate guaranteeing --- .../Validator/GuaranteeingService.swift | 29 ++++++------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift b/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift index 5adff4e1..7dca5e7a 100644 --- a/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift +++ b/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift @@ -170,23 +170,12 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable { try await refine(coreIndex: event.coreIndex, package: event.workPackageRef, extrinsics: event.extrinsics) } - private func refine(coreIndex _: CoreIndex, package: WorkPackageRef, extrinsics _: [Data]) async throws { + private func refine(coreIndex: CoreIndex, package: WorkPackageRef, extrinsics: [Data]) async throws { guard let (validatorIndex, signingKey) = signingKey.value else { logger.debug("not in current validator set, skipping refine") return } - - let state = try await dataProvider.getState(hash: dataProvider.bestHead.hash) - - // TODO: check for edge cases such as epoch end - let currentCoreAssignment = state.value.getCoreAssignment( - config: config, - randomness: state.value.entropyPool.t2, - timeslot: state.value.timeslot + 1 - ) - guard let coreIndex = currentCoreAssignment[safe: Int(validatorIndex)] else { - try throwUnreachable("invalid validator index/core assignment") - } + try await shareWorkPackage(coreIndex: coreIndex, workPackage: package.value, extrinsics: extrinsics) let workReport = try await createWorkReport(for: package, coreIndex: coreIndex) let payload = SigningContext.guarantee + workReport.hash().data @@ -195,16 +184,15 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable { publish(event) } - public func createWorkPackageBundle(_ workPackage: WorkPackage) async throws -> WorkPackageBundle { + public func createWorkPackageBundle(_ workPackage: WorkPackage, extrinsics: [Data]) async throws -> WorkPackageBundle { // 1. Retrieve the necessary data for the bundle - let extrinsicData = try await retrieveExtrinsicData(for: workPackage) let importSegments = try await retrieveImportSegments(for: workPackage) let justifications = try await retrieveJustifications(for: workPackage) // 2. Construct the work package bundle return WorkPackageBundle( workPackage: workPackage, - extrinsic: extrinsicData, + extrinsic: extrinsics, importSegments: importSegments, justifications: justifications ) @@ -244,8 +232,9 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable { return segmentsRoot } - public func shareWorkPackage(_ workPackage: WorkPackage, coreIndex: CoreIndex) async throws { - // 1. Get other guarantors assigned to the same core + // Work Package Sharing (Send Side) + public func shareWorkPackage(coreIndex: CoreIndex, workPackage: WorkPackage, extrinsics: [Data]) async throws { + // 1. Get other guarantors assigned to the same core, how to let guarantors = try await getGuarantors(for: coreIndex) // 2. Validate the work package @@ -255,9 +244,9 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable { } // 3. Create WorkPackageBundle - let bundle = try await createWorkPackageBundle(workPackage) + let bundle = try await createWorkPackageBundle(workPackage, extrinsics: extrinsics) - // 4. Send the bundle to other guarantors + // 4. TODO: Send the bundle to other guarantors // 5. Map work-package hashes to segments-roots var mappings: SegmentsRootMappings = [] for guarantor in guarantors { From f74d966c062e9d72110b8e859079ac1f31cb85a3 Mon Sep 17 00:00:00 2001 From: MacOMNI <414294494@qq.com> Date: Mon, 24 Feb 2025 18:55:55 +0800 Subject: [PATCH 15/26] shareWorkPackage adjust --- .../Validator/GuaranteeingService.swift | 51 ++++++++++--------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift b/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift index 7dca5e7a..6e6f2ffb 100644 --- a/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift +++ b/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift @@ -171,27 +171,17 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable { } private func refine(coreIndex: CoreIndex, package: WorkPackageRef, extrinsics: [Data]) async throws { - guard let (validatorIndex, signingKey) = signingKey.value else { - logger.debug("not in current validator set, skipping refine") - return - } - try await shareWorkPackage(coreIndex: coreIndex, workPackage: package.value, extrinsics: extrinsics) - - let workReport = try await createWorkReport(for: package, coreIndex: coreIndex) - let payload = SigningContext.guarantee + workReport.hash().data - let signature = try signingKey.sign(message: payload) - let event = RuntimeEvents.WorkReportGenerated(item: workReport, signature: signature) - publish(event) + try await shareWorkPackage(coreIndex: coreIndex, workPackage: package, extrinsics: extrinsics) } - public func createWorkPackageBundle(_ workPackage: WorkPackage, extrinsics: [Data]) async throws -> WorkPackageBundle { + public func createWorkPackageBundle(_ workPackage: WorkPackageRef, extrinsics: [Data]) async throws -> WorkPackageBundle { // 1. Retrieve the necessary data for the bundle - let importSegments = try await retrieveImportSegments(for: workPackage) - let justifications = try await retrieveJustifications(for: workPackage) + let importSegments = try await retrieveImportSegments(for: workPackage.value) + let justifications = try await retrieveJustifications(for: workPackage.value) // 2. Construct the work package bundle return WorkPackageBundle( - workPackage: workPackage, + workPackage: workPackage.value, extrinsic: extrinsics, importSegments: importSegments, justifications: justifications @@ -233,21 +223,31 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable { } // Work Package Sharing (Send Side) - public func shareWorkPackage(coreIndex: CoreIndex, workPackage: WorkPackage, extrinsics: [Data]) async throws { - // 1. Get other guarantors assigned to the same core, how to + public func shareWorkPackage(coreIndex: CoreIndex, workPackage: WorkPackageRef, extrinsics: [Data]) async throws { + guard let (validatorIndex, signingKey) = signingKey.value else { + logger.debug("not in current validator set, skipping refine") + return + } + // TODO: validatorIndex -> coreIndex + // 1. TODO: Get other guarantors assigned to the same core let guarantors = try await getGuarantors(for: coreIndex) // 2. Validate the work package - guard try validate(workPackage: workPackage) else { + guard try validate(workPackage: workPackage.value) else { logger.error("Invalid work package: \(workPackage)") throw WorkPackageError.invalidWorkPackage } - // 3. Create WorkPackageBundle + // 3. Create WorkPackageBundle let bundle = try await createWorkPackageBundle(workPackage, extrinsics: extrinsics) - // 4. TODO: Send the bundle to other guarantors - // 5. Map work-package hashes to segments-roots + // 4. Retrieve segments-root mappings + let segmentsRootMappings = try await retrieveSegmentsRootMappings(for: workPackage.value) + + // 5. create work report + let workReport = try await createWorkReport(for: workPackage, coreIndex: coreIndex) + // 6. TODO: Send the bundle to other guarantors + // 7. Map work-package hashes to segments-roots var mappings: SegmentsRootMappings = [] for guarantor in guarantors { let (workReportHash, signature) = try await guarantor.receiveWorkPackageBundle( @@ -255,11 +255,12 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable { segmentsRootMappings: mappings, bundle: bundle ) - - // 6. Publish the work report hash and signature - // let event = RuntimeEvents.WorkReportGenerated(hash: workReportHash, signature: signature) - // publish(event) } + // 8. push + let payload = SigningContext.guarantee + workReport.hash().data + let signature = try signingKey.sign(message: payload) + let event = RuntimeEvents.WorkReportGenerated(item: workReport, signature: signature) + publish(event) } public func getGuarantors(for coreIndex: CoreIndex) async throws -> [Guarantor] { From e997aa7a00bd29937938156141561d9e1f434738 Mon Sep 17 00:00:00 2001 From: MacOMNI <414294494@qq.com> Date: Tue, 25 Feb 2025 09:44:53 +0800 Subject: [PATCH 16/26] update shareWorkPackage --- .../Validator/GuaranteeingService.swift | 92 ++++++------------- 1 file changed, 27 insertions(+), 65 deletions(-) diff --git a/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift b/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift index 6e6f2ffb..81cee70d 100644 --- a/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift +++ b/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift @@ -28,19 +28,11 @@ public struct Guarantor: Codable, Identifiable { coreIndex _: CoreIndex, segmentsRootMappings: SegmentsRootMappings, bundle: WorkPackageBundle - ) async throws -> (Data32, Data) { + ) async throws { // 1. Perform basic verification guard try validateWorkPackageBundle(bundle, segmentsRootMappings: segmentsRootMappings) else { throw WorkPackageError.invalidBundle } - - // 2. Execute refine logic - let workReportHash = try await refineWorkPackageBundle(bundle) - - // 3. Sign the work report hash - let signature = try await signData(workReportHash) - - return (workReportHash, signature) } private func validateWorkPackageBundle( @@ -74,20 +66,6 @@ public struct Guarantor: Codable, Identifiable { // TODO: Implement logic to validate the work package authorization true // Placeholder } - - private func refineWorkPackageBundle(_: WorkPackageBundle) async throws -> Data32 { - // TODO: Implement refine logic here - // For example, execute the work items and generate a work report - // let workReportHash = try await refineLogic.execute(bundle) - Data32() - } - - private func signData(_: Data32) async throws -> Data { - // TODO: Implement signing logic here - // For example, use the guarantor's private key to sign the data - // let signature = try await keystore.sign(data: data, with: privateKey) - Data() - } } public final class GuaranteeingService: ServiceBase2, @unchecked Sendable { @@ -174,20 +152,6 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable { try await shareWorkPackage(coreIndex: coreIndex, workPackage: package, extrinsics: extrinsics) } - public func createWorkPackageBundle(_ workPackage: WorkPackageRef, extrinsics: [Data]) async throws -> WorkPackageBundle { - // 1. Retrieve the necessary data for the bundle - let importSegments = try await retrieveImportSegments(for: workPackage.value) - let justifications = try await retrieveJustifications(for: workPackage.value) - - // 2. Construct the work package bundle - return WorkPackageBundle( - workPackage: workPackage.value, - extrinsic: extrinsics, - importSegments: importSegments, - justifications: justifications - ) - } - public func retrieveSegmentsRootMappings(for workPackage: WorkPackage) async throws -> SegmentsRootMappings { // 1. Get the import segments from the work package let importSegments = try await retrieveImportSegments(for: workPackage) @@ -238,31 +202,33 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable { throw WorkPackageError.invalidWorkPackage } - // 3. Create WorkPackageBundle - let bundle = try await createWorkPackageBundle(workPackage, extrinsics: extrinsics) - - // 4. Retrieve segments-root mappings + // 3. Retrieve segments-root mappings let segmentsRootMappings = try await retrieveSegmentsRootMappings(for: workPackage.value) - // 5. create work report - let workReport = try await createWorkReport(for: workPackage, coreIndex: coreIndex) - // 6. TODO: Send the bundle to other guarantors - // 7. Map work-package hashes to segments-roots - var mappings: SegmentsRootMappings = [] + // 4. Create work report & WorkPackageBundle + let (bundle, mappings, workReport) = try await createWorkReport( + coreIndex: coreIndex, + workPackage: workPackage, + extrinsics: extrinsics + ) + // 5. TODO: Send the bundle to other guarantors for guarantor in guarantors { - let (workReportHash, signature) = try await guarantor.receiveWorkPackageBundle( + // 6. TODO: Something needs to do, when receive workpackage bundle + try await guarantor.receiveWorkPackageBundle( coreIndex: coreIndex, segmentsRootMappings: mappings, bundle: bundle ) } - // 8. push + // 7. Sign the work report hash let payload = SigningContext.guarantee + workReport.hash().data let signature = try signingKey.sign(message: payload) let event = RuntimeEvents.WorkReportGenerated(item: workReport, signature: signature) + // 8. Push publish(event) } + // TODO: Get other guarantors assigned to the same core public func getGuarantors(for coreIndex: CoreIndex) async throws -> [Guarantor] { // 1. Get the current blockchain state let state = try await dataProvider.getState(hash: dataProvider.bestHead.hash) @@ -298,13 +264,6 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable { true } - private func retrieveExtrinsicData(for _: WorkPackage) async throws -> [Data] { - // TODO: Implement retrieveExtrinsicData - // Implement logic to retrieve extrinsic data associated with the work package - // For example, fetch from the blockchain or local storage - [] // Placeholder - } - private func retrieveImportSegments(for _: WorkPackage) async throws -> [Data4104] { // TODO: Implement retrieveImportSegments // Implement logic to retrieve imported data segments @@ -320,12 +279,15 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable { } // workpackage -> workresult -> workreport - private func createWorkReport(for workPackage: WorkPackageRef, coreIndex: CoreIndex) async throws -> WorkReport { + private func createWorkReport(coreIndex: CoreIndex, workPackage: WorkPackageRef, + extrinsics: [Data]) async throws -> (WorkPackageBundle, SegmentsRootMappings, WorkReport) + { let state = try await dataProvider.getState(hash: dataProvider.bestHead.hash) let packageHash = workPackage.hash let corePool = state.value.coreAuthorizationPool[coreIndex] let authorizerHash = try corePool.array.first.unwrap(orError: GuaranteeingServiceError.noAuthorizerHash) var exportSegmentOffset: UInt16 = 0 + var mappings: SegmentsRootMappings = [] // 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: @@ -373,16 +335,16 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable { exportSegments.append(contentsOf: refineRes.exports) } - - let (erasureRoot, length) = try await dataAvailability.exportWorkpackageBundle(bundle: WorkPackageBundle( + let bundle = try await WorkPackageBundle( workPackage: workPackage.value, - extrinsic: [], // TODO: get extrinsic data - importSegments: [], - justifications: [] - )) + extrinsic: extrinsics, + importSegments: retrieveImportSegments(for: workPackage.value), + justifications: retrieveJustifications(for: workPackage.value) + ) + let (erasureRoot, length) = try await dataAvailability.exportWorkpackageBundle(bundle: bundle) let segmentRoot = try await dataAvailability.exportSegments(data: exportSegments, erasureRoot: erasureRoot) - + mappings.append(SegmentsRootMapping(workPackageHash: packageHash, segmentsRoot: segmentRoot)) // TODO: generate or find AvailabilitySpecifications 14.4.1 work-package bundle let packageSpecification = AvailabilitySpecifications( workPackageHash: packageHash, @@ -396,7 +358,7 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable { for item in state.value.recentHistory.items { oldLookups.merge(item.lookup, uniquingKeysWith: { _, new in new }) } - return try WorkReport( + return try (bundle, mappings, WorkReport( authorizerHash: authorizerHash, coreIndex: coreIndex, authorizationOutput: authorizationOutput, @@ -404,7 +366,7 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable { packageSpecification: packageSpecification, lookup: oldLookups, results: ConfigLimitedSizeArray(config: config, array: workResults) - ) + )) case let .failure(error): logger.error("Authorization failed with error: \(error)") From ed08b97eb56c633ef9a34fab756954d6cbce4973 Mon Sep 17 00:00:00 2001 From: MacOMNI <414294494@qq.com> Date: Tue, 25 Feb 2025 17:04:55 +0800 Subject: [PATCH 17/26] update local --- .../Blockchain/Validator/GuaranteeingService.swift | 1 + .../BlockchainTests/GuaranteeingServiceTests.swift | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift b/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift index 5ffbbf90..a0b6f7b3 100644 --- a/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift +++ b/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift @@ -149,6 +149,7 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable { logger.debug("not in current validator set, skipping refine") return } + logger.info("validatorIndex = \(validatorIndex)") // TODO: validatorIndex -> coreIndex // 1. TODO: Get other guarantors assigned to the same core let guarantors = try await getGuarantors(for: coreIndex) diff --git a/Blockchain/Tests/BlockchainTests/GuaranteeingServiceTests.swift b/Blockchain/Tests/BlockchainTests/GuaranteeingServiceTests.swift index 1061539a..38ae6553 100644 --- a/Blockchain/Tests/BlockchainTests/GuaranteeingServiceTests.swift +++ b/Blockchain/Tests/BlockchainTests/GuaranteeingServiceTests.swift @@ -39,4 +39,14 @@ struct GuaranteeingServiceTests { #expect(signingKey.0 == 0) #expect(signingKey.1.publicKey == publicKey) } + + @Test func workPackagesReceived() async throws { + let (services, guaranteeingService) = try await setup(keysCount: 1) + + await guaranteeingService.onSyncCompleted() + + let workpackage = WorkPackage.dummy(config: services.config) + await services.eventBus + .publish(RuntimeEvents.WorkPackagesReceived(coreIndex: 0, workPackageRef: workpackage.asRef(), extrinsics: [])) + } } From 7bd8a025213240c1659828d0c3fdafeedeaf736c Mon Sep 17 00:00:00 2001 From: MacOMNI <414294494@qq.com> Date: Tue, 25 Feb 2025 17:20:22 +0800 Subject: [PATCH 18/26] update shareWorkPackage --- .../Validator/GuaranteeingService.swift | 52 +++++++++---------- .../GuaranteeingServiceTests.swift | 18 +++---- 2 files changed, 33 insertions(+), 37 deletions(-) diff --git a/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift b/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift index a0b6f7b3..7a4f8a3e 100644 --- a/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift +++ b/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift @@ -140,16 +140,28 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable { } // Work Package Sharing (Send Side) - public func shareWorkPackage(coreIndex: CoreIndex, workPackage: WorkPackageRef, extrinsics: [Data]) async throws { - try await refinePkg(coreIndex: coreIndex, workPackage: workPackage, extrinsics: extrinsics) + public func shareWorkPackage(coreIndex _: CoreIndex, workPackage: WorkPackageRef, extrinsics: [Data]) async throws { + try await refinePkg(workPackage: workPackage, extrinsics: extrinsics) } - private func refinePkg(coreIndex: CoreIndex, workPackage: WorkPackageRef, extrinsics: [Data]) async throws { + private func refinePkg(workPackage: WorkPackageRef, extrinsics: [Data]) async throws { guard let (validatorIndex, signingKey) = signingKey.value else { logger.debug("not in current validator set, skipping refine") return } - logger.info("validatorIndex = \(validatorIndex)") + + let state = try await dataProvider.getState(hash: dataProvider.bestHead.hash) + + // TODO: check for edge cases such as epoch end + let currentCoreAssignment = state.value.getCoreAssignment( + config: config, + randomness: state.value.entropyPool.t2, + timeslot: state.value.timeslot + 1 + ) + // TODO: coreIndex equal with shareWorkPackage coreIndex? + guard let coreIndex = currentCoreAssignment[safe: Int(validatorIndex)] else { + try throwUnreachable("invalid validator index/core assignment") + } // TODO: validatorIndex -> coreIndex // 1. TODO: Get other guarantors assigned to the same core let guarantors = try await getGuarantors(for: coreIndex) @@ -187,31 +199,15 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable { public func getGuarantors(for coreIndex: CoreIndex) async throws -> [Guarantor] { // 1. Get the current blockchain state let state = try await dataProvider.getState(hash: dataProvider.bestHead.hash) - - // 2. Get the core assignment for the current timeslot - let coreAssignment: [CoreIndex] = state.value.getCoreAssignment( - config: config, - randomness: state.value.entropyPool.t2, - timeslot: state.value.timeslot - ) - - // 3. Ensure the core index is valid - guard coreIndex < coreAssignment.count else { - logger.error("Invalid core index: \(coreIndex)") - try throwUnreachable("invalid validator index/core assignment") + var guarantors = [Guarantor]() + // TODO: Mock + for (_, v) in state.value.currentValidators.enumerated() { + guarantors.append(Guarantor( + id: v.ed25519.blake2b256hash(), // Use the validator's public key hash as the ID + coreIndex: coreIndex + )) } - - // 4. Get the validator index assigned to the core - let validatorIndex = coreAssignment[Int(coreIndex)] - - let validator = state.value.currentValidators[Int(validatorIndex)] - // 5. Create a Guarantor object for the validator - let guarantor = Guarantor( - id: validator.ed25519.blake2b256hash(), // Use the validator's public key hash as the ID - coreIndex: coreIndex - ) - - return [guarantor] + return guarantors } private func validate(workPackage _: WorkPackage) throws -> Bool { diff --git a/Blockchain/Tests/BlockchainTests/GuaranteeingServiceTests.swift b/Blockchain/Tests/BlockchainTests/GuaranteeingServiceTests.swift index 38ae6553..6ec1badf 100644 --- a/Blockchain/Tests/BlockchainTests/GuaranteeingServiceTests.swift +++ b/Blockchain/Tests/BlockchainTests/GuaranteeingServiceTests.swift @@ -40,13 +40,13 @@ struct GuaranteeingServiceTests { #expect(signingKey.1.publicKey == publicKey) } - @Test func workPackagesReceived() async throws { - let (services, guaranteeingService) = try await setup(keysCount: 1) - - await guaranteeingService.onSyncCompleted() - - let workpackage = WorkPackage.dummy(config: services.config) - await services.eventBus - .publish(RuntimeEvents.WorkPackagesReceived(coreIndex: 0, workPackageRef: workpackage.asRef(), extrinsics: [])) - } +// @Test func workPackagesReceived() async throws { +// let (services, guaranteeingService) = try await setup(keysCount: 1) +// +// await guaranteeingService.onSyncCompleted() +// +// let workpackage = WorkPackage.dummy(config: services.config) +// await services.eventBus +// .publish(RuntimeEvents.WorkPackagesReceived(coreIndex: 0, workPackageRef: workpackage.asRef(), extrinsics: [])) +// } } From 7f28c6b9d0f14048fe46bb8c2826118bd9653a44 Mon Sep 17 00:00:00 2001 From: MacOMNI <414294494@qq.com> Date: Tue, 25 Feb 2025 17:27:36 +0800 Subject: [PATCH 19/26] update --- .../Sources/Blockchain/Validator/GuaranteeingService.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift b/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift index 7a4f8a3e..1c2f7fba 100644 --- a/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift +++ b/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift @@ -201,9 +201,9 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable { let state = try await dataProvider.getState(hash: dataProvider.bestHead.hash) var guarantors = [Guarantor]() // TODO: Mock - for (_, v) in state.value.currentValidators.enumerated() { + for validator in state.value.currentValidators { guarantors.append(Guarantor( - id: v.ed25519.blake2b256hash(), // Use the validator's public key hash as the ID + id: validator.ed25519.blake2b256hash(), // 使用验证者的公钥哈希作为 ID coreIndex: coreIndex )) } From cdd3ba788934e562d70dc6cc6e0c5a15ce6225fc Mon Sep 17 00:00:00 2001 From: MacOMNI <414294494@qq.com> Date: Wed, 26 Feb 2025 17:29:42 +0800 Subject: [PATCH 20/26] update handleWorkPackage --- .../RuntimeProtocols/RuntimeEvents.swift | 22 ++ .../Blockchain/Types/RefinementContext.swift | 6 - .../Types/SegmentsRootMappings.swift | 9 + .../Blockchain/Types/WorkPackage.swift | 6 - .../Validator/GuaranteeingService.swift | 195 +++++++++--------- 5 files changed, 124 insertions(+), 114 deletions(-) create mode 100644 Blockchain/Sources/Blockchain/Types/SegmentsRootMappings.swift diff --git a/Blockchain/Sources/Blockchain/RuntimeProtocols/RuntimeEvents.swift b/Blockchain/Sources/Blockchain/RuntimeProtocols/RuntimeEvents.swift index ff727e39..659de31a 100644 --- a/Blockchain/Sources/Blockchain/RuntimeProtocols/RuntimeEvents.swift +++ b/Blockchain/Sources/Blockchain/RuntimeProtocols/RuntimeEvents.swift @@ -67,7 +67,29 @@ public enum RuntimeEvents { // When a work package bundle is ready to shared via CE134 public struct WorkPackageBundleReady: Event { + public let coreIndex: CoreIndex public let bundle: WorkPackageBundle + public let segmentsRootMappings: SegmentsRootMappings + + public init( + coreIndex: CoreIndex, + bundle: WorkPackageBundle, + segmentsRootMappings: SegmentsRootMappings + ) { + self.coreIndex = coreIndex + self.bundle = bundle + self.segmentsRootMappings = segmentsRootMappings + } + } + + // When a work package bundle is is recived via CE134 + public struct WorkPackageBundleRecived: Event { + public let workPackageHash: Data32 + public let edd25519Signature: Data64 + public init(workPackageHash: Data32, edd25519Signature: Data64) { + self.workPackageHash = workPackageHash + self.edd25519Signature = edd25519Signature + } } // When a work report is generated and ready to be distrubuted via CE135 diff --git a/Blockchain/Sources/Blockchain/Types/RefinementContext.swift b/Blockchain/Sources/Blockchain/Types/RefinementContext.swift index b5092de0..849708f2 100644 --- a/Blockchain/Sources/Blockchain/Types/RefinementContext.swift +++ b/Blockchain/Sources/Blockchain/Types/RefinementContext.swift @@ -76,12 +76,6 @@ public struct RefinementContext: Comparable, Sendable, Equatable, Codable { } } -extension RefinementContext: Hashable32 { - public func hash() -> Data32 { - try! JamEncoder.encode(self).blake2b256hash() - } -} - extension RefinementContext: Dummy { public typealias Config = ProtocolConfigRef public static func dummy(config _: Config) -> RefinementContext { diff --git a/Blockchain/Sources/Blockchain/Types/SegmentsRootMappings.swift b/Blockchain/Sources/Blockchain/Types/SegmentsRootMappings.swift new file mode 100644 index 00000000..0e260ce2 --- /dev/null +++ b/Blockchain/Sources/Blockchain/Types/SegmentsRootMappings.swift @@ -0,0 +1,9 @@ +import Foundation +import Utils + +public struct SegmentsRootMapping: Sendable, Equatable, Codable { + public let workPackageHash: Data32 + public let segmentsRoot: Data32 +} + +public typealias SegmentsRootMappings = [SegmentsRootMapping] diff --git a/Blockchain/Sources/Blockchain/Types/WorkPackage.swift b/Blockchain/Sources/Blockchain/Types/WorkPackage.swift index d4dec89f..091d99a6 100644 --- a/Blockchain/Sources/Blockchain/Types/WorkPackage.swift +++ b/Blockchain/Sources/Blockchain/Types/WorkPackage.swift @@ -2,12 +2,6 @@ import Codec import Foundation import Utils -public enum WorkPackageError: Error { - case invalidWorkPackage - case invalidBundle - case segmentsRootNotFound -} - // P public struct WorkPackage: Comparable, Sendable, Equatable, Codable, Hashable { // j diff --git a/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift b/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift index 1c2f7fba..6f5b074f 100644 --- a/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift +++ b/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift @@ -6,63 +6,9 @@ import Utils public enum GuaranteeingServiceError: Error { case noAuthorizerHash case invalidExports -} - -public struct SegmentsRootMapping: Codable { - public let workPackageHash: Data32 - public let segmentsRoot: SegmentsRoot -} - -public typealias SegmentsRoot = Data32 -public typealias SegmentsRootMappings = [SegmentsRootMapping] - -public struct Guarantor: Codable, Identifiable { - public let id: Data32 // Unique identifier for the guarantor (e.g., public key hash) - public let coreIndex: CoreIndex // The core index to which the guarantor is assigned - - // Method to receive a work package bundle - public func receiveWorkPackageBundle( - coreIndex _: CoreIndex, - segmentsRootMappings: SegmentsRootMappings, - bundle: WorkPackageBundle - ) async throws { - // 1. Perform basic verification - guard try validateWorkPackageBundle(bundle, segmentsRootMappings: segmentsRootMappings) else { - throw WorkPackageError.invalidBundle - } - } - - private func validateWorkPackageBundle( - _ bundle: WorkPackageBundle, - segmentsRootMappings: SegmentsRootMappings - ) throws -> Bool { - // 1. Validate the work package authorization - guard try validateAuthorization(bundle.workPackage) else { - return false - } - - // 2. Validate the segments-root mappings - for mapping in segmentsRootMappings { - guard try validateSegmentsRootMapping(mapping, for: bundle.workPackage) else { - return false - } - } - - return true - } - - private func validateSegmentsRootMapping( - _: SegmentsRootMapping, - for _: WorkPackage - ) throws -> Bool { - // TODO: Implement logic to validate the segments-root mapping - true // Placeholder - } - - private func validateAuthorization(_: WorkPackage) throws -> Bool { - // TODO: Implement logic to validate the work package authorization - true // Placeholder - } + case invalidWorkPackage + case invalidBundle + case segmentsRootNotFound } public final class GuaranteeingService: ServiceBase2, @unchecked Sendable { @@ -95,6 +41,10 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable { await subscribe(RuntimeEvents.WorkPackagesReceived.self, id: "GuaranteeingService.WorkPackagesReceived") { [weak self] event in try await self?.on(workPackagesReceived: event) } + + await subscribe(RuntimeEvents.WorkPackageBundleReady.self, id: "GuaranteeingService.WorkPackageBundleReady") { [weak self] event in + try await self?.on(workPackageBundleReady: event) + } } public func onSyncCompleted() async { @@ -135,21 +85,88 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable { } } - private func on(workPackagesReceived event: RuntimeEvents.WorkPackagesReceived) async throws { - try await shareWorkPackage(coreIndex: event.coreIndex, workPackage: event.workPackageRef, extrinsics: event.extrinsics) + private func on(workPackageBundleReady event: RuntimeEvents.WorkPackageBundleReady) async throws { + try await receiveWorkPackageBundleReady( + coreIndex: event.coreIndex, + segmentsRootMappings: event.segmentsRootMappings, + bundle: event.bundle + ) + } + + private func on(workPackageBundleReceived _: RuntimeEvents.WorkPackageBundleRecived) async throws { + // TODO: check somethings + } + + // Method to receive a work package bundle ready + private func receiveWorkPackageBundleReady( + coreIndex _: CoreIndex, + segmentsRootMappings: SegmentsRootMappings, + bundle: WorkPackageBundle + ) async throws { + // 1. Perform basic verification + guard try validateWorkPackageBundle(bundle, segmentsRootMappings: segmentsRootMappings) else { + throw GuaranteeingServiceError.invalidBundle + } } - // Work Package Sharing (Send Side) - public func shareWorkPackage(coreIndex _: CoreIndex, workPackage: WorkPackageRef, extrinsics: [Data]) async throws { - try await refinePkg(workPackage: workPackage, extrinsics: extrinsics) + private func validateWorkPackageBundle( + _ bundle: WorkPackageBundle, + segmentsRootMappings: SegmentsRootMappings + ) throws -> Bool { + // 1. Validate the work package authorization + guard try validateAuthorization(bundle.workPackage) else { + return false + } + + // 2. Validate the segments-root mappings + for mapping in segmentsRootMappings { + guard try validateSegmentsRootMapping(mapping, for: bundle.workPackage) else { + return false + } + } + + return true + } + + private func on(workPackagesReceived event: RuntimeEvents.WorkPackagesReceived) async throws { + try await handleWorkPackage(coreIndex: event.coreIndex, workPackage: event.workPackageRef, extrinsics: event.extrinsics) } - private func refinePkg(workPackage: WorkPackageRef, extrinsics: [Data]) async throws { + // handle Work Package + public func handleWorkPackage(coreIndex: CoreIndex, workPackage: WorkPackageRef, extrinsics: [Data]) async throws { + // 1. Validate the work package + guard try validate(workPackage: workPackage.value) else { + logger.error("Invalid work package: \(workPackage)") + throw GuaranteeingServiceError.invalidWorkPackage + } guard let (validatorIndex, signingKey) = signingKey.value else { logger.debug("not in current validator set, skipping refine") return } + // 2. share work package + // 3. reine + let (bundle, mappings, workReport) = try await refine( + validatorIndex: validatorIndex, + workPackage: workPackage, + extrinsics: extrinsics + ) + // 4. share work bundle + let shareWorkBundleEvent = RuntimeEvents.WorkPackageBundleReady( + coreIndex: coreIndex, + bundle: bundle, + segmentsRootMappings: mappings + ) + publish(shareWorkBundleEvent) + // 5. sign work report & work-report distribution + let payload = SigningContext.guarantee + workReport.hash().data + let signature = try signingKey.sign(message: payload) + let workReportEvent = RuntimeEvents.WorkReportGenerated(item: workReport, signature: signature) + publish(workReportEvent) + } + private func refine(validatorIndex: ValidatorIndex, workPackage: WorkPackageRef, + extrinsics: [Data]) async throws -> (WorkPackageBundle, SegmentsRootMappings, WorkReport) + { let state = try await dataProvider.getState(hash: dataProvider.bestHead.hash) // TODO: check for edge cases such as epoch end @@ -162,52 +179,26 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable { guard let coreIndex = currentCoreAssignment[safe: Int(validatorIndex)] else { try throwUnreachable("invalid validator index/core assignment") } - // TODO: validatorIndex -> coreIndex - // 1. TODO: Get other guarantors assigned to the same core - let guarantors = try await getGuarantors(for: coreIndex) - // 2. Validate the work package - guard try validate(workPackage: workPackage.value) else { - logger.error("Invalid work package: \(workPackage)") - throw WorkPackageError.invalidWorkPackage - } - - // 3. Create work report & WorkPackageBundle - let (bundle, mappings, workReport) = try await createWorkReport( + // Create work report & WorkPackageBundle + return try await createWorkReport( coreIndex: coreIndex, workPackage: workPackage, extrinsics: extrinsics ) - // 4. TODO: Send the bundle to other guarantors - for guarantor in guarantors { - // 5. TODO: Something needs to do, when receive workpackage bundle - try await guarantor.receiveWorkPackageBundle( - coreIndex: coreIndex, - segmentsRootMappings: mappings, - bundle: bundle - ) - } - // 6. Sign the work report hash - let payload = SigningContext.guarantee + workReport.hash().data - let signature = try signingKey.sign(message: payload) - let event = RuntimeEvents.WorkReportGenerated(item: workReport, signature: signature) - // 7. Push - publish(event) } - // TODO: Get other guarantors assigned to the same core - public func getGuarantors(for coreIndex: CoreIndex) async throws -> [Guarantor] { - // 1. Get the current blockchain state - let state = try await dataProvider.getState(hash: dataProvider.bestHead.hash) - var guarantors = [Guarantor]() - // TODO: Mock - for validator in state.value.currentValidators { - guarantors.append(Guarantor( - id: validator.ed25519.blake2b256hash(), // 使用验证者的公钥哈希作为 ID - coreIndex: coreIndex - )) - } - return guarantors + private func validateSegmentsRootMapping( + _: SegmentsRootMapping, + for _: WorkPackage + ) throws -> Bool { + // TODO: Implement logic to validate the segments-root mapping + true // Placeholder + } + + private func validateAuthorization(_: WorkPackage) throws -> Bool { + // TODO: Implement logic to validate the work package authorization + true // Placeholder } private func validate(workPackage _: WorkPackage) throws -> Bool { From 3020b9856d6e918b4e56f3261147d3f57567bb0c Mon Sep 17 00:00:00 2001 From: MacOMNI <414294494@qq.com> Date: Wed, 26 Feb 2025 17:55:18 +0800 Subject: [PATCH 21/26] update ShareWorkPackage --- .../RuntimeProtocols/RuntimeEvents.swift | 15 +++++++- .../Validator/GuaranteeingService.swift | 35 +++++++++++++------ 2 files changed, 38 insertions(+), 12 deletions(-) diff --git a/Blockchain/Sources/Blockchain/RuntimeProtocols/RuntimeEvents.swift b/Blockchain/Sources/Blockchain/RuntimeProtocols/RuntimeEvents.swift index 659de31a..0676264a 100644 --- a/Blockchain/Sources/Blockchain/RuntimeProtocols/RuntimeEvents.swift +++ b/Blockchain/Sources/Blockchain/RuntimeProtocols/RuntimeEvents.swift @@ -82,7 +82,20 @@ public enum RuntimeEvents { } } - // When a work package bundle is is recived via CE134 + // When a work package will be shared via CE134 + public struct ShareWorkPackage: Event { + public let coreIndex: CoreIndex + public let workPackage: WorkPackageRef + public let extrinsics: [Data] + + public init(coreIndex: CoreIndex, workPackage: WorkPackageRef, extrinsics: [Data]) { + self.coreIndex = coreIndex + self.workPackage = workPackage + self.extrinsics = extrinsics + } + } + + // When a work package bundle is recived via CE134 public struct WorkPackageBundleRecived: Event { public let workPackageHash: Data32 public let edd25519Signature: Data64 diff --git a/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift b/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift index 6f5b074f..dff19477 100644 --- a/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift +++ b/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift @@ -38,6 +38,10 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable { super.init(id: "GuaranteeingService", config: config, eventBus: eventBus, scheduler: scheduler) + await subscribe(RuntimeEvents.ShareWorkPackage.self, id: "GuaranteeingService.ShareWorkPackage") { [weak self] event in + try await self?.on(shareWorkPackage: event) + } + await subscribe(RuntimeEvents.WorkPackagesReceived.self, id: "GuaranteeingService.WorkPackagesReceived") { [weak self] event in try await self?.on(workPackagesReceived: event) } @@ -85,6 +89,14 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable { } } + private func on(shareWorkPackage event: RuntimeEvents.ShareWorkPackage) async throws { + guard try validate(workPackage: event.workPackage.value) else { + logger.error("Invalid work package: \(event.workPackage)") + throw GuaranteeingServiceError.invalidWorkPackage + } + // TODO: sometings need to do + } + private func on(workPackageBundleReady event: RuntimeEvents.WorkPackageBundleReady) async throws { try await receiveWorkPackageBundleReady( coreIndex: event.coreIndex, @@ -103,7 +115,7 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable { segmentsRootMappings: SegmentsRootMappings, bundle: WorkPackageBundle ) async throws { - // 1. Perform basic verification + // Perform basic verification guard try validateWorkPackageBundle(bundle, segmentsRootMappings: segmentsRootMappings) else { throw GuaranteeingServiceError.invalidBundle } @@ -113,12 +125,12 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable { _ bundle: WorkPackageBundle, segmentsRootMappings: SegmentsRootMappings ) throws -> Bool { - // 1. Validate the work package authorization + // Validate the work package authorization guard try validateAuthorization(bundle.workPackage) else { return false } - // 2. Validate the segments-root mappings + // Validate the segments-root mappings for mapping in segmentsRootMappings { guard try validateSegmentsRootMapping(mapping, for: bundle.workPackage) else { return false @@ -134,7 +146,7 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable { // handle Work Package public func handleWorkPackage(coreIndex: CoreIndex, workPackage: WorkPackageRef, extrinsics: [Data]) async throws { - // 1. Validate the work package + // Validate the work package guard try validate(workPackage: workPackage.value) else { logger.error("Invalid work package: \(workPackage)") throw GuaranteeingServiceError.invalidWorkPackage @@ -143,29 +155,30 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable { logger.debug("not in current validator set, skipping refine") return } - // 2. share work package - // 3. reine - let (bundle, mappings, workReport) = try await refine( + // Share work package + + // Reine + let (bundle, mappings, workReport) = try await refinePkg( validatorIndex: validatorIndex, workPackage: workPackage, extrinsics: extrinsics ) - // 4. share work bundle + // Share work bundle let shareWorkBundleEvent = RuntimeEvents.WorkPackageBundleReady( coreIndex: coreIndex, bundle: bundle, segmentsRootMappings: mappings ) publish(shareWorkBundleEvent) - // 5. sign work report & work-report distribution + // Sign work report & work-report distribution via CE 135 let payload = SigningContext.guarantee + workReport.hash().data let signature = try signingKey.sign(message: payload) let workReportEvent = RuntimeEvents.WorkReportGenerated(item: workReport, signature: signature) publish(workReportEvent) } - private func refine(validatorIndex: ValidatorIndex, workPackage: WorkPackageRef, - extrinsics: [Data]) async throws -> (WorkPackageBundle, SegmentsRootMappings, WorkReport) + private func refinePkg(validatorIndex: ValidatorIndex, workPackage: WorkPackageRef, + extrinsics: [Data]) async throws -> (WorkPackageBundle, SegmentsRootMappings, WorkReport) { let state = try await dataProvider.getState(hash: dataProvider.bestHead.hash) From 16d01e9fdee0c1a49ebe0cdbcdaa896acb6d49ed Mon Sep 17 00:00:00 2001 From: MacOMNI <414294494@qq.com> Date: Wed, 26 Feb 2025 19:46:25 +0800 Subject: [PATCH 22/26] update Work-package sharing --- .../Blockchain/Validator/GuaranteeingService.swift | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift b/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift index dff19477..0f561728 100644 --- a/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift +++ b/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift @@ -155,14 +155,18 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable { logger.debug("not in current validator set, skipping refine") return } + // Share work package + let shareWorkPackageEvent = RuntimeEvents.ShareWorkPackage(coreIndex: coreIndex, workPackage: workPackage, extrinsics: extrinsics) + publish(shareWorkPackageEvent) - // Reine + // check & refine let (bundle, mappings, workReport) = try await refinePkg( validatorIndex: validatorIndex, workPackage: workPackage, extrinsics: extrinsics ) + // Share work bundle let shareWorkBundleEvent = RuntimeEvents.WorkPackageBundleReady( coreIndex: coreIndex, @@ -216,6 +220,8 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable { private func validate(workPackage _: WorkPackage) throws -> Bool { // TODO: Add validate func + // 1. Check if it is possible to generate a work-report + // 2. Check all import segments have been retrieved true } From 2204effa87fae29afef73c8f35a34d95ec67d018 Mon Sep 17 00:00:00 2001 From: MacOMNI <414294494@qq.com> Date: Thu, 27 Feb 2025 10:36:51 +0800 Subject: [PATCH 23/26] update WorkPackageShare --- .../RuntimeProtocols/RuntimeEvents.swift | 8 +++--- .../Validator/GuaranteeingService.swift | 12 ++++----- .../GuaranteeingServiceTests.swift | 2 +- .../CommonEphemeral/CERequest.swift | 10 +++++++ .../NetworkingProtocol/NetworkManager.swift | 13 ++++++++- .../Tests/NodeTests/NetworkManagerTests.swift | 27 ++++++++++++++++++- 6 files changed, 59 insertions(+), 13 deletions(-) diff --git a/Blockchain/Sources/Blockchain/RuntimeProtocols/RuntimeEvents.swift b/Blockchain/Sources/Blockchain/RuntimeProtocols/RuntimeEvents.swift index 0676264a..a92d216f 100644 --- a/Blockchain/Sources/Blockchain/RuntimeProtocols/RuntimeEvents.swift +++ b/Blockchain/Sources/Blockchain/RuntimeProtocols/RuntimeEvents.swift @@ -55,12 +55,12 @@ public enum RuntimeEvents { // When a work package is recived via CE133 public struct WorkPackagesReceived: Event { public let coreIndex: CoreIndex - public let workPackageRef: WorkPackageRef + public let workPackage: WorkPackageRef public let extrinsics: [Data] - public init(coreIndex: CoreIndex, workPackageRef: WorkPackageRef, extrinsics: [Data]) { + public init(coreIndex: CoreIndex, workPackage: WorkPackageRef, extrinsics: [Data]) { self.coreIndex = coreIndex - self.workPackageRef = workPackageRef + self.workPackage = workPackage self.extrinsics = extrinsics } } @@ -83,7 +83,7 @@ public enum RuntimeEvents { } // When a work package will be shared via CE134 - public struct ShareWorkPackage: Event { + public struct WorkPackageShare: Event { public let coreIndex: CoreIndex public let workPackage: WorkPackageRef public let extrinsics: [Data] diff --git a/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift b/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift index 0f561728..faba394b 100644 --- a/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift +++ b/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift @@ -38,8 +38,8 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable { super.init(id: "GuaranteeingService", config: config, eventBus: eventBus, scheduler: scheduler) - await subscribe(RuntimeEvents.ShareWorkPackage.self, id: "GuaranteeingService.ShareWorkPackage") { [weak self] event in - try await self?.on(shareWorkPackage: event) + await subscribe(RuntimeEvents.WorkPackageShare.self, id: "GuaranteeingService.ShareWorkPackage") { [weak self] event in + try await self?.on(workPackagSharee: event) } await subscribe(RuntimeEvents.WorkPackagesReceived.self, id: "GuaranteeingService.WorkPackagesReceived") { [weak self] event in @@ -89,7 +89,7 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable { } } - private func on(shareWorkPackage event: RuntimeEvents.ShareWorkPackage) async throws { + private func on(workPackagSharee event: RuntimeEvents.WorkPackageShare) async throws { guard try validate(workPackage: event.workPackage.value) else { logger.error("Invalid work package: \(event.workPackage)") throw GuaranteeingServiceError.invalidWorkPackage @@ -141,7 +141,7 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable { } private func on(workPackagesReceived event: RuntimeEvents.WorkPackagesReceived) async throws { - try await handleWorkPackage(coreIndex: event.coreIndex, workPackage: event.workPackageRef, extrinsics: event.extrinsics) + try await handleWorkPackage(coreIndex: event.coreIndex, workPackage: event.workPackage, extrinsics: event.extrinsics) } // handle Work Package @@ -157,7 +157,7 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable { } // Share work package - let shareWorkPackageEvent = RuntimeEvents.ShareWorkPackage(coreIndex: coreIndex, workPackage: workPackage, extrinsics: extrinsics) + let shareWorkPackageEvent = RuntimeEvents.WorkPackageShare(coreIndex: coreIndex, workPackage: workPackage, extrinsics: extrinsics) publish(shareWorkPackageEvent) // check & refine @@ -218,8 +218,8 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable { true // Placeholder } + // TODO: Add validate func private func validate(workPackage _: WorkPackage) throws -> Bool { - // TODO: Add validate func // 1. Check if it is possible to generate a work-report // 2. Check all import segments have been retrieved true diff --git a/Blockchain/Tests/BlockchainTests/GuaranteeingServiceTests.swift b/Blockchain/Tests/BlockchainTests/GuaranteeingServiceTests.swift index 6ec1badf..a9a4b1ce 100644 --- a/Blockchain/Tests/BlockchainTests/GuaranteeingServiceTests.swift +++ b/Blockchain/Tests/BlockchainTests/GuaranteeingServiceTests.swift @@ -47,6 +47,6 @@ struct GuaranteeingServiceTests { // // let workpackage = WorkPackage.dummy(config: services.config) // await services.eventBus -// .publish(RuntimeEvents.WorkPackagesReceived(coreIndex: 0, workPackageRef: workpackage.asRef(), extrinsics: [])) +// .publish(RuntimeEvents.WorkPackagesReceived(coreIndex: 0, workPackage: workpackage.asRef(), extrinsics: [])) // } } diff --git a/Node/Sources/Node/NetworkingProtocol/CommonEphemeral/CERequest.swift b/Node/Sources/Node/NetworkingProtocol/CommonEphemeral/CERequest.swift index f3b162e9..7d733c92 100644 --- a/Node/Sources/Node/NetworkingProtocol/CommonEphemeral/CERequest.swift +++ b/Node/Sources/Node/NetworkingProtocol/CommonEphemeral/CERequest.swift @@ -8,6 +8,7 @@ public enum CERequest: Sendable, Equatable, Hashable { case safroleTicket1(SafroleTicketMessage) case safroleTicket2(SafroleTicketMessage) case workPackageSubmission(WorkPackageMessage) + case workPackageSharing(WorkPackageMessage) } extension CERequest: RequestProtocol { @@ -23,6 +24,8 @@ extension CERequest: RequestProtocol { try JamEncoder.encode(message) case let .workPackageSubmission(message): try JamEncoder.encode(message) + case let .workPackageSharing(message): + try JamEncoder.encode(message) } } @@ -36,6 +39,8 @@ extension CERequest: RequestProtocol { .safroleTicket2 case .workPackageSubmission: .workPackageSubmission + case .workPackageSharing: + .workPackageSharing } } @@ -49,6 +54,8 @@ extension CERequest: RequestProtocol { SafroleTicketMessage.self case .workPackageSubmission: WorkPackageMessage.self + case .workPackageSharing: + WorkPackageMessage.self default: fatalError("unimplemented") } @@ -74,6 +81,9 @@ extension CERequest: RequestProtocol { case .workPackageSubmission: guard let message = data as? WorkPackageMessage else { return nil } return .workPackageSubmission(message) + case .workPackageSharing: + guard let message = data as? WorkPackageMessage else { return nil } + return .workPackageSharing(message) default: fatalError("unimplemented") } diff --git a/Node/Sources/Node/NetworkingProtocol/NetworkManager.swift b/Node/Sources/Node/NetworkingProtocol/NetworkManager.swift index 2e9ef0e6..39ccb868 100644 --- a/Node/Sources/Node/NetworkingProtocol/NetworkManager.swift +++ b/Node/Sources/Node/NetworkingProtocol/NetworkManager.swift @@ -232,7 +232,18 @@ struct HandlerImpl: NetworkProtocolHandler { event: RuntimeEvents .WorkPackagesReceived( coreIndex: message.coreIndex, - workPackageRef: message.workPackage.asRef(), + workPackage: message.workPackage.asRef(), + extrinsics: message.extrinsics + ) + ) + return [] + case let .workPackageSharing(message): + blockchain + .publish( + event: RuntimeEvents + .WorkPackageShare( + coreIndex: message.coreIndex, + workPackage: message.workPackage.asRef(), extrinsics: message.extrinsics ) ) diff --git a/Node/Tests/NodeTests/NetworkManagerTests.swift b/Node/Tests/NodeTests/NetworkManagerTests.swift index 70ebb7e1..b4daf53e 100644 --- a/Node/Tests/NodeTests/NetworkManagerTests.swift +++ b/Node/Tests/NodeTests/NetworkManagerTests.swift @@ -81,7 +81,32 @@ struct NetworkManagerTests { // Publish WorkPackagesReceived event await services.blockchain - .publish(event: RuntimeEvents.WorkPackagesReceived(coreIndex: 0, workPackageRef: workPackage, extrinsics: [])) + .publish(event: RuntimeEvents.WorkPackagesReceived(coreIndex: 0, workPackage: workPackage, extrinsics: [])) + + // Wait for event processing + await storeMiddleware.wait() + + // Verify network calls + #expect( + network.contain(calls: [ + .init(function: "connect", parameters: ["address": devPeers.first!, "role": PeerRole.validator]), + .init(function: "sendToPeer", parameters: [ + "message": CERequest.workPackageSubmission( + WorkPackageMessage(coreIndex: 0, workPackage: workPackage.value, extrinsics: []) + ), + ]), + ]) + ) + } + + @Test + func testWorkPackagesShare() async throws { + // Create dummy work packages + let workPackage = WorkPackage.dummy(config: services.config).asRef() + + // Publish WorkPackagesShare event + await services.blockchain + .publish(event: RuntimeEvents.WorkPackageShare(coreIndex: 0, workPackage: workPackage, extrinsics: [])) // Wait for event processing await storeMiddleware.wait() From 8ab084af339cc98fc7bd2276e72d7375db17a259 Mon Sep 17 00:00:00 2001 From: MacOMNI <414294494@qq.com> Date: Thu, 27 Feb 2025 11:16:23 +0800 Subject: [PATCH 24/26] update GuaranteeingServiceTests --- .../GuaranteeingServiceTests.swift | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Blockchain/Tests/BlockchainTests/GuaranteeingServiceTests.swift b/Blockchain/Tests/BlockchainTests/GuaranteeingServiceTests.swift index a9a4b1ce..e65f82a5 100644 --- a/Blockchain/Tests/BlockchainTests/GuaranteeingServiceTests.swift +++ b/Blockchain/Tests/BlockchainTests/GuaranteeingServiceTests.swift @@ -40,13 +40,13 @@ struct GuaranteeingServiceTests { #expect(signingKey.1.publicKey == publicKey) } -// @Test func workPackagesReceived() async throws { -// let (services, guaranteeingService) = try await setup(keysCount: 1) -// -// await guaranteeingService.onSyncCompleted() -// -// let workpackage = WorkPackage.dummy(config: services.config) -// await services.eventBus -// .publish(RuntimeEvents.WorkPackagesReceived(coreIndex: 0, workPackage: workpackage.asRef(), extrinsics: [])) -// } + @Test func workPackagesReceived() async throws { + let (services, guaranteeingService) = try await setup(keysCount: 0) + + await guaranteeingService.onSyncCompleted() + + let workpackage = WorkPackage.dummy(config: services.config) + await services.eventBus + .publish(RuntimeEvents.WorkPackagesReceived(coreIndex: 0, workPackage: workpackage.asRef(), extrinsics: [])) + } } From 0b370b1fdaa19b29fd86faf1cc3a59b84fc8ecdb Mon Sep 17 00:00:00 2001 From: MacOMNI <414294494@qq.com> Date: Thu, 27 Feb 2025 15:11:39 +0800 Subject: [PATCH 25/26] no message --- .../Blockchain/Validator/GuaranteeingService.swift | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift b/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift index faba394b..781c89ea 100644 --- a/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift +++ b/Blockchain/Sources/Blockchain/Validator/GuaranteeingService.swift @@ -39,7 +39,7 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable { super.init(id: "GuaranteeingService", config: config, eventBus: eventBus, scheduler: scheduler) await subscribe(RuntimeEvents.WorkPackageShare.self, id: "GuaranteeingService.ShareWorkPackage") { [weak self] event in - try await self?.on(workPackagSharee: event) + try await self?.on(workPackagShare: event) } await subscribe(RuntimeEvents.WorkPackagesReceived.self, id: "GuaranteeingService.WorkPackagesReceived") { [weak self] event in @@ -47,7 +47,7 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable { } await subscribe(RuntimeEvents.WorkPackageBundleReady.self, id: "GuaranteeingService.WorkPackageBundleReady") { [weak self] event in - try await self?.on(workPackageBundleReady: event) + try await self?.on(workPackageBundle: event) } } @@ -89,7 +89,7 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable { } } - private func on(workPackagSharee event: RuntimeEvents.WorkPackageShare) async throws { + private func on(workPackagShare event: RuntimeEvents.WorkPackageShare) async throws { guard try validate(workPackage: event.workPackage.value) else { logger.error("Invalid work package: \(event.workPackage)") throw GuaranteeingServiceError.invalidWorkPackage @@ -97,8 +97,8 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable { // TODO: sometings need to do } - private func on(workPackageBundleReady event: RuntimeEvents.WorkPackageBundleReady) async throws { - try await receiveWorkPackageBundleReady( + private func on(workPackageBundle event: RuntimeEvents.WorkPackageBundleReady) async throws { + try await receiveWorkPackageBundle( coreIndex: event.coreIndex, segmentsRootMappings: event.segmentsRootMappings, bundle: event.bundle @@ -109,8 +109,8 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable { // TODO: check somethings } - // Method to receive a work package bundle ready - private func receiveWorkPackageBundleReady( + // Method to receive a work package bundle + private func receiveWorkPackageBundle( coreIndex _: CoreIndex, segmentsRootMappings: SegmentsRootMappings, bundle: WorkPackageBundle From 252f698468cb18869f2d2f85cd777861ca021a6e Mon Sep 17 00:00:00 2001 From: MacOMNI <414294494@qq.com> Date: Thu, 27 Feb 2025 16:17:14 +0800 Subject: [PATCH 26/26] TODO: add more tests --- .../GuaranteeingServiceTests.swift | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/Blockchain/Tests/BlockchainTests/GuaranteeingServiceTests.swift b/Blockchain/Tests/BlockchainTests/GuaranteeingServiceTests.swift index e65f82a5..a114451e 100644 --- a/Blockchain/Tests/BlockchainTests/GuaranteeingServiceTests.swift +++ b/Blockchain/Tests/BlockchainTests/GuaranteeingServiceTests.swift @@ -39,14 +39,20 @@ struct GuaranteeingServiceTests { #expect(signingKey.0 == 0) #expect(signingKey.1.publicKey == publicKey) } - - @Test func workPackagesReceived() async throws { - let (services, guaranteeingService) = try await setup(keysCount: 0) - - await guaranteeingService.onSyncCompleted() - - let workpackage = WorkPackage.dummy(config: services.config) - await services.eventBus - .publish(RuntimeEvents.WorkPackagesReceived(coreIndex: 0, workPackage: workpackage.asRef(), extrinsics: [])) - } + // TODO: add more tests +// @Test func workPackagesReceived() async throws { +// let (services, guaranteeingService) = try await setup() +// +// await guaranteeingService.onSyncCompleted() +// let workpackage = WorkPackage( +// authorizationToken: Data(repeating: 0x00, count: 32), +// authorizationServiceIndex: 0, +// authorizationCodeHash: Data32(), +// parameterizationBlob: Data(), +// context: RefinementContext.dummy(config: services.config), +// workItems: try! ConfigLimitedSizeArray(config: services.config, defaultValue: WorkItem.dummy(config: services.config)) +// ) +// await services.eventBus +// .publish(RuntimeEvents.WorkPackagesReceived(coreIndex: 0, workPackage: workpackage.asRef(), extrinsics: [])) +// } }