@@ -58,21 +58,19 @@ public struct SingleAccumulationOutput {
5858
5959public protocol Accumulation : ServiceAccounts {
6060 var timeslot : TimeslotIndex { get }
61- var privilegedServices : PrivilegedServices { get }
61+ var privilegedServices : PrivilegedServices { get set }
6262 var validatorQueue : ConfigFixedSizeArray <
6363 ValidatorKey , ProtocolConfig . TotalNumberOfValidators
64- > { get }
64+ > { get set }
6565 var authorizationQueue : ConfigFixedSizeArray <
6666 ConfigFixedSizeArray <
6767 Data32 ,
6868 ProtocolConfig . MaxAuthorizationsQueueItems
6969 > ,
7070 ProtocolConfig . TotalNumberOfCores
71- > { get }
72- var accumlateFunction : AccumulateFunction { get }
73- var onTransferFunction : OnTransferFunction { get }
74- var accumulationQueue : StateKeys . AccumulationQueueKey . Value { get }
75- var accumulationHistory : StateKeys . AccumulationHistoryKey . Value { get }
71+ > { get set }
72+ var accumulationQueue : StateKeys . AccumulationQueueKey . Value { get set }
73+ var accumulationHistory : StateKeys . AccumulationHistoryKey . Value { get set }
7674}
7775
7876extension Accumulation {
@@ -105,7 +103,7 @@ extension Accumulation {
105103 }
106104 }
107105
108- let ( newState, transfers, commitment, gasUsed) = try await accumlateFunction . invoke (
106+ let ( newState, transfers, commitment, gasUsed) = try await accumulate (
109107 config: config,
110108 accounts: & self ,
111109 state: state,
@@ -269,30 +267,29 @@ extension Accumulation {
269267 }
270268 }
271269
272- // E: edit the accumulation queue, remove the dependencies of the items that are already accumulated
273- public func editAccumulatedItems ( items: inout [ AccumulationQueueItem ] , accumulatedPackages: Set < Data32 > ) {
274- for index in items. indices
275- where !accumulatedPackages . contains ( items [ index ] . workReport . packageSpecification . workPackageHash )
276- {
277- items [ index ] . dependencies. subtract ( accumulatedPackages)
270+ // E: edit the accumulation queue items when some work reports are accumulated
271+ private func editQueue ( items: inout [ AccumulationQueueItem ] , accumulatedPackages: Set < Data32 > ) {
272+ items = items. filter { !accumulatedPackages . contains ( $0 . workReport . packageSpecification . workPackageHash ) }
273+
274+ for i in items . indices {
275+ items [ i ] . dependencies. subtract ( accumulatedPackages)
278276 }
279277 }
280278
281- // Q: find the reports that have no dependencies
282- private func findNoDepsReports ( items: inout [ AccumulationQueueItem ] ) -> [ WorkReport ] {
279+ // Q: provides the sequence of work- reports which are accumulatable given queue items
280+ private func getAccumulatables ( items: inout [ AccumulationQueueItem ] ) -> [ WorkReport ] {
283281 let noDepsReports = items. filter ( \. dependencies. isEmpty) . map ( \. workReport)
284282 if noDepsReports. isEmpty {
285283 return [ ]
286284 } else {
287- editAccumulatedItems ( items: & items, accumulatedPackages: Set ( noDepsReports. map ( \. packageSpecification. workPackageHash) ) )
288- return noDepsReports + findNoDepsReports ( items: & items)
285+ editQueue ( items: & items, accumulatedPackages: Set ( noDepsReports. map ( \. packageSpecification. workPackageHash) ) )
286+ return noDepsReports + getAccumulatables ( items: & items)
289287 }
290288 }
291289
292290 // newly available work-reports, W, are partitioned into two sequences based on the condition of having zero prerequisite work-reports
293- public func partitionWorkReports(
294- availableReports: [ WorkReport ] ,
295- history: StateKeys . AccumulationHistoryKey . Value
291+ private func partitionWorkReports(
292+ availableReports: [ WorkReport ]
296293 ) -> ( zeroPrereqReports: [ WorkReport ] , newQueueItems: [ AccumulationQueueItem ] ) {
297294 let zeroPrereqReports = availableReports. filter { report in
298295 report. refinementContext. prerequisiteWorkPackages. isEmpty && report. lookup. isEmpty
@@ -308,40 +305,42 @@ extension Accumulation {
308305 ) )
309306 }
310307
311- editAccumulatedItems (
308+ editQueue (
312309 items: & newQueueItems,
313- accumulatedPackages: Set ( history . array. reduce ( into: Set < Data32 > ( ) ) { $0. formUnion ( $1. array) } )
310+ accumulatedPackages: Set ( accumulationHistory . array. reduce ( into: Set < Data32 > ( ) ) { $0. formUnion ( $1. array) } )
314311 )
315312
316313 return ( zeroPrereqReports, newQueueItems)
317314 }
318315
319- public func getAccumulatableReports(
320- index: Int , availableReports: [ WorkReport ] ,
321- history: StateKeys . AccumulationHistoryKey . Value
316+ // get all the work reports that can be accumulated in this block
317+ private func getAllAccumulatableReports(
318+ availableReports: [ WorkReport ] ,
319+ index: Int
322320 ) -> ( accumulatableReports: [ WorkReport ] , newQueueItems: [ AccumulationQueueItem ] ) {
323- let ( zeroPrereqReports, newQueueItems) = partitionWorkReports ( availableReports: availableReports, history : history )
321+ let ( zeroPrereqReports, newQueueItems) = partitionWorkReports ( availableReports: availableReports)
324322
325323 let rightQueueItems = accumulationQueue. array [ index... ]
326324 let leftQueueItems = accumulationQueue. array [ 0 ..< index]
327325 var allQueueItems = rightQueueItems. flatMap ( \. self) + leftQueueItems. flatMap ( \. self) + newQueueItems
328326
329- editAccumulatedItems ( items: & allQueueItems, accumulatedPackages: Set ( zeroPrereqReports. map ( \. packageSpecification. workPackageHash) ) )
327+ editQueue ( items: & allQueueItems, accumulatedPackages: Set ( zeroPrereqReports. map ( \. packageSpecification. workPackageHash) ) )
330328
331- return ( zeroPrereqReports + findNoDepsReports ( items: & allQueueItems) , newQueueItems)
329+ return ( zeroPrereqReports + getAccumulatables ( items: & allQueueItems) , newQueueItems)
332330 }
333331
334- public mutating func update(
332+ // accumulate execution
333+ private mutating func execution(
335334 config: ProtocolConfigRef ,
336335 workReports: [ WorkReport ] ,
337336 entropy: Data32 ,
338337 timeslot: TimeslotIndex
339- ) async throws -> ( numAccumulated : Int , state : AccumulateState , commitments : Set < Commitment > ) {
338+ ) async throws -> AccumulationOutput {
340339 let sumPrevilegedGas = privilegedServices. basicGas. values. reduce ( Gas ( 0 ) ) { $0 + $1. value }
341340 let minTotalGas = config. value. workReportAccumulationGas * Gas( config. value. totalNumberOfCores) + sumPrevilegedGas
342341 let gasLimit = max ( config. value. totalAccumulationGas, minTotalGas)
343342
344- let res = try await outerAccumulate (
343+ return try await outerAccumulate (
345344 config: config,
346345 state: AccumulateState (
347346 newServiceAccounts: [ : ] ,
@@ -355,23 +354,93 @@ extension Accumulation {
355354 entropy: entropy,
356355 timeslot: timeslot
357356 )
357+ }
358358
359- var transferGroups = [ ServiceIndex: [ DeferredTransfers] ] ( )
359+ /// Accumulate execution, state integration and deferred transfers
360+ ///
361+ /// Return accumulation-result merkle tree root
362+ public mutating func update(
363+ config: ProtocolConfigRef ,
364+ availableReports: [ WorkReport ] ,
365+ timeslot: TimeslotIndex ,
366+ prevTimeslot: TimeslotIndex ,
367+ entropy: Data32
368+ ) async throws -> Data32 {
369+ let index = Int ( timeslot) %% config. value. epochLength
370+
371+ var ( accumulatableReports, newQueueItems) = getAllAccumulatableReports (
372+ availableReports: availableReports,
373+ index: index
374+ )
360375
361- for transfer in res. transfers {
362- transferGroups [ transfer. destination, default: [ ] ] . append ( transfer)
376+ let accumulateOutput = try await execution (
377+ config: config,
378+ workReports: accumulatableReports,
379+ entropy: entropy,
380+ timeslot: timeslot
381+ )
382+
383+ authorizationQueue = accumulateOutput. state. authorizationQueue
384+ validatorQueue = accumulateOutput. state. validatorQueue
385+ privilegedServices = accumulateOutput. state. privilegedServices
386+
387+ // add new service accounts
388+ for (service, account) in accumulateOutput. state. newServiceAccounts {
389+ set ( serviceAccount: service, account: account. toDetails ( ) )
390+ for (hash, value) in account. storage {
391+ set ( serviceAccount: service, storageKey: hash, value: value)
392+ }
393+ for (hash, value) in account. preimages {
394+ set ( serviceAccount: service, preimageHash: hash, value: value)
395+ }
396+ for (hashLength, value) in account. preimageInfos {
397+ set ( serviceAccount: service, preimageHash: hashLength. hash, length: hashLength. length, value: value)
398+ }
363399 }
364400
401+ // transfers
402+ var transferGroups = [ ServiceIndex: [ DeferredTransfers] ] ( )
403+ for transfer in accumulateOutput. transfers {
404+ transferGroups [ transfer. destination, default: [ ] ] . append ( transfer)
405+ }
365406 for (service, transfers) in transferGroups {
366- try await onTransferFunction . invoke (
407+ try await onTransfer (
367408 config: config,
368- service : service,
409+ serviceIndex : service,
369410 serviceAccounts: & self ,
370411 timeslot: timeslot,
371412 transfers: transfers
372413 )
373414 }
374415
375- return ( res. numAccumulated, res. state, res. commitments)
416+ // update accumulation history
417+ let accumulated = accumulatableReports [ 0 ..< accumulateOutput. numAccumulated]
418+ let newHistoryItem = Set ( accumulated. map ( \. packageSpecification. workPackageHash) )
419+ for i in 0 ..< config. value. epochLength {
420+ if i == config. value. epochLength - 1 {
421+ accumulationHistory [ i] = . init( newHistoryItem)
422+ } else {
423+ accumulationHistory [ i] = accumulationHistory [ i + 1 ]
424+ }
425+ }
426+
427+ // update accumulation queue
428+ for i in 0 ..< config. value. epochLength {
429+ let queueIdx = ( index - i) %% config. value. epochLength
430+ if i == 0 {
431+ editQueue ( items: & newQueueItems, accumulatedPackages: newHistoryItem)
432+ accumulationQueue [ queueIdx] = newQueueItems
433+ } else if i >= 1 , i < timeslot - prevTimeslot {
434+ accumulationQueue [ queueIdx] = [ ]
435+ } else {
436+ editQueue ( items: & accumulationQueue[ queueIdx] , accumulatedPackages: newHistoryItem)
437+ }
438+ }
439+
440+ // accumulate root
441+ let nodes = try accumulateOutput. commitments. map { try JamEncoder . encode ( $0. serviceIndex) + JamEncoder. encode ( $0. hash) }
442+ let root = Merklization . binaryMerklize ( nodes, hasher: Keccak . self)
443+
444+ return root
376445 }
377446}
0 commit comments