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 }