github.com/onflow/flow-go@v0.33.17/engine/access/state_stream/backend/backend_executiondata.go (about) 1 package backend 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "time" 8 9 "github.com/rs/zerolog" 10 "google.golang.org/grpc/codes" 11 "google.golang.org/grpc/status" 12 13 "github.com/onflow/flow-go/engine" 14 "github.com/onflow/flow-go/engine/access/state_stream" 15 "github.com/onflow/flow-go/engine/common/rpc" 16 "github.com/onflow/flow-go/model/flow" 17 "github.com/onflow/flow-go/module/executiondatasync/execution_data" 18 "github.com/onflow/flow-go/storage" 19 ) 20 21 type ExecutionDataResponse struct { 22 Height uint64 23 ExecutionData *execution_data.BlockExecutionData 24 } 25 26 type ExecutionDataBackend struct { 27 log zerolog.Logger 28 headers storage.Headers 29 broadcaster *engine.Broadcaster 30 sendTimeout time.Duration 31 responseLimit float64 32 sendBufferSize int 33 34 getExecutionData GetExecutionDataFunc 35 getStartHeight GetStartHeightFunc 36 } 37 38 func (b *ExecutionDataBackend) GetExecutionDataByBlockID(ctx context.Context, blockID flow.Identifier) (*execution_data.BlockExecutionData, error) { 39 header, err := b.headers.ByBlockID(blockID) 40 if err != nil { 41 return nil, fmt.Errorf("could not get block header for %s: %w", blockID, err) 42 } 43 44 executionData, err := b.getExecutionData(ctx, header.Height) 45 46 if err != nil { 47 // need custom not found handler due to blob not found error 48 if errors.Is(err, storage.ErrNotFound) || execution_data.IsBlobNotFoundError(err) { 49 return nil, status.Errorf(codes.NotFound, "could not find execution data: %v", err) 50 } 51 52 return nil, rpc.ConvertError(err, "could not get execution data", codes.Internal) 53 } 54 55 return executionData.BlockExecutionData, nil 56 } 57 58 func (b *ExecutionDataBackend) SubscribeExecutionData(ctx context.Context, startBlockID flow.Identifier, startHeight uint64) state_stream.Subscription { 59 nextHeight, err := b.getStartHeight(startBlockID, startHeight) 60 if err != nil { 61 return NewFailedSubscription(err, "could not get start height") 62 } 63 64 sub := NewHeightBasedSubscription(b.sendBufferSize, nextHeight, b.getResponse) 65 66 go NewStreamer(b.log, b.broadcaster, b.sendTimeout, b.responseLimit, sub).Stream(ctx) 67 68 return sub 69 } 70 71 func (b *ExecutionDataBackend) getResponse(ctx context.Context, height uint64) (interface{}, error) { 72 executionData, err := b.getExecutionData(ctx, height) 73 if err != nil { 74 return nil, fmt.Errorf("could not get execution data for block %d: %w", height, err) 75 } 76 77 return &ExecutionDataResponse{ 78 Height: height, 79 ExecutionData: executionData.BlockExecutionData, 80 }, nil 81 }