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  }