github.com/koko1123/flow-go-1@v0.29.6/cmd/verification_builder.go (about) 1 package cmd 2 3 import ( 4 "fmt" 5 "time" 6 7 "github.com/spf13/pflag" 8 9 flowconsensus "github.com/koko1123/flow-go-1/consensus" 10 "github.com/koko1123/flow-go-1/consensus/hotstuff/committees" 11 "github.com/koko1123/flow-go-1/consensus/hotstuff/notifications/pubsub" 12 hotsignature "github.com/koko1123/flow-go-1/consensus/hotstuff/signature" 13 "github.com/koko1123/flow-go-1/consensus/hotstuff/verification" 14 recoveryprotocol "github.com/koko1123/flow-go-1/consensus/recovery/protocol" 15 "github.com/koko1123/flow-go-1/engine/common/follower" 16 commonsync "github.com/koko1123/flow-go-1/engine/common/synchronization" 17 "github.com/koko1123/flow-go-1/engine/verification/assigner" 18 "github.com/koko1123/flow-go-1/engine/verification/assigner/blockconsumer" 19 "github.com/koko1123/flow-go-1/engine/verification/fetcher" 20 "github.com/koko1123/flow-go-1/engine/verification/fetcher/chunkconsumer" 21 "github.com/koko1123/flow-go-1/engine/verification/requester" 22 "github.com/koko1123/flow-go-1/engine/verification/verifier" 23 "github.com/koko1123/flow-go-1/fvm" 24 "github.com/koko1123/flow-go-1/model/flow" 25 "github.com/koko1123/flow-go-1/module" 26 "github.com/koko1123/flow-go-1/module/buffer" 27 "github.com/koko1123/flow-go-1/module/chainsync" 28 "github.com/koko1123/flow-go-1/module/chunks" 29 "github.com/koko1123/flow-go-1/module/compliance" 30 finalizer "github.com/koko1123/flow-go-1/module/finalizer/consensus" 31 "github.com/koko1123/flow-go-1/module/mempool" 32 "github.com/koko1123/flow-go-1/module/mempool/stdmap" 33 "github.com/koko1123/flow-go-1/module/metrics" 34 "github.com/koko1123/flow-go-1/state/protocol" 35 badgerState "github.com/koko1123/flow-go-1/state/protocol/badger" 36 "github.com/koko1123/flow-go-1/state/protocol/blocktimer" 37 "github.com/koko1123/flow-go-1/storage/badger" 38 ) 39 40 type VerificationConfig struct { 41 chunkAlpha uint // number of verifiers assigned per chunk. 42 chunkLimit uint // size of chunk-related memory pools. 43 44 requestInterval time.Duration // time interval that requester engine tries requesting chunk data packs. 45 backoffMinInterval time.Duration // minimum time interval a chunk data pack request waits before dispatching. 46 backoffMaxInterval time.Duration // maximum time interval a chunk data pack request waits before dispatching. 47 backoffMultiplier float64 // base of exponent in exponential backoff multiplier for backing off requests for chunk data packs. 48 requestTargets uint64 // maximum number of execution nodes a chunk data pack request is dispatched to. 49 50 blockWorkers uint64 // number of blocks processed in parallel. 51 chunkWorkers uint64 // number of chunks processed in parallel. 52 53 stopAtHeight uint64 // height to stop the node on 54 } 55 56 type VerificationNodeBuilder struct { 57 *FlowNodeBuilder 58 verConf VerificationConfig 59 } 60 61 func NewVerificationNodeBuilder(nodeBuilder *FlowNodeBuilder) *VerificationNodeBuilder { 62 return &VerificationNodeBuilder{ 63 FlowNodeBuilder: nodeBuilder, 64 verConf: VerificationConfig{}, 65 } 66 } 67 68 func (v *VerificationNodeBuilder) LoadFlags() { 69 v.FlowNodeBuilder. 70 ExtraFlags(func(flags *pflag.FlagSet) { 71 flags.UintVar(&v.verConf.chunkLimit, "chunk-limit", 10000, "maximum number of chunk states in the memory pool") 72 flags.UintVar(&v.verConf.chunkAlpha, "chunk-alpha", flow.DefaultChunkAssignmentAlpha, "number of verifiers should be assigned to each chunk") 73 flags.DurationVar(&v.verConf.requestInterval, "chunk-request-interval", requester.DefaultRequestInterval, "time interval chunk data pack request is processed") 74 flags.DurationVar(&v.verConf.backoffMinInterval, "backoff-min-interval", requester.DefaultBackoffMinInterval, "min time interval a chunk data pack request waits before dispatching") 75 flags.DurationVar(&v.verConf.backoffMaxInterval, "backoff-max-interval", requester.DefaultBackoffMaxInterval, "min time interval a chunk data pack request waits before dispatching") 76 flags.Float64Var(&v.verConf.backoffMultiplier, "backoff-multiplier", requester.DefaultBackoffMultiplier, "base of exponent in exponential backoff requesting mechanism") 77 flags.Uint64Var(&v.verConf.requestTargets, "request-targets", requester.DefaultRequestTargets, "maximum number of execution nodes a chunk data pack request is dispatched to") 78 flags.Uint64Var(&v.verConf.blockWorkers, "block-workers", blockconsumer.DefaultBlockWorkers, "maximum number of blocks being processed in parallel") 79 flags.Uint64Var(&v.verConf.chunkWorkers, "chunk-workers", chunkconsumer.DefaultChunkWorkers, "maximum number of execution nodes a chunk data pack request is dispatched to") 80 flags.Uint64Var(&v.verConf.stopAtHeight, "stop-at-height", 0, "height to stop the node at (0 to disable)") 81 }) 82 } 83 84 func (v *VerificationNodeBuilder) LoadComponentsAndModules() { 85 var ( 86 followerState protocol.MutableState 87 88 chunkStatuses *stdmap.ChunkStatuses // used in fetcher engine 89 chunkRequests *stdmap.ChunkRequests // used in requester engine 90 processedChunkIndex *badger.ConsumerProgress // used in chunk consumer 91 processedBlockHeight *badger.ConsumerProgress // used in block consumer 92 chunkQueue *badger.ChunksQueue // used in chunk consumer 93 94 syncCore *chainsync.Core // used in follower engine 95 pendingBlocks *buffer.PendingBlocks // used in follower engine 96 assignerEngine *assigner.Engine // the assigner engine 97 fetcherEngine *fetcher.Engine // the fetcher engine 98 requesterEngine *requester.Engine // the requester engine 99 verifierEng *verifier.Engine // the verifier engine 100 chunkConsumer *chunkconsumer.ChunkConsumer 101 blockConsumer *blockconsumer.BlockConsumer 102 finalizationDistributor *pubsub.FinalizationDistributor 103 finalizedHeader *commonsync.FinalizedHeaderCache 104 105 followerEng *follower.Engine // the follower engine 106 collector module.VerificationMetrics // used to collect metrics of all engines 107 ) 108 109 v.FlowNodeBuilder. 110 PreInit(DynamicStartPreInit). 111 Module("mutable follower state", func(node *NodeConfig) error { 112 var err error 113 // For now, we only support state implementations from package badger. 114 // If we ever support different implementations, the following can be replaced by a type-aware factory 115 state, ok := node.State.(*badgerState.State) 116 if !ok { 117 return fmt.Errorf("only implementations of type badger.State are currently supported but read-only state has type %T", node.State) 118 } 119 followerState, err = badgerState.NewFollowerState( 120 state, 121 node.Storage.Index, 122 node.Storage.Payloads, 123 node.Tracer, 124 node.ProtocolEvents, 125 blocktimer.DefaultBlockTimer, 126 ) 127 return err 128 }). 129 Module("verification metrics", func(node *NodeConfig) error { 130 collector = metrics.NewVerificationCollector(node.Tracer, node.MetricsRegisterer) 131 return nil 132 }). 133 Module("chunk status memory pool", func(node *NodeConfig) error { 134 var err error 135 136 chunkStatuses = stdmap.NewChunkStatuses(v.verConf.chunkLimit) 137 err = node.Metrics.Mempool.Register(metrics.ResourceChunkStatus, chunkStatuses.Size) 138 if err != nil { 139 return fmt.Errorf("could not register backend metric: %w", err) 140 } 141 return nil 142 }). 143 Module("chunk requests memory pool", func(node *NodeConfig) error { 144 var err error 145 146 chunkRequests = stdmap.NewChunkRequests(v.verConf.chunkLimit) 147 err = node.Metrics.Mempool.Register(metrics.ResourceChunkRequest, chunkRequests.Size) 148 if err != nil { 149 return fmt.Errorf("could not register backend metric: %w", err) 150 } 151 return nil 152 }). 153 Module("processed chunk index consumer progress", func(node *NodeConfig) error { 154 processedChunkIndex = badger.NewConsumerProgress(node.DB, module.ConsumeProgressVerificationChunkIndex) 155 return nil 156 }). 157 Module("processed block height consumer progress", func(node *NodeConfig) error { 158 processedBlockHeight = badger.NewConsumerProgress(node.DB, module.ConsumeProgressVerificationBlockHeight) 159 return nil 160 }). 161 Module("chunks queue", func(node *NodeConfig) error { 162 chunkQueue = badger.NewChunkQueue(node.DB) 163 ok, err := chunkQueue.Init(chunkconsumer.DefaultJobIndex) 164 if err != nil { 165 return fmt.Errorf("could not initialize default index in chunks queue: %w", err) 166 } 167 168 node.Logger.Info(). 169 Str("component", "node-builder"). 170 Bool("init_to_default", ok). 171 Msg("chunks queue index has been initialized") 172 173 return nil 174 }). 175 Module("pending block cache", func(node *NodeConfig) error { 176 var err error 177 178 // consensus cache for follower engine 179 pendingBlocks = buffer.NewPendingBlocks() 180 181 // registers size method of backend for metrics 182 err = node.Metrics.Mempool.Register(metrics.ResourcePendingBlock, pendingBlocks.Size) 183 if err != nil { 184 return fmt.Errorf("could not register backend metric: %w", err) 185 } 186 187 return nil 188 }). 189 Module("sync core", func(node *NodeConfig) error { 190 var err error 191 192 syncCore, err = chainsync.New(node.Logger, node.SyncCoreConfig, metrics.NewChainSyncCollector()) 193 return err 194 }). 195 Component("verifier engine", func(node *NodeConfig) (module.ReadyDoneAware, error) { 196 var err error 197 198 vm := fvm.NewVirtualMachine() 199 fvmOptions := append( 200 []fvm.Option{fvm.WithLogger(node.Logger)}, 201 node.FvmOptions..., 202 ) 203 vmCtx := fvm.NewContext(fvmOptions...) 204 chunkVerifier := chunks.NewChunkVerifier(vm, vmCtx, node.Logger) 205 approvalStorage := badger.NewResultApprovals(node.Metrics.Cache, node.DB) 206 verifierEng, err = verifier.New( 207 node.Logger, 208 collector, 209 node.Tracer, 210 node.Network, 211 node.State, 212 node.Me, 213 chunkVerifier, 214 approvalStorage) 215 return verifierEng, err 216 }). 217 Component("chunk consumer, requester, and fetcher engines", func(node *NodeConfig) (module.ReadyDoneAware, error) { 218 var err error 219 220 requesterEngine, err = requester.New( 221 node.Logger, 222 node.State, 223 node.Network, 224 node.Tracer, 225 collector, 226 chunkRequests, 227 v.verConf.requestInterval, 228 requester.RetryAfterQualifier, 229 mempool.ExponentialUpdater( 230 v.verConf.backoffMultiplier, 231 v.verConf.backoffMaxInterval, 232 v.verConf.backoffMinInterval, 233 ), 234 v.verConf.requestTargets) 235 if err != nil { 236 return nil, fmt.Errorf("could not create requester engine: %w", err) 237 } 238 239 fetcherEngine = fetcher.New( 240 node.Logger, 241 collector, 242 node.Tracer, 243 verifierEng, 244 node.State, 245 chunkStatuses, 246 node.Storage.Headers, 247 node.Storage.Blocks, 248 node.Storage.Results, 249 node.Storage.Receipts, 250 requesterEngine, 251 v.verConf.stopAtHeight) 252 253 // requester and fetcher engines are started by chunk consumer 254 chunkConsumer = chunkconsumer.NewChunkConsumer( 255 node.Logger, 256 collector, 257 processedChunkIndex, 258 chunkQueue, 259 fetcherEngine, 260 v.verConf.chunkWorkers) 261 262 err = node.Metrics.Mempool.Register(metrics.ResourceChunkConsumer, chunkConsumer.Size) 263 if err != nil { 264 return nil, fmt.Errorf("could not register backend metric: %w", err) 265 } 266 267 return chunkConsumer, nil 268 }). 269 Component("assigner engine", func(node *NodeConfig) (module.ReadyDoneAware, error) { 270 var chunkAssigner module.ChunkAssigner 271 var err error 272 273 chunkAssigner, err = chunks.NewChunkAssigner(v.verConf.chunkAlpha, node.State) 274 if err != nil { 275 return nil, fmt.Errorf("could not initialize chunk assigner: %w", err) 276 } 277 278 assignerEngine = assigner.New( 279 node.Logger, 280 collector, 281 node.Tracer, 282 node.Me, 283 node.State, 284 chunkAssigner, 285 chunkQueue, 286 chunkConsumer, 287 v.verConf.stopAtHeight) 288 289 return assignerEngine, nil 290 }). 291 Component("block consumer", func(node *NodeConfig) (module.ReadyDoneAware, error) { 292 var initBlockHeight uint64 293 var err error 294 295 blockConsumer, initBlockHeight, err = blockconsumer.NewBlockConsumer( 296 node.Logger, 297 collector, 298 processedBlockHeight, 299 node.Storage.Blocks, 300 node.State, 301 assignerEngine, 302 v.verConf.blockWorkers) 303 304 if err != nil { 305 return nil, fmt.Errorf("could not initialize block consumer: %w", err) 306 } 307 308 err = node.Metrics.Mempool.Register(metrics.ResourceBlockConsumer, blockConsumer.Size) 309 if err != nil { 310 return nil, fmt.Errorf("could not register backend metric: %w", err) 311 } 312 313 node.Logger.Info(). 314 Str("component", "node-builder"). 315 Uint64("init_height", initBlockHeight). 316 Msg("block consumer initialized") 317 318 return blockConsumer, nil 319 }). 320 Component("follower engine", func(node *NodeConfig) (module.ReadyDoneAware, error) { 321 // initialize cleaner for DB 322 cleaner := badger.NewCleaner(node.Logger, node.DB, node.Metrics.CleanCollector, flow.DefaultValueLogGCFrequency) 323 324 // create a finalizer that handles updating the protocol 325 // state when the follower detects newly finalized blocks 326 final := finalizer.NewFinalizer(node.DB, node.Storage.Headers, followerState, node.Tracer) 327 328 // initialize consensus committee's membership state 329 // This committee state is for the HotStuff follower, which follows the MAIN CONSENSUS Committee 330 // Note: node.Me.NodeID() is not part of the consensus committee 331 committee, err := committees.NewConsensusCommittee(node.State, node.Me.NodeID()) 332 if err != nil { 333 return nil, fmt.Errorf("could not create Committee state for main consensus: %w", err) 334 } 335 336 packer := hotsignature.NewConsensusSigDataPacker(committee) 337 // initialize the verifier for the protocol consensus 338 verifier := verification.NewCombinedVerifier(committee, packer) 339 340 finalized, pending, err := recoveryprotocol.FindLatest(node.State, node.Storage.Headers) 341 if err != nil { 342 return nil, fmt.Errorf("could not find latest finalized block and pending blocks to recover consensus follower: %w", err) 343 } 344 345 finalizationDistributor = pubsub.NewFinalizationDistributor() 346 finalizationDistributor.AddConsumer(blockConsumer) 347 348 // creates a consensus follower with ingestEngine as the notifier 349 // so that it gets notified upon each new finalized block 350 followerCore, err := flowconsensus.NewFollower(node.Logger, committee, node.Storage.Headers, final, verifier, finalizationDistributor, node.RootBlock.Header, 351 node.RootQC, finalized, pending) 352 if err != nil { 353 return nil, fmt.Errorf("could not create follower core logic: %w", err) 354 } 355 356 followerEng, err = follower.New( 357 node.Logger, 358 node.Network, 359 node.Me, 360 node.Metrics.Engine, 361 node.Metrics.Mempool, 362 cleaner, 363 node.Storage.Headers, 364 node.Storage.Payloads, 365 followerState, 366 pendingBlocks, 367 followerCore, 368 syncCore, 369 node.Tracer, 370 follower.WithComplianceOptions(compliance.WithSkipNewProposalsThreshold(node.ComplianceConfig.SkipNewProposalsThreshold)), 371 ) 372 if err != nil { 373 return nil, fmt.Errorf("could not create follower engine: %w", err) 374 } 375 376 return followerEng, nil 377 }). 378 Component("finalized snapshot", func(node *NodeConfig) (module.ReadyDoneAware, error) { 379 var err error 380 finalizedHeader, err = commonsync.NewFinalizedHeaderCache(node.Logger, node.State, finalizationDistributor) 381 if err != nil { 382 return nil, fmt.Errorf("could not create finalized snapshot cache: %w", err) 383 } 384 385 return finalizedHeader, nil 386 }). 387 Component("sync engine", func(node *NodeConfig) (module.ReadyDoneAware, error) { 388 sync, err := commonsync.New( 389 node.Logger, 390 node.Metrics.Engine, 391 node.Network, 392 node.Me, 393 node.Storage.Blocks, 394 followerEng, 395 syncCore, 396 finalizedHeader, 397 node.SyncEngineIdentifierProvider, 398 ) 399 if err != nil { 400 return nil, fmt.Errorf("could not create synchronization engine: %w", err) 401 } 402 return sync, nil 403 }) 404 }