github.com/onflow/flow-go@v0.33.17/engine/execution/ingestion/loader/unfinalized_loader.go (about)

     1  package loader
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  
     7  	"github.com/rs/zerolog"
     8  
     9  	"github.com/onflow/flow-go/engine/execution/state"
    10  	"github.com/onflow/flow-go/model/flow"
    11  	"github.com/onflow/flow-go/state/protocol"
    12  	"github.com/onflow/flow-go/storage"
    13  )
    14  
    15  type UnfinalizedLoader struct {
    16  	log       zerolog.Logger
    17  	state     protocol.State
    18  	headers   storage.Headers
    19  	execState state.FinalizedExecutionState
    20  }
    21  
    22  // NewUnfinalizedLoader creates a new loader that loads all unfinalized and validated blocks
    23  func NewUnfinalizedLoader(
    24  	log zerolog.Logger,
    25  	state protocol.State,
    26  	headers storage.Headers,
    27  	execState state.FinalizedExecutionState,
    28  ) *UnfinalizedLoader {
    29  	return &UnfinalizedLoader{
    30  		log:       log.With().Str("component", "ingestion_engine_unfinalized_loader").Logger(),
    31  		state:     state,
    32  		headers:   headers,
    33  		execState: execState,
    34  	}
    35  }
    36  
    37  // LoadUnexecuted loads all unfinalized and validated blocks
    38  // any error returned are exceptions
    39  func (e *UnfinalizedLoader) LoadUnexecuted(ctx context.Context) ([]flow.Identifier, error) {
    40  	lastExecuted := e.execState.GetHighestFinalizedExecuted()
    41  
    42  	// get finalized height
    43  	finalized := e.state.Final()
    44  	final, err := finalized.Head()
    45  	if err != nil {
    46  		return nil, fmt.Errorf("could not get finalized block: %w", err)
    47  	}
    48  
    49  	lg := e.log.With().
    50  		Uint64("last_finalized", final.Height).
    51  		Uint64("last_finalized_executed", lastExecuted).
    52  		Logger()
    53  
    54  	lg.Info().Msgf("start loading unfinalized blocks")
    55  
    56  	// dynamically bootstrapped execution node will have highest finalized executed as sealed root,
    57  	// which is lower than finalized root. so we will reload blocks from
    58  	// [sealedRoot.Height + 1, finalizedRoot.Height] and execute them on startup.
    59  	unexecutedFinalized := make([]flow.Identifier, 0)
    60  
    61  	// starting from the first unexecuted block, go through each unexecuted and finalized block
    62  	// reload its block to execution queues
    63  	// loading finalized blocks
    64  	for height := lastExecuted + 1; height <= final.Height; height++ {
    65  		finalizedID, err := e.headers.BlockIDByHeight(height)
    66  		if err != nil {
    67  			return nil, fmt.Errorf("could not get header at height: %v, %w", height, err)
    68  		}
    69  
    70  		unexecutedFinalized = append(unexecutedFinalized, finalizedID)
    71  	}
    72  
    73  	// loaded all pending blocks
    74  	pendings, err := finalized.Descendants()
    75  	if err != nil {
    76  		return nil, fmt.Errorf("could not get descendants of finalized block: %w", err)
    77  	}
    78  
    79  	unexecuted := append(unexecutedFinalized, pendings...)
    80  
    81  	lg.Info().
    82  		// Uint64("sealed_root_height", rootBlock.Height).
    83  		// Hex("sealed_root_id", logging.Entity(rootBlock)).
    84  		Int("total_finalized_unexecuted", len(unexecutedFinalized)).
    85  		Int("total_unexecuted", len(unexecuted)).
    86  		Msgf("finalized unexecuted blocks")
    87  
    88  	return unexecuted, nil
    89  }