github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/engine/access/state_stream/backend/backend.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/access/index"
    14  	"github.com/onflow/flow-go/engine/access/state_stream"
    15  	"github.com/onflow/flow-go/engine/access/subscription"
    16  	"github.com/onflow/flow-go/model/flow"
    17  	"github.com/onflow/flow-go/module/execution"
    18  	"github.com/onflow/flow-go/module/executiondatasync/execution_data"
    19  	"github.com/onflow/flow-go/module/executiondatasync/execution_data/cache"
    20  	"github.com/onflow/flow-go/state/protocol"
    21  	"github.com/onflow/flow-go/storage"
    22  )
    23  
    24  // Config defines the configurable options for the ingress server.
    25  type Config struct {
    26  	state_stream.EventFilterConfig
    27  
    28  	// ListenAddr is the address the GRPC server will listen on as host:port
    29  	ListenAddr string
    30  
    31  	// MaxExecutionDataMsgSize is the max message size for block execution data API
    32  	MaxExecutionDataMsgSize uint
    33  
    34  	// RpcMetricsEnabled specifies whether to enable the GRPC metrics
    35  	RpcMetricsEnabled bool
    36  
    37  	// MaxGlobalStreams defines the global max number of streams that can be open at the same time.
    38  	MaxGlobalStreams uint32
    39  
    40  	// RegisterIDsRequestLimit defines the max number of register IDs that can be received in a single request.
    41  	RegisterIDsRequestLimit uint32
    42  
    43  	// ExecutionDataCacheSize is the max number of objects for the execution data cache.
    44  	ExecutionDataCacheSize uint32
    45  
    46  	// ClientSendTimeout is the timeout for sending a message to the client. After the timeout,
    47  	// the stream is closed with an error.
    48  	ClientSendTimeout time.Duration
    49  
    50  	// ClientSendBufferSize is the size of the response buffer for sending messages to the client.
    51  	ClientSendBufferSize uint
    52  
    53  	// ResponseLimit is the max responses per second allowed on a stream. After exceeding the limit,
    54  	// the stream is paused until more capacity is available. Searches of past data can be CPU
    55  	// intensive, so this helps manage the impact.
    56  	ResponseLimit float64
    57  
    58  	// HeartbeatInterval specifies the block interval at which heartbeat messages should be sent.
    59  	HeartbeatInterval uint64
    60  }
    61  
    62  type GetExecutionDataFunc func(context.Context, uint64) (*execution_data.BlockExecutionDataEntity, error)
    63  
    64  type StateStreamBackend struct {
    65  	subscription.ExecutionDataTracker
    66  
    67  	ExecutionDataBackend
    68  	EventsBackend
    69  	AccountStatusesBackend
    70  
    71  	log                  zerolog.Logger
    72  	state                protocol.State
    73  	headers              storage.Headers
    74  	seals                storage.Seals
    75  	results              storage.ExecutionResults
    76  	execDataStore        execution_data.ExecutionDataStore
    77  	execDataCache        *cache.ExecutionDataCache
    78  	registers            *execution.RegistersAsyncStore
    79  	registerRequestLimit int
    80  }
    81  
    82  func New(
    83  	log zerolog.Logger,
    84  	state protocol.State,
    85  	headers storage.Headers,
    86  	seals storage.Seals,
    87  	results storage.ExecutionResults,
    88  	execDataStore execution_data.ExecutionDataStore,
    89  	execDataCache *cache.ExecutionDataCache,
    90  	registers *execution.RegistersAsyncStore,
    91  	eventsIndex *index.EventsIndex,
    92  	useEventsIndex bool,
    93  	registerIDsRequestLimit int,
    94  	subscriptionHandler *subscription.SubscriptionHandler,
    95  	executionDataTracker subscription.ExecutionDataTracker,
    96  ) (*StateStreamBackend, error) {
    97  	logger := log.With().Str("module", "state_stream_api").Logger()
    98  
    99  	b := &StateStreamBackend{
   100  		ExecutionDataTracker: executionDataTracker,
   101  		log:                  logger,
   102  		state:                state,
   103  		headers:              headers,
   104  		seals:                seals,
   105  		results:              results,
   106  		execDataStore:        execDataStore,
   107  		execDataCache:        execDataCache,
   108  		registers:            registers,
   109  		registerRequestLimit: registerIDsRequestLimit,
   110  	}
   111  
   112  	b.ExecutionDataBackend = ExecutionDataBackend{
   113  		log:                  logger,
   114  		headers:              headers,
   115  		subscriptionHandler:  subscriptionHandler,
   116  		getExecutionData:     b.getExecutionData,
   117  		executionDataTracker: executionDataTracker,
   118  	}
   119  
   120  	eventsRetriever := EventsRetriever{
   121  		log:              logger,
   122  		headers:          headers,
   123  		getExecutionData: b.getExecutionData,
   124  		useEventsIndex:   useEventsIndex,
   125  		eventsIndex:      eventsIndex,
   126  	}
   127  
   128  	b.EventsBackend = EventsBackend{
   129  		log:                  logger,
   130  		subscriptionHandler:  subscriptionHandler,
   131  		executionDataTracker: executionDataTracker,
   132  		eventsRetriever:      eventsRetriever,
   133  	}
   134  
   135  	b.AccountStatusesBackend = AccountStatusesBackend{
   136  		log:                  logger,
   137  		subscriptionHandler:  subscriptionHandler,
   138  		executionDataTracker: b.ExecutionDataTracker,
   139  		eventsRetriever:      eventsRetriever,
   140  	}
   141  
   142  	return b, nil
   143  }
   144  
   145  // getExecutionData returns the execution data for the given block height.
   146  // Expected errors during normal operation:
   147  // - subscription.ErrBlockNotReady: execution data for the given block height is not available.
   148  func (b *StateStreamBackend) getExecutionData(ctx context.Context, height uint64) (*execution_data.BlockExecutionDataEntity, error) {
   149  	highestHeight := b.ExecutionDataTracker.GetHighestHeight()
   150  	// fail early if no notification has been received for the given block height.
   151  	// note: it's possible for the data to exist in the data store before the notification is
   152  	// received. this ensures a consistent view is available to all streams.
   153  	if height > highestHeight {
   154  		return nil, fmt.Errorf("execution data for block %d is not available yet: %w", height, subscription.ErrBlockNotReady)
   155  	}
   156  
   157  	execData, err := b.execDataCache.ByHeight(ctx, height)
   158  	if err != nil {
   159  		if errors.Is(err, storage.ErrNotFound) ||
   160  			execution_data.IsBlobNotFoundError(err) {
   161  			err = errors.Join(err, subscription.ErrBlockNotReady)
   162  			return nil, fmt.Errorf("could not get execution data for block %d: %w", height, err)
   163  		}
   164  		return nil, fmt.Errorf("could not get execution data for block %d: %w", height, err)
   165  	}
   166  
   167  	return execData, nil
   168  }
   169  
   170  // GetRegisterValues returns the register values for the given register IDs at the given block height.
   171  func (b *StateStreamBackend) GetRegisterValues(ids flow.RegisterIDs, height uint64) ([]flow.RegisterValue, error) {
   172  	if len(ids) > b.registerRequestLimit {
   173  		return nil, status.Errorf(codes.InvalidArgument, "number of register IDs exceeds limit of %d", b.registerRequestLimit)
   174  	}
   175  
   176  	values, err := b.registers.RegisterValues(ids, height)
   177  	if err != nil {
   178  		if errors.Is(err, storage.ErrHeightNotIndexed) {
   179  			return nil, status.Errorf(codes.OutOfRange, "register values for block %d is not available", height)
   180  		}
   181  		if errors.Is(err, storage.ErrNotFound) {
   182  			return nil, status.Errorf(codes.NotFound, "register values for block %d not found", height)
   183  		}
   184  		return nil, err
   185  	}
   186  
   187  	return values, nil
   188  }