github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/engine/collection/epochmgr/factories/hotstuff.go (about) 1 package factories 2 3 import ( 4 "fmt" 5 6 "github.com/dgraph-io/badger/v2" 7 "github.com/rs/zerolog" 8 9 "github.com/onflow/flow-go/consensus" 10 "github.com/onflow/flow-go/consensus/hotstuff" 11 "github.com/onflow/flow-go/consensus/hotstuff/blockproducer" 12 "github.com/onflow/flow-go/consensus/hotstuff/committees" 13 "github.com/onflow/flow-go/consensus/hotstuff/notifications" 14 "github.com/onflow/flow-go/consensus/hotstuff/notifications/pubsub" 15 "github.com/onflow/flow-go/consensus/hotstuff/persister" 16 "github.com/onflow/flow-go/consensus/hotstuff/timeoutcollector" 17 validatorImpl "github.com/onflow/flow-go/consensus/hotstuff/validator" 18 "github.com/onflow/flow-go/consensus/hotstuff/verification" 19 "github.com/onflow/flow-go/consensus/hotstuff/votecollector" 20 recovery "github.com/onflow/flow-go/consensus/recovery/cluster" 21 "github.com/onflow/flow-go/model/flow" 22 "github.com/onflow/flow-go/module" 23 hotmetrics "github.com/onflow/flow-go/module/metrics/hotstuff" 24 msig "github.com/onflow/flow-go/module/signature" 25 "github.com/onflow/flow-go/state/cluster" 26 "github.com/onflow/flow-go/state/protocol" 27 "github.com/onflow/flow-go/storage" 28 ) 29 30 type HotStuffMetricsFunc func(chainID flow.ChainID) module.HotstuffMetrics 31 32 type HotStuffFactory struct { 33 baseLogger zerolog.Logger 34 me module.Local 35 db *badger.DB 36 protoState protocol.State 37 engineMetrics module.EngineMetrics 38 mempoolMetrics module.MempoolMetrics 39 createMetrics HotStuffMetricsFunc 40 opts []consensus.Option 41 } 42 43 func NewHotStuffFactory( 44 log zerolog.Logger, 45 me module.Local, 46 db *badger.DB, 47 protoState protocol.State, 48 engineMetrics module.EngineMetrics, 49 mempoolMetrics module.MempoolMetrics, 50 createMetrics HotStuffMetricsFunc, 51 opts ...consensus.Option, 52 ) (*HotStuffFactory, error) { 53 54 factory := &HotStuffFactory{ 55 baseLogger: log, 56 me: me, 57 db: db, 58 protoState: protoState, 59 engineMetrics: engineMetrics, 60 mempoolMetrics: mempoolMetrics, 61 createMetrics: createMetrics, 62 opts: opts, 63 } 64 return factory, nil 65 } 66 67 func (f *HotStuffFactory) CreateModules( 68 epoch protocol.Epoch, 69 cluster protocol.Cluster, 70 clusterState cluster.State, 71 headers storage.Headers, 72 payloads storage.ClusterPayloads, 73 updater module.Finalizer, 74 ) (*consensus.HotstuffModules, module.HotstuffMetrics, error) { 75 // setup metrics/logging with the new chain ID 76 log := f.createLogger(cluster) 77 metrics := f.createMetrics(cluster.ChainID()) 78 telemetryConsumer := notifications.NewTelemetryConsumer(log) 79 slashingConsumer := notifications.NewSlashingViolationsConsumer(log) 80 notifier := pubsub.NewDistributor() 81 notifier.AddConsumer(notifications.NewLogConsumer(log)) 82 notifier.AddConsumer(hotmetrics.NewMetricsConsumer(metrics)) 83 notifier.AddParticipantConsumer(telemetryConsumer) 84 notifier.AddProposalViolationConsumer(slashingConsumer) 85 86 var ( 87 err error 88 committee hotstuff.DynamicCommittee 89 ) 90 committee, err = committees.NewClusterCommittee(f.protoState, payloads, cluster, epoch, f.me.NodeID()) 91 if err != nil { 92 return nil, nil, fmt.Errorf("could not create cluster committee: %w", err) 93 } 94 committee = committees.NewMetricsWrapper(committee, metrics) // wrapper for measuring time spent determining consensus committee relations 95 96 // create a signing provider 97 var signer hotstuff.Signer = verification.NewStakingSigner(f.me) 98 signer = verification.NewMetricsWrapper(signer, metrics) // wrapper for measuring time spent with crypto-related operations 99 100 finalizedBlock, err := clusterState.Final().Head() 101 if err != nil { 102 return nil, nil, fmt.Errorf("could not get cluster finalized block: %w", err) 103 } 104 105 forks, err := consensus.NewForks( 106 finalizedBlock, 107 headers, 108 updater, 109 notifier, 110 cluster.RootBlock().Header, 111 cluster.RootQC(), 112 ) 113 if err != nil { 114 return nil, nil, err 115 } 116 117 voteAggregationDistributor := pubsub.NewVoteAggregationDistributor() 118 voteAggregationDistributor.AddVoteCollectorConsumer(telemetryConsumer) 119 voteAggregationDistributor.AddVoteAggregationViolationConsumer(slashingConsumer) 120 121 verifier := verification.NewStakingVerifier() 122 validator := validatorImpl.NewMetricsWrapper(validatorImpl.New(committee, verifier), metrics) 123 voteProcessorFactory := votecollector.NewStakingVoteProcessorFactory(committee, voteAggregationDistributor.OnQcConstructedFromVotes) 124 voteAggregator, err := consensus.NewVoteAggregator( 125 log, 126 metrics, 127 f.engineMetrics, 128 f.mempoolMetrics, 129 // since we don't want to aggregate votes for finalized view, 130 // the lowest retained view starts with the next view of the last finalized view. 131 finalizedBlock.View+1, 132 voteAggregationDistributor, 133 voteProcessorFactory, 134 notifier.FollowerDistributor, 135 ) 136 if err != nil { 137 return nil, nil, err 138 } 139 140 timeoutCollectorDistributor := pubsub.NewTimeoutAggregationDistributor() 141 timeoutCollectorDistributor.AddTimeoutCollectorConsumer(telemetryConsumer) 142 timeoutCollectorDistributor.AddTimeoutAggregationViolationConsumer(slashingConsumer) 143 144 timeoutProcessorFactory := timeoutcollector.NewTimeoutProcessorFactory(log, timeoutCollectorDistributor, committee, validator, msig.CollectorTimeoutTag) 145 timeoutAggregator, err := consensus.NewTimeoutAggregator( 146 log, 147 metrics, 148 f.engineMetrics, 149 f.mempoolMetrics, 150 notifier, 151 timeoutProcessorFactory, 152 timeoutCollectorDistributor, 153 finalizedBlock.View+1, 154 ) 155 if err != nil { 156 return nil, nil, err 157 } 158 159 return &consensus.HotstuffModules{ 160 Forks: forks, 161 Validator: validator, 162 Notifier: notifier, 163 Committee: committee, 164 Signer: signer, 165 Persist: persister.New(f.db, cluster.ChainID()), 166 VoteAggregator: voteAggregator, 167 TimeoutAggregator: timeoutAggregator, 168 VoteCollectorDistributor: voteAggregationDistributor.VoteCollectorDistributor, 169 TimeoutCollectorDistributor: timeoutCollectorDistributor.TimeoutCollectorDistributor, 170 }, metrics, nil 171 } 172 173 func (f *HotStuffFactory) Create( 174 cluster protocol.Cluster, 175 clusterState cluster.State, 176 metrics module.HotstuffMetrics, 177 builder module.Builder, 178 headers storage.Headers, 179 hotstuffModules *consensus.HotstuffModules, 180 ) (module.HotStuff, error) { 181 182 // setup metrics/logging with the new chain ID 183 builder = blockproducer.NewMetricsWrapper(builder, metrics) // wrapper for measuring time spent building block payload component 184 185 finalizedBlock, pendingBlocks, err := recovery.FindLatest(clusterState, headers) 186 if err != nil { 187 return nil, err 188 } 189 190 log := f.createLogger(cluster) 191 participant, err := consensus.NewParticipant( 192 log, 193 metrics, 194 f.mempoolMetrics, 195 builder, 196 finalizedBlock, 197 pendingBlocks, 198 hotstuffModules, 199 f.opts..., 200 ) 201 return participant, err 202 } 203 204 // createLogger creates a logger by wrapping base logger by decorating it will cluster ID 205 func (f *HotStuffFactory) createLogger(cluster protocol.Cluster) zerolog.Logger { 206 return f.baseLogger.With().Str("chain", cluster.ChainID().String()).Logger() 207 }