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 }