github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/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, err := e.execState.GetHighestFinalizedExecuted()
    41  	if err != nil {
    42  		return nil, fmt.Errorf("could not get highest finalized executed: %w", err)
    43  	}
    44  
    45  	// get finalized height
    46  	finalized := e.state.Final()
    47  	final, err := finalized.Head()
    48  	if err != nil {
    49  		return nil, fmt.Errorf("could not get finalized block: %w", err)
    50  	}
    51  
    52  	lg := e.log.With().
    53  		Uint64("last_finalized", final.Height).
    54  		Uint64("last_finalized_executed", lastExecuted).
    55  		Logger()
    56  
    57  	lg.Info().Msgf("start loading unfinalized blocks")
    58  
    59  	// dynamically bootstrapped execution node will have highest finalized executed as sealed root,
    60  	// which is lower than finalized root. so we will reload blocks from
    61  	// [sealedRoot.Height + 1, finalizedRoot.Height] and execute them on startup.
    62  	unexecutedFinalized := make([]flow.Identifier, 0)
    63  
    64  	// starting from the first unexecuted block, go through each unexecuted and finalized block
    65  	// reload its block to execution queues
    66  	// loading finalized blocks
    67  	for height := lastExecuted + 1; height <= final.Height; height++ {
    68  		finalizedID, err := e.headers.BlockIDByHeight(height)
    69  		if err != nil {
    70  			return nil, fmt.Errorf("could not get header at height: %v, %w", height, err)
    71  		}
    72  
    73  		unexecutedFinalized = append(unexecutedFinalized, finalizedID)
    74  	}
    75  
    76  	// loaded all pending blocks
    77  	pendings, err := finalized.Descendants()
    78  	if err != nil {
    79  		return nil, fmt.Errorf("could not get descendants of finalized block: %w", err)
    80  	}
    81  
    82  	unexecuted := append(unexecutedFinalized, pendings...)
    83  
    84  	lg.Info().
    85  		// Uint64("sealed_root_height", rootBlock.Height).
    86  		// Hex("sealed_root_id", logging.Entity(rootBlock)).
    87  		Int("total_finalized_unexecuted", len(unexecutedFinalized)).
    88  		Int("total_unexecuted", len(unexecuted)).
    89  		Msgf("finalized unexecuted blocks")
    90  
    91  	return unexecuted, nil
    92  }