github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/consensus/hotstuff/pacemaker.go (about)

     1  package hotstuff
     2  
     3  import (
     4  	"context"
     5  	"time"
     6  
     7  	"github.com/onflow/flow-go/consensus/hotstuff/model"
     8  	"github.com/onflow/flow-go/model/flow"
     9  )
    10  
    11  type LivenessData struct {
    12  	// CurrentView is the currently active view tracked by the PaceMaker. It is updated
    13  	// whenever the PaceMaker sees evidence (QC or TC) for advancing to next view.
    14  	CurrentView uint64
    15  	// NewestQC is the newest QC (by view) observed by the PaceMaker. The QC can be observed on its own or as a part of TC.
    16  	NewestQC *flow.QuorumCertificate
    17  	// LastViewTC is the TC for the prior view (CurrentView-1), if this view timed out. If the previous round
    18  	// ended with a QC, this QC is stored in NewestQC and LastViewTC is nil.
    19  	LastViewTC *flow.TimeoutCertificate
    20  }
    21  
    22  // PaceMaker for HotStuff. The component is passive in that it only reacts to method calls.
    23  // The PaceMaker does not perform state transitions on its own. Timeouts are emitted through
    24  // channels. Each timeout has its own dedicated channel, which is garbage collected after the
    25  // respective state has been passed. It is the EventHandler's responsibility to pick up
    26  // timeouts from the currently active TimeoutChannel process them first and subsequently inform the
    27  // PaceMaker about processing the timeout. Specifically, the intended usage pattern for the
    28  // TimeoutChannels is as follows:
    29  //
    30  // • Each time the PaceMaker starts a new timeout, it created a new TimeoutChannel
    31  //
    32  // • The channel for the CURRENTLY ACTIVE timeout is returned by PaceMaker.TimeoutChannel()
    33  //
    34  //   - Each time the EventHandler processes an event, the EventHandler might call into PaceMaker
    35  //     potentially resulting in a state transition and the PaceMaker starting a new timeout
    36  //
    37  //   - Hence, after processing any event, EventHandler should retrieve the current TimeoutChannel
    38  //     from the PaceMaker.
    39  //
    40  // For Example:
    41  //
    42  //	for {
    43  //		timeoutChannel := el.eventHandler.TimeoutChannel()
    44  //		select {
    45  //		   case <-timeoutChannel:
    46  //		    	el.eventHandler.OnLocalTimeout()
    47  //		   case <other events>
    48  //		}
    49  //	}
    50  //
    51  // Not concurrency safe.
    52  type PaceMaker interface {
    53  	ProposalDurationProvider
    54  
    55  	// CurView returns the current view.
    56  	CurView() uint64
    57  
    58  	// NewestQC returns QC with the highest view discovered by PaceMaker.
    59  	NewestQC() *flow.QuorumCertificate
    60  
    61  	// LastViewTC returns TC for last view, this could be nil if previous round
    62  	// has entered with a QC.
    63  	LastViewTC() *flow.TimeoutCertificate
    64  
    65  	// ProcessQC will check if the given QC will allow PaceMaker to fast-forward to QC.view+1.
    66  	// If PaceMaker incremented the current View, a NewViewEvent will be returned.
    67  	// No errors are expected during normal operation.
    68  	ProcessQC(qc *flow.QuorumCertificate) (*model.NewViewEvent, error)
    69  
    70  	// ProcessTC will check if the given TC will allow PaceMaker to fast-forward to TC.view+1.
    71  	// If PaceMaker incremented the current View, a NewViewEvent will be returned.
    72  	// A nil TC is an expected valid input.
    73  	// No errors are expected during normal operation.
    74  	ProcessTC(tc *flow.TimeoutCertificate) (*model.NewViewEvent, error)
    75  
    76  	// TimeoutChannel returns the timeout channel for the CURRENTLY ACTIVE timeout.
    77  	// Each time the pacemaker starts a new timeout, this channel is replaced.
    78  	TimeoutChannel() <-chan time.Time
    79  
    80  	// Start starts the PaceMaker (i.e. the timeout for the configured starting value for view).
    81  	// CAUTION: EventHandler is not concurrency safe. The Start method must
    82  	// be executed by the same goroutine that also calls the other business logic
    83  	// methods, or concurrency safety has to be implemented externally.
    84  	Start(ctx context.Context)
    85  }
    86  
    87  // ProposalDurationProvider generates the target publication time for block proposals.
    88  type ProposalDurationProvider interface {
    89  
    90  	// TargetPublicationTime is intended to be called by the EventHandler, whenever it
    91  	// wants to publish a new proposal. The event handler inputs
    92  	//  - proposalView: the view it is proposing for,
    93  	//  - timeViewEntered: the time when the EventHandler entered this view
    94  	//  - parentBlockId: the ID of the parent block, which the EventHandler is building on
    95  	// TargetPublicationTime returns the time stamp when the new proposal should be broadcasted.
    96  	// For a given view where we are the primary, suppose the actual time we are done building our proposal is P:
    97  	//   - if P < TargetPublicationTime(..), then the EventHandler should wait until
    98  	//     `TargetPublicationTime` to broadcast the proposal
    99  	//   - if P >= TargetPublicationTime(..), then the EventHandler should immediately broadcast the proposal
   100  	//
   101  	// Note: Technically, our metrics capture the publication delay relative to this function's _latest_ call.
   102  	// Currently, the EventHandler is the only caller of this function, and only calls it once.
   103  	//
   104  	// Concurrency safe.
   105  	TargetPublicationTime(proposalView uint64, timeViewEntered time.Time, parentBlockId flow.Identifier) time.Time
   106  }