@@ -4,10 +4,7 @@ import TracingUtils
44import Utils
55
66public enum GuaranteeingServiceError : Error {
7- case invalidValidatorIndex
8- case customValidatorNotFound
97 case noAuthorizerHash
10- case invalidCoreIndex
118 case invalidExports
129}
1310
@@ -17,83 +14,106 @@ struct GuaranteeingRefineInvocation: RefineInvocation {}
1714public final class GuaranteeingService : ServiceBase2 , @unchecked Sendable {
1815 private let dataProvider : BlockchainDataProvider
1916 private let keystore : KeyStore
20- private let runtime : Runtime
21- private let safroleTicketPool : SafroleTicketPoolService
22- private let workPackagePool : WorkPackagePoolService
23- private let guarantees : ThreadSafeContainer < [ RuntimeEvents . GuaranteeGenerated ] > = . init( [ ] )
24- private let authorizationFunction : GuaranteeingAuthorizationFunction
2517 private let dataAvailability : DataAvailability
26- private let refineInvocation : GuaranteeingRefineInvocation
18+
19+ private let authorizationFunction : IsAuthorizedFunction
20+ private let refineInvocation : RefineInvocation
21+
22+ let signingKey : ThreadSafeContainer < ( ValidatorIndex , Ed25519 . SecretKey ) ? > = . init( nil )
2723
2824 public init (
2925 config: ProtocolConfigRef ,
3026 eventBus: EventBus ,
3127 scheduler: Scheduler ,
3228 dataProvider: BlockchainDataProvider ,
3329 keystore: KeyStore ,
34- runtime: Runtime ,
35- safroleTicketPool: SafroleTicketPoolService ,
3630 dataStore: DataStore
3731 ) async {
3832 self . dataProvider = dataProvider
3933 self . keystore = keystore
40- self . runtime = runtime
41- self . safroleTicketPool = safroleTicketPool
42- authorizationFunction = GuaranteeingAuthorizationFunction ( )
43- refineInvocation = GuaranteeingRefineInvocation ( )
44- workPackagePool = await WorkPackagePoolService ( config: config, dataProvider: dataProvider, eventBus: eventBus)
4534 dataAvailability = await DataAvailability (
4635 config: config,
4736 eventBus: eventBus,
4837 scheduler: scheduler,
4938 dataProvider: dataProvider,
5039 dataStore: dataStore
5140 )
41+
42+ authorizationFunction = GuaranteeingAuthorizationFunction ( )
43+ refineInvocation = GuaranteeingRefineInvocation ( )
44+
5245 super. init ( id: " GuaranteeingService " , config: config, eventBus: eventBus, scheduler: scheduler)
5346
54- await subscribe ( RuntimeEvents . GuaranteeGenerated . self, id: " GuaranteeingService.GuaranteeGenerated " ) { [ weak self] event in
55- try await self ? . onGuaranteeGenerated ( event : event)
47+ await subscribe ( RuntimeEvents . WorkPackagesReceived . self, id: " GuaranteeingService.WorkPackagesReceived " ) { [ weak self] event in
48+ try await self ? . on ( workPackagesReceived : event)
5649 }
5750 }
5851
59- public func on( genesis _: StateRef ) async {
60- await onGuaranteeing ( )
52+ public func onSyncCompleted( ) async {
53+ let nowTimeslot = timeProvider. getTime ( ) . timeToTimeslot ( config: config)
54+ let epoch = nowTimeslot. timeslotToEpochIndex ( config: config)
55+ await onBeforeEpoch ( epoch: epoch)
56+
57+ scheduleForNextEpoch ( " GuaranteeingService.scheduleForNextEpoch " ) { [ weak self] epoch in
58+ await self ? . onBeforeEpoch ( epoch: epoch)
59+ }
6160 }
6261
63- public func scheduleGuaranteeTasks( ) async throws {
64- let state = try await dataProvider. getState ( hash: dataProvider. bestHead. hash)
65- let header = try await dataProvider. getHeader ( hash: dataProvider. bestHead. hash)
66- let authorIndex = header. value. authorIndex
67- let authorKey = try Ed25519 . PublicKey ( from: state. value. currentValidators [ Int ( authorIndex) ] . ed25519)
68- let key = await keystore. get ( Ed25519 . self, publicKey: authorKey)
69- if key == nil {
70- throw GuaranteeingServiceError . customValidatorNotFound
62+ private func onBeforeEpoch( epoch: EpochIndex ) async {
63+ await withSpan ( " GuaranteeingService.onBeforeEpoch " , logger: logger) { _ in
64+ let state = try await dataProvider. getState ( hash: dataProvider. bestHead. hash)
65+ let timeslot = epoch. epochToTimeslotIndex ( config: config)
66+ // simulate next block to determine the correct current validators
67+ // this is more accurate than just using nextValidators from current state
68+ let res = try state. value. updateSafrole (
69+ config: config,
70+ slot: timeslot,
71+ entropy: Data32 ( ) ,
72+ offenders: [ ] ,
73+ extrinsics: . dummy( config: config)
74+ )
75+ let validators = res. state. currentValidators
76+
77+ let keys = await keystore. getAll ( Ed25519 . self)
78+ var result : ( ValidatorIndex , Ed25519 . SecretKey ) ?
79+ for key in keys {
80+ if let idx = validators. array. firstIndex ( where: { $0. ed25519 == key. publicKey. data } ) {
81+ result = ( ValidatorIndex ( idx) , key)
82+ break
83+ }
84+ }
85+
86+ signingKey. value = result
87+ }
88+ }
89+
90+ private func on( workPackagesReceived event: RuntimeEvents . WorkPackagesReceived ) async throws {
91+ try await refine ( package : event. item)
92+ }
93+
94+ private func refine( package : WorkPackageRef ) async throws {
95+ guard let ( validatorIndex, signingKey) = signingKey. value else {
96+ logger. debug ( " not in current validator set, skipping refine " )
97+ return
7198 }
99+
100+ let state = try await dataProvider. getState ( hash: dataProvider. bestHead. hash)
101+
102+ // TODO: check for edge cases such as epoch end
72103 let currentCoreAssignment = state. value. getCoreAssignment (
73104 config: config,
74105 randomness: state. value. entropyPool. t2,
75- timeslot: state. value. timeslot
106+ timeslot: state. value. timeslot + 1
76107 )
77- guard authorIndex < ValidatorIndex ( currentCoreAssignment. count) else {
78- logger. error ( " AuthorIndex not found " )
79- throw GuaranteeingServiceError . invalidValidatorIndex
80- }
81- let coreIndex = currentCoreAssignment [ Int ( authorIndex) ]
82- guard coreIndex < CoreIndex ( config. value. totalNumberOfCores) else {
83- throw GuaranteeingServiceError . invalidCoreIndex
108+ guard let coreIndex = currentCoreAssignment [ safe: Int ( validatorIndex) ] else {
109+ try throwUnreachable ( " invalid validator index/core assignment " )
84110 }
85111
86- let workPackages = await workPackagePool. getPendingPackages ( )
87- for workPackage in workPackages {
88- if try validate ( workPackage: workPackage) {
89- let workReport = try await createWorkReport ( for: workPackage, coreIndex: coreIndex)
90- let event = RuntimeEvents . WorkReportGenerated ( items: [ workReport] )
91- publish ( event)
92- break
93- } else {
94- logger. error ( " WorkPackage validation failed " )
95- }
96- }
112+ let workReport = try await createWorkReport ( for: package , coreIndex: coreIndex)
113+ let payload = SigningContext . guarantee + workReport. hash ( ) . data
114+ let signature = try signingKey. sign ( message: payload)
115+ let event = RuntimeEvents . WorkReportGenerated ( item: workReport, signature: signature)
116+ publish ( event)
97117 }
98118
99119 // workpackage -> workresult -> workreport
@@ -122,9 +142,6 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable {
122142 }
123143
124144 for (i, item) in workPackage. value. workItems. enumerated ( ) {
125- // TODO: generated by the work-package builder.
126- let extrinsicDataBlobs = [ Data] ( )
127-
128145 // RefineInvocation invoke up data to workresult
129146 let refineRes = try await refineInvocation
130147 . invoke (
@@ -191,19 +208,4 @@ public final class GuaranteeingService: ServiceBase2, @unchecked Sendable {
191208 throw error
192209 }
193210 }
194-
195- private func validate( workPackage _: WorkPackageRef ) throws -> Bool {
196- // TODO: Add validate func
197- true
198- }
199-
200- private func onGuaranteeing( ) async {
201- await withSpan ( " GuaranteeingService.onGuaranteeing " , logger: logger) { _ in
202- try await scheduleGuaranteeTasks ( )
203- }
204- }
205-
206- private func onGuaranteeGenerated( event: RuntimeEvents . GuaranteeGenerated ) async throws {
207- guarantees. write { $0. append ( event) }
208- }
209211}
0 commit comments