github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/rpc/prysm/v1alpha1/validator/attester_test.go (about) 1 package validator 2 3 import ( 4 "context" 5 "math/rand" 6 "sync" 7 "testing" 8 "time" 9 10 types "github.com/prysmaticlabs/eth2-types" 11 mock "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/testing" 12 "github.com/prysmaticlabs/prysm/beacon-chain/cache" 13 "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" 14 dbutil "github.com/prysmaticlabs/prysm/beacon-chain/db/testing" 15 "github.com/prysmaticlabs/prysm/beacon-chain/operations/attestations" 16 mockp2p "github.com/prysmaticlabs/prysm/beacon-chain/p2p/testing" 17 "github.com/prysmaticlabs/prysm/beacon-chain/state/stategen" 18 v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1" 19 mockSync "github.com/prysmaticlabs/prysm/beacon-chain/sync/initial-sync/testing" 20 pbp2p "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" 21 ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1" 22 "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1/wrapper" 23 "github.com/prysmaticlabs/prysm/shared/bls" 24 "github.com/prysmaticlabs/prysm/shared/bytesutil" 25 "github.com/prysmaticlabs/prysm/shared/params" 26 "github.com/prysmaticlabs/prysm/shared/testutil" 27 "github.com/prysmaticlabs/prysm/shared/testutil/assert" 28 "github.com/prysmaticlabs/prysm/shared/testutil/require" 29 "github.com/prysmaticlabs/prysm/shared/timeutils" 30 "google.golang.org/protobuf/proto" 31 ) 32 33 func TestProposeAttestation_OK(t *testing.T) { 34 db := dbutil.SetupDB(t) 35 ctx := context.Background() 36 37 attesterServer := &Server{ 38 HeadFetcher: &mock.ChainService{}, 39 P2P: &mockp2p.MockBroadcaster{}, 40 BeaconDB: db, 41 AttestationCache: cache.NewAttestationCache(), 42 AttPool: attestations.NewPool(), 43 OperationNotifier: (&mock.ChainService{}).OperationNotifier(), 44 } 45 head := testutil.NewBeaconBlock() 46 head.Block.Slot = 999 47 head.Block.ParentRoot = bytesutil.PadTo([]byte{'a'}, 32) 48 require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(head))) 49 root, err := head.Block.HashTreeRoot() 50 require.NoError(t, err) 51 52 validators := make([]*ethpb.Validator, 64) 53 for i := 0; i < len(validators); i++ { 54 validators[i] = ðpb.Validator{ 55 PublicKey: make([]byte, 48), 56 WithdrawalCredentials: make([]byte, 32), 57 ExitEpoch: params.BeaconConfig().FarFutureEpoch, 58 EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance, 59 } 60 } 61 62 state, err := testutil.NewBeaconState() 63 require.NoError(t, err) 64 require.NoError(t, state.SetSlot(params.BeaconConfig().SlotsPerEpoch+1)) 65 require.NoError(t, state.SetValidators(validators)) 66 require.NoError(t, db.SaveState(ctx, state, root)) 67 require.NoError(t, db.SaveHeadBlockRoot(ctx, root)) 68 69 sk, err := bls.RandKey() 70 require.NoError(t, err) 71 sig := sk.Sign([]byte("dummy_test_data")) 72 req := ðpb.Attestation{ 73 Signature: sig.Marshal(), 74 Data: ðpb.AttestationData{ 75 BeaconBlockRoot: root[:], 76 Source: ðpb.Checkpoint{Root: make([]byte, 32)}, 77 Target: ðpb.Checkpoint{Root: make([]byte, 32)}, 78 }, 79 } 80 _, err = attesterServer.ProposeAttestation(context.Background(), req) 81 assert.NoError(t, err) 82 } 83 84 func TestProposeAttestation_IncorrectSignature(t *testing.T) { 85 db := dbutil.SetupDB(t) 86 87 attesterServer := &Server{ 88 HeadFetcher: &mock.ChainService{}, 89 P2P: &mockp2p.MockBroadcaster{}, 90 BeaconDB: db, 91 AttestationCache: cache.NewAttestationCache(), 92 AttPool: attestations.NewPool(), 93 OperationNotifier: (&mock.ChainService{}).OperationNotifier(), 94 } 95 96 req := testutil.HydrateAttestation(ðpb.Attestation{}) 97 wanted := "Incorrect attestation signature" 98 _, err := attesterServer.ProposeAttestation(context.Background(), req) 99 assert.ErrorContains(t, wanted, err) 100 } 101 102 func TestGetAttestationData_OK(t *testing.T) { 103 ctx := context.Background() 104 db := dbutil.SetupDB(t) 105 106 block := testutil.NewBeaconBlock() 107 block.Block.Slot = 3*params.BeaconConfig().SlotsPerEpoch + 1 108 targetBlock := testutil.NewBeaconBlock() 109 targetBlock.Block.Slot = 1 * params.BeaconConfig().SlotsPerEpoch 110 justifiedBlock := testutil.NewBeaconBlock() 111 justifiedBlock.Block.Slot = 2 * params.BeaconConfig().SlotsPerEpoch 112 blockRoot, err := block.Block.HashTreeRoot() 113 require.NoError(t, err, "Could not hash beacon block") 114 justifiedRoot, err := justifiedBlock.Block.HashTreeRoot() 115 require.NoError(t, err, "Could not get signing root for justified block") 116 targetRoot, err := targetBlock.Block.HashTreeRoot() 117 require.NoError(t, err, "Could not get signing root for target block") 118 slot := 3*params.BeaconConfig().SlotsPerEpoch + 1 119 beaconState, err := testutil.NewBeaconState() 120 require.NoError(t, err) 121 require.NoError(t, beaconState.SetSlot(slot)) 122 err = beaconState.SetCurrentJustifiedCheckpoint(ðpb.Checkpoint{ 123 Epoch: 2, 124 Root: justifiedRoot[:], 125 }) 126 require.NoError(t, err) 127 128 blockRoots := beaconState.BlockRoots() 129 blockRoots[1] = blockRoot[:] 130 blockRoots[1*params.BeaconConfig().SlotsPerEpoch] = targetRoot[:] 131 blockRoots[2*params.BeaconConfig().SlotsPerEpoch] = justifiedRoot[:] 132 require.NoError(t, beaconState.SetBlockRoots(blockRoots)) 133 chainService := &mock.ChainService{ 134 Genesis: time.Now(), 135 } 136 offset := int64(slot.Mul(params.BeaconConfig().SecondsPerSlot)) 137 attesterServer := &Server{ 138 BeaconDB: db, 139 P2P: &mockp2p.MockBroadcaster{}, 140 SyncChecker: &mockSync.Sync{IsSyncing: false}, 141 AttestationCache: cache.NewAttestationCache(), 142 HeadFetcher: &mock.ChainService{ 143 State: beaconState, Root: blockRoot[:], 144 }, 145 FinalizationFetcher: &mock.ChainService{ 146 CurrentJustifiedCheckPoint: beaconState.CurrentJustifiedCheckpoint(), 147 }, 148 TimeFetcher: &mock.ChainService{ 149 Genesis: time.Now().Add(time.Duration(-1*offset) * time.Second), 150 }, 151 StateNotifier: chainService.StateNotifier(), 152 } 153 require.NoError(t, db.SaveState(ctx, beaconState, blockRoot)) 154 require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(block))) 155 require.NoError(t, db.SaveHeadBlockRoot(ctx, blockRoot)) 156 157 req := ðpb.AttestationDataRequest{ 158 CommitteeIndex: 0, 159 Slot: 3*params.BeaconConfig().SlotsPerEpoch + 1, 160 } 161 res, err := attesterServer.GetAttestationData(context.Background(), req) 162 require.NoError(t, err, "Could not get attestation info at slot") 163 164 expectedInfo := ðpb.AttestationData{ 165 Slot: 3*params.BeaconConfig().SlotsPerEpoch + 1, 166 BeaconBlockRoot: blockRoot[:], 167 Source: ðpb.Checkpoint{ 168 Epoch: 2, 169 Root: justifiedRoot[:], 170 }, 171 Target: ðpb.Checkpoint{ 172 Epoch: 3, 173 Root: blockRoot[:], 174 }, 175 } 176 177 if !proto.Equal(res, expectedInfo) { 178 t.Errorf("Expected attestation info to match, received %v, wanted %v", res, expectedInfo) 179 } 180 } 181 182 func TestGetAttestationData_SyncNotReady(t *testing.T) { 183 as := &Server{ 184 SyncChecker: &mockSync.Sync{IsSyncing: true}, 185 } 186 _, err := as.GetAttestationData(context.Background(), ðpb.AttestationDataRequest{}) 187 assert.ErrorContains(t, "Syncing to latest head", err) 188 } 189 190 func TestAttestationDataAtSlot_HandlesFarAwayJustifiedEpoch(t *testing.T) { 191 // Scenario: 192 // 193 // State slot = 10000 194 // Last justified slot = epoch start of 1500 195 // HistoricalRootsLimit = 8192 196 // 197 // More background: https://github.com/prysmaticlabs/prysm/issues/2153 198 // This test breaks if it doesnt use mainnet config 199 db := dbutil.SetupDB(t) 200 ctx := context.Background() 201 // Ensure HistoricalRootsLimit matches scenario 202 params.SetupTestConfigCleanup(t) 203 cfg := params.MainnetConfig() 204 cfg.HistoricalRootsLimit = 8192 205 params.OverrideBeaconConfig(cfg) 206 207 block := testutil.NewBeaconBlock() 208 block.Block.Slot = 10000 209 epochBoundaryBlock := testutil.NewBeaconBlock() 210 var err error 211 epochBoundaryBlock.Block.Slot, err = helpers.StartSlot(helpers.SlotToEpoch(10000)) 212 require.NoError(t, err) 213 justifiedBlock := testutil.NewBeaconBlock() 214 justifiedBlock.Block.Slot, err = helpers.StartSlot(helpers.SlotToEpoch(1500)) 215 require.NoError(t, err) 216 justifiedBlock.Block.Slot -= 2 // Imagine two skip block 217 blockRoot, err := block.Block.HashTreeRoot() 218 require.NoError(t, err, "Could not hash beacon block") 219 justifiedBlockRoot, err := justifiedBlock.Block.HashTreeRoot() 220 require.NoError(t, err, "Could not hash justified block") 221 epochBoundaryRoot, err := epochBoundaryBlock.Block.HashTreeRoot() 222 require.NoError(t, err, "Could not hash justified block") 223 slot := types.Slot(10000) 224 225 beaconState, err := testutil.NewBeaconState() 226 require.NoError(t, err) 227 require.NoError(t, beaconState.SetSlot(slot)) 228 err = beaconState.SetCurrentJustifiedCheckpoint(ðpb.Checkpoint{ 229 Epoch: helpers.SlotToEpoch(1500), 230 Root: justifiedBlockRoot[:], 231 }) 232 require.NoError(t, err) 233 blockRoots := beaconState.BlockRoots() 234 blockRoots[1] = blockRoot[:] 235 blockRoots[1*params.BeaconConfig().SlotsPerEpoch] = epochBoundaryRoot[:] 236 blockRoots[2*params.BeaconConfig().SlotsPerEpoch] = justifiedBlockRoot[:] 237 require.NoError(t, beaconState.SetBlockRoots(blockRoots)) 238 chainService := &mock.ChainService{ 239 Genesis: time.Now(), 240 } 241 offset := int64(slot.Mul(params.BeaconConfig().SecondsPerSlot)) 242 attesterServer := &Server{ 243 BeaconDB: db, 244 P2P: &mockp2p.MockBroadcaster{}, 245 AttestationCache: cache.NewAttestationCache(), 246 HeadFetcher: &mock.ChainService{State: beaconState, Root: blockRoot[:]}, 247 FinalizationFetcher: &mock.ChainService{ 248 CurrentJustifiedCheckPoint: beaconState.CurrentJustifiedCheckpoint(), 249 }, 250 SyncChecker: &mockSync.Sync{IsSyncing: false}, 251 TimeFetcher: &mock.ChainService{Genesis: time.Now().Add(time.Duration(-1*offset) * time.Second)}, 252 StateNotifier: chainService.StateNotifier(), 253 } 254 require.NoError(t, db.SaveState(ctx, beaconState, blockRoot)) 255 require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(block))) 256 require.NoError(t, db.SaveHeadBlockRoot(ctx, blockRoot)) 257 258 req := ðpb.AttestationDataRequest{ 259 CommitteeIndex: 0, 260 Slot: 10000, 261 } 262 res, err := attesterServer.GetAttestationData(context.Background(), req) 263 require.NoError(t, err, "Could not get attestation info at slot") 264 265 expectedInfo := ðpb.AttestationData{ 266 Slot: req.Slot, 267 BeaconBlockRoot: blockRoot[:], 268 Source: ðpb.Checkpoint{ 269 Epoch: helpers.SlotToEpoch(1500), 270 Root: justifiedBlockRoot[:], 271 }, 272 Target: ðpb.Checkpoint{ 273 Epoch: 312, 274 Root: blockRoot[:], 275 }, 276 } 277 278 if !proto.Equal(res, expectedInfo) { 279 t.Errorf("Expected attestation info to match, received %v, wanted %v", res, expectedInfo) 280 } 281 } 282 283 func TestAttestationDataSlot_handlesInProgressRequest(t *testing.T) { 284 s := &pbp2p.BeaconState{Slot: 100} 285 state, err := v1.InitializeFromProto(s) 286 require.NoError(t, err) 287 ctx := context.Background() 288 chainService := &mock.ChainService{ 289 Genesis: time.Now(), 290 } 291 slot := types.Slot(2) 292 offset := int64(slot.Mul(params.BeaconConfig().SecondsPerSlot)) 293 server := &Server{ 294 HeadFetcher: &mock.ChainService{State: state}, 295 AttestationCache: cache.NewAttestationCache(), 296 SyncChecker: &mockSync.Sync{IsSyncing: false}, 297 TimeFetcher: &mock.ChainService{Genesis: time.Now().Add(time.Duration(-1*offset) * time.Second)}, 298 StateNotifier: chainService.StateNotifier(), 299 } 300 301 req := ðpb.AttestationDataRequest{ 302 CommitteeIndex: 1, 303 Slot: slot, 304 } 305 306 res := ðpb.AttestationData{ 307 CommitteeIndex: 1, 308 Target: ðpb.Checkpoint{Epoch: 55, Root: make([]byte, 32)}, 309 } 310 311 require.NoError(t, server.AttestationCache.MarkInProgress(req)) 312 313 var wg sync.WaitGroup 314 315 wg.Add(1) 316 go func() { 317 defer wg.Done() 318 response, err := server.GetAttestationData(ctx, req) 319 require.NoError(t, err) 320 if !proto.Equal(res, response) { 321 t.Error("Expected equal responses from cache") 322 } 323 }() 324 325 wg.Add(1) 326 go func() { 327 defer wg.Done() 328 329 assert.NoError(t, server.AttestationCache.Put(ctx, req, res)) 330 assert.NoError(t, server.AttestationCache.MarkNotInProgress(req)) 331 }() 332 333 wg.Wait() 334 } 335 336 func TestServer_GetAttestationData_InvalidRequestSlot(t *testing.T) { 337 ctx := context.Background() 338 339 slot := 3*params.BeaconConfig().SlotsPerEpoch + 1 340 offset := int64(slot.Mul(params.BeaconConfig().SecondsPerSlot)) 341 attesterServer := &Server{ 342 SyncChecker: &mockSync.Sync{IsSyncing: false}, 343 TimeFetcher: &mock.ChainService{Genesis: time.Now().Add(time.Duration(-1*offset) * time.Second)}, 344 } 345 346 req := ðpb.AttestationDataRequest{ 347 Slot: 1000000000000, 348 } 349 _, err := attesterServer.GetAttestationData(ctx, req) 350 assert.ErrorContains(t, "invalid request", err) 351 } 352 353 func TestServer_GetAttestationData_HeadStateSlotGreaterThanRequestSlot(t *testing.T) { 354 // There exists a rare scenario where the validator may request an attestation for a slot less 355 // than the head state's slot. The Ethereum consensus spec constraints require the block root the 356 // attestation is referencing be less than or equal to the attestation data slot. 357 // See: https://github.com/prysmaticlabs/prysm/issues/5164 358 ctx := context.Background() 359 db := dbutil.SetupDB(t) 360 361 slot := 3*params.BeaconConfig().SlotsPerEpoch + 1 362 block := testutil.NewBeaconBlock() 363 block.Block.Slot = slot 364 block2 := testutil.NewBeaconBlock() 365 block2.Block.Slot = slot - 1 366 targetBlock := testutil.NewBeaconBlock() 367 targetBlock.Block.Slot = 1 * params.BeaconConfig().SlotsPerEpoch 368 justifiedBlock := testutil.NewBeaconBlock() 369 justifiedBlock.Block.Slot = 2 * params.BeaconConfig().SlotsPerEpoch 370 blockRoot, err := block.Block.HashTreeRoot() 371 require.NoError(t, err, "Could not hash beacon block") 372 blockRoot2, err := block2.HashTreeRoot() 373 require.NoError(t, err) 374 require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(block2))) 375 justifiedRoot, err := justifiedBlock.Block.HashTreeRoot() 376 require.NoError(t, err, "Could not get signing root for justified block") 377 targetRoot, err := targetBlock.Block.HashTreeRoot() 378 require.NoError(t, err, "Could not get signing root for target block") 379 380 beaconState, err := testutil.NewBeaconState() 381 require.NoError(t, err) 382 require.NoError(t, beaconState.SetSlot(slot)) 383 offset := int64(slot.Mul(params.BeaconConfig().SecondsPerSlot)) 384 require.NoError(t, beaconState.SetGenesisTime(uint64(time.Now().Unix()-offset))) 385 err = beaconState.SetLatestBlockHeader(testutil.HydrateBeaconHeader(ðpb.BeaconBlockHeader{ 386 ParentRoot: blockRoot2[:], 387 })) 388 require.NoError(t, err) 389 err = beaconState.SetCurrentJustifiedCheckpoint(ðpb.Checkpoint{ 390 Epoch: 2, 391 Root: justifiedRoot[:], 392 }) 393 require.NoError(t, err) 394 blockRoots := beaconState.BlockRoots() 395 blockRoots[1] = blockRoot[:] 396 blockRoots[1*params.BeaconConfig().SlotsPerEpoch] = targetRoot[:] 397 blockRoots[2*params.BeaconConfig().SlotsPerEpoch] = justifiedRoot[:] 398 blockRoots[3*params.BeaconConfig().SlotsPerEpoch] = blockRoot2[:] 399 require.NoError(t, beaconState.SetBlockRoots(blockRoots)) 400 401 beaconState2 := beaconState.Copy() 402 require.NoError(t, beaconState2.SetSlot(beaconState2.Slot()-1)) 403 require.NoError(t, db.SaveState(ctx, beaconState2, blockRoot2)) 404 chainService := &mock.ChainService{ 405 Genesis: time.Now(), 406 } 407 offset = int64(slot.Mul(params.BeaconConfig().SecondsPerSlot)) 408 attesterServer := &Server{ 409 BeaconDB: db, 410 P2P: &mockp2p.MockBroadcaster{}, 411 SyncChecker: &mockSync.Sync{IsSyncing: false}, 412 AttestationCache: cache.NewAttestationCache(), 413 HeadFetcher: &mock.ChainService{State: beaconState, Root: blockRoot[:]}, 414 FinalizationFetcher: &mock.ChainService{CurrentJustifiedCheckPoint: beaconState.CurrentJustifiedCheckpoint()}, 415 TimeFetcher: &mock.ChainService{Genesis: time.Now().Add(time.Duration(-1*offset) * time.Second)}, 416 StateNotifier: chainService.StateNotifier(), 417 StateGen: stategen.New(db), 418 } 419 require.NoError(t, db.SaveState(ctx, beaconState, blockRoot)) 420 require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(block))) 421 require.NoError(t, db.SaveHeadBlockRoot(ctx, blockRoot)) 422 423 req := ðpb.AttestationDataRequest{ 424 CommitteeIndex: 0, 425 Slot: slot - 1, 426 } 427 res, err := attesterServer.GetAttestationData(ctx, req) 428 require.NoError(t, err, "Could not get attestation info at slot") 429 430 expectedInfo := ðpb.AttestationData{ 431 Slot: slot - 1, 432 BeaconBlockRoot: blockRoot2[:], 433 Source: ðpb.Checkpoint{ 434 Epoch: 2, 435 Root: justifiedRoot[:], 436 }, 437 Target: ðpb.Checkpoint{ 438 Epoch: 3, 439 Root: blockRoot2[:], 440 }, 441 } 442 443 if !proto.Equal(res, expectedInfo) { 444 t.Errorf("Expected attestation info to match, received %v, wanted %v", res, expectedInfo) 445 } 446 } 447 448 func TestGetAttestationData_SucceedsInFirstEpoch(t *testing.T) { 449 ctx := context.Background() 450 db := dbutil.SetupDB(t) 451 452 slot := types.Slot(5) 453 block := testutil.NewBeaconBlock() 454 block.Block.Slot = slot 455 targetBlock := testutil.NewBeaconBlock() 456 targetBlock.Block.Slot = 0 457 justifiedBlock := testutil.NewBeaconBlock() 458 justifiedBlock.Block.Slot = 0 459 blockRoot, err := block.Block.HashTreeRoot() 460 require.NoError(t, err, "Could not hash beacon block") 461 justifiedRoot, err := justifiedBlock.Block.HashTreeRoot() 462 require.NoError(t, err, "Could not get signing root for justified block") 463 targetRoot, err := targetBlock.Block.HashTreeRoot() 464 require.NoError(t, err, "Could not get signing root for target block") 465 466 beaconState, err := testutil.NewBeaconState() 467 require.NoError(t, err) 468 require.NoError(t, beaconState.SetSlot(slot)) 469 err = beaconState.SetCurrentJustifiedCheckpoint(ðpb.Checkpoint{ 470 Epoch: 0, 471 Root: justifiedRoot[:], 472 }) 473 require.NoError(t, err) 474 blockRoots := beaconState.BlockRoots() 475 blockRoots[1] = blockRoot[:] 476 blockRoots[1*params.BeaconConfig().SlotsPerEpoch] = targetRoot[:] 477 blockRoots[2*params.BeaconConfig().SlotsPerEpoch] = justifiedRoot[:] 478 require.NoError(t, beaconState.SetBlockRoots(blockRoots)) 479 chainService := &mock.ChainService{ 480 Genesis: time.Now(), 481 } 482 offset := int64(slot.Mul(params.BeaconConfig().SecondsPerSlot)) 483 attesterServer := &Server{ 484 BeaconDB: db, 485 P2P: &mockp2p.MockBroadcaster{}, 486 SyncChecker: &mockSync.Sync{IsSyncing: false}, 487 AttestationCache: cache.NewAttestationCache(), 488 HeadFetcher: &mock.ChainService{ 489 State: beaconState, Root: blockRoot[:], 490 }, 491 FinalizationFetcher: &mock.ChainService{ 492 CurrentJustifiedCheckPoint: beaconState.CurrentJustifiedCheckpoint(), 493 }, 494 TimeFetcher: &mock.ChainService{Genesis: timeutils.Now().Add(time.Duration(-1*offset) * time.Second)}, 495 StateNotifier: chainService.StateNotifier(), 496 } 497 require.NoError(t, db.SaveState(ctx, beaconState, blockRoot)) 498 require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(block))) 499 require.NoError(t, db.SaveHeadBlockRoot(ctx, blockRoot)) 500 501 req := ðpb.AttestationDataRequest{ 502 CommitteeIndex: 0, 503 Slot: 5, 504 } 505 res, err := attesterServer.GetAttestationData(context.Background(), req) 506 require.NoError(t, err, "Could not get attestation info at slot") 507 508 expectedInfo := ðpb.AttestationData{ 509 Slot: slot, 510 BeaconBlockRoot: blockRoot[:], 511 Source: ðpb.Checkpoint{ 512 Epoch: 0, 513 Root: justifiedRoot[:], 514 }, 515 Target: ðpb.Checkpoint{ 516 Epoch: 0, 517 Root: blockRoot[:], 518 }, 519 } 520 521 if !proto.Equal(res, expectedInfo) { 522 t.Errorf("Expected attestation info to match, received %v, wanted %v", res, expectedInfo) 523 } 524 } 525 526 func TestServer_SubscribeCommitteeSubnets_NoSlots(t *testing.T) { 527 db := dbutil.SetupDB(t) 528 529 attesterServer := &Server{ 530 HeadFetcher: &mock.ChainService{}, 531 P2P: &mockp2p.MockBroadcaster{}, 532 BeaconDB: db, 533 AttestationCache: cache.NewAttestationCache(), 534 AttPool: attestations.NewPool(), 535 OperationNotifier: (&mock.ChainService{}).OperationNotifier(), 536 } 537 538 _, err := attesterServer.SubscribeCommitteeSubnets(context.Background(), ðpb.CommitteeSubnetsSubscribeRequest{ 539 Slots: nil, 540 CommitteeIds: nil, 541 IsAggregator: nil, 542 }) 543 assert.ErrorContains(t, "no attester slots provided", err) 544 } 545 546 func TestServer_SubscribeCommitteeSubnets_DifferentLengthSlots(t *testing.T) { 547 db := dbutil.SetupDB(t) 548 549 // fixed seed 550 s := rand.NewSource(10) 551 randGen := rand.New(s) 552 553 attesterServer := &Server{ 554 HeadFetcher: &mock.ChainService{}, 555 P2P: &mockp2p.MockBroadcaster{}, 556 BeaconDB: db, 557 AttestationCache: cache.NewAttestationCache(), 558 AttPool: attestations.NewPool(), 559 OperationNotifier: (&mock.ChainService{}).OperationNotifier(), 560 } 561 562 var slots []types.Slot 563 var comIdxs []types.CommitteeIndex 564 var isAggregator []bool 565 566 for i := types.Slot(100); i < 200; i++ { 567 slots = append(slots, i) 568 comIdxs = append(comIdxs, types.CommitteeIndex(randGen.Int63n(64))) 569 boolVal := randGen.Uint64()%2 == 0 570 isAggregator = append(isAggregator, boolVal) 571 } 572 573 slots = append(slots, 321) 574 575 _, err := attesterServer.SubscribeCommitteeSubnets(context.Background(), ðpb.CommitteeSubnetsSubscribeRequest{ 576 Slots: slots, 577 CommitteeIds: comIdxs, 578 IsAggregator: isAggregator, 579 }) 580 assert.ErrorContains(t, "request fields are not the same length", err) 581 } 582 583 func TestServer_SubscribeCommitteeSubnets_MultipleSlots(t *testing.T) { 584 db := dbutil.SetupDB(t) 585 // fixed seed 586 s := rand.NewSource(10) 587 randGen := rand.New(s) 588 589 validators := make([]*ethpb.Validator, 64) 590 for i := 0; i < len(validators); i++ { 591 validators[i] = ðpb.Validator{ 592 ExitEpoch: params.BeaconConfig().FarFutureEpoch, 593 EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance, 594 } 595 } 596 597 state, err := testutil.NewBeaconState() 598 require.NoError(t, err) 599 require.NoError(t, state.SetValidators(validators)) 600 601 attesterServer := &Server{ 602 HeadFetcher: &mock.ChainService{State: state}, 603 P2P: &mockp2p.MockBroadcaster{}, 604 BeaconDB: db, 605 AttestationCache: cache.NewAttestationCache(), 606 AttPool: attestations.NewPool(), 607 OperationNotifier: (&mock.ChainService{}).OperationNotifier(), 608 } 609 610 var slots []types.Slot 611 var comIdxs []types.CommitteeIndex 612 var isAggregator []bool 613 614 for i := types.Slot(100); i < 200; i++ { 615 slots = append(slots, i) 616 comIdxs = append(comIdxs, types.CommitteeIndex(randGen.Int63n(64))) 617 boolVal := randGen.Uint64()%2 == 0 618 isAggregator = append(isAggregator, boolVal) 619 } 620 621 _, err = attesterServer.SubscribeCommitteeSubnets(context.Background(), ðpb.CommitteeSubnetsSubscribeRequest{ 622 Slots: slots, 623 CommitteeIds: comIdxs, 624 IsAggregator: isAggregator, 625 }) 626 require.NoError(t, err) 627 for i := types.Slot(100); i < 200; i++ { 628 subnets := cache.SubnetIDs.GetAttesterSubnetIDs(i) 629 assert.Equal(t, 1, len(subnets)) 630 if isAggregator[i-100] { 631 subnets = cache.SubnetIDs.GetAggregatorSubnetIDs(i) 632 assert.Equal(t, 1, len(subnets)) 633 } 634 } 635 }