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  }