github.com/onflow/flow-go@v0.33.17/state/protocol/badger/state.go (about) 1 // (c) 2019 Dapper Labs - ALL RIGHTS RESERVED 2 3 package badger 4 5 import ( 6 "errors" 7 "fmt" 8 "sync/atomic" 9 10 "github.com/dgraph-io/badger/v2" 11 12 "github.com/onflow/flow-go/consensus/hotstuff" 13 "github.com/onflow/flow-go/model/flow" 14 "github.com/onflow/flow-go/module" 15 statepkg "github.com/onflow/flow-go/state" 16 "github.com/onflow/flow-go/state/protocol" 17 "github.com/onflow/flow-go/state/protocol/invalid" 18 "github.com/onflow/flow-go/storage" 19 "github.com/onflow/flow-go/storage/badger/operation" 20 "github.com/onflow/flow-go/storage/badger/transaction" 21 ) 22 23 // cachedHeader caches a block header and its ID. 24 type cachedHeader struct { 25 id flow.Identifier 26 header *flow.Header 27 } 28 29 type State struct { 30 metrics module.ComplianceMetrics 31 db *badger.DB 32 headers storage.Headers 33 blocks storage.Blocks 34 qcs storage.QuorumCertificates 35 results storage.ExecutionResults 36 seals storage.Seals 37 epoch struct { 38 setups storage.EpochSetups 39 commits storage.EpochCommits 40 statuses storage.EpochStatuses 41 } 42 versionBeacons storage.VersionBeacons 43 44 // rootHeight marks the cutoff of the history this node knows about. We cache it in the state 45 // because it cannot change over the lifecycle of a protocol state instance. It is frequently 46 // larger than the height of the root block of the spork, (also cached below as 47 // `sporkRootBlockHeight`), for instance if the node joined in an epoch after the last spork. 48 finalizedRootHeight uint64 49 // sealedRootHeight returns the root block that is sealed. 50 sealedRootHeight uint64 51 // sporkRootBlockHeight is the height of the root block in the current spork. We cache it in 52 // the state, because it cannot change over the lifecycle of a protocol state instance. 53 // Caution: A node that joined in a later epoch past the spork, the node will likely _not_ 54 // know the spork's root block in full (though it will always know the height). 55 sporkRootBlockHeight uint64 56 // cache the latest finalized and sealed block headers as these are common queries. 57 // It can be cached because the protocol state is solely responsible for updating these values. 58 cachedFinal *atomic.Pointer[cachedHeader] 59 cachedSealed *atomic.Pointer[cachedHeader] 60 } 61 62 var _ protocol.State = (*State)(nil) 63 64 type BootstrapConfig struct { 65 // SkipNetworkAddressValidation flags allows skipping all the network address related 66 // validations not needed for an unstaked node 67 SkipNetworkAddressValidation bool 68 } 69 70 func defaultBootstrapConfig() *BootstrapConfig { 71 return &BootstrapConfig{ 72 SkipNetworkAddressValidation: false, 73 } 74 } 75 76 type BootstrapConfigOptions func(conf *BootstrapConfig) 77 78 func SkipNetworkAddressValidation(conf *BootstrapConfig) { 79 conf.SkipNetworkAddressValidation = true 80 } 81 82 func Bootstrap( 83 metrics module.ComplianceMetrics, 84 db *badger.DB, 85 headers storage.Headers, 86 seals storage.Seals, 87 results storage.ExecutionResults, 88 blocks storage.Blocks, 89 qcs storage.QuorumCertificates, 90 setups storage.EpochSetups, 91 commits storage.EpochCommits, 92 statuses storage.EpochStatuses, 93 versionBeacons storage.VersionBeacons, 94 root protocol.Snapshot, 95 options ...BootstrapConfigOptions, 96 ) (*State, error) { 97 98 config := defaultBootstrapConfig() 99 for _, opt := range options { 100 opt(config) 101 } 102 103 isBootstrapped, err := IsBootstrapped(db) 104 if err != nil { 105 return nil, fmt.Errorf("failed to determine whether database contains bootstrapped state: %w", err) 106 } 107 if isBootstrapped { 108 return nil, fmt.Errorf("expected empty database") 109 } 110 111 state := newState( 112 metrics, 113 db, 114 headers, 115 seals, 116 results, 117 blocks, 118 qcs, 119 setups, 120 commits, 121 statuses, 122 versionBeacons, 123 ) 124 125 if err := IsValidRootSnapshot(root, !config.SkipNetworkAddressValidation); err != nil { 126 return nil, fmt.Errorf("cannot bootstrap invalid root snapshot: %w", err) 127 } 128 129 segment, err := root.SealingSegment() 130 if err != nil { 131 return nil, fmt.Errorf("could not get sealing segment: %w", err) 132 } 133 134 _, rootSeal, err := root.SealedResult() 135 if err != nil { 136 return nil, fmt.Errorf("could not get sealed result for sealing segment: %w", err) 137 } 138 139 err = operation.RetryOnConflictTx(db, transaction.Update, func(tx *transaction.Tx) error { 140 // sealing segment is in ascending height order, so the tail is the 141 // oldest ancestor and head is the newest child in the segment 142 // TAIL <- ... <- HEAD 143 lastFinalized := segment.Finalized() // the highest block in sealing segment is the last finalized block 144 lastSealed := segment.Sealed() // the lowest block in sealing segment is the last sealed block 145 146 // 1) bootstrap the sealing segment 147 // creating sealed root block with the rootResult 148 // creating finalized root block with lastFinalized 149 err = state.bootstrapSealingSegment(segment, lastFinalized, rootSeal)(tx) 150 if err != nil { 151 return fmt.Errorf("could not bootstrap sealing chain segment blocks: %w", err) 152 } 153 154 // 2) insert the root quorum certificate into the database 155 qc, err := root.QuorumCertificate() 156 if err != nil { 157 return fmt.Errorf("could not get root qc: %w", err) 158 } 159 err = qcs.StoreTx(qc)(tx) 160 if err != nil { 161 return fmt.Errorf("could not insert root qc: %w", err) 162 } 163 164 // 3) initialize the current protocol state height/view pointers 165 err = transaction.WithTx(state.bootstrapStatePointers(root))(tx) 166 if err != nil { 167 return fmt.Errorf("could not bootstrap height/view pointers: %w", err) 168 } 169 170 // 4) initialize values related to the epoch logic 171 err = state.bootstrapEpoch(root.Epochs(), segment, !config.SkipNetworkAddressValidation)(tx) 172 if err != nil { 173 return fmt.Errorf("could not bootstrap epoch values: %w", err) 174 } 175 176 // 5) initialize spork params 177 err = transaction.WithTx(state.bootstrapSporkInfo(root))(tx) 178 if err != nil { 179 return fmt.Errorf("could not bootstrap spork info: %w", err) 180 } 181 182 // 6) set metric values 183 err = state.updateEpochMetrics(root) 184 if err != nil { 185 return fmt.Errorf("could not update epoch metrics: %w", err) 186 } 187 state.metrics.BlockSealed(lastSealed) 188 state.metrics.SealedHeight(lastSealed.Header.Height) 189 state.metrics.FinalizedHeight(lastFinalized.Header.Height) 190 for _, block := range segment.Blocks { 191 state.metrics.BlockFinalized(block) 192 } 193 194 // 7) initialize version beacon 195 err = transaction.WithTx(state.boostrapVersionBeacon(root))(tx) 196 if err != nil { 197 return fmt.Errorf("could not bootstrap version beacon: %w", err) 198 } 199 200 return nil 201 }) 202 if err != nil { 203 return nil, fmt.Errorf("bootstrapping failed: %w", err) 204 } 205 206 // populate the protocol state cache 207 err = state.populateCache() 208 if err != nil { 209 return nil, fmt.Errorf("failed to populate cache: %w", err) 210 } 211 212 return state, nil 213 } 214 215 // bootstrapSealingSegment inserts all blocks and associated metadata for the 216 // protocol state root snapshot to disk. 217 func (state *State) bootstrapSealingSegment(segment *flow.SealingSegment, head *flow.Block, rootSeal *flow.Seal) func(tx *transaction.Tx) error { 218 return func(tx *transaction.Tx) error { 219 220 for _, result := range segment.ExecutionResults { 221 err := transaction.WithTx(operation.SkipDuplicates(operation.InsertExecutionResult(result)))(tx) 222 if err != nil { 223 return fmt.Errorf("could not insert execution result: %w", err) 224 } 225 err = transaction.WithTx(operation.IndexExecutionResult(result.BlockID, result.ID()))(tx) 226 if err != nil { 227 return fmt.Errorf("could not index execution result: %w", err) 228 } 229 } 230 231 // insert the first seal (in case the segment's first block contains no seal) 232 if segment.FirstSeal != nil { 233 err := transaction.WithTx(operation.InsertSeal(segment.FirstSeal.ID(), segment.FirstSeal))(tx) 234 if err != nil { 235 return fmt.Errorf("could not insert first seal: %w", err) 236 } 237 } 238 239 // root seal contains the result ID for the sealed root block. If the sealed root block is 240 // different from the finalized root block, then it means the node dynamically bootstrapped. 241 // In that case, we should index the result of the sealed root block so that the EN is able 242 // to execute the next block. 243 err := transaction.WithTx(operation.SkipDuplicates(operation.IndexExecutionResult(rootSeal.BlockID, rootSeal.ResultID)))(tx) 244 if err != nil { 245 return fmt.Errorf("could not index root result: %w", err) 246 } 247 248 for _, block := range segment.ExtraBlocks { 249 blockID := block.ID() 250 height := block.Header.Height 251 err := state.blocks.StoreTx(block)(tx) 252 if err != nil { 253 return fmt.Errorf("could not insert SealingSegment extra block: %w", err) 254 } 255 err = transaction.WithTx(operation.IndexBlockHeight(height, blockID))(tx) 256 if err != nil { 257 return fmt.Errorf("could not index SealingSegment extra block (id=%x): %w", blockID, err) 258 } 259 err = state.qcs.StoreTx(block.Header.QuorumCertificate())(tx) 260 if err != nil { 261 return fmt.Errorf("could not store qc for SealingSegment extra block (id=%x): %w", blockID, err) 262 } 263 } 264 265 for i, block := range segment.Blocks { 266 blockID := block.ID() 267 height := block.Header.Height 268 269 err := state.blocks.StoreTx(block)(tx) 270 if err != nil { 271 return fmt.Errorf("could not insert SealingSegment block: %w", err) 272 } 273 err = transaction.WithTx(operation.IndexBlockHeight(height, blockID))(tx) 274 if err != nil { 275 return fmt.Errorf("could not index SealingSegment block (id=%x): %w", blockID, err) 276 } 277 err = state.qcs.StoreTx(block.Header.QuorumCertificate())(tx) 278 if err != nil { 279 return fmt.Errorf("could not store qc for SealingSegment block (id=%x): %w", blockID, err) 280 } 281 282 // index the latest seal as of this block 283 latestSealID, ok := segment.LatestSeals[blockID] 284 if !ok { 285 return fmt.Errorf("missing latest seal for sealing segment block (id=%s)", blockID) 286 } 287 // sanity check: make sure the seal exists 288 var latestSeal flow.Seal 289 err = transaction.WithTx(operation.RetrieveSeal(latestSealID, &latestSeal))(tx) 290 if err != nil { 291 return fmt.Errorf("could not verify latest seal for block (id=%x) exists: %w", blockID, err) 292 } 293 err = transaction.WithTx(operation.IndexLatestSealAtBlock(blockID, latestSealID))(tx) 294 if err != nil { 295 return fmt.Errorf("could not index block seal: %w", err) 296 } 297 298 // for all but the first block in the segment, index the parent->child relationship 299 if i > 0 { 300 err = transaction.WithTx(operation.InsertBlockChildren(block.Header.ParentID, []flow.Identifier{blockID}))(tx) 301 if err != nil { 302 return fmt.Errorf("could not insert child index for block (id=%x): %w", blockID, err) 303 } 304 } 305 } 306 307 // insert an empty child index for the final block in the segment 308 err = transaction.WithTx(operation.InsertBlockChildren(head.ID(), nil))(tx) 309 if err != nil { 310 return fmt.Errorf("could not insert child index for head block (id=%x): %w", head.ID(), err) 311 } 312 313 return nil 314 } 315 } 316 317 // bootstrapStatePointers instantiates special pointers used to by the protocol 318 // state to keep track of special block heights and views. 319 func (state *State) bootstrapStatePointers(root protocol.Snapshot) func(*badger.Txn) error { 320 return func(tx *badger.Txn) error { 321 segment, err := root.SealingSegment() 322 if err != nil { 323 return fmt.Errorf("could not get sealing segment: %w", err) 324 } 325 highest := segment.Finalized() 326 lowest := segment.Sealed() 327 // find the finalized seal that seals the lowest block, meaning seal.BlockID == lowest.ID() 328 seal, err := segment.FinalizedSeal() 329 if err != nil { 330 return fmt.Errorf("could not get finalized seal from sealing segment: %w", err) 331 } 332 333 safetyData := &hotstuff.SafetyData{ 334 LockedOneChainView: highest.Header.View, 335 HighestAcknowledgedView: highest.Header.View, 336 } 337 338 // Per convention, all blocks in the sealing segment must be finalized. Therefore, a QC must 339 // exist for the `highest` block in the sealing segment. The QC for `highest` should be 340 // contained in the `root` Snapshot and returned by `root.QuorumCertificate()`. Otherwise, 341 // the Snapshot is incomplete, because consensus nodes require this QC. To reduce the chance of 342 // accidental misconfiguration undermining consensus liveness, we do the following sanity checks: 343 // * `rootQC` should not be nil 344 // * `rootQC` should be for `highest` block, i.e. its view and blockID should match 345 rootQC, err := root.QuorumCertificate() 346 if err != nil { 347 return fmt.Errorf("could not get root QC: %w", err) 348 } 349 if rootQC == nil { 350 return fmt.Errorf("QC for highest (finalized) block in sealing segment cannot be nil") 351 } 352 if rootQC.View != highest.Header.View { 353 return fmt.Errorf("root QC's view %d does not match the highest block in sealing segment (view %d)", rootQC.View, highest.Header.View) 354 } 355 if rootQC.BlockID != highest.Header.ID() { 356 return fmt.Errorf("root QC is for block %v, which does not match the highest block %v in sealing segment", rootQC.BlockID, highest.Header.ID()) 357 } 358 359 livenessData := &hotstuff.LivenessData{ 360 CurrentView: highest.Header.View + 1, 361 NewestQC: rootQC, 362 } 363 364 // insert initial views for HotStuff 365 err = operation.InsertSafetyData(highest.Header.ChainID, safetyData)(tx) 366 if err != nil { 367 return fmt.Errorf("could not insert safety data: %w", err) 368 } 369 err = operation.InsertLivenessData(highest.Header.ChainID, livenessData)(tx) 370 if err != nil { 371 return fmt.Errorf("could not insert liveness data: %w", err) 372 } 373 374 // insert height pointers 375 err = operation.InsertRootHeight(highest.Header.Height)(tx) 376 if err != nil { 377 return fmt.Errorf("could not insert finalized root height: %w", err) 378 } 379 // the sealed root height is the lowest block in sealing segment 380 err = operation.InsertSealedRootHeight(lowest.Header.Height)(tx) 381 if err != nil { 382 return fmt.Errorf("could not insert sealed root height: %w", err) 383 } 384 err = operation.InsertFinalizedHeight(highest.Header.Height)(tx) 385 if err != nil { 386 return fmt.Errorf("could not insert finalized height: %w", err) 387 } 388 err = operation.InsertSealedHeight(lowest.Header.Height)(tx) 389 if err != nil { 390 return fmt.Errorf("could not insert sealed height: %w", err) 391 } 392 err = operation.IndexFinalizedSealByBlockID(seal.BlockID, seal.ID())(tx) 393 if err != nil { 394 return fmt.Errorf("could not index sealed block: %w", err) 395 } 396 397 return nil 398 } 399 } 400 401 // bootstrapEpoch bootstraps the protocol state database with information about 402 // the previous, current, and next epochs as of the root snapshot. 403 // 404 // The root snapshot's sealing segment must not straddle any epoch transitions 405 // or epoch phase transitions. 406 func (state *State) bootstrapEpoch(epochs protocol.EpochQuery, segment *flow.SealingSegment, verifyNetworkAddress bool) func(*transaction.Tx) error { 407 return func(tx *transaction.Tx) error { 408 previous := epochs.Previous() 409 current := epochs.Current() 410 next := epochs.Next() 411 412 // build the status as we go 413 status := new(flow.EpochStatus) 414 var setups []*flow.EpochSetup 415 var commits []*flow.EpochCommit 416 417 // insert previous epoch if it exists 418 _, err := previous.Counter() 419 if err == nil { 420 // if there is a previous epoch, both setup and commit events must exist 421 setup, err := protocol.ToEpochSetup(previous) 422 if err != nil { 423 return fmt.Errorf("could not get previous epoch setup event: %w", err) 424 } 425 commit, err := protocol.ToEpochCommit(previous) 426 if err != nil { 427 return fmt.Errorf("could not get previous epoch commit event: %w", err) 428 } 429 430 if err := verifyEpochSetup(setup, verifyNetworkAddress); err != nil { 431 return fmt.Errorf("invalid setup: %w", err) 432 } 433 if err := isValidEpochCommit(commit, setup); err != nil { 434 return fmt.Errorf("invalid commit: %w", err) 435 } 436 437 err = indexFirstHeight(previous)(tx.DBTxn) 438 if err != nil { 439 return fmt.Errorf("could not index epoch first height: %w", err) 440 } 441 442 setups = append(setups, setup) 443 commits = append(commits, commit) 444 status.PreviousEpoch.SetupID = setup.ID() 445 status.PreviousEpoch.CommitID = commit.ID() 446 } else if !errors.Is(err, protocol.ErrNoPreviousEpoch) { 447 return fmt.Errorf("could not retrieve previous epoch: %w", err) 448 } 449 450 // insert current epoch - both setup and commit events must exist 451 setup, err := protocol.ToEpochSetup(current) 452 if err != nil { 453 return fmt.Errorf("could not get current epoch setup event: %w", err) 454 } 455 commit, err := protocol.ToEpochCommit(current) 456 if err != nil { 457 return fmt.Errorf("could not get current epoch commit event: %w", err) 458 } 459 460 if err := verifyEpochSetup(setup, verifyNetworkAddress); err != nil { 461 return fmt.Errorf("invalid setup: %w", err) 462 } 463 if err := isValidEpochCommit(commit, setup); err != nil { 464 return fmt.Errorf("invalid commit: %w", err) 465 } 466 467 err = indexFirstHeight(current)(tx.DBTxn) 468 if err != nil { 469 return fmt.Errorf("could not index epoch first height: %w", err) 470 } 471 472 setups = append(setups, setup) 473 commits = append(commits, commit) 474 status.CurrentEpoch.SetupID = setup.ID() 475 status.CurrentEpoch.CommitID = commit.ID() 476 477 // insert next epoch, if it exists 478 _, err = next.Counter() 479 if err == nil { 480 // either only the setup event, or both the setup and commit events must exist 481 setup, err := protocol.ToEpochSetup(next) 482 if err != nil { 483 return fmt.Errorf("could not get next epoch setup event: %w", err) 484 } 485 486 if err := verifyEpochSetup(setup, verifyNetworkAddress); err != nil { 487 return fmt.Errorf("invalid setup: %w", err) 488 } 489 490 setups = append(setups, setup) 491 status.NextEpoch.SetupID = setup.ID() 492 commit, err := protocol.ToEpochCommit(next) 493 if err != nil && !errors.Is(err, protocol.ErrNextEpochNotCommitted) { 494 return fmt.Errorf("could not get next epoch commit event: %w", err) 495 } 496 if err == nil { 497 if err := isValidEpochCommit(commit, setup); err != nil { 498 return fmt.Errorf("invalid commit") 499 } 500 commits = append(commits, commit) 501 status.NextEpoch.CommitID = commit.ID() 502 } 503 } else if !errors.Is(err, protocol.ErrNextEpochNotSetup) { 504 return fmt.Errorf("could not get next epoch: %w", err) 505 } 506 507 // sanity check: ensure epoch status is valid 508 err = status.Check() 509 if err != nil { 510 return fmt.Errorf("bootstrapping resulting in invalid epoch status: %w", err) 511 } 512 513 // insert all epoch setup/commit service events 514 for _, setup := range setups { 515 err = state.epoch.setups.StoreTx(setup)(tx) 516 if err != nil { 517 return fmt.Errorf("could not store epoch setup event: %w", err) 518 } 519 } 520 for _, commit := range commits { 521 err = state.epoch.commits.StoreTx(commit)(tx) 522 if err != nil { 523 return fmt.Errorf("could not store epoch commit event: %w", err) 524 } 525 } 526 527 // NOTE: as specified in the godoc, this code assumes that each block 528 // in the sealing segment in within the same phase within the same epoch. 529 for _, block := range segment.AllBlocks() { 530 blockID := block.ID() 531 err = state.epoch.statuses.StoreTx(blockID, status)(tx) 532 if err != nil { 533 return fmt.Errorf("could not store epoch status for block (id=%x): %w", blockID, err) 534 } 535 } 536 537 return nil 538 } 539 } 540 541 // bootstrapSporkInfo bootstraps the protocol state with information about the 542 // spork which is used to disambiguate Flow networks. 543 func (state *State) bootstrapSporkInfo(root protocol.Snapshot) func(*badger.Txn) error { 544 return func(tx *badger.Txn) error { 545 params := root.Params() 546 547 sporkID, err := params.SporkID() 548 if err != nil { 549 return fmt.Errorf("could not get spork ID: %w", err) 550 } 551 err = operation.InsertSporkID(sporkID)(tx) 552 if err != nil { 553 return fmt.Errorf("could not insert spork ID: %w", err) 554 } 555 556 sporkRootBlockHeight, err := params.SporkRootBlockHeight() 557 if err != nil { 558 return fmt.Errorf("could not get spork root block height: %w", err) 559 } 560 err = operation.InsertSporkRootBlockHeight(sporkRootBlockHeight)(tx) 561 if err != nil { 562 return fmt.Errorf("could not insert spork root block height: %w", err) 563 } 564 565 version, err := params.ProtocolVersion() 566 if err != nil { 567 return fmt.Errorf("could not get protocol version: %w", err) 568 } 569 err = operation.InsertProtocolVersion(version)(tx) 570 if err != nil { 571 return fmt.Errorf("could not insert protocol version: %w", err) 572 } 573 574 threshold, err := params.EpochCommitSafetyThreshold() 575 if err != nil { 576 return fmt.Errorf("could not get epoch commit safety threshold: %w", err) 577 } 578 err = operation.InsertEpochCommitSafetyThreshold(threshold)(tx) 579 if err != nil { 580 return fmt.Errorf("could not insert epoch commit safety threshold: %w", err) 581 } 582 583 return nil 584 } 585 } 586 587 // indexFirstHeight indexes the first height for the epoch, as part of bootstrapping. 588 // The input epoch must have been started (the first block of the epoch has been finalized). 589 // No errors are expected during normal operation. 590 func indexFirstHeight(epoch protocol.Epoch) func(*badger.Txn) error { 591 return func(tx *badger.Txn) error { 592 counter, err := epoch.Counter() 593 if err != nil { 594 return fmt.Errorf("could not get epoch counter: %w", err) 595 } 596 firstHeight, err := epoch.FirstHeight() 597 if err != nil { 598 return fmt.Errorf("could not get epoch first height: %w", err) 599 } 600 err = operation.InsertEpochFirstHeight(counter, firstHeight)(tx) 601 if err != nil { 602 return fmt.Errorf("could not index first height %d for epoch %d: %w", firstHeight, counter, err) 603 } 604 return nil 605 } 606 } 607 608 func OpenState( 609 metrics module.ComplianceMetrics, 610 db *badger.DB, 611 headers storage.Headers, 612 seals storage.Seals, 613 results storage.ExecutionResults, 614 blocks storage.Blocks, 615 qcs storage.QuorumCertificates, 616 setups storage.EpochSetups, 617 commits storage.EpochCommits, 618 statuses storage.EpochStatuses, 619 versionBeacons storage.VersionBeacons, 620 ) (*State, error) { 621 isBootstrapped, err := IsBootstrapped(db) 622 if err != nil { 623 return nil, fmt.Errorf("failed to determine whether database contains bootstrapped state: %w", err) 624 } 625 if !isBootstrapped { 626 return nil, fmt.Errorf("expected database to contain bootstrapped state") 627 } 628 state := newState( 629 metrics, 630 db, 631 headers, 632 seals, 633 results, 634 blocks, 635 qcs, 636 setups, 637 commits, 638 statuses, 639 versionBeacons, 640 ) // populate the protocol state cache 641 err = state.populateCache() 642 if err != nil { 643 return nil, fmt.Errorf("failed to populate cache: %w", err) 644 } 645 646 // report last finalized and sealed block height 647 finalSnapshot := state.Final() 648 head, err := finalSnapshot.Head() 649 if err != nil { 650 return nil, fmt.Errorf("unexpected error to get finalized block: %w", err) 651 } 652 metrics.FinalizedHeight(head.Height) 653 654 sealed, err := state.Sealed().Head() 655 if err != nil { 656 return nil, fmt.Errorf("could not get latest sealed block: %w", err) 657 } 658 metrics.SealedHeight(sealed.Height) 659 660 // update all epoch related metrics 661 err = state.updateEpochMetrics(finalSnapshot) 662 if err != nil { 663 return nil, fmt.Errorf("failed to update epoch metrics: %w", err) 664 } 665 666 return state, nil 667 } 668 669 func (state *State) Params() protocol.Params { 670 return Params{state: state} 671 } 672 673 // Sealed returns a snapshot for the latest sealed block. A latest sealed block 674 // must always exist, so this function always returns a valid snapshot. 675 func (state *State) Sealed() protocol.Snapshot { 676 cached := state.cachedSealed.Load() 677 if cached == nil { 678 return invalid.NewSnapshotf("internal inconsistency: no cached sealed header") 679 } 680 return NewFinalizedSnapshot(state, cached.id, cached.header) 681 } 682 683 // Final returns a snapshot for the latest finalized block. A latest finalized 684 // block must always exist, so this function always returns a valid snapshot. 685 func (state *State) Final() protocol.Snapshot { 686 cached := state.cachedFinal.Load() 687 if cached == nil { 688 return invalid.NewSnapshotf("internal inconsistency: no cached final header") 689 } 690 return NewFinalizedSnapshot(state, cached.id, cached.header) 691 } 692 693 // AtHeight returns a snapshot for the finalized block at the given height. 694 // This function may return an invalid.Snapshot with: 695 // - state.ErrUnknownSnapshotReference: 696 // -> if no block with the given height has been finalized, even if it is incorporated 697 // -> if the given height is below the root height 698 // - exception for critical unexpected storage errors 699 func (state *State) AtHeight(height uint64) protocol.Snapshot { 700 // retrieve the block ID for the finalized height 701 var blockID flow.Identifier 702 err := state.db.View(operation.LookupBlockHeight(height, &blockID)) 703 if err != nil { 704 if errors.Is(err, storage.ErrNotFound) { 705 return invalid.NewSnapshotf("unknown finalized height %d: %w", height, statepkg.ErrUnknownSnapshotReference) 706 } 707 // critical storage error 708 return invalid.NewSnapshotf("could not look up block by height: %w", err) 709 } 710 return newSnapshotWithIncorporatedReferenceBlock(state, blockID) 711 } 712 713 // AtBlockID returns a snapshot for the block with the given ID. The block may be 714 // finalized or un-finalized. 715 // This function may return an invalid.Snapshot with: 716 // - state.ErrUnknownSnapshotReference: 717 // -> if no block with the given ID exists in the state 718 // - exception for critical unexpected storage errors 719 func (state *State) AtBlockID(blockID flow.Identifier) protocol.Snapshot { 720 exists, err := state.headers.Exists(blockID) 721 if err != nil { 722 return invalid.NewSnapshotf("could not check existence of reference block: %w", err) 723 } 724 if !exists { 725 return invalid.NewSnapshotf("unknown block %x: %w", blockID, statepkg.ErrUnknownSnapshotReference) 726 } 727 return newSnapshotWithIncorporatedReferenceBlock(state, blockID) 728 } 729 730 // newState initializes a new state backed by the provided a badger database, 731 // mempools and service components. 732 // The parameter `expectedBootstrappedState` indicates whether the database 733 // is expected to contain an already bootstrapped state or not 734 func newState( 735 metrics module.ComplianceMetrics, 736 db *badger.DB, 737 headers storage.Headers, 738 seals storage.Seals, 739 results storage.ExecutionResults, 740 blocks storage.Blocks, 741 qcs storage.QuorumCertificates, 742 setups storage.EpochSetups, 743 commits storage.EpochCommits, 744 statuses storage.EpochStatuses, 745 versionBeacons storage.VersionBeacons, 746 ) *State { 747 return &State{ 748 metrics: metrics, 749 db: db, 750 headers: headers, 751 results: results, 752 seals: seals, 753 blocks: blocks, 754 qcs: qcs, 755 epoch: struct { 756 setups storage.EpochSetups 757 commits storage.EpochCommits 758 statuses storage.EpochStatuses 759 }{ 760 setups: setups, 761 commits: commits, 762 statuses: statuses, 763 }, 764 versionBeacons: versionBeacons, 765 cachedFinal: new(atomic.Pointer[cachedHeader]), 766 cachedSealed: new(atomic.Pointer[cachedHeader]), 767 } 768 } 769 770 // IsBootstrapped returns whether the database contains a bootstrapped state 771 func IsBootstrapped(db *badger.DB) (bool, error) { 772 var finalized uint64 773 err := db.View(operation.RetrieveFinalizedHeight(&finalized)) 774 if errors.Is(err, storage.ErrNotFound) { 775 return false, nil 776 } 777 if err != nil { 778 return false, fmt.Errorf("retrieving finalized height failed: %w", err) 779 } 780 return true, nil 781 } 782 783 // updateEpochMetrics update the `consensus_compliance_current_epoch_counter` and the 784 // `consensus_compliance_current_epoch_phase` metric 785 func (state *State) updateEpochMetrics(snap protocol.Snapshot) error { 786 787 // update epoch counter 788 counter, err := snap.Epochs().Current().Counter() 789 if err != nil { 790 return fmt.Errorf("could not get current epoch counter: %w", err) 791 } 792 state.metrics.CurrentEpochCounter(counter) 793 794 // update epoch phase 795 phase, err := snap.Phase() 796 if err != nil { 797 return fmt.Errorf("could not get current epoch counter: %w", err) 798 } 799 state.metrics.CurrentEpochPhase(phase) 800 801 // update committed epoch final view 802 err = state.updateCommittedEpochFinalView(snap) 803 if err != nil { 804 return fmt.Errorf("could not update committed epoch final view") 805 } 806 807 currentEpochFinalView, err := snap.Epochs().Current().FinalView() 808 if err != nil { 809 return fmt.Errorf("could not update current epoch final view: %w", err) 810 } 811 state.metrics.CurrentEpochFinalView(currentEpochFinalView) 812 813 dkgPhase1FinalView, dkgPhase2FinalView, dkgPhase3FinalView, err := protocol.DKGPhaseViews(snap.Epochs().Current()) 814 if err != nil { 815 return fmt.Errorf("could not get dkg phase final view: %w", err) 816 } 817 818 state.metrics.CurrentDKGPhase1FinalView(dkgPhase1FinalView) 819 state.metrics.CurrentDKGPhase2FinalView(dkgPhase2FinalView) 820 state.metrics.CurrentDKGPhase3FinalView(dkgPhase3FinalView) 821 822 // EECC - check whether the epoch emergency fallback flag has been set 823 // in the database. If so, skip updating any epoch-related metrics. 824 epochFallbackTriggered, err := state.isEpochEmergencyFallbackTriggered() 825 if err != nil { 826 return fmt.Errorf("could not check epoch emergency fallback flag: %w", err) 827 } 828 if epochFallbackTriggered { 829 state.metrics.EpochEmergencyFallbackTriggered() 830 } 831 832 return nil 833 } 834 835 // boostrapVersionBeacon bootstraps version beacon, by adding the latest beacon 836 // to an index, if present. 837 func (state *State) boostrapVersionBeacon( 838 snapshot protocol.Snapshot, 839 ) func(*badger.Txn) error { 840 return func(txn *badger.Txn) error { 841 versionBeacon, err := snapshot.VersionBeacon() 842 if err != nil { 843 return err 844 } 845 846 if versionBeacon == nil { 847 return nil 848 } 849 850 return operation.IndexVersionBeaconByHeight(versionBeacon)(txn) 851 } 852 } 853 854 // populateCache is used after opening or bootstrapping the state to populate the cache. 855 // The cache must be populated before the State receives any queries. 856 // No errors expected during normal operations. 857 func (state *State) populateCache() error { 858 859 // cache the initial value for finalized block 860 err := state.db.View(func(tx *badger.Txn) error { 861 // root height 862 err := state.db.View(operation.RetrieveRootHeight(&state.finalizedRootHeight)) 863 if err != nil { 864 return fmt.Errorf("could not read root block to populate cache: %w", err) 865 } 866 // sealed root height 867 err = state.db.View(operation.RetrieveSealedRootHeight(&state.sealedRootHeight)) 868 if err != nil { 869 return fmt.Errorf("could not read sealed root block to populate cache: %w", err) 870 } 871 // spork root block height 872 err = state.db.View(operation.RetrieveSporkRootBlockHeight(&state.sporkRootBlockHeight)) 873 if err != nil { 874 return fmt.Errorf("could not get spork root block height: %w", err) 875 } 876 // finalized header 877 var finalizedHeight uint64 878 err = operation.RetrieveFinalizedHeight(&finalizedHeight)(tx) 879 if err != nil { 880 return fmt.Errorf("could not lookup finalized height: %w", err) 881 } 882 var cachedFinalHeader cachedHeader 883 err = operation.LookupBlockHeight(finalizedHeight, &cachedFinalHeader.id)(tx) 884 if err != nil { 885 return fmt.Errorf("could not lookup finalized id (height=%d): %w", finalizedHeight, err) 886 } 887 cachedFinalHeader.header, err = state.headers.ByBlockID(cachedFinalHeader.id) 888 if err != nil { 889 return fmt.Errorf("could not get finalized block (id=%x): %w", cachedFinalHeader.id, err) 890 } 891 state.cachedFinal.Store(&cachedFinalHeader) 892 // sealed header 893 var sealedHeight uint64 894 err = operation.RetrieveSealedHeight(&sealedHeight)(tx) 895 if err != nil { 896 return fmt.Errorf("could not lookup sealed height: %w", err) 897 } 898 var cachedSealedHeader cachedHeader 899 err = operation.LookupBlockHeight(sealedHeight, &cachedSealedHeader.id)(tx) 900 if err != nil { 901 return fmt.Errorf("could not lookup sealed id (height=%d): %w", sealedHeight, err) 902 } 903 cachedSealedHeader.header, err = state.headers.ByBlockID(cachedSealedHeader.id) 904 if err != nil { 905 return fmt.Errorf("could not get sealed block (id=%x): %w", cachedSealedHeader.id, err) 906 } 907 state.cachedSealed.Store(&cachedSealedHeader) 908 return nil 909 }) 910 if err != nil { 911 return fmt.Errorf("could not cache finalized header: %w", err) 912 } 913 914 return nil 915 } 916 917 // updateCommittedEpochFinalView updates the `committed_epoch_final_view` metric 918 // based on the current epoch phase of the input snapshot. It should be called 919 // at startup and during transitions between EpochSetup and EpochCommitted phases. 920 // 921 // For example, suppose we have epochs N and N+1. 922 // If we are in epoch N's Staking or Setup Phase, then epoch N's final view should be the value of the metric. 923 // If we are in epoch N's Committed Phase, then epoch N+1's final view should be the value of the metric. 924 func (state *State) updateCommittedEpochFinalView(snap protocol.Snapshot) error { 925 926 phase, err := snap.Phase() 927 if err != nil { 928 return fmt.Errorf("could not get epoch phase: %w", err) 929 } 930 931 // update metric based of epoch phase 932 switch phase { 933 case flow.EpochPhaseStaking, flow.EpochPhaseSetup: 934 935 // if we are in Staking or Setup phase, then set the metric value to the current epoch's final view 936 finalView, err := snap.Epochs().Current().FinalView() 937 if err != nil { 938 return fmt.Errorf("could not get current epoch final view from snapshot: %w", err) 939 } 940 state.metrics.CommittedEpochFinalView(finalView) 941 case flow.EpochPhaseCommitted: 942 943 // if we are in Committed phase, then set the metric value to the next epoch's final view 944 finalView, err := snap.Epochs().Next().FinalView() 945 if err != nil { 946 return fmt.Errorf("could not get next epoch final view from snapshot: %w", err) 947 } 948 state.metrics.CommittedEpochFinalView(finalView) 949 default: 950 return fmt.Errorf("invalid phase: %s", phase) 951 } 952 953 return nil 954 } 955 956 // isEpochEmergencyFallbackTriggered checks whether epoch fallback has been globally triggered. 957 // Returns: 958 // * (true, nil) if epoch fallback is triggered 959 // * (false, nil) if epoch fallback is not triggered (including if the flag is not set) 960 // * (false, err) if an unexpected error occurs 961 func (state *State) isEpochEmergencyFallbackTriggered() (bool, error) { 962 var triggered bool 963 err := state.db.View(operation.CheckEpochEmergencyFallbackTriggered(&triggered)) 964 return triggered, err 965 }