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