github.com/onflow/flow-go@v0.33.17/engine/access/state_stream/backend/engine.go (about)

     1  package backend
     2  
     3  import (
     4  	"github.com/rs/zerolog"
     5  
     6  	"github.com/onflow/flow/protobuf/go/flow/executiondata"
     7  
     8  	"github.com/onflow/flow-go/engine"
     9  	"github.com/onflow/flow-go/model/flow"
    10  	"github.com/onflow/flow-go/module/component"
    11  	"github.com/onflow/flow-go/module/executiondatasync/execution_data"
    12  	"github.com/onflow/flow-go/module/executiondatasync/execution_data/cache"
    13  	"github.com/onflow/flow-go/module/grpcserver"
    14  	"github.com/onflow/flow-go/module/irrecoverable"
    15  	"github.com/onflow/flow-go/storage"
    16  	"github.com/onflow/flow-go/utils/logging"
    17  )
    18  
    19  // Engine exposes the server with the state stream API.
    20  // By default, this engine is not enabled.
    21  // In order to run this engine a port for the GRPC server to be served on should be specified in the run config.
    22  type Engine struct {
    23  	*component.ComponentManager
    24  	log     zerolog.Logger
    25  	backend *StateStreamBackend
    26  	config  Config
    27  	chain   flow.Chain
    28  	handler *Handler
    29  
    30  	execDataBroadcaster *engine.Broadcaster
    31  	execDataCache       *cache.ExecutionDataCache
    32  	headers             storage.Headers
    33  }
    34  
    35  // NewEng returns a new ingress server.
    36  func NewEng(
    37  	log zerolog.Logger,
    38  	config Config,
    39  	execDataCache *cache.ExecutionDataCache,
    40  	headers storage.Headers,
    41  	chainID flow.ChainID,
    42  	server *grpcserver.GrpcServer,
    43  	backend *StateStreamBackend,
    44  	broadcaster *engine.Broadcaster,
    45  ) (*Engine, error) {
    46  	logger := log.With().Str("engine", "state_stream_rpc").Logger()
    47  
    48  	e := &Engine{
    49  		log:                 logger,
    50  		backend:             backend,
    51  		headers:             headers,
    52  		chain:               chainID.Chain(),
    53  		config:              config,
    54  		handler:             NewHandler(backend, chainID.Chain(), config),
    55  		execDataBroadcaster: broadcaster,
    56  		execDataCache:       execDataCache,
    57  	}
    58  
    59  	e.ComponentManager = component.NewComponentManagerBuilder().
    60  		AddWorker(func(ctx irrecoverable.SignalerContext, ready component.ReadyFunc) {
    61  			ready()
    62  			<-server.Done()
    63  		}).
    64  		Build()
    65  
    66  	executiondata.RegisterExecutionDataAPIServer(server.Server, e.handler)
    67  
    68  	return e, nil
    69  }
    70  
    71  // OnExecutionData is called to notify the engine when a new execution data is received.
    72  // The caller must guarantee that execution data is locally available for all blocks with
    73  // heights between the initialBlockHeight provided during startup and the block height of
    74  // the execution data provided.
    75  func (e *Engine) OnExecutionData(executionData *execution_data.BlockExecutionDataEntity) {
    76  	lg := e.log.With().Hex("block_id", logging.ID(executionData.BlockID)).Logger()
    77  
    78  	lg.Trace().Msg("received execution data")
    79  
    80  	header, err := e.headers.ByBlockID(executionData.BlockID)
    81  	if err != nil {
    82  		// if the execution data is available, the block must be locally finalized
    83  		lg.Fatal().Err(err).Msg("failed to get header for execution data")
    84  		return
    85  	}
    86  
    87  	if ok := e.backend.setHighestHeight(header.Height); !ok {
    88  		// this means that the height was lower than the current highest height
    89  		// OnExecutionData is guaranteed by the requester to be called in order, but may be called
    90  		// multiple times for the same block.
    91  		lg.Debug().Msg("execution data for block already received")
    92  		return
    93  	}
    94  
    95  	e.execDataBroadcaster.Publish()
    96  }