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  }