github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/rpc/prysm/v1alpha1/validator/status_test.go (about) 1 package validator 2 3 import ( 4 "context" 5 "reflect" 6 "testing" 7 "time" 8 9 types "github.com/prysmaticlabs/eth2-types" 10 mockChain "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/testing" 11 "github.com/prysmaticlabs/prysm/beacon-chain/cache/depositcache" 12 "github.com/prysmaticlabs/prysm/beacon-chain/core/helpers" 13 dbutil "github.com/prysmaticlabs/prysm/beacon-chain/db/testing" 14 mockPOW "github.com/prysmaticlabs/prysm/beacon-chain/powchain/testing" 15 iface "github.com/prysmaticlabs/prysm/beacon-chain/state/interface" 16 "github.com/prysmaticlabs/prysm/beacon-chain/state/stategen" 17 v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1" 18 mockSync "github.com/prysmaticlabs/prysm/beacon-chain/sync/initial-sync/testing" 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/shared/bls" 23 "github.com/prysmaticlabs/prysm/shared/bytesutil" 24 "github.com/prysmaticlabs/prysm/shared/params" 25 "github.com/prysmaticlabs/prysm/shared/testutil" 26 "github.com/prysmaticlabs/prysm/shared/testutil/assert" 27 "github.com/prysmaticlabs/prysm/shared/testutil/require" 28 "github.com/prysmaticlabs/prysm/shared/trieutil" 29 "google.golang.org/protobuf/proto" 30 ) 31 32 func TestValidatorStatus_DepositedEth1(t *testing.T) { 33 db := dbutil.SetupDB(t) 34 ctx := context.Background() 35 deposits, _, err := testutil.DeterministicDepositsAndKeys(1) 36 require.NoError(t, err, "Could not generate deposits and keys") 37 deposit := deposits[0] 38 pubKey1 := deposit.Data.PublicKey 39 depositTrie, err := trieutil.NewTrie(params.BeaconConfig().DepositContractTreeDepth) 40 require.NoError(t, err, "Could not setup deposit trie") 41 depositCache, err := depositcache.New() 42 require.NoError(t, err) 43 44 assert.NoError(t, depositCache.InsertDeposit(ctx, deposit, 0 /*blockNum*/, 0, depositTrie.Root())) 45 height := time.Unix(int64(params.BeaconConfig().Eth1FollowDistance), 0).Unix() 46 p := &mockPOW.POWChain{ 47 TimesByHeight: map[int]uint64{ 48 0: uint64(height), 49 }, 50 } 51 stateObj, err := v1.InitializeFromProtoUnsafe(&pbp2p.BeaconState{}) 52 require.NoError(t, err) 53 vs := &Server{ 54 BeaconDB: db, 55 DepositFetcher: depositCache, 56 BlockFetcher: p, 57 HeadFetcher: &mockChain.ChainService{ 58 State: stateObj, 59 }, 60 Eth1InfoFetcher: p, 61 } 62 req := ðpb.ValidatorStatusRequest{ 63 PublicKey: pubKey1, 64 } 65 resp, err := vs.ValidatorStatus(context.Background(), req) 66 require.NoError(t, err, "Could not get validator status") 67 assert.Equal(t, ethpb.ValidatorStatus_DEPOSITED, resp.Status) 68 } 69 70 func TestValidatorStatus_Deposited(t *testing.T) { 71 db := dbutil.SetupDB(t) 72 ctx := context.Background() 73 74 pubKey1 := pubKey(1) 75 depData := ðpb.Deposit_Data{ 76 Amount: params.BeaconConfig().MaxEffectiveBalance, 77 PublicKey: pubKey1, 78 Signature: bytesutil.PadTo([]byte("hi"), 96), 79 WithdrawalCredentials: bytesutil.PadTo([]byte("hey"), 32), 80 } 81 deposit := ðpb.Deposit{ 82 Data: depData, 83 } 84 depositTrie, err := trieutil.NewTrie(params.BeaconConfig().DepositContractTreeDepth) 85 require.NoError(t, err, "Could not setup deposit trie") 86 depositCache, err := depositcache.New() 87 require.NoError(t, err) 88 89 assert.NoError(t, depositCache.InsertDeposit(ctx, deposit, 0 /*blockNum*/, 0, depositTrie.Root())) 90 height := time.Unix(int64(params.BeaconConfig().Eth1FollowDistance), 0).Unix() 91 p := &mockPOW.POWChain{ 92 TimesByHeight: map[int]uint64{ 93 0: uint64(height), 94 }, 95 } 96 stateObj, err := v1.InitializeFromProtoUnsafe(&pbp2p.BeaconState{ 97 Validators: []*ethpb.Validator{ 98 { 99 PublicKey: pubKey1, 100 ActivationEligibilityEpoch: 1, 101 }, 102 }, 103 }) 104 require.NoError(t, err) 105 vs := &Server{ 106 BeaconDB: db, 107 DepositFetcher: depositCache, 108 BlockFetcher: p, 109 HeadFetcher: &mockChain.ChainService{ 110 State: stateObj, 111 }, 112 Eth1InfoFetcher: p, 113 } 114 req := ðpb.ValidatorStatusRequest{ 115 PublicKey: pubKey1, 116 } 117 resp, err := vs.ValidatorStatus(context.Background(), req) 118 require.NoError(t, err, "Could not get validator status") 119 assert.Equal(t, ethpb.ValidatorStatus_DEPOSITED, resp.Status) 120 } 121 122 func TestValidatorStatus_PartiallyDeposited(t *testing.T) { 123 db := dbutil.SetupDB(t) 124 ctx := context.Background() 125 126 pubKey1 := pubKey(1) 127 depData := ðpb.Deposit_Data{ 128 Amount: params.BeaconConfig().MinDepositAmount, 129 PublicKey: pubKey1, 130 Signature: []byte("hi"), 131 WithdrawalCredentials: []byte("hey"), 132 } 133 deposit := ðpb.Deposit{ 134 Data: depData, 135 } 136 depositTrie, err := trieutil.NewTrie(params.BeaconConfig().DepositContractTreeDepth) 137 require.NoError(t, err, "Could not setup deposit trie") 138 depositCache, err := depositcache.New() 139 require.NoError(t, err) 140 141 assert.NoError(t, depositCache.InsertDeposit(ctx, deposit, 0 /*blockNum*/, 0, depositTrie.Root())) 142 height := time.Unix(int64(params.BeaconConfig().Eth1FollowDistance), 0).Unix() 143 p := &mockPOW.POWChain{ 144 TimesByHeight: map[int]uint64{ 145 0: uint64(height), 146 }, 147 } 148 stateObj, err := v1.InitializeFromProtoUnsafe(&pbp2p.BeaconState{ 149 Validators: []*ethpb.Validator{ 150 { 151 PublicKey: pubKey1, 152 ActivationEligibilityEpoch: 1, 153 }, 154 }, 155 }) 156 require.NoError(t, err) 157 vs := &Server{ 158 BeaconDB: db, 159 DepositFetcher: depositCache, 160 BlockFetcher: p, 161 HeadFetcher: &mockChain.ChainService{ 162 State: stateObj, 163 }, 164 Eth1InfoFetcher: p, 165 } 166 req := ðpb.ValidatorStatusRequest{ 167 PublicKey: pubKey1, 168 } 169 resp, err := vs.ValidatorStatus(context.Background(), req) 170 require.NoError(t, err, "Could not get validator status") 171 assert.Equal(t, ethpb.ValidatorStatus_PARTIALLY_DEPOSITED, resp.Status) 172 } 173 174 func TestValidatorStatus_Pending(t *testing.T) { 175 db := dbutil.SetupDB(t) 176 ctx := context.Background() 177 178 pubKey := pubKey(1) 179 block := testutil.NewBeaconBlock() 180 require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(block)), "Could not save genesis block") 181 genesisRoot, err := block.Block.HashTreeRoot() 182 require.NoError(t, err, "Could not get signing root") 183 // Pending active because activation epoch is still defaulted at far future slot. 184 state, err := testutil.NewBeaconState() 185 require.NoError(t, err) 186 require.NoError(t, state.SetSlot(5000)) 187 err = state.SetValidators([]*ethpb.Validator{ 188 { 189 ActivationEpoch: params.BeaconConfig().FarFutureEpoch, 190 ExitEpoch: params.BeaconConfig().FarFutureEpoch, 191 WithdrawableEpoch: params.BeaconConfig().FarFutureEpoch, 192 PublicKey: pubKey, 193 WithdrawalCredentials: make([]byte, 32), 194 }, 195 }) 196 require.NoError(t, err) 197 require.NoError(t, db.SaveState(ctx, state, genesisRoot), "Could not save state") 198 require.NoError(t, db.SaveHeadBlockRoot(ctx, genesisRoot), "Could not save genesis state") 199 200 depData := ðpb.Deposit_Data{ 201 PublicKey: pubKey, 202 Signature: bytesutil.PadTo([]byte("hi"), 96), 203 WithdrawalCredentials: bytesutil.PadTo([]byte("hey"), 32), 204 } 205 206 deposit := ðpb.Deposit{ 207 Data: depData, 208 } 209 depositTrie, err := trieutil.NewTrie(params.BeaconConfig().DepositContractTreeDepth) 210 require.NoError(t, err, "Could not setup deposit trie") 211 depositCache, err := depositcache.New() 212 require.NoError(t, err) 213 214 assert.NoError(t, depositCache.InsertDeposit(ctx, deposit, 0 /*blockNum*/, 0, depositTrie.Root())) 215 216 height := time.Unix(int64(params.BeaconConfig().Eth1FollowDistance), 0).Unix() 217 p := &mockPOW.POWChain{ 218 TimesByHeight: map[int]uint64{ 219 0: uint64(height), 220 }, 221 } 222 vs := &Server{ 223 BeaconDB: db, 224 ChainStartFetcher: p, 225 BlockFetcher: p, 226 Eth1InfoFetcher: p, 227 DepositFetcher: depositCache, 228 HeadFetcher: &mockChain.ChainService{State: state, Root: genesisRoot[:]}, 229 } 230 req := ðpb.ValidatorStatusRequest{ 231 PublicKey: pubKey, 232 } 233 resp, err := vs.ValidatorStatus(context.Background(), req) 234 require.NoError(t, err, "Could not get validator status") 235 assert.Equal(t, ethpb.ValidatorStatus_PENDING, resp.Status) 236 } 237 238 func TestValidatorStatus_Active(t *testing.T) { 239 db := dbutil.SetupDB(t) 240 // This test breaks if it doesnt use mainnet config 241 params.SetupTestConfigCleanup(t) 242 params.OverrideBeaconConfig(params.MainnetConfig()) 243 ctx := context.Background() 244 245 pubKey := pubKey(1) 246 247 depData := ðpb.Deposit_Data{ 248 PublicKey: pubKey, 249 Signature: bytesutil.PadTo([]byte("hi"), 96), 250 WithdrawalCredentials: bytesutil.PadTo([]byte("hey"), 32), 251 } 252 253 deposit := ðpb.Deposit{ 254 Data: depData, 255 } 256 depositTrie, err := trieutil.NewTrie(params.BeaconConfig().DepositContractTreeDepth) 257 require.NoError(t, err, "Could not setup deposit trie") 258 depositCache, err := depositcache.New() 259 require.NoError(t, err) 260 261 assert.NoError(t, depositCache.InsertDeposit(ctx, deposit, 0 /*blockNum*/, 0, depositTrie.Root())) 262 263 // Active because activation epoch <= current epoch < exit epoch. 264 activeEpoch := helpers.ActivationExitEpoch(0) 265 266 block := testutil.NewBeaconBlock() 267 require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(block)), "Could not save genesis block") 268 genesisRoot, err := block.Block.HashTreeRoot() 269 require.NoError(t, err, "Could not get signing root") 270 271 state := &pbp2p.BeaconState{ 272 GenesisTime: uint64(time.Unix(0, 0).Unix()), 273 Slot: 10000, 274 Validators: []*ethpb.Validator{{ 275 ActivationEpoch: activeEpoch, 276 ExitEpoch: params.BeaconConfig().FarFutureEpoch, 277 WithdrawableEpoch: params.BeaconConfig().FarFutureEpoch, 278 PublicKey: pubKey}, 279 }} 280 stateObj, err := v1.InitializeFromProtoUnsafe(state) 281 require.NoError(t, err) 282 283 timestamp := time.Unix(int64(params.BeaconConfig().Eth1FollowDistance), 0).Unix() 284 p := &mockPOW.POWChain{ 285 TimesByHeight: map[int]uint64{ 286 int(params.BeaconConfig().Eth1FollowDistance): uint64(timestamp), 287 }, 288 } 289 vs := &Server{ 290 BeaconDB: db, 291 ChainStartFetcher: p, 292 BlockFetcher: p, 293 Eth1InfoFetcher: p, 294 DepositFetcher: depositCache, 295 HeadFetcher: &mockChain.ChainService{State: stateObj, Root: genesisRoot[:]}, 296 } 297 req := ðpb.ValidatorStatusRequest{ 298 PublicKey: pubKey, 299 } 300 resp, err := vs.ValidatorStatus(context.Background(), req) 301 require.NoError(t, err, "Could not get validator status") 302 303 expected := ðpb.ValidatorStatusResponse{ 304 Status: ethpb.ValidatorStatus_ACTIVE, 305 ActivationEpoch: 5, 306 } 307 if !proto.Equal(resp, expected) { 308 t.Errorf("Wanted %v, got %v", expected, resp) 309 } 310 } 311 312 func TestValidatorStatus_Exiting(t *testing.T) { 313 db := dbutil.SetupDB(t) 314 ctx := context.Background() 315 316 pubKey := pubKey(1) 317 318 // Initiated exit because validator exit epoch and withdrawable epoch are not FAR_FUTURE_EPOCH 319 slot := types.Slot(10000) 320 epoch := helpers.SlotToEpoch(slot) 321 exitEpoch := helpers.ActivationExitEpoch(epoch) 322 withdrawableEpoch := exitEpoch + params.BeaconConfig().MinValidatorWithdrawabilityDelay 323 block := testutil.NewBeaconBlock() 324 require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(block)), "Could not save genesis block") 325 genesisRoot, err := block.Block.HashTreeRoot() 326 require.NoError(t, err, "Could not get signing root") 327 328 state := &pbp2p.BeaconState{ 329 Slot: slot, 330 Validators: []*ethpb.Validator{{ 331 PublicKey: pubKey, 332 ActivationEpoch: 0, 333 ExitEpoch: exitEpoch, 334 WithdrawableEpoch: withdrawableEpoch}, 335 }} 336 stateObj, err := v1.InitializeFromProtoUnsafe(state) 337 require.NoError(t, err) 338 depData := ðpb.Deposit_Data{ 339 PublicKey: pubKey, 340 Signature: bytesutil.PadTo([]byte("hi"), 96), 341 WithdrawalCredentials: bytesutil.PadTo([]byte("hey"), 32), 342 } 343 344 deposit := ðpb.Deposit{ 345 Data: depData, 346 } 347 depositTrie, err := trieutil.NewTrie(params.BeaconConfig().DepositContractTreeDepth) 348 require.NoError(t, err, "Could not setup deposit trie") 349 depositCache, err := depositcache.New() 350 require.NoError(t, err) 351 352 assert.NoError(t, depositCache.InsertDeposit(ctx, deposit, 0 /*blockNum*/, 0, depositTrie.Root())) 353 height := time.Unix(int64(params.BeaconConfig().Eth1FollowDistance), 0).Unix() 354 p := &mockPOW.POWChain{ 355 TimesByHeight: map[int]uint64{ 356 0: uint64(height), 357 }, 358 } 359 vs := &Server{ 360 BeaconDB: db, 361 ChainStartFetcher: p, 362 BlockFetcher: p, 363 Eth1InfoFetcher: p, 364 DepositFetcher: depositCache, 365 HeadFetcher: &mockChain.ChainService{State: stateObj, Root: genesisRoot[:]}, 366 } 367 req := ðpb.ValidatorStatusRequest{ 368 PublicKey: pubKey, 369 } 370 resp, err := vs.ValidatorStatus(context.Background(), req) 371 require.NoError(t, err, "Could not get validator status") 372 assert.Equal(t, ethpb.ValidatorStatus_EXITING, resp.Status) 373 } 374 375 func TestValidatorStatus_Slashing(t *testing.T) { 376 db := dbutil.SetupDB(t) 377 ctx := context.Background() 378 379 pubKey := pubKey(1) 380 381 // Exit slashed because slashed is true, exit epoch is =< current epoch and withdrawable epoch > epoch . 382 slot := types.Slot(10000) 383 epoch := helpers.SlotToEpoch(slot) 384 block := testutil.NewBeaconBlock() 385 require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(block)), "Could not save genesis block") 386 genesisRoot, err := block.Block.HashTreeRoot() 387 require.NoError(t, err, "Could not get signing root") 388 389 state := &pbp2p.BeaconState{ 390 Slot: slot, 391 Validators: []*ethpb.Validator{{ 392 Slashed: true, 393 PublicKey: pubKey, 394 WithdrawableEpoch: epoch + 1}, 395 }} 396 stateObj, err := v1.InitializeFromProtoUnsafe(state) 397 require.NoError(t, err) 398 depData := ðpb.Deposit_Data{ 399 PublicKey: pubKey, 400 Signature: bytesutil.PadTo([]byte("hi"), 96), 401 WithdrawalCredentials: bytesutil.PadTo([]byte("hey"), 32), 402 } 403 404 deposit := ðpb.Deposit{ 405 Data: depData, 406 } 407 depositTrie, err := trieutil.NewTrie(params.BeaconConfig().DepositContractTreeDepth) 408 require.NoError(t, err, "Could not setup deposit trie") 409 depositCache, err := depositcache.New() 410 require.NoError(t, err) 411 412 assert.NoError(t, depositCache.InsertDeposit(ctx, deposit, 0 /*blockNum*/, 0, depositTrie.Root())) 413 height := time.Unix(int64(params.BeaconConfig().Eth1FollowDistance), 0).Unix() 414 p := &mockPOW.POWChain{ 415 TimesByHeight: map[int]uint64{ 416 0: uint64(height), 417 }, 418 } 419 vs := &Server{ 420 BeaconDB: db, 421 ChainStartFetcher: p, 422 Eth1InfoFetcher: p, 423 DepositFetcher: depositCache, 424 BlockFetcher: p, 425 HeadFetcher: &mockChain.ChainService{State: stateObj, Root: genesisRoot[:]}, 426 } 427 req := ðpb.ValidatorStatusRequest{ 428 PublicKey: pubKey, 429 } 430 resp, err := vs.ValidatorStatus(context.Background(), req) 431 require.NoError(t, err, "Could not get validator status") 432 assert.Equal(t, ethpb.ValidatorStatus_EXITED, resp.Status) 433 } 434 435 func TestValidatorStatus_Exited(t *testing.T) { 436 db := dbutil.SetupDB(t) 437 ctx := context.Background() 438 439 pubKey := pubKey(1) 440 441 // Exit because only exit epoch is =< current epoch. 442 slot := types.Slot(10000) 443 epoch := helpers.SlotToEpoch(slot) 444 block := testutil.NewBeaconBlock() 445 require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(block)), "Could not save genesis block") 446 genesisRoot, err := block.Block.HashTreeRoot() 447 require.NoError(t, err, "Could not get signing root") 448 params.SetupTestConfigCleanup(t) 449 params.OverrideBeaconConfig(params.MainnetConfig()) 450 numDeposits := uint64(64) 451 beaconState, _ := testutil.DeterministicGenesisState(t, numDeposits) 452 require.NoError(t, db.SaveState(ctx, beaconState, genesisRoot)) 453 require.NoError(t, db.SaveHeadBlockRoot(ctx, genesisRoot), "Could not save genesis state") 454 state, err := testutil.NewBeaconState() 455 require.NoError(t, err) 456 require.NoError(t, state.SetSlot(slot)) 457 err = state.SetValidators([]*ethpb.Validator{{ 458 PublicKey: pubKey, 459 WithdrawableEpoch: epoch + 1, 460 WithdrawalCredentials: make([]byte, 32)}, 461 }) 462 require.NoError(t, err) 463 depData := ðpb.Deposit_Data{ 464 PublicKey: pubKey, 465 Signature: bytesutil.PadTo([]byte("hi"), 96), 466 WithdrawalCredentials: bytesutil.PadTo([]byte("hey"), 32), 467 } 468 469 deposit := ðpb.Deposit{ 470 Data: depData, 471 } 472 depositTrie, err := trieutil.NewTrie(params.BeaconConfig().DepositContractTreeDepth) 473 require.NoError(t, err, "Could not setup deposit trie") 474 depositCache, err := depositcache.New() 475 require.NoError(t, err) 476 477 assert.NoError(t, depositCache.InsertDeposit(ctx, deposit, 0 /*blockNum*/, 0, depositTrie.Root())) 478 height := time.Unix(int64(params.BeaconConfig().Eth1FollowDistance), 0).Unix() 479 p := &mockPOW.POWChain{ 480 TimesByHeight: map[int]uint64{ 481 0: uint64(height), 482 }, 483 } 484 vs := &Server{ 485 BeaconDB: db, 486 ChainStartFetcher: p, 487 Eth1InfoFetcher: p, 488 BlockFetcher: p, 489 DepositFetcher: depositCache, 490 HeadFetcher: &mockChain.ChainService{State: state, Root: genesisRoot[:]}, 491 } 492 req := ðpb.ValidatorStatusRequest{ 493 PublicKey: pubKey, 494 } 495 resp, err := vs.ValidatorStatus(context.Background(), req) 496 require.NoError(t, err, "Could not get validator status") 497 assert.Equal(t, ethpb.ValidatorStatus_EXITED, resp.Status) 498 } 499 500 func TestValidatorStatus_UnknownStatus(t *testing.T) { 501 db := dbutil.SetupDB(t) 502 pubKey := pubKey(1) 503 depositCache, err := depositcache.New() 504 require.NoError(t, err) 505 506 stateObj, err := v1.InitializeFromProtoUnsafe(&pbp2p.BeaconState{ 507 Slot: 0, 508 }) 509 require.NoError(t, err) 510 vs := &Server{ 511 DepositFetcher: depositCache, 512 Eth1InfoFetcher: &mockPOW.POWChain{}, 513 HeadFetcher: &mockChain.ChainService{ 514 State: stateObj, 515 }, 516 BeaconDB: db, 517 } 518 req := ðpb.ValidatorStatusRequest{ 519 PublicKey: pubKey, 520 } 521 resp, err := vs.ValidatorStatus(context.Background(), req) 522 require.NoError(t, err, "Could not get validator status") 523 assert.Equal(t, ethpb.ValidatorStatus_UNKNOWN_STATUS, resp.Status) 524 } 525 526 func TestActivationStatus_OK(t *testing.T) { 527 db := dbutil.SetupDB(t) 528 ctx := context.Background() 529 530 deposits, _, err := testutil.DeterministicDepositsAndKeys(4) 531 require.NoError(t, err) 532 pubKeys := [][]byte{deposits[0].Data.PublicKey, deposits[1].Data.PublicKey, deposits[2].Data.PublicKey, deposits[3].Data.PublicKey} 533 stateObj, err := v1.InitializeFromProtoUnsafe(&pbp2p.BeaconState{ 534 Slot: 4000, 535 Validators: []*ethpb.Validator{ 536 { 537 ActivationEpoch: 0, 538 ExitEpoch: params.BeaconConfig().FarFutureEpoch, 539 PublicKey: pubKeys[0], 540 }, 541 { 542 ActivationEpoch: 0, 543 ExitEpoch: params.BeaconConfig().FarFutureEpoch, 544 PublicKey: pubKeys[1], 545 }, 546 { 547 ActivationEligibilityEpoch: 700, 548 ExitEpoch: params.BeaconConfig().FarFutureEpoch, 549 PublicKey: pubKeys[3], 550 EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance, 551 }, 552 }, 553 }) 554 require.NoError(t, err) 555 block := testutil.NewBeaconBlock() 556 genesisRoot, err := block.Block.HashTreeRoot() 557 require.NoError(t, err, "Could not get signing root") 558 dep := deposits[0] 559 depositTrie, err := trieutil.NewTrie(params.BeaconConfig().DepositContractTreeDepth) 560 require.NoError(t, err, "Could not setup deposit trie") 561 depositCache, err := depositcache.New() 562 require.NoError(t, err) 563 564 assert.NoError(t, depositCache.InsertDeposit(ctx, dep, 10 /*blockNum*/, 0, depositTrie.Root())) 565 566 dep = deposits[2] 567 depositTrie.Insert(dep.Data.Signature, 15) 568 assert.NoError(t, depositCache.InsertDeposit(context.Background(), dep, 0, 1, depositTrie.Root())) 569 570 vs := &Server{ 571 BeaconDB: db, 572 Ctx: context.Background(), 573 CanonicalStateChan: make(chan *pbp2p.BeaconState, 1), 574 ChainStartFetcher: &mockPOW.POWChain{}, 575 BlockFetcher: &mockPOW.POWChain{}, 576 Eth1InfoFetcher: &mockPOW.POWChain{}, 577 DepositFetcher: depositCache, 578 HeadFetcher: &mockChain.ChainService{State: stateObj, Root: genesisRoot[:]}, 579 } 580 activeExists, response, err := vs.activationStatus(context.Background(), pubKeys) 581 require.NoError(t, err) 582 require.Equal(t, true, activeExists, "No activated validator exists when there was supposed to be 2") 583 if response[0].Status.Status != ethpb.ValidatorStatus_ACTIVE { 584 t.Errorf("Validator with pubkey %#x is not activated and instead has this status: %s", 585 response[0].PublicKey, response[0].Status.Status.String()) 586 } 587 if response[0].Index != 0 { 588 t.Errorf("Validator with pubkey %#x is expected to have index %d, received %d", response[0].PublicKey, 0, response[0].Index) 589 } 590 591 if response[1].Status.Status != ethpb.ValidatorStatus_ACTIVE { 592 t.Errorf("Validator with pubkey %#x was activated when not supposed to", 593 response[1].PublicKey) 594 } 595 if response[1].Index != 1 { 596 t.Errorf("Validator with pubkey %#x is expected to have index %d, received %d", response[1].PublicKey, 1, response[1].Index) 597 } 598 599 if response[2].Status.Status != ethpb.ValidatorStatus_DEPOSITED { 600 t.Errorf("Validator with pubkey %#x is not unknown and instead has this status: %s", 601 response[2].PublicKey, response[2].Status.Status.String()) 602 } 603 if uint64(response[2].Index) != uint64(params.BeaconConfig().FarFutureEpoch) { 604 t.Errorf("Validator with pubkey %#x is expected to have index %d, received %d", response[2].PublicKey, params.BeaconConfig().FarFutureEpoch, response[2].Index) 605 } 606 607 if response[3].Status.Status != ethpb.ValidatorStatus_DEPOSITED { 608 t.Errorf("Validator with pubkey %#x was not deposited and has this status: %s", 609 response[3].PublicKey, response[3].Status.Status.String()) 610 } 611 if response[3].Index != 2 { 612 t.Errorf("Validator with pubkey %#x is expected to have index %d, received %d", response[3].PublicKey, 2, response[3].Index) 613 } 614 } 615 616 func TestValidatorStatus_CorrectActivationQueue(t *testing.T) { 617 db := dbutil.SetupDB(t) 618 ctx := context.Background() 619 620 pbKey := pubKey(5) 621 block := testutil.NewBeaconBlock() 622 require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(block)), "Could not save genesis block") 623 genesisRoot, err := block.Block.HashTreeRoot() 624 require.NoError(t, err, "Could not get signing root") 625 currentSlot := types.Slot(5000) 626 // Pending active because activation epoch is still defaulted at far future slot. 627 validators := []*ethpb.Validator{ 628 { 629 ActivationEpoch: 0, 630 PublicKey: pubKey(0), 631 WithdrawalCredentials: make([]byte, 32), 632 ExitEpoch: params.BeaconConfig().FarFutureEpoch, 633 WithdrawableEpoch: params.BeaconConfig().FarFutureEpoch, 634 }, 635 { 636 ActivationEpoch: 0, 637 PublicKey: pubKey(1), 638 WithdrawalCredentials: make([]byte, 32), 639 ExitEpoch: params.BeaconConfig().FarFutureEpoch, 640 WithdrawableEpoch: params.BeaconConfig().FarFutureEpoch, 641 }, 642 { 643 ActivationEpoch: 0, 644 PublicKey: pubKey(2), 645 WithdrawalCredentials: make([]byte, 32), 646 ExitEpoch: params.BeaconConfig().FarFutureEpoch, 647 WithdrawableEpoch: params.BeaconConfig().FarFutureEpoch, 648 }, 649 { 650 ActivationEpoch: 0, 651 PublicKey: pubKey(3), 652 WithdrawalCredentials: make([]byte, 32), 653 ExitEpoch: params.BeaconConfig().FarFutureEpoch, 654 WithdrawableEpoch: params.BeaconConfig().FarFutureEpoch, 655 }, 656 { 657 ActivationEpoch: types.Epoch(currentSlot/params.BeaconConfig().SlotsPerEpoch + 1), 658 PublicKey: pbKey, 659 WithdrawalCredentials: make([]byte, 32), 660 ExitEpoch: params.BeaconConfig().FarFutureEpoch, 661 WithdrawableEpoch: params.BeaconConfig().FarFutureEpoch, 662 }, 663 { 664 ActivationEpoch: types.Epoch(currentSlot/params.BeaconConfig().SlotsPerEpoch + 4), 665 PublicKey: pubKey(5), 666 WithdrawalCredentials: make([]byte, 32), 667 ExitEpoch: params.BeaconConfig().FarFutureEpoch, 668 WithdrawableEpoch: params.BeaconConfig().FarFutureEpoch, 669 }, 670 } 671 state, err := testutil.NewBeaconState() 672 require.NoError(t, err) 673 require.NoError(t, state.SetValidators(validators)) 674 require.NoError(t, state.SetSlot(currentSlot)) 675 require.NoError(t, db.SaveState(ctx, state, genesisRoot), "Could not save state") 676 require.NoError(t, db.SaveHeadBlockRoot(ctx, genesisRoot), "Could not save genesis state") 677 678 depositTrie, err := trieutil.NewTrie(params.BeaconConfig().DepositContractTreeDepth) 679 require.NoError(t, err, "Could not setup deposit trie") 680 depositCache, err := depositcache.New() 681 require.NoError(t, err) 682 683 for i := 0; i < 6; i++ { 684 depData := ðpb.Deposit_Data{ 685 PublicKey: pubKey(uint64(i)), 686 Signature: bytesutil.PadTo([]byte("hi"), 96), 687 WithdrawalCredentials: bytesutil.PadTo([]byte("hey"), 32), 688 } 689 690 deposit := ðpb.Deposit{ 691 Data: depData, 692 } 693 assert.NoError(t, depositCache.InsertDeposit(ctx, deposit, 0 /*blockNum*/, int64(i), depositTrie.Root())) 694 695 } 696 697 height := time.Unix(int64(params.BeaconConfig().Eth1FollowDistance), 0).Unix() 698 p := &mockPOW.POWChain{ 699 TimesByHeight: map[int]uint64{ 700 0: uint64(height), 701 }, 702 } 703 vs := &Server{ 704 BeaconDB: db, 705 ChainStartFetcher: p, 706 BlockFetcher: p, 707 Eth1InfoFetcher: p, 708 DepositFetcher: depositCache, 709 HeadFetcher: &mockChain.ChainService{State: state, Root: genesisRoot[:]}, 710 } 711 req := ðpb.ValidatorStatusRequest{ 712 PublicKey: pbKey, 713 } 714 resp, err := vs.ValidatorStatus(context.Background(), req) 715 require.NoError(t, err, "Could not get validator status") 716 assert.Equal(t, ethpb.ValidatorStatus_PENDING, resp.Status) 717 assert.Equal(t, uint64(2), resp.PositionInActivationQueue, "Unexpected position in activation queue") 718 } 719 720 func TestMultipleValidatorStatus_Pubkeys(t *testing.T) { 721 db := dbutil.SetupDB(t) 722 ctx := context.Background() 723 724 deposits, _, err := testutil.DeterministicDepositsAndKeys(6) 725 require.NoError(t, err) 726 pubKeys := [][]byte{ 727 deposits[0].Data.PublicKey, 728 deposits[1].Data.PublicKey, 729 deposits[2].Data.PublicKey, 730 deposits[3].Data.PublicKey, 731 deposits[4].Data.PublicKey, 732 deposits[5].Data.PublicKey, 733 } 734 stateObj, err := v1.InitializeFromProtoUnsafe(&pbp2p.BeaconState{ 735 Slot: 4000, 736 Validators: []*ethpb.Validator{ 737 { 738 ActivationEpoch: 0, 739 ExitEpoch: params.BeaconConfig().FarFutureEpoch, 740 PublicKey: pubKeys[0], 741 }, 742 { 743 ActivationEpoch: 0, 744 ExitEpoch: params.BeaconConfig().FarFutureEpoch, 745 PublicKey: pubKeys[1], 746 }, 747 { 748 ActivationEligibilityEpoch: 700, 749 ExitEpoch: params.BeaconConfig().FarFutureEpoch, 750 PublicKey: pubKeys[3], 751 EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance, 752 }, 753 { 754 ActivationEligibilityEpoch: 700, 755 ExitEpoch: params.BeaconConfig().FarFutureEpoch, 756 PublicKey: pubKeys[4], 757 EffectiveBalance: params.BeaconConfig().MinDepositAmount, 758 }, 759 { 760 ActivationEligibilityEpoch: 700, 761 ExitEpoch: params.BeaconConfig().FarFutureEpoch, 762 PublicKey: pubKeys[5], 763 }, 764 }, 765 }) 766 require.NoError(t, err) 767 block := testutil.NewBeaconBlock() 768 genesisRoot, err := block.Block.HashTreeRoot() 769 require.NoError(t, err, "Could not get signing root") 770 depositTrie, err := trieutil.NewTrie(params.BeaconConfig().DepositContractTreeDepth) 771 require.NoError(t, err, "Could not setup deposit trie") 772 depositCache, err := depositcache.New() 773 require.NoError(t, err) 774 775 dep := deposits[0] 776 assert.NoError(t, depositCache.InsertDeposit(ctx, dep, 10 /*blockNum*/, 0, depositTrie.Root())) 777 dep = deposits[2] 778 depositTrie.Insert(dep.Data.Signature, 15) 779 assert.NoError(t, depositCache.InsertDeposit(context.Background(), dep, 0, 1, depositTrie.Root())) 780 781 vs := &Server{ 782 BeaconDB: db, 783 Ctx: context.Background(), 784 CanonicalStateChan: make(chan *pbp2p.BeaconState, 1), 785 ChainStartFetcher: &mockPOW.POWChain{}, 786 BlockFetcher: &mockPOW.POWChain{}, 787 Eth1InfoFetcher: &mockPOW.POWChain{}, 788 DepositFetcher: depositCache, 789 HeadFetcher: &mockChain.ChainService{State: stateObj, Root: genesisRoot[:]}, 790 SyncChecker: &mockSync.Sync{IsSyncing: false}, 791 } 792 793 want := []*ethpb.ValidatorStatusResponse{ 794 { 795 Status: ethpb.ValidatorStatus_ACTIVE, 796 }, 797 { 798 Status: ethpb.ValidatorStatus_ACTIVE, 799 }, 800 { 801 Status: ethpb.ValidatorStatus_DEPOSITED, 802 ActivationEpoch: 18446744073709551615, 803 }, 804 { 805 Status: ethpb.ValidatorStatus_DEPOSITED, 806 }, 807 { 808 Status: ethpb.ValidatorStatus_PARTIALLY_DEPOSITED, 809 }, 810 { 811 Status: ethpb.ValidatorStatus_PENDING, 812 }, 813 } 814 815 req := ðpb.MultipleValidatorStatusRequest{PublicKeys: pubKeys} 816 response, err := vs.MultipleValidatorStatus(context.Background(), req) 817 require.NoError(t, err) 818 819 assert.Equal(t, len(response.PublicKeys), len(pubKeys)) 820 for i, resp := range response.PublicKeys { 821 require.DeepEqual(t, pubKeys[i], resp) 822 } 823 assert.Equal(t, len(pubKeys), len(response.Statuses)) 824 for i, resp := range response.Statuses { 825 if !proto.Equal(want[i], resp) { 826 t.Fatalf("Wanted %v\n Recieved: %v\n", want[i], resp) 827 } 828 } 829 } 830 831 func TestMultipleValidatorStatus_Indices(t *testing.T) { 832 db := dbutil.SetupDB(t) 833 slot := types.Slot(10000) 834 epoch := helpers.SlotToEpoch(slot) 835 pubKeys := [][]byte{pubKey(1), pubKey(2), pubKey(3), pubKey(4), pubKey(5), pubKey(6), pubKey(7)} 836 beaconState := &pbp2p.BeaconState{ 837 Slot: 4000, 838 Validators: []*ethpb.Validator{ 839 { 840 ActivationEpoch: 0, 841 ExitEpoch: params.BeaconConfig().FarFutureEpoch, 842 PublicKey: pubKeys[0], 843 }, 844 { 845 ActivationEpoch: 0, 846 ExitEpoch: params.BeaconConfig().FarFutureEpoch, 847 PublicKey: pubKeys[1], 848 }, 849 { 850 ActivationEligibilityEpoch: 700, 851 ExitEpoch: params.BeaconConfig().FarFutureEpoch, 852 PublicKey: pubKeys[2], 853 EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance, 854 }, 855 { 856 Slashed: true, 857 ExitEpoch: epoch + 1, 858 PublicKey: pubKeys[3], 859 }, 860 { 861 ActivationEligibilityEpoch: 700, 862 ExitEpoch: params.BeaconConfig().FarFutureEpoch, 863 PublicKey: pubKeys[4], 864 EffectiveBalance: params.BeaconConfig().MinDepositAmount, 865 }, 866 { 867 ActivationEligibilityEpoch: 700, 868 ExitEpoch: params.BeaconConfig().FarFutureEpoch, 869 PublicKey: pubKeys[5], 870 }, 871 }, 872 } 873 stateObj, err := v1.InitializeFromProtoUnsafe(beaconState) 874 require.NoError(t, err) 875 block := testutil.NewBeaconBlock() 876 genesisRoot, err := block.Block.HashTreeRoot() 877 require.NoError(t, err, "Could not get signing root") 878 879 vs := &Server{ 880 BeaconDB: db, 881 Ctx: context.Background(), 882 CanonicalStateChan: make(chan *pbp2p.BeaconState, 1), 883 ChainStartFetcher: &mockPOW.POWChain{}, 884 BlockFetcher: &mockPOW.POWChain{}, 885 Eth1InfoFetcher: &mockPOW.POWChain{}, 886 HeadFetcher: &mockChain.ChainService{State: stateObj, Root: genesisRoot[:]}, 887 SyncChecker: &mockSync.Sync{IsSyncing: false}, 888 } 889 890 want := []*ethpb.ValidatorStatusResponse{ 891 { 892 Status: ethpb.ValidatorStatus_ACTIVE, 893 }, 894 { 895 Status: ethpb.ValidatorStatus_ACTIVE, 896 }, 897 { 898 Status: ethpb.ValidatorStatus_DEPOSITED, 899 }, 900 { 901 Status: ethpb.ValidatorStatus_SLASHING, 902 }, 903 { 904 Status: ethpb.ValidatorStatus_PARTIALLY_DEPOSITED, 905 }, 906 { 907 Status: ethpb.ValidatorStatus_PENDING, 908 }, 909 } 910 911 // Note: Index 6 should be skipped. 912 req := ðpb.MultipleValidatorStatusRequest{Indices: []int64{0, 1, 2, 3, 4, 5, 6}} 913 response, err := vs.MultipleValidatorStatus(context.Background(), req) 914 require.NoError(t, err) 915 916 assert.Equal(t, len(beaconState.Validators), len(response.PublicKeys)) 917 for i, resp := range response.PublicKeys { 918 expected := beaconState.Validators[i].PublicKey 919 require.DeepEqual(t, expected, resp) 920 } 921 assert.Equal(t, len(beaconState.Validators), len(response.Statuses)) 922 for i, resp := range response.Statuses { 923 if !proto.Equal(want[i], resp) { 924 t.Fatalf("Wanted %v\n Recieved: %v\n", want[i], resp) 925 } 926 } 927 } 928 929 func TestValidatorStatus_Invalid(t *testing.T) { 930 db := dbutil.SetupDB(t) 931 ctx := context.Background() 932 deposits, _, err := testutil.DeterministicDepositsAndKeys(1) 933 require.NoError(t, err, "Could not generate deposits and keys") 934 deposit := deposits[0] 935 pubKey1 := deposit.Data.PublicKey 936 deposit.Data.Signature = deposit.Data.Signature[1:] 937 depositTrie, err := trieutil.NewTrie(params.BeaconConfig().DepositContractTreeDepth) 938 require.NoError(t, err, "Could not setup deposit trie") 939 depositCache, err := depositcache.New() 940 require.NoError(t, err) 941 942 assert.NoError(t, depositCache.InsertDeposit(ctx, deposit, 0 /*blockNum*/, 0, depositTrie.Root())) 943 height := time.Unix(int64(params.BeaconConfig().Eth1FollowDistance), 0).Unix() 944 p := &mockPOW.POWChain{ 945 TimesByHeight: map[int]uint64{ 946 0: uint64(height), 947 }, 948 } 949 stateObj, err := v1.InitializeFromProtoUnsafe(&pbp2p.BeaconState{}) 950 require.NoError(t, err) 951 vs := &Server{ 952 BeaconDB: db, 953 DepositFetcher: depositCache, 954 BlockFetcher: p, 955 HeadFetcher: &mockChain.ChainService{ 956 State: stateObj, 957 }, 958 Eth1InfoFetcher: p, 959 } 960 req := ðpb.ValidatorStatusRequest{ 961 PublicKey: pubKey1, 962 } 963 resp, err := vs.ValidatorStatus(context.Background(), req) 964 require.NoError(t, err, "Could not get validator status") 965 assert.Equal(t, ethpb.ValidatorStatus_INVALID, resp.Status) 966 } 967 968 func Test_DepositStatus(t *testing.T) { 969 assert.Equal(t, depositStatus(0), ethpb.ValidatorStatus_PENDING) 970 assert.Equal(t, depositStatus(params.BeaconConfig().MinDepositAmount), ethpb.ValidatorStatus_PARTIALLY_DEPOSITED) 971 assert.Equal(t, depositStatus(params.BeaconConfig().MaxEffectiveBalance), ethpb.ValidatorStatus_DEPOSITED) 972 } 973 974 func TestServer_CheckDoppelGanger(t *testing.T) { 975 tests := []struct { 976 name string 977 wantErr bool 978 svSetup func(t *testing.T) (*Server, *ethpb.DoppelGangerRequest, *ethpb.DoppelGangerResponse) 979 }{ 980 { 981 name: "normal doppelganger request", 982 wantErr: false, 983 svSetup: func(t *testing.T) (*Server, *ethpb.DoppelGangerRequest, *ethpb.DoppelGangerResponse) { 984 db := dbutil.SetupDB(t) 985 mockGen := stategen.NewMockService() 986 hs, ps, os, keys := createStateSetup(t, 4, mockGen) 987 // Previous Epoch State 988 for i := 0; i < 3; i++ { 989 bal, err := ps.BalanceAtIndex(types.ValidatorIndex(i)) 990 assert.NoError(t, err) 991 // Add 100 gwei, to mock an inactivity leak 992 assert.NoError(t, ps.UpdateBalancesAtIndex(types.ValidatorIndex(i), bal+100)) 993 } 994 // Older Epoch State 995 for i := 0; i < 3; i++ { 996 bal, err := os.BalanceAtIndex(types.ValidatorIndex(i)) 997 assert.NoError(t, err) 998 // Add 200 gwei, to mock an inactivity leak 999 assert.NoError(t, os.UpdateBalancesAtIndex(types.ValidatorIndex(i), bal+200)) 1000 } 1001 vs := &Server{ 1002 BeaconDB: db, 1003 StateGen: mockGen, 1004 HeadFetcher: &mockChain.ChainService{ 1005 State: hs, 1006 }, 1007 SyncChecker: &mockSync.Sync{IsSyncing: false}, 1008 } 1009 request := ðpb.DoppelGangerRequest{ 1010 ValidatorRequests: make([]*ethpb.DoppelGangerRequest_ValidatorRequest, 0), 1011 } 1012 response := ðpb.DoppelGangerResponse{Responses: make([]*ethpb.DoppelGangerResponse_ValidatorResponse, 0)} 1013 for i := 0; i < 3; i++ { 1014 request.ValidatorRequests = append(request.ValidatorRequests, ðpb.DoppelGangerRequest_ValidatorRequest{ 1015 PublicKey: keys[i].PublicKey().Marshal(), 1016 Epoch: 1, 1017 SignedRoot: []byte{'A'}, 1018 }) 1019 response.Responses = append(response.Responses, ðpb.DoppelGangerResponse_ValidatorResponse{ 1020 PublicKey: keys[i].PublicKey().Marshal(), 1021 DuplicateExists: false, 1022 }) 1023 } 1024 return vs, request, response 1025 }, 1026 }, 1027 { 1028 name: "doppelganger exists current epoch", 1029 wantErr: false, 1030 svSetup: func(t *testing.T) (*Server, *ethpb.DoppelGangerRequest, *ethpb.DoppelGangerResponse) { 1031 db := dbutil.SetupDB(t) 1032 mockGen := stategen.NewMockService() 1033 1034 hs, ps, os, keys := createStateSetup(t, 4, mockGen) 1035 // Previous Epoch State 1036 for i := 0; i < 2; i++ { 1037 bal, err := ps.BalanceAtIndex(types.ValidatorIndex(i)) 1038 assert.NoError(t, err) 1039 // Add 100 gwei, to mock an inactivity leak 1040 assert.NoError(t, ps.UpdateBalancesAtIndex(types.ValidatorIndex(i), bal+100)) 1041 } 1042 bal, err := ps.BalanceAtIndex(types.ValidatorIndex(2)) 1043 assert.NoError(t, err) 1044 // Sub 100 gwei, to mock an active validator. 1045 assert.NoError(t, ps.UpdateBalancesAtIndex(types.ValidatorIndex(2), bal-100)) 1046 1047 // Older Epoch State 1048 for i := 0; i < 2; i++ { 1049 bal, err := os.BalanceAtIndex(types.ValidatorIndex(i)) 1050 assert.NoError(t, err) 1051 // Add 200 gwei, to mock an inactivity leak 1052 assert.NoError(t, os.UpdateBalancesAtIndex(types.ValidatorIndex(i), bal+200)) 1053 } 1054 bal, err = os.BalanceAtIndex(types.ValidatorIndex(2)) 1055 assert.NoError(t, err) 1056 // Sub 100 gwei, to mock an active validator. 1057 assert.NoError(t, os.UpdateBalancesAtIndex(types.ValidatorIndex(2), bal-100)) 1058 1059 vs := &Server{ 1060 BeaconDB: db, 1061 StateGen: mockGen, 1062 HeadFetcher: &mockChain.ChainService{ 1063 State: hs, 1064 }, 1065 SyncChecker: &mockSync.Sync{IsSyncing: false}, 1066 } 1067 request := ðpb.DoppelGangerRequest{ 1068 ValidatorRequests: make([]*ethpb.DoppelGangerRequest_ValidatorRequest, 0), 1069 } 1070 response := ðpb.DoppelGangerResponse{Responses: make([]*ethpb.DoppelGangerResponse_ValidatorResponse, 0)} 1071 for i := 0; i < 2; i++ { 1072 request.ValidatorRequests = append(request.ValidatorRequests, ðpb.DoppelGangerRequest_ValidatorRequest{ 1073 PublicKey: keys[i].PublicKey().Marshal(), 1074 Epoch: 1, 1075 SignedRoot: []byte{'A'}, 1076 }) 1077 response.Responses = append(response.Responses, ðpb.DoppelGangerResponse_ValidatorResponse{ 1078 PublicKey: keys[i].PublicKey().Marshal(), 1079 DuplicateExists: false, 1080 }) 1081 } 1082 1083 // Add in for duplicate validator 1084 request.ValidatorRequests = append(request.ValidatorRequests, ðpb.DoppelGangerRequest_ValidatorRequest{ 1085 PublicKey: keys[2].PublicKey().Marshal(), 1086 Epoch: 1, 1087 SignedRoot: []byte{'A'}, 1088 }) 1089 response.Responses = append(response.Responses, ðpb.DoppelGangerResponse_ValidatorResponse{ 1090 PublicKey: keys[2].PublicKey().Marshal(), 1091 DuplicateExists: true, 1092 }) 1093 return vs, request, response 1094 }, 1095 }, 1096 { 1097 name: "doppelganger exists previous epoch", 1098 wantErr: false, 1099 svSetup: func(t *testing.T) (*Server, *ethpb.DoppelGangerRequest, *ethpb.DoppelGangerResponse) { 1100 db := dbutil.SetupDB(t) 1101 mockGen := stategen.NewMockService() 1102 1103 hs, ps, os, keys := createStateSetup(t, 4, mockGen) 1104 // Previous Epoch State 1105 for i := 0; i < 2; i++ { 1106 bal, err := ps.BalanceAtIndex(types.ValidatorIndex(i)) 1107 assert.NoError(t, err) 1108 // Add 100 gwei, to mock an inactivity leak 1109 assert.NoError(t, ps.UpdateBalancesAtIndex(types.ValidatorIndex(i), bal+100)) 1110 } 1111 bal, err := ps.BalanceAtIndex(types.ValidatorIndex(2)) 1112 assert.NoError(t, err) 1113 // Sub 100 gwei, to mock an active validator. 1114 assert.NoError(t, ps.UpdateBalancesAtIndex(types.ValidatorIndex(2), bal-100)) 1115 1116 // Older Epoch State 1117 for i := 0; i < 2; i++ { 1118 bal, err := os.BalanceAtIndex(types.ValidatorIndex(i)) 1119 assert.NoError(t, err) 1120 // Add 200 gwei, to mock an inactivity leak 1121 assert.NoError(t, os.UpdateBalancesAtIndex(types.ValidatorIndex(i), bal+200)) 1122 } 1123 bal, err = os.BalanceAtIndex(types.ValidatorIndex(2)) 1124 assert.NoError(t, err) 1125 // Sub 200 gwei, to mock an active validator. 1126 assert.NoError(t, os.UpdateBalancesAtIndex(types.ValidatorIndex(2), bal-200)) 1127 1128 vs := &Server{ 1129 BeaconDB: db, 1130 StateGen: mockGen, 1131 HeadFetcher: &mockChain.ChainService{ 1132 State: hs, 1133 }, 1134 SyncChecker: &mockSync.Sync{IsSyncing: false}, 1135 } 1136 request := ðpb.DoppelGangerRequest{ 1137 ValidatorRequests: make([]*ethpb.DoppelGangerRequest_ValidatorRequest, 0), 1138 } 1139 response := ðpb.DoppelGangerResponse{Responses: make([]*ethpb.DoppelGangerResponse_ValidatorResponse, 0)} 1140 for i := 0; i < 2; i++ { 1141 request.ValidatorRequests = append(request.ValidatorRequests, ðpb.DoppelGangerRequest_ValidatorRequest{ 1142 PublicKey: keys[i].PublicKey().Marshal(), 1143 Epoch: 1, 1144 SignedRoot: []byte{'A'}, 1145 }) 1146 response.Responses = append(response.Responses, ðpb.DoppelGangerResponse_ValidatorResponse{ 1147 PublicKey: keys[i].PublicKey().Marshal(), 1148 DuplicateExists: false, 1149 }) 1150 } 1151 1152 // Add in for duplicate validator 1153 request.ValidatorRequests = append(request.ValidatorRequests, ðpb.DoppelGangerRequest_ValidatorRequest{ 1154 PublicKey: keys[2].PublicKey().Marshal(), 1155 Epoch: 1, 1156 SignedRoot: []byte{'A'}, 1157 }) 1158 response.Responses = append(response.Responses, ðpb.DoppelGangerResponse_ValidatorResponse{ 1159 PublicKey: keys[2].PublicKey().Marshal(), 1160 DuplicateExists: true, 1161 }) 1162 return vs, request, response 1163 }, 1164 }, 1165 { 1166 name: "multiple doppelganger exists", 1167 wantErr: false, 1168 svSetup: func(t *testing.T) (*Server, *ethpb.DoppelGangerRequest, *ethpb.DoppelGangerResponse) { 1169 db := dbutil.SetupDB(t) 1170 mockGen := stategen.NewMockService() 1171 1172 hs, ps, os, keys := createStateSetup(t, 4, mockGen) 1173 // Previous Epoch State 1174 for i := 10; i < 15; i++ { 1175 bal, err := ps.BalanceAtIndex(types.ValidatorIndex(i)) 1176 assert.NoError(t, err) 1177 // Add 100 gwei, to mock an inactivity leak 1178 assert.NoError(t, ps.UpdateBalancesAtIndex(types.ValidatorIndex(i), bal-100)) 1179 } 1180 1181 // Older Epoch State 1182 for i := 10; i < 15; i++ { 1183 bal, err := os.BalanceAtIndex(types.ValidatorIndex(i)) 1184 assert.NoError(t, err) 1185 // Add 200 gwei, to mock an inactivity leak 1186 assert.NoError(t, os.UpdateBalancesAtIndex(types.ValidatorIndex(i), bal-200)) 1187 } 1188 1189 vs := &Server{ 1190 BeaconDB: db, 1191 StateGen: mockGen, 1192 HeadFetcher: &mockChain.ChainService{ 1193 State: hs, 1194 }, 1195 SyncChecker: &mockSync.Sync{IsSyncing: false}, 1196 } 1197 request := ðpb.DoppelGangerRequest{ 1198 ValidatorRequests: make([]*ethpb.DoppelGangerRequest_ValidatorRequest, 0), 1199 } 1200 response := ðpb.DoppelGangerResponse{Responses: make([]*ethpb.DoppelGangerResponse_ValidatorResponse, 0)} 1201 for i := 0; i < 10; i++ { 1202 request.ValidatorRequests = append(request.ValidatorRequests, ðpb.DoppelGangerRequest_ValidatorRequest{ 1203 PublicKey: keys[i].PublicKey().Marshal(), 1204 Epoch: 1, 1205 SignedRoot: []byte{'A'}, 1206 }) 1207 response.Responses = append(response.Responses, ðpb.DoppelGangerResponse_ValidatorResponse{ 1208 PublicKey: keys[i].PublicKey().Marshal(), 1209 DuplicateExists: false, 1210 }) 1211 } 1212 for i := 10; i < 15; i++ { 1213 // Add in for duplicate validator 1214 request.ValidatorRequests = append(request.ValidatorRequests, ðpb.DoppelGangerRequest_ValidatorRequest{ 1215 PublicKey: keys[i].PublicKey().Marshal(), 1216 Epoch: 1, 1217 SignedRoot: []byte{'A'}, 1218 }) 1219 response.Responses = append(response.Responses, ðpb.DoppelGangerResponse_ValidatorResponse{ 1220 PublicKey: keys[i].PublicKey().Marshal(), 1221 DuplicateExists: true, 1222 }) 1223 } 1224 1225 return vs, request, response 1226 }, 1227 }, 1228 { 1229 name: "attesters are too recent", 1230 wantErr: false, 1231 svSetup: func(t *testing.T) (*Server, *ethpb.DoppelGangerRequest, *ethpb.DoppelGangerResponse) { 1232 db := dbutil.SetupDB(t) 1233 mockGen := stategen.NewMockService() 1234 1235 hs, ps, os, keys := createStateSetup(t, 4, mockGen) 1236 // Previous Epoch State 1237 for i := 10; i < 15; i++ { 1238 bal, err := ps.BalanceAtIndex(types.ValidatorIndex(i)) 1239 assert.NoError(t, err) 1240 // Add 100 gwei, to mock an active validator 1241 assert.NoError(t, ps.UpdateBalancesAtIndex(types.ValidatorIndex(i), bal-100)) 1242 } 1243 1244 // Older Epoch State 1245 for i := 10; i < 15; i++ { 1246 bal, err := os.BalanceAtIndex(types.ValidatorIndex(i)) 1247 assert.NoError(t, err) 1248 // Add 200 gwei, to mock an active validator 1249 assert.NoError(t, os.UpdateBalancesAtIndex(types.ValidatorIndex(i), bal-200)) 1250 } 1251 1252 vs := &Server{ 1253 BeaconDB: db, 1254 StateGen: mockGen, 1255 HeadFetcher: &mockChain.ChainService{ 1256 State: hs, 1257 }, 1258 SyncChecker: &mockSync.Sync{IsSyncing: false}, 1259 } 1260 request := ðpb.DoppelGangerRequest{ 1261 ValidatorRequests: make([]*ethpb.DoppelGangerRequest_ValidatorRequest, 0), 1262 } 1263 response := ðpb.DoppelGangerResponse{Responses: make([]*ethpb.DoppelGangerResponse_ValidatorResponse, 0)} 1264 for i := 0; i < 15; i++ { 1265 request.ValidatorRequests = append(request.ValidatorRequests, ðpb.DoppelGangerRequest_ValidatorRequest{ 1266 PublicKey: keys[i].PublicKey().Marshal(), 1267 Epoch: 2, 1268 SignedRoot: []byte{'A'}, 1269 }) 1270 response.Responses = append(response.Responses, ðpb.DoppelGangerResponse_ValidatorResponse{ 1271 PublicKey: keys[i].PublicKey().Marshal(), 1272 DuplicateExists: false, 1273 }) 1274 } 1275 1276 return vs, request, response 1277 }, 1278 }, 1279 } 1280 for _, tt := range tests { 1281 t.Run(tt.name, func(t *testing.T) { 1282 vs, req, resp := tt.svSetup(t) 1283 got, err := vs.CheckDoppelGanger(context.Background(), req) 1284 if (err != nil) != tt.wantErr { 1285 t.Errorf("CheckDoppelGanger() error = %v, wantErr %v", err, tt.wantErr) 1286 return 1287 } 1288 if !reflect.DeepEqual(got, resp) { 1289 t.Errorf("CheckDoppelGanger() got = %v, want %v", got.String(), resp.String()) 1290 } 1291 }) 1292 } 1293 } 1294 1295 func createStateSetup(t *testing.T, head types.Epoch, mockgen *stategen.MockStateManager) (iface.BeaconState, 1296 iface.BeaconState, iface.BeaconState, []bls.SecretKey) { 1297 gs, keys := testutil.DeterministicGenesisState(t, 64) 1298 hs := gs.Copy() 1299 // Head State 1300 headEpoch := head 1301 headSlot := types.Slot(headEpoch) * params.BeaconConfig().SlotsPerEpoch 1302 assert.NoError(t, hs.SetSlot(headSlot)) 1303 mockgen.StatesBySlot[headSlot] = hs 1304 1305 // Previous Epoch State 1306 prevEpoch := headEpoch - 1 1307 ps := gs.Copy() 1308 prevSlot := types.Slot(prevEpoch) * params.BeaconConfig().SlotsPerEpoch 1309 assert.NoError(t, ps.SetSlot(prevSlot)) 1310 mockgen.StatesBySlot[prevSlot] = ps 1311 1312 // Older Epoch State 1313 olderEpoch := prevEpoch - 1 1314 os := gs.Copy() 1315 olderSlot := types.Slot(olderEpoch) * params.BeaconConfig().SlotsPerEpoch 1316 assert.NoError(t, os.SetSlot(olderSlot)) 1317 mockgen.StatesBySlot[olderSlot] = os 1318 return hs, ps, os, keys 1319 }