github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/module/events/finalization_actor.go (about) 1 package events 2 3 import ( 4 "github.com/onflow/flow-go/consensus/hotstuff" 5 "github.com/onflow/flow-go/consensus/hotstuff/model" 6 "github.com/onflow/flow-go/consensus/hotstuff/tracker" 7 "github.com/onflow/flow-go/engine" 8 "github.com/onflow/flow-go/module/component" 9 "github.com/onflow/flow-go/module/irrecoverable" 10 ) 11 12 // ProcessLatestFinalizedBlock is invoked when a new block is finalized. 13 // It is possible that blocks will be skipped. 14 type ProcessLatestFinalizedBlock func(block *model.Block) error 15 16 // FinalizationActor is an event responder worker which can be embedded in a component 17 // to simplify the plumbing required to respond to block finalization events. 18 // This worker is designed to respond to a newly finalized blocks on a best-effort basis, 19 // meaning that it may skip blocks when finalization occurs more quickly. 20 // CAUTION: This is suitable for use only when the handler can tolerate skipped blocks. 21 type FinalizationActor struct { 22 newestFinalized *tracker.NewestBlockTracker 23 notifier engine.Notifier 24 handler ProcessLatestFinalizedBlock 25 } 26 27 var _ hotstuff.FinalizationConsumer = (*FinalizationActor)(nil) 28 29 // NewFinalizationActor creates a new FinalizationActor, and returns the worker routine 30 // and event consumer required to operate it. 31 // The caller MUST: 32 // - start the returned component.ComponentWorker function 33 // - subscribe the returned FinalizationActor to ProcessLatestFinalizedBlock events 34 func NewFinalizationActor(handler ProcessLatestFinalizedBlock) (*FinalizationActor, component.ComponentWorker) { 35 actor := &FinalizationActor{ 36 newestFinalized: tracker.NewNewestBlockTracker(), 37 notifier: engine.NewNotifier(), 38 handler: handler, 39 } 40 return actor, actor.workerLogic 41 } 42 43 // workerLogic is the worker function exposed by the FinalizationActor. It should be 44 // attached to a ComponentBuilder by the higher-level component. 45 // It processes each new finalized block by invoking the ProcessLatestFinalizedBlock callback. 46 func (actor *FinalizationActor) workerLogic(ctx irrecoverable.SignalerContext, ready component.ReadyFunc) { 47 ready() 48 49 doneSignal := ctx.Done() 50 blockFinalizedSignal := actor.notifier.Channel() 51 52 for { 53 select { 54 case <-doneSignal: 55 return 56 case <-blockFinalizedSignal: 57 block := actor.newestFinalized.NewestBlock() 58 err := actor.handler(block) 59 if err != nil { 60 ctx.Throw(err) 61 return 62 } 63 } 64 } 65 } 66 67 // OnFinalizedBlock receives block finalization events. It updates the newest finalized 68 // block tracker and notifies the worker thread. 69 func (actor *FinalizationActor) OnFinalizedBlock(block *model.Block) { 70 if actor.newestFinalized.Track(block) { 71 actor.notifier.Notify() 72 } 73 } 74 75 func (actor *FinalizationActor) OnBlockIncorporated(*model.Block) {} 76 func (actor *FinalizationActor) OnDoubleProposeDetected(*model.Block, *model.Block) {}