github.com/koko1123/flow-go-1@v0.29.6/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  
     9  	"github.com/dgraph-io/badger/v3"
    10  
    11  	"github.com/koko1123/flow-go-1/model/flow"
    12  	"github.com/koko1123/flow-go-1/module"
    13  	statepkg "github.com/koko1123/flow-go-1/state"
    14  	"github.com/koko1123/flow-go-1/state/protocol"
    15  	"github.com/koko1123/flow-go-1/state/protocol/invalid"
    16  	"github.com/koko1123/flow-go-1/storage"
    17  	"github.com/koko1123/flow-go-1/storage/badger/operation"
    18  	"github.com/koko1123/flow-go-1/storage/badger/transaction"
    19  )
    20  
    21  type State struct {
    22  	metrics module.ComplianceMetrics
    23  	db      *badger.DB
    24  	headers storage.Headers
    25  	blocks  storage.Blocks
    26  	results storage.ExecutionResults
    27  	seals   storage.Seals
    28  	epoch   struct {
    29  		setups   storage.EpochSetups
    30  		commits  storage.EpochCommits
    31  		statuses storage.EpochStatuses
    32  	}
    33  }
    34  
    35  type BootstrapConfig struct {
    36  	// SkipNetworkAddressValidation flags allows skipping all the network address related validations not needed for
    37  	// an unstaked node
    38  	SkipNetworkAddressValidation bool
    39  }
    40  
    41  func defaultBootstrapConfig() *BootstrapConfig {
    42  	return &BootstrapConfig{
    43  		SkipNetworkAddressValidation: false,
    44  	}
    45  }
    46  
    47  type BootstrapConfigOptions func(conf *BootstrapConfig)
    48  
    49  func SkipNetworkAddressValidation(conf *BootstrapConfig) {
    50  	conf.SkipNetworkAddressValidation = true
    51  }
    52  
    53  func Bootstrap(
    54  	metrics module.ComplianceMetrics,
    55  	db *badger.DB,
    56  	headers storage.Headers,
    57  	seals storage.Seals,
    58  	results storage.ExecutionResults,
    59  	blocks storage.Blocks,
    60  	setups storage.EpochSetups,
    61  	commits storage.EpochCommits,
    62  	statuses storage.EpochStatuses,
    63  	root protocol.Snapshot,
    64  	options ...BootstrapConfigOptions,
    65  ) (*State, error) {
    66  
    67  	config := defaultBootstrapConfig()
    68  	for _, opt := range options {
    69  		opt(config)
    70  	}
    71  
    72  	isBootstrapped, err := IsBootstrapped(db)
    73  	if err != nil {
    74  		return nil, fmt.Errorf("failed to determine whether database contains bootstrapped state: %w", err)
    75  	}
    76  	if isBootstrapped {
    77  		return nil, fmt.Errorf("expected empty database")
    78  	}
    79  
    80  	state := newState(metrics, db, headers, seals, results, blocks, setups, commits, statuses)
    81  
    82  	if err := IsValidRootSnapshot(root, !config.SkipNetworkAddressValidation); err != nil {
    83  		return nil, fmt.Errorf("cannot bootstrap invalid root snapshot: %w", err)
    84  	}
    85  
    86  	segment, err := root.SealingSegment()
    87  	if err != nil {
    88  		return nil, fmt.Errorf("could not get sealing segment: %w", err)
    89  	}
    90  
    91  	err = operation.RetryOnConflictTx(db, transaction.Update, func(tx *transaction.Tx) error {
    92  		// sealing segment is in ascending height order, so the tail is the
    93  		// oldest ancestor and head is the newest child in the segment
    94  		// TAIL <- ... <- HEAD
    95  		highest := segment.Highest() // reference block of the snapshot
    96  		lowest := segment.Lowest()   // last sealed block
    97  
    98  		// 1) bootstrap the sealing segment
    99  		err = state.bootstrapSealingSegment(segment, highest)(tx)
   100  		if err != nil {
   101  			return fmt.Errorf("could not bootstrap sealing chain segment blocks: %w", err)
   102  		}
   103  
   104  		// 2) insert the root quorum certificate into the database
   105  		qc, err := root.QuorumCertificate()
   106  		if err != nil {
   107  			return fmt.Errorf("could not get root qc: %w", err)
   108  		}
   109  		err = transaction.WithTx(operation.InsertRootQuorumCertificate(qc))(tx)
   110  		if err != nil {
   111  			return fmt.Errorf("could not insert root qc: %w", err)
   112  		}
   113  
   114  		// 3) initialize the current protocol state height/view pointers
   115  		err = transaction.WithTx(state.bootstrapStatePointers(root))(tx)
   116  		if err != nil {
   117  			return fmt.Errorf("could not bootstrap height/view pointers: %w", err)
   118  		}
   119  
   120  		// 4) initialize values related to the epoch logic
   121  		err = state.bootstrapEpoch(root, !config.SkipNetworkAddressValidation)(tx)
   122  		if err != nil {
   123  			return fmt.Errorf("could not bootstrap epoch values: %w", err)
   124  		}
   125  
   126  		// 5) initialize spork params
   127  		err = transaction.WithTx(state.bootstrapSporkInfo(root))(tx)
   128  		if err != nil {
   129  			return fmt.Errorf("could not bootstrap spork info: %w", err)
   130  		}
   131  
   132  		// 6) set metric values
   133  		err = state.updateEpochMetrics(root)
   134  		if err != nil {
   135  			return fmt.Errorf("could not update epoch metrics: %w", err)
   136  		}
   137  		state.metrics.BlockSealed(lowest)
   138  		state.metrics.SealedHeight(lowest.Header.Height)
   139  		state.metrics.FinalizedHeight(highest.Header.Height)
   140  		for _, block := range segment.Blocks {
   141  			state.metrics.BlockFinalized(block)
   142  		}
   143  
   144  		return nil
   145  	})
   146  	if err != nil {
   147  		return nil, fmt.Errorf("bootstrapping failed: %w", err)
   148  	}
   149  
   150  	return state, nil
   151  }
   152  
   153  // bootstrapSealingSegment inserts all blocks and associated metadata for the
   154  // protocol state root snapshot to disk.
   155  func (state *State) bootstrapSealingSegment(segment *flow.SealingSegment, head *flow.Block) func(tx *transaction.Tx) error {
   156  	return func(tx *transaction.Tx) error {
   157  
   158  		for _, result := range segment.ExecutionResults {
   159  			err := transaction.WithTx(operation.SkipDuplicates(operation.InsertExecutionResult(result)))(tx)
   160  			if err != nil {
   161  				return fmt.Errorf("could not insert execution result: %w", err)
   162  			}
   163  			err = transaction.WithTx(operation.IndexExecutionResult(result.BlockID, result.ID()))(tx)
   164  			if err != nil {
   165  				return fmt.Errorf("could not index execution result: %w", err)
   166  			}
   167  		}
   168  
   169  		// insert the first seal (in case the segment's first block contains no seal)
   170  		if segment.FirstSeal != nil {
   171  			err := transaction.WithTx(operation.InsertSeal(segment.FirstSeal.ID(), segment.FirstSeal))(tx)
   172  			if err != nil {
   173  				return fmt.Errorf("could not insert first seal: %w", err)
   174  			}
   175  		}
   176  
   177  		for i, block := range segment.Blocks {
   178  			blockID := block.ID()
   179  			height := block.Header.Height
   180  
   181  			err := state.blocks.StoreTx(block)(tx)
   182  			if err != nil {
   183  				return fmt.Errorf("could not insert root block: %w", err)
   184  			}
   185  			err = transaction.WithTx(operation.InsertBlockValidity(blockID, true))(tx)
   186  			if err != nil {
   187  				return fmt.Errorf("could not mark root block as valid: %w", err)
   188  			}
   189  			err = transaction.WithTx(operation.IndexBlockHeight(height, blockID))(tx)
   190  			if err != nil {
   191  				return fmt.Errorf("could not index root block segment (id=%x): %w", blockID, err)
   192  			}
   193  
   194  			// index the latest seal as of this block
   195  			latestSealID, ok := segment.LatestSeals[blockID]
   196  			if !ok {
   197  				return fmt.Errorf("missing latest seal for sealing segment block (id=%s)", blockID)
   198  			}
   199  			// sanity check: make sure the seal exists
   200  			var latestSeal flow.Seal
   201  			err = transaction.WithTx(operation.RetrieveSeal(latestSealID, &latestSeal))(tx)
   202  			if err != nil {
   203  				return fmt.Errorf("could not verify latest seal for block (id=%x) exists: %w", blockID, err)
   204  			}
   205  			err = transaction.WithTx(operation.IndexLatestSealAtBlock(blockID, latestSealID))(tx)
   206  			if err != nil {
   207  				return fmt.Errorf("could not index block seal: %w", err)
   208  			}
   209  
   210  			// for all but the first block in the segment, index the parent->child relationship
   211  			if i > 0 {
   212  				err = transaction.WithTx(operation.InsertBlockChildren(block.Header.ParentID, []flow.Identifier{blockID}))(tx)
   213  				if err != nil {
   214  					return fmt.Errorf("could not insert child index for block (id=%x): %w", blockID, err)
   215  				}
   216  			}
   217  		}
   218  
   219  		// insert an empty child index for the final block in the segment
   220  		err := transaction.WithTx(operation.InsertBlockChildren(head.ID(), nil))(tx)
   221  		if err != nil {
   222  			return fmt.Errorf("could not insert child index for head block (id=%x): %w", head.ID(), err)
   223  		}
   224  
   225  		return nil
   226  	}
   227  }
   228  
   229  // bootstrapStatePointers instantiates special pointers used to by the protocol
   230  // state to keep track of special block heights and views.
   231  func (state *State) bootstrapStatePointers(root protocol.Snapshot) func(*badger.Txn) error {
   232  	return func(tx *badger.Txn) error {
   233  		segment, err := root.SealingSegment()
   234  		if err != nil {
   235  			return fmt.Errorf("could not get sealing segment: %w", err)
   236  		}
   237  		highest := segment.Highest()
   238  		lowest := segment.Lowest()
   239  		// find the finalized seal that seals the lowest block, meaning seal.BlockID == lowest.ID()
   240  		seal, err := segment.FinalizedSeal()
   241  		if err != nil {
   242  			return fmt.Errorf("could not get finalized seal from sealing segment: %w", err)
   243  		}
   244  
   245  		// insert initial views for HotStuff
   246  		err = operation.InsertStartedView(highest.Header.ChainID, highest.Header.View)(tx)
   247  		if err != nil {
   248  			return fmt.Errorf("could not insert started view: %w", err)
   249  		}
   250  		err = operation.InsertVotedView(highest.Header.ChainID, highest.Header.View)(tx)
   251  		if err != nil {
   252  			return fmt.Errorf("could not insert started view: %w", err)
   253  		}
   254  
   255  		// insert height pointers
   256  		err = operation.InsertRootHeight(highest.Header.Height)(tx)
   257  		if err != nil {
   258  			return fmt.Errorf("could not insert root height: %w", err)
   259  		}
   260  		err = operation.InsertFinalizedHeight(highest.Header.Height)(tx)
   261  		if err != nil {
   262  			return fmt.Errorf("could not insert finalized height: %w", err)
   263  		}
   264  		err = operation.InsertSealedHeight(lowest.Header.Height)(tx)
   265  		if err != nil {
   266  			return fmt.Errorf("could not insert sealed height: %w", err)
   267  		}
   268  		err = operation.IndexFinalizedSealByBlockID(seal.BlockID, seal.ID())(tx)
   269  		if err != nil {
   270  			return fmt.Errorf("could not index sealed block: %w", err)
   271  		}
   272  
   273  		return nil
   274  	}
   275  }
   276  
   277  // bootstrapEpoch bootstraps the protocol state database with information about
   278  // the previous, current, and next epochs as of the root snapshot.
   279  //
   280  // The root snapshot's sealing segment must not straddle any epoch transitions
   281  // or epoch phase transitions.
   282  func (state *State) bootstrapEpoch(root protocol.Snapshot, verifyNetworkAddress bool) func(*transaction.Tx) error {
   283  	return func(tx *transaction.Tx) error {
   284  		previous := root.Epochs().Previous()
   285  		current := root.Epochs().Current()
   286  		next := root.Epochs().Next()
   287  
   288  		// build the status as we go
   289  		status := new(flow.EpochStatus)
   290  		var setups []*flow.EpochSetup
   291  		var commits []*flow.EpochCommit
   292  
   293  		// insert previous epoch if it exists
   294  		_, err := previous.Counter()
   295  		if err == nil {
   296  			// if there is a previous epoch, both setup and commit events must exist
   297  			setup, err := protocol.ToEpochSetup(previous)
   298  			if err != nil {
   299  				return fmt.Errorf("could not get previous epoch setup event: %w", err)
   300  			}
   301  			commit, err := protocol.ToEpochCommit(previous)
   302  			if err != nil {
   303  				return fmt.Errorf("could not get previous epoch commit event: %w", err)
   304  			}
   305  
   306  			if err := verifyEpochSetup(setup, verifyNetworkAddress); err != nil {
   307  				return fmt.Errorf("invalid setup: %w", err)
   308  			}
   309  
   310  			if err := isValidEpochCommit(commit, setup); err != nil {
   311  				return fmt.Errorf("invalid commit")
   312  			}
   313  
   314  			setups = append(setups, setup)
   315  			commits = append(commits, commit)
   316  			status.PreviousEpoch.SetupID = setup.ID()
   317  			status.PreviousEpoch.CommitID = commit.ID()
   318  		} else if !errors.Is(err, protocol.ErrNoPreviousEpoch) {
   319  			return fmt.Errorf("could not retrieve previous epoch: %w", err)
   320  		}
   321  
   322  		// insert current epoch - both setup and commit events must exist
   323  		setup, err := protocol.ToEpochSetup(current)
   324  		if err != nil {
   325  			return fmt.Errorf("could not get current epoch setup event: %w", err)
   326  		}
   327  		commit, err := protocol.ToEpochCommit(current)
   328  		if err != nil {
   329  			return fmt.Errorf("could not get current epoch commit event: %w", err)
   330  		}
   331  
   332  		if err := verifyEpochSetup(setup, verifyNetworkAddress); err != nil {
   333  			return fmt.Errorf("invalid setup: %w", err)
   334  		}
   335  
   336  		if err := isValidEpochCommit(commit, setup); err != nil {
   337  			return fmt.Errorf("invalid commit")
   338  		}
   339  
   340  		setups = append(setups, setup)
   341  		commits = append(commits, commit)
   342  		status.CurrentEpoch.SetupID = setup.ID()
   343  		status.CurrentEpoch.CommitID = commit.ID()
   344  
   345  		// insert next epoch, if it exists
   346  		_, err = next.Counter()
   347  		if err == nil {
   348  			// either only the setup event, or both the setup and commit events must exist
   349  			setup, err := protocol.ToEpochSetup(next)
   350  			if err != nil {
   351  				return fmt.Errorf("could not get next epoch setup event: %w", err)
   352  			}
   353  
   354  			if err := verifyEpochSetup(setup, verifyNetworkAddress); err != nil {
   355  				return fmt.Errorf("invalid setup: %w", err)
   356  			}
   357  
   358  			setups = append(setups, setup)
   359  			status.NextEpoch.SetupID = setup.ID()
   360  			commit, err := protocol.ToEpochCommit(next)
   361  			if err != nil && !errors.Is(err, protocol.ErrEpochNotCommitted) {
   362  				return fmt.Errorf("could not get next epoch commit event: %w", err)
   363  			}
   364  			if err == nil {
   365  				if err := isValidEpochCommit(commit, setup); err != nil {
   366  					return fmt.Errorf("invalid commit")
   367  				}
   368  				commits = append(commits, commit)
   369  				status.NextEpoch.CommitID = commit.ID()
   370  			}
   371  		} else if !errors.Is(err, protocol.ErrNextEpochNotSetup) {
   372  			return fmt.Errorf("could not get next epoch: %w", err)
   373  		}
   374  
   375  		// sanity check: ensure epoch status is valid
   376  		err = status.Check()
   377  		if err != nil {
   378  			return fmt.Errorf("bootstrapping resulting in invalid epoch status: %w", err)
   379  		}
   380  
   381  		// insert all epoch setup/commit service events
   382  		for _, setup := range setups {
   383  			err = state.epoch.setups.StoreTx(setup)(tx)
   384  			if err != nil {
   385  				return fmt.Errorf("could not store epoch setup event: %w", err)
   386  			}
   387  		}
   388  		for _, commit := range commits {
   389  			err = state.epoch.commits.StoreTx(commit)(tx)
   390  			if err != nil {
   391  				return fmt.Errorf("could not store epoch commit event: %w", err)
   392  			}
   393  		}
   394  
   395  		// NOTE: as specified in the godoc, this code assumes that each block
   396  		// in the sealing segment in within the same phase within the same epoch.
   397  		segment, err := root.SealingSegment()
   398  		if err != nil {
   399  			return fmt.Errorf("could not get sealing segment: %w", err)
   400  		}
   401  		for _, block := range segment.Blocks {
   402  			blockID := block.ID()
   403  			err = state.epoch.statuses.StoreTx(blockID, status)(tx)
   404  			if err != nil {
   405  				return fmt.Errorf("could not store epoch status for block (id=%x): %w", blockID, err)
   406  			}
   407  		}
   408  
   409  		return nil
   410  	}
   411  }
   412  
   413  // bootstrapSporkInfo bootstraps the protocol state with information about the
   414  // spork which is used to disambiguate Flow networks.
   415  func (state *State) bootstrapSporkInfo(root protocol.Snapshot) func(*badger.Txn) error {
   416  	return func(tx *badger.Txn) error {
   417  		params := root.Params()
   418  
   419  		sporkID, err := params.SporkID()
   420  		if err != nil {
   421  			return fmt.Errorf("could not get spork ID: %w", err)
   422  		}
   423  		err = operation.InsertSporkID(sporkID)(tx)
   424  		if err != nil {
   425  			return fmt.Errorf("could not insert spork ID: %w", err)
   426  		}
   427  
   428  		version, err := params.ProtocolVersion()
   429  		if err != nil {
   430  			return fmt.Errorf("could not get protocol version: %w", err)
   431  		}
   432  		err = operation.InsertProtocolVersion(version)(tx)
   433  		if err != nil {
   434  			return fmt.Errorf("could not insert protocol version: %w", err)
   435  		}
   436  
   437  		return nil
   438  	}
   439  }
   440  
   441  func OpenState(
   442  	metrics module.ComplianceMetrics,
   443  	db *badger.DB,
   444  	headers storage.Headers,
   445  	seals storage.Seals,
   446  	results storage.ExecutionResults,
   447  	blocks storage.Blocks,
   448  	setups storage.EpochSetups,
   449  	commits storage.EpochCommits,
   450  	statuses storage.EpochStatuses,
   451  ) (*State, error) {
   452  	isBootstrapped, err := IsBootstrapped(db)
   453  	if err != nil {
   454  		return nil, fmt.Errorf("failed to determine whether database contains bootstrapped state: %w", err)
   455  	}
   456  	if !isBootstrapped {
   457  		return nil, fmt.Errorf("expected database to contain bootstrapped state")
   458  	}
   459  	state := newState(metrics, db, headers, seals, results, blocks, setups, commits, statuses)
   460  
   461  	// report last finalized and sealed block height
   462  	finalSnapshot := state.Final()
   463  	head, err := finalSnapshot.Head()
   464  	if err != nil {
   465  		return nil, fmt.Errorf("unexpected error to get finalized block: %w", err)
   466  	}
   467  	metrics.FinalizedHeight(head.Height)
   468  
   469  	sealed, err := state.Sealed().Head()
   470  	if err != nil {
   471  		return nil, fmt.Errorf("could not get latest sealed block: %w", err)
   472  	}
   473  	metrics.SealedHeight(sealed.Height)
   474  
   475  	// update all epoch related metrics
   476  	err = state.updateEpochMetrics(finalSnapshot)
   477  	if err != nil {
   478  		return nil, fmt.Errorf("failed to update epoch metrics: %w", err)
   479  	}
   480  
   481  	return state, nil
   482  }
   483  
   484  func (state *State) Params() protocol.Params {
   485  	return &Params{state: state}
   486  }
   487  
   488  func (state *State) Sealed() protocol.Snapshot {
   489  	// retrieve the latest sealed height
   490  	var sealed uint64
   491  	err := state.db.View(operation.RetrieveSealedHeight(&sealed))
   492  	if err != nil {
   493  		// sealed height must always be set, all errors here are critical
   494  		return invalid.NewSnapshotf("could not retrieve sealed height: %w", err)
   495  	}
   496  	return state.AtHeight(sealed)
   497  }
   498  
   499  func (state *State) Final() protocol.Snapshot {
   500  	// retrieve the latest finalized height
   501  	var finalized uint64
   502  	err := state.db.View(operation.RetrieveFinalizedHeight(&finalized))
   503  	if err != nil {
   504  		// finalized height must always be set, so all errors here are critical
   505  		return invalid.NewSnapshot(fmt.Errorf("could not retrieve finalized height: %w", err))
   506  	}
   507  	return state.AtHeight(finalized)
   508  }
   509  
   510  func (state *State) AtHeight(height uint64) protocol.Snapshot {
   511  	// retrieve the block ID for the finalized height
   512  	var blockID flow.Identifier
   513  	err := state.db.View(operation.LookupBlockHeight(height, &blockID))
   514  	if errors.Is(err, storage.ErrNotFound) {
   515  		return invalid.NewSnapshotf("unknown finalized height %d: %w", height, statepkg.ErrUnknownSnapshotReference)
   516  	}
   517  	if err != nil {
   518  		// critical storage error
   519  		return invalid.NewSnapshotf("could not look up block by height: %w", err)
   520  	}
   521  	return state.AtBlockID(blockID)
   522  }
   523  
   524  func (state *State) AtBlockID(blockID flow.Identifier) protocol.Snapshot {
   525  	// TODO should return invalid.NewSnapshot(ErrUnknownSnapshotReference) if block doesn't exist
   526  	return NewSnapshot(state, blockID)
   527  }
   528  
   529  // newState initializes a new state backed by the provided a badger database,
   530  // mempools and service components.
   531  // The parameter `expectedBootstrappedState` indicates whether or not the database
   532  // is expected to contain a an already bootstrapped state or not
   533  func newState(
   534  	metrics module.ComplianceMetrics,
   535  	db *badger.DB,
   536  	headers storage.Headers,
   537  	seals storage.Seals,
   538  	results storage.ExecutionResults,
   539  	blocks storage.Blocks,
   540  	setups storage.EpochSetups,
   541  	commits storage.EpochCommits,
   542  	statuses storage.EpochStatuses,
   543  ) *State {
   544  	return &State{
   545  		metrics: metrics,
   546  		db:      db,
   547  		headers: headers,
   548  		results: results,
   549  		seals:   seals,
   550  		blocks:  blocks,
   551  		epoch: struct {
   552  			setups   storage.EpochSetups
   553  			commits  storage.EpochCommits
   554  			statuses storage.EpochStatuses
   555  		}{
   556  			setups:   setups,
   557  			commits:  commits,
   558  			statuses: statuses,
   559  		},
   560  	}
   561  }
   562  
   563  // IsBootstrapped returns whether or not the database contains a bootstrapped state
   564  func IsBootstrapped(db *badger.DB) (bool, error) {
   565  	var finalized uint64
   566  	err := db.View(operation.RetrieveFinalizedHeight(&finalized))
   567  	if errors.Is(err, storage.ErrNotFound) {
   568  		return false, nil
   569  	}
   570  	if err != nil {
   571  		return false, fmt.Errorf("retrieving finalized height failed: %w", err)
   572  	}
   573  	return true, nil
   574  }
   575  
   576  // updateEpochMetrics update the `consensus_compliance_current_epoch_counter` and the
   577  // `consensus_compliance_current_epoch_phase` metric
   578  func (state *State) updateEpochMetrics(snap protocol.Snapshot) error {
   579  
   580  	// update epoch counter
   581  	counter, err := snap.Epochs().Current().Counter()
   582  	if err != nil {
   583  		return fmt.Errorf("could not get current epoch counter: %w", err)
   584  	}
   585  	state.metrics.CurrentEpochCounter(counter)
   586  
   587  	// update epoch phase
   588  	phase, err := snap.Phase()
   589  	if err != nil {
   590  		return fmt.Errorf("could not get current epoch counter: %w", err)
   591  	}
   592  	state.metrics.CurrentEpochPhase(phase)
   593  
   594  	// update committed epoch final view
   595  	err = state.updateCommittedEpochFinalView(snap)
   596  	if err != nil {
   597  		return fmt.Errorf("could not update committed epoch final view")
   598  	}
   599  
   600  	currentEpochFinalView, err := snap.Epochs().Current().FinalView()
   601  	if err != nil {
   602  		return fmt.Errorf("could not update current epoch final view: %w", err)
   603  	}
   604  	state.metrics.CurrentEpochFinalView(currentEpochFinalView)
   605  
   606  	dkgPhase1FinalView, dkgPhase2FinalView, dkgPhase3FinalView, err := protocol.DKGPhaseViews(snap.Epochs().Current())
   607  	if err != nil {
   608  		return fmt.Errorf("could not get dkg phase final view: %w", err)
   609  	}
   610  
   611  	state.metrics.CurrentDKGPhase1FinalView(dkgPhase1FinalView)
   612  	state.metrics.CurrentDKGPhase2FinalView(dkgPhase2FinalView)
   613  	state.metrics.CurrentDKGPhase3FinalView(dkgPhase3FinalView)
   614  
   615  	// EECC - check whether the epoch emergency fallback flag has been set
   616  	// in the database. If so, skip updating any epoch-related metrics.
   617  	epochFallbackTriggered, err := state.isEpochEmergencyFallbackTriggered()
   618  	if err != nil {
   619  		return fmt.Errorf("could not check epoch emergency fallback flag: %w", err)
   620  	}
   621  	if epochFallbackTriggered {
   622  		state.metrics.EpochEmergencyFallbackTriggered()
   623  	}
   624  
   625  	return nil
   626  }
   627  
   628  // updateCommittedEpochFinalView updates the `committed_epoch_final_view` metric
   629  // based on the current epoch phase of the input snapshot. It should be called
   630  // at startup and during transitions between EpochSetup and EpochCommitted phases.
   631  //
   632  // For example, suppose we have epochs N and N+1.
   633  // If we are in epoch N's Staking or Setup Phase, then epoch N's final view should be the value of the metric.
   634  // If we are in epoch N's Committed Phase, then epoch N+1's final view should be the value of the metric.
   635  func (state *State) updateCommittedEpochFinalView(snap protocol.Snapshot) error {
   636  
   637  	phase, err := snap.Phase()
   638  	if err != nil {
   639  		return fmt.Errorf("could not get epoch phase: %w", err)
   640  	}
   641  
   642  	// update metric based of epoch phase
   643  	switch phase {
   644  	case flow.EpochPhaseStaking, flow.EpochPhaseSetup:
   645  
   646  		// if we are in Staking or Setup phase, then set the metric value to the current epoch's final view
   647  		finalView, err := snap.Epochs().Current().FinalView()
   648  		if err != nil {
   649  			return fmt.Errorf("could not get current epoch final view from snapshot: %w", err)
   650  		}
   651  		state.metrics.CommittedEpochFinalView(finalView)
   652  	case flow.EpochPhaseCommitted:
   653  
   654  		// if we are in Committed phase, then set the metric value to the next epoch's final view
   655  		finalView, err := snap.Epochs().Next().FinalView()
   656  		if err != nil {
   657  			return fmt.Errorf("could not get next epoch final view from snapshot: %w", err)
   658  		}
   659  		state.metrics.CommittedEpochFinalView(finalView)
   660  	default:
   661  		return fmt.Errorf("invalid phase: %s", phase)
   662  	}
   663  
   664  	return nil
   665  }
   666  
   667  func (m *State) isEpochEmergencyFallbackTriggered() (bool, error) {
   668  	var triggered bool
   669  	err := m.db.View(operation.CheckEpochEmergencyFallbackTriggered(&triggered))
   670  	return triggered, err
   671  }