github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/consensus/participant.go (about) 1 package consensus 2 3 import ( 4 "fmt" 5 6 "github.com/rs/zerolog" 7 8 "github.com/onflow/flow-go/consensus/hotstuff" 9 "github.com/onflow/flow-go/consensus/hotstuff/blockproducer" 10 "github.com/onflow/flow-go/consensus/hotstuff/eventhandler" 11 "github.com/onflow/flow-go/consensus/hotstuff/eventloop" 12 "github.com/onflow/flow-go/consensus/hotstuff/forks" 13 "github.com/onflow/flow-go/consensus/hotstuff/model" 14 "github.com/onflow/flow-go/consensus/hotstuff/pacemaker" 15 "github.com/onflow/flow-go/consensus/hotstuff/pacemaker/timeout" 16 "github.com/onflow/flow-go/consensus/hotstuff/safetyrules" 17 "github.com/onflow/flow-go/consensus/hotstuff/signature" 18 validatorImpl "github.com/onflow/flow-go/consensus/hotstuff/validator" 19 "github.com/onflow/flow-go/consensus/hotstuff/verification" 20 "github.com/onflow/flow-go/consensus/recovery" 21 "github.com/onflow/flow-go/model/flow" 22 "github.com/onflow/flow-go/module" 23 "github.com/onflow/flow-go/storage" 24 ) 25 26 // NewParticipant initialize the EventLoop instance with needed dependencies 27 func NewParticipant( 28 log zerolog.Logger, 29 metrics module.HotstuffMetrics, 30 mempoolMetrics module.MempoolMetrics, 31 builder module.Builder, 32 finalized *flow.Header, 33 pending []*flow.Header, 34 modules *HotstuffModules, 35 options ...Option, 36 ) (*eventloop.EventLoop, error) { 37 38 // initialize the default configuration and apply the configuration options 39 cfg := DefaultParticipantConfig() 40 for _, option := range options { 41 option(&cfg) 42 } 43 44 // prune vote aggregator to initial view 45 modules.VoteAggregator.PruneUpToView(finalized.View) 46 modules.TimeoutAggregator.PruneUpToView(finalized.View) 47 48 // recover HotStuff state from all pending blocks 49 qcCollector := recovery.NewCollector[*flow.QuorumCertificate]() 50 tcCollector := recovery.NewCollector[*flow.TimeoutCertificate]() 51 err := recovery.Recover(log, pending, 52 recovery.ForksState(modules.Forks), // add pending blocks to Forks 53 recovery.VoteAggregatorState(modules.VoteAggregator), // accept votes for all pending blocks 54 recovery.CollectParentQCs(qcCollector), // collect QCs from all pending block to initialize PaceMaker (below) 55 recovery.CollectTCs(tcCollector), // collect TCs from all pending block to initialize PaceMaker (below) 56 ) 57 if err != nil { 58 return nil, fmt.Errorf("failed to scan tree of pending blocks: %w", err) 59 } 60 61 // initialize dynamically updatable timeout config 62 timeoutConfig, err := timeout.NewConfig(cfg.TimeoutMinimum, cfg.TimeoutMaximum, cfg.TimeoutAdjustmentFactor, cfg.HappyPathMaxRoundFailures, cfg.MaxTimeoutObjectRebroadcastInterval) 63 if err != nil { 64 return nil, fmt.Errorf("could not initialize timeout config: %w", err) 65 } 66 67 // initialize the pacemaker 68 controller := timeout.NewController(timeoutConfig) 69 pacemaker, err := pacemaker.New(controller, cfg.ProposalDurationProvider, modules.Notifier, modules.Persist, 70 pacemaker.WithQCs(qcCollector.Retrieve()...), 71 pacemaker.WithTCs(tcCollector.Retrieve()...), 72 ) 73 if err != nil { 74 return nil, fmt.Errorf("could not initialize flow pacemaker: %w", err) 75 } 76 77 // initialize block producer 78 producer, err := blockproducer.New(modules.Signer, modules.Committee, builder) 79 if err != nil { 80 return nil, fmt.Errorf("could not initialize block producer: %w", err) 81 } 82 83 // initialize the safetyRules 84 safetyRules, err := safetyrules.New(modules.Signer, modules.Persist, modules.Committee) 85 if err != nil { 86 return nil, fmt.Errorf("could not initialize safety rules: %w", err) 87 } 88 89 // initialize the event handler 90 eventHandler, err := eventhandler.NewEventHandler( 91 log, 92 pacemaker, 93 producer, 94 modules.Forks, 95 modules.Persist, 96 modules.Committee, 97 safetyRules, 98 modules.Notifier, 99 ) 100 if err != nil { 101 return nil, fmt.Errorf("could not initialize event handler: %w", err) 102 } 103 104 // initialize and return the event loop 105 loop, err := eventloop.NewEventLoop(log, metrics, mempoolMetrics, eventHandler, cfg.StartupTime) 106 if err != nil { 107 return nil, fmt.Errorf("could not initialize event loop: %w", err) 108 } 109 110 // add observer, event loop needs to receive events from distributor 111 modules.VoteCollectorDistributor.AddVoteCollectorConsumer(loop) 112 modules.TimeoutCollectorDistributor.AddTimeoutCollectorConsumer(loop) 113 114 return loop, nil 115 } 116 117 // NewValidator creates new instance of hotstuff validator needed for votes & proposal validation 118 func NewValidator(metrics module.HotstuffMetrics, committee hotstuff.DynamicCommittee) hotstuff.Validator { 119 packer := signature.NewConsensusSigDataPacker(committee) 120 verifier := verification.NewCombinedVerifier(committee, packer) 121 122 // initialize the Validator 123 validator := validatorImpl.New(committee, verifier) 124 return validatorImpl.NewMetricsWrapper(validator, metrics) // wrapper for measuring time spent in Validator component 125 } 126 127 // NewForks recovers trusted root and creates new forks manager 128 func NewForks(final *flow.Header, headers storage.Headers, updater module.Finalizer, notifier hotstuff.FollowerConsumer, rootHeader *flow.Header, rootQC *flow.QuorumCertificate) (*forks.Forks, error) { 129 // recover the trusted root 130 trustedRoot, err := recoverTrustedRoot(final, headers, rootHeader, rootQC) 131 if err != nil { 132 return nil, fmt.Errorf("could not recover trusted root: %w", err) 133 } 134 135 // initialize the forks 136 forks, err := forks.New(trustedRoot, updater, notifier) 137 if err != nil { 138 return nil, fmt.Errorf("could not initialize forks: %w", err) 139 } 140 141 return forks, nil 142 } 143 144 // recoverTrustedRoot based on our local state returns root block and QC that can be used to initialize base state 145 func recoverTrustedRoot(final *flow.Header, headers storage.Headers, rootHeader *flow.Header, rootQC *flow.QuorumCertificate) (*model.CertifiedBlock, error) { 146 if final.View < rootHeader.View { 147 return nil, fmt.Errorf("finalized Block has older view than trusted root") 148 } 149 150 // if finalized view is genesis block, then use genesis block as the trustedRoot 151 if final.View == rootHeader.View { 152 if final.ID() != rootHeader.ID() { 153 return nil, fmt.Errorf("finalized Block conflicts with trusted root") 154 } 155 certifiedRoot, err := makeCertifiedRootBlock(rootHeader, rootQC) 156 if err != nil { 157 return nil, fmt.Errorf("constructing certified root block failed: %w", err) 158 } 159 return &certifiedRoot, nil 160 } 161 162 // find a valid child of the finalized block in order to get its QC 163 children, err := headers.ByParentID(final.ID()) 164 if err != nil { 165 // a finalized block must have a valid child, if err happens, we exit 166 return nil, fmt.Errorf("could not get children for finalized block (ID: %v, view: %v): %w", final.ID(), final.View, err) 167 } 168 if len(children) == 0 { 169 return nil, fmt.Errorf("finalized block has no children") 170 } 171 172 child := model.BlockFromFlow(children[0]) 173 174 // create the root block to use 175 trustedRoot, err := model.NewCertifiedBlock(model.BlockFromFlow(final), child.QC) 176 if err != nil { 177 return nil, fmt.Errorf("constructing certified root block failed: %w", err) 178 } 179 return &trustedRoot, nil 180 } 181 182 func makeCertifiedRootBlock(header *flow.Header, qc *flow.QuorumCertificate) (model.CertifiedBlock, error) { 183 // By convention of Forks, the trusted root block does not need to have a qc 184 // (as is the case for the genesis block). For simplify of the implementation, we always omit 185 // the QC of the root block. Thereby, we have one algorithm which handles all cases, 186 // instead of having to distinguish between a genesis block without a qc 187 // and a later-finalized root block where we can retrieve the qc. 188 rootBlock := &model.Block{ 189 View: header.View, 190 BlockID: header.ID(), 191 ProposerID: header.ProposerID, 192 QC: nil, // QC is omitted 193 PayloadHash: header.PayloadHash, 194 Timestamp: header.Timestamp, 195 } 196 return model.NewCertifiedBlock(rootBlock, qc) 197 }