github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/rpc/prysm/v1alpha1/beacon/blocks.go (about) 1 package beacon 2 3 import ( 4 "context" 5 "strconv" 6 7 "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks" 8 "github.com/prysmaticlabs/prysm/beacon-chain/core/feed" 9 blockfeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/block" 10 statefeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/state" 11 "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" 12 "github.com/prysmaticlabs/prysm/beacon-chain/db/filters" 13 ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1" 14 "github.com/prysmaticlabs/prysm/shared/bytesutil" 15 "github.com/prysmaticlabs/prysm/shared/cmd" 16 "github.com/prysmaticlabs/prysm/shared/event" 17 "github.com/prysmaticlabs/prysm/shared/pagination" 18 "github.com/prysmaticlabs/prysm/shared/params" 19 "google.golang.org/grpc/codes" 20 "google.golang.org/grpc/status" 21 "google.golang.org/protobuf/types/known/emptypb" 22 ) 23 24 // ListBlocks retrieves blocks by root, slot, or epoch. 25 // 26 // The server may return multiple blocks in the case that a slot or epoch is 27 // provided as the filter criteria. The server may return an empty list when 28 // no blocks in their database match the filter criteria. This RPC should 29 // not return NOT_FOUND. Only one filter criteria should be used. 30 func (bs *Server) ListBlocks( 31 ctx context.Context, req *ethpb.ListBlocksRequest, 32 ) (*ethpb.ListBlocksResponse, error) { 33 if int(req.PageSize) > cmd.Get().MaxRPCPageSize { 34 return nil, status.Errorf(codes.InvalidArgument, "Requested page size %d can not be greater than max size %d", 35 req.PageSize, cmd.Get().MaxRPCPageSize) 36 } 37 38 switch q := req.QueryFilter.(type) { 39 case *ethpb.ListBlocksRequest_Epoch: 40 blks, _, err := bs.BeaconDB.Blocks(ctx, filters.NewFilter().SetStartEpoch(q.Epoch).SetEndEpoch(q.Epoch)) 41 if err != nil { 42 return nil, status.Errorf(codes.Internal, "Could not get blocks: %v", err) 43 } 44 45 numBlks := len(blks) 46 if numBlks == 0 { 47 return ðpb.ListBlocksResponse{ 48 BlockContainers: make([]*ethpb.BeaconBlockContainer, 0), 49 TotalSize: 0, 50 NextPageToken: strconv.Itoa(0), 51 }, nil 52 } 53 54 start, end, nextPageToken, err := pagination.StartAndEndPage(req.PageToken, int(req.PageSize), numBlks) 55 if err != nil { 56 return nil, status.Errorf(codes.Internal, "Could not paginate blocks: %v", err) 57 } 58 59 returnedBlks := blks[start:end] 60 containers := make([]*ethpb.BeaconBlockContainer, len(returnedBlks)) 61 for i, b := range returnedBlks { 62 root, err := b.Block().HashTreeRoot() 63 if err != nil { 64 return nil, err 65 } 66 canonical, err := bs.CanonicalFetcher.IsCanonical(ctx, root) 67 if err != nil { 68 return nil, status.Errorf(codes.Internal, "Could not determine if block is canonical: %v", err) 69 } 70 phBlk, err := b.PbPhase0Block() 71 if err != nil { 72 return nil, status.Errorf(codes.Internal, "Could not get phase 0 block: %v", err) 73 } 74 containers[i] = ðpb.BeaconBlockContainer{ 75 Block: phBlk, 76 BlockRoot: root[:], 77 Canonical: canonical, 78 } 79 } 80 81 return ðpb.ListBlocksResponse{ 82 BlockContainers: containers, 83 TotalSize: int32(numBlks), 84 NextPageToken: nextPageToken, 85 }, nil 86 case *ethpb.ListBlocksRequest_Root: 87 blk, err := bs.BeaconDB.Block(ctx, bytesutil.ToBytes32(q.Root)) 88 if err != nil { 89 return nil, status.Errorf(codes.Internal, "Could not retrieve block: %v", err) 90 } 91 if blk == nil || blk.IsNil() { 92 return ðpb.ListBlocksResponse{ 93 BlockContainers: make([]*ethpb.BeaconBlockContainer, 0), 94 TotalSize: 0, 95 NextPageToken: strconv.Itoa(0), 96 }, nil 97 } 98 root, err := blk.Block().HashTreeRoot() 99 if err != nil { 100 return nil, err 101 } 102 canonical, err := bs.CanonicalFetcher.IsCanonical(ctx, root) 103 if err != nil { 104 return nil, status.Errorf(codes.Internal, "Could not determine if block is canonical: %v", err) 105 } 106 phBlk, err := blk.PbPhase0Block() 107 if err != nil { 108 return nil, status.Errorf(codes.Internal, "Could not determine if block is phase 0 block: %v", err) 109 } 110 return ðpb.ListBlocksResponse{ 111 BlockContainers: []*ethpb.BeaconBlockContainer{{ 112 Block: phBlk, 113 BlockRoot: root[:], 114 Canonical: canonical}, 115 }, 116 TotalSize: 1, 117 }, nil 118 119 case *ethpb.ListBlocksRequest_Slot: 120 hasBlocks, blks, err := bs.BeaconDB.BlocksBySlot(ctx, q.Slot) 121 if err != nil { 122 return nil, status.Errorf(codes.Internal, "Could not retrieve blocks for slot %d: %v", q.Slot, err) 123 } 124 if !hasBlocks { 125 return ðpb.ListBlocksResponse{ 126 BlockContainers: make([]*ethpb.BeaconBlockContainer, 0), 127 TotalSize: 0, 128 NextPageToken: strconv.Itoa(0), 129 }, nil 130 } 131 132 numBlks := len(blks) 133 134 start, end, nextPageToken, err := pagination.StartAndEndPage(req.PageToken, int(req.PageSize), numBlks) 135 if err != nil { 136 return nil, status.Errorf(codes.Internal, "Could not paginate blocks: %v", err) 137 } 138 139 returnedBlks := blks[start:end] 140 containers := make([]*ethpb.BeaconBlockContainer, len(returnedBlks)) 141 for i, b := range returnedBlks { 142 root, err := b.Block().HashTreeRoot() 143 if err != nil { 144 return nil, err 145 } 146 canonical, err := bs.CanonicalFetcher.IsCanonical(ctx, root) 147 if err != nil { 148 return nil, status.Errorf(codes.Internal, "Could not determine if block is canonical: %v", err) 149 } 150 phBlk, err := b.PbPhase0Block() 151 if err != nil { 152 return nil, status.Errorf(codes.Internal, "Could not determine if block is phase 0 block: %v", err) 153 } 154 containers[i] = ðpb.BeaconBlockContainer{ 155 Block: phBlk, 156 BlockRoot: root[:], 157 Canonical: canonical, 158 } 159 } 160 161 return ðpb.ListBlocksResponse{ 162 BlockContainers: containers, 163 TotalSize: int32(numBlks), 164 NextPageToken: nextPageToken, 165 }, nil 166 case *ethpb.ListBlocksRequest_Genesis: 167 genBlk, err := bs.BeaconDB.GenesisBlock(ctx) 168 if err != nil { 169 return nil, status.Errorf(codes.Internal, "Could not retrieve blocks for genesis slot: %v", err) 170 } 171 if genBlk.IsNil() { 172 return nil, status.Error(codes.Internal, "Could not find genesis block") 173 } 174 root, err := genBlk.Block().HashTreeRoot() 175 if err != nil { 176 return nil, err 177 } 178 phBlk, err := genBlk.PbPhase0Block() 179 if err != nil { 180 return nil, status.Errorf(codes.Internal, "Could not determine if block is phase 0 block: %v", err) 181 } 182 containers := []*ethpb.BeaconBlockContainer{ 183 { 184 Block: phBlk, 185 BlockRoot: root[:], 186 Canonical: true, 187 }, 188 } 189 190 return ðpb.ListBlocksResponse{ 191 BlockContainers: containers, 192 TotalSize: int32(1), 193 NextPageToken: strconv.Itoa(0), 194 }, nil 195 } 196 197 return nil, status.Error(codes.InvalidArgument, "Must specify a filter criteria for fetching blocks") 198 } 199 200 // GetChainHead retrieves information about the head of the beacon chain from 201 // the view of the beacon chain node. 202 // 203 // This includes the head block slot and root as well as information about 204 // the most recent finalized and justified slots. 205 func (bs *Server) GetChainHead(ctx context.Context, _ *emptypb.Empty) (*ethpb.ChainHead, error) { 206 return bs.chainHeadRetrieval(ctx) 207 } 208 209 // StreamBlocks to clients every single time a block is received by the beacon node. 210 func (bs *Server) StreamBlocks(req *ethpb.StreamBlocksRequest, stream ethpb.BeaconChain_StreamBlocksServer) error { 211 blocksChannel := make(chan *feed.Event, 1) 212 var blockSub event.Subscription 213 if req.VerifiedOnly { 214 blockSub = bs.StateNotifier.StateFeed().Subscribe(blocksChannel) 215 } else { 216 blockSub = bs.BlockNotifier.BlockFeed().Subscribe(blocksChannel) 217 } 218 defer blockSub.Unsubscribe() 219 220 for { 221 select { 222 case blockEvent := <-blocksChannel: 223 if req.VerifiedOnly { 224 if blockEvent.Type == statefeed.BlockProcessed { 225 data, ok := blockEvent.Data.(*statefeed.BlockProcessedData) 226 if !ok || data == nil { 227 continue 228 } 229 phBlk, err := data.SignedBlock.PbPhase0Block() 230 if err != nil { 231 log.Error(err) 232 continue 233 } 234 if err := stream.Send(phBlk); err != nil { 235 return status.Errorf(codes.Unavailable, "Could not send over stream: %v", err) 236 } 237 } 238 } else { 239 if blockEvent.Type == blockfeed.ReceivedBlock { 240 data, ok := blockEvent.Data.(*blockfeed.ReceivedBlockData) 241 if !ok { 242 // Got bad data over the stream. 243 continue 244 } 245 if data.SignedBlock == nil { 246 // One nil block shouldn't stop the stream. 247 continue 248 } 249 headState, err := bs.HeadFetcher.HeadState(bs.Ctx) 250 if err != nil { 251 log.WithError(err).WithField("blockSlot", data.SignedBlock.Block().Slot()).Error("Could not get head state") 252 continue 253 } 254 signed := data.SignedBlock 255 if err := blocks.VerifyBlockSignature(headState, signed.Block().ProposerIndex(), signed.Signature(), signed.Block().HashTreeRoot); err != nil { 256 log.WithError(err).WithField("blockSlot", data.SignedBlock.Block().Slot()).Error("Could not verify block signature") 257 continue 258 } 259 phBlk, err := signed.PbPhase0Block() 260 if err != nil { 261 log.Error(err) 262 continue 263 } 264 if err := stream.Send(phBlk); err != nil { 265 return status.Errorf(codes.Unavailable, "Could not send over stream: %v", err) 266 } 267 } 268 } 269 case <-blockSub.Err(): 270 return status.Error(codes.Aborted, "Subscriber closed, exiting goroutine") 271 case <-bs.Ctx.Done(): 272 return status.Error(codes.Canceled, "Context canceled") 273 case <-stream.Context().Done(): 274 return status.Error(codes.Canceled, "Context canceled") 275 } 276 } 277 } 278 279 // StreamChainHead to clients every single time the head block and state of the chain change. 280 func (bs *Server) StreamChainHead(_ *emptypb.Empty, stream ethpb.BeaconChain_StreamChainHeadServer) error { 281 stateChannel := make(chan *feed.Event, 1) 282 stateSub := bs.StateNotifier.StateFeed().Subscribe(stateChannel) 283 defer stateSub.Unsubscribe() 284 for { 285 select { 286 case stateEvent := <-stateChannel: 287 if stateEvent.Type == statefeed.BlockProcessed { 288 res, err := bs.chainHeadRetrieval(stream.Context()) 289 if err != nil { 290 return status.Errorf(codes.Internal, "Could not retrieve chain head: %v", err) 291 } 292 if err := stream.Send(res); err != nil { 293 return status.Errorf(codes.Unavailable, "Could not send over stream: %v", err) 294 } 295 } 296 case <-stateSub.Err(): 297 return status.Error(codes.Aborted, "Subscriber closed, exiting goroutine") 298 case <-bs.Ctx.Done(): 299 return status.Error(codes.Canceled, "Context canceled") 300 case <-stream.Context().Done(): 301 return status.Error(codes.Canceled, "Context canceled") 302 } 303 } 304 } 305 306 // Retrieve chain head information from the DB and the current beacon state. 307 func (bs *Server) chainHeadRetrieval(ctx context.Context) (*ethpb.ChainHead, error) { 308 headBlock, err := bs.HeadFetcher.HeadBlock(ctx) 309 if err != nil { 310 return nil, status.Error(codes.Internal, "Could not get head block") 311 } 312 if headBlock == nil || headBlock.IsNil() || headBlock.Block().IsNil() { 313 return nil, status.Error(codes.Internal, "Head block of chain was nil") 314 } 315 headBlockRoot, err := headBlock.Block().HashTreeRoot() 316 if err != nil { 317 return nil, status.Errorf(codes.Internal, "Could not get head block root: %v", err) 318 } 319 320 isGenesis := func(cp *ethpb.Checkpoint) bool { 321 return bytesutil.ToBytes32(cp.Root) == params.BeaconConfig().ZeroHash && cp.Epoch == 0 322 } 323 // Retrieve genesis block in the event we have genesis checkpoints. 324 genBlock, err := bs.BeaconDB.GenesisBlock(ctx) 325 if err != nil || genBlock == nil || genBlock.IsNil() || genBlock.Block().IsNil() { 326 return nil, status.Error(codes.Internal, "Could not get genesis block") 327 } 328 329 finalizedCheckpoint := bs.FinalizationFetcher.FinalizedCheckpt() 330 if !isGenesis(finalizedCheckpoint) { 331 b, err := bs.BeaconDB.Block(ctx, bytesutil.ToBytes32(finalizedCheckpoint.Root)) 332 if err != nil { 333 return nil, status.Error(codes.Internal, "Could not get finalized block") 334 } 335 if err := helpers.VerifyNilBeaconBlock(b); err != nil { 336 return nil, status.Errorf(codes.Internal, "Could not get finalized block: %v", err) 337 } 338 } 339 340 justifiedCheckpoint := bs.FinalizationFetcher.CurrentJustifiedCheckpt() 341 if !isGenesis(justifiedCheckpoint) { 342 b, err := bs.BeaconDB.Block(ctx, bytesutil.ToBytes32(justifiedCheckpoint.Root)) 343 if err != nil { 344 return nil, status.Error(codes.Internal, "Could not get justified block") 345 } 346 if err := helpers.VerifyNilBeaconBlock(b); err != nil { 347 return nil, status.Errorf(codes.Internal, "Could not get justified block: %v", err) 348 } 349 } 350 351 prevJustifiedCheckpoint := bs.FinalizationFetcher.PreviousJustifiedCheckpt() 352 if !isGenesis(prevJustifiedCheckpoint) { 353 b, err := bs.BeaconDB.Block(ctx, bytesutil.ToBytes32(prevJustifiedCheckpoint.Root)) 354 if err != nil { 355 return nil, status.Error(codes.Internal, "Could not get prev justified block") 356 } 357 if err := helpers.VerifyNilBeaconBlock(b); err != nil { 358 return nil, status.Errorf(codes.Internal, "Could not get prev justified block: %v", err) 359 } 360 } 361 362 fSlot, err := helpers.StartSlot(finalizedCheckpoint.Epoch) 363 if err != nil { 364 return nil, err 365 } 366 jSlot, err := helpers.StartSlot(justifiedCheckpoint.Epoch) 367 if err != nil { 368 return nil, err 369 } 370 pjSlot, err := helpers.StartSlot(prevJustifiedCheckpoint.Epoch) 371 if err != nil { 372 return nil, err 373 } 374 return ðpb.ChainHead{ 375 HeadSlot: headBlock.Block().Slot(), 376 HeadEpoch: helpers.SlotToEpoch(headBlock.Block().Slot()), 377 HeadBlockRoot: headBlockRoot[:], 378 FinalizedSlot: fSlot, 379 FinalizedEpoch: finalizedCheckpoint.Epoch, 380 FinalizedBlockRoot: finalizedCheckpoint.Root, 381 JustifiedSlot: jSlot, 382 JustifiedEpoch: justifiedCheckpoint.Epoch, 383 JustifiedBlockRoot: justifiedCheckpoint.Root, 384 PreviousJustifiedSlot: pjSlot, 385 PreviousJustifiedEpoch: prevJustifiedCheckpoint.Epoch, 386 PreviousJustifiedBlockRoot: prevJustifiedCheckpoint.Root, 387 }, nil 388 } 389 390 // GetWeakSubjectivityCheckpoint retrieves weak subjectivity state root, block root, and epoch. 391 func (bs *Server) GetWeakSubjectivityCheckpoint(ctx context.Context, _ *emptypb.Empty) (*ethpb.WeakSubjectivityCheckpoint, error) { 392 hs, err := bs.HeadFetcher.HeadState(ctx) 393 if err != nil { 394 return nil, status.Error(codes.Internal, "Could not get head state") 395 } 396 wsEpoch, err := helpers.LatestWeakSubjectivityEpoch(hs) 397 if err != nil { 398 return nil, status.Error(codes.Internal, "Could not get weak subjectivity epoch") 399 } 400 wsSlot, err := helpers.StartSlot(wsEpoch) 401 if err != nil { 402 return nil, status.Error(codes.Internal, "Could not get weak subjectivity slot") 403 } 404 405 wsState, err := bs.StateGen.StateBySlot(ctx, wsSlot) 406 if err != nil { 407 return nil, status.Error(codes.Internal, "Could not get weak subjectivity state") 408 } 409 stateRoot, err := wsState.HashTreeRoot(ctx) 410 if err != nil { 411 return nil, status.Error(codes.Internal, "Could not get weak subjectivity state root") 412 } 413 blkRoot, err := wsState.LatestBlockHeader().HashTreeRoot() 414 if err != nil { 415 return nil, status.Error(codes.Internal, "Could not get weak subjectivity block root") 416 } 417 418 return ðpb.WeakSubjectivityCheckpoint{ 419 BlockRoot: blkRoot[:], 420 StateRoot: stateRoot[:], 421 Epoch: wsEpoch, 422 }, nil 423 }