github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/rpc/prysm/v1alpha1/beacon/blocks_test.go (about) 1 package beacon 2 3 import ( 4 "context" 5 "fmt" 6 "strconv" 7 "testing" 8 9 "github.com/golang/mock/gomock" 10 types "github.com/prysmaticlabs/eth2-types" 11 chainMock "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/testing" 12 "github.com/prysmaticlabs/prysm/beacon-chain/core/feed" 13 blockfeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/block" 14 statefeed "github.com/prysmaticlabs/prysm/beacon-chain/core/feed/state" 15 "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" 16 dbTest "github.com/prysmaticlabs/prysm/beacon-chain/db/testing" 17 "github.com/prysmaticlabs/prysm/beacon-chain/state/stategen" 18 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1" 19 pbp2p "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" 20 ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1" 21 "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1/wrapper" 22 "github.com/prysmaticlabs/prysm/proto/interfaces" 23 "github.com/prysmaticlabs/prysm/shared/bytesutil" 24 "github.com/prysmaticlabs/prysm/shared/cmd" 25 "github.com/prysmaticlabs/prysm/shared/mock" 26 "github.com/prysmaticlabs/prysm/shared/params" 27 "github.com/prysmaticlabs/prysm/shared/testutil" 28 "github.com/prysmaticlabs/prysm/shared/testutil/assert" 29 "github.com/prysmaticlabs/prysm/shared/testutil/require" 30 "google.golang.org/protobuf/proto" 31 "google.golang.org/protobuf/types/known/emptypb" 32 ) 33 34 func TestServer_ListBlocks_NoResults(t *testing.T) { 35 db := dbTest.SetupDB(t) 36 ctx := context.Background() 37 38 bs := &Server{ 39 BeaconDB: db, 40 } 41 wanted := ðpb.ListBlocksResponse{ 42 BlockContainers: make([]*ethpb.BeaconBlockContainer, 0), 43 TotalSize: int32(0), 44 NextPageToken: strconv.Itoa(0), 45 } 46 res, err := bs.ListBlocks(ctx, ðpb.ListBlocksRequest{ 47 QueryFilter: ðpb.ListBlocksRequest_Slot{ 48 Slot: 0, 49 }, 50 }) 51 require.NoError(t, err) 52 if !proto.Equal(wanted, res) { 53 t.Errorf("Wanted %v, received %v", wanted, res) 54 } 55 res, err = bs.ListBlocks(ctx, ðpb.ListBlocksRequest{ 56 QueryFilter: ðpb.ListBlocksRequest_Slot{ 57 Slot: 0, 58 }, 59 }) 60 require.NoError(t, err) 61 if !proto.Equal(wanted, res) { 62 t.Errorf("Wanted %v, received %v", wanted, res) 63 } 64 res, err = bs.ListBlocks(ctx, ðpb.ListBlocksRequest{ 65 QueryFilter: ðpb.ListBlocksRequest_Root{ 66 Root: make([]byte, 32), 67 }, 68 }) 69 require.NoError(t, err) 70 if !proto.Equal(wanted, res) { 71 t.Errorf("Wanted %v, received %v", wanted, res) 72 } 73 } 74 75 func TestServer_ListBlocks_Genesis(t *testing.T) { 76 db := dbTest.SetupDB(t) 77 ctx := context.Background() 78 79 bs := &Server{ 80 BeaconDB: db, 81 } 82 83 // Should throw an error if no genesis block is found. 84 _, err := bs.ListBlocks(ctx, ðpb.ListBlocksRequest{ 85 QueryFilter: ðpb.ListBlocksRequest_Genesis{ 86 Genesis: true, 87 }, 88 }) 89 require.ErrorContains(t, "Could not find genesis", err) 90 91 // Should return the proper genesis block if it exists. 92 parentRoot := [32]byte{'a'} 93 blk := testutil.NewBeaconBlock() 94 blk.Block.ParentRoot = parentRoot[:] 95 root, err := blk.Block.HashTreeRoot() 96 require.NoError(t, err) 97 require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(blk))) 98 require.NoError(t, db.SaveGenesisBlockRoot(ctx, root)) 99 wanted := ðpb.ListBlocksResponse{ 100 BlockContainers: []*ethpb.BeaconBlockContainer{ 101 { 102 Block: blk, 103 BlockRoot: root[:], 104 Canonical: true, 105 }, 106 }, 107 NextPageToken: "0", 108 TotalSize: 1, 109 } 110 res, err := bs.ListBlocks(ctx, ðpb.ListBlocksRequest{ 111 QueryFilter: ðpb.ListBlocksRequest_Genesis{ 112 Genesis: true, 113 }, 114 }) 115 require.NoError(t, err) 116 if !proto.Equal(wanted, res) { 117 t.Errorf("Wanted %v, received %v", wanted, res) 118 } 119 } 120 121 func TestServer_ListBlocks_Genesis_MultiBlocks(t *testing.T) { 122 db := dbTest.SetupDB(t) 123 ctx := context.Background() 124 125 bs := &Server{ 126 BeaconDB: db, 127 } 128 // Should return the proper genesis block if it exists. 129 parentRoot := [32]byte{1, 2, 3} 130 blk := testutil.NewBeaconBlock() 131 blk.Block.ParentRoot = parentRoot[:] 132 root, err := blk.Block.HashTreeRoot() 133 require.NoError(t, err) 134 require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(blk))) 135 require.NoError(t, db.SaveGenesisBlockRoot(ctx, root)) 136 137 count := types.Slot(100) 138 blks := make([]interfaces.SignedBeaconBlock, count) 139 for i := types.Slot(0); i < count; i++ { 140 b := testutil.NewBeaconBlock() 141 b.Block.Slot = i 142 require.NoError(t, err) 143 blks[i] = wrapper.WrappedPhase0SignedBeaconBlock(b) 144 } 145 require.NoError(t, db.SaveBlocks(ctx, blks)) 146 147 // Should throw an error if more than one blk returned. 148 _, err = bs.ListBlocks(ctx, ðpb.ListBlocksRequest{ 149 QueryFilter: ðpb.ListBlocksRequest_Genesis{ 150 Genesis: true, 151 }, 152 }) 153 require.NoError(t, err) 154 } 155 156 func TestServer_ListBlocks_Pagination(t *testing.T) { 157 params.UseMinimalConfig() 158 defer params.UseMainnetConfig() 159 160 db := dbTest.SetupDB(t) 161 chain := &chainMock.ChainService{ 162 CanonicalRoots: map[[32]byte]bool{}, 163 } 164 ctx := context.Background() 165 166 count := types.Slot(100) 167 blks := make([]interfaces.SignedBeaconBlock, count) 168 blkContainers := make([]*ethpb.BeaconBlockContainer, count) 169 for i := types.Slot(0); i < count; i++ { 170 b := testutil.NewBeaconBlock() 171 b.Block.Slot = i 172 root, err := b.Block.HashTreeRoot() 173 require.NoError(t, err) 174 chain.CanonicalRoots[root] = true 175 blks[i] = wrapper.WrappedPhase0SignedBeaconBlock(b) 176 blkContainers[i] = ðpb.BeaconBlockContainer{Block: b, BlockRoot: root[:], Canonical: true} 177 } 178 require.NoError(t, db.SaveBlocks(ctx, blks)) 179 180 orphanedBlk := testutil.NewBeaconBlock() 181 orphanedBlk.Block.Slot = 300 182 orphanedBlkRoot, err := orphanedBlk.Block.HashTreeRoot() 183 require.NoError(t, err) 184 require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(orphanedBlk))) 185 186 bs := &Server{ 187 BeaconDB: db, 188 CanonicalFetcher: chain, 189 } 190 191 root6, err := blks[6].Block().HashTreeRoot() 192 require.NoError(t, err) 193 194 tests := []struct { 195 req *ethpb.ListBlocksRequest 196 res *ethpb.ListBlocksResponse 197 }{ 198 {req: ðpb.ListBlocksRequest{ 199 PageToken: strconv.Itoa(0), 200 QueryFilter: ðpb.ListBlocksRequest_Slot{Slot: 5}, 201 PageSize: 3}, 202 res: ðpb.ListBlocksResponse{ 203 BlockContainers: []*ethpb.BeaconBlockContainer{{Block: testutil.HydrateSignedBeaconBlock(ðpb.SignedBeaconBlock{ 204 Block: ðpb.BeaconBlock{ 205 Slot: 5}}), 206 BlockRoot: blkContainers[5].BlockRoot, 207 Canonical: blkContainers[5].Canonical}}, 208 NextPageToken: "", 209 TotalSize: 1}}, 210 {req: ðpb.ListBlocksRequest{ 211 PageToken: strconv.Itoa(0), 212 QueryFilter: ðpb.ListBlocksRequest_Root{Root: root6[:]}, 213 PageSize: 3}, 214 res: ðpb.ListBlocksResponse{ 215 BlockContainers: []*ethpb.BeaconBlockContainer{{Block: testutil.HydrateSignedBeaconBlock(ðpb.SignedBeaconBlock{ 216 Block: ðpb.BeaconBlock{ 217 Slot: 6}}), 218 BlockRoot: blkContainers[6].BlockRoot, 219 Canonical: blkContainers[6].Canonical}}, 220 TotalSize: 1}}, 221 {req: ðpb.ListBlocksRequest{QueryFilter: ðpb.ListBlocksRequest_Root{Root: root6[:]}}, 222 res: ðpb.ListBlocksResponse{ 223 BlockContainers: []*ethpb.BeaconBlockContainer{{Block: testutil.HydrateSignedBeaconBlock(ðpb.SignedBeaconBlock{ 224 Block: ðpb.BeaconBlock{ 225 Slot: 6}}), 226 BlockRoot: blkContainers[6].BlockRoot, 227 Canonical: blkContainers[6].Canonical}}, 228 TotalSize: 1}}, 229 {req: ðpb.ListBlocksRequest{ 230 PageToken: strconv.Itoa(0), 231 QueryFilter: ðpb.ListBlocksRequest_Epoch{Epoch: 0}, 232 PageSize: 100}, 233 res: ðpb.ListBlocksResponse{ 234 BlockContainers: blkContainers[0:params.BeaconConfig().SlotsPerEpoch], 235 NextPageToken: "", 236 TotalSize: int32(params.BeaconConfig().SlotsPerEpoch)}}, 237 {req: ðpb.ListBlocksRequest{ 238 PageToken: strconv.Itoa(1), 239 QueryFilter: ðpb.ListBlocksRequest_Epoch{Epoch: 5}, 240 PageSize: 3}, 241 res: ðpb.ListBlocksResponse{ 242 BlockContainers: blkContainers[43:46], 243 NextPageToken: "2", 244 TotalSize: int32(params.BeaconConfig().SlotsPerEpoch)}}, 245 {req: ðpb.ListBlocksRequest{ 246 PageToken: strconv.Itoa(1), 247 QueryFilter: ðpb.ListBlocksRequest_Epoch{Epoch: 11}, 248 PageSize: 7}, 249 res: ðpb.ListBlocksResponse{ 250 BlockContainers: blkContainers[95:96], 251 NextPageToken: "", 252 TotalSize: int32(params.BeaconConfig().SlotsPerEpoch)}}, 253 {req: ðpb.ListBlocksRequest{ 254 PageToken: strconv.Itoa(0), 255 QueryFilter: ðpb.ListBlocksRequest_Epoch{Epoch: 12}, 256 PageSize: 4}, 257 res: ðpb.ListBlocksResponse{ 258 BlockContainers: blkContainers[96:100], 259 NextPageToken: "", 260 TotalSize: int32(params.BeaconConfig().SlotsPerEpoch / 2)}}, 261 {req: ðpb.ListBlocksRequest{ 262 PageToken: strconv.Itoa(0), 263 QueryFilter: ðpb.ListBlocksRequest_Slot{Slot: 300}, 264 PageSize: 3}, 265 res: ðpb.ListBlocksResponse{ 266 BlockContainers: []*ethpb.BeaconBlockContainer{{Block: testutil.HydrateSignedBeaconBlock(ðpb.SignedBeaconBlock{ 267 Block: ðpb.BeaconBlock{ 268 Slot: 300}}), 269 BlockRoot: orphanedBlkRoot[:], 270 Canonical: false}}, 271 NextPageToken: "", 272 TotalSize: 1}}, 273 } 274 275 for i, test := range tests { 276 t.Run(fmt.Sprintf("test_%d", i), func(t *testing.T) { 277 res, err := bs.ListBlocks(ctx, test.req) 278 require.NoError(t, err) 279 require.DeepSSZEqual(t, res, test.res) 280 }) 281 } 282 } 283 284 func TestServer_ListBlocks_Errors(t *testing.T) { 285 db := dbTest.SetupDB(t) 286 ctx := context.Background() 287 288 bs := &Server{BeaconDB: db} 289 exceedsMax := int32(cmd.Get().MaxRPCPageSize + 1) 290 291 wanted := fmt.Sprintf("Requested page size %d can not be greater than max size %d", exceedsMax, cmd.Get().MaxRPCPageSize) 292 req := ðpb.ListBlocksRequest{PageToken: strconv.Itoa(0), PageSize: exceedsMax} 293 _, err := bs.ListBlocks(ctx, req) 294 assert.ErrorContains(t, wanted, err) 295 296 wanted = "Must specify a filter criteria for fetching" 297 req = ðpb.ListBlocksRequest{} 298 _, err = bs.ListBlocks(ctx, req) 299 assert.ErrorContains(t, wanted, err) 300 301 req = ðpb.ListBlocksRequest{QueryFilter: ðpb.ListBlocksRequest_Slot{Slot: 0}} 302 res, err := bs.ListBlocks(ctx, req) 303 require.NoError(t, err) 304 assert.Equal(t, 0, len(res.BlockContainers), "Wanted empty list") 305 assert.Equal(t, int32(0), res.TotalSize, "Wanted total size 0") 306 307 req = ðpb.ListBlocksRequest{QueryFilter: ðpb.ListBlocksRequest_Slot{}} 308 res, err = bs.ListBlocks(ctx, req) 309 require.NoError(t, err) 310 assert.Equal(t, 0, len(res.BlockContainers), "Wanted empty list") 311 assert.Equal(t, int32(0), res.TotalSize, "Wanted total size 0") 312 313 req = ðpb.ListBlocksRequest{QueryFilter: ðpb.ListBlocksRequest_Root{Root: []byte{'A'}}} 314 res, err = bs.ListBlocks(ctx, req) 315 require.NoError(t, err) 316 assert.Equal(t, 0, len(res.BlockContainers), "Wanted empty list") 317 assert.Equal(t, int32(0), res.TotalSize, "Wanted total size 0") 318 319 req = ðpb.ListBlocksRequest{QueryFilter: ðpb.ListBlocksRequest_Root{Root: []byte{'A'}}} 320 res, err = bs.ListBlocks(ctx, req) 321 require.NoError(t, err) 322 assert.Equal(t, 0, len(res.BlockContainers), "Wanted empty list") 323 assert.Equal(t, int32(0), res.TotalSize, "Wanted total size 0") 324 } 325 326 func TestServer_GetChainHead_NoFinalizedBlock(t *testing.T) { 327 db := dbTest.SetupDB(t) 328 329 s, err := testutil.NewBeaconState() 330 require.NoError(t, err) 331 require.NoError(t, s.SetSlot(1)) 332 require.NoError(t, s.SetPreviousJustifiedCheckpoint(ðpb.Checkpoint{Epoch: 3, Root: bytesutil.PadTo([]byte{'A'}, 32)})) 333 require.NoError(t, s.SetCurrentJustifiedCheckpoint(ðpb.Checkpoint{Epoch: 2, Root: bytesutil.PadTo([]byte{'B'}, 32)})) 334 require.NoError(t, s.SetFinalizedCheckpoint(ðpb.Checkpoint{Epoch: 1, Root: bytesutil.PadTo([]byte{'C'}, 32)})) 335 336 genBlock := testutil.NewBeaconBlock() 337 genBlock.Block.ParentRoot = bytesutil.PadTo([]byte{'G'}, 32) 338 require.NoError(t, db.SaveBlock(context.Background(), wrapper.WrappedPhase0SignedBeaconBlock(genBlock))) 339 gRoot, err := genBlock.Block.HashTreeRoot() 340 require.NoError(t, err) 341 require.NoError(t, db.SaveGenesisBlockRoot(context.Background(), gRoot)) 342 343 bs := &Server{ 344 BeaconDB: db, 345 HeadFetcher: &chainMock.ChainService{Block: wrapper.WrappedPhase0SignedBeaconBlock(genBlock), State: s}, 346 FinalizationFetcher: &chainMock.ChainService{ 347 FinalizedCheckPoint: s.FinalizedCheckpoint(), 348 CurrentJustifiedCheckPoint: s.CurrentJustifiedCheckpoint(), 349 PreviousJustifiedCheckPoint: s.PreviousJustifiedCheckpoint()}, 350 } 351 352 _, err = bs.GetChainHead(context.Background(), nil) 353 require.ErrorContains(t, "Could not get finalized block", err) 354 } 355 356 func TestServer_GetChainHead_NoHeadBlock(t *testing.T) { 357 bs := &Server{ 358 HeadFetcher: &chainMock.ChainService{Block: nil}, 359 } 360 _, err := bs.GetChainHead(context.Background(), nil) 361 assert.ErrorContains(t, "Head block of chain was nil", err) 362 } 363 364 func TestServer_GetChainHead(t *testing.T) { 365 params.UseMinimalConfig() 366 defer params.UseMainnetConfig() 367 368 db := dbTest.SetupDB(t) 369 genBlock := testutil.NewBeaconBlock() 370 genBlock.Block.ParentRoot = bytesutil.PadTo([]byte{'G'}, 32) 371 require.NoError(t, db.SaveBlock(context.Background(), wrapper.WrappedPhase0SignedBeaconBlock(genBlock))) 372 gRoot, err := genBlock.Block.HashTreeRoot() 373 require.NoError(t, err) 374 require.NoError(t, db.SaveGenesisBlockRoot(context.Background(), gRoot)) 375 376 finalizedBlock := testutil.NewBeaconBlock() 377 finalizedBlock.Block.Slot = 1 378 finalizedBlock.Block.ParentRoot = bytesutil.PadTo([]byte{'A'}, 32) 379 require.NoError(t, db.SaveBlock(context.Background(), wrapper.WrappedPhase0SignedBeaconBlock(finalizedBlock))) 380 fRoot, err := finalizedBlock.Block.HashTreeRoot() 381 require.NoError(t, err) 382 383 justifiedBlock := testutil.NewBeaconBlock() 384 justifiedBlock.Block.Slot = 2 385 justifiedBlock.Block.ParentRoot = bytesutil.PadTo([]byte{'B'}, 32) 386 require.NoError(t, db.SaveBlock(context.Background(), wrapper.WrappedPhase0SignedBeaconBlock(justifiedBlock))) 387 jRoot, err := justifiedBlock.Block.HashTreeRoot() 388 require.NoError(t, err) 389 390 prevJustifiedBlock := testutil.NewBeaconBlock() 391 prevJustifiedBlock.Block.Slot = 3 392 prevJustifiedBlock.Block.ParentRoot = bytesutil.PadTo([]byte{'C'}, 32) 393 require.NoError(t, db.SaveBlock(context.Background(), wrapper.WrappedPhase0SignedBeaconBlock(prevJustifiedBlock))) 394 pjRoot, err := prevJustifiedBlock.Block.HashTreeRoot() 395 require.NoError(t, err) 396 397 s, err := v1.InitializeFromProto(&pbp2p.BeaconState{ 398 Slot: 1, 399 PreviousJustifiedCheckpoint: ðpb.Checkpoint{Epoch: 3, Root: pjRoot[:]}, 400 CurrentJustifiedCheckpoint: ðpb.Checkpoint{Epoch: 2, Root: jRoot[:]}, 401 FinalizedCheckpoint: ðpb.Checkpoint{Epoch: 1, Root: fRoot[:]}, 402 }) 403 require.NoError(t, err) 404 405 b := testutil.NewBeaconBlock() 406 b.Block.Slot, err = helpers.StartSlot(s.PreviousJustifiedCheckpoint().Epoch) 407 require.NoError(t, err) 408 b.Block.Slot++ 409 bs := &Server{ 410 BeaconDB: db, 411 HeadFetcher: &chainMock.ChainService{Block: wrapper.WrappedPhase0SignedBeaconBlock(b), State: s}, 412 FinalizationFetcher: &chainMock.ChainService{ 413 FinalizedCheckPoint: s.FinalizedCheckpoint(), 414 CurrentJustifiedCheckPoint: s.CurrentJustifiedCheckpoint(), 415 PreviousJustifiedCheckPoint: s.PreviousJustifiedCheckpoint()}, 416 } 417 418 head, err := bs.GetChainHead(context.Background(), nil) 419 require.NoError(t, err) 420 assert.Equal(t, types.Epoch(3), head.PreviousJustifiedEpoch, "Unexpected PreviousJustifiedEpoch") 421 assert.Equal(t, types.Epoch(2), head.JustifiedEpoch, "Unexpected JustifiedEpoch") 422 assert.Equal(t, types.Epoch(1), head.FinalizedEpoch, "Unexpected FinalizedEpoch") 423 assert.Equal(t, types.Slot(24), head.PreviousJustifiedSlot, "Unexpected PreviousJustifiedSlot") 424 assert.Equal(t, types.Slot(16), head.JustifiedSlot, "Unexpected JustifiedSlot") 425 assert.Equal(t, types.Slot(8), head.FinalizedSlot, "Unexpected FinalizedSlot") 426 assert.DeepEqual(t, pjRoot[:], head.PreviousJustifiedBlockRoot, "Unexpected PreviousJustifiedBlockRoot") 427 assert.DeepEqual(t, jRoot[:], head.JustifiedBlockRoot, "Unexpected JustifiedBlockRoot") 428 assert.DeepEqual(t, fRoot[:], head.FinalizedBlockRoot, "Unexpected FinalizedBlockRoot") 429 } 430 431 func TestServer_StreamChainHead_ContextCanceled(t *testing.T) { 432 db := dbTest.SetupDB(t) 433 ctx := context.Background() 434 435 ctx, cancel := context.WithCancel(ctx) 436 chainService := &chainMock.ChainService{} 437 server := &Server{ 438 Ctx: ctx, 439 StateNotifier: chainService.StateNotifier(), 440 BeaconDB: db, 441 } 442 443 exitRoutine := make(chan bool) 444 ctrl := gomock.NewController(t) 445 defer ctrl.Finish() 446 mockStream := mock.NewMockBeaconChain_StreamChainHeadServer(ctrl) 447 mockStream.EXPECT().Context().Return(ctx) 448 go func(tt *testing.T) { 449 assert.ErrorContains(tt, "Context canceled", server.StreamChainHead(&emptypb.Empty{}, mockStream)) 450 <-exitRoutine 451 }(t) 452 cancel() 453 exitRoutine <- true 454 } 455 456 func TestServer_StreamChainHead_OnHeadUpdated(t *testing.T) { 457 db := dbTest.SetupDB(t) 458 params.UseMainnetConfig() 459 genBlock := testutil.NewBeaconBlock() 460 genBlock.Block.ParentRoot = bytesutil.PadTo([]byte{'G'}, 32) 461 require.NoError(t, db.SaveBlock(context.Background(), wrapper.WrappedPhase0SignedBeaconBlock(genBlock))) 462 gRoot, err := genBlock.Block.HashTreeRoot() 463 require.NoError(t, err) 464 require.NoError(t, db.SaveGenesisBlockRoot(context.Background(), gRoot)) 465 466 finalizedBlock := testutil.NewBeaconBlock() 467 finalizedBlock.Block.Slot = 32 468 finalizedBlock.Block.ParentRoot = bytesutil.PadTo([]byte{'A'}, 32) 469 require.NoError(t, db.SaveBlock(context.Background(), wrapper.WrappedPhase0SignedBeaconBlock(finalizedBlock))) 470 fRoot, err := finalizedBlock.Block.HashTreeRoot() 471 require.NoError(t, err) 472 473 justifiedBlock := testutil.NewBeaconBlock() 474 justifiedBlock.Block.Slot = 64 475 justifiedBlock.Block.ParentRoot = bytesutil.PadTo([]byte{'B'}, 32) 476 require.NoError(t, db.SaveBlock(context.Background(), wrapper.WrappedPhase0SignedBeaconBlock(justifiedBlock))) 477 jRoot, err := justifiedBlock.Block.HashTreeRoot() 478 require.NoError(t, err) 479 480 prevJustifiedBlock := testutil.NewBeaconBlock() 481 prevJustifiedBlock.Block.Slot = 96 482 prevJustifiedBlock.Block.ParentRoot = bytesutil.PadTo([]byte{'C'}, 32) 483 require.NoError(t, db.SaveBlock(context.Background(), wrapper.WrappedPhase0SignedBeaconBlock(prevJustifiedBlock))) 484 pjRoot, err := prevJustifiedBlock.Block.HashTreeRoot() 485 require.NoError(t, err) 486 487 s, err := v1.InitializeFromProto(&pbp2p.BeaconState{ 488 Slot: 1, 489 PreviousJustifiedCheckpoint: ðpb.Checkpoint{Epoch: 3, Root: pjRoot[:]}, 490 CurrentJustifiedCheckpoint: ðpb.Checkpoint{Epoch: 2, Root: jRoot[:]}, 491 FinalizedCheckpoint: ðpb.Checkpoint{Epoch: 1, Root: fRoot[:]}, 492 }) 493 require.NoError(t, err) 494 495 b := testutil.NewBeaconBlock() 496 b.Block.Slot, err = helpers.StartSlot(s.PreviousJustifiedCheckpoint().Epoch) 497 require.NoError(t, err) 498 499 hRoot, err := b.Block.HashTreeRoot() 500 require.NoError(t, err) 501 502 chainService := &chainMock.ChainService{} 503 ctx := context.Background() 504 server := &Server{ 505 Ctx: ctx, 506 HeadFetcher: &chainMock.ChainService{Block: wrapper.WrappedPhase0SignedBeaconBlock(b), State: s}, 507 BeaconDB: db, 508 StateNotifier: chainService.StateNotifier(), 509 FinalizationFetcher: &chainMock.ChainService{ 510 FinalizedCheckPoint: s.FinalizedCheckpoint(), 511 CurrentJustifiedCheckPoint: s.CurrentJustifiedCheckpoint(), 512 PreviousJustifiedCheckPoint: s.PreviousJustifiedCheckpoint()}, 513 } 514 exitRoutine := make(chan bool) 515 ctrl := gomock.NewController(t) 516 defer ctrl.Finish() 517 mockStream := mock.NewMockBeaconChain_StreamChainHeadServer(ctrl) 518 mockStream.EXPECT().Send( 519 ðpb.ChainHead{ 520 HeadSlot: b.Block.Slot, 521 HeadEpoch: helpers.SlotToEpoch(b.Block.Slot), 522 HeadBlockRoot: hRoot[:], 523 FinalizedSlot: 32, 524 FinalizedEpoch: 1, 525 FinalizedBlockRoot: fRoot[:], 526 JustifiedSlot: 64, 527 JustifiedEpoch: 2, 528 JustifiedBlockRoot: jRoot[:], 529 PreviousJustifiedSlot: 96, 530 PreviousJustifiedEpoch: 3, 531 PreviousJustifiedBlockRoot: pjRoot[:], 532 }, 533 ).Do(func(arg0 interface{}) { 534 exitRoutine <- true 535 }) 536 mockStream.EXPECT().Context().Return(ctx).AnyTimes() 537 538 go func(tt *testing.T) { 539 assert.NoError(tt, server.StreamChainHead(&emptypb.Empty{}, mockStream), "Could not call RPC method") 540 }(t) 541 542 // Send in a loop to ensure it is delivered (busy wait for the service to subscribe to the state feed). 543 for sent := 0; sent == 0; { 544 sent = server.StateNotifier.StateFeed().Send(&feed.Event{ 545 Type: statefeed.BlockProcessed, 546 Data: &statefeed.BlockProcessedData{}, 547 }) 548 } 549 <-exitRoutine 550 } 551 552 func TestServer_StreamBlocksVerified_ContextCanceled(t *testing.T) { 553 db := dbTest.SetupDB(t) 554 ctx := context.Background() 555 556 chainService := &chainMock.ChainService{} 557 ctx, cancel := context.WithCancel(ctx) 558 server := &Server{ 559 Ctx: ctx, 560 StateNotifier: chainService.StateNotifier(), 561 HeadFetcher: chainService, 562 BeaconDB: db, 563 } 564 565 exitRoutine := make(chan bool) 566 ctrl := gomock.NewController(t) 567 defer ctrl.Finish() 568 mockStream := mock.NewMockBeaconChain_StreamBlocksServer(ctrl) 569 mockStream.EXPECT().Context().Return(ctx) 570 go func(tt *testing.T) { 571 assert.ErrorContains(tt, "Context canceled", server.StreamBlocks(ðpb.StreamBlocksRequest{ 572 VerifiedOnly: true, 573 }, mockStream)) 574 <-exitRoutine 575 }(t) 576 cancel() 577 exitRoutine <- true 578 } 579 580 func TestServer_StreamBlocks_ContextCanceled(t *testing.T) { 581 db := dbTest.SetupDB(t) 582 ctx := context.Background() 583 584 chainService := &chainMock.ChainService{} 585 ctx, cancel := context.WithCancel(ctx) 586 server := &Server{ 587 Ctx: ctx, 588 BlockNotifier: chainService.BlockNotifier(), 589 HeadFetcher: chainService, 590 BeaconDB: db, 591 } 592 593 exitRoutine := make(chan bool) 594 ctrl := gomock.NewController(t) 595 defer ctrl.Finish() 596 mockStream := mock.NewMockBeaconChain_StreamBlocksServer(ctrl) 597 mockStream.EXPECT().Context().Return(ctx) 598 go func(tt *testing.T) { 599 assert.ErrorContains(tt, "Context canceled", server.StreamBlocks(ðpb.StreamBlocksRequest{}, mockStream)) 600 <-exitRoutine 601 }(t) 602 cancel() 603 exitRoutine <- true 604 } 605 606 func TestServer_StreamBlocks_OnHeadUpdated(t *testing.T) { 607 ctx := context.Background() 608 beaconState, privs := testutil.DeterministicGenesisState(t, 32) 609 b, err := testutil.GenerateFullBlock(beaconState, privs, testutil.DefaultBlockGenConfig(), 1) 610 require.NoError(t, err) 611 chainService := &chainMock.ChainService{State: beaconState} 612 server := &Server{ 613 Ctx: ctx, 614 BlockNotifier: chainService.BlockNotifier(), 615 HeadFetcher: chainService, 616 } 617 exitRoutine := make(chan bool) 618 ctrl := gomock.NewController(t) 619 defer ctrl.Finish() 620 mockStream := mock.NewMockBeaconChain_StreamBlocksServer(ctrl) 621 mockStream.EXPECT().Send(b).Do(func(arg0 interface{}) { 622 exitRoutine <- true 623 }) 624 mockStream.EXPECT().Context().Return(ctx).AnyTimes() 625 626 go func(tt *testing.T) { 627 assert.NoError(tt, server.StreamBlocks(ðpb.StreamBlocksRequest{}, mockStream), "Could not call RPC method") 628 }(t) 629 630 // Send in a loop to ensure it is delivered (busy wait for the service to subscribe to the state feed). 631 for sent := 0; sent == 0; { 632 sent = server.BlockNotifier.BlockFeed().Send(&feed.Event{ 633 Type: blockfeed.ReceivedBlock, 634 Data: &blockfeed.ReceivedBlockData{SignedBlock: wrapper.WrappedPhase0SignedBeaconBlock(b)}, 635 }) 636 } 637 <-exitRoutine 638 } 639 640 func TestServer_StreamBlocksVerified_OnHeadUpdated(t *testing.T) { 641 db := dbTest.SetupDB(t) 642 ctx := context.Background() 643 beaconState, privs := testutil.DeterministicGenesisState(t, 32) 644 b, err := testutil.GenerateFullBlock(beaconState, privs, testutil.DefaultBlockGenConfig(), 1) 645 require.NoError(t, err) 646 r, err := b.Block.HashTreeRoot() 647 require.NoError(t, err) 648 require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(b))) 649 chainService := &chainMock.ChainService{State: beaconState} 650 server := &Server{ 651 Ctx: ctx, 652 StateNotifier: chainService.StateNotifier(), 653 HeadFetcher: chainService, 654 BeaconDB: db, 655 } 656 exitRoutine := make(chan bool) 657 ctrl := gomock.NewController(t) 658 defer ctrl.Finish() 659 mockStream := mock.NewMockBeaconChain_StreamBlocksServer(ctrl) 660 mockStream.EXPECT().Send(b).Do(func(arg0 interface{}) { 661 exitRoutine <- true 662 }) 663 mockStream.EXPECT().Context().Return(ctx).AnyTimes() 664 665 go func(tt *testing.T) { 666 assert.NoError(tt, server.StreamBlocks(ðpb.StreamBlocksRequest{ 667 VerifiedOnly: true, 668 }, mockStream), "Could not call RPC method") 669 }(t) 670 671 // Send in a loop to ensure it is delivered (busy wait for the service to subscribe to the state feed). 672 for sent := 0; sent == 0; { 673 sent = server.StateNotifier.StateFeed().Send(&feed.Event{ 674 Type: statefeed.BlockProcessed, 675 Data: &statefeed.BlockProcessedData{Slot: b.Block.Slot, BlockRoot: r, SignedBlock: wrapper.WrappedPhase0SignedBeaconBlock(b)}, 676 }) 677 } 678 <-exitRoutine 679 } 680 681 func TestServer_GetWeakSubjectivityCheckpoint(t *testing.T) { 682 params.UseMainnetConfig() 683 684 db := dbTest.SetupDB(t) 685 ctx := context.Background() 686 687 // Beacon state. 688 beaconState, err := testutil.NewBeaconState() 689 require.NoError(t, err) 690 require.NoError(t, beaconState.SetSlot(10)) 691 692 // Active validator set is used for computing the weak subjectivity period. 693 numVals := 256 // Works with params.BeaconConfig().MinGenesisActiveValidatorCount as well, but takes longer. 694 validators := make([]*ethpb.Validator, numVals) 695 balances := make([]uint64, len(validators)) 696 for i := 0; i < len(validators); i++ { 697 validators[i] = ðpb.Validator{ 698 PublicKey: make([]byte, params.BeaconConfig().BLSPubkeyLength), 699 WithdrawalCredentials: make([]byte, 32), 700 EffectiveBalance: 28 * 1e9, 701 ExitEpoch: params.BeaconConfig().FarFutureEpoch, 702 } 703 balances[i] = validators[i].EffectiveBalance 704 } 705 require.NoError(t, beaconState.SetValidators(validators)) 706 require.NoError(t, beaconState.SetBalances(balances)) 707 708 // Genesis block. 709 genesisBlock := testutil.NewBeaconBlock() 710 genesisBlockRoot, err := genesisBlock.Block.HashTreeRoot() 711 require.NoError(t, err) 712 require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(genesisBlock))) 713 require.NoError(t, db.SaveState(ctx, beaconState, genesisBlockRoot)) 714 require.NoError(t, db.SaveGenesisBlockRoot(ctx, genesisBlockRoot)) 715 716 // Finalized checkpoint. 717 finalizedEpoch := types.Epoch(1020) 718 require.NoError(t, beaconState.SetSlot(types.Slot(finalizedEpoch.Mul(uint64(params.BeaconConfig().SlotsPerEpoch))))) 719 require.NoError(t, beaconState.SetCurrentJustifiedCheckpoint(ðpb.Checkpoint{ 720 Epoch: finalizedEpoch - 1, 721 Root: bytesutil.PadTo([]byte{'A'}, 32), 722 })) 723 require.NoError(t, beaconState.SetFinalizedCheckpoint(ðpb.Checkpoint{ 724 Epoch: finalizedEpoch, 725 Root: bytesutil.PadTo([]byte{'B'}, 32), 726 })) 727 728 chainService := &chainMock.ChainService{State: beaconState} 729 server := &Server{ 730 Ctx: ctx, 731 BlockNotifier: chainService.BlockNotifier(), 732 HeadFetcher: chainService, 733 BeaconDB: db, 734 StateGen: stategen.New(db), 735 } 736 737 wsEpoch, err := helpers.ComputeWeakSubjectivityPeriod(beaconState) 738 require.NoError(t, err) 739 740 c, err := server.GetWeakSubjectivityCheckpoint(ctx, &emptypb.Empty{}) 741 require.NoError(t, err) 742 e := finalizedEpoch - (finalizedEpoch % wsEpoch) 743 require.Equal(t, e, c.Epoch) 744 wsState, err := server.StateGen.StateBySlot(ctx, params.BeaconConfig().SlotsPerEpoch.Mul(uint64(e))) 745 require.NoError(t, err) 746 sRoot, err := wsState.HashTreeRoot(ctx) 747 require.NoError(t, err) 748 require.DeepEqual(t, sRoot[:], c.StateRoot) 749 }