github.com/onflow/flow-go@v0.35.7-crescendo-preview.23-atree-inlining/engine/access/rpc/backend/backend_block_details.go (about) 1 package backend 2 3 import ( 4 "context" 5 6 "google.golang.org/grpc/codes" 7 "google.golang.org/grpc/status" 8 9 "github.com/onflow/flow-go/engine/common/rpc" 10 "github.com/onflow/flow-go/model/flow" 11 "github.com/onflow/flow-go/module/irrecoverable" 12 "github.com/onflow/flow-go/state/protocol" 13 "github.com/onflow/flow-go/storage" 14 ) 15 16 type backendBlockDetails struct { 17 blocks storage.Blocks 18 state protocol.State 19 } 20 21 func (b *backendBlockDetails) GetLatestBlock(ctx context.Context, isSealed bool) (*flow.Block, flow.BlockStatus, error) { 22 var header *flow.Header 23 var err error 24 25 if isSealed { 26 // get the latest seal header from storage 27 header, err = b.state.Sealed().Head() 28 if err != nil { 29 err = irrecoverable.NewExceptionf("failed to lookup sealed header: %w", err) 30 31 } 32 } else { 33 // get the finalized header from state 34 header, err = b.state.Final().Head() 35 if err != nil { 36 err = irrecoverable.NewExceptionf("failed to lookup final header: %w", err) 37 } 38 } 39 40 if err != nil { 41 // node should always have the latest block 42 43 // In the RPC engine, if we encounter an error from the protocol state indicating state corruption, 44 // we should halt processing requests, but do throw an exception which might cause a crash: 45 // - It is unsafe to process requests if we have an internally bad state. 46 // - We would like to avoid throwing an exception as a result of an Access API request by policy 47 // because this can cause DOS potential 48 // - Since the protocol state is widely shared, we assume that in practice another component will 49 // observe the protocol state error and throw an exception. 50 irrecoverable.Throw(ctx, err) 51 return nil, flow.BlockStatusUnknown, err 52 } 53 54 // since we are querying a finalized or sealed block, we can use the height index and save an ID computation 55 block, err := b.blocks.ByHeight(header.Height) 56 if err != nil { 57 return nil, flow.BlockStatusUnknown, status.Errorf(codes.Internal, "could not get latest block: %v", err) 58 } 59 60 stat, err := b.getBlockStatus(ctx, block) 61 if err != nil { 62 return nil, stat, err 63 } 64 return block, stat, nil 65 } 66 67 func (b *backendBlockDetails) GetBlockByID(ctx context.Context, id flow.Identifier) (*flow.Block, flow.BlockStatus, error) { 68 block, err := b.blocks.ByID(id) 69 if err != nil { 70 return nil, flow.BlockStatusUnknown, rpc.ConvertStorageError(err) 71 } 72 73 stat, err := b.getBlockStatus(ctx, block) 74 if err != nil { 75 return nil, stat, err 76 } 77 return block, stat, nil 78 } 79 80 func (b *backendBlockDetails) GetBlockByHeight(ctx context.Context, height uint64) (*flow.Block, flow.BlockStatus, error) { 81 block, err := b.blocks.ByHeight(height) 82 if err != nil { 83 return nil, flow.BlockStatusUnknown, rpc.ConvertStorageError(err) 84 } 85 86 stat, err := b.getBlockStatus(ctx, block) 87 if err != nil { 88 return nil, stat, err 89 } 90 return block, stat, nil 91 } 92 93 // No errors are expected during normal operations. 94 func (b *backendBlockDetails) getBlockStatus(ctx context.Context, block *flow.Block) (flow.BlockStatus, error) { 95 sealed, err := b.state.Sealed().Head() 96 if err != nil { 97 // In the RPC engine, if we encounter an error from the protocol state indicating state corruption, 98 // we should halt processing requests, but do throw an exception which might cause a crash: 99 // - It is unsafe to process requests if we have an internally bad state. 100 // - We would like to avoid throwing an exception as a result of an Access API request by policy 101 // because this can cause DOS potential 102 // - Since the protocol state is widely shared, we assume that in practice another component will 103 // observe the protocol state error and throw an exception. 104 err := irrecoverable.NewExceptionf("failed to lookup sealed header: %w", err) 105 irrecoverable.Throw(ctx, err) 106 return flow.BlockStatusUnknown, err 107 } 108 109 if block.Header.Height > sealed.Height { 110 return flow.BlockStatusFinalized, nil 111 } 112 return flow.BlockStatusSealed, nil 113 }