github.com/onflow/flow-go@v0.33.17/engine/execution/rpc/engine.go (about)

     1  package rpc
     2  
     3  import (
     4  	"context"
     5  	"encoding/hex"
     6  	"errors"
     7  	"fmt"
     8  	"net"
     9  	"strings"
    10  	"unicode/utf8"
    11  
    12  	"github.com/onflow/flow/protobuf/go/flow/entities"
    13  
    14  	grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
    15  	"github.com/onflow/flow/protobuf/go/flow/execution"
    16  	"github.com/rs/zerolog"
    17  	"google.golang.org/grpc"
    18  	"google.golang.org/grpc/codes"
    19  	_ "google.golang.org/grpc/encoding/gzip" // required for gRPC compression
    20  	"google.golang.org/grpc/status"
    21  
    22  	"github.com/onflow/flow-go/consensus/hotstuff"
    23  	"github.com/onflow/flow-go/engine"
    24  	_ "github.com/onflow/flow-go/engine/common/grpc/compressor/deflate" // required for gRPC compression
    25  	_ "github.com/onflow/flow-go/engine/common/grpc/compressor/snappy"  // required for gRPC compression
    26  	"github.com/onflow/flow-go/engine/common/rpc"
    27  	"github.com/onflow/flow-go/engine/common/rpc/convert"
    28  	exeEng "github.com/onflow/flow-go/engine/execution"
    29  	"github.com/onflow/flow-go/engine/execution/state"
    30  	fvmerrors "github.com/onflow/flow-go/fvm/errors"
    31  	"github.com/onflow/flow-go/model/flow"
    32  	"github.com/onflow/flow-go/state/protocol"
    33  	"github.com/onflow/flow-go/storage"
    34  )
    35  
    36  const DefaultMaxBlockRange = 300
    37  
    38  // Config defines the configurable options for the gRPC server.
    39  type Config struct {
    40  	ListenAddr        string
    41  	MaxMsgSize        uint // In bytes
    42  	RpcMetricsEnabled bool // enable GRPC metrics reporting
    43  }
    44  
    45  // Engine implements a gRPC server with a simplified version of the Observation API.
    46  type Engine struct {
    47  	unit    *engine.Unit
    48  	log     zerolog.Logger
    49  	handler *handler     // the gRPC service implementation
    50  	server  *grpc.Server // the gRPC server
    51  	config  Config
    52  }
    53  
    54  // New returns a new RPC engine.
    55  func New(
    56  	log zerolog.Logger,
    57  	config Config,
    58  	scriptsExecutor exeEng.ScriptExecutor,
    59  	headers storage.Headers,
    60  	state protocol.State,
    61  	events storage.Events,
    62  	exeResults storage.ExecutionResults,
    63  	txResults storage.TransactionResults,
    64  	commits storage.Commits,
    65  	chainID flow.ChainID,
    66  	signerIndicesDecoder hotstuff.BlockSignerDecoder,
    67  	apiRatelimits map[string]int, // the api rate limit (max calls per second) for each of the gRPC API e.g. Ping->100, ExecuteScriptAtBlockID->300
    68  	apiBurstLimits map[string]int, // the api burst limit (max calls at the same time) for each of the gRPC API e.g. Ping->50, ExecuteScriptAtBlockID->10
    69  ) *Engine {
    70  	log = log.With().Str("engine", "rpc").Logger()
    71  	serverOptions := []grpc.ServerOption{
    72  		grpc.MaxRecvMsgSize(int(config.MaxMsgSize)),
    73  		grpc.MaxSendMsgSize(int(config.MaxMsgSize)),
    74  	}
    75  
    76  	var interceptors []grpc.UnaryServerInterceptor // ordered list of interceptors
    77  	// if rpc metrics is enabled, add the grpc metrics interceptor as a server option
    78  	if config.RpcMetricsEnabled {
    79  		interceptors = append(interceptors, grpc_prometheus.UnaryServerInterceptor)
    80  	}
    81  
    82  	if len(apiRatelimits) > 0 {
    83  		// create a rate limit interceptor
    84  		rateLimitInterceptor := rpc.NewRateLimiterInterceptor(log, apiRatelimits, apiBurstLimits).UnaryServerInterceptor
    85  		// append the rate limit interceptor to the list of interceptors
    86  		interceptors = append(interceptors, rateLimitInterceptor)
    87  	}
    88  
    89  	// create a chained unary interceptor
    90  	chainedInterceptors := grpc.ChainUnaryInterceptor(interceptors...)
    91  	serverOptions = append(serverOptions, chainedInterceptors)
    92  
    93  	server := grpc.NewServer(serverOptions...)
    94  
    95  	eng := &Engine{
    96  		log:  log,
    97  		unit: engine.NewUnit(),
    98  		handler: &handler{
    99  			engine:               scriptsExecutor,
   100  			chain:                chainID,
   101  			headers:              headers,
   102  			state:                state,
   103  			signerIndicesDecoder: signerIndicesDecoder,
   104  			events:               events,
   105  			exeResults:           exeResults,
   106  			transactionResults:   txResults,
   107  			commits:              commits,
   108  			log:                  log,
   109  			maxBlockRange:        DefaultMaxBlockRange,
   110  		},
   111  		server: server,
   112  		config: config,
   113  	}
   114  
   115  	if config.RpcMetricsEnabled {
   116  		grpc_prometheus.EnableHandlingTimeHistogram()
   117  		grpc_prometheus.Register(server)
   118  	}
   119  
   120  	execution.RegisterExecutionAPIServer(eng.server, eng.handler)
   121  
   122  	return eng
   123  }
   124  
   125  // Ready returns a ready channel that is closed once the engine has fully
   126  // started. The RPC engine is ready when the gRPC server has successfully
   127  // started.
   128  func (e *Engine) Ready() <-chan struct{} {
   129  	e.unit.Launch(e.serve)
   130  	return e.unit.Ready()
   131  }
   132  
   133  // Done returns a done channel that is closed once the engine has fully stopped.
   134  // It sends a signal to stop the gRPC server, then closes the channel.
   135  func (e *Engine) Done() <-chan struct{} {
   136  	return e.unit.Done(e.server.GracefulStop)
   137  }
   138  
   139  // serve starts the gRPC server .
   140  //
   141  // When this function returns, the server is considered ready.
   142  func (e *Engine) serve() {
   143  	e.log.Info().Msgf("starting server on address %s", e.config.ListenAddr)
   144  
   145  	l, err := net.Listen("tcp", e.config.ListenAddr)
   146  	if err != nil {
   147  		e.log.Err(err).Msg("failed to start server")
   148  		return
   149  	}
   150  
   151  	err = e.server.Serve(l)
   152  	if err != nil {
   153  		e.log.Err(err).Msg("fatal error in server")
   154  	}
   155  }
   156  
   157  // handler implements a subset of the Observation API.
   158  type handler struct {
   159  	engine               exeEng.ScriptExecutor
   160  	chain                flow.ChainID
   161  	headers              storage.Headers
   162  	state                protocol.State
   163  	signerIndicesDecoder hotstuff.BlockSignerDecoder
   164  	events               storage.Events
   165  	exeResults           storage.ExecutionResults
   166  	transactionResults   storage.TransactionResults
   167  	log                  zerolog.Logger
   168  	commits              storage.Commits
   169  	maxBlockRange        int
   170  }
   171  
   172  var _ execution.ExecutionAPIServer = (*handler)(nil)
   173  
   174  // Ping responds to requests when the server is up.
   175  func (h *handler) Ping(
   176  	_ context.Context,
   177  	_ *execution.PingRequest,
   178  ) (*execution.PingResponse, error) {
   179  	return &execution.PingResponse{}, nil
   180  }
   181  
   182  func (h *handler) ExecuteScriptAtBlockID(
   183  	ctx context.Context,
   184  	req *execution.ExecuteScriptAtBlockIDRequest,
   185  ) (*execution.ExecuteScriptAtBlockIDResponse, error) {
   186  
   187  	blockID, err := convert.BlockID(req.GetBlockId())
   188  	if err != nil {
   189  		return nil, err
   190  	}
   191  
   192  	// return a more user friendly error if block has not been executed
   193  	if _, err = h.commits.ByBlockID(blockID); err != nil {
   194  		if errors.Is(err, storage.ErrNotFound) {
   195  			return nil, status.Errorf(codes.NotFound, "block %s has not been executed by node or was pruned", blockID)
   196  		}
   197  		return nil, status.Errorf(codes.Internal, "state commitment for block ID %s could not be retrieved", blockID)
   198  	}
   199  
   200  	value, err := h.engine.ExecuteScriptAtBlockID(ctx, req.GetScript(), req.GetArguments(), blockID)
   201  	if err != nil {
   202  		// todo check the error code instead
   203  		// return code 3 as this passes the litmus test in our context
   204  		return nil, status.Errorf(codes.InvalidArgument, "failed to execute script: %v", err)
   205  	}
   206  
   207  	res := &execution.ExecuteScriptAtBlockIDResponse{
   208  		Value: value,
   209  	}
   210  
   211  	return res, nil
   212  }
   213  
   214  func (h *handler) GetRegisterAtBlockID(
   215  	ctx context.Context,
   216  	req *execution.GetRegisterAtBlockIDRequest,
   217  ) (*execution.GetRegisterAtBlockIDResponse, error) {
   218  
   219  	blockID, err := convert.BlockID(req.GetBlockId())
   220  	if err != nil {
   221  		return nil, err
   222  	}
   223  
   224  	owner := req.GetRegisterOwner()
   225  	key := req.GetRegisterKey()
   226  	value, err := h.engine.GetRegisterAtBlockID(ctx, owner, key, blockID)
   227  
   228  	if err != nil {
   229  		return nil, status.Errorf(codes.Internal, "failed to collect register  (owner : %s, key: %s): %v", hex.EncodeToString(owner), string(key), err)
   230  	}
   231  
   232  	res := &execution.GetRegisterAtBlockIDResponse{
   233  		Value: value,
   234  	}
   235  
   236  	return res, nil
   237  }
   238  
   239  func (h *handler) GetEventsForBlockIDs(
   240  	_ context.Context,
   241  	req *execution.GetEventsForBlockIDsRequest,
   242  ) (*execution.GetEventsForBlockIDsResponse, error) {
   243  
   244  	// validate request
   245  	blockIDs := req.GetBlockIds()
   246  	flowBlockIDs, err := convert.BlockIDs(blockIDs)
   247  	if err != nil {
   248  		return nil, err
   249  	}
   250  	reqEvent := req.GetType()
   251  	eType, err := convert.EventType(reqEvent)
   252  	if err != nil {
   253  		return nil, err
   254  	}
   255  
   256  	if len(blockIDs) > h.maxBlockRange {
   257  		return nil, status.Errorf(codes.InvalidArgument, "too many block IDs requested: %d > %d", len(blockIDs), h.maxBlockRange)
   258  	}
   259  
   260  	results := make([]*execution.GetEventsForBlockIDsResponse_Result, len(blockIDs))
   261  
   262  	// collect all the events and create a EventsResponse_Result for each block
   263  	for i, bID := range flowBlockIDs {
   264  		// Check if block has been executed
   265  		if _, err := h.commits.ByBlockID(bID); err != nil {
   266  			if errors.Is(err, storage.ErrNotFound) {
   267  				return nil, status.Errorf(codes.NotFound, "block %s has not been executed by node or was pruned", bID)
   268  			}
   269  			return nil, status.Errorf(codes.Internal, "state commitment for block ID %s could not be retrieved", bID)
   270  		}
   271  
   272  		// lookup events
   273  		blockEvents, err := h.events.ByBlockIDEventType(bID, flow.EventType(eType))
   274  		if err != nil {
   275  			return nil, status.Errorf(codes.Internal, "failed to get events for block: %v", err)
   276  		}
   277  
   278  		result, err := h.eventResult(bID, blockEvents)
   279  		if err != nil {
   280  			return nil, err
   281  		}
   282  		results[i] = result
   283  
   284  	}
   285  
   286  	return &execution.GetEventsForBlockIDsResponse{
   287  		Results:              results,
   288  		EventEncodingVersion: entities.EventEncodingVersion_CCF_V0,
   289  	}, nil
   290  }
   291  
   292  func (h *handler) GetTransactionResult(
   293  	_ context.Context,
   294  	req *execution.GetTransactionResultRequest,
   295  ) (*execution.GetTransactionResultResponse, error) {
   296  
   297  	reqBlockID := req.GetBlockId()
   298  	blockID, err := convert.BlockID(reqBlockID)
   299  	if err != nil {
   300  		return nil, status.Errorf(codes.InvalidArgument, "invalid blockID: %v", err)
   301  	}
   302  
   303  	reqTxID := req.GetTransactionId()
   304  	txID, err := convert.TransactionID(reqTxID)
   305  	if err != nil {
   306  		return nil, status.Errorf(codes.InvalidArgument, "invalid transactionID: %v", err)
   307  	}
   308  
   309  	var statusCode uint32 = 0
   310  	errMsg := ""
   311  
   312  	// lookup any transaction error that might have occurred
   313  	txResult, err := h.transactionResults.ByBlockIDTransactionID(blockID, txID)
   314  	if err != nil {
   315  		if errors.Is(err, storage.ErrNotFound) {
   316  			return nil, status.Error(codes.NotFound, "transaction result not found")
   317  		}
   318  
   319  		return nil, status.Errorf(codes.Internal, "failed to get transaction result: %v", err)
   320  	}
   321  
   322  	if txResult.ErrorMessage != "" {
   323  		cadenceErrMessage := txResult.ErrorMessage
   324  		if !utf8.ValidString(cadenceErrMessage) {
   325  			h.log.Warn().
   326  				Str("block_id", blockID.String()).
   327  				Str("transaction_id", txID.String()).
   328  				Str("error_mgs", fmt.Sprintf("%q", cadenceErrMessage)).
   329  				Msg("invalid character in Cadence error message")
   330  			// convert non UTF-8 string to a UTF-8 string for safe GRPC marshaling
   331  			cadenceErrMessage = strings.ToValidUTF8(txResult.ErrorMessage, "?")
   332  		}
   333  
   334  		statusCode = 1 // for now a statusCode of 1 indicates an error and 0 indicates no error
   335  		errMsg = cadenceErrMessage
   336  	}
   337  
   338  	// lookup events by block id and transaction ID
   339  	blockEvents, err := h.events.ByBlockIDTransactionID(blockID, txID)
   340  	if err != nil {
   341  		return nil, status.Errorf(codes.Internal, "failed to get events for block: %v", err)
   342  	}
   343  
   344  	events := convert.EventsToMessages(blockEvents)
   345  
   346  	// compose a response with the events and the transaction error
   347  	return &execution.GetTransactionResultResponse{
   348  		StatusCode:           statusCode,
   349  		ErrorMessage:         errMsg,
   350  		Events:               events,
   351  		EventEncodingVersion: entities.EventEncodingVersion_CCF_V0,
   352  	}, nil
   353  }
   354  
   355  func (h *handler) GetTransactionResultByIndex(
   356  	_ context.Context,
   357  	req *execution.GetTransactionByIndexRequest,
   358  ) (*execution.GetTransactionResultResponse, error) {
   359  
   360  	reqBlockID := req.GetBlockId()
   361  	blockID, err := convert.BlockID(reqBlockID)
   362  	if err != nil {
   363  		return nil, status.Errorf(codes.InvalidArgument, "invalid blockID: %v", err)
   364  	}
   365  
   366  	index := req.GetIndex()
   367  
   368  	var statusCode uint32 = 0
   369  	errMsg := ""
   370  
   371  	// lookup any transaction error that might have occurred
   372  	txResult, err := h.transactionResults.ByBlockIDTransactionIndex(blockID, index)
   373  	if err != nil {
   374  		if errors.Is(err, storage.ErrNotFound) {
   375  			return nil, status.Error(codes.NotFound, "transaction result not found")
   376  		}
   377  
   378  		return nil, status.Errorf(codes.Internal, "failed to get transaction result: %v", err)
   379  	}
   380  
   381  	if txResult.ErrorMessage != "" {
   382  		cadenceErrMessage := txResult.ErrorMessage
   383  		if !utf8.ValidString(cadenceErrMessage) {
   384  			h.log.Warn().
   385  				Str("block_id", blockID.String()).
   386  				Uint32("index", index).
   387  				Str("error_mgs", fmt.Sprintf("%q", cadenceErrMessage)).
   388  				Msg("invalid character in Cadence error message")
   389  			// convert non UTF-8 string to a UTF-8 string for safe GRPC marshaling
   390  			cadenceErrMessage = strings.ToValidUTF8(txResult.ErrorMessage, "?")
   391  		}
   392  
   393  		statusCode = 1 // for now a statusCode of 1 indicates an error and 0 indicates no error
   394  		errMsg = cadenceErrMessage
   395  	}
   396  
   397  	// lookup events by block id and transaction index
   398  	txEvents, err := h.events.ByBlockIDTransactionIndex(blockID, index)
   399  	if err != nil {
   400  		return nil, status.Errorf(codes.Internal, "failed to get events for block: %v", err)
   401  	}
   402  
   403  	events := convert.EventsToMessages(txEvents)
   404  
   405  	// compose a response with the events and the transaction error
   406  	return &execution.GetTransactionResultResponse{
   407  		StatusCode:           statusCode,
   408  		ErrorMessage:         errMsg,
   409  		Events:               events,
   410  		EventEncodingVersion: entities.EventEncodingVersion_CCF_V0,
   411  	}, nil
   412  }
   413  
   414  func (h *handler) GetTransactionResultsByBlockID(
   415  	_ context.Context,
   416  	req *execution.GetTransactionsByBlockIDRequest,
   417  ) (*execution.GetTransactionResultsResponse, error) {
   418  
   419  	reqBlockID := req.GetBlockId()
   420  	blockID, err := convert.BlockID(reqBlockID)
   421  	if err != nil {
   422  		return nil, status.Errorf(codes.InvalidArgument, "invalid blockID: %v", err)
   423  	}
   424  
   425  	// must verify block was locally executed first since transactionResults.ByBlockID will return
   426  	// an empty slice if block does not exist
   427  	if _, err = h.commits.ByBlockID(blockID); err != nil {
   428  		if errors.Is(err, storage.ErrNotFound) {
   429  			return nil, status.Errorf(codes.NotFound, "block %s has not been executed by node or was pruned", blockID)
   430  		}
   431  		return nil, status.Errorf(codes.Internal, "state commitment for block ID %s could not be retrieved", blockID)
   432  	}
   433  
   434  	// Get all tx results
   435  	txResults, err := h.transactionResults.ByBlockID(blockID)
   436  	if err != nil {
   437  		if errors.Is(err, storage.ErrNotFound) {
   438  			return nil, status.Error(codes.NotFound, "transaction results not found")
   439  		}
   440  
   441  		return nil, status.Errorf(codes.Internal, "failed to get transaction result: %v", err)
   442  	}
   443  
   444  	// get all events for a block
   445  	blockEvents, err := h.events.ByBlockID(blockID)
   446  	if err != nil {
   447  		return nil, status.Errorf(codes.Internal, "failed to get events for block: %v", err)
   448  	}
   449  
   450  	responseTxResults := make([]*execution.GetTransactionResultResponse, len(txResults))
   451  
   452  	eventsByTxIndex := make(map[uint32][]flow.Event, len(txResults)) //we will have at most as many buckets as tx results
   453  
   454  	// re-partition events by tx index
   455  	// it's not documented but events are stored indexed by (blockID, event.TransactionID, event.TransactionIndex, event.EventIndex)
   456  	// hence they should keep order within a transaction, so we don't sort resulting events slices
   457  	for _, event := range blockEvents {
   458  		eventsByTxIndex[event.TransactionIndex] = append(eventsByTxIndex[event.TransactionIndex], event)
   459  	}
   460  
   461  	// match tx results with events
   462  	for index, txResult := range txResults {
   463  		var statusCode uint32 = 0
   464  		errMsg := ""
   465  
   466  		txIndex := uint32(index)
   467  
   468  		if txResult.ErrorMessage != "" {
   469  			cadenceErrMessage := txResult.ErrorMessage
   470  			if !utf8.ValidString(cadenceErrMessage) {
   471  				h.log.Warn().
   472  					Str("block_id", blockID.String()).
   473  					Uint32("index", txIndex).
   474  					Str("error_mgs", fmt.Sprintf("%q", cadenceErrMessage)).
   475  					Msg("invalid character in Cadence error message")
   476  				// convert non UTF-8 string to a UTF-8 string for safe GRPC marshaling
   477  				cadenceErrMessage = strings.ToValidUTF8(txResult.ErrorMessage, "?")
   478  			}
   479  
   480  			statusCode = 1 // for now a statusCode of 1 indicates an error and 0 indicates no error
   481  			errMsg = cadenceErrMessage
   482  		}
   483  
   484  		events := convert.EventsToMessages(eventsByTxIndex[txIndex])
   485  
   486  		responseTxResults[index] = &execution.GetTransactionResultResponse{
   487  			StatusCode:   statusCode,
   488  			ErrorMessage: errMsg,
   489  			Events:       events,
   490  		}
   491  	}
   492  
   493  	// compose a response
   494  	return &execution.GetTransactionResultsResponse{
   495  		TransactionResults:   responseTxResults,
   496  		EventEncodingVersion: entities.EventEncodingVersion_CCF_V0,
   497  	}, nil
   498  }
   499  
   500  // GetTransactionErrorMessage implements a grpc handler for getting a transaction error message by block ID and tx ID.
   501  // Expected error codes during normal operations:
   502  // - codes.InvalidArgument - invalid blockID, tx ID.
   503  // - codes.NotFound - transaction result by tx ID not found.
   504  func (h *handler) GetTransactionErrorMessage(
   505  	_ context.Context,
   506  	req *execution.GetTransactionErrorMessageRequest,
   507  ) (*execution.GetTransactionErrorMessageResponse, error) {
   508  	reqBlockID := req.GetBlockId()
   509  	blockID, err := convert.BlockID(reqBlockID)
   510  	if err != nil {
   511  		return nil, status.Errorf(codes.InvalidArgument, "invalid blockID: %v", err)
   512  	}
   513  
   514  	reqTxID := req.GetTransactionId()
   515  	txID, err := convert.TransactionID(reqTxID)
   516  	if err != nil {
   517  		return nil, status.Errorf(codes.InvalidArgument, "invalid transactionID: %v", err)
   518  	}
   519  
   520  	// lookup any transaction error that might have occurred
   521  	txResult, err := h.transactionResults.ByBlockIDTransactionID(blockID, txID)
   522  	if err != nil {
   523  		if errors.Is(err, storage.ErrNotFound) {
   524  			return nil, status.Error(codes.NotFound, "transaction result not found")
   525  		}
   526  
   527  		return nil, status.Errorf(codes.Internal, "failed to get transaction result: %v", err)
   528  	}
   529  
   530  	result := &execution.GetTransactionErrorMessageResponse{
   531  		TransactionId: convert.IdentifierToMessage(txResult.TransactionID),
   532  	}
   533  
   534  	if len(txResult.ErrorMessage) > 0 {
   535  		cadenceErrMessage := txResult.ErrorMessage
   536  		if !utf8.ValidString(cadenceErrMessage) {
   537  			h.log.Warn().
   538  				Str("block_id", blockID.String()).
   539  				Str("transaction_id", txID.String()).
   540  				Str("error_mgs", fmt.Sprintf("%q", cadenceErrMessage)).
   541  				Msg("invalid character in Cadence error message")
   542  			// convert non UTF-8 string to a UTF-8 string for safe GRPC marshaling
   543  			cadenceErrMessage = strings.ToValidUTF8(txResult.ErrorMessage, "?")
   544  		}
   545  		result.ErrorMessage = cadenceErrMessage
   546  	}
   547  	return result, nil
   548  }
   549  
   550  // GetTransactionErrorMessageByIndex implements a grpc handler for getting a transaction error message by block ID and tx index.
   551  // Expected error codes during normal operations:
   552  // - codes.InvalidArgument - invalid blockID.
   553  // - codes.NotFound - transaction result at index not found.
   554  func (h *handler) GetTransactionErrorMessageByIndex(
   555  	_ context.Context,
   556  	req *execution.GetTransactionErrorMessageByIndexRequest,
   557  ) (*execution.GetTransactionErrorMessageResponse, error) {
   558  	reqBlockID := req.GetBlockId()
   559  	blockID, err := convert.BlockID(reqBlockID)
   560  	if err != nil {
   561  		return nil, status.Errorf(codes.InvalidArgument, "invalid blockID: %v", err)
   562  	}
   563  
   564  	index := req.GetIndex()
   565  
   566  	// lookup any transaction error that might have occurred
   567  	txResult, err := h.transactionResults.ByBlockIDTransactionIndex(blockID, index)
   568  	if err != nil {
   569  		if errors.Is(err, storage.ErrNotFound) {
   570  			return nil, status.Error(codes.NotFound, "transaction result not found")
   571  		}
   572  
   573  		return nil, status.Errorf(codes.Internal, "failed to get transaction result: %v", err)
   574  	}
   575  
   576  	result := &execution.GetTransactionErrorMessageResponse{
   577  		TransactionId: convert.IdentifierToMessage(txResult.TransactionID),
   578  	}
   579  
   580  	if len(txResult.ErrorMessage) > 0 {
   581  		cadenceErrMessage := txResult.ErrorMessage
   582  		if !utf8.ValidString(cadenceErrMessage) {
   583  			h.log.Warn().
   584  				Str("block_id", blockID.String()).
   585  				Str("transaction_id", txResult.TransactionID.String()).
   586  				Str("error_mgs", fmt.Sprintf("%q", cadenceErrMessage)).
   587  				Msg("invalid character in Cadence error message")
   588  			// convert non UTF-8 string to a UTF-8 string for safe GRPC marshaling
   589  			cadenceErrMessage = strings.ToValidUTF8(txResult.ErrorMessage, "?")
   590  		}
   591  		result.ErrorMessage = cadenceErrMessage
   592  	}
   593  	return result, nil
   594  }
   595  
   596  // GetTransactionErrorMessagesByBlockID implements a grpc handler for getting transaction error messages by block ID.
   597  // Only failed transactions will be returned.
   598  // Expected error codes during normal operations:
   599  // - codes.InvalidArgument - invalid blockID.
   600  // - codes.NotFound - block was not executed or was pruned.
   601  func (h *handler) GetTransactionErrorMessagesByBlockID(
   602  	_ context.Context,
   603  	req *execution.GetTransactionErrorMessagesByBlockIDRequest,
   604  ) (*execution.GetTransactionErrorMessagesResponse, error) {
   605  	reqBlockID := req.GetBlockId()
   606  	blockID, err := convert.BlockID(reqBlockID)
   607  	if err != nil {
   608  		return nil, status.Errorf(codes.InvalidArgument, "invalid blockID: %v", err)
   609  	}
   610  
   611  	// must verify block was locally executed first since transactionResults.ByBlockID will return
   612  	// an empty slice if block does not exist
   613  	if _, err = h.commits.ByBlockID(blockID); err != nil {
   614  		if errors.Is(err, storage.ErrNotFound) {
   615  			return nil, status.Errorf(codes.NotFound, "block %s has not been executed by node or was pruned", blockID)
   616  		}
   617  		return nil, status.Errorf(codes.Internal, "state commitment for block ID %s could not be retrieved", blockID)
   618  	}
   619  
   620  	// Get all tx results
   621  	txResults, err := h.transactionResults.ByBlockID(blockID)
   622  	if err != nil {
   623  		if errors.Is(err, storage.ErrNotFound) {
   624  			return nil, status.Error(codes.NotFound, "transaction results not found")
   625  		}
   626  
   627  		return nil, status.Errorf(codes.Internal, "failed to get transaction results: %v", err)
   628  	}
   629  
   630  	var results []*execution.GetTransactionErrorMessagesResponse_Result
   631  	for index, txResult := range txResults {
   632  		if len(txResult.ErrorMessage) == 0 {
   633  			continue
   634  		}
   635  		txIndex := uint32(index)
   636  		cadenceErrMessage := txResult.ErrorMessage
   637  		if !utf8.ValidString(cadenceErrMessage) {
   638  			h.log.Warn().
   639  				Str("block_id", blockID.String()).
   640  				Uint32("index", txIndex).
   641  				Str("error_mgs", fmt.Sprintf("%q", cadenceErrMessage)).
   642  				Msg("invalid character in Cadence error message")
   643  			// convert non UTF-8 string to a UTF-8 string for safe GRPC marshaling
   644  			cadenceErrMessage = strings.ToValidUTF8(txResult.ErrorMessage, "?")
   645  		}
   646  		results = append(results, &execution.GetTransactionErrorMessagesResponse_Result{
   647  			TransactionId: convert.IdentifierToMessage(txResult.TransactionID),
   648  			Index:         txIndex,
   649  			ErrorMessage:  cadenceErrMessage,
   650  		})
   651  	}
   652  
   653  	return &execution.GetTransactionErrorMessagesResponse{
   654  		Results: results,
   655  	}, nil
   656  }
   657  
   658  // eventResult creates EventsResponse_Result from flow.Event for the given blockID
   659  func (h *handler) eventResult(
   660  	blockID flow.Identifier,
   661  	flowEvents []flow.Event,
   662  ) (*execution.GetEventsForBlockIDsResponse_Result, error) {
   663  
   664  	// convert events to event message
   665  	events := convert.EventsToMessages(flowEvents)
   666  
   667  	// lookup block
   668  	header, err := h.headers.ByBlockID(blockID)
   669  	if err != nil {
   670  		return nil, status.Errorf(codes.Internal, "failed to lookup block: %v", err)
   671  	}
   672  
   673  	return &execution.GetEventsForBlockIDsResponse_Result{
   674  		BlockId:     blockID[:],
   675  		BlockHeight: header.Height,
   676  		Events:      events,
   677  	}, nil
   678  }
   679  
   680  func (h *handler) GetAccountAtBlockID(
   681  	ctx context.Context,
   682  	req *execution.GetAccountAtBlockIDRequest,
   683  ) (*execution.GetAccountAtBlockIDResponse, error) {
   684  
   685  	blockID := req.GetBlockId()
   686  	blockFlowID, err := convert.BlockID(blockID)
   687  	if err != nil {
   688  		return nil, status.Errorf(codes.InvalidArgument, "invalid blockID: %v", err)
   689  	}
   690  
   691  	flowAddress, err := convert.Address(req.GetAddress(), h.chain.Chain())
   692  	if err != nil {
   693  		return nil, status.Errorf(codes.InvalidArgument, "invalid address: %v", err)
   694  	}
   695  
   696  	// return a more user friendly error if block has not been executed
   697  	if _, err = h.commits.ByBlockID(blockFlowID); err != nil {
   698  		if errors.Is(err, storage.ErrNotFound) {
   699  			return nil, status.Errorf(codes.NotFound, "block %s has not been executed by node or was pruned", blockFlowID)
   700  		}
   701  		return nil, status.Errorf(codes.Internal, "state commitment for block ID %s could not be retrieved", blockFlowID)
   702  	}
   703  
   704  	value, err := h.engine.GetAccount(ctx, flowAddress, blockFlowID)
   705  	if err != nil {
   706  		if errors.Is(err, state.ErrExecutionStatePruned) {
   707  			return nil, status.Errorf(codes.OutOfRange, "state for block ID %s not available", blockFlowID)
   708  		}
   709  		if errors.Is(err, state.ErrNotExecuted) {
   710  			return nil, status.Errorf(codes.NotFound, "block %s has not been executed by node or was pruned", blockFlowID)
   711  		}
   712  		if errors.Is(err, storage.ErrNotFound) {
   713  			return nil, status.Errorf(codes.NotFound, "block %s not found", blockFlowID)
   714  		}
   715  		if fvmerrors.IsAccountNotFoundError(err) {
   716  			return nil, status.Errorf(codes.NotFound, "account not found")
   717  		}
   718  		return nil, status.Errorf(codes.Internal, "failed to get account: %v", err)
   719  	}
   720  
   721  	if value == nil {
   722  		return nil, status.Errorf(codes.NotFound, "account with address %s does not exist", flowAddress)
   723  	}
   724  
   725  	account, err := convert.AccountToMessage(value)
   726  	if err != nil {
   727  		return nil, status.Errorf(codes.Internal, "failed to convert account to message: %v", err)
   728  	}
   729  
   730  	res := &execution.GetAccountAtBlockIDResponse{
   731  		Account: account,
   732  	}
   733  
   734  	return res, nil
   735  
   736  }
   737  
   738  // GetLatestBlockHeader gets the latest sealed or finalized block header.
   739  func (h *handler) GetLatestBlockHeader(
   740  	_ context.Context,
   741  	req *execution.GetLatestBlockHeaderRequest,
   742  ) (*execution.BlockHeaderResponse, error) {
   743  	var header *flow.Header
   744  	var err error
   745  
   746  	if req.GetIsSealed() {
   747  		// get the latest seal header from storage
   748  		header, err = h.state.Sealed().Head()
   749  	} else {
   750  		// get the finalized header from state
   751  		header, err = h.state.Final().Head()
   752  	}
   753  	if err != nil {
   754  		// this header MUST exist in the db, otherwise the node likely has inconsistent state.
   755  		// Don't crash as a result of an external API request, but other components will likely panic.
   756  		h.log.Err(err).Msg("failed to get latest block header. potentially inconsistent protocol state.")
   757  		return nil, status.Errorf(codes.Internal, "unable to get latest header: %v", err)
   758  	}
   759  
   760  	return h.blockHeaderResponse(header)
   761  }
   762  
   763  // GetBlockHeaderByID gets a block header by ID.
   764  func (h *handler) GetBlockHeaderByID(
   765  	_ context.Context,
   766  	req *execution.GetBlockHeaderByIDRequest,
   767  ) (*execution.BlockHeaderResponse, error) {
   768  	id, err := convert.BlockID(req.GetId())
   769  	if err != nil {
   770  		return nil, err
   771  	}
   772  	header, err := h.headers.ByBlockID(id)
   773  	if err != nil {
   774  		return nil, status.Errorf(codes.NotFound, "not found: %v", err)
   775  	}
   776  	return h.blockHeaderResponse(header)
   777  }
   778  
   779  func (h *handler) blockHeaderResponse(header *flow.Header) (*execution.BlockHeaderResponse, error) {
   780  	signerIDs, err := h.signerIndicesDecoder.DecodeSignerIDs(header)
   781  	if err != nil {
   782  		// the block was retrieved from local storage - so no errors are expected
   783  		return nil, fmt.Errorf("failed to decode signer indices to Identifiers for block %v: %w", header.ID(), err)
   784  	}
   785  
   786  	msg, err := convert.BlockHeaderToMessage(header, signerIDs)
   787  	if err != nil {
   788  		return nil, err
   789  	}
   790  
   791  	return &execution.BlockHeaderResponse{
   792  		Block: msg,
   793  	}, nil
   794  }