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 }