github.com/koko1123/flow-go-1@v0.29.6/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/v3"
    11  
    12  	"github.com/koko1123/flow-go-1/engine"
    13  	"github.com/koko1123/flow-go-1/model/flow"
    14  	"github.com/koko1123/flow-go-1/module"
    15  	"github.com/koko1123/flow-go-1/module/signature"
    16  	"github.com/koko1123/flow-go-1/module/trace"
    17  	"github.com/koko1123/flow-go-1/state"
    18  	"github.com/koko1123/flow-go-1/state/protocol"
    19  	"github.com/koko1123/flow-go-1/storage"
    20  	"github.com/koko1123/flow-go-1/storage/badger/operation"
    21  	"github.com/koko1123/flow-go-1/storage/badger/procedure"
    22  	"github.com/koko1123/flow-go-1/storage/badger/transaction"
    23  )
    24  
    25  // errIncompleteEpochConfiguration is a sentinel error returned when there are
    26  // still epoch service events missing and the new epoch can't be constructed.
    27  var errIncompleteEpochConfiguration = errors.New("block beyond epoch boundary")
    28  
    29  // FollowerState implements a lighter version of a mutable protocol state.
    30  // When extending the state, it performs hardly any checks on the block payload.
    31  // Instead, the FollowerState relies on the consensus nodes to run the full
    32  // payload check. Consequently, a block B should only be considered valid, if
    33  // a child block with a valid header is known. The child block's header
    34  // includes quorum certificate, which proves that a super-majority of consensus
    35  // nodes consider block B as valid.
    36  //
    37  // The FollowerState allows non-consensus nodes to execute fork-aware queries
    38  // against the protocol state, while minimizing the amount of payload checks
    39  // the non-consensus nodes have to perform.
    40  type FollowerState struct {
    41  	*State
    42  
    43  	index      storage.Index
    44  	payloads   storage.Payloads
    45  	tracer     module.Tracer
    46  	consumer   protocol.Consumer
    47  	blockTimer protocol.BlockTimer
    48  	cfg        Config
    49  }
    50  
    51  // MutableState implements a mutable protocol state. When extending the
    52  // state with a new block, it checks the _entire_ block payload.
    53  type MutableState struct {
    54  	*FollowerState
    55  	receiptValidator module.ReceiptValidator
    56  	sealValidator    module.SealValidator
    57  }
    58  
    59  // NewFollowerState initializes a light-weight version of a mutable protocol
    60  // state. This implementation is suitable only for NON-Consensus nodes.
    61  func NewFollowerState(
    62  	state *State,
    63  	index storage.Index,
    64  	payloads storage.Payloads,
    65  	tracer module.Tracer,
    66  	consumer protocol.Consumer,
    67  	blockTimer protocol.BlockTimer,
    68  ) (*FollowerState, error) {
    69  	followerState := &FollowerState{
    70  		State:      state,
    71  		index:      index,
    72  		payloads:   payloads,
    73  		tracer:     tracer,
    74  		consumer:   consumer,
    75  		blockTimer: blockTimer,
    76  		cfg:        DefaultConfig(),
    77  	}
    78  	return followerState, nil
    79  }
    80  
    81  // NewFullConsensusState initializes a new mutable protocol state backed by a
    82  // badger database. When extending the state with a new block, it checks the
    83  // _entire_ block payload. Consensus nodes should use the FullConsensusState,
    84  // while other node roles can use the lighter FollowerState.
    85  func NewFullConsensusState(
    86  	state *State,
    87  	index storage.Index,
    88  	payloads storage.Payloads,
    89  	tracer module.Tracer,
    90  	consumer protocol.Consumer,
    91  	blockTimer protocol.BlockTimer,
    92  	receiptValidator module.ReceiptValidator,
    93  	sealValidator module.SealValidator,
    94  ) (*MutableState, error) {
    95  	followerState, err := NewFollowerState(state, index, payloads, tracer, consumer, blockTimer)
    96  	if err != nil {
    97  		return nil, fmt.Errorf("initialization of Mutable Follower State failed: %w", err)
    98  	}
    99  	return &MutableState{
   100  		FollowerState:    followerState,
   101  		receiptValidator: receiptValidator,
   102  		sealValidator:    sealValidator,
   103  	}, nil
   104  }
   105  
   106  // Extend extends the protocol state of a CONSENSUS FOLLOWER. While it checks
   107  // the validity of the header; it does _not_ check the validity of the payload.
   108  // Instead, the consensus follower relies on the consensus participants to
   109  // validate the full payload. Therefore, a follower a QC (i.e. a child block) as
   110  // proof that a block is valid.
   111  func (m *FollowerState) Extend(ctx context.Context, candidate *flow.Block) error {
   112  
   113  	span, ctx := m.tracer.StartSpanFromContext(ctx, trace.ProtoStateMutatorHeaderExtend)
   114  	defer span.End()
   115  
   116  	// check if the block header is a valid extension of the finalized state
   117  	err := m.headerExtend(candidate)
   118  	if err != nil {
   119  		return fmt.Errorf("header not compliant with chain state: %w", err)
   120  	}
   121  
   122  	// find the last seal at the parent block
   123  	last, err := m.lastSealed(candidate)
   124  	if err != nil {
   125  		return fmt.Errorf("payload seal(s) not compliant with chain state: %w", err)
   126  	}
   127  
   128  	// insert the block and index the last seal for the block
   129  	err = m.insert(ctx, candidate, last)
   130  	if err != nil {
   131  		return fmt.Errorf("failed to insert the block: %w", err)
   132  	}
   133  
   134  	return nil
   135  }
   136  
   137  // Extend extends the protocol state of a CONSENSUS PARTICIPANT. It checks
   138  // the validity of the _entire block_ (header and full payload).
   139  func (m *MutableState) Extend(ctx context.Context, candidate *flow.Block) error {
   140  
   141  	span, ctx := m.tracer.StartSpanFromContext(ctx, trace.ProtoStateMutatorExtend)
   142  	defer span.End()
   143  
   144  	// check if the block header is a valid extension of the finalized state
   145  	err := m.headerExtend(candidate)
   146  	if err != nil {
   147  		return fmt.Errorf("header not compliant with chain state: %w", err)
   148  	}
   149  
   150  	// check if the guarantees in the payload is a valid extension of the finalized state
   151  	err = m.guaranteeExtend(ctx, candidate)
   152  	if err != nil {
   153  		return fmt.Errorf("payload guarantee(s) not compliant with chain state: %w", err)
   154  	}
   155  
   156  	// check if the receipts in the payload are valid
   157  	err = m.receiptExtend(ctx, candidate)
   158  	if err != nil {
   159  		return fmt.Errorf("payload receipt(s) not compliant with chain state: %w", err)
   160  	}
   161  
   162  	// check if the seals in the payload is a valid extension of the finalized
   163  	// state
   164  	lastSeal, err := m.sealExtend(ctx, candidate)
   165  	if err != nil {
   166  		return fmt.Errorf("payload seal(s) not compliant with chain state: %w", err)
   167  	}
   168  
   169  	// insert the block and index the last seal for the block
   170  	err = m.insert(ctx, candidate, lastSeal)
   171  	if err != nil {
   172  		return fmt.Errorf("failed to insert the block: %w", err)
   173  	}
   174  
   175  	return nil
   176  }
   177  
   178  // headerExtend verifies the validity of the block header (excluding verification of the
   179  // consensus rules). Specifically, we check that the block connects to the last finalized block.
   180  func (m *FollowerState) headerExtend(candidate *flow.Block) error {
   181  	// FIRST: We do some initial cheap sanity checks, like checking the payload
   182  	// hash is consistent
   183  
   184  	header := candidate.Header
   185  	payload := candidate.Payload
   186  	if payload.Hash() != header.PayloadHash {
   187  		return state.NewInvalidExtensionError("payload integrity check failed")
   188  	}
   189  
   190  	// SECOND: Next, we can check whether the block is a valid descendant of the
   191  	// parent. It should have the same chain ID and a height that is one bigger.
   192  
   193  	parent, err := m.headers.ByBlockID(header.ParentID)
   194  	if err != nil {
   195  		return state.NewInvalidExtensionErrorf("could not retrieve parent: %s", err)
   196  	}
   197  	if header.ChainID != parent.ChainID {
   198  		return state.NewInvalidExtensionErrorf("candidate built for invalid chain (candidate: %s, parent: %s)",
   199  			header.ChainID, parent.ChainID)
   200  	}
   201  	if header.Height != parent.Height+1 {
   202  		return state.NewInvalidExtensionErrorf("candidate built with invalid height (candidate: %d, parent: %d)",
   203  			header.Height, parent.Height)
   204  	}
   205  
   206  	// check validity of block timestamp using parent's timestamp
   207  	err = m.blockTimer.Validate(parent.Timestamp, candidate.Header.Timestamp)
   208  	if err != nil {
   209  		if protocol.IsInvalidBlockTimestampError(err) {
   210  			return state.NewInvalidExtensionErrorf("candidate contains invalid timestamp: %w", err)
   211  		}
   212  		return fmt.Errorf("validating block's time stamp failed with unexpected error: %w", err)
   213  	}
   214  
   215  	// THIRD: Once we have established the block is valid within itself, and the
   216  	// block is valid in relation to its parent, we can check whether it is
   217  	// valid in the context of the entire state. For this, the block needs to
   218  	// directly connect, through its ancestors, to the last finalized block.
   219  
   220  	var finalizedHeight uint64
   221  	err = m.db.View(operation.RetrieveFinalizedHeight(&finalizedHeight))
   222  	if err != nil {
   223  		return fmt.Errorf("could not retrieve finalized height: %w", err)
   224  	}
   225  	var finalID flow.Identifier
   226  	err = m.db.View(operation.LookupBlockHeight(finalizedHeight, &finalID))
   227  	if err != nil {
   228  		return fmt.Errorf("could not lookup finalized block: %w", err)
   229  	}
   230  
   231  	ancestorID := header.ParentID
   232  	for ancestorID != finalID {
   233  		ancestor, err := m.headers.ByBlockID(ancestorID)
   234  		if err != nil {
   235  			return fmt.Errorf("could not retrieve ancestor (%x): %w", ancestorID, err)
   236  		}
   237  		if ancestor.Height < finalizedHeight {
   238  			// this happens when the candidate block is on a fork that does not include all the
   239  			// finalized blocks.
   240  			// for instance:
   241  			// A (Finalized) <- B (Finalized) <- C (Finalized) <- D <- E <- F
   242  			//                  ^- G             ^- H             ^- I
   243  			// block G is not a valid block, because it does not have C (which has been finalized) as an ancestor
   244  			// block H and I are valid, because they do have C as an ancestor
   245  			return state.NewOutdatedExtensionErrorf(
   246  				"candidate block (height: %d) conflicts with finalized state (ancestor: %d final: %d)",
   247  				header.Height, ancestor.Height, finalizedHeight)
   248  		}
   249  		ancestorID = ancestor.ParentID
   250  	}
   251  
   252  	return nil
   253  }
   254  
   255  // guaranteeExtend verifies the validity of the collection guarantees that are
   256  // included in the block. Specifically, we check for expired collections and
   257  // duplicated collections (also including ancestor blocks).
   258  func (m *MutableState) guaranteeExtend(ctx context.Context, candidate *flow.Block) error {
   259  
   260  	span, _ := m.tracer.StartSpanFromContext(ctx, trace.ProtoStateMutatorExtendCheckGuarantees)
   261  	defer span.End()
   262  
   263  	header := candidate.Header
   264  	payload := candidate.Payload
   265  
   266  	// we only look as far back for duplicates as the transaction expiry limit;
   267  	// if a guarantee was included before that, we will disqualify it on the
   268  	// basis of the reference block anyway
   269  	limit := header.Height - m.cfg.transactionExpiry
   270  	if limit > header.Height { // overflow check
   271  		limit = 0
   272  	}
   273  
   274  	// look up the root height so we don't look too far back
   275  	// initially this is the genesis block height (aka 0).
   276  	var rootHeight uint64
   277  	err := m.db.View(operation.RetrieveRootHeight(&rootHeight))
   278  	if err != nil {
   279  		return fmt.Errorf("could not retrieve root block height: %w", err)
   280  	}
   281  	if limit < rootHeight {
   282  		limit = rootHeight
   283  	}
   284  
   285  	// build a list of all previously used guarantees on this part of the chain
   286  	ancestorID := header.ParentID
   287  	lookup := make(map[flow.Identifier]struct{})
   288  	for {
   289  		ancestor, err := m.headers.ByBlockID(ancestorID)
   290  		if err != nil {
   291  			return fmt.Errorf("could not retrieve ancestor header (%x): %w", ancestorID, err)
   292  		}
   293  		index, err := m.index.ByBlockID(ancestorID)
   294  		if err != nil {
   295  			return fmt.Errorf("could not retrieve ancestor index (%x): %w", ancestorID, err)
   296  		}
   297  		for _, collID := range index.CollectionIDs {
   298  			lookup[collID] = struct{}{}
   299  		}
   300  		if ancestor.Height <= limit {
   301  			break
   302  		}
   303  		ancestorID = ancestor.ParentID
   304  	}
   305  
   306  	// check each guarantee included in the payload for duplication and expiry
   307  	for _, guarantee := range payload.Guarantees {
   308  
   309  		// if the guarantee was already included before, error
   310  		_, duplicated := lookup[guarantee.ID()]
   311  		if duplicated {
   312  			return state.NewInvalidExtensionErrorf("payload includes duplicate guarantee (%x)", guarantee.ID())
   313  		}
   314  
   315  		// get the reference block to check expiry
   316  		ref, err := m.headers.ByBlockID(guarantee.ReferenceBlockID)
   317  		if err != nil {
   318  			if errors.Is(err, storage.ErrNotFound) {
   319  				return state.NewInvalidExtensionErrorf("could not get reference block %x: %w", guarantee.ReferenceBlockID, err)
   320  			}
   321  			return fmt.Errorf("could not get reference block (%x): %w", guarantee.ReferenceBlockID, err)
   322  		}
   323  
   324  		// if the guarantee references a block with expired height, error
   325  		if ref.Height < limit {
   326  			return state.NewInvalidExtensionErrorf("payload includes expired guarantee (height: %d, limit: %d)",
   327  				ref.Height, limit)
   328  		}
   329  
   330  		// check the guarantors are correct
   331  		_, err = protocol.FindGuarantors(m, guarantee)
   332  		if err != nil {
   333  			if signature.IsInvalidSignerIndicesError(err) ||
   334  				errors.Is(err, protocol.ErrEpochNotCommitted) ||
   335  				errors.Is(err, protocol.ErrClusterNotFound) {
   336  				return state.NewInvalidExtensionErrorf("guarantee %v contains invalid guarantors: %w", guarantee.ID(), err)
   337  			}
   338  			return fmt.Errorf("could not find guarantor for guarantee %v: %w", guarantee.ID(), err)
   339  		}
   340  	}
   341  
   342  	return nil
   343  }
   344  
   345  // sealExtend checks the compliance of the payload seals. Returns last seal that form a chain for
   346  // candidate block.
   347  func (m *MutableState) sealExtend(ctx context.Context, candidate *flow.Block) (*flow.Seal, error) {
   348  
   349  	span, _ := m.tracer.StartSpanFromContext(ctx, trace.ProtoStateMutatorExtendCheckSeals)
   350  	defer span.End()
   351  
   352  	lastSeal, err := m.sealValidator.Validate(candidate)
   353  	if err != nil {
   354  		return nil, state.NewInvalidExtensionErrorf("seal validation error: %w", err)
   355  	}
   356  
   357  	return lastSeal, nil
   358  }
   359  
   360  // receiptExtend checks the compliance of the receipt payload.
   361  //   - Receipts should pertain to blocks on the fork
   362  //   - Receipts should not appear more than once on a fork
   363  //   - Receipts should pass the ReceiptValidator check
   364  //   - No seal has been included for the respective block in this particular fork
   365  //
   366  // We require the receipts to be sorted by block height (within a payload).
   367  func (m *MutableState) receiptExtend(ctx context.Context, candidate *flow.Block) error {
   368  
   369  	span, _ := m.tracer.StartSpanFromContext(ctx, trace.ProtoStateMutatorExtendCheckReceipts)
   370  	defer span.End()
   371  
   372  	err := m.receiptValidator.ValidatePayload(candidate)
   373  	if err != nil {
   374  		// TODO: this might be not an error, potentially it can be solved by requesting more data and processing this receipt again
   375  		if errors.Is(err, storage.ErrNotFound) {
   376  			return state.NewInvalidExtensionErrorf("some entities referenced by receipts are missing: %w", err)
   377  		}
   378  		if engine.IsInvalidInputError(err) {
   379  			return state.NewInvalidExtensionErrorf("payload includes invalid receipts: %w", err)
   380  		}
   381  		return fmt.Errorf("unexpected payload validation error %w", err)
   382  	}
   383  
   384  	return nil
   385  }
   386  
   387  // lastSealed returns the highest sealed block from the fork with head `candidate`.
   388  // For instance, here is the chain state: block 100 is the head, block 97 is finalized,
   389  // and 95 is the last sealed block at the state of block 100.
   390  // 95 (sealed) <- 96 <- 97 (finalized) <- 98 <- 99 <- 100
   391  // Now, if block 101 is extending block 100, and its payload has a seal for 96, then it will
   392  // be the last sealed for block 101.
   393  func (m *FollowerState) lastSealed(candidate *flow.Block) (*flow.Seal, error) {
   394  	header := candidate.Header
   395  	payload := candidate.Payload
   396  
   397  	// getting the last sealed block
   398  	last, err := m.seals.HighestInFork(header.ParentID)
   399  	if err != nil {
   400  		return nil, fmt.Errorf("could not retrieve parent seal (%x): %w", header.ParentID, err)
   401  	}
   402  
   403  	// if the payload of the block has seals, then the last seal is the seal for the highest
   404  	// block
   405  	if len(payload.Seals) > 0 {
   406  		var highestHeader *flow.Header
   407  		for i, seal := range payload.Seals {
   408  			header, err := m.headers.ByBlockID(seal.BlockID)
   409  			if err != nil {
   410  				return nil, state.NewInvalidExtensionErrorf("could not retrieve the header %v for seal: %w", seal.BlockID, err)
   411  			}
   412  
   413  			if i == 0 || header.Height > highestHeader.Height {
   414  				highestHeader = header
   415  				last = seal
   416  			}
   417  		}
   418  	}
   419  
   420  	return last, nil
   421  }
   422  
   423  // insert stores the candidate block in the data base. The
   424  // `candidate` block _must be valid_ (otherwise, the state will be corrupted).
   425  func (m *FollowerState) insert(ctx context.Context, candidate *flow.Block, last *flow.Seal) error {
   426  
   427  	span, _ := m.tracer.StartSpanFromContext(ctx, trace.ProtoStateMutatorExtendDBInsert)
   428  	defer span.End()
   429  
   430  	blockID := candidate.ID()
   431  
   432  	// SIXTH: epoch transitions and service events
   433  	//    (i) Determine protocol state for block's _current_ Epoch.
   434  	//        As we don't have slashing yet, the protocol state is fully
   435  	//        determined by the Epoch Preparation events.
   436  	//   (ii) Determine protocol state for block's _next_ Epoch.
   437  	//        In case any of the payload seals includes system events,
   438  	//        we need to check if they are valid and must apply them
   439  	//        to the protocol state as needed.
   440  	ops, err := m.handleServiceEvents(candidate)
   441  	if err != nil {
   442  		return fmt.Errorf("could not handle service events: %w", err)
   443  	}
   444  
   445  	// FINALLY: Both the header itself and its payload are in compliance with the
   446  	// protocol state. We can now store the candidate block, as well as adding
   447  	// its final seal to the seal index and initializing its children index.
   448  
   449  	err = operation.RetryOnConflictTx(m.db, transaction.Update, func(tx *transaction.Tx) error {
   450  		// insert the block into the database AND cache
   451  		err := m.blocks.StoreTx(candidate)(tx)
   452  		if err != nil {
   453  			return fmt.Errorf("could not store candidate block: %w", err)
   454  		}
   455  
   456  		// index the latest sealed block in this fork
   457  		err = transaction.WithTx(operation.IndexLatestSealAtBlock(blockID, last.ID()))(tx)
   458  		if err != nil {
   459  			return fmt.Errorf("could not index candidate seal: %w", err)
   460  		}
   461  
   462  		// index the child block for recovery
   463  		err = transaction.WithTx(procedure.IndexNewBlock(blockID, candidate.Header.ParentID))(tx)
   464  		if err != nil {
   465  			return fmt.Errorf("could not index new block: %w", err)
   466  		}
   467  
   468  		// apply any optional DB operations from service events
   469  		for _, apply := range ops {
   470  			err := apply(tx)
   471  			if err != nil {
   472  				return fmt.Errorf("could not apply operation: %w", err)
   473  			}
   474  		}
   475  
   476  		return nil
   477  	})
   478  
   479  	if err != nil {
   480  		return fmt.Errorf("could not execute state extension: %w", err)
   481  	}
   482  
   483  	return nil
   484  }
   485  
   486  // Finalize marks the specified block as finalized. This method only
   487  // finalizes one block at a time. Hence, the parent of `blockID`
   488  // has to be the last finalized block.
   489  func (m *FollowerState) Finalize(ctx context.Context, blockID flow.Identifier) error {
   490  	// preliminaries: start tracer and retrieve full block
   491  	span, _ := m.tracer.StartSpanFromContext(ctx, trace.ProtoStateMutatorFinalize)
   492  	defer span.End()
   493  	block, err := m.blocks.ByID(blockID)
   494  	if err != nil {
   495  		return fmt.Errorf("could not retrieve full block that should be finalized: %w", err)
   496  	}
   497  	header := block.Header
   498  
   499  	// FIRST: verify that the parent block is the latest finalized block. This
   500  	// must be the case, as the `Finalize(..)` method only finalizes one block
   501  	// at a time and hence the parent of `blockID` must already be finalized.
   502  	var finalized uint64
   503  	err = m.db.View(operation.RetrieveFinalizedHeight(&finalized))
   504  	if err != nil {
   505  		return fmt.Errorf("could not retrieve finalized height: %w", err)
   506  	}
   507  	var finalID flow.Identifier
   508  	err = m.db.View(operation.LookupBlockHeight(finalized, &finalID))
   509  	if err != nil {
   510  		return fmt.Errorf("could not retrieve final header: %w", err)
   511  	}
   512  	if header.ParentID != finalID {
   513  		return fmt.Errorf("can only finalize child of last finalized block")
   514  	}
   515  
   516  	// SECOND: We also want to update the last sealed height. Retrieve the block
   517  	// seal indexed for the block and retrieve the block that was sealed by it.
   518  	last, err := m.seals.HighestInFork(blockID)
   519  	if err != nil {
   520  		return fmt.Errorf("could not look up sealed header: %w", err)
   521  	}
   522  	sealed, err := m.headers.ByBlockID(last.BlockID)
   523  	if err != nil {
   524  		return fmt.Errorf("could not retrieve sealed header: %w", err)
   525  	}
   526  
   527  	// THIRD: preparing Epoch-Phase-Change service notifications and metrics updates.
   528  	// Convention:
   529  	//                            .. <--- P <----- B
   530  	//                                    ↑        ↑
   531  	//             block sealing service event        first block of new
   532  	//           for epoch-phase transition        Epoch phase (e.g.
   533  	//              (e.g. EpochSetup event)        (EpochSetup phase)
   534  	// Per convention, service notifications for Epoch-Phase-Changes are emitted, when
   535  	// the first block of the new phase (EpochSetup phase) is _finalized_. Meaning
   536  	// that the new phase has started.
   537  	epochStatus, err := m.epoch.statuses.ByBlockID(blockID)
   538  	if err != nil {
   539  		return fmt.Errorf("could not retrieve epoch state: %w", err)
   540  	}
   541  	currentEpochSetup, err := m.epoch.setups.ByID(epochStatus.CurrentEpoch.SetupID)
   542  	if err != nil {
   543  		return fmt.Errorf("could not retrieve setup event for current epoch: %w", err)
   544  	}
   545  	parent, err := m.blocks.ByID(header.ParentID)
   546  	if err != nil {
   547  		return fmt.Errorf("could not get parent (id=%x): %w", header.ParentID, err)
   548  	}
   549  
   550  	// EECC - check whether the epoch emergency fallback flag has been set
   551  	// in the database. If so, skip updating any epoch-related metrics.
   552  	epochFallbackTriggered, err := m.isEpochEmergencyFallbackTriggered()
   553  	if err != nil {
   554  		return fmt.Errorf("could not check epoch emergency fallback flag: %w", err)
   555  	}
   556  
   557  	// track service event driven metrics and protocol events that should be emitted
   558  	var events []func()
   559  	for _, seal := range parent.Payload.Seals {
   560  		// skip updating epoch-related metrics if EECC is triggered
   561  		if epochFallbackTriggered {
   562  			break
   563  		}
   564  
   565  		result, err := m.results.ByID(seal.ResultID)
   566  		if err != nil {
   567  			return fmt.Errorf("could not retrieve result (id=%x) for seal (id=%x): %w", seal.ResultID, seal.ID(), err)
   568  		}
   569  		for _, event := range result.ServiceEvents {
   570  			switch ev := event.Event.(type) {
   571  			case *flow.EpochSetup:
   572  				// update current epoch phase
   573  				events = append(events, func() { m.metrics.CurrentEpochPhase(flow.EpochPhaseSetup) })
   574  				// track epoch phase transition (staking->setup)
   575  				events = append(events, func() { m.consumer.EpochSetupPhaseStarted(ev.Counter-1, header) })
   576  			case *flow.EpochCommit:
   577  				// update current epoch phase
   578  				events = append(events, func() { m.metrics.CurrentEpochPhase(flow.EpochPhaseCommitted) })
   579  				// track epoch phase transition (setup->committed)
   580  				events = append(events, func() { m.consumer.EpochCommittedPhaseStarted(ev.Counter-1, header) })
   581  				// track final view of committed epoch
   582  				nextEpochSetup, err := m.epoch.setups.ByID(epochStatus.NextEpoch.SetupID)
   583  				if err != nil {
   584  					return fmt.Errorf("could not retrieve setup event for next epoch: %w", err)
   585  				}
   586  				events = append(events, func() { m.metrics.CommittedEpochFinalView(nextEpochSetup.FinalView) })
   587  			default:
   588  				return fmt.Errorf("invalid service event type in payload (%T)", event)
   589  			}
   590  		}
   591  	}
   592  
   593  	// FOURTH: preparing Epoch-Change service notifications and metrics updates.
   594  	// Convention:
   595  	// Service notifications and updating metrics happen when we finalize the _first_
   596  	// block of the new Epoch (same convention as for Epoch-Phase-Changes)
   597  	// Approach: We retrieve the parent block's epoch information. If this block's view
   598  	// exceeds the final view of its parent's current epoch, this block begins the next epoch.
   599  	parentBlocksEpoch := m.AtBlockID(header.ParentID).Epochs().Current()
   600  	parentEpochFinalView, err := parentBlocksEpoch.FinalView()
   601  	if err != nil {
   602  		return fmt.Errorf("could not get parent epoch final view: %w", err)
   603  	}
   604  
   605  	// When this block's view exceeds the parent epoch's final view, this block
   606  	// represents the first block of the next epoch. Therefore we update metrics
   607  	// related to the epoch transition here.
   608  	//
   609  	// We skip updating these metrics when EECC has been triggered
   610  	if header.View > parentEpochFinalView && !epochFallbackTriggered {
   611  		events = append(events, func() { m.consumer.EpochTransition(currentEpochSetup.Counter, header) })
   612  
   613  		// set current epoch counter corresponding to new epoch
   614  		events = append(events, func() { m.metrics.CurrentEpochCounter(currentEpochSetup.Counter) })
   615  		// set epoch phase - since we are starting a new epoch we begin in the staking phase
   616  		events = append(events, func() { m.metrics.CurrentEpochPhase(flow.EpochPhaseStaking) })
   617  		// set current epoch view values
   618  		events = append(
   619  			events,
   620  			func() { m.metrics.CurrentEpochFinalView(currentEpochSetup.FinalView) },
   621  			func() { m.metrics.CurrentDKGPhase1FinalView(currentEpochSetup.DKGPhase1FinalView) },
   622  			func() { m.metrics.CurrentDKGPhase2FinalView(currentEpochSetup.DKGPhase2FinalView) },
   623  			func() { m.metrics.CurrentDKGPhase3FinalView(currentEpochSetup.DKGPhase3FinalView) },
   624  		)
   625  	}
   626  
   627  	// if EECC is triggered, update metric
   628  	if epochFallbackTriggered {
   629  		m.metrics.EpochEmergencyFallbackTriggered()
   630  	}
   631  
   632  	// FIFTH: Persist updates in database
   633  	// * Add this block to the height-indexed set of finalized blocks.
   634  	// * Update the largest finalized height to this block's height.
   635  	// * Update the largest height of sealed and finalized block.
   636  	//   This value could actually stay the same if it has no seals in
   637  	//   its payload, in which case the parent's seal is the same.
   638  	err = operation.RetryOnConflict(m.db.Update, func(tx *badger.Txn) error {
   639  		err = operation.IndexBlockHeight(header.Height, blockID)(tx)
   640  		if err != nil {
   641  			return fmt.Errorf("could not insert number mapping: %w", err)
   642  		}
   643  		err = operation.UpdateFinalizedHeight(header.Height)(tx)
   644  		if err != nil {
   645  			return fmt.Errorf("could not update finalized height: %w", err)
   646  		}
   647  		err = operation.UpdateSealedHeight(sealed.Height)(tx)
   648  		if err != nil {
   649  			return fmt.Errorf("could not update sealed height: %w", err)
   650  		}
   651  
   652  		// When a block is finalized, we commit the result for each seal it contains. The sealing logic
   653  		// guarantees that only a single, continuous execution fork is sealed. Here, we index for
   654  		// each block ID the ID of its _finalized_ seal.
   655  		for _, seal := range block.Payload.Seals {
   656  			err = operation.IndexFinalizedSealByBlockID(seal.BlockID, seal.ID())(tx)
   657  			if err != nil {
   658  				return fmt.Errorf("could not index the seal by the sealed block ID: %w", err)
   659  			}
   660  		}
   661  
   662  		// emit protocol events within the scope of the Badger transaction to
   663  		// guarantee at-least-once delivery
   664  		m.consumer.BlockFinalized(header)
   665  		for _, emit := range events {
   666  			emit()
   667  		}
   668  		return nil
   669  	})
   670  	if err != nil {
   671  		return fmt.Errorf("could not execute finalization: %w", err)
   672  	}
   673  
   674  	// FINALLY: update metrics
   675  	m.metrics.FinalizedHeight(header.Height)
   676  	m.metrics.SealedHeight(sealed.Height)
   677  	m.metrics.BlockFinalized(block)
   678  
   679  	for _, seal := range block.Payload.Seals {
   680  		sealedBlock, err := m.blocks.ByID(seal.BlockID)
   681  		if err != nil {
   682  			return fmt.Errorf("could not retrieve sealed block (%x): %w", seal.BlockID, err)
   683  		}
   684  		m.metrics.BlockSealed(sealedBlock)
   685  	}
   686  
   687  	return nil
   688  }
   689  
   690  // epochStatus computes the EpochStatus for the given block
   691  // BEFORE applying the block payload itself
   692  // Specifically, we must determine whether block is the first block of a new
   693  // epoch in its respective fork. We do this by comparing the block's view to
   694  // the Epoch data from its parent. If the block's view is _larger_ than the
   695  // final View of the parent's epoch, the block starts a new Epoch.
   696  //   - case (a): block is in same Epoch as parent.
   697  //     the parent's EpochStatus.CurrentEpoch also applies for the current block
   698  //   - case (b): block starts new Epoch in its respective fork.
   699  //     the parent's EpochStatus.NextEpoch is the current block's EpochStatus.CurrentEpoch
   700  //
   701  // As the parent was a valid extension of the chain, by induction, the parent satisfies all
   702  // consistency requirements of the protocol.
   703  //
   704  // Returns:
   705  //   - errIncompleteEpochConfiguration if the epoch has ended before processing
   706  //     both an EpochSetup and EpochCommit event; so the new epoch can't be constructed.
   707  func (m *FollowerState) epochStatus(block *flow.Header) (*flow.EpochStatus, error) {
   708  
   709  	parentStatus, err := m.epoch.statuses.ByBlockID(block.ParentID)
   710  	if err != nil {
   711  		return nil, fmt.Errorf("could not retrieve epoch state for parent: %w", err)
   712  	}
   713  
   714  	// Retrieve EpochSetup and EpochCommit event for parent block's Epoch
   715  	parentSetup, err := m.epoch.setups.ByID(parentStatus.CurrentEpoch.SetupID)
   716  	if err != nil {
   717  		return nil, fmt.Errorf("could not retrieve EpochSetup event for parent: %w", err)
   718  	}
   719  
   720  	if parentSetup.FinalView < block.View { // first block of a new epoch
   721  		// sanity check: parent's epoch Preparation should be completed and have EpochSetup and EpochCommit events
   722  		if parentStatus.NextEpoch.SetupID == flow.ZeroID {
   723  			return nil, fmt.Errorf("missing setup event for starting next epoch: %w", errIncompleteEpochConfiguration)
   724  		}
   725  		if parentStatus.NextEpoch.CommitID == flow.ZeroID {
   726  			return nil, fmt.Errorf("missing commit event for starting next epoch: %w", errIncompleteEpochConfiguration)
   727  		}
   728  		status, err := flow.NewEpochStatus(
   729  			parentStatus.CurrentEpoch.SetupID, parentStatus.CurrentEpoch.CommitID,
   730  			parentStatus.NextEpoch.SetupID, parentStatus.NextEpoch.CommitID,
   731  			flow.ZeroID, flow.ZeroID,
   732  		)
   733  		return status, err
   734  	}
   735  
   736  	// Block is in the same epoch as its parent, re-use the same epoch status
   737  	// IMPORTANT: copy the status to avoid modifying the parent status in the cache
   738  	currentStatus := parentStatus.Copy()
   739  	return currentStatus, err
   740  }
   741  
   742  // handleServiceEvents handles applying state changes which occur as a result
   743  // of service events being included in a block payload.
   744  //
   745  // Consider a chain where a service event is emitted during execution of block A.
   746  // Block B contains a receipt for A. Block C contains a seal for block A. Block
   747  // D contains a QC for C.
   748  //
   749  // A <- B(RA) <- C(SA) <- D
   750  //
   751  // Service events are included within execution results, which are stored
   752  // opaquely as part of the block payload in block B. We only validate and insert
   753  // the typed service event to storage once we have received a valid QC for the
   754  // block containing the seal for A. This occurs once we mark block D as valid
   755  // with MarkValid. Because of this, any change to the protocol state introduced
   756  // by a service event emitted in A would only become visible when querying D or
   757  // later (D's children).
   758  //
   759  // This method will only apply service-event-induced state changes when the
   760  // input block has the form of block D (ie. has a parent, which contains a seal
   761  // for a block in which a service event was emitted).
   762  //
   763  // If the service events are valid, or there are no service events, this method
   764  // returns a slice of Badger operations to apply while storing the block. This
   765  // includes an operation to index the epoch status for every block, and
   766  // operations to insert service events for blocks that include them.
   767  //
   768  // Return values:
   769  //   - ops: pending database operations to persist this processing step
   770  //   - error: no errors expected during normal operations
   771  func (m *FollowerState) handleServiceEvents(block *flow.Block) ([]func(*transaction.Tx) error, error) {
   772  	var ops []func(*transaction.Tx) error
   773  	blockID := block.ID()
   774  
   775  	// Determine epoch status for block's CURRENT epoch.
   776  	//
   777  	// This yields the tentative protocol state BEFORE applying the block payload.
   778  	// As we don't have slashing yet, there is nothing in the payload which could
   779  	// modify the protocol state for the current epoch.
   780  
   781  	epochStatus, err := m.epochStatus(block.Header)
   782  	if errors.Is(err, errIncompleteEpochConfiguration) {
   783  		// TMP: EMERGENCY EPOCH CHAIN CONTINUATION
   784  		//
   785  		// We are proposing or processing the first block of the next epoch,
   786  		// but that epoch has not been setup. Rather than returning an error
   787  		// which prevents further block production, we store the block with
   788  		// the same epoch status as its parent, resulting in it being considered
   789  		// by the protocol state to fall in the same epoch as its parent.
   790  		//
   791  		// CAUTION: this is inconsistent with the FinalView value specified in the epoch.
   792  		parentStatus, err := m.epoch.statuses.ByBlockID(block.Header.ParentID)
   793  		if err != nil {
   794  			return nil, fmt.Errorf("internal error constructing EECC from parent's epoch status: %w", err)
   795  		}
   796  		ops = append(ops, m.epoch.statuses.StoreTx(blockID, parentStatus.Copy()))
   797  		ops = append(ops, transaction.WithTx(operation.SetEpochEmergencyFallbackTriggered(blockID)))
   798  		ops = append(ops, func(tx *transaction.Tx) error {
   799  			tx.OnSucceed(m.metrics.EpochEmergencyFallbackTriggered)
   800  			return nil
   801  		})
   802  		return ops, nil
   803  	} else if err != nil {
   804  		return nil, fmt.Errorf("could not determine epoch status: %w", err)
   805  	}
   806  
   807  	activeSetup, err := m.epoch.setups.ByID(epochStatus.CurrentEpoch.SetupID)
   808  	if err != nil {
   809  		return nil, fmt.Errorf("could not retrieve current epoch setup event: %w", err)
   810  	}
   811  
   812  	// we will apply service events from blocks which are sealed by this block's PARENT
   813  	parent, err := m.blocks.ByID(block.Header.ParentID)
   814  	if err != nil {
   815  		return nil, fmt.Errorf("could not get parent (id=%x): %w", block.Header.ParentID, err)
   816  	}
   817  
   818  	// The payload might contain epoch preparation service events for the next
   819  	// epoch. In this case, we need to update the tentative protocol state.
   820  	// We need to validate whether all information is available in the protocol
   821  	// state to go to the next epoch when needed. In cases where there is a bug
   822  	// in the smart contract, it could be that this happens too late and the
   823  	// chain finalization should halt.
   824  SealLoop:
   825  	for _, seal := range parent.Payload.Seals {
   826  		result, err := m.results.ByID(seal.ResultID)
   827  		if err != nil {
   828  			return nil, fmt.Errorf("could not get result (id=%x) for seal (id=%x): %w", seal.ResultID, seal.ID(), err)
   829  		}
   830  
   831  		for _, event := range result.ServiceEvents {
   832  
   833  			switch ev := event.Event.(type) {
   834  			case *flow.EpochSetup:
   835  
   836  				// validate the service event
   837  				err := isValidExtendingEpochSetup(ev, activeSetup, epochStatus)
   838  				if protocol.IsInvalidServiceEventError(err) {
   839  					// EECC - we have observed an invalid service event, which is
   840  					// an unrecoverable failure. Flag this in the DB and exit
   841  					ops = append(ops, transaction.WithTx(operation.SetEpochEmergencyFallbackTriggered(blockID)))
   842  					break SealLoop
   843  				}
   844  
   845  				// prevents multiple setup events for same Epoch (including multiple setup events in payload of same block)
   846  				epochStatus.NextEpoch.SetupID = ev.ID()
   847  
   848  				// we'll insert the setup event when we insert the block
   849  				ops = append(ops, m.epoch.setups.StoreTx(ev))
   850  
   851  			case *flow.EpochCommit:
   852  
   853  				extendingSetup, err := m.epoch.setups.ByID(epochStatus.NextEpoch.SetupID)
   854  				if err != nil {
   855  					return nil, state.NewInvalidExtensionErrorf("could not retrieve next epoch setup: %s", err)
   856  				}
   857  				// validate the service event
   858  				err = isValidExtendingEpochCommit(ev, extendingSetup, activeSetup, epochStatus)
   859  				if protocol.IsInvalidServiceEventError(err) {
   860  					// EECC - we have observed an invalid service event, which is
   861  					// an unrecoverable failure. Flag this in the DB and exit
   862  					ops = append(ops, transaction.WithTx(operation.SetEpochEmergencyFallbackTriggered(blockID)))
   863  					break SealLoop
   864  				}
   865  
   866  				// prevents multiple setup events for same Epoch (including multiple setup events in payload of same block)
   867  				epochStatus.NextEpoch.CommitID = ev.ID()
   868  
   869  				// we'll insert the commit event when we insert the block
   870  				ops = append(ops, m.epoch.commits.StoreTx(ev))
   871  
   872  			default:
   873  				return nil, fmt.Errorf("invalid service event type: %s", event.Type)
   874  			}
   875  		}
   876  	}
   877  
   878  	// we always index the epoch status, even when there are no service events
   879  	ops = append(ops, m.epoch.statuses.StoreTx(block.ID(), epochStatus))
   880  
   881  	return ops, nil
   882  }
   883  
   884  // MarkValid marks the block as valid in protocol state, and triggers
   885  // `BlockProcessable` event to notify that its parent block is processable.
   886  //
   887  // Why is the parent block processable, not the block itself?
   888  // because a block having a child block means it has been verified
   889  // by the majority of consensus participants.
   890  // Hence, if a block has passed the header validity check, its parent block
   891  // must have passed both the header validity check and the body validity check.
   892  // So that consensus followers can skip the block body validity checks and wait
   893  // for its child to arrive, and if the child passes the header validity check, it means
   894  // the consensus participants have done a complete check on its parent block,
   895  // so consensus followers can trust consensus nodes did the right job, and start
   896  // processing the parent block.
   897  //
   898  // NOTE: since a parent can have multiple children, `BlockProcessable` event
   899  // could be triggered multiple times for the same block.
   900  // NOTE: BlockProcessable should not be blocking, otherwise, it will block the follower
   901  func (m *FollowerState) MarkValid(blockID flow.Identifier) error {
   902  	header, err := m.headers.ByBlockID(blockID)
   903  	if err != nil {
   904  		return fmt.Errorf("could not retrieve block header for %x: %w", blockID, err)
   905  	}
   906  	parentID := header.ParentID
   907  	var isParentValid bool
   908  	err = m.db.View(operation.RetrieveBlockValidity(parentID, &isParentValid))
   909  	if err != nil {
   910  		return fmt.Errorf("could not retrieve validity of parent block (%x): %w", parentID, err)
   911  	}
   912  	if !isParentValid {
   913  		return fmt.Errorf("can only mark block as valid whose parent is valid")
   914  	}
   915  
   916  	parent, err := m.headers.ByBlockID(parentID)
   917  	if err != nil {
   918  		return fmt.Errorf("could not retrieve block header for %x: %w", parentID, err)
   919  	}
   920  	// root blocks and blocks below the root block are considered as "processed",
   921  	// so we don't want to trigger `BlockProcessable` event for them.
   922  	var rootHeight uint64
   923  	err = m.db.View(operation.RetrieveRootHeight(&rootHeight))
   924  	if err != nil {
   925  		return fmt.Errorf("could not retrieve root block's height: %w", err)
   926  	}
   927  
   928  	err = operation.RetryOnConflict(m.db.Update, func(tx *badger.Txn) error {
   929  		// insert block validity for this block
   930  		err = operation.SkipDuplicates(operation.InsertBlockValidity(blockID, true))(tx)
   931  		if err != nil {
   932  			return fmt.Errorf("could not insert validity for block (id=%x, height=%d): %w", blockID, header.Height, err)
   933  		}
   934  
   935  		// trigger BlockProcessable for parent blocks above root height
   936  		if parent.Height > rootHeight {
   937  			// emit protocol event within the scope of the Badger transaction to
   938  			// guarantee at-least-once delivery
   939  			m.consumer.BlockProcessable(parent)
   940  		}
   941  		return nil
   942  	})
   943  	if err != nil {
   944  		return fmt.Errorf("could not mark block as valid (%x): %w", blockID, err)
   945  	}
   946  
   947  	return nil
   948  }