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) {}