github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/engine/access/rest/apiproxy/rest_proxy_handler.go (about)

     1  package apiproxy
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  
     7  	"google.golang.org/grpc/status"
     8  
     9  	"github.com/rs/zerolog"
    10  
    11  	"github.com/onflow/flow-go/access"
    12  	"github.com/onflow/flow-go/engine/access/rpc/connection"
    13  	"github.com/onflow/flow-go/engine/common/grpc/forwarder"
    14  	"github.com/onflow/flow-go/engine/common/rpc/convert"
    15  	"github.com/onflow/flow-go/model/flow"
    16  	"github.com/onflow/flow-go/module/metrics"
    17  
    18  	accessproto "github.com/onflow/flow/protobuf/go/flow/access"
    19  	"github.com/onflow/flow/protobuf/go/flow/entities"
    20  )
    21  
    22  // RestProxyHandler is a structure that represents the proxy algorithm for observer node.
    23  // It includes the local backend and forwards the methods which can't be handled locally to an upstream using gRPC API.
    24  type RestProxyHandler struct {
    25  	access.API
    26  	*forwarder.Forwarder
    27  	Logger  zerolog.Logger
    28  	Metrics metrics.ObserverMetrics
    29  	Chain   flow.Chain
    30  }
    31  
    32  // NewRestProxyHandler returns a new rest proxy handler for observer node.
    33  func NewRestProxyHandler(
    34  	api access.API,
    35  	identities flow.IdentitySkeletonList,
    36  	connectionFactory connection.ConnectionFactory,
    37  	log zerolog.Logger,
    38  	metrics metrics.ObserverMetrics,
    39  	chain flow.Chain,
    40  ) (*RestProxyHandler, error) {
    41  	forwarder, err := forwarder.NewForwarder(
    42  		identities,
    43  		connectionFactory,
    44  	)
    45  	if err != nil {
    46  		return nil, fmt.Errorf("could not create REST forwarder: %w", err)
    47  	}
    48  
    49  	restProxyHandler := &RestProxyHandler{
    50  		Logger:  log,
    51  		Metrics: metrics,
    52  		Chain:   chain,
    53  	}
    54  
    55  	restProxyHandler.API = api
    56  	restProxyHandler.Forwarder = forwarder
    57  
    58  	return restProxyHandler, nil
    59  }
    60  
    61  func (r *RestProxyHandler) log(handler, rpc string, err error) {
    62  	code := status.Code(err)
    63  	r.Metrics.RecordRPC(handler, rpc, code)
    64  
    65  	logger := r.Logger.With().
    66  		Str("handler", handler).
    67  		Str("rest_method", rpc).
    68  		Str("rest_code", code.String()).
    69  		Logger()
    70  
    71  	if err != nil {
    72  		logger.Error().Err(err).Msg("request failed")
    73  		return
    74  	}
    75  
    76  	logger.Info().Msg("request succeeded")
    77  }
    78  
    79  // GetCollectionByID returns a collection by ID.
    80  func (r *RestProxyHandler) GetCollectionByID(ctx context.Context, id flow.Identifier) (*flow.LightCollection, error) {
    81  	upstream, closer, err := r.FaultTolerantClient()
    82  	if err != nil {
    83  		return nil, err
    84  	}
    85  	defer closer.Close()
    86  
    87  	getCollectionByIDRequest := &accessproto.GetCollectionByIDRequest{
    88  		Id: id[:],
    89  	}
    90  
    91  	collectionResponse, err := upstream.GetCollectionByID(ctx, getCollectionByIDRequest)
    92  	r.log("upstream", "GetCollectionByID", err)
    93  
    94  	if err != nil {
    95  		return nil, err
    96  	}
    97  
    98  	transactions, err := convert.MessageToLightCollection(collectionResponse.Collection)
    99  	if err != nil {
   100  		return nil, err
   101  	}
   102  
   103  	return transactions, nil
   104  }
   105  
   106  // SendTransaction sends already created transaction.
   107  func (r *RestProxyHandler) SendTransaction(ctx context.Context, tx *flow.TransactionBody) error {
   108  	upstream, closer, err := r.FaultTolerantClient()
   109  	if err != nil {
   110  		return err
   111  	}
   112  	defer closer.Close()
   113  
   114  	transaction := convert.TransactionToMessage(*tx)
   115  	sendTransactionRequest := &accessproto.SendTransactionRequest{
   116  		Transaction: transaction,
   117  	}
   118  
   119  	_, err = upstream.SendTransaction(ctx, sendTransactionRequest)
   120  	r.log("upstream", "SendTransaction", err)
   121  
   122  	return err
   123  }
   124  
   125  // GetTransaction returns transaction by ID.
   126  func (r *RestProxyHandler) GetTransaction(ctx context.Context, id flow.Identifier) (*flow.TransactionBody, error) {
   127  	upstream, closer, err := r.FaultTolerantClient()
   128  	if err != nil {
   129  		return nil, err
   130  	}
   131  	defer closer.Close()
   132  
   133  	getTransactionRequest := &accessproto.GetTransactionRequest{
   134  		Id: id[:],
   135  	}
   136  	transactionResponse, err := upstream.GetTransaction(ctx, getTransactionRequest)
   137  	r.log("upstream", "GetTransaction", err)
   138  
   139  	if err != nil {
   140  		return nil, err
   141  	}
   142  
   143  	transactionBody, err := convert.MessageToTransaction(transactionResponse.Transaction, r.Chain)
   144  	if err != nil {
   145  		return nil, err
   146  	}
   147  
   148  	return &transactionBody, nil
   149  }
   150  
   151  // GetTransactionResult returns transaction result by the transaction ID.
   152  func (r *RestProxyHandler) GetTransactionResult(
   153  	ctx context.Context,
   154  	id flow.Identifier,
   155  	blockID flow.Identifier,
   156  	collectionID flow.Identifier,
   157  	requiredEventEncodingVersion entities.EventEncodingVersion,
   158  ) (*access.TransactionResult, error) {
   159  	upstream, closer, err := r.FaultTolerantClient()
   160  	if err != nil {
   161  
   162  		return nil, err
   163  	}
   164  	defer closer.Close()
   165  
   166  	getTransactionResultRequest := &accessproto.GetTransactionRequest{
   167  		Id:                   id[:],
   168  		BlockId:              blockID[:],
   169  		CollectionId:         collectionID[:],
   170  		EventEncodingVersion: requiredEventEncodingVersion,
   171  	}
   172  
   173  	transactionResultResponse, err := upstream.GetTransactionResult(ctx, getTransactionResultRequest)
   174  	r.log("upstream", "GetTransactionResult", err)
   175  
   176  	if err != nil {
   177  		return nil, err
   178  	}
   179  
   180  	return access.MessageToTransactionResult(transactionResultResponse), nil
   181  }
   182  
   183  // GetAccountAtBlockHeight returns account by account address and block height.
   184  func (r *RestProxyHandler) GetAccountAtBlockHeight(ctx context.Context, address flow.Address, height uint64) (*flow.Account, error) {
   185  	upstream, closer, err := r.FaultTolerantClient()
   186  	if err != nil {
   187  		return nil, err
   188  	}
   189  	defer closer.Close()
   190  
   191  	getAccountAtBlockHeightRequest := &accessproto.GetAccountAtBlockHeightRequest{
   192  		Address:     address.Bytes(),
   193  		BlockHeight: height,
   194  	}
   195  
   196  	accountResponse, err := upstream.GetAccountAtBlockHeight(ctx, getAccountAtBlockHeightRequest)
   197  	r.log("upstream", "GetAccountAtBlockHeight", err)
   198  
   199  	if err != nil {
   200  		return nil, err
   201  	}
   202  
   203  	return convert.MessageToAccount(accountResponse.Account)
   204  }
   205  
   206  // ExecuteScriptAtLatestBlock executes script at latest block.
   207  func (r *RestProxyHandler) ExecuteScriptAtLatestBlock(ctx context.Context, script []byte, arguments [][]byte) ([]byte, error) {
   208  	upstream, closer, err := r.FaultTolerantClient()
   209  	if err != nil {
   210  		return nil, err
   211  	}
   212  	defer closer.Close()
   213  
   214  	executeScriptAtLatestBlockRequest := &accessproto.ExecuteScriptAtLatestBlockRequest{
   215  		Script:    script,
   216  		Arguments: arguments,
   217  	}
   218  	executeScriptAtLatestBlockResponse, err := upstream.ExecuteScriptAtLatestBlock(ctx, executeScriptAtLatestBlockRequest)
   219  	r.log("upstream", "ExecuteScriptAtLatestBlock", err)
   220  
   221  	if err != nil {
   222  		return nil, err
   223  	}
   224  
   225  	return executeScriptAtLatestBlockResponse.Value, nil
   226  }
   227  
   228  // ExecuteScriptAtBlockHeight executes script at the given block height .
   229  func (r *RestProxyHandler) ExecuteScriptAtBlockHeight(ctx context.Context, blockHeight uint64, script []byte, arguments [][]byte) ([]byte, error) {
   230  	upstream, closer, err := r.FaultTolerantClient()
   231  	if err != nil {
   232  		return nil, err
   233  	}
   234  	defer closer.Close()
   235  
   236  	executeScriptAtBlockHeightRequest := &accessproto.ExecuteScriptAtBlockHeightRequest{
   237  		BlockHeight: blockHeight,
   238  		Script:      script,
   239  		Arguments:   arguments,
   240  	}
   241  	executeScriptAtBlockHeightResponse, err := upstream.ExecuteScriptAtBlockHeight(ctx, executeScriptAtBlockHeightRequest)
   242  	r.log("upstream", "ExecuteScriptAtBlockHeight", err)
   243  
   244  	if err != nil {
   245  		return nil, err
   246  	}
   247  
   248  	return executeScriptAtBlockHeightResponse.Value, nil
   249  }
   250  
   251  // ExecuteScriptAtBlockID executes script at the given block id .
   252  func (r *RestProxyHandler) ExecuteScriptAtBlockID(ctx context.Context, blockID flow.Identifier, script []byte, arguments [][]byte) ([]byte, error) {
   253  	upstream, closer, err := r.FaultTolerantClient()
   254  	if err != nil {
   255  		return nil, err
   256  	}
   257  	defer closer.Close()
   258  
   259  	executeScriptAtBlockIDRequest := &accessproto.ExecuteScriptAtBlockIDRequest{
   260  		BlockId:   blockID[:],
   261  		Script:    script,
   262  		Arguments: arguments,
   263  	}
   264  	executeScriptAtBlockIDResponse, err := upstream.ExecuteScriptAtBlockID(ctx, executeScriptAtBlockIDRequest)
   265  	r.log("upstream", "ExecuteScriptAtBlockID", err)
   266  
   267  	if err != nil {
   268  		return nil, err
   269  	}
   270  
   271  	return executeScriptAtBlockIDResponse.Value, nil
   272  }
   273  
   274  // GetEventsForHeightRange returns events by their name in the specified blocks heights.
   275  func (r *RestProxyHandler) GetEventsForHeightRange(
   276  	ctx context.Context,
   277  	eventType string,
   278  	startHeight, endHeight uint64,
   279  	requiredEventEncodingVersion entities.EventEncodingVersion,
   280  ) ([]flow.BlockEvents, error) {
   281  	upstream, closer, err := r.FaultTolerantClient()
   282  	if err != nil {
   283  		return nil, err
   284  	}
   285  	defer closer.Close()
   286  
   287  	getEventsForHeightRangeRequest := &accessproto.GetEventsForHeightRangeRequest{
   288  		Type:                 eventType,
   289  		StartHeight:          startHeight,
   290  		EndHeight:            endHeight,
   291  		EventEncodingVersion: requiredEventEncodingVersion,
   292  	}
   293  	eventsResponse, err := upstream.GetEventsForHeightRange(ctx, getEventsForHeightRangeRequest)
   294  	r.log("upstream", "GetEventsForHeightRange", err)
   295  
   296  	if err != nil {
   297  		return nil, err
   298  	}
   299  
   300  	return convert.MessagesToBlockEvents(eventsResponse.Results), nil
   301  }
   302  
   303  // GetEventsForBlockIDs returns events by their name in the specified block IDs.
   304  func (r *RestProxyHandler) GetEventsForBlockIDs(
   305  	ctx context.Context,
   306  	eventType string,
   307  	blockIDs []flow.Identifier,
   308  	requiredEventEncodingVersion entities.EventEncodingVersion,
   309  ) ([]flow.BlockEvents, error) {
   310  	upstream, closer, err := r.FaultTolerantClient()
   311  	if err != nil {
   312  		return nil, err
   313  	}
   314  	defer closer.Close()
   315  
   316  	blockIds := convert.IdentifiersToMessages(blockIDs)
   317  
   318  	getEventsForBlockIDsRequest := &accessproto.GetEventsForBlockIDsRequest{
   319  		Type:                 eventType,
   320  		BlockIds:             blockIds,
   321  		EventEncodingVersion: requiredEventEncodingVersion,
   322  	}
   323  	eventsResponse, err := upstream.GetEventsForBlockIDs(ctx, getEventsForBlockIDsRequest)
   324  	r.log("upstream", "GetEventsForBlockIDs", err)
   325  
   326  	if err != nil {
   327  		return nil, err
   328  	}
   329  
   330  	return convert.MessagesToBlockEvents(eventsResponse.Results), nil
   331  }
   332  
   333  // GetExecutionResultForBlockID gets execution result by provided block ID.
   334  func (r *RestProxyHandler) GetExecutionResultForBlockID(ctx context.Context, blockID flow.Identifier) (*flow.ExecutionResult, error) {
   335  	upstream, closer, err := r.FaultTolerantClient()
   336  	if err != nil {
   337  		return nil, err
   338  	}
   339  	defer closer.Close()
   340  
   341  	getExecutionResultForBlockID := &accessproto.GetExecutionResultForBlockIDRequest{
   342  		BlockId: blockID[:],
   343  	}
   344  	executionResultForBlockIDResponse, err := upstream.GetExecutionResultForBlockID(ctx, getExecutionResultForBlockID)
   345  	r.log("upstream", "GetExecutionResultForBlockID", err)
   346  
   347  	if err != nil {
   348  		return nil, err
   349  	}
   350  
   351  	return convert.MessageToExecutionResult(executionResultForBlockIDResponse.ExecutionResult)
   352  }
   353  
   354  // GetExecutionResultByID gets execution result by its ID.
   355  func (r *RestProxyHandler) GetExecutionResultByID(ctx context.Context, id flow.Identifier) (*flow.ExecutionResult, error) {
   356  	upstream, closer, err := r.FaultTolerantClient()
   357  	if err != nil {
   358  		return nil, err
   359  	}
   360  	defer closer.Close()
   361  
   362  	executionResultByIDRequest := &accessproto.GetExecutionResultByIDRequest{
   363  		Id: id[:],
   364  	}
   365  
   366  	executionResultByIDResponse, err := upstream.GetExecutionResultByID(ctx, executionResultByIDRequest)
   367  	r.log("upstream", "GetExecutionResultByID", err)
   368  
   369  	if err != nil {
   370  		return nil, err
   371  	}
   372  
   373  	return convert.MessageToExecutionResult(executionResultByIDResponse.ExecutionResult)
   374  }