github.com/onflow/flow-go@v0.33.17/state/protocol/badger/mutator.go (about)

     1  // (c) 2019 Dapper Labs - ALL RIGHTS RESERVED
     2  
     3  package badger
     4  
     5  import (
     6  	"context"
     7  	"errors"
     8  	"fmt"
     9  
    10  	"github.com/dgraph-io/badger/v2"
    11  	"github.com/rs/zerolog"
    12  
    13  	"github.com/onflow/flow-go/engine"
    14  	"github.com/onflow/flow-go/model/flow"
    15  	"github.com/onflow/flow-go/module"
    16  	"github.com/onflow/flow-go/module/irrecoverable"
    17  	"github.com/onflow/flow-go/module/signature"
    18  	"github.com/onflow/flow-go/module/trace"
    19  	"github.com/onflow/flow-go/state"
    20  	"github.com/onflow/flow-go/state/protocol"
    21  	"github.com/onflow/flow-go/storage"
    22  	"github.com/onflow/flow-go/storage/badger/operation"
    23  	"github.com/onflow/flow-go/storage/badger/procedure"
    24  	"github.com/onflow/flow-go/storage/badger/transaction"
    25  )
    26  
    27  // FollowerState implements a lighter version of a mutable protocol state.
    28  // When extending the state, it performs hardly any checks on the block payload.
    29  // Instead, the FollowerState relies on the consensus nodes to run the full
    30  // payload check and uses quorum certificates to prove validity of block payloads.
    31  // Consequently, a block B should only be considered valid, if
    32  // there is a certifying QC for that block QC.View == Block.View && QC.BlockID == Block.ID().
    33  //
    34  // The FollowerState allows non-consensus nodes to execute fork-aware queries
    35  // against the protocol state, while minimizing the amount of payload checks
    36  // the non-consensus nodes have to perform.
    37  type FollowerState struct {
    38  	*State
    39  
    40  	index      storage.Index
    41  	payloads   storage.Payloads
    42  	tracer     module.Tracer
    43  	logger     zerolog.Logger
    44  	consumer   protocol.Consumer
    45  	blockTimer protocol.BlockTimer
    46  }
    47  
    48  var _ protocol.FollowerState = (*FollowerState)(nil)
    49  
    50  // ParticipantState implements a mutable state for consensus participant. It can extend the
    51  // state with a new block, by checking the _entire_ block payload.
    52  type ParticipantState struct {
    53  	*FollowerState
    54  	receiptValidator module.ReceiptValidator
    55  	sealValidator    module.SealValidator
    56  }
    57  
    58  var _ protocol.ParticipantState = (*ParticipantState)(nil)
    59  
    60  // NewFollowerState initializes a light-weight version of a mutable protocol
    61  // state. This implementation is suitable only for NON-Consensus nodes.
    62  func NewFollowerState(
    63  	logger zerolog.Logger,
    64  	tracer module.Tracer,
    65  	consumer protocol.Consumer,
    66  	state *State,
    67  	index storage.Index,
    68  	payloads storage.Payloads,
    69  	blockTimer protocol.BlockTimer,
    70  ) (*FollowerState, error) {
    71  	followerState := &FollowerState{
    72  		State:      state,
    73  		index:      index,
    74  		payloads:   payloads,
    75  		tracer:     tracer,
    76  		logger:     logger,
    77  		consumer:   consumer,
    78  		blockTimer: blockTimer,
    79  	}
    80  	return followerState, nil
    81  }
    82  
    83  // NewFullConsensusState initializes a new mutable protocol state backed by a
    84  // badger database. When extending the state with a new block, it checks the
    85  // _entire_ block payload. Consensus nodes should use the FullConsensusState,
    86  // while other node roles can use the lighter FollowerState.
    87  func NewFullConsensusState(
    88  	logger zerolog.Logger,
    89  	tracer module.Tracer,
    90  	consumer protocol.Consumer,
    91  	state *State,
    92  	index storage.Index,
    93  	payloads storage.Payloads,
    94  	blockTimer protocol.BlockTimer,
    95  	receiptValidator module.ReceiptValidator,
    96  	sealValidator module.SealValidator,
    97  ) (*ParticipantState, error) {
    98  	followerState, err := NewFollowerState(
    99  		logger,
   100  		tracer,
   101  		consumer,
   102  		state,
   103  		index,
   104  		payloads,
   105  		blockTimer,
   106  	)
   107  	if err != nil {
   108  		return nil, fmt.Errorf("initialization of Mutable Follower State failed: %w", err)
   109  	}
   110  	return &ParticipantState{
   111  		FollowerState:    followerState,
   112  		receiptValidator: receiptValidator,
   113  		sealValidator:    sealValidator,
   114  	}, nil
   115  }
   116  
   117  // ExtendCertified extends the protocol state of a CONSENSUS FOLLOWER. While it checks
   118  // the validity of the header; it does _not_ check the validity of the payload.
   119  // Instead, the consensus follower relies on the consensus participants to
   120  // validate the full payload. Payload validity can be proved by a valid quorum certificate.
   121  // Certifying QC must match candidate block:
   122  //
   123  //	candidate.View == certifyingQC.View && candidate.ID() == certifyingQC.BlockID
   124  //
   125  // Caution:
   126  //   - This function expects that `certifyingQC` has been validated.
   127  //   - The parent block must already be stored.
   128  //
   129  // No errors are expected during normal operations.
   130  func (m *FollowerState) ExtendCertified(ctx context.Context, candidate *flow.Block, certifyingQC *flow.QuorumCertificate) error {
   131  	span, ctx := m.tracer.StartSpanFromContext(ctx, trace.ProtoStateMutatorHeaderExtend)
   132  	defer span.End()
   133  
   134  	// check if candidate block has been already processed
   135  	blockID := candidate.ID()
   136  	isDuplicate, err := m.checkBlockAlreadyProcessed(blockID)
   137  	if err != nil || isDuplicate {
   138  		return err
   139  	}
   140  
   141  	// sanity check if certifyingQC actually certifies candidate block
   142  	if certifyingQC.View != candidate.Header.View {
   143  		return fmt.Errorf("qc doesn't certify candidate block, expect %d view, got %d", candidate.Header.View, certifyingQC.View)
   144  	}
   145  	if certifyingQC.BlockID != blockID {
   146  		return fmt.Errorf("qc doesn't certify candidate block, expect %x blockID, got %x", blockID, certifyingQC.BlockID)
   147  	}
   148  
   149  	// check if the block header is a valid extension of parent block
   150  	err = m.headerExtend(candidate)
   151  	if err != nil {
   152  		// since we have a QC for this block, it cannot be an invalid extension
   153  		return fmt.Errorf("unexpected invalid block (id=%x) with certifying qc (id=%x): %s",
   154  			candidate.ID(), certifyingQC.ID(), err.Error())
   155  	}
   156  
   157  	// find the last seal at the parent block
   158  	last, err := m.lastSealed(candidate)
   159  	if err != nil {
   160  		return fmt.Errorf("payload seal(s) not compliant with chain state: %w", err)
   161  	}
   162  
   163  	// insert the block, certifying QC and index the last seal for the block
   164  	err = m.insert(ctx, candidate, certifyingQC, last)
   165  	if err != nil {
   166  		return fmt.Errorf("failed to insert the block: %w", err)
   167  	}
   168  
   169  	return nil
   170  }
   171  
   172  // Extend extends the protocol state of a CONSENSUS PARTICIPANT. It checks
   173  // the validity of the _entire block_ (header and full payload).
   174  // Expected errors during normal operations:
   175  //   - state.OutdatedExtensionError if the candidate block is outdated (e.g. orphaned)
   176  //   - state.InvalidExtensionError if the candidate block is invalid
   177  func (m *ParticipantState) Extend(ctx context.Context, candidate *flow.Block) error {
   178  	span, ctx := m.tracer.StartSpanFromContext(ctx, trace.ProtoStateMutatorExtend)
   179  	defer span.End()
   180  
   181  	// check if candidate block has been already processed
   182  	isDuplicate, err := m.checkBlockAlreadyProcessed(candidate.ID())
   183  	if err != nil || isDuplicate {
   184  		return err
   185  	}
   186  
   187  	// check if the block header is a valid extension of parent block
   188  	err = m.headerExtend(candidate)
   189  	if err != nil {
   190  		return fmt.Errorf("header not compliant with chain state: %w", err)
   191  	}
   192  
   193  	// check if the block header is a valid extension of the finalized state
   194  	err = m.checkOutdatedExtension(candidate.Header)
   195  	if err != nil {
   196  		if state.IsOutdatedExtensionError(err) {
   197  			return fmt.Errorf("candidate block is an outdated extension: %w", err)
   198  		}
   199  		return fmt.Errorf("could not check if block is an outdated extension: %w", err)
   200  	}
   201  
   202  	// check if the guarantees in the payload is a valid extension of the finalized state
   203  	err = m.guaranteeExtend(ctx, candidate)
   204  	if err != nil {
   205  		return fmt.Errorf("payload guarantee(s) not compliant with chain state: %w", err)
   206  	}
   207  
   208  	// check if the receipts in the payload are valid
   209  	err = m.receiptExtend(ctx, candidate)
   210  	if err != nil {
   211  		return fmt.Errorf("payload receipt(s) not compliant with chain state: %w", err)
   212  	}
   213  
   214  	// check if the seals in the payload is a valid extension of the finalized state
   215  	lastSeal, err := m.sealExtend(ctx, candidate)
   216  	if err != nil {
   217  		return fmt.Errorf("payload seal(s) not compliant with chain state: %w", err)
   218  	}
   219  
   220  	// insert the block and index the last seal for the block
   221  	err = m.insert(ctx, candidate, nil, lastSeal)
   222  	if err != nil {
   223  		return fmt.Errorf("failed to insert the block: %w", err)
   224  	}
   225  
   226  	return nil
   227  }
   228  
   229  // headerExtend verifies the validity of the block header (excluding verification of the
   230  // consensus rules). Specifically, we check that the block connects to the last finalized block.
   231  // Expected errors during normal operations:
   232  //   - state.InvalidExtensionError if the candidate block is invalid
   233  func (m *FollowerState) headerExtend(candidate *flow.Block) error {
   234  	// FIRST: We do some initial cheap sanity checks, like checking the payload
   235  	// hash is consistent
   236  
   237  	header := candidate.Header
   238  	payload := candidate.Payload
   239  	if payload.Hash() != header.PayloadHash {
   240  		return state.NewInvalidExtensionError("payload integrity check failed")
   241  	}
   242  
   243  	// SECOND: Next, we can check whether the block is a valid descendant of the
   244  	// parent. It should have the same chain ID and a height that is one bigger.
   245  
   246  	parent, err := m.headers.ByBlockID(header.ParentID)
   247  	if err != nil {
   248  		return state.NewInvalidExtensionErrorf("could not retrieve parent: %s", err)
   249  	}
   250  	if header.ChainID != parent.ChainID {
   251  		return state.NewInvalidExtensionErrorf("candidate built for invalid chain (candidate: %s, parent: %s)",
   252  			header.ChainID, parent.ChainID)
   253  	}
   254  	if header.ParentView != parent.View {
   255  		return state.NewInvalidExtensionErrorf("candidate build with inconsistent parent view (candidate: %d, parent %d)",
   256  			header.ParentView, parent.View)
   257  	}
   258  	if header.Height != parent.Height+1 {
   259  		return state.NewInvalidExtensionErrorf("candidate built with invalid height (candidate: %d, parent: %d)",
   260  			header.Height, parent.Height)
   261  	}
   262  
   263  	// check validity of block timestamp using parent's timestamp
   264  	err = m.blockTimer.Validate(parent.Timestamp, candidate.Header.Timestamp)
   265  	if err != nil {
   266  		if protocol.IsInvalidBlockTimestampError(err) {
   267  			return state.NewInvalidExtensionErrorf("candidate contains invalid timestamp: %w", err)
   268  		}
   269  		return fmt.Errorf("validating block's time stamp failed with unexpected error: %w", err)
   270  	}
   271  
   272  	return nil
   273  }
   274  
   275  // checkBlockAlreadyProcessed checks if block has been added to the protocol state.
   276  // Returns:
   277  // * (true, nil) - block has been already processed.
   278  // * (false, nil) - block has not been processed.
   279  // * (false, error) - unknown error when trying to query protocol state.
   280  // No errors are expected during normal operation.
   281  func (m *FollowerState) checkBlockAlreadyProcessed(blockID flow.Identifier) (bool, error) {
   282  	_, err := m.headers.ByBlockID(blockID)
   283  	if err != nil {
   284  		if errors.Is(err, storage.ErrNotFound) {
   285  			return false, nil
   286  		}
   287  		return false, fmt.Errorf("could not check if candidate block (%x) has been already processed: %w", blockID, err)
   288  	}
   289  	return true, nil
   290  }
   291  
   292  // checkOutdatedExtension checks whether given block is
   293  // valid in the context of the entire state. For this, the block needs to
   294  // directly connect, through its ancestors, to the last finalized block.
   295  // Expected errors during normal operations:
   296  //   - state.OutdatedExtensionError if the candidate block is outdated (e.g. orphaned)
   297  func (m *ParticipantState) checkOutdatedExtension(header *flow.Header) error {
   298  	var finalizedHeight uint64
   299  	err := m.db.View(operation.RetrieveFinalizedHeight(&finalizedHeight))
   300  	if err != nil {
   301  		return fmt.Errorf("could not retrieve finalized height: %w", err)
   302  	}
   303  	var finalID flow.Identifier
   304  	err = m.db.View(operation.LookupBlockHeight(finalizedHeight, &finalID))
   305  	if err != nil {
   306  		return fmt.Errorf("could not lookup finalized block: %w", err)
   307  	}
   308  
   309  	ancestorID := header.ParentID
   310  	for ancestorID != finalID {
   311  		ancestor, err := m.headers.ByBlockID(ancestorID)
   312  		if err != nil {
   313  			return fmt.Errorf("could not retrieve ancestor (%x): %w", ancestorID, err)
   314  		}
   315  		if ancestor.Height < finalizedHeight {
   316  			// this happens when the candidate block is on a fork that does not include all the
   317  			// finalized blocks.
   318  			// for instance:
   319  			// A (Finalized) <- B (Finalized) <- C (Finalized) <- D <- E <- F
   320  			//                  ^- G             ^- H             ^- I
   321  			// block G is not a valid block, because it does not have C (which has been finalized) as an ancestor
   322  			// block H and I are valid, because they do have C as an ancestor
   323  			return state.NewOutdatedExtensionErrorf(
   324  				"candidate block (height: %d) conflicts with finalized state (ancestor: %d final: %d)",
   325  				header.Height, ancestor.Height, finalizedHeight)
   326  		}
   327  		ancestorID = ancestor.ParentID
   328  	}
   329  	return nil
   330  }
   331  
   332  // guaranteeExtend verifies the validity of the collection guarantees that are
   333  // included in the block. Specifically, we check for expired collections and
   334  // duplicated collections (also including ancestor blocks).
   335  func (m *ParticipantState) guaranteeExtend(ctx context.Context, candidate *flow.Block) error {
   336  
   337  	span, _ := m.tracer.StartSpanFromContext(ctx, trace.ProtoStateMutatorExtendCheckGuarantees)
   338  	defer span.End()
   339  
   340  	header := candidate.Header
   341  	payload := candidate.Payload
   342  
   343  	// we only look as far back for duplicates as the transaction expiry limit;
   344  	// if a guarantee was included before that, we will disqualify it on the
   345  	// basis of the reference block anyway
   346  	limit := header.Height - flow.DefaultTransactionExpiry
   347  	if limit > header.Height { // overflow check
   348  		limit = 0
   349  	}
   350  	if limit < m.sporkRootBlockHeight {
   351  		limit = m.sporkRootBlockHeight
   352  	}
   353  
   354  	// build a list of all previously used guarantees on this part of the chain
   355  	ancestorID := header.ParentID
   356  	lookup := make(map[flow.Identifier]struct{})
   357  	for {
   358  		ancestor, err := m.headers.ByBlockID(ancestorID)
   359  		if err != nil {
   360  			return fmt.Errorf("could not retrieve ancestor header (%x): %w", ancestorID, err)
   361  		}
   362  		index, err := m.index.ByBlockID(ancestorID)
   363  		if err != nil {
   364  			return fmt.Errorf("could not retrieve ancestor index (%x): %w", ancestorID, err)
   365  		}
   366  		for _, collID := range index.CollectionIDs {
   367  			lookup[collID] = struct{}{}
   368  		}
   369  		if ancestor.Height <= limit {
   370  			break
   371  		}
   372  		ancestorID = ancestor.ParentID
   373  	}
   374  
   375  	// check each guarantee included in the payload for duplication and expiry
   376  	for _, guarantee := range payload.Guarantees {
   377  
   378  		// if the guarantee was already included before, error
   379  		_, duplicated := lookup[guarantee.ID()]
   380  		if duplicated {
   381  			return state.NewInvalidExtensionErrorf("payload includes duplicate guarantee (%x)", guarantee.ID())
   382  		}
   383  
   384  		// get the reference block to check expiry
   385  		ref, err := m.headers.ByBlockID(guarantee.ReferenceBlockID)
   386  		if err != nil {
   387  			if errors.Is(err, storage.ErrNotFound) {
   388  				return state.NewInvalidExtensionErrorf("could not get reference block %x: %w", guarantee.ReferenceBlockID, err)
   389  			}
   390  			return fmt.Errorf("could not get reference block (%x): %w", guarantee.ReferenceBlockID, err)
   391  		}
   392  
   393  		// if the guarantee references a block with expired height, error
   394  		if ref.Height < limit {
   395  			return state.NewInvalidExtensionErrorf("payload includes expired guarantee (height: %d, limit: %d)",
   396  				ref.Height, limit)
   397  		}
   398  
   399  		// check the guarantors are correct
   400  		_, err = protocol.FindGuarantors(m, guarantee)
   401  		if err != nil {
   402  			if signature.IsInvalidSignerIndicesError(err) ||
   403  				errors.Is(err, protocol.ErrNextEpochNotCommitted) ||
   404  				errors.Is(err, protocol.ErrClusterNotFound) {
   405  				return state.NewInvalidExtensionErrorf("guarantee %v contains invalid guarantors: %w", guarantee.ID(), err)
   406  			}
   407  			return fmt.Errorf("could not find guarantor for guarantee %v: %w", guarantee.ID(), err)
   408  		}
   409  	}
   410  
   411  	return nil
   412  }
   413  
   414  // sealExtend checks the compliance of the payload seals. Returns last seal that form a chain for
   415  // candidate block.
   416  func (m *ParticipantState) sealExtend(ctx context.Context, candidate *flow.Block) (*flow.Seal, error) {
   417  
   418  	span, _ := m.tracer.StartSpanFromContext(ctx, trace.ProtoStateMutatorExtendCheckSeals)
   419  	defer span.End()
   420  
   421  	lastSeal, err := m.sealValidator.Validate(candidate)
   422  	if err != nil {
   423  		return nil, state.NewInvalidExtensionErrorf("seal validation error: %w", err)
   424  	}
   425  
   426  	return lastSeal, nil
   427  }
   428  
   429  // receiptExtend checks the compliance of the receipt payload.
   430  //   - Receipts should pertain to blocks on the fork
   431  //   - Receipts should not appear more than once on a fork
   432  //   - Receipts should pass the ReceiptValidator check
   433  //   - No seal has been included for the respective block in this particular fork
   434  //
   435  // We require the receipts to be sorted by block height (within a payload).
   436  func (m *ParticipantState) receiptExtend(ctx context.Context, candidate *flow.Block) error {
   437  
   438  	span, _ := m.tracer.StartSpanFromContext(ctx, trace.ProtoStateMutatorExtendCheckReceipts)
   439  	defer span.End()
   440  
   441  	err := m.receiptValidator.ValidatePayload(candidate)
   442  	if err != nil {
   443  		// TODO: this might be not an error, potentially it can be solved by requesting more data and processing this receipt again
   444  		if errors.Is(err, storage.ErrNotFound) {
   445  			return state.NewInvalidExtensionErrorf("some entities referenced by receipts are missing: %w", err)
   446  		}
   447  		if engine.IsInvalidInputError(err) {
   448  			return state.NewInvalidExtensionErrorf("payload includes invalid receipts: %w", err)
   449  		}
   450  		return fmt.Errorf("unexpected payload validation error %w", err)
   451  	}
   452  
   453  	return nil
   454  }
   455  
   456  // lastSealed returns the highest sealed block from the fork with head `candidate`.
   457  // For instance, here is the chain state: block 100 is the head, block 97 is finalized,
   458  // and 95 is the last sealed block at the state of block 100.
   459  // 95 (sealed) <- 96 <- 97 (finalized) <- 98 <- 99 <- 100
   460  // Now, if block 101 is extending block 100, and its payload has a seal for 96, then it will
   461  // be the last sealed for block 101.
   462  // No errors are expected during normal operation.
   463  func (m *FollowerState) lastSealed(candidate *flow.Block) (*flow.Seal, error) {
   464  	header := candidate.Header
   465  	payload := candidate.Payload
   466  
   467  	// getting the last sealed block
   468  	last, err := m.seals.HighestInFork(header.ParentID)
   469  	if err != nil {
   470  		return nil, fmt.Errorf("could not retrieve parent seal (%x): %w", header.ParentID, err)
   471  	}
   472  
   473  	// if the payload of the block has no seals, then the last seal is the seal for the highest block
   474  	if len(payload.Seals) == 0 {
   475  		return last, nil
   476  	}
   477  
   478  	ordered, err := protocol.OrderedSeals(payload, m.headers)
   479  	if err != nil {
   480  		// all errors are unexpected - differentiation is for clearer error messages
   481  		if errors.Is(err, storage.ErrNotFound) {
   482  			return nil, fmt.Errorf("ordering seals: candidate payload contains seals for unknown block: %s", err.Error())
   483  		}
   484  		if errors.Is(err, protocol.ErrDiscontinuousSeals) || errors.Is(err, protocol.ErrMultipleSealsForSameHeight) {
   485  			return nil, fmt.Errorf("ordering seals: candidate payload contains invalid seal set: %s", err.Error())
   486  		}
   487  		return nil, fmt.Errorf("unexpected error ordering seals: %w", err)
   488  	}
   489  	return ordered[len(ordered)-1], nil
   490  }
   491  
   492  // insert stores the candidate block in the database.
   493  // The `candidate` block _must be valid_ (otherwise, the state will be corrupted).
   494  // dbUpdates contains other database operations which must be applied atomically
   495  // with inserting the block.
   496  // Caller is responsible for ensuring block validity.
   497  // If insert is called from Extend(by consensus participant) then certifyingQC will be nil but the block payload will be validated.
   498  // If insert is called from ExtendCertified(by consensus follower) then certifyingQC must be not nil which proves payload validity.
   499  // No errors are expected during normal operations.
   500  func (m *FollowerState) insert(ctx context.Context, candidate *flow.Block, certifyingQC *flow.QuorumCertificate, last *flow.Seal) error {
   501  	span, _ := m.tracer.StartSpanFromContext(ctx, trace.ProtoStateMutatorExtendDBInsert)
   502  	defer span.End()
   503  
   504  	blockID := candidate.ID()
   505  	parentID := candidate.Header.ParentID
   506  	latestSealID := last.ID()
   507  
   508  	parent, err := m.headers.ByBlockID(parentID)
   509  	if err != nil {
   510  		return fmt.Errorf("could not retrieve block header for %x: %w", parentID, err)
   511  	}
   512  
   513  	// apply any state changes from service events sealed by this block's parent
   514  	dbUpdates, err := m.handleEpochServiceEvents(candidate)
   515  	if err != nil {
   516  		return fmt.Errorf("could not process service events: %w", err)
   517  	}
   518  
   519  	qc := candidate.Header.QuorumCertificate()
   520  
   521  	var events []func()
   522  
   523  	// Both the header itself and its payload are in compliance with the protocol state.
   524  	// We can now store the candidate block, as well as adding its final seal
   525  	// to the seal index and initializing its children index.
   526  	err = operation.RetryOnConflictTx(m.db, transaction.Update, func(tx *transaction.Tx) error {
   527  		// insert the block into the database AND cache
   528  		err := m.blocks.StoreTx(candidate)(tx)
   529  		if err != nil {
   530  			return fmt.Errorf("could not store candidate block: %w", err)
   531  		}
   532  
   533  		err = m.qcs.StoreTx(qc)(tx)
   534  		if err != nil {
   535  			if !errors.Is(err, storage.ErrAlreadyExists) {
   536  				return fmt.Errorf("could not store incorporated qc: %w", err)
   537  			}
   538  		} else {
   539  			// trigger BlockProcessable for parent blocks above root height
   540  			if parent.Height > m.finalizedRootHeight {
   541  				events = append(events, func() {
   542  					m.consumer.BlockProcessable(parent, qc)
   543  				})
   544  			}
   545  		}
   546  
   547  		if certifyingQC != nil {
   548  			err = m.qcs.StoreTx(certifyingQC)(tx)
   549  			if err != nil {
   550  				return fmt.Errorf("could not store certifying qc: %w", err)
   551  			}
   552  
   553  			// trigger BlockProcessable for candidate block if it's certified
   554  			events = append(events, func() {
   555  				m.consumer.BlockProcessable(candidate.Header, certifyingQC)
   556  			})
   557  		}
   558  
   559  		// index the latest sealed block in this fork
   560  		err = transaction.WithTx(operation.IndexLatestSealAtBlock(blockID, latestSealID))(tx)
   561  		if err != nil {
   562  			return fmt.Errorf("could not index candidate seal: %w", err)
   563  		}
   564  
   565  		// index the child block for recovery
   566  		err = transaction.WithTx(procedure.IndexNewBlock(blockID, candidate.Header.ParentID))(tx)
   567  		if err != nil {
   568  			return fmt.Errorf("could not index new block: %w", err)
   569  		}
   570  
   571  		// apply any optional DB operations from service events
   572  		for _, apply := range dbUpdates {
   573  			err := apply(tx)
   574  			if err != nil {
   575  				return fmt.Errorf("could not apply operation: %w", err)
   576  			}
   577  		}
   578  
   579  		return nil
   580  	})
   581  	if err != nil {
   582  		return fmt.Errorf("could not execute state extension: %w", err)
   583  	}
   584  
   585  	// execute scheduled events
   586  	for _, event := range events {
   587  		event()
   588  	}
   589  
   590  	return nil
   591  }
   592  
   593  // Finalize marks the specified block as finalized.
   594  // This method only finalizes one block at a time.
   595  // Hence, the parent of `blockID` has to be the last finalized block.
   596  // No errors are expected during normal operations.
   597  func (m *FollowerState) Finalize(ctx context.Context, blockID flow.Identifier) error {
   598  
   599  	// preliminaries: start tracer and retrieve full block
   600  	span, _ := m.tracer.StartSpanFromContext(ctx, trace.ProtoStateMutatorFinalize)
   601  	defer span.End()
   602  	block, err := m.blocks.ByID(blockID)
   603  	if err != nil {
   604  		return fmt.Errorf("could not retrieve full block that should be finalized: %w", err)
   605  	}
   606  	header := block.Header
   607  
   608  	// keep track of metrics updates and protocol events to emit:
   609  	// * metrics are updated after a successful database update
   610  	// * protocol events are emitted atomically with the database update
   611  	var metrics []func()
   612  	var events []func()
   613  
   614  	// Verify that the parent block is the latest finalized block.
   615  	// this must be the case, as the `Finalize` method only finalizes one block
   616  	// at a time and hence the parent of `blockID` must already be finalized.
   617  	var finalized uint64
   618  	err = m.db.View(operation.RetrieveFinalizedHeight(&finalized))
   619  	if err != nil {
   620  		return fmt.Errorf("could not retrieve finalized height: %w", err)
   621  	}
   622  	var finalID flow.Identifier
   623  	err = m.db.View(operation.LookupBlockHeight(finalized, &finalID))
   624  	if err != nil {
   625  		return fmt.Errorf("could not retrieve final header: %w", err)
   626  	}
   627  	if header.ParentID != finalID {
   628  		return fmt.Errorf("can only finalize child of last finalized block")
   629  	}
   630  
   631  	// We also want to update the last sealed height. Retrieve the block
   632  	// seal indexed for the block and retrieve the block that was sealed by it.
   633  	lastSeal, err := m.seals.HighestInFork(blockID)
   634  	if err != nil {
   635  		return fmt.Errorf("could not look up sealed header: %w", err)
   636  	}
   637  	sealed, err := m.headers.ByBlockID(lastSeal.BlockID)
   638  	if err != nil {
   639  		return fmt.Errorf("could not retrieve sealed header: %w", err)
   640  	}
   641  
   642  	// We update metrics and emit protocol events for epoch state changes when
   643  	// the block corresponding to the state change is finalized
   644  	epochStatus, err := m.epoch.statuses.ByBlockID(blockID)
   645  	if err != nil {
   646  		return fmt.Errorf("could not retrieve epoch state: %w", err)
   647  	}
   648  	currentEpochSetup, err := m.epoch.setups.ByID(epochStatus.CurrentEpoch.SetupID)
   649  	if err != nil {
   650  		return fmt.Errorf("could not retrieve setup event for current epoch: %w", err)
   651  	}
   652  	epochFallbackTriggered, err := m.isEpochEmergencyFallbackTriggered()
   653  	if err != nil {
   654  		return fmt.Errorf("could not check persisted epoch emergency fallback flag: %w", err)
   655  	}
   656  
   657  	// if epoch fallback was not previously triggered, check whether this block triggers it
   658  	if !epochFallbackTriggered {
   659  		epochFallbackTriggered, err = m.epochFallbackTriggeredByFinalizedBlock(header, epochStatus, currentEpochSetup)
   660  		if err != nil {
   661  			return fmt.Errorf("could not check whether finalized block triggers epoch fallback: %w", err)
   662  		}
   663  		if epochFallbackTriggered {
   664  			// emit the protocol event only the first time epoch fallback is triggered
   665  			events = append(events, m.consumer.EpochEmergencyFallbackTriggered)
   666  			metrics = append(metrics, m.metrics.EpochEmergencyFallbackTriggered)
   667  		}
   668  	}
   669  
   670  	isFirstBlockOfEpoch, err := m.isFirstBlockOfEpoch(header, currentEpochSetup)
   671  	if err != nil {
   672  		return fmt.Errorf("could not check if block is first of epoch: %w", err)
   673  	}
   674  
   675  	// Determine metric updates and protocol events related to epoch phase
   676  	// changes and epoch transitions.
   677  	// If epoch emergency fallback is triggered, the current epoch continues until
   678  	// the next spork - so skip these updates.
   679  	if !epochFallbackTriggered {
   680  		epochPhaseMetrics, epochPhaseEvents, err := m.epochPhaseMetricsAndEventsOnBlockFinalized(block, epochStatus)
   681  		if err != nil {
   682  			return fmt.Errorf("could not determine epoch phase metrics/events for finalized block: %w", err)
   683  		}
   684  		metrics = append(metrics, epochPhaseMetrics...)
   685  		events = append(events, epochPhaseEvents...)
   686  
   687  		if isFirstBlockOfEpoch {
   688  			epochTransitionMetrics, epochTransitionEvents := m.epochTransitionMetricsAndEventsOnBlockFinalized(header, currentEpochSetup)
   689  			if err != nil {
   690  				return fmt.Errorf("could not determine epoch transition metrics/events for finalized block: %w", err)
   691  			}
   692  			metrics = append(metrics, epochTransitionMetrics...)
   693  			events = append(events, epochTransitionEvents...)
   694  		}
   695  	}
   696  
   697  	// Extract and validate version beacon events from the block seals.
   698  	versionBeacons, err := m.versionBeaconOnBlockFinalized(block)
   699  	if err != nil {
   700  		return fmt.Errorf("cannot process version beacon: %w", err)
   701  	}
   702  
   703  	// Persist updates in database
   704  	// * Add this block to the height-indexed set of finalized blocks.
   705  	// * Update the largest finalized height to this block's height.
   706  	// * Update the largest height of sealed and finalized block.
   707  	//   This value could actually stay the same if it has no seals in
   708  	//   its payload, in which case the parent's seal is the same.
   709  	// * set the epoch fallback flag, if it is triggered
   710  	err = operation.RetryOnConflict(m.db.Update, func(tx *badger.Txn) error {
   711  		err = operation.IndexBlockHeight(header.Height, blockID)(tx)
   712  		if err != nil {
   713  			return fmt.Errorf("could not insert number mapping: %w", err)
   714  		}
   715  		err = operation.UpdateFinalizedHeight(header.Height)(tx)
   716  		if err != nil {
   717  			return fmt.Errorf("could not update finalized height: %w", err)
   718  		}
   719  		err = operation.UpdateSealedHeight(sealed.Height)(tx)
   720  		if err != nil {
   721  			return fmt.Errorf("could not update sealed height: %w", err)
   722  		}
   723  		if epochFallbackTriggered {
   724  			err = operation.SetEpochEmergencyFallbackTriggered(blockID)(tx)
   725  			if err != nil {
   726  				return fmt.Errorf("could not set epoch fallback flag: %w", err)
   727  			}
   728  		}
   729  		if isFirstBlockOfEpoch && !epochFallbackTriggered {
   730  			err = operation.InsertEpochFirstHeight(currentEpochSetup.Counter, header.Height)(tx)
   731  			if err != nil {
   732  				return fmt.Errorf("could not insert epoch first block height: %w", err)
   733  			}
   734  		}
   735  
   736  		// When a block is finalized, we commit the result for each seal it contains. The sealing logic
   737  		// guarantees that only a single, continuous execution fork is sealed. Here, we index for
   738  		// each block ID the ID of its _finalized_ seal.
   739  		for _, seal := range block.Payload.Seals {
   740  			err = operation.IndexFinalizedSealByBlockID(seal.BlockID, seal.ID())(tx)
   741  			if err != nil {
   742  				return fmt.Errorf("could not index the seal by the sealed block ID: %w", err)
   743  			}
   744  		}
   745  
   746  		if len(versionBeacons) > 0 {
   747  			// only index the last version beacon as that is the relevant one.
   748  			// TODO: The other version beacons can be used for validation.
   749  			err := operation.IndexVersionBeaconByHeight(versionBeacons[len(versionBeacons)-1])(tx)
   750  			if err != nil {
   751  				return fmt.Errorf("could not index version beacon or height (%d): %w", header.Height, err)
   752  			}
   753  		}
   754  
   755  		return nil
   756  	})
   757  	if err != nil {
   758  		return fmt.Errorf("could not persist finalization operations for block (%x): %w", blockID, err)
   759  	}
   760  
   761  	// update the cache
   762  	m.State.cachedFinal.Store(&cachedHeader{blockID, header})
   763  	if len(block.Payload.Seals) > 0 {
   764  		m.State.cachedSealed.Store(&cachedHeader{lastSeal.BlockID, sealed})
   765  	}
   766  
   767  	// Emit protocol events after database transaction succeeds. Event delivery is guaranteed,
   768  	// _except_ in case of a crash. Hence, when recovering from a crash, consumers need to deduce
   769  	// from the state whether they have missed events and re-execute the respective actions.
   770  	m.consumer.BlockFinalized(header)
   771  	for _, emit := range events {
   772  		emit()
   773  	}
   774  
   775  	// update sealed/finalized block metrics
   776  	m.metrics.FinalizedHeight(header.Height)
   777  	m.metrics.SealedHeight(sealed.Height)
   778  	m.metrics.BlockFinalized(block)
   779  	for _, seal := range block.Payload.Seals {
   780  		sealedBlock, err := m.blocks.ByID(seal.BlockID)
   781  		if err != nil {
   782  			return fmt.Errorf("could not retrieve sealed block (%x): %w", seal.BlockID, err)
   783  		}
   784  		m.metrics.BlockSealed(sealedBlock)
   785  	}
   786  
   787  	// apply all queued metrics
   788  	for _, updateMetric := range metrics {
   789  		updateMetric()
   790  	}
   791  
   792  	return nil
   793  }
   794  
   795  // epochFallbackTriggeredByFinalizedBlock checks whether finalizing the input block
   796  // would trigger epoch emergency fallback mode. In particular, we trigger epoch
   797  // fallback mode while finalizing block B in either of the following cases:
   798  //  1. B is the head of a fork in which epoch fallback was tentatively triggered,
   799  //     due to incorporating an invalid service event.
   800  //  2. (a) B is the first finalized block with view greater than or equal to the epoch
   801  //     commitment deadline for the current epoch AND
   802  //     (b) the next epoch has not been committed as of B.
   803  //
   804  // This function should only be called when epoch fallback *has not already been triggered*.
   805  // See protocol.Params for more details on the epoch commitment deadline.
   806  //
   807  // No errors are expected during normal operation.
   808  func (m *FollowerState) epochFallbackTriggeredByFinalizedBlock(block *flow.Header, epochStatus *flow.EpochStatus, currentEpochSetup *flow.EpochSetup) (bool, error) {
   809  	// 1. Epoch fallback is tentatively triggered on this fork
   810  	if epochStatus.InvalidServiceEventIncorporated {
   811  		return true, nil
   812  	}
   813  
   814  	// 2.(a) determine whether block B is past the epoch commitment deadline
   815  	safetyThreshold, err := m.Params().EpochCommitSafetyThreshold()
   816  	if err != nil {
   817  		return false, fmt.Errorf("could not get epoch commit safety threshold: %w", err)
   818  	}
   819  	blockExceedsDeadline := block.View+safetyThreshold >= currentEpochSetup.FinalView
   820  
   821  	// 2.(b) determine whether the next epoch is committed w.r.t. block B
   822  	currentEpochPhase, err := epochStatus.Phase()
   823  	if err != nil {
   824  		return false, fmt.Errorf("could not get current epoch phase: %w", err)
   825  	}
   826  	isNextEpochCommitted := currentEpochPhase == flow.EpochPhaseCommitted
   827  
   828  	blockTriggersEpochFallback := blockExceedsDeadline && !isNextEpochCommitted
   829  	return blockTriggersEpochFallback, nil
   830  }
   831  
   832  // isFirstBlockOfEpoch returns true if the given block is the first block of a new epoch.
   833  // We accept the EpochSetup event for the current epoch (w.r.t. input block B) which contains
   834  // the FirstView for the epoch (denoted W). By construction, B.View >= W.
   835  // Definition: B is the first block of the epoch if and only if B.parent.View < W
   836  //
   837  // NOTE: There can be multiple (un-finalized) blocks that qualify as the first block of epoch N.
   838  // No errors are expected during normal operation.
   839  func (m *FollowerState) isFirstBlockOfEpoch(block *flow.Header, currentEpochSetup *flow.EpochSetup) (bool, error) {
   840  	currentEpochFirstView := currentEpochSetup.FirstView
   841  	// sanity check: B.View >= W
   842  	if block.View < currentEpochFirstView {
   843  		return false, irrecoverable.NewExceptionf("data inconsistency: block (id=%x, view=%d) is below its epoch first view %d", block.ID(), block.View, currentEpochFirstView)
   844  	}
   845  
   846  	parent, err := m.headers.ByBlockID(block.ParentID)
   847  	if err != nil {
   848  		return false, irrecoverable.NewExceptionf("could not retrieve parent (id=%s): %w", block.ParentID, err)
   849  	}
   850  
   851  	return parent.View < currentEpochFirstView, nil
   852  }
   853  
   854  // epochTransitionMetricsAndEventsOnBlockFinalized determines metrics to update
   855  // and protocol events to emit for blocks which are the first block of a new epoch.
   856  // Protocol events and updating metrics happen once when we finalize the _first_
   857  // block of the new Epoch (same convention as for Epoch-Phase-Changes).
   858  //
   859  // NOTE: This function must only be called when input `block` is the first block
   860  // of the epoch denoted by `currentEpochSetup`.
   861  func (m *FollowerState) epochTransitionMetricsAndEventsOnBlockFinalized(block *flow.Header, currentEpochSetup *flow.EpochSetup) (
   862  	metrics []func(),
   863  	events []func(),
   864  ) {
   865  
   866  	events = append(events, func() { m.consumer.EpochTransition(currentEpochSetup.Counter, block) })
   867  	// set current epoch counter corresponding to new epoch
   868  	metrics = append(metrics, func() { m.metrics.CurrentEpochCounter(currentEpochSetup.Counter) })
   869  	// denote the most recent epoch transition height
   870  	metrics = append(metrics, func() { m.metrics.EpochTransitionHeight(block.Height) })
   871  	// set epoch phase - since we are starting a new epoch we begin in the staking phase
   872  	metrics = append(metrics, func() { m.metrics.CurrentEpochPhase(flow.EpochPhaseStaking) })
   873  	// set current epoch view values
   874  	metrics = append(
   875  		metrics,
   876  		func() { m.metrics.CurrentEpochFinalView(currentEpochSetup.FinalView) },
   877  		func() { m.metrics.CurrentDKGPhase1FinalView(currentEpochSetup.DKGPhase1FinalView) },
   878  		func() { m.metrics.CurrentDKGPhase2FinalView(currentEpochSetup.DKGPhase2FinalView) },
   879  		func() { m.metrics.CurrentDKGPhase3FinalView(currentEpochSetup.DKGPhase3FinalView) },
   880  	)
   881  
   882  	return
   883  }
   884  
   885  // epochPhaseMetricsAndEventsOnBlockFinalized determines metrics to update and protocol
   886  // events to emit. Service Events embedded into an execution result take effect, when the
   887  // execution result's _seal is finalized_ (i.e. when the block holding a seal for the
   888  // result is finalized). See also handleEpochServiceEvents for further details. Example:
   889  //
   890  // Convention:
   891  //
   892  //	A <-- ... <-- C(Seal_A)
   893  //
   894  // Suppose an EpochSetup service event is emitted during execution of block A. C seals A, therefore
   895  // we apply the metrics/events when C is finalized. The first block of the EpochSetup
   896  // phase is block C.
   897  //
   898  // This function should only be called when epoch fallback *has not already been triggered*.
   899  // No errors are expected during normal operation.
   900  func (m *FollowerState) epochPhaseMetricsAndEventsOnBlockFinalized(block *flow.Block, epochStatus *flow.EpochStatus) (
   901  	metrics []func(),
   902  	events []func(),
   903  	err error,
   904  ) {
   905  
   906  	// block payload may not specify seals in order, so order them by block height before processing
   907  	orderedSeals, err := protocol.OrderedSeals(block.Payload, m.headers)
   908  	if err != nil {
   909  		if errors.Is(err, storage.ErrNotFound) {
   910  			return nil, nil, fmt.Errorf("ordering seals: parent payload contains seals for unknown block: %s", err.Error())
   911  		}
   912  		return nil, nil, fmt.Errorf("unexpected error ordering seals: %w", err)
   913  	}
   914  
   915  	// track service event driven metrics and protocol events that should be emitted
   916  	for _, seal := range orderedSeals {
   917  		result, err := m.results.ByID(seal.ResultID)
   918  		if err != nil {
   919  			return nil, nil, fmt.Errorf("could not retrieve result (id=%x) for seal (id=%x): %w", seal.ResultID, seal.ID(), err)
   920  		}
   921  		for _, event := range result.ServiceEvents {
   922  			switch ev := event.Event.(type) {
   923  			case *flow.EpochSetup:
   924  				// update current epoch phase
   925  				events = append(events, func() { m.metrics.CurrentEpochPhase(flow.EpochPhaseSetup) })
   926  				// track epoch phase transition (staking->setup)
   927  				events = append(events, func() { m.consumer.EpochSetupPhaseStarted(ev.Counter-1, block.Header) })
   928  			case *flow.EpochCommit:
   929  				// update current epoch phase
   930  				events = append(events, func() { m.metrics.CurrentEpochPhase(flow.EpochPhaseCommitted) })
   931  				// track epoch phase transition (setup->committed)
   932  				events = append(events, func() { m.consumer.EpochCommittedPhaseStarted(ev.Counter-1, block.Header) })
   933  				// track final view of committed epoch
   934  				nextEpochSetup, err := m.epoch.setups.ByID(epochStatus.NextEpoch.SetupID)
   935  				if err != nil {
   936  					return nil, nil, fmt.Errorf("could not retrieve setup event for next epoch: %w", err)
   937  				}
   938  				events = append(events, func() { m.metrics.CommittedEpochFinalView(nextEpochSetup.FinalView) })
   939  			case *flow.VersionBeacon:
   940  				// do nothing for now
   941  			default:
   942  				return nil, nil, fmt.Errorf("invalid service event type in payload (%T)", ev)
   943  			}
   944  		}
   945  	}
   946  
   947  	return
   948  }
   949  
   950  // epochStatus computes the EpochStatus for the given block *before* applying
   951  // any service event state changes which come into effect with this block.
   952  //
   953  // Specifically, we must determine whether block is the first block of a new
   954  // epoch in its respective fork. We do this by comparing the block's view to
   955  // the Epoch data from its parent. If the block's view is _larger_ than the
   956  // final View of the parent's epoch, the block starts a new Epoch.
   957  //
   958  // Possible outcomes:
   959  //  1. Block is in same Epoch as parent (block.View < epoch.FinalView)
   960  //     -> the parent's EpochStatus.CurrentEpoch also applies for the current block
   961  //  2. Block enters the next Epoch (block.View ≥ epoch.FinalView)
   962  //     a) HAPPY PATH: Epoch fallback is not triggered, we enter the next epoch:
   963  //     -> the parent's EpochStatus.NextEpoch is the current block's EpochStatus.CurrentEpoch
   964  //     b) FALLBACK PATH: Epoch fallback is triggered, we continue the current epoch:
   965  //     -> the parent's EpochStatus.CurrentEpoch also applies for the current block
   966  //
   967  // As the parent was a valid extension of the chain, by induction, the parent
   968  // satisfies all consistency requirements of the protocol.
   969  //
   970  // Returns the EpochStatus for the input block.
   971  // No error returns are expected under normal operations
   972  func (m *FollowerState) epochStatus(block *flow.Header, epochFallbackTriggered bool) (*flow.EpochStatus, error) {
   973  	parentStatus, err := m.epoch.statuses.ByBlockID(block.ParentID)
   974  	if err != nil {
   975  		return nil, fmt.Errorf("could not retrieve epoch state for parent: %w", err)
   976  	}
   977  	parentSetup, err := m.epoch.setups.ByID(parentStatus.CurrentEpoch.SetupID)
   978  	if err != nil {
   979  		return nil, fmt.Errorf("could not retrieve EpochSetup event for parent: %w", err)
   980  	}
   981  
   982  	// Case 1 or 2b (still in parent block's epoch or epoch fallback triggered):
   983  	if block.View <= parentSetup.FinalView || epochFallbackTriggered {
   984  		// IMPORTANT: copy the status to avoid modifying the parent status in the cache
   985  		return parentStatus.Copy(), nil
   986  	}
   987  
   988  	// Case 2a (first block of new epoch):
   989  	// sanity check: parent's epoch Preparation should be completed and have EpochSetup and EpochCommit events
   990  	if parentStatus.NextEpoch.SetupID == flow.ZeroID {
   991  		return nil, fmt.Errorf("missing setup event for starting next epoch")
   992  	}
   993  	if parentStatus.NextEpoch.CommitID == flow.ZeroID {
   994  		return nil, fmt.Errorf("missing commit event for starting next epoch")
   995  	}
   996  	epochStatus, err := flow.NewEpochStatus(
   997  		parentStatus.CurrentEpoch.SetupID, parentStatus.CurrentEpoch.CommitID,
   998  		parentStatus.NextEpoch.SetupID, parentStatus.NextEpoch.CommitID,
   999  		flow.ZeroID, flow.ZeroID,
  1000  	)
  1001  	return epochStatus, err
  1002  
  1003  }
  1004  
  1005  // versionBeaconOnBlockFinalized extracts and returns the VersionBeacons from the
  1006  // finalized block's seals.
  1007  // This could return multiple VersionBeacons if the parent block contains multiple Seals.
  1008  // The version beacons will be returned in the ascending height order of the seals.
  1009  // Technically only the last VersionBeacon is relevant.
  1010  func (m *FollowerState) versionBeaconOnBlockFinalized(
  1011  	finalized *flow.Block,
  1012  ) ([]*flow.SealedVersionBeacon, error) {
  1013  	var versionBeacons []*flow.SealedVersionBeacon
  1014  
  1015  	seals, err := protocol.OrderedSeals(finalized.Payload, m.headers)
  1016  	if err != nil {
  1017  		if errors.Is(err, storage.ErrNotFound) {
  1018  			return nil, fmt.Errorf(
  1019  				"ordering seals: parent payload contains"+
  1020  					" seals for unknown block: %w", err)
  1021  		}
  1022  		return nil, fmt.Errorf("unexpected error ordering seals: %w", err)
  1023  	}
  1024  
  1025  	for _, seal := range seals {
  1026  		result, err := m.results.ByID(seal.ResultID)
  1027  		if err != nil {
  1028  			return nil, fmt.Errorf(
  1029  				"could not retrieve result (id=%x) for seal (id=%x): %w",
  1030  				seal.ResultID,
  1031  				seal.ID(),
  1032  				err)
  1033  		}
  1034  		for _, event := range result.ServiceEvents {
  1035  
  1036  			ev, ok := event.Event.(*flow.VersionBeacon)
  1037  
  1038  			if !ok {
  1039  				// skip other service event types.
  1040  				// validation if this is a known service event type is done elsewhere.
  1041  				continue
  1042  			}
  1043  
  1044  			err := ev.Validate()
  1045  			if err != nil {
  1046  				m.logger.Warn().
  1047  					Err(err).
  1048  					Str("block_id", finalized.ID().String()).
  1049  					Interface("event", ev).
  1050  					Msg("invalid VersionBeacon service event")
  1051  				continue
  1052  			}
  1053  
  1054  			// The version beacon only becomes actionable/valid/active once the block
  1055  			// containing the version beacon has been sealed. That is why we set the
  1056  			// Seal height to the current block height.
  1057  			versionBeacons = append(versionBeacons, &flow.SealedVersionBeacon{
  1058  				VersionBeacon: ev,
  1059  				SealHeight:    finalized.Header.Height,
  1060  			})
  1061  		}
  1062  	}
  1063  
  1064  	return versionBeacons, nil
  1065  }
  1066  
  1067  // handleEpochServiceEvents handles applying state changes which occur as a result
  1068  // of service events being included in a block payload:
  1069  //   - inserting incorporated service events
  1070  //   - updating EpochStatus for the candidate block
  1071  //
  1072  // Consider a chain where a service event is emitted during execution of block A.
  1073  // Block B contains a receipt for A. Block C contains a seal for block A.
  1074  //
  1075  // A <- .. <- B(RA) <- .. <- C(SA)
  1076  //
  1077  // Service events are included within execution results, which are stored
  1078  // opaquely as part of the block payload in block B. We only validate and insert
  1079  // the typed service event to storage once we process C, the block containing the
  1080  // seal for block A. This is because we rely on the sealing subsystem to validate
  1081  // correctness of the service event before processing it.
  1082  // Consequently, any change to the protocol state introduced by a service event
  1083  // emitted during execution of block A would only become visible when querying
  1084  // C or its descendants.
  1085  //
  1086  // This method will only apply service-event-induced state changes when the
  1087  // input block has the form of block C (ie. contains a seal for a block in
  1088  // which a service event was emitted).
  1089  //
  1090  // Return values:
  1091  //   - dbUpdates - If the service events are valid, or there are no service events,
  1092  //     this method returns a slice of Badger operations to apply while storing the block.
  1093  //     This includes an operation to index the epoch status for every block, and
  1094  //     operations to insert service events for blocks that include them.
  1095  //
  1096  // No errors are expected during normal operation.
  1097  func (m *FollowerState) handleEpochServiceEvents(candidate *flow.Block) (dbUpdates []func(*transaction.Tx) error, err error) {
  1098  	epochFallbackTriggered, err := m.isEpochEmergencyFallbackTriggered()
  1099  	if err != nil {
  1100  		return nil, fmt.Errorf("could not retrieve epoch fallback status: %w", err)
  1101  	}
  1102  	epochStatus, err := m.epochStatus(candidate.Header, epochFallbackTriggered)
  1103  	if err != nil {
  1104  		return nil, fmt.Errorf("could not determine epoch status for candidate block: %w", err)
  1105  	}
  1106  	activeSetup, err := m.epoch.setups.ByID(epochStatus.CurrentEpoch.SetupID)
  1107  	if err != nil {
  1108  		return nil, fmt.Errorf("could not retrieve current epoch setup event: %w", err)
  1109  	}
  1110  
  1111  	// always persist the candidate's epoch status
  1112  	// note: We are scheduling the operation to store the Epoch status using the _pointer_ variable `epochStatus`.
  1113  	// The struct `epochStatus` points to will still be modified below.
  1114  	blockID := candidate.ID()
  1115  	dbUpdates = append(dbUpdates, m.epoch.statuses.StoreTx(blockID, epochStatus))
  1116  
  1117  	// never process service events after epoch fallback is triggered
  1118  	if epochStatus.InvalidServiceEventIncorporated || epochFallbackTriggered {
  1119  		return dbUpdates, nil
  1120  	}
  1121  
  1122  	// We apply service events from blocks which are sealed by this candidate block.
  1123  	// The block's payload might contain epoch preparation service events for the next
  1124  	// epoch. In this case, we need to update the tentative protocol state.
  1125  	// We need to validate whether all information is available in the protocol
  1126  	// state to go to the next epoch when needed. In cases where there is a bug
  1127  	// in the smart contract, it could be that this happens too late and the
  1128  	// chain finalization should halt.
  1129  
  1130  	// block payload may not specify seals in order, so order them by block height before processing
  1131  	orderedSeals, err := protocol.OrderedSeals(candidate.Payload, m.headers)
  1132  	if err != nil {
  1133  		if errors.Is(err, storage.ErrNotFound) {
  1134  			return nil, fmt.Errorf("ordering seals: parent payload contains seals for unknown block: %s", err.Error())
  1135  		}
  1136  		return nil, fmt.Errorf("unexpected error ordering seals: %w", err)
  1137  	}
  1138  	for _, seal := range orderedSeals {
  1139  		result, err := m.results.ByID(seal.ResultID)
  1140  		if err != nil {
  1141  			return nil, fmt.Errorf("could not get result (id=%x) for seal (id=%x): %w", seal.ResultID, seal.ID(), err)
  1142  		}
  1143  
  1144  		for _, event := range result.ServiceEvents {
  1145  
  1146  			switch ev := event.Event.(type) {
  1147  			case *flow.EpochSetup:
  1148  				// validate the service event
  1149  				err := isValidExtendingEpochSetup(ev, activeSetup, epochStatus)
  1150  				if err != nil {
  1151  					if protocol.IsInvalidServiceEventError(err) {
  1152  						// we have observed an invalid service event, which triggers epoch fallback mode
  1153  						epochStatus.InvalidServiceEventIncorporated = true
  1154  						return dbUpdates, nil
  1155  					}
  1156  					return nil, fmt.Errorf("unexpected error validating EpochSetup service event: %w", err)
  1157  				}
  1158  
  1159  				// prevents multiple setup events for same Epoch (including multiple setup events in payload of same block)
  1160  				epochStatus.NextEpoch.SetupID = ev.ID()
  1161  
  1162  				// we'll insert the setup event when we insert the block
  1163  				dbUpdates = append(dbUpdates, m.epoch.setups.StoreTx(ev))
  1164  
  1165  			case *flow.EpochCommit:
  1166  				// if we receive an EpochCommit event, we must have already observed an EpochSetup event
  1167  				// => otherwise, we have observed an EpochCommit without corresponding EpochSetup, which triggers epoch fallback mode
  1168  				if epochStatus.NextEpoch.SetupID == flow.ZeroID {
  1169  					epochStatus.InvalidServiceEventIncorporated = true
  1170  					return dbUpdates, nil
  1171  				}
  1172  
  1173  				// if we have observed an EpochSetup event, we must be able to retrieve it from the database
  1174  				// => otherwise, this is a symptom of bug or data corruption since this component sets the SetupID field
  1175  				extendingSetup, err := m.epoch.setups.ByID(epochStatus.NextEpoch.SetupID)
  1176  				if err != nil {
  1177  					if errors.Is(err, storage.ErrNotFound) {
  1178  						return nil, irrecoverable.NewExceptionf("could not retrieve EpochSetup (id=%x) stored in EpochStatus for block %x: %w",
  1179  							epochStatus.NextEpoch.SetupID, blockID, err)
  1180  					}
  1181  					return nil, fmt.Errorf("unexpected error retrieving next epoch setup: %w", err)
  1182  				}
  1183  
  1184  				// validate the service event
  1185  				err = isValidExtendingEpochCommit(ev, extendingSetup, activeSetup, epochStatus)
  1186  				if err != nil {
  1187  					if protocol.IsInvalidServiceEventError(err) {
  1188  						// we have observed an invalid service event, which triggers epoch fallback mode
  1189  						epochStatus.InvalidServiceEventIncorporated = true
  1190  						return dbUpdates, nil
  1191  					}
  1192  					return nil, fmt.Errorf("unexpected error validating EpochCommit service event: %w", err)
  1193  				}
  1194  
  1195  				// prevents multiple setup events for same Epoch (including multiple setup events in payload of same block)
  1196  				epochStatus.NextEpoch.CommitID = ev.ID()
  1197  
  1198  				// we'll insert the commit event when we insert the block
  1199  				dbUpdates = append(dbUpdates, m.epoch.commits.StoreTx(ev))
  1200  			case *flow.VersionBeacon:
  1201  				// do nothing for now
  1202  			default:
  1203  				return nil, fmt.Errorf("invalid service event type (type_name=%s, go_type=%T)", event.Type, ev)
  1204  			}
  1205  		}
  1206  	}
  1207  	return
  1208  }