github.com/koko1123/flow-go-1@v0.29.6/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  	grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
    13  	"github.com/onflow/flow/protobuf/go/flow/execution"
    14  	"github.com/rs/zerolog"
    15  	"google.golang.org/grpc"
    16  	"google.golang.org/grpc/codes"
    17  	"google.golang.org/grpc/status"
    18  
    19  	"github.com/koko1123/flow-go-1/consensus/hotstuff"
    20  	"github.com/koko1123/flow-go-1/engine"
    21  	"github.com/koko1123/flow-go-1/engine/common/rpc"
    22  	"github.com/koko1123/flow-go-1/engine/common/rpc/convert"
    23  	"github.com/koko1123/flow-go-1/engine/execution/ingestion"
    24  	"github.com/koko1123/flow-go-1/model/flow"
    25  	"github.com/koko1123/flow-go-1/state/protocol"
    26  	"github.com/koko1123/flow-go-1/storage"
    27  	"github.com/koko1123/flow-go-1/utils/grpcutils"
    28  )
    29  
    30  // Config defines the configurable options for the gRPC server.
    31  type Config struct {
    32  	ListenAddr        string
    33  	MaxMsgSize        int  // In bytes
    34  	RpcMetricsEnabled bool // enable GRPC metrics reporting
    35  }
    36  
    37  // Engine implements a gRPC server with a simplified version of the Observation API.
    38  type Engine struct {
    39  	unit    *engine.Unit
    40  	log     zerolog.Logger
    41  	handler *handler     // the gRPC service implementation
    42  	server  *grpc.Server // the gRPC server
    43  	config  Config
    44  }
    45  
    46  // New returns a new RPC engine.
    47  func New(
    48  	log zerolog.Logger,
    49  	config Config,
    50  	e *ingestion.Engine,
    51  	headers storage.Headers,
    52  	state protocol.State,
    53  	events storage.Events,
    54  	exeResults storage.ExecutionResults,
    55  	txResults storage.TransactionResults,
    56  	commits storage.Commits,
    57  	chainID flow.ChainID,
    58  	signerIndicesDecoder hotstuff.BlockSignerDecoder,
    59  	apiRatelimits map[string]int, // the api rate limit (max calls per second) for each of the gRPC API e.g. Ping->100, ExecuteScriptAtBlockID->300
    60  	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
    61  ) *Engine {
    62  	log = log.With().Str("engine", "rpc").Logger()
    63  	if config.MaxMsgSize == 0 {
    64  		config.MaxMsgSize = grpcutils.DefaultMaxMsgSize
    65  	}
    66  
    67  	serverOptions := []grpc.ServerOption{
    68  		grpc.MaxRecvMsgSize(config.MaxMsgSize),
    69  		grpc.MaxSendMsgSize(config.MaxMsgSize),
    70  	}
    71  
    72  	var interceptors []grpc.UnaryServerInterceptor // ordered list of interceptors
    73  	// if rpc metrics is enabled, add the grpc metrics interceptor as a server option
    74  	if config.RpcMetricsEnabled {
    75  		interceptors = append(interceptors, grpc_prometheus.UnaryServerInterceptor)
    76  	}
    77  
    78  	if len(apiRatelimits) > 0 {
    79  		// create a rate limit interceptor
    80  		rateLimitInterceptor := rpc.NewRateLimiterInterceptor(log, apiRatelimits, apiBurstLimits).UnaryServerInterceptor
    81  		// append the rate limit interceptor to the list of interceptors
    82  		interceptors = append(interceptors, rateLimitInterceptor)
    83  	}
    84  
    85  	// create a chained unary interceptor
    86  	chainedInterceptors := grpc.ChainUnaryInterceptor(interceptors...)
    87  	serverOptions = append(serverOptions, chainedInterceptors)
    88  
    89  	server := grpc.NewServer(serverOptions...)
    90  
    91  	eng := &Engine{
    92  		log:  log,
    93  		unit: engine.NewUnit(),
    94  		handler: &handler{
    95  			engine:               e,
    96  			chain:                chainID,
    97  			headers:              headers,
    98  			state:                state,
    99  			signerIndicesDecoder: signerIndicesDecoder,
   100  			events:               events,
   101  			exeResults:           exeResults,
   102  			transactionResults:   txResults,
   103  			commits:              commits,
   104  			log:                  log,
   105  		},
   106  		server: server,
   107  		config: config,
   108  	}
   109  
   110  	if config.RpcMetricsEnabled {
   111  		grpc_prometheus.EnableHandlingTimeHistogram()
   112  		grpc_prometheus.Register(server)
   113  	}
   114  
   115  	execution.RegisterExecutionAPIServer(eng.server, eng.handler)
   116  
   117  	return eng
   118  }
   119  
   120  // Ready returns a ready channel that is closed once the engine has fully
   121  // started. The RPC engine is ready when the gRPC server has successfully
   122  // started.
   123  func (e *Engine) Ready() <-chan struct{} {
   124  	e.unit.Launch(e.serve)
   125  	return e.unit.Ready()
   126  }
   127  
   128  // Done returns a done channel that is closed once the engine has fully stopped.
   129  // It sends a signal to stop the gRPC server, then closes the channel.
   130  func (e *Engine) Done() <-chan struct{} {
   131  	return e.unit.Done(e.server.GracefulStop)
   132  }
   133  
   134  // serve starts the gRPC server .
   135  //
   136  // When this function returns, the server is considered ready.
   137  func (e *Engine) serve() {
   138  	e.log.Info().Msgf("starting server on address %s", e.config.ListenAddr)
   139  
   140  	l, err := net.Listen("tcp", e.config.ListenAddr)
   141  	if err != nil {
   142  		e.log.Err(err).Msg("failed to start server")
   143  		return
   144  	}
   145  
   146  	err = e.server.Serve(l)
   147  	if err != nil {
   148  		e.log.Err(err).Msg("fatal error in server")
   149  	}
   150  }
   151  
   152  // handler implements a subset of the Observation API.
   153  type handler struct {
   154  	engine               ingestion.IngestRPC
   155  	chain                flow.ChainID
   156  	headers              storage.Headers
   157  	state                protocol.State
   158  	signerIndicesDecoder hotstuff.BlockSignerDecoder
   159  	events               storage.Events
   160  	exeResults           storage.ExecutionResults
   161  	transactionResults   storage.TransactionResults
   162  	log                  zerolog.Logger
   163  	commits              storage.Commits
   164  }
   165  
   166  var _ execution.ExecutionAPIServer = &handler{}
   167  
   168  // Ping responds to requests when the server is up.
   169  func (h *handler) Ping(_ context.Context, _ *execution.PingRequest) (*execution.PingResponse, error) {
   170  	return &execution.PingResponse{}, nil
   171  }
   172  
   173  func (h *handler) ExecuteScriptAtBlockID(
   174  	ctx context.Context,
   175  	req *execution.ExecuteScriptAtBlockIDRequest,
   176  ) (*execution.ExecuteScriptAtBlockIDResponse, error) {
   177  
   178  	blockID, err := convert.BlockID(req.GetBlockId())
   179  	if err != nil {
   180  		return nil, err
   181  	}
   182  
   183  	value, err := h.engine.ExecuteScriptAtBlockID(ctx, req.GetScript(), req.GetArguments(), blockID)
   184  	if err != nil {
   185  		// return code 3 as this passes the litmus test in our context
   186  		return nil, status.Errorf(codes.InvalidArgument, "failed to execute script: %v", err)
   187  	}
   188  
   189  	res := &execution.ExecuteScriptAtBlockIDResponse{
   190  		Value: value,
   191  	}
   192  
   193  	return res, nil
   194  }
   195  
   196  func (h *handler) GetRegisterAtBlockID(
   197  	ctx context.Context,
   198  	req *execution.GetRegisterAtBlockIDRequest,
   199  ) (*execution.GetRegisterAtBlockIDResponse, error) {
   200  
   201  	blockID, err := convert.BlockID(req.GetBlockId())
   202  	if err != nil {
   203  		return nil, err
   204  	}
   205  
   206  	owner := req.GetRegisterOwner()
   207  	key := req.GetRegisterKey()
   208  	value, err := h.engine.GetRegisterAtBlockID(ctx, owner, key, blockID)
   209  
   210  	if err != nil {
   211  		return nil, status.Errorf(codes.Internal, "failed to collect register  (owner : %s, key: %s): %v", hex.EncodeToString(owner), string(key), err)
   212  	}
   213  
   214  	res := &execution.GetRegisterAtBlockIDResponse{
   215  		Value: value,
   216  	}
   217  
   218  	return res, nil
   219  }
   220  
   221  func (h *handler) GetEventsForBlockIDs(_ context.Context,
   222  	req *execution.GetEventsForBlockIDsRequest) (*execution.GetEventsForBlockIDsResponse, error) {
   223  
   224  	// validate request
   225  	blockIDs := req.GetBlockIds()
   226  	flowBlockIDs, err := convert.BlockIDs(blockIDs)
   227  	if err != nil {
   228  		return nil, err
   229  	}
   230  	reqEvent := req.GetType()
   231  	eType, err := convert.EventType(reqEvent)
   232  	if err != nil {
   233  		return nil, err
   234  	}
   235  
   236  	results := make([]*execution.GetEventsForBlockIDsResponse_Result, len(blockIDs))
   237  
   238  	// collect all the events and create a EventsResponse_Result for each block
   239  	for i, bID := range flowBlockIDs {
   240  		// Check if block has been executed
   241  		if _, err := h.commits.ByBlockID(bID); err != nil {
   242  			if errors.Is(err, storage.ErrNotFound) {
   243  				return nil, status.Errorf(codes.NotFound, "state commitment for block ID %s does not exist", bID)
   244  			}
   245  			return nil, status.Errorf(codes.Internal, "state commitment for block ID %s could not be retrieved", bID)
   246  		}
   247  
   248  		// lookup events
   249  		blockEvents, err := h.events.ByBlockIDEventType(bID, flow.EventType(eType))
   250  		if err != nil {
   251  			return nil, status.Errorf(codes.Internal, "failed to get events for block: %v", err)
   252  		}
   253  
   254  		result, err := h.eventResult(bID, blockEvents)
   255  		if err != nil {
   256  			return nil, err
   257  		}
   258  		results[i] = result
   259  
   260  	}
   261  
   262  	return &execution.GetEventsForBlockIDsResponse{
   263  		Results: results,
   264  	}, nil
   265  }
   266  
   267  func (h *handler) GetTransactionResult(
   268  	_ context.Context,
   269  	req *execution.GetTransactionResultRequest,
   270  ) (*execution.GetTransactionResultResponse, error) {
   271  
   272  	reqBlockID := req.GetBlockId()
   273  	blockID, err := convert.BlockID(reqBlockID)
   274  	if err != nil {
   275  		return nil, err
   276  	}
   277  
   278  	reqTxID := req.GetTransactionId()
   279  	txID, err := convert.TransactionID(reqTxID)
   280  	if err != nil {
   281  		return nil, err
   282  	}
   283  
   284  	var statusCode uint32 = 0
   285  	errMsg := ""
   286  
   287  	// lookup any transaction error that might have occurred
   288  	txResult, err := h.transactionResults.ByBlockIDTransactionID(blockID, txID)
   289  	if err != nil {
   290  		if errors.Is(err, storage.ErrNotFound) {
   291  			return nil, status.Error(codes.NotFound, "transaction result not found")
   292  		}
   293  
   294  		return nil, status.Errorf(codes.Internal, "failed to get transaction result: %v", err)
   295  	}
   296  
   297  	if txResult.ErrorMessage != "" {
   298  		cadenceErrMessage := txResult.ErrorMessage
   299  		if !utf8.ValidString(cadenceErrMessage) {
   300  			h.log.Warn().
   301  				Str("block_id", blockID.String()).
   302  				Str("transaction_id", txID.String()).
   303  				Str("error_mgs", fmt.Sprintf("%q", cadenceErrMessage)).
   304  				Msg("invalid character in Cadence error message")
   305  			// convert non UTF-8 string to a UTF-8 string for safe GRPC marshaling
   306  			cadenceErrMessage = strings.ToValidUTF8(txResult.ErrorMessage, "?")
   307  		}
   308  
   309  		statusCode = 1 // for now a statusCode of 1 indicates an error and 0 indicates no error
   310  		errMsg = cadenceErrMessage
   311  	}
   312  
   313  	// lookup events by block id and transaction ID
   314  	blockEvents, err := h.events.ByBlockIDTransactionID(blockID, txID)
   315  	if err != nil {
   316  		return nil, status.Errorf(codes.Internal, "failed to get events for block: %v", err)
   317  	}
   318  
   319  	events := convert.EventsToMessages(blockEvents)
   320  
   321  	// compose a response with the events and the transaction error
   322  	return &execution.GetTransactionResultResponse{
   323  		StatusCode:   statusCode,
   324  		ErrorMessage: errMsg,
   325  		Events:       events,
   326  	}, nil
   327  }
   328  
   329  func (h *handler) GetTransactionResultByIndex(
   330  	_ context.Context,
   331  	req *execution.GetTransactionByIndexRequest,
   332  ) (*execution.GetTransactionResultResponse, error) {
   333  
   334  	reqBlockID := req.GetBlockId()
   335  	blockID, err := convert.BlockID(reqBlockID)
   336  	if err != nil {
   337  		return nil, err
   338  	}
   339  
   340  	index := req.GetIndex()
   341  
   342  	var statusCode uint32 = 0
   343  	errMsg := ""
   344  
   345  	// lookup any transaction error that might have occurred
   346  	txResult, err := h.transactionResults.ByBlockIDTransactionIndex(blockID, index)
   347  	if err != nil {
   348  		if errors.Is(err, storage.ErrNotFound) {
   349  			return nil, status.Error(codes.NotFound, "transaction result not found")
   350  		}
   351  
   352  		return nil, status.Errorf(codes.Internal, "failed to get transaction result: %v", err)
   353  	}
   354  
   355  	if txResult.ErrorMessage != "" {
   356  		cadenceErrMessage := txResult.ErrorMessage
   357  		if !utf8.ValidString(cadenceErrMessage) {
   358  			h.log.Warn().
   359  				Str("block_id", blockID.String()).
   360  				Uint32("index", index).
   361  				Str("error_mgs", fmt.Sprintf("%q", cadenceErrMessage)).
   362  				Msg("invalid character in Cadence error message")
   363  			// convert non UTF-8 string to a UTF-8 string for safe GRPC marshaling
   364  			cadenceErrMessage = strings.ToValidUTF8(txResult.ErrorMessage, "?")
   365  		}
   366  
   367  		statusCode = 1 // for now a statusCode of 1 indicates an error and 0 indicates no error
   368  		errMsg = cadenceErrMessage
   369  	}
   370  
   371  	// lookup events by block id and transaction index
   372  	txEvents, err := h.events.ByBlockIDTransactionIndex(blockID, index)
   373  	if err != nil {
   374  		return nil, status.Errorf(codes.Internal, "failed to get events for block: %v", err)
   375  	}
   376  
   377  	events := convert.EventsToMessages(txEvents)
   378  
   379  	// compose a response with the events and the transaction error
   380  	return &execution.GetTransactionResultResponse{
   381  		StatusCode:   statusCode,
   382  		ErrorMessage: errMsg,
   383  		Events:       events,
   384  	}, nil
   385  }
   386  
   387  func (h *handler) GetTransactionResultsByBlockID(
   388  	_ context.Context,
   389  	req *execution.GetTransactionsByBlockIDRequest,
   390  ) (*execution.GetTransactionResultsResponse, error) {
   391  
   392  	reqBlockID := req.GetBlockId()
   393  	blockID, err := convert.BlockID(reqBlockID)
   394  	if err != nil {
   395  		return nil, err
   396  	}
   397  
   398  	// Get all tx results
   399  	txResults, err := h.transactionResults.ByBlockID(blockID)
   400  	if err != nil {
   401  		if errors.Is(err, storage.ErrNotFound) {
   402  			return nil, status.Error(codes.NotFound, "transaction results not found")
   403  		}
   404  
   405  		return nil, status.Errorf(codes.Internal, "failed to get transaction result: %v", err)
   406  	}
   407  
   408  	// get all events for a block
   409  	blockEvents, err := h.events.ByBlockID(blockID)
   410  	if err != nil {
   411  		return nil, status.Errorf(codes.Internal, "failed to get events for block: %v", err)
   412  	}
   413  
   414  	responseTxResults := make([]*execution.GetTransactionResultResponse, len(txResults))
   415  
   416  	eventsByTxIndex := make(map[uint32][]flow.Event, len(txResults)) //we will have at most as many buckets as tx results
   417  
   418  	// re-partition events by tx index
   419  	// it's not documented but events are stored indexed by (blockID, event.TransactionID, event.TransactionIndex, event.EventIndex)
   420  	// hence they should keep order within a transaction, so we don't sort resulting events slices
   421  	for _, event := range blockEvents {
   422  		eventsByTxIndex[event.TransactionIndex] = append(eventsByTxIndex[event.TransactionIndex], event)
   423  	}
   424  
   425  	// match tx results with events
   426  	for index, txResult := range txResults {
   427  		var statusCode uint32 = 0
   428  		errMsg := ""
   429  
   430  		txIndex := uint32(index)
   431  
   432  		if txResult.ErrorMessage != "" {
   433  			cadenceErrMessage := txResult.ErrorMessage
   434  			if !utf8.ValidString(cadenceErrMessage) {
   435  				h.log.Warn().
   436  					Str("block_id", blockID.String()).
   437  					Uint32("index", txIndex).
   438  					Str("error_mgs", fmt.Sprintf("%q", cadenceErrMessage)).
   439  					Msg("invalid character in Cadence error message")
   440  				// convert non UTF-8 string to a UTF-8 string for safe GRPC marshaling
   441  				cadenceErrMessage = strings.ToValidUTF8(txResult.ErrorMessage, "?")
   442  			}
   443  
   444  			statusCode = 1 // for now a statusCode of 1 indicates an error and 0 indicates no error
   445  			errMsg = cadenceErrMessage
   446  		}
   447  
   448  		events := convert.EventsToMessages(eventsByTxIndex[txIndex])
   449  
   450  		responseTxResults[index] = &execution.GetTransactionResultResponse{
   451  			StatusCode:   statusCode,
   452  			ErrorMessage: errMsg,
   453  			Events:       events,
   454  		}
   455  	}
   456  
   457  	// compose a response
   458  	return &execution.GetTransactionResultsResponse{
   459  		TransactionResults: responseTxResults,
   460  	}, nil
   461  }
   462  
   463  // eventResult creates EventsResponse_Result from flow.Event for the given blockID
   464  func (h *handler) eventResult(blockID flow.Identifier,
   465  	flowEvents []flow.Event) (*execution.GetEventsForBlockIDsResponse_Result, error) {
   466  
   467  	// convert events to event message
   468  	events := convert.EventsToMessages(flowEvents)
   469  
   470  	// lookup block
   471  	header, err := h.headers.ByBlockID(blockID)
   472  	if err != nil {
   473  		return nil, status.Errorf(codes.Internal, "failed to lookup block: %v", err)
   474  	}
   475  
   476  	return &execution.GetEventsForBlockIDsResponse_Result{
   477  		BlockId:     blockID[:],
   478  		BlockHeight: header.Height,
   479  		Events:      events,
   480  	}, nil
   481  }
   482  
   483  func (h *handler) GetAccountAtBlockID(
   484  	ctx context.Context,
   485  	req *execution.GetAccountAtBlockIDRequest,
   486  ) (*execution.GetAccountAtBlockIDResponse, error) {
   487  
   488  	blockID := req.GetBlockId()
   489  	blockFlowID, err := convert.BlockID(blockID)
   490  	if err != nil {
   491  		return nil, err
   492  	}
   493  
   494  	flowAddress, err := convert.Address(req.GetAddress(), h.chain.Chain())
   495  	if err != nil {
   496  		return nil, err
   497  	}
   498  
   499  	value, err := h.engine.GetAccount(ctx, flowAddress, blockFlowID)
   500  	if err != nil {
   501  		return nil, status.Errorf(codes.Internal, "failed to get account: %v", err)
   502  	}
   503  
   504  	if value == nil {
   505  		return nil, status.Errorf(codes.NotFound, "account with address %s does not exist", flowAddress)
   506  	}
   507  
   508  	account, err := convert.AccountToMessage(value)
   509  	if err != nil {
   510  		return nil, status.Errorf(codes.Internal, "failed to convert account to message: %v", err)
   511  	}
   512  
   513  	res := &execution.GetAccountAtBlockIDResponse{
   514  		Account: account,
   515  	}
   516  
   517  	return res, nil
   518  
   519  }
   520  
   521  // GetLatestBlockHeader gets the latest sealed or finalized block header.
   522  func (h *handler) GetLatestBlockHeader(
   523  	_ context.Context,
   524  	req *execution.GetLatestBlockHeaderRequest,
   525  ) (*execution.BlockHeaderResponse, error) {
   526  	var header *flow.Header
   527  	var err error
   528  
   529  	if req.GetIsSealed() {
   530  		// get the latest seal header from storage
   531  		header, err = h.state.Sealed().Head()
   532  	} else {
   533  		// get the finalized header from state
   534  		header, err = h.state.Final().Head()
   535  	}
   536  	if err != nil {
   537  		return nil, status.Errorf(codes.NotFound, "not found: %v", err)
   538  	}
   539  
   540  	return h.blockHeaderResponse(header)
   541  }
   542  
   543  // GetBlockHeaderByID gets a block header by ID.
   544  func (h *handler) GetBlockHeaderByID(
   545  	_ context.Context,
   546  	req *execution.GetBlockHeaderByIDRequest,
   547  ) (*execution.BlockHeaderResponse, error) {
   548  	id, err := convert.BlockID(req.GetId())
   549  	if err != nil {
   550  		return nil, err
   551  	}
   552  	header, err := h.headers.ByBlockID(id)
   553  	if err != nil {
   554  		return nil, status.Errorf(codes.NotFound, "not found: %v", err)
   555  	}
   556  	return h.blockHeaderResponse(header)
   557  }
   558  
   559  func (h *handler) blockHeaderResponse(header *flow.Header) (*execution.BlockHeaderResponse, error) {
   560  	signerIDs, err := h.signerIndicesDecoder.DecodeSignerIDs(header)
   561  	if err != nil {
   562  		return nil, fmt.Errorf("failed to decode signer indices to Identifiers for block %v: %w", header.ID(), err)
   563  	}
   564  
   565  	msg, err := convert.BlockHeaderToMessage(header, signerIDs)
   566  	if err != nil {
   567  		return nil, err
   568  	}
   569  
   570  	return &execution.BlockHeaderResponse{
   571  		Block: msg,
   572  	}, nil
   573  }