github.com/koko1123/flow-go-1@v0.29.6/consensus/participant.go (about) 1 package consensus 2 3 import ( 4 "fmt" 5 6 "github.com/rs/zerolog" 7 8 "github.com/koko1123/flow-go-1/consensus/hotstuff" 9 "github.com/koko1123/flow-go-1/consensus/hotstuff/blockproducer" 10 "github.com/koko1123/flow-go-1/consensus/hotstuff/eventhandler" 11 "github.com/koko1123/flow-go-1/consensus/hotstuff/eventloop" 12 "github.com/koko1123/flow-go-1/consensus/hotstuff/forks" 13 "github.com/koko1123/flow-go-1/consensus/hotstuff/forks/finalizer" 14 "github.com/koko1123/flow-go-1/consensus/hotstuff/forks/forkchoice" 15 "github.com/koko1123/flow-go-1/consensus/hotstuff/model" 16 "github.com/koko1123/flow-go-1/consensus/hotstuff/pacemaker" 17 "github.com/koko1123/flow-go-1/consensus/hotstuff/pacemaker/timeout" 18 "github.com/koko1123/flow-go-1/consensus/hotstuff/signature" 19 validatorImpl "github.com/koko1123/flow-go-1/consensus/hotstuff/validator" 20 "github.com/koko1123/flow-go-1/consensus/hotstuff/verification" 21 "github.com/koko1123/flow-go-1/consensus/hotstuff/voter" 22 "github.com/koko1123/flow-go-1/consensus/recovery" 23 "github.com/koko1123/flow-go-1/model/flow" 24 "github.com/koko1123/flow-go-1/module" 25 "github.com/koko1123/flow-go-1/storage" 26 ) 27 28 // NewParticipant initialize the EventLoop instance with needed dependencies 29 func NewParticipant( 30 log zerolog.Logger, 31 metrics module.HotstuffMetrics, 32 builder module.Builder, 33 communicator hotstuff.Communicator, 34 finalized *flow.Header, 35 pending []*flow.Header, 36 modules *HotstuffModules, 37 options ...Option, 38 ) (*eventloop.EventLoop, error) { 39 40 // initialize the default configuration 41 cfg := DefaultParticipantConfig() 42 43 // apply the configuration options 44 for _, option := range options { 45 option(&cfg) 46 } 47 48 // get the last view we started 49 started, err := modules.Persist.GetStarted() 50 if err != nil { 51 return nil, fmt.Errorf("could not recover last started: %w", err) 52 } 53 54 // get the last view we voted 55 voted, err := modules.Persist.GetVoted() 56 if err != nil { 57 return nil, fmt.Errorf("could not recover last voted: %w", err) 58 } 59 60 // prune vote aggregator to initial view 61 modules.Aggregator.PruneUpToView(finalized.View) 62 63 // recover the hotstuff state, mainly to recover all pending blocks in Forks 64 err = recovery.Participant(log, modules.Forks, modules.Aggregator, modules.Validator, finalized, pending) 65 if err != nil { 66 return nil, fmt.Errorf("could not recover hotstuff state: %w", err) 67 } 68 69 // initialize the timeout config 70 timeoutConfig, err := timeout.NewConfig( 71 cfg.TimeoutInitial, 72 cfg.TimeoutMinimum, 73 cfg.TimeoutAggregationFraction, 74 cfg.TimeoutIncreaseFactor, 75 cfg.TimeoutDecreaseFactor, 76 cfg.BlockRateDelay, 77 ) 78 if err != nil { 79 return nil, fmt.Errorf("could not initialize timeout config: %w", err) 80 } 81 82 // initialize the pacemaker 83 controller := timeout.NewController(timeoutConfig) 84 pacemaker, err := pacemaker.New(started+1, controller, modules.Notifier) 85 if err != nil { 86 return nil, fmt.Errorf("could not initialize flow pacemaker: %w", err) 87 } 88 89 // initialize block producer 90 producer, err := blockproducer.New(modules.Signer, modules.Committee, builder) 91 if err != nil { 92 return nil, fmt.Errorf("could not initialize block producer: %w", err) 93 } 94 95 // initialize the voter 96 voter := voter.New(modules.Signer, modules.Forks, modules.Persist, modules.Committee, voted) 97 98 // initialize the event handler 99 eventHandler, err := eventhandler.NewEventHandler( 100 log, 101 pacemaker, 102 producer, 103 modules.Forks, 104 modules.Persist, 105 communicator, 106 modules.Committee, 107 modules.Aggregator, 108 voter, 109 modules.Validator, 110 modules.Notifier, 111 ) 112 if err != nil { 113 return nil, fmt.Errorf("could not initialize event handler: %w", err) 114 } 115 116 // initialize and return the event loop 117 loop, err := eventloop.NewEventLoop(log, metrics, eventHandler, cfg.StartupTime) 118 if err != nil { 119 return nil, fmt.Errorf("could not initialize event loop: %w", err) 120 } 121 122 // add observer, event loop needs to receive events from distributor 123 modules.QCCreatedDistributor.AddConsumer(loop.SubmitTrustedQC) 124 125 // register dynamically updatable configs 126 if cfg.Registrar != nil { 127 err = cfg.Registrar.RegisterDurationConfig("hotstuff-block-rate-delay", timeoutConfig.GetBlockRateDelay, timeoutConfig.SetBlockRateDelay) 128 if err != nil { 129 return nil, fmt.Errorf("failed to register block rate delay config: %w", err) 130 } 131 } 132 133 return loop, nil 134 } 135 136 // NewForks creates new consensus forks manager 137 func NewForks(final *flow.Header, headers storage.Headers, updater module.Finalizer, notifier hotstuff.Consumer, rootHeader *flow.Header, rootQC *flow.QuorumCertificate) (hotstuff.Forks, error) { 138 finalizer, err := newFinalizer(final, headers, updater, notifier, rootHeader, rootQC) 139 if err != nil { 140 return nil, fmt.Errorf("could not initialize finalizer: %w", err) 141 } 142 143 // initialize the fork choice 144 forkchoice, err := forkchoice.NewNewestForkChoice(finalizer, notifier) 145 if err != nil { 146 return nil, fmt.Errorf("could not initialize fork choice: %w", err) 147 } 148 149 // initialize the Forks manager 150 return forks.New(finalizer, forkchoice), nil 151 } 152 153 // NewValidator creates new instance of hotstuff validator needed for votes & proposal validation 154 func NewValidator(metrics module.HotstuffMetrics, committee hotstuff.Committee, forks hotstuff.ForksReader) hotstuff.Validator { 155 packer := signature.NewConsensusSigDataPacker(committee) 156 verifier := verification.NewCombinedVerifier(committee, packer) 157 158 // initialize the Validator 159 validator := validatorImpl.New(committee, forks, verifier) 160 return validatorImpl.NewMetricsWrapper(validator, metrics) // wrapper for measuring time spent in Validator component 161 } 162 163 // newFinalizer recovers trusted root and creates new finalizer 164 func newFinalizer(final *flow.Header, headers storage.Headers, updater module.Finalizer, notifier hotstuff.FinalizationConsumer, rootHeader *flow.Header, rootQC *flow.QuorumCertificate) (*finalizer.Finalizer, error) { 165 // recover the trusted root 166 trustedRoot, err := recoverTrustedRoot(final, headers, rootHeader, rootQC) 167 if err != nil { 168 return nil, fmt.Errorf("could not recover trusted root: %w", err) 169 } 170 171 // initialize the finalizer 172 finalizer, err := finalizer.New(trustedRoot, updater, notifier) 173 if err != nil { 174 return nil, fmt.Errorf("could not initialize finalizer: %w", err) 175 } 176 177 return finalizer, nil 178 } 179 180 // recoverTrustedRoot based on our local state returns root block and QC that can be used to initialize base state 181 func recoverTrustedRoot(final *flow.Header, headers storage.Headers, rootHeader *flow.Header, rootQC *flow.QuorumCertificate) (*forks.BlockQC, error) { 182 if final.View < rootHeader.View { 183 return nil, fmt.Errorf("finalized Block has older view than trusted root") 184 } 185 186 // if finalized view is genesis block, then use genesis block as the trustedRoot 187 if final.View == rootHeader.View { 188 if final.ID() != rootHeader.ID() { 189 return nil, fmt.Errorf("finalized Block conflicts with trusted root") 190 } 191 return makeRootBlockQC(rootHeader, rootQC), nil 192 } 193 194 // get the parent for the latest finalized block 195 parent, err := headers.ByBlockID(final.ParentID) 196 if err != nil { 197 return nil, fmt.Errorf("could not get parent for finalized: %w", err) 198 } 199 200 // find a valid child of the finalized block in order to get its QC 201 children, err := headers.ByParentID(final.ID()) 202 if err != nil { 203 // a finalized block must have a valid child, if err happens, we exit 204 return nil, fmt.Errorf("could not get children for finalized block (ID: %v, view: %v): %w", final.ID(), final.View, err) 205 } 206 if len(children) == 0 { 207 return nil, fmt.Errorf("finalized block has no children") 208 } 209 210 child := model.BlockFromFlow(children[0], final.View) 211 212 // create the root block to use 213 trustedRoot := &forks.BlockQC{ 214 Block: model.BlockFromFlow(final, parent.View), 215 QC: child.QC, 216 } 217 218 return trustedRoot, nil 219 } 220 221 func makeRootBlockQC(header *flow.Header, qc *flow.QuorumCertificate) *forks.BlockQC { 222 // By convention of Forks, the trusted root block does not need to have a qc 223 // (as is the case for the genesis block). For simplify of the implementation, we always omit 224 // the QC of the root block. Thereby, we have one algorithm which handles all cases, 225 // instead of having to distinguish between a genesis block without a qc 226 // and a later-finalized root block where we can retrieve the qc. 227 rootBlock := &model.Block{ 228 View: header.View, 229 BlockID: header.ID(), 230 ProposerID: header.ProposerID, 231 QC: nil, // QC is omitted 232 PayloadHash: header.PayloadHash, 233 Timestamp: header.Timestamp, 234 } 235 return &forks.BlockQC{ 236 QC: qc, 237 Block: rootBlock, 238 } 239 }