github.com/prysmaticlabs/prysm@v1.4.4/beacon-chain/rpc/prysm/v1alpha1/validator/proposer_test.go (about) 1 package validator 2 3 import ( 4 "context" 5 "math/big" 6 "testing" 7 8 types "github.com/prysmaticlabs/eth2-types" 9 "github.com/prysmaticlabs/go-bitfield" 10 mock "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/testing" 11 "github.com/prysmaticlabs/prysm/beacon-chain/cache/depositcache" 12 b "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks" 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 "github.com/prysmaticlabs/prysm/beacon-chain/operations/slashings" 17 "github.com/prysmaticlabs/prysm/beacon-chain/operations/voluntaryexits" 18 mockp2p "github.com/prysmaticlabs/prysm/beacon-chain/p2p/testing" 19 mockPOW "github.com/prysmaticlabs/prysm/beacon-chain/powchain/testing" 20 "github.com/prysmaticlabs/prysm/beacon-chain/state/stategen" 21 v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1" 22 mockSync "github.com/prysmaticlabs/prysm/beacon-chain/sync/initial-sync/testing" 23 dbpb "github.com/prysmaticlabs/prysm/proto/beacon/db" 24 pbp2p "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1" 25 ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1" 26 "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1/wrapper" 27 attaggregation "github.com/prysmaticlabs/prysm/shared/aggregation/attestations" 28 "github.com/prysmaticlabs/prysm/shared/attestationutil" 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 "github.com/prysmaticlabs/prysm/shared/trieutil" 36 "google.golang.org/protobuf/proto" 37 ) 38 39 func TestProposer_GetBlock_OK(t *testing.T) { 40 db := dbutil.SetupDB(t) 41 ctx := context.Background() 42 43 params.SetupTestConfigCleanup(t) 44 params.OverrideBeaconConfig(params.MainnetConfig()) 45 beaconState, privKeys := testutil.DeterministicGenesisState(t, 64) 46 47 stateRoot, err := beaconState.HashTreeRoot(ctx) 48 require.NoError(t, err, "Could not hash genesis state") 49 50 genesis := b.NewGenesisBlock(stateRoot[:]) 51 require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(genesis)), "Could not save genesis block") 52 53 parentRoot, err := genesis.Block.HashTreeRoot() 54 require.NoError(t, err, "Could not get signing root") 55 require.NoError(t, db.SaveState(ctx, beaconState, parentRoot), "Could not save genesis state") 56 require.NoError(t, db.SaveHeadBlockRoot(ctx, parentRoot), "Could not save genesis state") 57 58 proposerServer := &Server{ 59 BeaconDB: db, 60 HeadFetcher: &mock.ChainService{State: beaconState, Root: parentRoot[:]}, 61 SyncChecker: &mockSync.Sync{IsSyncing: false}, 62 BlockReceiver: &mock.ChainService{}, 63 ChainStartFetcher: &mockPOW.POWChain{}, 64 Eth1InfoFetcher: &mockPOW.POWChain{}, 65 Eth1BlockFetcher: &mockPOW.POWChain{}, 66 MockEth1Votes: true, 67 AttPool: attestations.NewPool(), 68 SlashingsPool: slashings.NewPool(), 69 ExitPool: voluntaryexits.NewPool(), 70 StateGen: stategen.New(db), 71 } 72 73 randaoReveal, err := testutil.RandaoReveal(beaconState, 0, privKeys) 74 require.NoError(t, err) 75 76 graffiti := bytesutil.ToBytes32([]byte("eth2")) 77 req := ðpb.BlockRequest{ 78 Slot: 1, 79 RandaoReveal: randaoReveal, 80 Graffiti: graffiti[:], 81 } 82 83 proposerSlashings := make([]*ethpb.ProposerSlashing, params.BeaconConfig().MaxProposerSlashings) 84 for i := types.ValidatorIndex(0); uint64(i) < params.BeaconConfig().MaxProposerSlashings; i++ { 85 proposerSlashing, err := testutil.GenerateProposerSlashingForValidator( 86 beaconState, 87 privKeys[i], 88 i, /* validator index */ 89 ) 90 require.NoError(t, err) 91 proposerSlashings[i] = proposerSlashing 92 err = proposerServer.SlashingsPool.InsertProposerSlashing(context.Background(), beaconState, proposerSlashing) 93 require.NoError(t, err) 94 } 95 96 attSlashings := make([]*ethpb.AttesterSlashing, params.BeaconConfig().MaxAttesterSlashings) 97 for i := uint64(0); i < params.BeaconConfig().MaxAttesterSlashings; i++ { 98 attesterSlashing, err := testutil.GenerateAttesterSlashingForValidator( 99 beaconState, 100 privKeys[i+params.BeaconConfig().MaxProposerSlashings], 101 types.ValidatorIndex(i+params.BeaconConfig().MaxProposerSlashings), /* validator index */ 102 ) 103 require.NoError(t, err) 104 attSlashings[i] = attesterSlashing 105 err = proposerServer.SlashingsPool.InsertAttesterSlashing(context.Background(), beaconState, attesterSlashing) 106 require.NoError(t, err) 107 } 108 block, err := proposerServer.GetBlock(ctx, req) 109 require.NoError(t, err) 110 111 assert.Equal(t, req.Slot, block.Slot, "Expected block to have slot of 1") 112 assert.DeepEqual(t, parentRoot[:], block.ParentRoot, "Expected block to have correct parent root") 113 assert.DeepEqual(t, randaoReveal, block.Body.RandaoReveal, "Expected block to have correct randao reveal") 114 assert.DeepEqual(t, req.Graffiti, block.Body.Graffiti, "Expected block to have correct graffiti") 115 assert.Equal(t, params.BeaconConfig().MaxProposerSlashings, uint64(len(block.Body.ProposerSlashings))) 116 assert.DeepEqual(t, proposerSlashings, block.Body.ProposerSlashings) 117 assert.Equal(t, params.BeaconConfig().MaxAttesterSlashings, uint64(len(block.Body.AttesterSlashings))) 118 assert.DeepEqual(t, attSlashings, block.Body.AttesterSlashings) 119 } 120 121 func TestProposer_GetBlock_AddsUnaggregatedAtts(t *testing.T) { 122 db := dbutil.SetupDB(t) 123 ctx := context.Background() 124 125 params.SetupTestConfigCleanup(t) 126 params.OverrideBeaconConfig(params.MainnetConfig()) 127 beaconState, privKeys := testutil.DeterministicGenesisState(t, params.BeaconConfig().MinGenesisActiveValidatorCount) 128 129 stateRoot, err := beaconState.HashTreeRoot(ctx) 130 require.NoError(t, err, "Could not hash genesis state") 131 132 genesis := b.NewGenesisBlock(stateRoot[:]) 133 require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(genesis)), "Could not save genesis block") 134 135 parentRoot, err := genesis.Block.HashTreeRoot() 136 require.NoError(t, err, "Could not get signing root") 137 require.NoError(t, db.SaveState(ctx, beaconState, parentRoot), "Could not save genesis state") 138 require.NoError(t, db.SaveHeadBlockRoot(ctx, parentRoot), "Could not save genesis state") 139 140 proposerServer := &Server{ 141 BeaconDB: db, 142 HeadFetcher: &mock.ChainService{State: beaconState, Root: parentRoot[:]}, 143 SyncChecker: &mockSync.Sync{IsSyncing: false}, 144 BlockReceiver: &mock.ChainService{}, 145 ChainStartFetcher: &mockPOW.POWChain{}, 146 Eth1InfoFetcher: &mockPOW.POWChain{}, 147 Eth1BlockFetcher: &mockPOW.POWChain{}, 148 MockEth1Votes: true, 149 SlashingsPool: slashings.NewPool(), 150 AttPool: attestations.NewPool(), 151 ExitPool: voluntaryexits.NewPool(), 152 StateGen: stategen.New(db), 153 } 154 155 // Generate a bunch of random attestations at slot. These would be considered double votes, but 156 // we don't care for the purpose of this test. 157 var atts []*ethpb.Attestation 158 for i := uint64(0); len(atts) < int(params.BeaconConfig().MaxAttestations); i++ { 159 a, err := testutil.GenerateAttestations(beaconState, privKeys, 4, 1, true) 160 require.NoError(t, err) 161 atts = append(atts, a...) 162 } 163 // Max attestations minus one so we can almost fill the block and then include 1 unaggregated 164 // att to maximize inclusion. 165 atts = atts[:params.BeaconConfig().MaxAttestations-1] 166 require.NoError(t, proposerServer.AttPool.SaveAggregatedAttestations(atts)) 167 168 // Generate some more random attestations with a larger spread so that we can capture at least 169 // one unaggregated attestation. 170 atts, err = testutil.GenerateAttestations(beaconState, privKeys, 300, 1, true) 171 require.NoError(t, err) 172 found := false 173 for _, a := range atts { 174 if !helpers.IsAggregated(a) { 175 found = true 176 require.NoError(t, proposerServer.AttPool.SaveUnaggregatedAttestation(a)) 177 } 178 } 179 require.Equal(t, true, found, "No unaggregated attestations were generated") 180 181 randaoReveal, err := testutil.RandaoReveal(beaconState, 0, privKeys) 182 assert.NoError(t, err) 183 184 graffiti := bytesutil.ToBytes32([]byte("eth2")) 185 req := ðpb.BlockRequest{ 186 Slot: 1, 187 RandaoReveal: randaoReveal, 188 Graffiti: graffiti[:], 189 } 190 block, err := proposerServer.GetBlock(ctx, req) 191 require.NoError(t, err) 192 193 assert.Equal(t, req.Slot, block.Slot, "Expected block to have slot of 1") 194 assert.DeepEqual(t, parentRoot[:], block.ParentRoot, "Expected block to have correct parent root") 195 assert.DeepEqual(t, randaoReveal, block.Body.RandaoReveal, "Expected block to have correct randao reveal") 196 assert.DeepEqual(t, req.Graffiti, block.Body.Graffiti, "Expected block to have correct graffiti") 197 assert.Equal(t, params.BeaconConfig().MaxAttestations, uint64(len(block.Body.Attestations)), "Expected block atts to be aggregated down to 1") 198 hasUnaggregatedAtt := false 199 for _, a := range block.Body.Attestations { 200 if !helpers.IsAggregated(a) { 201 hasUnaggregatedAtt = true 202 break 203 } 204 } 205 assert.Equal(t, false, hasUnaggregatedAtt, "Expected block to not have unaggregated attestation") 206 } 207 208 func TestProposer_ProposeBlock_OK(t *testing.T) { 209 db := dbutil.SetupDB(t) 210 ctx := context.Background() 211 params.SetupTestConfigCleanup(t) 212 params.OverrideBeaconConfig(params.MainnetConfig()) 213 214 genesis := testutil.NewBeaconBlock() 215 require.NoError(t, db.SaveBlock(context.Background(), wrapper.WrappedPhase0SignedBeaconBlock(genesis)), "Could not save genesis block") 216 217 numDeposits := uint64(64) 218 beaconState, _ := testutil.DeterministicGenesisState(t, numDeposits) 219 bsRoot, err := beaconState.HashTreeRoot(ctx) 220 require.NoError(t, err) 221 genesisRoot, err := genesis.Block.HashTreeRoot() 222 require.NoError(t, err) 223 require.NoError(t, db.SaveState(ctx, beaconState, genesisRoot), "Could not save genesis state") 224 225 c := &mock.ChainService{Root: bsRoot[:], State: beaconState} 226 proposerServer := &Server{ 227 BeaconDB: db, 228 ChainStartFetcher: &mockPOW.POWChain{}, 229 Eth1InfoFetcher: &mockPOW.POWChain{}, 230 Eth1BlockFetcher: &mockPOW.POWChain{}, 231 BlockReceiver: c, 232 HeadFetcher: c, 233 BlockNotifier: c.BlockNotifier(), 234 P2P: mockp2p.NewTestP2P(t), 235 } 236 req := testutil.NewBeaconBlock() 237 req.Block.Slot = 5 238 req.Block.ParentRoot = bsRoot[:] 239 require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(req))) 240 _, err = proposerServer.ProposeBlock(context.Background(), req) 241 assert.NoError(t, err, "Could not propose block correctly") 242 } 243 244 func TestProposer_ComputeStateRoot_OK(t *testing.T) { 245 db := dbutil.SetupDB(t) 246 ctx := context.Background() 247 248 params.SetupTestConfigCleanup(t) 249 params.OverrideBeaconConfig(params.MainnetConfig()) 250 beaconState, privKeys := testutil.DeterministicGenesisState(t, 100) 251 252 stateRoot, err := beaconState.HashTreeRoot(ctx) 253 require.NoError(t, err, "Could not hash genesis state") 254 255 genesis := b.NewGenesisBlock(stateRoot[:]) 256 require.NoError(t, db.SaveBlock(ctx, wrapper.WrappedPhase0SignedBeaconBlock(genesis)), "Could not save genesis block") 257 258 parentRoot, err := genesis.Block.HashTreeRoot() 259 require.NoError(t, err, "Could not get signing root") 260 require.NoError(t, db.SaveState(ctx, beaconState, parentRoot), "Could not save genesis state") 261 require.NoError(t, db.SaveHeadBlockRoot(ctx, parentRoot), "Could not save genesis state") 262 263 proposerServer := &Server{ 264 BeaconDB: db, 265 ChainStartFetcher: &mockPOW.POWChain{}, 266 Eth1InfoFetcher: &mockPOW.POWChain{}, 267 Eth1BlockFetcher: &mockPOW.POWChain{}, 268 StateGen: stategen.New(db), 269 } 270 req := testutil.NewBeaconBlock() 271 req.Block.ProposerIndex = 21 272 req.Block.ParentRoot = parentRoot[:] 273 req.Block.Slot = 1 274 require.NoError(t, beaconState.SetSlot(beaconState.Slot()+1)) 275 randaoReveal, err := testutil.RandaoReveal(beaconState, 0, privKeys) 276 require.NoError(t, err) 277 proposerIdx, err := helpers.BeaconProposerIndex(beaconState) 278 require.NoError(t, err) 279 require.NoError(t, beaconState.SetSlot(beaconState.Slot()-1)) 280 req.Block.Body.RandaoReveal = randaoReveal 281 currentEpoch := helpers.CurrentEpoch(beaconState) 282 req.Signature, err = helpers.ComputeDomainAndSign(beaconState, currentEpoch, req.Block, params.BeaconConfig().DomainBeaconProposer, privKeys[proposerIdx]) 283 require.NoError(t, err) 284 285 _, err = proposerServer.computeStateRoot(context.Background(), wrapper.WrappedPhase0SignedBeaconBlock(req)) 286 require.NoError(t, err) 287 } 288 289 func TestProposer_PendingDeposits_Eth1DataVoteOK(t *testing.T) { 290 ctx := context.Background() 291 292 height := big.NewInt(int64(params.BeaconConfig().Eth1FollowDistance)) 293 newHeight := big.NewInt(height.Int64() + 11000) 294 p := &mockPOW.POWChain{ 295 LatestBlockNumber: height, 296 HashesByHeight: map[int][]byte{ 297 int(height.Int64()): []byte("0x0"), 298 int(newHeight.Int64()): []byte("0x1"), 299 }, 300 } 301 302 var votes []*ethpb.Eth1Data 303 304 blockHash := make([]byte, 32) 305 copy(blockHash, "0x1") 306 vote := ðpb.Eth1Data{ 307 DepositRoot: make([]byte, 32), 308 BlockHash: blockHash, 309 DepositCount: 3, 310 } 311 period := uint64(params.BeaconConfig().SlotsPerEpoch.Mul(uint64(params.BeaconConfig().EpochsPerEth1VotingPeriod))) 312 for i := 0; i <= int(period/2); i++ { 313 votes = append(votes, vote) 314 } 315 316 blockHash = make([]byte, 32) 317 copy(blockHash, "0x0") 318 beaconState, err := testutil.NewBeaconState() 319 require.NoError(t, err) 320 require.NoError(t, beaconState.SetEth1DepositIndex(2)) 321 require.NoError(t, beaconState.SetEth1Data(ðpb.Eth1Data{ 322 DepositRoot: make([]byte, 32), 323 BlockHash: blockHash, 324 DepositCount: 2, 325 })) 326 require.NoError(t, beaconState.SetEth1DataVotes(votes)) 327 328 blk := testutil.NewBeaconBlock() 329 blkRoot, err := blk.Block.HashTreeRoot() 330 require.NoError(t, err) 331 332 bs := &Server{ 333 ChainStartFetcher: p, 334 Eth1InfoFetcher: p, 335 Eth1BlockFetcher: p, 336 BlockReceiver: &mock.ChainService{State: beaconState, Root: blkRoot[:]}, 337 HeadFetcher: &mock.ChainService{State: beaconState, Root: blkRoot[:]}, 338 } 339 340 // It should also return the recent deposits after their follow window. 341 p.LatestBlockNumber = big.NewInt(0).Add(p.LatestBlockNumber, big.NewInt(10000)) 342 _, eth1Height, err := bs.canonicalEth1Data(ctx, beaconState, ðpb.Eth1Data{}) 343 require.NoError(t, err) 344 345 assert.Equal(t, 0, eth1Height.Cmp(height)) 346 347 newState, err := b.ProcessEth1DataInBlock(ctx, beaconState, blk.Block.Body.Eth1Data) 348 require.NoError(t, err) 349 350 if proto.Equal(newState.Eth1Data(), vote) { 351 t.Errorf("eth1data in the state equal to vote, when not expected to"+ 352 "have majority: Got %v", vote) 353 } 354 355 blk.Block.Body.Eth1Data = vote 356 357 _, eth1Height, err = bs.canonicalEth1Data(ctx, beaconState, vote) 358 require.NoError(t, err) 359 assert.Equal(t, 0, eth1Height.Cmp(newHeight)) 360 361 newState, err = b.ProcessEth1DataInBlock(ctx, beaconState, blk.Block.Body.Eth1Data) 362 require.NoError(t, err) 363 364 if !proto.Equal(newState.Eth1Data(), vote) { 365 t.Errorf("eth1data in the state not of the expected kind: Got %v but wanted %v", newState.Eth1Data(), vote) 366 } 367 } 368 369 func TestProposer_PendingDeposits_OutsideEth1FollowWindow(t *testing.T) { 370 ctx := context.Background() 371 372 height := big.NewInt(int64(params.BeaconConfig().Eth1FollowDistance)) 373 p := &mockPOW.POWChain{ 374 LatestBlockNumber: height, 375 HashesByHeight: map[int][]byte{ 376 int(height.Int64()): []byte("0x0"), 377 }, 378 } 379 380 beaconState, err := v1.InitializeFromProto(&pbp2p.BeaconState{ 381 Eth1Data: ðpb.Eth1Data{ 382 BlockHash: bytesutil.PadTo([]byte("0x0"), 32), 383 DepositRoot: make([]byte, 32), 384 }, 385 Eth1DepositIndex: 2, 386 }) 387 require.NoError(t, err) 388 389 var mockSig [96]byte 390 var mockCreds [32]byte 391 392 // Using the merkleTreeIndex as the block number for this test... 393 readyDeposits := []*dbpb.DepositContainer{ 394 { 395 Index: 0, 396 Eth1BlockHeight: 2, 397 Deposit: ðpb.Deposit{ 398 Data: ðpb.Deposit_Data{ 399 PublicKey: bytesutil.PadTo([]byte("a"), 48), 400 Signature: mockSig[:], 401 WithdrawalCredentials: mockCreds[:], 402 }}, 403 }, 404 { 405 Index: 1, 406 Eth1BlockHeight: 8, 407 Deposit: ðpb.Deposit{ 408 Data: ðpb.Deposit_Data{ 409 PublicKey: bytesutil.PadTo([]byte("b"), 48), 410 Signature: mockSig[:], 411 WithdrawalCredentials: mockCreds[:], 412 }}, 413 }, 414 } 415 416 recentDeposits := []*dbpb.DepositContainer{ 417 { 418 Index: 2, 419 Eth1BlockHeight: 400, 420 Deposit: ðpb.Deposit{ 421 Data: ðpb.Deposit_Data{ 422 PublicKey: bytesutil.PadTo([]byte("c"), 48), 423 Signature: mockSig[:], 424 WithdrawalCredentials: mockCreds[:], 425 }}, 426 }, 427 { 428 Index: 3, 429 Eth1BlockHeight: 600, 430 Deposit: ðpb.Deposit{ 431 Data: ðpb.Deposit_Data{ 432 PublicKey: bytesutil.PadTo([]byte("d"), 48), 433 Signature: mockSig[:], 434 WithdrawalCredentials: mockCreds[:], 435 }}, 436 }, 437 } 438 439 depositCache, err := depositcache.New() 440 require.NoError(t, err) 441 442 depositTrie, err := trieutil.NewTrie(params.BeaconConfig().DepositContractTreeDepth) 443 require.NoError(t, err, "Could not setup deposit trie") 444 for _, dp := range append(readyDeposits, recentDeposits...) { 445 depositHash, err := dp.Deposit.Data.HashTreeRoot() 446 require.NoError(t, err, "Unable to determine hashed value of deposit") 447 448 depositTrie.Insert(depositHash[:], int(dp.Index)) 449 assert.NoError(t, depositCache.InsertDeposit(ctx, dp.Deposit, dp.Eth1BlockHeight, dp.Index, depositTrie.Root())) 450 } 451 for _, dp := range recentDeposits { 452 depositCache.InsertPendingDeposit(ctx, dp.Deposit, dp.Eth1BlockHeight, dp.Index, depositTrie.Root()) 453 } 454 455 blk := testutil.NewBeaconBlock() 456 blk.Block.Slot = beaconState.Slot() 457 458 blkRoot, err := blk.HashTreeRoot() 459 require.NoError(t, err) 460 461 bs := &Server{ 462 ChainStartFetcher: p, 463 Eth1InfoFetcher: p, 464 Eth1BlockFetcher: p, 465 DepositFetcher: depositCache, 466 PendingDepositsFetcher: depositCache, 467 BlockReceiver: &mock.ChainService{State: beaconState, Root: blkRoot[:]}, 468 HeadFetcher: &mock.ChainService{State: beaconState, Root: blkRoot[:]}, 469 } 470 471 deposits, err := bs.deposits(ctx, beaconState, ðpb.Eth1Data{}) 472 require.NoError(t, err) 473 assert.Equal(t, 0, len(deposits), "Received unexpected list of deposits") 474 475 // It should not return the recent deposits after their follow window. 476 // as latest block number makes no difference in retrieval of deposits 477 p.LatestBlockNumber = big.NewInt(0).Add(p.LatestBlockNumber, big.NewInt(10000)) 478 deposits, err = bs.deposits(ctx, beaconState, ðpb.Eth1Data{}) 479 require.NoError(t, err) 480 assert.Equal(t, 0, len(deposits), "Received unexpected number of pending deposits") 481 } 482 483 func TestProposer_PendingDeposits_FollowsCorrectEth1Block(t *testing.T) { 484 ctx := context.Background() 485 486 height := big.NewInt(int64(params.BeaconConfig().Eth1FollowDistance)) 487 newHeight := big.NewInt(height.Int64() + 11000) 488 p := &mockPOW.POWChain{ 489 LatestBlockNumber: height, 490 HashesByHeight: map[int][]byte{ 491 int(height.Int64()): []byte("0x0"), 492 int(newHeight.Int64()): []byte("0x1"), 493 }, 494 } 495 496 var votes []*ethpb.Eth1Data 497 498 vote := ðpb.Eth1Data{ 499 BlockHash: bytesutil.PadTo([]byte("0x1"), 32), 500 DepositRoot: make([]byte, 32), 501 DepositCount: 7, 502 } 503 period := uint64(params.BeaconConfig().SlotsPerEpoch.Mul(uint64(params.BeaconConfig().EpochsPerEth1VotingPeriod))) 504 for i := 0; i <= int(period/2); i++ { 505 votes = append(votes, vote) 506 } 507 508 beaconState, err := v1.InitializeFromProto(&pbp2p.BeaconState{ 509 Eth1Data: ðpb.Eth1Data{ 510 BlockHash: []byte("0x0"), 511 DepositRoot: make([]byte, 32), 512 DepositCount: 5, 513 }, 514 Eth1DepositIndex: 1, 515 Eth1DataVotes: votes, 516 }) 517 require.NoError(t, err) 518 blk := testutil.NewBeaconBlock() 519 blk.Block.Slot = beaconState.Slot() 520 521 blkRoot, err := blk.HashTreeRoot() 522 require.NoError(t, err) 523 524 var mockSig [96]byte 525 var mockCreds [32]byte 526 527 // Using the merkleTreeIndex as the block number for this test... 528 readyDeposits := []*dbpb.DepositContainer{ 529 { 530 Index: 0, 531 Eth1BlockHeight: 8, 532 Deposit: ðpb.Deposit{ 533 Data: ðpb.Deposit_Data{ 534 PublicKey: bytesutil.PadTo([]byte("a"), 48), 535 Signature: mockSig[:], 536 WithdrawalCredentials: mockCreds[:], 537 }}, 538 }, 539 { 540 Index: 1, 541 Eth1BlockHeight: 14, 542 Deposit: ðpb.Deposit{ 543 Data: ðpb.Deposit_Data{ 544 PublicKey: bytesutil.PadTo([]byte("b"), 48), 545 Signature: mockSig[:], 546 WithdrawalCredentials: mockCreds[:], 547 }}, 548 }, 549 } 550 551 recentDeposits := []*dbpb.DepositContainer{ 552 { 553 Index: 2, 554 Eth1BlockHeight: 5000, 555 Deposit: ðpb.Deposit{ 556 Data: ðpb.Deposit_Data{ 557 PublicKey: bytesutil.PadTo([]byte("c"), 48), 558 Signature: mockSig[:], 559 WithdrawalCredentials: mockCreds[:], 560 }}, 561 }, 562 { 563 Index: 3, 564 Eth1BlockHeight: 6000, 565 Deposit: ðpb.Deposit{ 566 Data: ðpb.Deposit_Data{ 567 PublicKey: bytesutil.PadTo([]byte("d"), 48), 568 Signature: mockSig[:], 569 WithdrawalCredentials: mockCreds[:], 570 }}, 571 }, 572 } 573 574 depositCache, err := depositcache.New() 575 require.NoError(t, err) 576 577 depositTrie, err := trieutil.NewTrie(params.BeaconConfig().DepositContractTreeDepth) 578 require.NoError(t, err, "Could not setup deposit trie") 579 for _, dp := range append(readyDeposits, recentDeposits...) { 580 depositHash, err := dp.Deposit.Data.HashTreeRoot() 581 require.NoError(t, err, "Unable to determine hashed value of deposit") 582 583 depositTrie.Insert(depositHash[:], int(dp.Index)) 584 assert.NoError(t, depositCache.InsertDeposit(ctx, dp.Deposit, dp.Eth1BlockHeight, dp.Index, depositTrie.Root())) 585 } 586 for _, dp := range recentDeposits { 587 depositCache.InsertPendingDeposit(ctx, dp.Deposit, dp.Eth1BlockHeight, dp.Index, depositTrie.Root()) 588 } 589 590 bs := &Server{ 591 ChainStartFetcher: p, 592 Eth1InfoFetcher: p, 593 Eth1BlockFetcher: p, 594 DepositFetcher: depositCache, 595 PendingDepositsFetcher: depositCache, 596 BlockReceiver: &mock.ChainService{State: beaconState, Root: blkRoot[:]}, 597 HeadFetcher: &mock.ChainService{State: beaconState, Root: blkRoot[:]}, 598 } 599 600 deposits, err := bs.deposits(ctx, beaconState, ðpb.Eth1Data{}) 601 require.NoError(t, err) 602 assert.Equal(t, 0, len(deposits), "Received unexpected list of deposits") 603 604 // It should also return the recent deposits after their follow window. 605 p.LatestBlockNumber = big.NewInt(0).Add(p.LatestBlockNumber, big.NewInt(10000)) 606 // we should get our pending deposits once this vote pushes the vote tally to include 607 // the updated eth1 data. 608 deposits, err = bs.deposits(ctx, beaconState, vote) 609 require.NoError(t, err) 610 assert.Equal(t, len(recentDeposits), len(deposits), "Received unexpected number of pending deposits") 611 } 612 613 func TestProposer_PendingDeposits_CantReturnBelowStateEth1DepositIndex(t *testing.T) { 614 ctx := context.Background() 615 height := big.NewInt(int64(params.BeaconConfig().Eth1FollowDistance)) 616 p := &mockPOW.POWChain{ 617 LatestBlockNumber: height, 618 HashesByHeight: map[int][]byte{ 619 int(height.Int64()): []byte("0x0"), 620 }, 621 } 622 623 beaconState, err := testutil.NewBeaconState() 624 require.NoError(t, err) 625 require.NoError(t, beaconState.SetEth1Data(ðpb.Eth1Data{ 626 BlockHash: bytesutil.PadTo([]byte("0x0"), 32), 627 DepositRoot: make([]byte, 32), 628 DepositCount: 100, 629 })) 630 require.NoError(t, beaconState.SetEth1DepositIndex(10)) 631 blk := testutil.NewBeaconBlock() 632 blk.Block.Slot = beaconState.Slot() 633 blkRoot, err := blk.HashTreeRoot() 634 require.NoError(t, err) 635 636 var mockSig [96]byte 637 var mockCreds [32]byte 638 639 readyDeposits := []*dbpb.DepositContainer{ 640 { 641 Index: 0, 642 Deposit: ðpb.Deposit{ 643 Data: ðpb.Deposit_Data{ 644 PublicKey: bytesutil.PadTo([]byte("a"), 48), 645 Signature: mockSig[:], 646 WithdrawalCredentials: mockCreds[:], 647 }}, 648 }, 649 { 650 Index: 1, 651 Deposit: ðpb.Deposit{ 652 Data: ðpb.Deposit_Data{ 653 PublicKey: bytesutil.PadTo([]byte("b"), 48), 654 Signature: mockSig[:], 655 WithdrawalCredentials: mockCreds[:], 656 }}, 657 }, 658 } 659 660 var recentDeposits []*dbpb.DepositContainer 661 for i := int64(2); i < 16; i++ { 662 recentDeposits = append(recentDeposits, &dbpb.DepositContainer{ 663 Index: i, 664 Deposit: ðpb.Deposit{ 665 Data: ðpb.Deposit_Data{ 666 PublicKey: bytesutil.PadTo([]byte{byte(i)}, 48), 667 Signature: mockSig[:], 668 WithdrawalCredentials: mockCreds[:], 669 }}, 670 }) 671 } 672 depositTrie, err := trieutil.NewTrie(params.BeaconConfig().DepositContractTreeDepth) 673 require.NoError(t, err, "Could not setup deposit trie") 674 675 depositCache, err := depositcache.New() 676 require.NoError(t, err) 677 678 for _, dp := range append(readyDeposits, recentDeposits...) { 679 depositHash, err := dp.Deposit.Data.HashTreeRoot() 680 require.NoError(t, err, "Unable to determine hashed value of deposit") 681 682 depositTrie.Insert(depositHash[:], int(dp.Index)) 683 assert.NoError(t, depositCache.InsertDeposit(ctx, dp.Deposit, uint64(dp.Index), dp.Index, depositTrie.Root())) 684 } 685 for _, dp := range recentDeposits { 686 depositCache.InsertPendingDeposit(ctx, dp.Deposit, uint64(dp.Index), dp.Index, depositTrie.Root()) 687 } 688 689 bs := &Server{ 690 ChainStartFetcher: p, 691 Eth1InfoFetcher: p, 692 Eth1BlockFetcher: p, 693 DepositFetcher: depositCache, 694 PendingDepositsFetcher: depositCache, 695 BlockReceiver: &mock.ChainService{State: beaconState, Root: blkRoot[:]}, 696 HeadFetcher: &mock.ChainService{State: beaconState, Root: blkRoot[:]}, 697 } 698 699 // It should also return the recent deposits after their follow window. 700 p.LatestBlockNumber = big.NewInt(0).Add(p.LatestBlockNumber, big.NewInt(10000)) 701 deposits, err := bs.deposits(ctx, beaconState, ðpb.Eth1Data{}) 702 require.NoError(t, err) 703 704 expectedDeposits := 6 705 assert.Equal(t, expectedDeposits, len(deposits), "Received unexpected number of pending deposits") 706 } 707 708 func TestProposer_PendingDeposits_CantReturnMoreThanMax(t *testing.T) { 709 ctx := context.Background() 710 711 height := big.NewInt(int64(params.BeaconConfig().Eth1FollowDistance)) 712 p := &mockPOW.POWChain{ 713 LatestBlockNumber: height, 714 HashesByHeight: map[int][]byte{ 715 int(height.Int64()): []byte("0x0"), 716 }, 717 } 718 719 beaconState, err := v1.InitializeFromProto(&pbp2p.BeaconState{ 720 Eth1Data: ðpb.Eth1Data{ 721 BlockHash: bytesutil.PadTo([]byte("0x0"), 32), 722 DepositRoot: make([]byte, 32), 723 DepositCount: 100, 724 }, 725 Eth1DepositIndex: 2, 726 }) 727 require.NoError(t, err) 728 blk := testutil.NewBeaconBlock() 729 blk.Block.Slot = beaconState.Slot() 730 blkRoot, err := blk.HashTreeRoot() 731 require.NoError(t, err) 732 var mockSig [96]byte 733 var mockCreds [32]byte 734 735 readyDeposits := []*dbpb.DepositContainer{ 736 { 737 Index: 0, 738 Deposit: ðpb.Deposit{ 739 Data: ðpb.Deposit_Data{ 740 PublicKey: bytesutil.PadTo([]byte("a"), 48), 741 Signature: mockSig[:], 742 WithdrawalCredentials: mockCreds[:], 743 }}, 744 }, 745 { 746 Index: 1, 747 Deposit: ðpb.Deposit{ 748 Data: ðpb.Deposit_Data{ 749 PublicKey: bytesutil.PadTo([]byte("b"), 48), 750 Signature: mockSig[:], 751 WithdrawalCredentials: mockCreds[:], 752 }}, 753 }, 754 } 755 756 var recentDeposits []*dbpb.DepositContainer 757 for i := int64(2); i < 22; i++ { 758 recentDeposits = append(recentDeposits, &dbpb.DepositContainer{ 759 Index: i, 760 Deposit: ðpb.Deposit{ 761 Data: ðpb.Deposit_Data{ 762 PublicKey: bytesutil.PadTo([]byte{byte(i)}, 48), 763 Signature: mockSig[:], 764 WithdrawalCredentials: mockCreds[:], 765 }}, 766 }) 767 } 768 depositTrie, err := trieutil.NewTrie(params.BeaconConfig().DepositContractTreeDepth) 769 require.NoError(t, err, "Could not setup deposit trie") 770 771 depositCache, err := depositcache.New() 772 require.NoError(t, err) 773 774 for _, dp := range append(readyDeposits, recentDeposits...) { 775 depositHash, err := dp.Deposit.Data.HashTreeRoot() 776 require.NoError(t, err, "Unable to determine hashed value of deposit") 777 778 depositTrie.Insert(depositHash[:], int(dp.Index)) 779 assert.NoError(t, depositCache.InsertDeposit(ctx, dp.Deposit, height.Uint64(), dp.Index, depositTrie.Root())) 780 } 781 for _, dp := range recentDeposits { 782 depositCache.InsertPendingDeposit(ctx, dp.Deposit, height.Uint64(), dp.Index, depositTrie.Root()) 783 } 784 785 bs := &Server{ 786 ChainStartFetcher: p, 787 Eth1InfoFetcher: p, 788 Eth1BlockFetcher: p, 789 DepositFetcher: depositCache, 790 PendingDepositsFetcher: depositCache, 791 BlockReceiver: &mock.ChainService{State: beaconState, Root: blkRoot[:]}, 792 HeadFetcher: &mock.ChainService{State: beaconState, Root: blkRoot[:]}, 793 } 794 795 // It should also return the recent deposits after their follow window. 796 p.LatestBlockNumber = big.NewInt(0).Add(p.LatestBlockNumber, big.NewInt(10000)) 797 deposits, err := bs.deposits(ctx, beaconState, ðpb.Eth1Data{}) 798 require.NoError(t, err) 799 assert.Equal(t, params.BeaconConfig().MaxDeposits, uint64(len(deposits)), "Received unexpected number of pending deposits") 800 } 801 802 func TestProposer_PendingDeposits_CantReturnMoreThanDepositCount(t *testing.T) { 803 ctx := context.Background() 804 805 height := big.NewInt(int64(params.BeaconConfig().Eth1FollowDistance)) 806 p := &mockPOW.POWChain{ 807 LatestBlockNumber: height, 808 HashesByHeight: map[int][]byte{ 809 int(height.Int64()): []byte("0x0"), 810 }, 811 } 812 813 beaconState, err := v1.InitializeFromProto(&pbp2p.BeaconState{ 814 Eth1Data: ðpb.Eth1Data{ 815 BlockHash: bytesutil.PadTo([]byte("0x0"), 32), 816 DepositRoot: make([]byte, 32), 817 DepositCount: 5, 818 }, 819 Eth1DepositIndex: 2, 820 }) 821 require.NoError(t, err) 822 blk := testutil.NewBeaconBlock() 823 blk.Block.Slot = beaconState.Slot() 824 blkRoot, err := blk.HashTreeRoot() 825 require.NoError(t, err) 826 var mockSig [96]byte 827 var mockCreds [32]byte 828 829 readyDeposits := []*dbpb.DepositContainer{ 830 { 831 Index: 0, 832 Deposit: ðpb.Deposit{ 833 Data: ðpb.Deposit_Data{ 834 PublicKey: bytesutil.PadTo([]byte("a"), 48), 835 Signature: mockSig[:], 836 WithdrawalCredentials: mockCreds[:], 837 }}, 838 }, 839 { 840 Index: 1, 841 Deposit: ðpb.Deposit{ 842 Data: ðpb.Deposit_Data{ 843 PublicKey: bytesutil.PadTo([]byte("b"), 48), 844 Signature: mockSig[:], 845 WithdrawalCredentials: mockCreds[:], 846 }}, 847 }, 848 } 849 850 var recentDeposits []*dbpb.DepositContainer 851 for i := int64(2); i < 22; i++ { 852 recentDeposits = append(recentDeposits, &dbpb.DepositContainer{ 853 Index: i, 854 Deposit: ðpb.Deposit{ 855 Data: ðpb.Deposit_Data{ 856 PublicKey: bytesutil.PadTo([]byte{byte(i)}, 48), 857 Signature: mockSig[:], 858 WithdrawalCredentials: mockCreds[:], 859 }}, 860 }) 861 } 862 depositTrie, err := trieutil.NewTrie(params.BeaconConfig().DepositContractTreeDepth) 863 require.NoError(t, err, "Could not setup deposit trie") 864 865 depositCache, err := depositcache.New() 866 require.NoError(t, err) 867 868 for _, dp := range append(readyDeposits, recentDeposits...) { 869 depositHash, err := dp.Deposit.Data.HashTreeRoot() 870 require.NoError(t, err, "Unable to determine hashed value of deposit") 871 872 depositTrie.Insert(depositHash[:], int(dp.Index)) 873 assert.NoError(t, depositCache.InsertDeposit(ctx, dp.Deposit, uint64(dp.Index), dp.Index, depositTrie.Root())) 874 } 875 for _, dp := range recentDeposits { 876 depositCache.InsertPendingDeposit(ctx, dp.Deposit, uint64(dp.Index), dp.Index, depositTrie.Root()) 877 } 878 879 bs := &Server{ 880 BlockReceiver: &mock.ChainService{State: beaconState, Root: blkRoot[:]}, 881 HeadFetcher: &mock.ChainService{State: beaconState, Root: blkRoot[:]}, 882 ChainStartFetcher: p, 883 Eth1InfoFetcher: p, 884 Eth1BlockFetcher: p, 885 DepositFetcher: depositCache, 886 PendingDepositsFetcher: depositCache, 887 } 888 889 // It should also return the recent deposits after their follow window. 890 p.LatestBlockNumber = big.NewInt(0).Add(p.LatestBlockNumber, big.NewInt(10000)) 891 deposits, err := bs.deposits(ctx, beaconState, ðpb.Eth1Data{}) 892 require.NoError(t, err) 893 assert.Equal(t, 3, len(deposits), "Received unexpected number of pending deposits") 894 } 895 896 func TestProposer_DepositTrie_UtilizesCachedFinalizedDeposits(t *testing.T) { 897 ctx := context.Background() 898 899 height := big.NewInt(int64(params.BeaconConfig().Eth1FollowDistance)) 900 p := &mockPOW.POWChain{ 901 LatestBlockNumber: height, 902 HashesByHeight: map[int][]byte{ 903 int(height.Int64()): []byte("0x0"), 904 }, 905 } 906 907 beaconState, err := v1.InitializeFromProto(&pbp2p.BeaconState{ 908 Eth1Data: ðpb.Eth1Data{ 909 BlockHash: bytesutil.PadTo([]byte("0x0"), 32), 910 DepositRoot: make([]byte, 32), 911 DepositCount: 4, 912 }, 913 Eth1DepositIndex: 1, 914 }) 915 require.NoError(t, err) 916 blk := testutil.NewBeaconBlock() 917 blk.Block.Slot = beaconState.Slot() 918 919 blkRoot, err := blk.Block.HashTreeRoot() 920 require.NoError(t, err) 921 922 var mockSig [96]byte 923 var mockCreds [32]byte 924 925 // Using the merkleTreeIndex as the block number for this test... 926 finalizedDeposits := []*dbpb.DepositContainer{ 927 { 928 Index: 0, 929 Eth1BlockHeight: 10, 930 Deposit: ðpb.Deposit{ 931 Data: ðpb.Deposit_Data{ 932 PublicKey: bytesutil.PadTo([]byte("a"), 48), 933 Signature: mockSig[:], 934 WithdrawalCredentials: mockCreds[:], 935 }}, 936 }, 937 { 938 Index: 1, 939 Eth1BlockHeight: 10, 940 Deposit: ðpb.Deposit{ 941 Data: ðpb.Deposit_Data{ 942 PublicKey: bytesutil.PadTo([]byte("b"), 48), 943 Signature: mockSig[:], 944 WithdrawalCredentials: mockCreds[:], 945 }}, 946 }, 947 } 948 949 recentDeposits := []*dbpb.DepositContainer{ 950 { 951 Index: 2, 952 Eth1BlockHeight: 11, 953 Deposit: ðpb.Deposit{ 954 Data: ðpb.Deposit_Data{ 955 PublicKey: bytesutil.PadTo([]byte("c"), 48), 956 Signature: mockSig[:], 957 WithdrawalCredentials: mockCreds[:], 958 }}, 959 }, 960 { 961 Index: 3, 962 Eth1BlockHeight: 11, 963 Deposit: ðpb.Deposit{ 964 Data: ðpb.Deposit_Data{ 965 PublicKey: bytesutil.PadTo([]byte("d"), 48), 966 Signature: mockSig[:], 967 WithdrawalCredentials: mockCreds[:], 968 }}, 969 }, 970 } 971 972 depositCache, err := depositcache.New() 973 require.NoError(t, err) 974 975 depositTrie, err := trieutil.NewTrie(params.BeaconConfig().DepositContractTreeDepth) 976 require.NoError(t, err, "Could not setup deposit trie") 977 for _, dp := range append(finalizedDeposits, recentDeposits...) { 978 depositHash, err := dp.Deposit.Data.HashTreeRoot() 979 require.NoError(t, err, "Unable to determine hashed value of deposit") 980 981 depositTrie.Insert(depositHash[:], int(dp.Index)) 982 assert.NoError(t, depositCache.InsertDeposit(ctx, dp.Deposit, dp.Eth1BlockHeight, dp.Index, depositTrie.Root())) 983 } 984 for _, dp := range recentDeposits { 985 depositCache.InsertPendingDeposit(ctx, dp.Deposit, dp.Eth1BlockHeight, dp.Index, depositTrie.Root()) 986 } 987 988 bs := &Server{ 989 ChainStartFetcher: p, 990 Eth1InfoFetcher: p, 991 Eth1BlockFetcher: p, 992 DepositFetcher: depositCache, 993 PendingDepositsFetcher: depositCache, 994 BlockReceiver: &mock.ChainService{State: beaconState, Root: blkRoot[:]}, 995 HeadFetcher: &mock.ChainService{State: beaconState, Root: blkRoot[:]}, 996 } 997 998 trie, err := bs.depositTrie(ctx, ðpb.Eth1Data{}, big.NewInt(int64(params.BeaconConfig().Eth1FollowDistance))) 999 require.NoError(t, err) 1000 1001 actualRoot := trie.HashTreeRoot() 1002 expectedRoot := depositTrie.HashTreeRoot() 1003 assert.Equal(t, expectedRoot, actualRoot, "Incorrect deposit trie root") 1004 } 1005 1006 func TestProposer_DepositTrie_RebuildTrie(t *testing.T) { 1007 ctx := context.Background() 1008 1009 height := big.NewInt(int64(params.BeaconConfig().Eth1FollowDistance)) 1010 p := &mockPOW.POWChain{ 1011 LatestBlockNumber: height, 1012 HashesByHeight: map[int][]byte{ 1013 int(height.Int64()): []byte("0x0"), 1014 }, 1015 } 1016 1017 beaconState, err := v1.InitializeFromProto(&pbp2p.BeaconState{ 1018 Eth1Data: ðpb.Eth1Data{ 1019 BlockHash: bytesutil.PadTo([]byte("0x0"), 32), 1020 DepositRoot: make([]byte, 32), 1021 DepositCount: 4, 1022 }, 1023 Eth1DepositIndex: 1, 1024 }) 1025 require.NoError(t, err) 1026 blk := testutil.NewBeaconBlock() 1027 blk.Block.Slot = beaconState.Slot() 1028 1029 blkRoot, err := blk.Block.HashTreeRoot() 1030 require.NoError(t, err) 1031 1032 var mockSig [96]byte 1033 var mockCreds [32]byte 1034 1035 // Using the merkleTreeIndex as the block number for this test... 1036 finalizedDeposits := []*dbpb.DepositContainer{ 1037 { 1038 Index: 0, 1039 Eth1BlockHeight: 10, 1040 Deposit: ðpb.Deposit{ 1041 Data: ðpb.Deposit_Data{ 1042 PublicKey: bytesutil.PadTo([]byte("a"), 48), 1043 Signature: mockSig[:], 1044 WithdrawalCredentials: mockCreds[:], 1045 }}, 1046 }, 1047 { 1048 Index: 1, 1049 Eth1BlockHeight: 10, 1050 Deposit: ðpb.Deposit{ 1051 Data: ðpb.Deposit_Data{ 1052 PublicKey: bytesutil.PadTo([]byte("b"), 48), 1053 Signature: mockSig[:], 1054 WithdrawalCredentials: mockCreds[:], 1055 }}, 1056 }, 1057 } 1058 1059 recentDeposits := []*dbpb.DepositContainer{ 1060 { 1061 Index: 2, 1062 Eth1BlockHeight: 11, 1063 Deposit: ðpb.Deposit{ 1064 Data: ðpb.Deposit_Data{ 1065 PublicKey: bytesutil.PadTo([]byte("c"), 48), 1066 Signature: mockSig[:], 1067 WithdrawalCredentials: mockCreds[:], 1068 }}, 1069 }, 1070 { 1071 Index: 3, 1072 Eth1BlockHeight: 11, 1073 Deposit: ðpb.Deposit{ 1074 Data: ðpb.Deposit_Data{ 1075 PublicKey: bytesutil.PadTo([]byte("d"), 48), 1076 Signature: mockSig[:], 1077 WithdrawalCredentials: mockCreds[:], 1078 }}, 1079 }, 1080 } 1081 1082 depositCache, err := depositcache.New() 1083 require.NoError(t, err) 1084 1085 depositTrie, err := trieutil.NewTrie(params.BeaconConfig().DepositContractTreeDepth) 1086 require.NoError(t, err, "Could not setup deposit trie") 1087 for _, dp := range append(finalizedDeposits, recentDeposits...) { 1088 depositHash, err := dp.Deposit.Data.HashTreeRoot() 1089 require.NoError(t, err, "Unable to determine hashed value of deposit") 1090 1091 depositTrie.Insert(depositHash[:], int(dp.Index)) 1092 assert.NoError(t, depositCache.InsertDeposit(ctx, dp.Deposit, dp.Eth1BlockHeight, dp.Index, depositTrie.Root())) 1093 } 1094 for _, dp := range recentDeposits { 1095 depositCache.InsertPendingDeposit(ctx, dp.Deposit, dp.Eth1BlockHeight, dp.Index, depositTrie.Root()) 1096 } 1097 d := depositCache.AllDepositContainers(ctx) 1098 origDeposit, ok := proto.Clone(d[0].Deposit).(*ethpb.Deposit) 1099 assert.Equal(t, true, ok) 1100 junkCreds := mockCreds 1101 copy(junkCreds[:1], []byte{'A'}) 1102 // Mutate it since its a pointer 1103 d[0].Deposit.Data.WithdrawalCredentials = junkCreds[:] 1104 // Insert junk to corrupt trie. 1105 depositCache.InsertFinalizedDeposits(ctx, 2) 1106 1107 // Add original back 1108 d[0].Deposit = origDeposit 1109 1110 bs := &Server{ 1111 ChainStartFetcher: p, 1112 Eth1InfoFetcher: p, 1113 Eth1BlockFetcher: p, 1114 DepositFetcher: depositCache, 1115 PendingDepositsFetcher: depositCache, 1116 BlockReceiver: &mock.ChainService{State: beaconState, Root: blkRoot[:]}, 1117 HeadFetcher: &mock.ChainService{State: beaconState, Root: blkRoot[:]}, 1118 } 1119 1120 trie, err := bs.depositTrie(ctx, ðpb.Eth1Data{}, big.NewInt(int64(params.BeaconConfig().Eth1FollowDistance))) 1121 require.NoError(t, err) 1122 1123 expectedRoot := depositTrie.HashTreeRoot() 1124 actualRoot := trie.HashTreeRoot() 1125 assert.Equal(t, expectedRoot, actualRoot, "Incorrect deposit trie root") 1126 1127 } 1128 1129 func TestProposer_ValidateDepositTrie(t *testing.T) { 1130 tt := []struct { 1131 name string 1132 eth1dataCreator func() *ethpb.Eth1Data 1133 trieCreator func() *trieutil.SparseMerkleTrie 1134 success bool 1135 }{ 1136 { 1137 name: "invalid trie items", 1138 eth1dataCreator: func() *ethpb.Eth1Data { 1139 return ðpb.Eth1Data{DepositRoot: []byte{}, DepositCount: 10, BlockHash: []byte{}} 1140 }, 1141 trieCreator: func() *trieutil.SparseMerkleTrie { 1142 trie, err := trieutil.NewTrie(params.BeaconConfig().DepositContractTreeDepth) 1143 assert.NoError(t, err) 1144 return trie 1145 }, 1146 success: false, 1147 }, 1148 { 1149 name: "invalid deposit root", 1150 eth1dataCreator: func() *ethpb.Eth1Data { 1151 trie, err := trieutil.NewTrie(params.BeaconConfig().DepositContractTreeDepth) 1152 assert.NoError(t, err) 1153 trie.Insert([]byte{'a'}, 0) 1154 trie.Insert([]byte{'b'}, 1) 1155 trie.Insert([]byte{'c'}, 2) 1156 return ðpb.Eth1Data{DepositRoot: []byte{'B'}, DepositCount: 3, BlockHash: []byte{}} 1157 }, 1158 trieCreator: func() *trieutil.SparseMerkleTrie { 1159 trie, err := trieutil.NewTrie(params.BeaconConfig().DepositContractTreeDepth) 1160 assert.NoError(t, err) 1161 trie.Insert([]byte{'a'}, 0) 1162 trie.Insert([]byte{'b'}, 1) 1163 trie.Insert([]byte{'c'}, 2) 1164 return trie 1165 }, 1166 success: false, 1167 }, 1168 { 1169 name: "valid deposit trie", 1170 eth1dataCreator: func() *ethpb.Eth1Data { 1171 trie, err := trieutil.NewTrie(params.BeaconConfig().DepositContractTreeDepth) 1172 assert.NoError(t, err) 1173 trie.Insert([]byte{'a'}, 0) 1174 trie.Insert([]byte{'b'}, 1) 1175 trie.Insert([]byte{'c'}, 2) 1176 rt := trie.HashTreeRoot() 1177 return ðpb.Eth1Data{DepositRoot: rt[:], DepositCount: 3, BlockHash: []byte{}} 1178 }, 1179 trieCreator: func() *trieutil.SparseMerkleTrie { 1180 trie, err := trieutil.NewTrie(params.BeaconConfig().DepositContractTreeDepth) 1181 assert.NoError(t, err) 1182 trie.Insert([]byte{'a'}, 0) 1183 trie.Insert([]byte{'b'}, 1) 1184 trie.Insert([]byte{'c'}, 2) 1185 return trie 1186 }, 1187 success: true, 1188 }, 1189 } 1190 1191 for _, test := range tt { 1192 t.Run(test.name, func(t *testing.T) { 1193 server := &Server{} 1194 valid, err := server.validateDepositTrie(test.trieCreator(), test.eth1dataCreator()) 1195 assert.Equal(t, test.success, valid) 1196 if valid { 1197 assert.NoError(t, err) 1198 } 1199 }) 1200 } 1201 } 1202 1203 func TestProposer_Eth1Data_NoBlockExists(t *testing.T) { 1204 ctx := context.Background() 1205 1206 height := big.NewInt(int64(params.BeaconConfig().Eth1FollowDistance)) 1207 deps := []*dbpb.DepositContainer{ 1208 { 1209 Index: 0, 1210 Eth1BlockHeight: 8, 1211 Deposit: ðpb.Deposit{ 1212 Data: ðpb.Deposit_Data{ 1213 PublicKey: bytesutil.PadTo([]byte("a"), 48), 1214 Signature: make([]byte, 96), 1215 WithdrawalCredentials: make([]byte, 32), 1216 }}, 1217 }, 1218 { 1219 Index: 1, 1220 Eth1BlockHeight: 14, 1221 Deposit: ðpb.Deposit{ 1222 Data: ðpb.Deposit_Data{ 1223 PublicKey: bytesutil.PadTo([]byte("b"), 48), 1224 Signature: make([]byte, 96), 1225 WithdrawalCredentials: make([]byte, 32), 1226 }}, 1227 }, 1228 } 1229 depositTrie, err := trieutil.NewTrie(params.BeaconConfig().DepositContractTreeDepth) 1230 require.NoError(t, err, "Could not setup deposit trie") 1231 1232 depositCache, err := depositcache.New() 1233 require.NoError(t, err) 1234 1235 for _, dp := range deps { 1236 assert.NoError(t, depositCache.InsertDeposit(context.Background(), dp.Deposit, dp.Eth1BlockHeight, dp.Index, depositTrie.Root())) 1237 } 1238 1239 p := &mockPOW.POWChain{ 1240 LatestBlockNumber: height, 1241 HashesByHeight: map[int][]byte{ 1242 0: []byte("hash0"), 1243 12: []byte("hash12"), 1244 }, 1245 } 1246 proposerServer := &Server{ 1247 ChainStartFetcher: p, 1248 Eth1InfoFetcher: p, 1249 Eth1BlockFetcher: p, 1250 DepositFetcher: depositCache, 1251 PendingDepositsFetcher: depositCache, 1252 } 1253 1254 defEth1Data := ðpb.Eth1Data{ 1255 DepositCount: 10, 1256 BlockHash: []byte{'t', 'e', 's', 't'}, 1257 DepositRoot: []byte{'r', 'o', 'o', 't'}, 1258 } 1259 1260 p.Eth1Data = defEth1Data 1261 1262 result, err := proposerServer.defaultEth1DataResponse(ctx, big.NewInt(16)) 1263 require.NoError(t, err) 1264 1265 if !proto.Equal(result, defEth1Data) { 1266 t.Errorf("Did not receive default eth1data. Wanted %v but got %v", defEth1Data, result) 1267 } 1268 } 1269 1270 func TestProposer_Eth1Data_MajorityVote(t *testing.T) { 1271 slot := types.Slot(64) 1272 earliestValidTime, latestValidTime := majorityVoteBoundaryTime(slot) 1273 1274 dc := dbpb.DepositContainer{ 1275 Index: 0, 1276 Eth1BlockHeight: 0, 1277 Deposit: ðpb.Deposit{ 1278 Data: ðpb.Deposit_Data{ 1279 PublicKey: bytesutil.PadTo([]byte("a"), 48), 1280 Signature: make([]byte, 96), 1281 WithdrawalCredentials: make([]byte, 32), 1282 }}, 1283 } 1284 depositTrie, err := trieutil.NewTrie(params.BeaconConfig().DepositContractTreeDepth) 1285 require.NoError(t, err) 1286 depositCache, err := depositcache.New() 1287 require.NoError(t, err) 1288 assert.NoError(t, depositCache.InsertDeposit(context.Background(), dc.Deposit, dc.Eth1BlockHeight, dc.Index, depositTrie.Root())) 1289 1290 t.Run("choose highest count", func(t *testing.T) { 1291 t.Skip() 1292 p := mockPOW.NewPOWChain(). 1293 InsertBlock(50, earliestValidTime, []byte("earliest")). 1294 InsertBlock(51, earliestValidTime+1, []byte("first")). 1295 InsertBlock(52, earliestValidTime+2, []byte("second")). 1296 InsertBlock(100, latestValidTime, []byte("latest")) 1297 1298 beaconState, err := v1.InitializeFromProto(&pbp2p.BeaconState{ 1299 Slot: slot, 1300 Eth1DataVotes: []*ethpb.Eth1Data{ 1301 {BlockHash: []byte("first"), DepositCount: 1}, 1302 {BlockHash: []byte("first"), DepositCount: 1}, 1303 {BlockHash: []byte("second"), DepositCount: 1}, 1304 }, 1305 }) 1306 require.NoError(t, err) 1307 1308 ps := &Server{ 1309 ChainStartFetcher: p, 1310 Eth1InfoFetcher: p, 1311 Eth1BlockFetcher: p, 1312 BlockFetcher: p, 1313 DepositFetcher: depositCache, 1314 HeadFetcher: &mock.ChainService{ETH1Data: ðpb.Eth1Data{DepositCount: 1}}, 1315 } 1316 1317 ctx := context.Background() 1318 majorityVoteEth1Data, err := ps.eth1DataMajorityVote(ctx, beaconState) 1319 require.NoError(t, err) 1320 1321 hash := majorityVoteEth1Data.BlockHash 1322 1323 expectedHash := []byte("first") 1324 assert.DeepEqual(t, expectedHash, hash) 1325 }) 1326 1327 t.Run("highest count at earliest valid time - choose highest count", func(t *testing.T) { 1328 t.Skip() 1329 p := mockPOW.NewPOWChain(). 1330 InsertBlock(50, earliestValidTime, []byte("earliest")). 1331 InsertBlock(52, earliestValidTime+2, []byte("second")). 1332 InsertBlock(100, latestValidTime, []byte("latest")) 1333 1334 beaconState, err := v1.InitializeFromProto(&pbp2p.BeaconState{ 1335 Slot: slot, 1336 Eth1DataVotes: []*ethpb.Eth1Data{ 1337 {BlockHash: []byte("earliest"), DepositCount: 1}, 1338 {BlockHash: []byte("earliest"), DepositCount: 1}, 1339 {BlockHash: []byte("second"), DepositCount: 1}, 1340 }, 1341 }) 1342 require.NoError(t, err) 1343 1344 ps := &Server{ 1345 ChainStartFetcher: p, 1346 Eth1InfoFetcher: p, 1347 Eth1BlockFetcher: p, 1348 BlockFetcher: p, 1349 DepositFetcher: depositCache, 1350 HeadFetcher: &mock.ChainService{ETH1Data: ðpb.Eth1Data{DepositCount: 1}}, 1351 } 1352 1353 ctx := context.Background() 1354 majorityVoteEth1Data, err := ps.eth1DataMajorityVote(ctx, beaconState) 1355 require.NoError(t, err) 1356 1357 hash := majorityVoteEth1Data.BlockHash 1358 1359 expectedHash := []byte("earliest") 1360 assert.DeepEqual(t, expectedHash, hash) 1361 }) 1362 1363 t.Run("highest count at latest valid time - choose highest count", func(t *testing.T) { 1364 t.Skip() 1365 p := mockPOW.NewPOWChain(). 1366 InsertBlock(50, earliestValidTime, []byte("earliest")). 1367 InsertBlock(51, earliestValidTime+1, []byte("first")). 1368 InsertBlock(100, latestValidTime, []byte("latest")) 1369 1370 beaconState, err := v1.InitializeFromProto(&pbp2p.BeaconState{ 1371 Slot: slot, 1372 Eth1DataVotes: []*ethpb.Eth1Data{ 1373 {BlockHash: []byte("first"), DepositCount: 1}, 1374 {BlockHash: []byte("latest"), DepositCount: 1}, 1375 {BlockHash: []byte("latest"), DepositCount: 1}, 1376 }, 1377 }) 1378 require.NoError(t, err) 1379 1380 ps := &Server{ 1381 ChainStartFetcher: p, 1382 Eth1InfoFetcher: p, 1383 Eth1BlockFetcher: p, 1384 BlockFetcher: p, 1385 DepositFetcher: depositCache, 1386 HeadFetcher: &mock.ChainService{ETH1Data: ðpb.Eth1Data{DepositCount: 1}}, 1387 } 1388 1389 ctx := context.Background() 1390 majorityVoteEth1Data, err := ps.eth1DataMajorityVote(ctx, beaconState) 1391 require.NoError(t, err) 1392 1393 hash := majorityVoteEth1Data.BlockHash 1394 1395 expectedHash := []byte("latest") 1396 assert.DeepEqual(t, expectedHash, hash) 1397 }) 1398 1399 t.Run("highest count before range - choose highest count within range", func(t *testing.T) { 1400 t.Skip() 1401 p := mockPOW.NewPOWChain(). 1402 InsertBlock(49, earliestValidTime-1, []byte("before_range")). 1403 InsertBlock(50, earliestValidTime, []byte("earliest")). 1404 InsertBlock(51, earliestValidTime+1, []byte("first")). 1405 InsertBlock(100, latestValidTime, []byte("latest")) 1406 1407 beaconState, err := v1.InitializeFromProto(&pbp2p.BeaconState{ 1408 Slot: slot, 1409 Eth1DataVotes: []*ethpb.Eth1Data{ 1410 {BlockHash: []byte("before_range"), DepositCount: 1}, 1411 {BlockHash: []byte("before_range"), DepositCount: 1}, 1412 {BlockHash: []byte("first"), DepositCount: 1}, 1413 }, 1414 }) 1415 require.NoError(t, err) 1416 1417 ps := &Server{ 1418 ChainStartFetcher: p, 1419 Eth1InfoFetcher: p, 1420 Eth1BlockFetcher: p, 1421 BlockFetcher: p, 1422 DepositFetcher: depositCache, 1423 HeadFetcher: &mock.ChainService{ETH1Data: ðpb.Eth1Data{DepositCount: 1}}, 1424 } 1425 1426 ctx := context.Background() 1427 majorityVoteEth1Data, err := ps.eth1DataMajorityVote(ctx, beaconState) 1428 require.NoError(t, err) 1429 1430 hash := majorityVoteEth1Data.BlockHash 1431 1432 expectedHash := []byte("first") 1433 assert.DeepEqual(t, expectedHash, hash) 1434 }) 1435 1436 t.Run("highest count after range - choose highest count within range", func(t *testing.T) { 1437 t.Skip() 1438 p := mockPOW.NewPOWChain(). 1439 InsertBlock(50, earliestValidTime, []byte("earliest")). 1440 InsertBlock(51, earliestValidTime+1, []byte("first")). 1441 InsertBlock(100, latestValidTime, []byte("latest")). 1442 InsertBlock(101, latestValidTime+1, []byte("after_range")) 1443 1444 beaconState, err := v1.InitializeFromProto(&pbp2p.BeaconState{ 1445 Slot: slot, 1446 Eth1DataVotes: []*ethpb.Eth1Data{ 1447 {BlockHash: []byte("first"), DepositCount: 1}, 1448 {BlockHash: []byte("after_range"), DepositCount: 1}, 1449 {BlockHash: []byte("after_range"), DepositCount: 1}, 1450 }, 1451 }) 1452 require.NoError(t, err) 1453 1454 ps := &Server{ 1455 ChainStartFetcher: p, 1456 Eth1InfoFetcher: p, 1457 Eth1BlockFetcher: p, 1458 BlockFetcher: p, 1459 DepositFetcher: depositCache, 1460 HeadFetcher: &mock.ChainService{ETH1Data: ðpb.Eth1Data{DepositCount: 1}}, 1461 } 1462 1463 ctx := context.Background() 1464 majorityVoteEth1Data, err := ps.eth1DataMajorityVote(ctx, beaconState) 1465 require.NoError(t, err) 1466 1467 hash := majorityVoteEth1Data.BlockHash 1468 1469 expectedHash := []byte("first") 1470 assert.DeepEqual(t, expectedHash, hash) 1471 }) 1472 1473 t.Run("highest count on unknown block - choose known block with highest count", func(t *testing.T) { 1474 t.Skip() 1475 p := mockPOW.NewPOWChain(). 1476 InsertBlock(50, earliestValidTime, []byte("earliest")). 1477 InsertBlock(51, earliestValidTime+1, []byte("first")). 1478 InsertBlock(52, earliestValidTime+2, []byte("second")). 1479 InsertBlock(100, latestValidTime, []byte("latest")) 1480 1481 beaconState, err := v1.InitializeFromProto(&pbp2p.BeaconState{ 1482 Slot: slot, 1483 Eth1DataVotes: []*ethpb.Eth1Data{ 1484 {BlockHash: []byte("unknown"), DepositCount: 1}, 1485 {BlockHash: []byte("unknown"), DepositCount: 1}, 1486 {BlockHash: []byte("first"), DepositCount: 1}, 1487 }, 1488 }) 1489 require.NoError(t, err) 1490 1491 ps := &Server{ 1492 ChainStartFetcher: p, 1493 Eth1InfoFetcher: p, 1494 Eth1BlockFetcher: p, 1495 BlockFetcher: p, 1496 DepositFetcher: depositCache, 1497 HeadFetcher: &mock.ChainService{ETH1Data: ðpb.Eth1Data{DepositCount: 1}}, 1498 } 1499 1500 ctx := context.Background() 1501 majorityVoteEth1Data, err := ps.eth1DataMajorityVote(ctx, beaconState) 1502 require.NoError(t, err) 1503 1504 hash := majorityVoteEth1Data.BlockHash 1505 1506 expectedHash := []byte("first") 1507 assert.DeepEqual(t, expectedHash, hash) 1508 }) 1509 1510 t.Run("no blocks in range - choose current eth1data", func(t *testing.T) { 1511 p := mockPOW.NewPOWChain(). 1512 InsertBlock(49, earliestValidTime-1, []byte("before_range")). 1513 InsertBlock(101, latestValidTime+1, []byte("after_range")) 1514 1515 beaconState, err := v1.InitializeFromProto(&pbp2p.BeaconState{ 1516 Slot: slot, 1517 }) 1518 require.NoError(t, err) 1519 1520 currentEth1Data := ðpb.Eth1Data{DepositCount: 1, BlockHash: []byte("current")} 1521 ps := &Server{ 1522 ChainStartFetcher: p, 1523 Eth1InfoFetcher: p, 1524 Eth1BlockFetcher: p, 1525 BlockFetcher: p, 1526 DepositFetcher: depositCache, 1527 HeadFetcher: &mock.ChainService{ETH1Data: currentEth1Data}, 1528 } 1529 1530 ctx := context.Background() 1531 majorityVoteEth1Data, err := ps.eth1DataMajorityVote(ctx, beaconState) 1532 require.NoError(t, err) 1533 1534 hash := majorityVoteEth1Data.BlockHash 1535 1536 expectedHash := []byte("current") 1537 assert.DeepEqual(t, expectedHash, hash) 1538 }) 1539 1540 t.Run("no votes in range - choose most recent block", func(t *testing.T) { 1541 p := mockPOW.NewPOWChain(). 1542 InsertBlock(49, earliestValidTime-1, []byte("before_range")). 1543 InsertBlock(51, earliestValidTime+1, []byte("first")). 1544 InsertBlock(52, earliestValidTime+2, []byte("second")). 1545 InsertBlock(101, latestValidTime+1, []byte("after_range")) 1546 1547 beaconState, err := v1.InitializeFromProto(&pbp2p.BeaconState{ 1548 Slot: slot, 1549 Eth1DataVotes: []*ethpb.Eth1Data{ 1550 {BlockHash: []byte("before_range"), DepositCount: 1}, 1551 {BlockHash: []byte("after_range"), DepositCount: 1}, 1552 }, 1553 }) 1554 require.NoError(t, err) 1555 1556 ps := &Server{ 1557 ChainStartFetcher: p, 1558 Eth1InfoFetcher: p, 1559 Eth1BlockFetcher: p, 1560 BlockFetcher: p, 1561 DepositFetcher: depositCache, 1562 HeadFetcher: &mock.ChainService{ETH1Data: ðpb.Eth1Data{DepositCount: 1}}, 1563 } 1564 1565 ctx := context.Background() 1566 majorityVoteEth1Data, err := ps.eth1DataMajorityVote(ctx, beaconState) 1567 require.NoError(t, err) 1568 1569 hash := majorityVoteEth1Data.BlockHash 1570 1571 expectedHash := make([]byte, 32) 1572 copy(expectedHash, "second") 1573 assert.DeepEqual(t, expectedHash, hash) 1574 }) 1575 1576 t.Run("no votes - choose more recent block", func(t *testing.T) { 1577 p := mockPOW.NewPOWChain(). 1578 InsertBlock(50, earliestValidTime, []byte("earliest")). 1579 InsertBlock(100, latestValidTime, []byte("latest")) 1580 1581 beaconState, err := v1.InitializeFromProto(&pbp2p.BeaconState{ 1582 Slot: slot, 1583 Eth1DataVotes: []*ethpb.Eth1Data{}}) 1584 require.NoError(t, err) 1585 1586 ps := &Server{ 1587 ChainStartFetcher: p, 1588 Eth1InfoFetcher: p, 1589 Eth1BlockFetcher: p, 1590 BlockFetcher: p, 1591 DepositFetcher: depositCache, 1592 HeadFetcher: &mock.ChainService{ETH1Data: ðpb.Eth1Data{DepositCount: 1}}, 1593 } 1594 1595 ctx := context.Background() 1596 majorityVoteEth1Data, err := ps.eth1DataMajorityVote(ctx, beaconState) 1597 require.NoError(t, err) 1598 1599 hash := majorityVoteEth1Data.BlockHash 1600 1601 expectedHash := make([]byte, 32) 1602 copy(expectedHash, "latest") 1603 assert.DeepEqual(t, expectedHash, hash) 1604 }) 1605 1606 t.Run("no votes and more recent block has less deposits - choose current eth1data", func(t *testing.T) { 1607 p := mockPOW.NewPOWChain(). 1608 InsertBlock(50, earliestValidTime, []byte("earliest")). 1609 InsertBlock(100, latestValidTime, []byte("latest")) 1610 1611 beaconState, err := v1.InitializeFromProto(&pbp2p.BeaconState{ 1612 Slot: slot, 1613 }) 1614 require.NoError(t, err) 1615 1616 // Set the deposit count in current eth1data to exceed the latest most recent block's deposit count. 1617 currentEth1Data := ðpb.Eth1Data{DepositCount: 2, BlockHash: []byte("current")} 1618 ps := &Server{ 1619 ChainStartFetcher: p, 1620 Eth1InfoFetcher: p, 1621 Eth1BlockFetcher: p, 1622 BlockFetcher: p, 1623 DepositFetcher: depositCache, 1624 HeadFetcher: &mock.ChainService{ETH1Data: currentEth1Data}, 1625 } 1626 1627 ctx := context.Background() 1628 majorityVoteEth1Data, err := ps.eth1DataMajorityVote(ctx, beaconState) 1629 require.NoError(t, err) 1630 1631 hash := majorityVoteEth1Data.BlockHash 1632 1633 expectedHash := []byte("current") 1634 assert.DeepEqual(t, expectedHash, hash) 1635 }) 1636 1637 t.Run("same count - choose more recent block", func(t *testing.T) { 1638 t.Skip() 1639 p := mockPOW.NewPOWChain(). 1640 InsertBlock(50, earliestValidTime, []byte("earliest")). 1641 InsertBlock(51, earliestValidTime+1, []byte("first")). 1642 InsertBlock(52, earliestValidTime+2, []byte("second")). 1643 InsertBlock(100, latestValidTime, []byte("latest")) 1644 1645 beaconState, err := v1.InitializeFromProto(&pbp2p.BeaconState{ 1646 Slot: slot, 1647 Eth1DataVotes: []*ethpb.Eth1Data{ 1648 {BlockHash: []byte("first"), DepositCount: 1}, 1649 {BlockHash: []byte("second"), DepositCount: 1}, 1650 }, 1651 }) 1652 require.NoError(t, err) 1653 1654 ps := &Server{ 1655 ChainStartFetcher: p, 1656 Eth1InfoFetcher: p, 1657 Eth1BlockFetcher: p, 1658 BlockFetcher: p, 1659 DepositFetcher: depositCache, 1660 HeadFetcher: &mock.ChainService{ETH1Data: ðpb.Eth1Data{DepositCount: 1}}, 1661 } 1662 1663 ctx := context.Background() 1664 majorityVoteEth1Data, err := ps.eth1DataMajorityVote(ctx, beaconState) 1665 require.NoError(t, err) 1666 1667 hash := majorityVoteEth1Data.BlockHash 1668 1669 expectedHash := []byte("second") 1670 assert.DeepEqual(t, expectedHash, hash) 1671 }) 1672 1673 t.Run("highest count on block with less deposits - choose another block", func(t *testing.T) { 1674 t.Skip() 1675 p := mockPOW.NewPOWChain(). 1676 InsertBlock(50, earliestValidTime, []byte("earliest")). 1677 InsertBlock(51, earliestValidTime+1, []byte("first")). 1678 InsertBlock(52, earliestValidTime+2, []byte("second")). 1679 InsertBlock(100, latestValidTime, []byte("latest")) 1680 1681 beaconState, err := v1.InitializeFromProto(&pbp2p.BeaconState{ 1682 Slot: slot, 1683 Eth1DataVotes: []*ethpb.Eth1Data{ 1684 {BlockHash: []byte("no_new_deposits"), DepositCount: 0}, 1685 {BlockHash: []byte("no_new_deposits"), DepositCount: 0}, 1686 {BlockHash: []byte("second"), DepositCount: 1}, 1687 }, 1688 }) 1689 require.NoError(t, err) 1690 1691 ps := &Server{ 1692 ChainStartFetcher: p, 1693 Eth1InfoFetcher: p, 1694 Eth1BlockFetcher: p, 1695 BlockFetcher: p, 1696 DepositFetcher: depositCache, 1697 HeadFetcher: &mock.ChainService{ETH1Data: ðpb.Eth1Data{DepositCount: 1}}, 1698 } 1699 1700 ctx := context.Background() 1701 majorityVoteEth1Data, err := ps.eth1DataMajorityVote(ctx, beaconState) 1702 require.NoError(t, err) 1703 1704 hash := majorityVoteEth1Data.BlockHash 1705 1706 expectedHash := []byte("second") 1707 assert.DeepEqual(t, expectedHash, hash) 1708 }) 1709 1710 t.Run("only one block at earliest valid time - choose this block", func(t *testing.T) { 1711 t.Skip() 1712 p := mockPOW.NewPOWChain().InsertBlock(50, earliestValidTime, []byte("earliest")) 1713 1714 beaconState, err := v1.InitializeFromProto(&pbp2p.BeaconState{ 1715 Slot: slot, 1716 Eth1DataVotes: []*ethpb.Eth1Data{ 1717 {BlockHash: []byte("earliest"), DepositCount: 1}, 1718 }, 1719 }) 1720 require.NoError(t, err) 1721 1722 ps := &Server{ 1723 ChainStartFetcher: p, 1724 Eth1InfoFetcher: p, 1725 Eth1BlockFetcher: p, 1726 BlockFetcher: p, 1727 DepositFetcher: depositCache, 1728 HeadFetcher: &mock.ChainService{ETH1Data: ðpb.Eth1Data{DepositCount: 1}}, 1729 } 1730 1731 ctx := context.Background() 1732 majorityVoteEth1Data, err := ps.eth1DataMajorityVote(ctx, beaconState) 1733 require.NoError(t, err) 1734 1735 hash := majorityVoteEth1Data.BlockHash 1736 1737 expectedHash := []byte("earliest") 1738 assert.DeepEqual(t, expectedHash, hash) 1739 }) 1740 1741 t.Run("vote on last block before range - choose next block", func(t *testing.T) { 1742 p := mockPOW.NewPOWChain(). 1743 InsertBlock(49, earliestValidTime-1, []byte("before_range")). 1744 // It is important to have height `50` with time `earliestValidTime+1` and not `earliestValidTime` 1745 // because of earliest block increment in the algorithm. 1746 InsertBlock(50, earliestValidTime+1, []byte("first")) 1747 1748 beaconState, err := v1.InitializeFromProto(&pbp2p.BeaconState{ 1749 Slot: slot, 1750 Eth1DataVotes: []*ethpb.Eth1Data{ 1751 {BlockHash: []byte("before_range"), DepositCount: 1}, 1752 }, 1753 }) 1754 require.NoError(t, err) 1755 1756 ps := &Server{ 1757 ChainStartFetcher: p, 1758 Eth1InfoFetcher: p, 1759 Eth1BlockFetcher: p, 1760 BlockFetcher: p, 1761 DepositFetcher: depositCache, 1762 HeadFetcher: &mock.ChainService{ETH1Data: ðpb.Eth1Data{DepositCount: 1}}, 1763 } 1764 1765 ctx := context.Background() 1766 majorityVoteEth1Data, err := ps.eth1DataMajorityVote(ctx, beaconState) 1767 require.NoError(t, err) 1768 1769 hash := majorityVoteEth1Data.BlockHash 1770 1771 expectedHash := make([]byte, 32) 1772 copy(expectedHash, "first") 1773 assert.DeepEqual(t, expectedHash, hash) 1774 }) 1775 1776 t.Run("no deposits - choose chain start eth1data", func(t *testing.T) { 1777 p := mockPOW.NewPOWChain(). 1778 InsertBlock(50, earliestValidTime, []byte("earliest")). 1779 InsertBlock(100, latestValidTime, []byte("latest")) 1780 p.Eth1Data = ðpb.Eth1Data{ 1781 BlockHash: []byte("eth1data"), 1782 } 1783 1784 depositCache, err := depositcache.New() 1785 require.NoError(t, err) 1786 1787 beaconState, err := v1.InitializeFromProto(&pbp2p.BeaconState{ 1788 Slot: slot, 1789 Eth1DataVotes: []*ethpb.Eth1Data{ 1790 {BlockHash: []byte("earliest"), DepositCount: 1}, 1791 }, 1792 }) 1793 require.NoError(t, err) 1794 1795 ps := &Server{ 1796 ChainStartFetcher: p, 1797 Eth1InfoFetcher: p, 1798 Eth1BlockFetcher: p, 1799 BlockFetcher: p, 1800 DepositFetcher: depositCache, 1801 HeadFetcher: &mock.ChainService{ETH1Data: ðpb.Eth1Data{DepositCount: 0}}, 1802 } 1803 1804 ctx := context.Background() 1805 majorityVoteEth1Data, err := ps.eth1DataMajorityVote(ctx, beaconState) 1806 require.NoError(t, err) 1807 1808 hash := majorityVoteEth1Data.BlockHash 1809 1810 expectedHash := []byte("eth1data") 1811 assert.DeepEqual(t, expectedHash, hash) 1812 }) 1813 } 1814 1815 func TestProposer_FilterAttestation(t *testing.T) { 1816 db := dbutil.SetupDB(t) 1817 ctx := context.Background() 1818 1819 params.SetupTestConfigCleanup(t) 1820 params.OverrideBeaconConfig(params.MainnetConfig()) 1821 genesis := testutil.NewBeaconBlock() 1822 require.NoError(t, db.SaveBlock(context.Background(), wrapper.WrappedPhase0SignedBeaconBlock(genesis)), "Could not save genesis block") 1823 1824 numValidators := uint64(64) 1825 state, privKeys := testutil.DeterministicGenesisState(t, numValidators) 1826 require.NoError(t, state.SetGenesisValidatorRoot(params.BeaconConfig().ZeroHash[:])) 1827 assert.NoError(t, state.SetSlot(1)) 1828 1829 genesisRoot, err := genesis.Block.HashTreeRoot() 1830 require.NoError(t, err) 1831 require.NoError(t, db.SaveState(ctx, state, genesisRoot), "Could not save genesis state") 1832 require.NoError(t, db.SaveHeadBlockRoot(ctx, genesisRoot), "Could not save genesis state") 1833 1834 tests := []struct { 1835 name string 1836 wantedErr string 1837 inputAtts func() []*ethpb.Attestation 1838 expectedAtts func(inputAtts []*ethpb.Attestation) []*ethpb.Attestation 1839 }{ 1840 { 1841 name: "nil attestations", 1842 inputAtts: func() []*ethpb.Attestation { 1843 return nil 1844 }, 1845 expectedAtts: func(inputAtts []*ethpb.Attestation) []*ethpb.Attestation { 1846 return []*ethpb.Attestation{} 1847 }, 1848 }, 1849 { 1850 name: "invalid attestations", 1851 inputAtts: func() []*ethpb.Attestation { 1852 atts := make([]*ethpb.Attestation, 10) 1853 for i := 0; i < len(atts); i++ { 1854 atts[i] = testutil.HydrateAttestation(ðpb.Attestation{ 1855 Data: ðpb.AttestationData{ 1856 CommitteeIndex: types.CommitteeIndex(i), 1857 }, 1858 }) 1859 } 1860 return atts 1861 }, 1862 expectedAtts: func(inputAtts []*ethpb.Attestation) []*ethpb.Attestation { 1863 return []*ethpb.Attestation{} 1864 }, 1865 }, 1866 { 1867 name: "filter aggregates ok", 1868 inputAtts: func() []*ethpb.Attestation { 1869 atts := make([]*ethpb.Attestation, 10) 1870 for i := 0; i < len(atts); i++ { 1871 atts[i] = testutil.HydrateAttestation(ðpb.Attestation{ 1872 Data: ðpb.AttestationData{ 1873 CommitteeIndex: types.CommitteeIndex(i), 1874 Source: ðpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]}, 1875 }, 1876 AggregationBits: bitfield.Bitlist{0b00000110}, 1877 }) 1878 committee, err := helpers.BeaconCommitteeFromState(state, atts[i].Data.Slot, atts[i].Data.CommitteeIndex) 1879 assert.NoError(t, err) 1880 attestingIndices, err := attestationutil.AttestingIndices(atts[i].AggregationBits, committee) 1881 require.NoError(t, err) 1882 assert.NoError(t, err) 1883 domain, err := helpers.Domain(state.Fork(), 0, params.BeaconConfig().DomainBeaconAttester, params.BeaconConfig().ZeroHash[:]) 1884 require.NoError(t, err) 1885 sigs := make([]bls.Signature, len(attestingIndices)) 1886 zeroSig := [96]byte{} 1887 atts[i].Signature = zeroSig[:] 1888 1889 for i, indice := range attestingIndices { 1890 hashTreeRoot, err := helpers.ComputeSigningRoot(atts[i].Data, domain) 1891 require.NoError(t, err) 1892 sig := privKeys[indice].Sign(hashTreeRoot[:]) 1893 sigs[i] = sig 1894 } 1895 atts[i].Signature = bls.AggregateSignatures(sigs).Marshal() 1896 } 1897 return atts 1898 }, 1899 expectedAtts: func(inputAtts []*ethpb.Attestation) []*ethpb.Attestation { 1900 return []*ethpb.Attestation{inputAtts[0]} 1901 }, 1902 }, 1903 } 1904 1905 for _, tt := range tests { 1906 t.Run(tt.name, func(t *testing.T) { 1907 proposerServer := &Server{ 1908 BeaconDB: db, 1909 AttPool: attestations.NewPool(), 1910 HeadFetcher: &mock.ChainService{State: state, Root: genesisRoot[:]}, 1911 } 1912 atts := tt.inputAtts() 1913 received, err := proposerServer.filterAttestationsForBlockInclusion(context.Background(), state, atts) 1914 if tt.wantedErr != "" { 1915 assert.ErrorContains(t, tt.wantedErr, err) 1916 assert.Equal(t, nil, received) 1917 } else { 1918 assert.NoError(t, err) 1919 assert.DeepEqual(t, tt.expectedAtts(atts), received) 1920 } 1921 }) 1922 } 1923 } 1924 1925 func TestProposer_Deposits_ReturnsEmptyList_IfLatestEth1DataEqGenesisEth1Block(t *testing.T) { 1926 ctx := context.Background() 1927 1928 height := big.NewInt(int64(params.BeaconConfig().Eth1FollowDistance)) 1929 p := &mockPOW.POWChain{ 1930 LatestBlockNumber: height, 1931 HashesByHeight: map[int][]byte{ 1932 int(height.Int64()): []byte("0x0"), 1933 }, 1934 GenesisEth1Block: height, 1935 } 1936 1937 beaconState, err := v1.InitializeFromProto(&pbp2p.BeaconState{ 1938 Eth1Data: ðpb.Eth1Data{ 1939 BlockHash: bytesutil.PadTo([]byte("0x0"), 32), 1940 DepositRoot: make([]byte, 32), 1941 }, 1942 Eth1DepositIndex: 2, 1943 }) 1944 require.NoError(t, err) 1945 blk := testutil.NewBeaconBlock() 1946 blk.Block.Slot = beaconState.Slot() 1947 blkRoot, err := blk.Block.HashTreeRoot() 1948 require.NoError(t, err) 1949 1950 var mockSig [96]byte 1951 var mockCreds [32]byte 1952 1953 readyDeposits := []*dbpb.DepositContainer{ 1954 { 1955 Index: 0, 1956 Deposit: ðpb.Deposit{ 1957 Data: ðpb.Deposit_Data{ 1958 PublicKey: bytesutil.PadTo([]byte("a"), 48), 1959 Signature: mockSig[:], 1960 WithdrawalCredentials: mockCreds[:], 1961 }}, 1962 }, 1963 { 1964 Index: 1, 1965 Deposit: ðpb.Deposit{ 1966 Data: ðpb.Deposit_Data{ 1967 PublicKey: bytesutil.PadTo([]byte("b"), 48), 1968 Signature: mockSig[:], 1969 WithdrawalCredentials: mockCreds[:], 1970 }}, 1971 }, 1972 } 1973 1974 var recentDeposits []*dbpb.DepositContainer 1975 for i := int64(2); i < 22; i++ { 1976 recentDeposits = append(recentDeposits, &dbpb.DepositContainer{ 1977 Index: i, 1978 Deposit: ðpb.Deposit{ 1979 Data: ðpb.Deposit_Data{ 1980 PublicKey: bytesutil.PadTo([]byte{byte(i)}, 48), 1981 Signature: mockSig[:], 1982 WithdrawalCredentials: mockCreds[:], 1983 }}, 1984 }) 1985 } 1986 depositTrie, err := trieutil.NewTrie(params.BeaconConfig().DepositContractTreeDepth) 1987 require.NoError(t, err, "Could not setup deposit trie") 1988 1989 depositCache, err := depositcache.New() 1990 require.NoError(t, err) 1991 1992 for _, dp := range append(readyDeposits, recentDeposits...) { 1993 depositHash, err := dp.Deposit.Data.HashTreeRoot() 1994 require.NoError(t, err, "Unable to determine hashed value of deposit") 1995 1996 depositTrie.Insert(depositHash[:], int(dp.Index)) 1997 assert.NoError(t, depositCache.InsertDeposit(ctx, dp.Deposit, uint64(dp.Index), dp.Index, depositTrie.Root())) 1998 } 1999 for _, dp := range recentDeposits { 2000 depositCache.InsertPendingDeposit(ctx, dp.Deposit, uint64(dp.Index), dp.Index, depositTrie.Root()) 2001 } 2002 2003 bs := &Server{ 2004 BlockReceiver: &mock.ChainService{State: beaconState, Root: blkRoot[:]}, 2005 HeadFetcher: &mock.ChainService{State: beaconState, Root: blkRoot[:]}, 2006 ChainStartFetcher: p, 2007 Eth1InfoFetcher: p, 2008 Eth1BlockFetcher: p, 2009 DepositFetcher: depositCache, 2010 PendingDepositsFetcher: depositCache, 2011 } 2012 2013 // It should also return the recent deposits after their follow window. 2014 p.LatestBlockNumber = big.NewInt(0).Add(p.LatestBlockNumber, big.NewInt(10000)) 2015 deposits, err := bs.deposits(ctx, beaconState, ðpb.Eth1Data{}) 2016 require.NoError(t, err) 2017 assert.Equal(t, 0, len(deposits), "Received unexpected number of pending deposits") 2018 } 2019 2020 func TestProposer_DeleteAttsInPool_Aggregated(t *testing.T) { 2021 s := &Server{ 2022 AttPool: attestations.NewPool(), 2023 } 2024 priv, err := bls.RandKey() 2025 require.NoError(t, err) 2026 sig := priv.Sign([]byte("foo")).Marshal() 2027 aggregatedAtts := []*ethpb.Attestation{ 2028 testutil.HydrateAttestation(ðpb.Attestation{Data: ðpb.AttestationData{Slot: 1}, AggregationBits: bitfield.Bitlist{0b10101}, Signature: sig}), 2029 testutil.HydrateAttestation(ðpb.Attestation{Data: ðpb.AttestationData{Slot: 1}, AggregationBits: bitfield.Bitlist{0b11010}, Signature: sig})} 2030 unaggregatedAtts := []*ethpb.Attestation{ 2031 testutil.HydrateAttestation(ðpb.Attestation{Data: ðpb.AttestationData{Slot: 1}, AggregationBits: bitfield.Bitlist{0b10010}, Signature: sig}), 2032 testutil.HydrateAttestation(ðpb.Attestation{Data: ðpb.AttestationData{Slot: 1}, AggregationBits: bitfield.Bitlist{0b10100}, Signature: sig})} 2033 2034 require.NoError(t, s.AttPool.SaveAggregatedAttestations(aggregatedAtts)) 2035 require.NoError(t, s.AttPool.SaveUnaggregatedAttestations(unaggregatedAtts)) 2036 2037 aa, err := attaggregation.Aggregate(aggregatedAtts) 2038 require.NoError(t, err) 2039 require.NoError(t, s.deleteAttsInPool(context.Background(), append(aa, unaggregatedAtts...))) 2040 assert.Equal(t, 0, len(s.AttPool.AggregatedAttestations()), "Did not delete aggregated attestation") 2041 atts, err := s.AttPool.UnaggregatedAttestations() 2042 require.NoError(t, err) 2043 assert.Equal(t, 0, len(atts), "Did not delete unaggregated attestation") 2044 } 2045 2046 func majorityVoteBoundaryTime(slot types.Slot) (uint64, uint64) { 2047 slots := params.BeaconConfig().SlotsPerEpoch.Mul(uint64(params.BeaconConfig().EpochsPerEth1VotingPeriod)) 2048 slotStartTime := uint64(mockPOW.GenesisTime) + uint64((slot - (slot % (slots))).Mul(params.BeaconConfig().SecondsPerSlot)) 2049 earliestValidTime := slotStartTime - 2*params.BeaconConfig().SecondsPerETH1Block*params.BeaconConfig().Eth1FollowDistance 2050 latestValidTime := slotStartTime - params.BeaconConfig().SecondsPerETH1Block*params.BeaconConfig().Eth1FollowDistance 2051 2052 return earliestValidTime, latestValidTime 2053 }