github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/rpc/eth/v1/beacon/blocks.go (about)

     1  package beacon
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"strconv"
     7  
     8  	"github.com/pkg/errors"
     9  	types "github.com/prysmaticlabs/eth2-types"
    10  	"github.com/prysmaticlabs/prysm/beacon-chain/core/feed"
    11  	blockfeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/block"
    12  	"github.com/prysmaticlabs/prysm/beacon-chain/db/filters"
    13  	ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1"
    14  	"github.com/prysmaticlabs/prysm/proto/eth/v1alpha1/wrapper"
    15  	"github.com/prysmaticlabs/prysm/proto/interfaces"
    16  	"github.com/prysmaticlabs/prysm/proto/migration"
    17  	"github.com/prysmaticlabs/prysm/shared/bytesutil"
    18  	"go.opencensus.io/trace"
    19  	"google.golang.org/grpc/codes"
    20  	"google.golang.org/grpc/status"
    21  	"google.golang.org/protobuf/types/known/emptypb"
    22  )
    23  
    24  // blockIdParseError represents an error scenario where a block ID could not be parsed.
    25  type blockIdParseError struct {
    26  	message string
    27  }
    28  
    29  // newBlockIdParseError creates a new error instance.
    30  func newBlockIdParseError(reason error) blockIdParseError {
    31  	return blockIdParseError{
    32  		message: errors.Wrapf(reason, "could not parse block ID").Error(),
    33  	}
    34  }
    35  
    36  // Error returns the underlying error message.
    37  func (e *blockIdParseError) Error() string {
    38  	return e.message
    39  }
    40  
    41  // GetBlockHeader retrieves block header for given block id.
    42  func (bs *Server) GetBlockHeader(ctx context.Context, req *ethpb.BlockRequest) (*ethpb.BlockHeaderResponse, error) {
    43  	ctx, span := trace.StartSpan(ctx, "beaconv1.GetBlockHeader")
    44  	defer span.End()
    45  
    46  	rBlk, err := bs.blockFromBlockID(ctx, req.BlockId)
    47  	if invalidBlockIdErr, ok := err.(*blockIdParseError); ok {
    48  		return nil, status.Errorf(codes.InvalidArgument, "Invalid block ID: %v", invalidBlockIdErr)
    49  	}
    50  	if err != nil {
    51  		return nil, status.Errorf(codes.Internal, "Could not get block from block ID: %v", err)
    52  	}
    53  	if rBlk == nil || rBlk.IsNil() {
    54  		return nil, status.Errorf(codes.NotFound, "Could not find requested block header")
    55  	}
    56  	blk, err := rBlk.PbPhase0Block()
    57  	if err != nil {
    58  		return nil, status.Errorf(codes.Internal, "Could not get raw block: %v", err)
    59  	}
    60  
    61  	v1BlockHdr, err := migration.V1Alpha1BlockToV1BlockHeader(blk)
    62  	if err != nil {
    63  		return nil, status.Errorf(codes.Internal, "Could not get block header from block: %v", err)
    64  	}
    65  
    66  	blkRoot, err := blk.Block.HashTreeRoot()
    67  	if err != nil {
    68  		return nil, status.Errorf(codes.Internal, "Could not hash block: %v", err)
    69  	}
    70  	canonical, err := bs.ChainInfoFetcher.IsCanonical(ctx, blkRoot)
    71  	if err != nil {
    72  		return nil, status.Errorf(codes.Internal, "Could not determine if block root is canonical: %v", err)
    73  	}
    74  	root, err := v1BlockHdr.HashTreeRoot()
    75  	if err != nil {
    76  		return nil, status.Errorf(codes.Internal, "Could not hash block header: %v", err)
    77  	}
    78  
    79  	return &ethpb.BlockHeaderResponse{
    80  		Data: &ethpb.BlockHeaderContainer{
    81  			Root:      root[:],
    82  			Canonical: canonical,
    83  			Header: &ethpb.BeaconBlockHeaderContainer{
    84  				Message:   v1BlockHdr.Message,
    85  				Signature: v1BlockHdr.Signature,
    86  			},
    87  		},
    88  	}, nil
    89  }
    90  
    91  // ListBlockHeaders retrieves block headers matching given query. By default it will fetch current head slot blocks.
    92  func (bs *Server) ListBlockHeaders(ctx context.Context, req *ethpb.BlockHeadersRequest) (*ethpb.BlockHeadersResponse, error) {
    93  	ctx, span := trace.StartSpan(ctx, "beaconv1.ListBlockHeaders")
    94  	defer span.End()
    95  
    96  	var err error
    97  	var blks []interfaces.SignedBeaconBlock
    98  	var blkRoots [][32]byte
    99  	if len(req.ParentRoot) == 32 {
   100  		blks, blkRoots, err = bs.BeaconDB.Blocks(ctx, filters.NewFilter().SetParentRoot(req.ParentRoot))
   101  		if err != nil {
   102  			return nil, status.Errorf(codes.Internal, "Could not retrieve blocks: %v", err)
   103  		}
   104  	} else {
   105  		slot := bs.ChainInfoFetcher.HeadSlot()
   106  		if req.Slot != nil {
   107  			slot = *req.Slot
   108  		}
   109  		_, blks, err = bs.BeaconDB.BlocksBySlot(ctx, slot)
   110  		if err != nil {
   111  			return nil, status.Errorf(codes.Internal, "Could not retrieve blocks for slot %d: %v", req.Slot, err)
   112  		}
   113  		_, blkRoots, err = bs.BeaconDB.BlockRootsBySlot(ctx, slot)
   114  		if err != nil {
   115  			return nil, status.Errorf(codes.Internal, "Could not retrieve block roots for slot %d: %v", req.Slot, err)
   116  		}
   117  	}
   118  	if len(blks) == 0 {
   119  		return nil, status.Error(codes.NotFound, "Could not find requested blocks")
   120  	}
   121  
   122  	blkHdrs := make([]*ethpb.BlockHeaderContainer, len(blks))
   123  	for i, bl := range blks {
   124  		blk, err := bl.PbPhase0Block()
   125  		if err != nil {
   126  			return nil, status.Errorf(codes.Internal, "Could not get raw block: %v", err)
   127  		}
   128  		blkHdr, err := migration.V1Alpha1BlockToV1BlockHeader(blk)
   129  		if err != nil {
   130  			return nil, status.Errorf(codes.Internal, "Could not get block header from block: %v", err)
   131  		}
   132  		canonical, err := bs.ChainInfoFetcher.IsCanonical(ctx, blkRoots[i])
   133  		if err != nil {
   134  			return nil, status.Errorf(codes.Internal, "Could not determine if block root is canonical: %v", err)
   135  		}
   136  		root, err := blkHdr.Message.HashTreeRoot()
   137  		if err != nil {
   138  			return nil, status.Errorf(codes.Internal, "Could not hash block header: %v", err)
   139  		}
   140  		blkHdrs[i] = &ethpb.BlockHeaderContainer{
   141  			Root:      root[:],
   142  			Canonical: canonical,
   143  			Header: &ethpb.BeaconBlockHeaderContainer{
   144  				Message:   blkHdr.Message,
   145  				Signature: blkHdr.Signature,
   146  			},
   147  		}
   148  	}
   149  
   150  	return &ethpb.BlockHeadersResponse{Data: blkHdrs}, nil
   151  }
   152  
   153  // SubmitBlock instructs the beacon node to broadcast a newly signed beacon block to the beacon network, to be
   154  // included in the beacon chain. The beacon node is not required to validate the signed BeaconBlock, and a successful
   155  // response (20X) only indicates that the broadcast has been successful. The beacon node is expected to integrate the
   156  // new block into its state, and therefore validate the block internally, however blocks which fail the validation are
   157  // still broadcast but a different status code is returned (202).
   158  func (bs *Server) SubmitBlock(ctx context.Context, req *ethpb.BeaconBlockContainer) (*emptypb.Empty, error) {
   159  	ctx, span := trace.StartSpan(ctx, "beaconv1.SubmitBlock")
   160  	defer span.End()
   161  
   162  	blk := req.Message
   163  	rBlock, err := migration.V1ToV1Alpha1Block(&ethpb.SignedBeaconBlock{Block: blk, Signature: req.Signature})
   164  	if err != nil {
   165  		return nil, status.Errorf(codes.InvalidArgument, "Could not convert block to v1 block")
   166  	}
   167  	v1alpha1Block := wrapper.WrappedPhase0SignedBeaconBlock(rBlock)
   168  
   169  	root, err := blk.HashTreeRoot()
   170  	if err != nil {
   171  		return nil, status.Errorf(codes.InvalidArgument, "Could not tree hash block: %v", err)
   172  	}
   173  
   174  	// Do not block proposal critical path with debug logging or block feed updates.
   175  	defer func() {
   176  		log.WithField("blockRoot", fmt.Sprintf("%#x", bytesutil.Trunc(root[:]))).Debugf(
   177  			"Block proposal received via RPC")
   178  		bs.BlockNotifier.BlockFeed().Send(&feed.Event{
   179  			Type: blockfeed.ReceivedBlock,
   180  			Data: &blockfeed.ReceivedBlockData{SignedBlock: v1alpha1Block},
   181  		})
   182  	}()
   183  
   184  	// Broadcast the new block to the network.
   185  	if err := bs.Broadcaster.Broadcast(ctx, v1alpha1Block.Proto()); err != nil {
   186  		return nil, status.Errorf(codes.Internal, "Could not broadcast block: %v", err)
   187  	}
   188  
   189  	if err := bs.BlockReceiver.ReceiveBlock(ctx, v1alpha1Block, root); err != nil {
   190  		return nil, status.Errorf(codes.Internal, "Could not process beacon block: %v", err)
   191  	}
   192  
   193  	return &emptypb.Empty{}, nil
   194  }
   195  
   196  // GetBlock retrieves block details for given block ID.
   197  func (bs *Server) GetBlock(ctx context.Context, req *ethpb.BlockRequest) (*ethpb.BlockResponse, error) {
   198  	ctx, span := trace.StartSpan(ctx, "beaconv1.GetBlock")
   199  	defer span.End()
   200  
   201  	block, err := bs.blockFromBlockID(ctx, req.BlockId)
   202  	if invalidBlockIdErr, ok := err.(*blockIdParseError); ok {
   203  		return nil, status.Errorf(codes.InvalidArgument, "Invalid block ID: %v", invalidBlockIdErr)
   204  	}
   205  	if err != nil {
   206  		return nil, status.Errorf(codes.Internal, "Could not get block from block ID: %v", err)
   207  	}
   208  	signedBeaconBlock, err := migration.SignedBeaconBlock(block)
   209  	if err != nil {
   210  		return nil, status.Errorf(codes.Internal, "Could not get signed beacon block: %v", err)
   211  	}
   212  
   213  	return &ethpb.BlockResponse{
   214  		Data: &ethpb.BeaconBlockContainer{
   215  			Message:   signedBeaconBlock.Block,
   216  			Signature: signedBeaconBlock.Signature,
   217  		},
   218  	}, nil
   219  }
   220  
   221  // GetBlockSSZ returns the SSZ-serialized version of the becaon block for given block ID.
   222  func (bs *Server) GetBlockSSZ(ctx context.Context, req *ethpb.BlockRequest) (*ethpb.BlockSSZResponse, error) {
   223  	ctx, span := trace.StartSpan(ctx, "beaconv1.GetBlockSSZ")
   224  	defer span.End()
   225  
   226  	block, err := bs.blockFromBlockID(ctx, req.BlockId)
   227  	if invalidBlockIdErr, ok := err.(*blockIdParseError); ok {
   228  		return nil, status.Errorf(codes.InvalidArgument, "Invalid block ID: %v", invalidBlockIdErr)
   229  	}
   230  	if err != nil {
   231  		return nil, status.Errorf(codes.Internal, "Could not get block from block ID: %v", err)
   232  	}
   233  	signedBeaconBlock, err := migration.SignedBeaconBlock(block)
   234  	if err != nil {
   235  		return nil, status.Errorf(codes.Internal, "Could not get signed beacon block: %v", err)
   236  	}
   237  	sszBlock, err := signedBeaconBlock.MarshalSSZ()
   238  	if err != nil {
   239  		return nil, status.Errorf(codes.Internal, "Could not marshal block into SSZ: %v", err)
   240  	}
   241  
   242  	return &ethpb.BlockSSZResponse{Data: sszBlock}, nil
   243  }
   244  
   245  // GetBlockRoot retrieves hashTreeRoot of BeaconBlock/BeaconBlockHeader.
   246  func (bs *Server) GetBlockRoot(ctx context.Context, req *ethpb.BlockRequest) (*ethpb.BlockRootResponse, error) {
   247  	ctx, span := trace.StartSpan(ctx, "beaconv1.GetBlockRoot")
   248  	defer span.End()
   249  
   250  	var root []byte
   251  	var err error
   252  	switch string(req.BlockId) {
   253  	case "head":
   254  		root, err = bs.ChainInfoFetcher.HeadRoot(ctx)
   255  		if err != nil {
   256  			return nil, status.Errorf(codes.Internal, "Could not retrieve head block: %v", err)
   257  		}
   258  		if root == nil {
   259  			return nil, status.Errorf(codes.NotFound, "No head root was found")
   260  		}
   261  	case "finalized":
   262  		finalized := bs.ChainInfoFetcher.FinalizedCheckpt()
   263  		root = finalized.Root
   264  	case "genesis":
   265  		blk, err := bs.BeaconDB.GenesisBlock(ctx)
   266  		if err != nil {
   267  			return nil, status.Errorf(codes.Internal, "Could not retrieve blocks for genesis slot: %v", err)
   268  		}
   269  		if blk == nil || blk.IsNil() {
   270  			return nil, status.Error(codes.NotFound, "Could not find genesis block")
   271  		}
   272  		blkRoot, err := blk.Block().HashTreeRoot()
   273  		if err != nil {
   274  			return nil, status.Error(codes.Internal, "Could not hash genesis block")
   275  		}
   276  		root = blkRoot[:]
   277  	default:
   278  		if len(req.BlockId) == 32 {
   279  			block, err := bs.BeaconDB.Block(ctx, bytesutil.ToBytes32(req.BlockId))
   280  			if err != nil {
   281  				return nil, status.Errorf(codes.Internal, "Could not retrieve block for block root %#x: %v", req.BlockId, err)
   282  			}
   283  			if block == nil || block.IsNil() {
   284  				return nil, status.Error(codes.NotFound, "Could not find any blocks with given root")
   285  			}
   286  
   287  			root = req.BlockId
   288  		} else {
   289  			slot, err := strconv.ParseUint(string(req.BlockId), 10, 64)
   290  			if err != nil {
   291  				return nil, status.Errorf(codes.InvalidArgument, "Could not parse block ID: %v", err)
   292  			}
   293  			hasRoots, roots, err := bs.BeaconDB.BlockRootsBySlot(ctx, types.Slot(slot))
   294  			if err != nil {
   295  				return nil, status.Errorf(codes.Internal, "Could not retrieve blocks for slot %d: %v", slot, err)
   296  			}
   297  
   298  			if !hasRoots {
   299  				return nil, status.Error(codes.NotFound, "Could not find any blocks with given slot")
   300  			}
   301  			root = roots[0][:]
   302  			if len(roots) == 1 {
   303  				break
   304  			}
   305  			for _, blockRoot := range roots {
   306  				canonical, err := bs.ChainInfoFetcher.IsCanonical(ctx, blockRoot)
   307  				if err != nil {
   308  					return nil, status.Errorf(codes.Internal, "Could not determine if block root is canonical: %v", err)
   309  				}
   310  				if canonical {
   311  					root = blockRoot[:]
   312  					break
   313  				}
   314  			}
   315  		}
   316  	}
   317  
   318  	return &ethpb.BlockRootResponse{
   319  		Data: &ethpb.BlockRootContainer{
   320  			Root: root,
   321  		},
   322  	}, nil
   323  }
   324  
   325  // ListBlockAttestations retrieves attestation included in requested block.
   326  func (bs *Server) ListBlockAttestations(ctx context.Context, req *ethpb.BlockRequest) (*ethpb.BlockAttestationsResponse, error) {
   327  	ctx, span := trace.StartSpan(ctx, "beaconv1.ListBlockAttestations")
   328  	defer span.End()
   329  
   330  	rBlk, err := bs.blockFromBlockID(ctx, req.BlockId)
   331  	if invalidBlockIdErr, ok := err.(*blockIdParseError); ok {
   332  		return nil, status.Errorf(codes.InvalidArgument, "Invalid block ID: %v", invalidBlockIdErr)
   333  	}
   334  	if err != nil {
   335  		return nil, status.Errorf(codes.Internal, "Could not get block from block ID: %v", err)
   336  	}
   337  	if rBlk == nil || rBlk.IsNil() {
   338  		return nil, status.Errorf(codes.NotFound, "Could not find requested block")
   339  	}
   340  
   341  	blk, err := rBlk.PbPhase0Block()
   342  	if err != nil {
   343  		return nil, status.Errorf(codes.Internal, "Could not get raw block: %v", err)
   344  	}
   345  
   346  	v1Block, err := migration.V1Alpha1ToV1Block(blk)
   347  	if err != nil {
   348  		return nil, status.Errorf(codes.Internal, "Could not convert block to v1 block")
   349  	}
   350  	return &ethpb.BlockAttestationsResponse{
   351  		Data: v1Block.Block.Body.Attestations,
   352  	}, nil
   353  }
   354  
   355  func (bs *Server) blockFromBlockID(ctx context.Context, blockId []byte) (interfaces.SignedBeaconBlock, error) {
   356  	var err error
   357  	var blk interfaces.SignedBeaconBlock
   358  	switch string(blockId) {
   359  	case "head":
   360  		blk, err = bs.ChainInfoFetcher.HeadBlock(ctx)
   361  		if err != nil {
   362  			return nil, errors.Wrap(err, "could not retrieve head block")
   363  		}
   364  	case "finalized":
   365  		finalized := bs.ChainInfoFetcher.FinalizedCheckpt()
   366  		finalizedRoot := bytesutil.ToBytes32(finalized.Root)
   367  		blk, err = bs.BeaconDB.Block(ctx, finalizedRoot)
   368  		if err != nil {
   369  			return nil, errors.New("could not get finalized block from db")
   370  		}
   371  	case "genesis":
   372  		blk, err = bs.BeaconDB.GenesisBlock(ctx)
   373  		if err != nil {
   374  			return nil, errors.Wrap(err, "could not retrieve blocks for genesis slot")
   375  		}
   376  	default:
   377  		if len(blockId) == 32 {
   378  			blk, err = bs.BeaconDB.Block(ctx, bytesutil.ToBytes32(blockId))
   379  			if err != nil {
   380  				return nil, errors.Wrap(err, "could not retrieve block")
   381  			}
   382  		} else {
   383  			slot, err := strconv.ParseUint(string(blockId), 10, 64)
   384  			if err != nil {
   385  				e := newBlockIdParseError(err)
   386  				return nil, &e
   387  			}
   388  			_, blks, err := bs.BeaconDB.BlocksBySlot(ctx, types.Slot(slot))
   389  			if err != nil {
   390  				return nil, errors.Wrapf(err, "could not retrieve blocks for slot %d", slot)
   391  			}
   392  			_, roots, err := bs.BeaconDB.BlockRootsBySlot(ctx, types.Slot(slot))
   393  			if err != nil {
   394  				return nil, errors.Wrapf(err, "could not retrieve block roots for slot %d", slot)
   395  			}
   396  
   397  			numBlks := len(blks)
   398  			if numBlks == 0 {
   399  				return nil, nil
   400  			}
   401  			blk = blks[0]
   402  			if numBlks == 1 {
   403  				break
   404  			}
   405  			for i, block := range blks {
   406  				canonical, err := bs.ChainInfoFetcher.IsCanonical(ctx, roots[i])
   407  				if err != nil {
   408  					return nil, status.Errorf(codes.Internal, "Could not determine if block root is canonical: %v", err)
   409  				}
   410  				if canonical {
   411  					blk = block
   412  					break
   413  				}
   414  			}
   415  		}
   416  	}
   417  	return blk, nil
   418  }