github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/engine/execution/ingestion/machine.go (about)

     1  package ingestion
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  
     7  	"github.com/rs/zerolog"
     8  
     9  	"github.com/onflow/flow-go/engine/common/requester"
    10  	"github.com/onflow/flow-go/engine/execution"
    11  	"github.com/onflow/flow-go/engine/execution/computation"
    12  	"github.com/onflow/flow-go/engine/execution/ingestion/stop"
    13  	"github.com/onflow/flow-go/engine/execution/ingestion/uploader"
    14  	"github.com/onflow/flow-go/engine/execution/provider"
    15  	"github.com/onflow/flow-go/engine/execution/state"
    16  	"github.com/onflow/flow-go/model/flow"
    17  	"github.com/onflow/flow-go/module"
    18  	"github.com/onflow/flow-go/module/mempool/entity"
    19  	"github.com/onflow/flow-go/state/protocol"
    20  	"github.com/onflow/flow-go/state/protocol/events"
    21  	"github.com/onflow/flow-go/storage"
    22  )
    23  
    24  // Machine forwards blocks and collections to the core for processing.
    25  type Machine struct {
    26  	events.Noop        // satisfy protocol events consumer interface
    27  	log                zerolog.Logger
    28  	core               *Core
    29  	throttle           Throttle
    30  	broadcaster        provider.ProviderEngine
    31  	uploader           *uploader.Manager
    32  	execState          state.ExecutionState
    33  	computationManager computation.ComputationManager
    34  }
    35  
    36  type CollectionRequester interface {
    37  	WithHandle(requester.HandleFunc)
    38  }
    39  
    40  func NewMachine(
    41  	logger zerolog.Logger,
    42  	protocolEvents *events.Distributor,
    43  	collectionRequester CollectionRequester,
    44  
    45  	collectionFetcher CollectionFetcher,
    46  	headers storage.Headers,
    47  	blocks storage.Blocks,
    48  	collections storage.Collections,
    49  	execState state.ExecutionState,
    50  	state protocol.State,
    51  	metrics module.ExecutionMetrics,
    52  	computationManager computation.ComputationManager,
    53  	broadcaster provider.ProviderEngine,
    54  	uploader *uploader.Manager,
    55  	stopControl *stop.StopControl,
    56  ) (*Machine, module.ReadyDoneAware, error) {
    57  
    58  	e := &Machine{
    59  		log:                logger.With().Str("engine", "ingestion_machine").Logger(),
    60  		broadcaster:        broadcaster,
    61  		uploader:           uploader,
    62  		execState:          execState,
    63  		computationManager: computationManager,
    64  	}
    65  
    66  	throttle, err := NewBlockThrottle(
    67  		logger,
    68  		state,
    69  		execState,
    70  		headers,
    71  	)
    72  
    73  	if err != nil {
    74  		return nil, nil, fmt.Errorf("failed to create block throttle: %w", err)
    75  	}
    76  
    77  	core, err := NewCore(
    78  		logger,
    79  		throttle,
    80  		execState,
    81  		stopControl,
    82  		blocks,
    83  		collections,
    84  		e,
    85  		collectionFetcher,
    86  		e,
    87  		metrics,
    88  	)
    89  
    90  	if err != nil {
    91  		return nil, nil, fmt.Errorf("failed to create ingestion core: %w", err)
    92  	}
    93  
    94  	e.throttle = throttle
    95  	e.core = core
    96  
    97  	protocolEvents.AddConsumer(e)
    98  	collectionRequester.WithHandle(func(originID flow.Identifier, entity flow.Entity) {
    99  		collection, ok := entity.(*flow.Collection)
   100  		if !ok {
   101  			e.log.Error().Msgf("invalid entity type (%T)", entity)
   102  			return
   103  		}
   104  		e.core.OnCollection(collection)
   105  	})
   106  
   107  	return e, core, nil
   108  }
   109  
   110  // Protocol Events implementation
   111  func (e *Machine) BlockProcessable(header *flow.Header, qc *flow.QuorumCertificate) {
   112  	err := e.throttle.OnBlock(qc.BlockID, header.Height)
   113  	if err != nil {
   114  		e.log.Fatal().Err(err).Msgf("error processing block %v (qc.BlockID: %v, blockID: %v)",
   115  			header.Height, qc.BlockID, header.ID())
   116  	}
   117  }
   118  
   119  func (e *Machine) BlockFinalized(b *flow.Header) {
   120  	e.throttle.OnBlockFinalized(b.Height)
   121  }
   122  
   123  // EventConsumer implementation
   124  var _ EventConsumer = (*Machine)(nil)
   125  
   126  func (e *Machine) BeforeComputationResultSaved(
   127  	ctx context.Context,
   128  	result *execution.ComputationResult,
   129  ) {
   130  	err := e.uploader.Upload(ctx, result)
   131  	if err != nil {
   132  		e.log.Err(err).Msg("error while uploading block")
   133  		// continue processing. uploads should not block execution
   134  	}
   135  }
   136  
   137  func (e *Machine) OnComputationResultSaved(
   138  	ctx context.Context,
   139  	result *execution.ComputationResult,
   140  ) string {
   141  	header := result.BlockExecutionResult.ExecutableBlock.Block.Header
   142  	broadcasted, err := e.broadcaster.BroadcastExecutionReceipt(
   143  		ctx, header.Height, result.ExecutionReceipt)
   144  	if err != nil {
   145  		e.log.Err(err).Msg("critical: failed to broadcast the receipt")
   146  	}
   147  	return fmt.Sprintf("broadcasted: %v", broadcasted)
   148  }
   149  
   150  // BlockExecutor implementation
   151  var _ BlockExecutor = (*Machine)(nil)
   152  
   153  func (e *Machine) ExecuteBlock(ctx context.Context, executableBlock *entity.ExecutableBlock) (*execution.ComputationResult, error) {
   154  	parentID := executableBlock.Block.Header.ParentID
   155  	parentErID, err := e.execState.GetExecutionResultID(ctx, parentID)
   156  	if err != nil {
   157  		return nil, fmt.Errorf("failed to get parent execution result ID %v: %w", parentID, err)
   158  	}
   159  
   160  	snapshot := e.execState.NewStorageSnapshot(*executableBlock.StartState,
   161  		executableBlock.Block.Header.ParentID,
   162  		executableBlock.Block.Header.Height-1,
   163  	)
   164  
   165  	computationResult, err := e.computationManager.ComputeBlock(
   166  		ctx,
   167  		parentErID,
   168  		executableBlock,
   169  		snapshot)
   170  	if err != nil {
   171  		return nil, fmt.Errorf("failed to compute block: %w", err)
   172  	}
   173  
   174  	return computationResult, nil
   175  }