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 ðpb.BlockHeaderResponse{ 80 Data: ðpb.BlockHeaderContainer{ 81 Root: root[:], 82 Canonical: canonical, 83 Header: ðpb.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] = ðpb.BlockHeaderContainer{ 141 Root: root[:], 142 Canonical: canonical, 143 Header: ðpb.BeaconBlockHeaderContainer{ 144 Message: blkHdr.Message, 145 Signature: blkHdr.Signature, 146 }, 147 } 148 } 149 150 return ðpb.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(ðpb.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 ðpb.BlockResponse{ 214 Data: ðpb.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 ðpb.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 ðpb.BlockRootResponse{ 319 Data: ðpb.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 ðpb.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 }