github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/sync/validate_beacon_blocks_test.go (about) 1 package sync 2 3 import ( 4 "bytes" 5 "context" 6 "errors" 7 "reflect" 8 "testing" 9 "time" 10 11 lru "github.com/hashicorp/golang-lru" 12 pubsub "github.com/libp2p/go-libp2p-pubsub" 13 pubsubpb "github.com/libp2p/go-libp2p-pubsub/pb" 14 gcache "github.com/patrickmn/go-cache" 15 types "github.com/prysmaticlabs/eth2-types" 16 mock "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/testing" 17 "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" 18 "github.com/prysmaticlabs/prysm/beacon-chain/core/state" 19 dbtest "github.com/prysmaticlabs/prysm/beacon-chain/db/testing" 20 "github.com/prysmaticlabs/prysm/beacon-chain/operations/attestations" 21 "github.com/prysmaticlabs/prysm/beacon-chain/p2p" 22 p2ptest "github.com/prysmaticlabs/prysm/beacon-chain/p2p/testing" 23 "github.com/prysmaticlabs/prysm/beacon-chain/state/stategen" 24 mockSync "github.com/prysmaticlabs/prysm/beacon-chain/sync/initial-sync/testing" 25 pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" 26 ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1" 27 "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1/wrapper" 28 "github.com/prysmaticlabs/prysm/shared/abool" 29 "github.com/prysmaticlabs/prysm/shared/bls" 30 "github.com/prysmaticlabs/prysm/shared/bytesutil" 31 "github.com/prysmaticlabs/prysm/shared/params" 32 "github.com/prysmaticlabs/prysm/shared/testutil" 33 "github.com/prysmaticlabs/prysm/shared/testutil/assert" 34 "github.com/prysmaticlabs/prysm/shared/testutil/require" 35 logTest "github.com/sirupsen/logrus/hooks/test" 36 ) 37 38 // General note for writing validation tests: Use a random value for any field 39 // on the beacon block to avoid hitting shared global cache conditions across 40 // tests in this package. 41 42 func TestValidateBeaconBlockPubSub_InvalidSignature(t *testing.T) { 43 db := dbtest.SetupDB(t) 44 p := p2ptest.NewTestP2P(t) 45 ctx := context.Background() 46 beaconState, _ := testutil.DeterministicGenesisState(t, 100) 47 parentBlock := testutil.NewBeaconBlock() 48 require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(parentBlock))) 49 bRoot, err := parentBlock.Block.HashTreeRoot() 50 require.NoError(t, err) 51 require.NoError(t, db.SaveState(ctx, beaconState, bRoot)) 52 require.NoError(t, db.SaveStateSummary(ctx, &pb.StateSummary{Root: bRoot[:]})) 53 copied := beaconState.Copy() 54 require.NoError(t, copied.SetSlot(1)) 55 proposerIdx, err := helpers.BeaconProposerIndex(copied) 56 require.NoError(t, err) 57 msg := testutil.NewBeaconBlock() 58 msg.Block.ParentRoot = bRoot[:] 59 msg.Block.Slot = 1 60 msg.Block.ProposerIndex = proposerIdx 61 msg.Signature = bytesutil.PadTo([]byte("fake"), 96) 62 63 c, err := lru.New(10) 64 require.NoError(t, err) 65 c2, err := lru.New(10) 66 require.NoError(t, err) 67 stateGen := stategen.New(db) 68 chainService := &mock.ChainService{Genesis: time.Unix(time.Now().Unix()-int64(params.BeaconConfig().SecondsPerSlot), 0), 69 FinalizedCheckPoint: ðpb.Checkpoint{ 70 Epoch: 0, 71 Root: make([]byte, 32), 72 }} 73 r := &Service{ 74 cfg: &Config{ 75 DB: db, 76 P2P: p, 77 InitialSync: &mockSync.Sync{IsSyncing: false}, 78 Chain: chainService, 79 BlockNotifier: chainService.BlockNotifier(), 80 StateGen: stateGen, 81 }, 82 seenBlockCache: c, 83 badBlockCache: c2, 84 } 85 86 buf := new(bytes.Buffer) 87 _, err = p.Encoding().EncodeGossip(buf, msg) 88 require.NoError(t, err) 89 topic := p2p.GossipTypeMapping[reflect.TypeOf(msg)] 90 m := &pubsub.Message{ 91 Message: &pubsubpb.Message{ 92 Data: buf.Bytes(), 93 Topic: &topic, 94 }, 95 } 96 result := r.validateBeaconBlockPubSub(ctx, "", m) == pubsub.ValidationReject 97 assert.Equal(t, true, result) 98 } 99 100 func TestValidateBeaconBlockPubSub_BlockAlreadyPresentInDB(t *testing.T) { 101 db := dbtest.SetupDB(t) 102 ctx := context.Background() 103 104 p := p2ptest.NewTestP2P(t) 105 msg := testutil.NewBeaconBlock() 106 msg.Block.Slot = 100 107 msg.Block.ParentRoot = testutil.Random32Bytes(t) 108 require.NoError(t, db.SaveBlock(context.Background(), wrapper.WrappedPhase0SignedBeaconBlock(msg))) 109 110 c, err := lru.New(10) 111 require.NoError(t, err) 112 c2, err := lru.New(10) 113 require.NoError(t, err) 114 chainService := &mock.ChainService{Genesis: time.Now()} 115 r := &Service{ 116 cfg: &Config{ 117 DB: db, 118 P2P: p, 119 InitialSync: &mockSync.Sync{IsSyncing: false}, 120 Chain: chainService, 121 BlockNotifier: chainService.BlockNotifier(), 122 }, 123 seenBlockCache: c, 124 badBlockCache: c2, 125 } 126 127 buf := new(bytes.Buffer) 128 _, err = p.Encoding().EncodeGossip(buf, msg) 129 require.NoError(t, err) 130 131 topic := p2p.GossipTypeMapping[reflect.TypeOf(msg)] 132 m := &pubsub.Message{ 133 Message: &pubsubpb.Message{ 134 Data: buf.Bytes(), 135 Topic: &topic, 136 }, 137 } 138 result := r.validateBeaconBlockPubSub(ctx, "", m) == pubsub.ValidationAccept 139 assert.Equal(t, false, result) 140 } 141 142 func TestValidateBeaconBlockPubSub_CanRecoverStateSummary(t *testing.T) { 143 db := dbtest.SetupDB(t) 144 p := p2ptest.NewTestP2P(t) 145 ctx := context.Background() 146 beaconState, privKeys := testutil.DeterministicGenesisState(t, 100) 147 parentBlock := testutil.NewBeaconBlock() 148 require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(parentBlock))) 149 bRoot, err := parentBlock.Block.HashTreeRoot() 150 require.NoError(t, err) 151 require.NoError(t, db.SaveState(ctx, beaconState, bRoot)) 152 copied := beaconState.Copy() 153 require.NoError(t, copied.SetSlot(1)) 154 proposerIdx, err := helpers.BeaconProposerIndex(copied) 155 require.NoError(t, err) 156 msg := testutil.NewBeaconBlock() 157 msg.Block.ParentRoot = bRoot[:] 158 msg.Block.Slot = 1 159 msg.Block.ProposerIndex = proposerIdx 160 msg.Signature, err = helpers.ComputeDomainAndSign(beaconState, 0, msg.Block, params.BeaconConfig().DomainBeaconProposer, privKeys[proposerIdx]) 161 require.NoError(t, err) 162 163 c, err := lru.New(10) 164 require.NoError(t, err) 165 c2, err := lru.New(10) 166 require.NoError(t, err) 167 stateGen := stategen.New(db) 168 chainService := &mock.ChainService{Genesis: time.Unix(time.Now().Unix()-int64(params.BeaconConfig().SecondsPerSlot), 0), 169 State: beaconState, 170 FinalizedCheckPoint: ðpb.Checkpoint{ 171 Epoch: 0, 172 Root: make([]byte, 32), 173 }, 174 } 175 r := &Service{ 176 cfg: &Config{ 177 DB: db, 178 P2P: p, 179 InitialSync: &mockSync.Sync{IsSyncing: false}, 180 Chain: chainService, 181 BlockNotifier: chainService.BlockNotifier(), 182 StateGen: stateGen, 183 }, 184 seenBlockCache: c, 185 badBlockCache: c2, 186 slotToPendingBlocks: gcache.New(time.Second, 2*time.Second), 187 seenPendingBlocks: make(map[[32]byte]bool), 188 } 189 buf := new(bytes.Buffer) 190 _, err = p.Encoding().EncodeGossip(buf, msg) 191 require.NoError(t, err) 192 topic := p2p.GossipTypeMapping[reflect.TypeOf(msg)] 193 m := &pubsub.Message{ 194 Message: &pubsubpb.Message{ 195 Data: buf.Bytes(), 196 Topic: &topic, 197 }, 198 } 199 result := r.validateBeaconBlockPubSub(ctx, "", m) == pubsub.ValidationAccept 200 assert.Equal(t, true, result) 201 assert.NotNil(t, m.ValidatorData, "Decoded message was not set on the message validator data") 202 } 203 204 func TestValidateBeaconBlockPubSub_ValidProposerSignature(t *testing.T) { 205 db := dbtest.SetupDB(t) 206 p := p2ptest.NewTestP2P(t) 207 ctx := context.Background() 208 beaconState, privKeys := testutil.DeterministicGenesisState(t, 100) 209 parentBlock := testutil.NewBeaconBlock() 210 require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(parentBlock))) 211 bRoot, err := parentBlock.Block.HashTreeRoot() 212 require.NoError(t, err) 213 require.NoError(t, db.SaveState(ctx, beaconState, bRoot)) 214 require.NoError(t, db.SaveStateSummary(ctx, &pb.StateSummary{Root: bRoot[:]})) 215 copied := beaconState.Copy() 216 require.NoError(t, copied.SetSlot(1)) 217 proposerIdx, err := helpers.BeaconProposerIndex(copied) 218 require.NoError(t, err) 219 msg := testutil.NewBeaconBlock() 220 msg.Block.ParentRoot = bRoot[:] 221 msg.Block.Slot = 1 222 msg.Block.ProposerIndex = proposerIdx 223 msg.Signature, err = helpers.ComputeDomainAndSign(beaconState, 0, msg.Block, params.BeaconConfig().DomainBeaconProposer, privKeys[proposerIdx]) 224 require.NoError(t, err) 225 226 c, err := lru.New(10) 227 require.NoError(t, err) 228 c2, err := lru.New(10) 229 require.NoError(t, err) 230 stateGen := stategen.New(db) 231 chainService := &mock.ChainService{Genesis: time.Unix(time.Now().Unix()-int64(params.BeaconConfig().SecondsPerSlot), 0), 232 State: beaconState, 233 FinalizedCheckPoint: ðpb.Checkpoint{ 234 Epoch: 0, 235 Root: make([]byte, 32), 236 }, 237 } 238 r := &Service{ 239 cfg: &Config{ 240 DB: db, 241 P2P: p, 242 InitialSync: &mockSync.Sync{IsSyncing: false}, 243 Chain: chainService, 244 BlockNotifier: chainService.BlockNotifier(), 245 StateGen: stateGen, 246 }, 247 seenBlockCache: c, 248 badBlockCache: c2, 249 slotToPendingBlocks: gcache.New(time.Second, 2*time.Second), 250 seenPendingBlocks: make(map[[32]byte]bool), 251 } 252 buf := new(bytes.Buffer) 253 _, err = p.Encoding().EncodeGossip(buf, msg) 254 require.NoError(t, err) 255 topic := p2p.GossipTypeMapping[reflect.TypeOf(msg)] 256 m := &pubsub.Message{ 257 Message: &pubsubpb.Message{ 258 Data: buf.Bytes(), 259 Topic: &topic, 260 }, 261 } 262 result := r.validateBeaconBlockPubSub(ctx, "", m) == pubsub.ValidationAccept 263 assert.Equal(t, true, result) 264 assert.NotNil(t, m.ValidatorData, "Decoded message was not set on the message validator data") 265 } 266 267 func TestValidateBeaconBlockPubSub_WithLookahead(t *testing.T) { 268 db := dbtest.SetupDB(t) 269 p := p2ptest.NewTestP2P(t) 270 ctx := context.Background() 271 beaconState, privKeys := testutil.DeterministicGenesisState(t, 100) 272 parentBlock := testutil.NewBeaconBlock() 273 require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(parentBlock))) 274 bRoot, err := parentBlock.Block.HashTreeRoot() 275 require.NoError(t, err) 276 require.NoError(t, db.SaveState(ctx, beaconState, bRoot)) 277 require.NoError(t, db.SaveStateSummary(ctx, &pb.StateSummary{Root: bRoot[:]})) 278 copied := beaconState.Copy() 279 // The next block is only 1 epoch ahead so as to not induce a new seed. 280 blkSlot := params.BeaconConfig().SlotsPerEpoch.Mul(uint64(helpers.NextEpoch(copied))) 281 copied, err = state.ProcessSlots(context.Background(), copied, blkSlot) 282 require.NoError(t, err) 283 proposerIdx, err := helpers.BeaconProposerIndex(copied) 284 require.NoError(t, err) 285 msg := testutil.NewBeaconBlock() 286 msg.Block.ProposerIndex = proposerIdx 287 msg.Block.Slot = blkSlot 288 msg.Block.ParentRoot = bRoot[:] 289 msg.Signature, err = helpers.ComputeDomainAndSign(beaconState, 0, msg.Block, params.BeaconConfig().DomainBeaconProposer, privKeys[proposerIdx]) 290 require.NoError(t, err) 291 292 c, err := lru.New(10) 293 require.NoError(t, err) 294 c2, err := lru.New(10) 295 require.NoError(t, err) 296 stateGen := stategen.New(db) 297 offset := int64(blkSlot.Mul(params.BeaconConfig().SecondsPerSlot)) 298 chainService := &mock.ChainService{Genesis: time.Unix(time.Now().Unix()-offset, 0), 299 State: beaconState, 300 FinalizedCheckPoint: ðpb.Checkpoint{ 301 Epoch: 0, 302 }} 303 r := &Service{ 304 cfg: &Config{ 305 DB: db, 306 P2P: p, 307 InitialSync: &mockSync.Sync{IsSyncing: false}, 308 Chain: chainService, 309 BlockNotifier: chainService.BlockNotifier(), 310 StateGen: stateGen, 311 }, 312 seenBlockCache: c, 313 badBlockCache: c2, 314 slotToPendingBlocks: gcache.New(time.Second, 2*time.Second), 315 seenPendingBlocks: make(map[[32]byte]bool), 316 } 317 buf := new(bytes.Buffer) 318 _, err = p.Encoding().EncodeGossip(buf, msg) 319 require.NoError(t, err) 320 topic := p2p.GossipTypeMapping[reflect.TypeOf(msg)] 321 m := &pubsub.Message{ 322 Message: &pubsubpb.Message{ 323 Data: buf.Bytes(), 324 Topic: &topic, 325 }, 326 } 327 result := r.validateBeaconBlockPubSub(ctx, "", m) == pubsub.ValidationAccept 328 assert.Equal(t, true, result) 329 assert.NotNil(t, m.ValidatorData, "Decoded message was not set on the message validator data") 330 } 331 332 func TestValidateBeaconBlockPubSub_AdvanceEpochsForState(t *testing.T) { 333 db := dbtest.SetupDB(t) 334 p := p2ptest.NewTestP2P(t) 335 ctx := context.Background() 336 beaconState, privKeys := testutil.DeterministicGenesisState(t, 100) 337 parentBlock := testutil.NewBeaconBlock() 338 require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(parentBlock))) 339 bRoot, err := parentBlock.Block.HashTreeRoot() 340 require.NoError(t, err) 341 require.NoError(t, db.SaveState(ctx, beaconState, bRoot)) 342 require.NoError(t, db.SaveStateSummary(ctx, &pb.StateSummary{Root: bRoot[:]})) 343 copied := beaconState.Copy() 344 // The next block is at least 2 epochs ahead to induce shuffling and a new seed. 345 blkSlot := params.BeaconConfig().SlotsPerEpoch * 2 346 copied, err = state.ProcessSlots(context.Background(), copied, blkSlot) 347 require.NoError(t, err) 348 proposerIdx, err := helpers.BeaconProposerIndex(copied) 349 require.NoError(t, err) 350 msg := testutil.NewBeaconBlock() 351 msg.Block.ProposerIndex = proposerIdx 352 msg.Block.Slot = blkSlot 353 msg.Block.ParentRoot = bRoot[:] 354 msg.Signature, err = helpers.ComputeDomainAndSign(beaconState, 0, msg.Block, params.BeaconConfig().DomainBeaconProposer, privKeys[proposerIdx]) 355 require.NoError(t, err) 356 357 c, err := lru.New(10) 358 require.NoError(t, err) 359 c2, err := lru.New(10) 360 require.NoError(t, err) 361 stateGen := stategen.New(db) 362 offset := int64(blkSlot.Mul(params.BeaconConfig().SecondsPerSlot)) 363 chainService := &mock.ChainService{Genesis: time.Unix(time.Now().Unix()-offset, 0), 364 State: beaconState, 365 FinalizedCheckPoint: ðpb.Checkpoint{ 366 Epoch: 0, 367 }} 368 r := &Service{ 369 cfg: &Config{ 370 DB: db, 371 P2P: p, 372 InitialSync: &mockSync.Sync{IsSyncing: false}, 373 Chain: chainService, 374 BlockNotifier: chainService.BlockNotifier(), 375 StateGen: stateGen, 376 }, 377 seenBlockCache: c, 378 badBlockCache: c2, 379 slotToPendingBlocks: gcache.New(time.Second, 2*time.Second), 380 seenPendingBlocks: make(map[[32]byte]bool), 381 } 382 buf := new(bytes.Buffer) 383 _, err = p.Encoding().EncodeGossip(buf, msg) 384 require.NoError(t, err) 385 topic := p2p.GossipTypeMapping[reflect.TypeOf(msg)] 386 m := &pubsub.Message{ 387 Message: &pubsubpb.Message{ 388 Data: buf.Bytes(), 389 Topic: &topic, 390 }, 391 } 392 result := r.validateBeaconBlockPubSub(ctx, "", m) == pubsub.ValidationAccept 393 assert.Equal(t, true, result) 394 assert.NotNil(t, m.ValidatorData, "Decoded message was not set on the message validator data") 395 } 396 397 func TestValidateBeaconBlockPubSub_Syncing(t *testing.T) { 398 db := dbtest.SetupDB(t) 399 p := p2ptest.NewTestP2P(t) 400 ctx := context.Background() 401 b := []byte("sk") 402 b32 := bytesutil.ToBytes32(b) 403 sk, err := bls.SecretKeyFromBytes(b32[:]) 404 require.NoError(t, err) 405 msg := testutil.NewBeaconBlock() 406 msg.Block.ParentRoot = testutil.Random32Bytes(t) 407 msg.Signature = sk.Sign([]byte("data")).Marshal() 408 chainService := &mock.ChainService{ 409 Genesis: time.Now(), 410 FinalizedCheckPoint: ðpb.Checkpoint{ 411 Epoch: 0, 412 }} 413 r := &Service{ 414 cfg: &Config{ 415 DB: db, 416 P2P: p, 417 InitialSync: &mockSync.Sync{IsSyncing: true}, 418 Chain: chainService, 419 BlockNotifier: chainService.BlockNotifier(), 420 }, 421 } 422 423 buf := new(bytes.Buffer) 424 _, err = p.Encoding().EncodeGossip(buf, msg) 425 require.NoError(t, err) 426 topic := p2p.GossipTypeMapping[reflect.TypeOf(msg)] 427 m := &pubsub.Message{ 428 Message: &pubsubpb.Message{ 429 Data: buf.Bytes(), 430 Topic: &topic, 431 }, 432 } 433 result := r.validateBeaconBlockPubSub(ctx, "", m) == pubsub.ValidationAccept 434 assert.Equal(t, false, result) 435 } 436 437 func TestValidateBeaconBlockPubSub_AcceptBlocksFromNearFuture(t *testing.T) { 438 db := dbtest.SetupDB(t) 439 p := p2ptest.NewTestP2P(t) 440 ctx := context.Background() 441 442 beaconState, privKeys := testutil.DeterministicGenesisState(t, 100) 443 parentBlock := testutil.NewBeaconBlock() 444 require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(parentBlock))) 445 bRoot, err := parentBlock.Block.HashTreeRoot() 446 require.NoError(t, err) 447 require.NoError(t, db.SaveState(ctx, beaconState, bRoot)) 448 require.NoError(t, db.SaveStateSummary(ctx, &pb.StateSummary{Root: bRoot[:]})) 449 copied := beaconState.Copy() 450 require.NoError(t, copied.SetSlot(1)) 451 proposerIdx, err := helpers.BeaconProposerIndex(copied) 452 require.NoError(t, err) 453 454 msg := testutil.NewBeaconBlock() 455 msg.Block.Slot = 2 // two slots in future 456 msg.Block.ParentRoot = bRoot[:] 457 msg.Block.ProposerIndex = proposerIdx 458 msg.Signature, err = helpers.ComputeDomainAndSign(beaconState, 0, msg.Block, params.BeaconConfig().DomainBeaconProposer, privKeys[proposerIdx]) 459 require.NoError(t, err) 460 461 c, err := lru.New(10) 462 require.NoError(t, err) 463 c2, err := lru.New(10) 464 require.NoError(t, err) 465 stateGen := stategen.New(db) 466 chainService := &mock.ChainService{Genesis: time.Now(), 467 FinalizedCheckPoint: ðpb.Checkpoint{ 468 Epoch: 0, 469 Root: make([]byte, 32), 470 }} 471 r := &Service{ 472 cfg: &Config{ 473 P2P: p, 474 DB: db, 475 InitialSync: &mockSync.Sync{IsSyncing: false}, 476 Chain: chainService, 477 BlockNotifier: chainService.BlockNotifier(), 478 StateGen: stateGen, 479 }, 480 chainStarted: abool.New(), 481 seenBlockCache: c, 482 badBlockCache: c2, 483 slotToPendingBlocks: gcache.New(time.Second, 2*time.Second), 484 seenPendingBlocks: make(map[[32]byte]bool), 485 } 486 487 buf := new(bytes.Buffer) 488 _, err = p.Encoding().EncodeGossip(buf, msg) 489 require.NoError(t, err) 490 topic := p2p.GossipTypeMapping[reflect.TypeOf(msg)] 491 m := &pubsub.Message{ 492 Message: &pubsubpb.Message{ 493 Data: buf.Bytes(), 494 Topic: &topic, 495 }, 496 } 497 result := r.validateBeaconBlockPubSub(ctx, "", m) == pubsub.ValidationIgnore 498 assert.Equal(t, true, result) 499 500 // check if the block is inserted in the Queue 501 assert.Equal(t, true, len(r.pendingBlocksInCache(msg.Block.Slot)) == 1) 502 } 503 504 func TestValidateBeaconBlockPubSub_RejectBlocksFromFuture(t *testing.T) { 505 db := dbtest.SetupDB(t) 506 p := p2ptest.NewTestP2P(t) 507 ctx := context.Background() 508 b := []byte("sk") 509 b32 := bytesutil.ToBytes32(b) 510 sk, err := bls.SecretKeyFromBytes(b32[:]) 511 require.NoError(t, err) 512 msg := testutil.NewBeaconBlock() 513 msg.Block.Slot = 3 514 msg.Block.ParentRoot = testutil.Random32Bytes(t) 515 msg.Signature = sk.Sign([]byte("data")).Marshal() 516 517 c, err := lru.New(10) 518 require.NoError(t, err) 519 c2, err := lru.New(10) 520 require.NoError(t, err) 521 chainService := &mock.ChainService{Genesis: time.Now()} 522 r := &Service{ 523 cfg: &Config{ 524 P2P: p, 525 DB: db, 526 InitialSync: &mockSync.Sync{IsSyncing: false}, 527 Chain: chainService, 528 BlockNotifier: chainService.BlockNotifier(), 529 }, 530 chainStarted: abool.New(), 531 seenBlockCache: c, 532 badBlockCache: c2, 533 slotToPendingBlocks: gcache.New(time.Second, 2*time.Second), 534 seenPendingBlocks: make(map[[32]byte]bool), 535 } 536 537 buf := new(bytes.Buffer) 538 _, err = p.Encoding().EncodeGossip(buf, msg) 539 require.NoError(t, err) 540 topic := p2p.GossipTypeMapping[reflect.TypeOf(msg)] 541 m := &pubsub.Message{ 542 Message: &pubsubpb.Message{ 543 Data: buf.Bytes(), 544 Topic: &topic, 545 }, 546 } 547 result := r.validateBeaconBlockPubSub(ctx, "", m) == pubsub.ValidationAccept 548 assert.Equal(t, false, result) 549 } 550 551 func TestValidateBeaconBlockPubSub_RejectBlocksFromThePast(t *testing.T) { 552 db := dbtest.SetupDB(t) 553 b := []byte("sk") 554 b32 := bytesutil.ToBytes32(b) 555 p := p2ptest.NewTestP2P(t) 556 ctx := context.Background() 557 sk, err := bls.SecretKeyFromBytes(b32[:]) 558 require.NoError(t, err) 559 msg := testutil.NewBeaconBlock() 560 msg.Block.ParentRoot = testutil.Random32Bytes(t) 561 msg.Block.Slot = 10 562 msg.Signature = sk.Sign([]byte("data")).Marshal() 563 564 genesisTime := time.Now() 565 c, err := lru.New(10) 566 require.NoError(t, err) 567 c2, err := lru.New(10) 568 require.NoError(t, err) 569 chainService := &mock.ChainService{ 570 Genesis: time.Unix(genesisTime.Unix()-1000, 0), 571 FinalizedCheckPoint: ðpb.Checkpoint{ 572 Epoch: 1, 573 }, 574 } 575 r := &Service{ 576 cfg: &Config{ 577 DB: db, 578 P2P: p, 579 InitialSync: &mockSync.Sync{IsSyncing: false}, 580 Chain: chainService, 581 BlockNotifier: chainService.BlockNotifier(), 582 }, 583 seenBlockCache: c, 584 badBlockCache: c2, 585 } 586 587 buf := new(bytes.Buffer) 588 _, err = p.Encoding().EncodeGossip(buf, msg) 589 require.NoError(t, err) 590 topic := p2p.GossipTypeMapping[reflect.TypeOf(msg)] 591 m := &pubsub.Message{ 592 Message: &pubsubpb.Message{ 593 Data: buf.Bytes(), 594 Topic: &topic, 595 }, 596 } 597 result := r.validateBeaconBlockPubSub(ctx, "", m) == pubsub.ValidationAccept 598 assert.Equal(t, false, result) 599 } 600 601 func TestValidateBeaconBlockPubSub_SeenProposerSlot(t *testing.T) { 602 db := dbtest.SetupDB(t) 603 p := p2ptest.NewTestP2P(t) 604 ctx := context.Background() 605 beaconState, privKeys := testutil.DeterministicGenesisState(t, 100) 606 parentBlock := testutil.NewBeaconBlock() 607 require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(parentBlock))) 608 bRoot, err := parentBlock.Block.HashTreeRoot() 609 require.NoError(t, err) 610 require.NoError(t, db.SaveState(ctx, beaconState, bRoot)) 611 proposerIdx, err := helpers.BeaconProposerIndex(beaconState) 612 require.NoError(t, err) 613 614 msg := testutil.NewBeaconBlock() 615 msg.Block.Slot = 1 616 msg.Block.ProposerIndex = proposerIdx 617 msg.Block.ParentRoot = bRoot[:] 618 msg.Signature, err = helpers.ComputeDomainAndSign(beaconState, 0, msg.Block, params.BeaconConfig().DomainBeaconProposer, privKeys[proposerIdx]) 619 require.NoError(t, err) 620 621 c, err := lru.New(10) 622 require.NoError(t, err) 623 c2, err := lru.New(10) 624 require.NoError(t, err) 625 chainService := &mock.ChainService{Genesis: time.Unix(time.Now().Unix()-int64(params.BeaconConfig().SecondsPerSlot), 0), 626 State: beaconState, 627 FinalizedCheckPoint: ðpb.Checkpoint{ 628 Epoch: 0, 629 Root: make([]byte, 32), 630 }, 631 } 632 r := &Service{ 633 cfg: &Config{ 634 DB: db, 635 P2P: p, 636 InitialSync: &mockSync.Sync{IsSyncing: false}, 637 Chain: chainService, 638 BlockNotifier: chainService.BlockNotifier(), 639 }, 640 seenBlockCache: c, 641 badBlockCache: c2, 642 slotToPendingBlocks: gcache.New(time.Second, 2*time.Second), 643 seenPendingBlocks: make(map[[32]byte]bool), 644 } 645 646 buf := new(bytes.Buffer) 647 _, err = p.Encoding().EncodeGossip(buf, msg) 648 require.NoError(t, err) 649 topic := p2p.GossipTypeMapping[reflect.TypeOf(msg)] 650 m := &pubsub.Message{ 651 Message: &pubsubpb.Message{ 652 Data: buf.Bytes(), 653 Topic: &topic, 654 }, 655 } 656 r.setSeenBlockIndexSlot(msg.Block.Slot, msg.Block.ProposerIndex) 657 time.Sleep(10 * time.Millisecond) // Wait for cached value to pass through buffers. 658 result := r.validateBeaconBlockPubSub(ctx, "", m) == pubsub.ValidationAccept 659 assert.Equal(t, false, result) 660 } 661 662 func TestValidateBeaconBlockPubSub_FilterByFinalizedEpoch(t *testing.T) { 663 hook := logTest.NewGlobal() 664 db := dbtest.SetupDB(t) 665 p := p2ptest.NewTestP2P(t) 666 667 parent := testutil.NewBeaconBlock() 668 require.NoError(t, db.SaveBlock(context.Background(), wrapper.WrappedPhase0SignedBeaconBlock(parent))) 669 parentRoot, err := parent.Block.HashTreeRoot() 670 require.NoError(t, err) 671 chain := &mock.ChainService{Genesis: time.Unix(time.Now().Unix()-int64(params.BeaconConfig().SecondsPerSlot), 0), 672 FinalizedCheckPoint: ðpb.Checkpoint{ 673 Epoch: 1, 674 }} 675 c, err := lru.New(10) 676 require.NoError(t, err) 677 c2, err := lru.New(10) 678 require.NoError(t, err) 679 r := &Service{ 680 cfg: &Config{ 681 DB: db, 682 P2P: p, 683 Chain: chain, 684 BlockNotifier: chain.BlockNotifier(), 685 AttPool: attestations.NewPool(), 686 InitialSync: &mockSync.Sync{IsSyncing: false}, 687 }, 688 seenBlockCache: c, 689 badBlockCache: c2, 690 } 691 692 b := testutil.NewBeaconBlock() 693 b.Block.Slot = 1 694 b.Block.ParentRoot = parentRoot[:] 695 buf := new(bytes.Buffer) 696 _, err = p.Encoding().EncodeGossip(buf, b) 697 require.NoError(t, err) 698 topic := p2p.GossipTypeMapping[reflect.TypeOf(b)] 699 m := &pubsub.Message{ 700 Message: &pubsubpb.Message{ 701 Data: buf.Bytes(), 702 Topic: &topic, 703 }, 704 } 705 706 r.validateBeaconBlockPubSub(context.Background(), "", m) 707 708 hook.Reset() 709 b.Block.Slot = params.BeaconConfig().SlotsPerEpoch 710 buf = new(bytes.Buffer) 711 _, err = p.Encoding().EncodeGossip(buf, b) 712 require.NoError(t, err) 713 m = &pubsub.Message{ 714 Message: &pubsubpb.Message{ 715 Data: buf.Bytes(), 716 Topic: &topic, 717 }, 718 } 719 720 r.validateBeaconBlockPubSub(context.Background(), "", m) 721 } 722 723 func TestValidateBeaconBlockPubSub_ParentNotFinalizedDescendant(t *testing.T) { 724 hook := logTest.NewGlobal() 725 db := dbtest.SetupDB(t) 726 p := p2ptest.NewTestP2P(t) 727 ctx := context.Background() 728 beaconState, privKeys := testutil.DeterministicGenesisState(t, 100) 729 parentBlock := testutil.NewBeaconBlock() 730 require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(parentBlock))) 731 bRoot, err := parentBlock.Block.HashTreeRoot() 732 require.NoError(t, err) 733 require.NoError(t, db.SaveState(ctx, beaconState, bRoot)) 734 require.NoError(t, db.SaveStateSummary(ctx, &pb.StateSummary{Root: bRoot[:]})) 735 copied := beaconState.Copy() 736 require.NoError(t, copied.SetSlot(1)) 737 proposerIdx, err := helpers.BeaconProposerIndex(copied) 738 require.NoError(t, err) 739 msg := testutil.NewBeaconBlock() 740 msg.Block.Slot = 1 741 msg.Block.ProposerIndex = proposerIdx 742 msg.Block.ParentRoot = bRoot[:] 743 msg.Signature, err = helpers.ComputeDomainAndSign(beaconState, 0, msg.Block, params.BeaconConfig().DomainBeaconProposer, privKeys[proposerIdx]) 744 require.NoError(t, err) 745 746 c, err := lru.New(10) 747 require.NoError(t, err) 748 c2, err := lru.New(10) 749 require.NoError(t, err) 750 stateGen := stategen.New(db) 751 chainService := &mock.ChainService{Genesis: time.Unix(time.Now().Unix()-int64(params.BeaconConfig().SecondsPerSlot), 0), 752 State: beaconState, 753 FinalizedCheckPoint: ðpb.Checkpoint{ 754 Epoch: 0, 755 Root: make([]byte, 32), 756 }, 757 VerifyBlkDescendantErr: errors.New("not part of finalized chain"), 758 } 759 r := &Service{ 760 cfg: &Config{ 761 DB: db, 762 P2P: p, 763 InitialSync: &mockSync.Sync{IsSyncing: false}, 764 Chain: chainService, 765 BlockNotifier: chainService.BlockNotifier(), 766 StateGen: stateGen, 767 }, 768 seenBlockCache: c, 769 badBlockCache: c2, 770 slotToPendingBlocks: gcache.New(time.Second, 2*time.Second), 771 seenPendingBlocks: make(map[[32]byte]bool), 772 } 773 buf := new(bytes.Buffer) 774 _, err = p.Encoding().EncodeGossip(buf, msg) 775 require.NoError(t, err) 776 topic := p2p.GossipTypeMapping[reflect.TypeOf(msg)] 777 m := &pubsub.Message{ 778 Message: &pubsubpb.Message{ 779 Data: buf.Bytes(), 780 Topic: &topic, 781 }, 782 } 783 assert.Equal(t, pubsub.ValidationReject, r.validateBeaconBlockPubSub(ctx, "", m), "Wrong validation result returned") 784 require.LogsContain(t, hook, "not part of finalized chain") 785 } 786 787 func TestValidateBeaconBlockPubSub_InvalidParentBlock(t *testing.T) { 788 db := dbtest.SetupDB(t) 789 p := p2ptest.NewTestP2P(t) 790 ctx := context.Background() 791 beaconState, privKeys := testutil.DeterministicGenesisState(t, 100) 792 parentBlock := testutil.NewBeaconBlock() 793 require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(parentBlock))) 794 bRoot, err := parentBlock.Block.HashTreeRoot() 795 require.NoError(t, err) 796 require.NoError(t, db.SaveState(ctx, beaconState, bRoot)) 797 require.NoError(t, db.SaveStateSummary(ctx, &pb.StateSummary{Root: bRoot[:]})) 798 copied := beaconState.Copy() 799 require.NoError(t, copied.SetSlot(1)) 800 proposerIdx, err := helpers.BeaconProposerIndex(copied) 801 require.NoError(t, err) 802 msg := testutil.NewBeaconBlock() 803 msg.Block.ProposerIndex = proposerIdx 804 msg.Block.Slot = 1 805 msg.Block.ParentRoot = bRoot[:] 806 msg.Signature, err = helpers.ComputeDomainAndSign(beaconState, 0, msg.Block, params.BeaconConfig().DomainBeaconProposer, privKeys[proposerIdx]) 807 require.NoError(t, err) 808 809 // Mutate Signature 810 copy(msg.Signature[:4], []byte{1, 2, 3, 4}) 811 currBlockRoot, err := msg.Block.HashTreeRoot() 812 require.NoError(t, err) 813 814 c, err := lru.New(10) 815 require.NoError(t, err) 816 c2, err := lru.New(10) 817 require.NoError(t, err) 818 stateGen := stategen.New(db) 819 chainService := &mock.ChainService{Genesis: time.Unix(time.Now().Unix()-int64(params.BeaconConfig().SecondsPerSlot), 0), 820 State: beaconState, 821 FinalizedCheckPoint: ðpb.Checkpoint{ 822 Epoch: 0, 823 }} 824 r := &Service{ 825 cfg: &Config{ 826 DB: db, 827 P2P: p, 828 InitialSync: &mockSync.Sync{IsSyncing: false}, 829 Chain: chainService, 830 BlockNotifier: chainService.BlockNotifier(), 831 StateGen: stateGen, 832 }, 833 seenBlockCache: c, 834 badBlockCache: c2, 835 slotToPendingBlocks: gcache.New(time.Second, 2*time.Second), 836 seenPendingBlocks: make(map[[32]byte]bool), 837 } 838 buf := new(bytes.Buffer) 839 _, err = p.Encoding().EncodeGossip(buf, msg) 840 require.NoError(t, err) 841 topic := p2p.GossipTypeMapping[reflect.TypeOf(msg)] 842 m := &pubsub.Message{ 843 Message: &pubsubpb.Message{ 844 Data: buf.Bytes(), 845 Topic: &topic, 846 }, 847 } 848 result := r.validateBeaconBlockPubSub(ctx, "", m) == pubsub.ValidationAccept 849 assert.Equal(t, false, result) 850 851 require.NoError(t, copied.SetSlot(2)) 852 proposerIdx, err = helpers.BeaconProposerIndex(copied) 853 require.NoError(t, err) 854 855 msg = testutil.NewBeaconBlock() 856 msg.Block.Slot = 2 857 msg.Block.ProposerIndex = proposerIdx 858 msg.Block.ParentRoot = currBlockRoot[:] 859 860 buf = new(bytes.Buffer) 861 _, err = p.Encoding().EncodeGossip(buf, msg) 862 require.NoError(t, err) 863 m = &pubsub.Message{ 864 Message: &pubsubpb.Message{ 865 Data: buf.Bytes(), 866 Topic: &topic, 867 }, 868 } 869 870 // Expect block with bad parent to fail too 871 result = r.validateBeaconBlockPubSub(ctx, "", m) == pubsub.ValidationAccept 872 assert.Equal(t, false, result) 873 } 874 875 func TestValidateBeaconBlockPubSub_RejectEvilBlocksFromFuture(t *testing.T) { 876 db := dbtest.SetupDB(t) 877 p := p2ptest.NewTestP2P(t) 878 ctx := context.Background() 879 880 beaconState, privKeys := testutil.DeterministicGenesisState(t, 100) 881 parentBlock := testutil.NewBeaconBlock() 882 require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(parentBlock))) 883 bRoot, err := parentBlock.Block.HashTreeRoot() 884 require.NoError(t, err) 885 require.NoError(t, db.SaveState(ctx, beaconState, bRoot)) 886 require.NoError(t, db.SaveStateSummary(ctx, &pb.StateSummary{Root: bRoot[:]})) 887 888 copied := beaconState.Copy() 889 // The next block is at least 2 epochs ahead to induce shuffling and a new seed. 890 blkSlot := params.BeaconConfig().SlotsPerEpoch * 2 891 copied, err = state.ProcessSlots(context.Background(), copied, blkSlot) 892 require.NoError(t, err) 893 proposerIdx, err := helpers.BeaconProposerIndex(copied) 894 require.NoError(t, err) 895 896 msg := testutil.NewBeaconBlock() 897 msg.Block.ProposerIndex = proposerIdx 898 msg.Block.Slot = blkSlot 899 900 perSlot := params.BeaconConfig().SecondsPerSlot 901 // current slot time 902 slotsSinceGenesis := types.Slot(1000) 903 // max uint, divided by slot time. But avoid losing precision too much. 904 overflowBase := (1 << 63) / (perSlot >> 1) 905 msg.Block.Slot = slotsSinceGenesis.Add(overflowBase) 906 907 // valid block 908 msg.Block.ParentRoot = bRoot[:] 909 msg.Signature, err = helpers.ComputeDomainAndSign(beaconState, 0, msg.Block, params.BeaconConfig().DomainBeaconProposer, privKeys[proposerIdx]) 910 require.NoError(t, err) 911 912 genesisTime := time.Now() 913 c, err := lru.New(10) 914 require.NoError(t, err) 915 c2, err := lru.New(10) 916 require.NoError(t, err) 917 918 stateGen := stategen.New(db) 919 chainService := &mock.ChainService{ 920 Genesis: time.Unix(genesisTime.Unix()-int64(slotsSinceGenesis.Mul(perSlot)), 0), 921 FinalizedCheckPoint: ðpb.Checkpoint{ 922 Epoch: 0, 923 }, 924 } 925 r := &Service{ 926 cfg: &Config{ 927 DB: db, 928 P2P: p, 929 InitialSync: &mockSync.Sync{IsSyncing: false}, 930 Chain: chainService, 931 BlockNotifier: chainService.BlockNotifier(), 932 StateGen: stateGen, 933 }, 934 seenBlockCache: c, 935 badBlockCache: c2, 936 slotToPendingBlocks: gcache.New(time.Second, 2*time.Second), 937 seenPendingBlocks: make(map[[32]byte]bool), 938 } 939 940 buf := new(bytes.Buffer) 941 _, err = p.Encoding().EncodeGossip(buf, msg) 942 require.NoError(t, err) 943 topic := p2p.GossipTypeMapping[reflect.TypeOf(msg)] 944 m := &pubsub.Message{ 945 Message: &pubsubpb.Message{ 946 Data: buf.Bytes(), 947 Topic: &topic, 948 }, 949 } 950 result := r.validateBeaconBlockPubSub(ctx, "", m) == pubsub.ValidationAccept 951 assert.Equal(t, false, result) 952 } 953 954 func TestService_setBadBlock_DoesntSetWithContextErr(t *testing.T) { 955 s := Service{} 956 require.NoError(t, s.initCaches()) 957 958 root := [32]byte{'b', 'a', 'd'} 959 ctx, cancel := context.WithCancel(context.Background()) 960 cancel() 961 s.setBadBlock(ctx, root) 962 if s.hasBadBlock(root) { 963 t.Error("Set bad root with cancelled context") 964 } 965 } 966 967 func TestService_isBlockQueueable(t *testing.T) { 968 currentTime := time.Now().Round(time.Second) 969 genesisTime := uint64(currentTime.Unix() - int64(params.BeaconConfig().SecondsPerSlot)) 970 blockSlot := types.Slot(1) 971 972 // slot time within MAXIMUM_GOSSIP_CLOCK_DISPARITY, so dont queue the block. 973 receivedTime := currentTime.Add(-400 * time.Millisecond) 974 result := isBlockQueueable(genesisTime, blockSlot, receivedTime) 975 assert.Equal(t, false, result) 976 977 // slot time just above MAXIMUM_GOSSIP_CLOCK_DISPARITY, so queue the block. 978 receivedTime = currentTime.Add(-600 * time.Millisecond) 979 result = isBlockQueueable(genesisTime, blockSlot, receivedTime) 980 assert.Equal(t, true, result) 981 }