prysm-pulse/beacon-chain/rpc/validator/proposer_test.go
Preston Van Loon b7175b3482
Update fastssz: Attempt 2 (#7115)
* Revert "Revert "Update fastssz" (#7100)"

This reverts commit b954db9704.
* Preston's patch
* Merge branch 'master' of github.com:prysmaticlabs/prysm into revert-7100-revert-6760-update-fssz
* Update fssz, add regression test case
* more HTR with fssz
* fix some tests
* only one test left
* Make it so that HTR will work
* gofmt, imports
* gofmt, imports
* fix
* Merge branch 'master' of github.com:prysmaticlabs/prysm into revert-7100-revert-6760-update-fssz
* fix
* Merge branch 'master' into revert-7100-revert-6760-update-fssz
* Merge refs/heads/master into revert-7100-revert-6760-update-fssz
* gaz
* Merge branch 'revert-7100-revert-6760-update-fssz' of github.com:prysmaticlabs/prysm into revert-7100-revert-6760-update-fssz
* Merge refs/heads/master into revert-7100-revert-6760-update-fssz
* fix test
* Merge branch 'revert-7100-revert-6760-update-fssz' of github.com:prysmaticlabs/prysm into revert-7100-revert-6760-update-fssz
* Merge refs/heads/master into revert-7100-revert-6760-update-fssz
2020-08-27 18:13:32 +00:00

2053 lines
70 KiB
Go

package validator
import (
"bytes"
"context"
"math/big"
"sort"
"testing"
fastssz "github.com/ferranbt/fastssz"
"github.com/gogo/protobuf/proto"
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
"github.com/prysmaticlabs/go-bitfield"
mock "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/testing"
"github.com/prysmaticlabs/prysm/beacon-chain/cache/depositcache"
b "github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
dbutil "github.com/prysmaticlabs/prysm/beacon-chain/db/testing"
"github.com/prysmaticlabs/prysm/beacon-chain/operations/attestations"
"github.com/prysmaticlabs/prysm/beacon-chain/operations/slashings"
"github.com/prysmaticlabs/prysm/beacon-chain/operations/voluntaryexits"
mockp2p "github.com/prysmaticlabs/prysm/beacon-chain/p2p/testing"
mockPOW "github.com/prysmaticlabs/prysm/beacon-chain/powchain/testing"
beaconstate "github.com/prysmaticlabs/prysm/beacon-chain/state"
"github.com/prysmaticlabs/prysm/beacon-chain/state/stategen"
mockSync "github.com/prysmaticlabs/prysm/beacon-chain/sync/initial-sync/testing"
dbpb "github.com/prysmaticlabs/prysm/proto/beacon/db"
pbp2p "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
attaggregation "github.com/prysmaticlabs/prysm/shared/aggregation/attestations"
"github.com/prysmaticlabs/prysm/shared/attestationutil"
"github.com/prysmaticlabs/prysm/shared/bls"
"github.com/prysmaticlabs/prysm/shared/bytesutil"
"github.com/prysmaticlabs/prysm/shared/featureconfig"
"github.com/prysmaticlabs/prysm/shared/hashutil"
"github.com/prysmaticlabs/prysm/shared/params"
"github.com/prysmaticlabs/prysm/shared/testutil"
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
"github.com/prysmaticlabs/prysm/shared/testutil/require"
"github.com/prysmaticlabs/prysm/shared/trieutil"
)
func TestGetBlock_OK(t *testing.T) {
db, sc := dbutil.SetupDB(t)
ctx := context.Background()
testutil.ResetCache()
params.SetupTestConfigCleanup(t)
params.OverrideBeaconConfig(params.MainnetConfig())
beaconState, privKeys := testutil.DeterministicGenesisState(t, 64)
stateRoot, err := beaconState.HashTreeRoot(ctx)
require.NoError(t, err, "Could not hash genesis state")
genesis := b.NewGenesisBlock(stateRoot[:])
require.NoError(t, db.SaveBlock(ctx, genesis), "Could not save genesis block")
parentRoot, err := genesis.Block.HashTreeRoot()
require.NoError(t, err, "Could not get signing root")
require.NoError(t, db.SaveState(ctx, beaconState, parentRoot), "Could not save genesis state")
require.NoError(t, db.SaveHeadBlockRoot(ctx, parentRoot), "Could not save genesis state")
proposerServer := &Server{
BeaconDB: db,
HeadFetcher: &mock.ChainService{State: beaconState, Root: parentRoot[:]},
SyncChecker: &mockSync.Sync{IsSyncing: false},
BlockReceiver: &mock.ChainService{},
ChainStartFetcher: &mockPOW.POWChain{},
Eth1InfoFetcher: &mockPOW.POWChain{},
Eth1BlockFetcher: &mockPOW.POWChain{},
MockEth1Votes: true,
AttPool: attestations.NewPool(),
SlashingsPool: slashings.NewPool(),
ExitPool: voluntaryexits.NewPool(),
StateGen: stategen.New(db, sc),
}
randaoReveal, err := testutil.RandaoReveal(beaconState, 0, privKeys)
require.NoError(t, err)
graffiti := bytesutil.ToBytes32([]byte("eth2"))
req := &ethpb.BlockRequest{
Slot: 1,
RandaoReveal: randaoReveal,
Graffiti: graffiti[:],
}
proposerSlashings := make([]*ethpb.ProposerSlashing, params.BeaconConfig().MaxProposerSlashings)
for i := uint64(0); i < params.BeaconConfig().MaxProposerSlashings; i++ {
proposerSlashing, err := testutil.GenerateProposerSlashingForValidator(
beaconState,
privKeys[i],
i, /* validator index */
)
require.NoError(t, err)
proposerSlashings[i] = proposerSlashing
err = proposerServer.SlashingsPool.InsertProposerSlashing(context.Background(), beaconState, proposerSlashing)
require.NoError(t, err)
}
attSlashings := make([]*ethpb.AttesterSlashing, params.BeaconConfig().MaxAttesterSlashings)
for i := uint64(0); i < params.BeaconConfig().MaxAttesterSlashings; i++ {
attesterSlashing, err := testutil.GenerateAttesterSlashingForValidator(
beaconState,
privKeys[i+params.BeaconConfig().MaxProposerSlashings],
i+params.BeaconConfig().MaxProposerSlashings, /* validator index */
)
require.NoError(t, err)
attSlashings[i] = attesterSlashing
err = proposerServer.SlashingsPool.InsertAttesterSlashing(context.Background(), beaconState, attesterSlashing)
require.NoError(t, err)
}
block, err := proposerServer.GetBlock(ctx, req)
require.NoError(t, err)
assert.Equal(t, req.Slot, block.Slot, "Expected block to have slot of 1")
assert.DeepEqual(t, parentRoot[:], block.ParentRoot, "Expected block to have correct parent root")
assert.DeepEqual(t, randaoReveal, block.Body.RandaoReveal, "Expected block to have correct randao reveal")
assert.DeepEqual(t, req.Graffiti, block.Body.Graffiti, "Expected block to have correct graffiti")
assert.Equal(t, params.BeaconConfig().MaxProposerSlashings, uint64(len(block.Body.ProposerSlashings)))
assert.DeepEqual(t, proposerSlashings, block.Body.ProposerSlashings)
assert.Equal(t, params.BeaconConfig().MaxAttesterSlashings, uint64(len(block.Body.AttesterSlashings)))
assert.DeepEqual(t, attSlashings, block.Body.AttesterSlashings)
}
func TestGetBlock_AddsUnaggregatedAtts(t *testing.T) {
db, sc := dbutil.SetupDB(t)
ctx := context.Background()
params.SetupTestConfigCleanup(t)
params.OverrideBeaconConfig(params.MainnetConfig())
beaconState, privKeys := testutil.DeterministicGenesisState(t, params.BeaconConfig().MinGenesisActiveValidatorCount)
stateRoot, err := beaconState.HashTreeRoot(ctx)
require.NoError(t, err, "Could not hash genesis state")
genesis := b.NewGenesisBlock(stateRoot[:])
require.NoError(t, db.SaveBlock(ctx, genesis), "Could not save genesis block")
parentRoot, err := genesis.Block.HashTreeRoot()
require.NoError(t, err, "Could not get signing root")
require.NoError(t, db.SaveState(ctx, beaconState, parentRoot), "Could not save genesis state")
require.NoError(t, db.SaveHeadBlockRoot(ctx, parentRoot), "Could not save genesis state")
proposerServer := &Server{
BeaconDB: db,
HeadFetcher: &mock.ChainService{State: beaconState, Root: parentRoot[:]},
SyncChecker: &mockSync.Sync{IsSyncing: false},
BlockReceiver: &mock.ChainService{},
ChainStartFetcher: &mockPOW.POWChain{},
Eth1InfoFetcher: &mockPOW.POWChain{},
Eth1BlockFetcher: &mockPOW.POWChain{},
MockEth1Votes: true,
SlashingsPool: slashings.NewPool(),
AttPool: attestations.NewPool(),
ExitPool: voluntaryexits.NewPool(),
StateGen: stategen.New(db, sc),
}
// Generate a bunch of random attestations at slot. These would be considered double votes, but
// we don't care for the purpose of this test.
var atts []*ethpb.Attestation
for i := uint64(0); len(atts) < int(params.BeaconConfig().MaxAttestations); i++ {
a, err := testutil.GenerateAttestations(beaconState, privKeys, 2, 1, true)
require.NoError(t, err)
atts = append(atts, a...)
}
// Max attestations minus one so we can almost fill the block and then include 1 unaggregated
// att to maximize inclusion.
atts = atts[:params.BeaconConfig().MaxAttestations-1]
require.NoError(t, proposerServer.AttPool.SaveAggregatedAttestations(atts))
// Generate some more random attestations with a larger spread so that we can capture at least
// one unaggregated attestation.
atts, err = testutil.GenerateAttestations(beaconState, privKeys, 300, 1, true)
require.NoError(t, err)
found := false
for _, a := range atts {
if !helpers.IsAggregated(a) {
found = true
require.NoError(t, proposerServer.AttPool.SaveUnaggregatedAttestation(a))
}
}
require.Equal(t, true, found, "No unaggregated attestations were generated")
randaoReveal, err := testutil.RandaoReveal(beaconState, 0, privKeys)
assert.NoError(t, err)
graffiti := bytesutil.ToBytes32([]byte("eth2"))
req := &ethpb.BlockRequest{
Slot: 1,
RandaoReveal: randaoReveal,
Graffiti: graffiti[:],
}
block, err := proposerServer.GetBlock(ctx, req)
require.NoError(t, err)
assert.Equal(t, req.Slot, block.Slot, "Expected block to have slot of 1")
assert.DeepEqual(t, parentRoot[:], block.ParentRoot, "Expected block to have correct parent root")
assert.DeepEqual(t, randaoReveal, block.Body.RandaoReveal, "Expected block to have correct randao reveal")
assert.DeepEqual(t, req.Graffiti, block.Body.Graffiti, "Expected block to have correct graffiti")
assert.Equal(t, params.BeaconConfig().MaxAttestations, uint64(len(block.Body.Attestations)), "Expected block atts to be aggregated down to 1")
hasUnaggregatedAtt := false
for _, a := range block.Body.Attestations {
if !helpers.IsAggregated(a) {
hasUnaggregatedAtt = true
break
}
}
assert.Equal(t, false, hasUnaggregatedAtt, "Expected block to not have unaggregated attestation")
}
func TestProposeBlock_OK(t *testing.T) {
db, _ := dbutil.SetupDB(t)
ctx := context.Background()
params.SetupTestConfigCleanup(t)
params.OverrideBeaconConfig(params.MainnetConfig())
genesis := testutil.NewBeaconBlock()
require.NoError(t, db.SaveBlock(context.Background(), genesis), "Could not save genesis block")
numDeposits := uint64(64)
beaconState, _ := testutil.DeterministicGenesisState(t, numDeposits)
bsRoot, err := beaconState.HashTreeRoot(ctx)
require.NoError(t, err)
genesisRoot, err := genesis.Block.HashTreeRoot()
require.NoError(t, err)
require.NoError(t, db.SaveState(ctx, beaconState, genesisRoot), "Could not save genesis state")
c := &mock.ChainService{Root: bsRoot[:], State: beaconState}
proposerServer := &Server{
BeaconDB: db,
ChainStartFetcher: &mockPOW.POWChain{},
Eth1InfoFetcher: &mockPOW.POWChain{},
Eth1BlockFetcher: &mockPOW.POWChain{},
BlockReceiver: c,
HeadFetcher: c,
BlockNotifier: c.BlockNotifier(),
P2P: mockp2p.NewTestP2P(t),
}
req := testutil.NewBeaconBlock()
req.Block.Slot = 5
req.Block.ParentRoot = bsRoot[:]
require.NoError(t, db.SaveBlock(ctx, req))
_, err = proposerServer.ProposeBlock(context.Background(), req)
assert.NoError(t, err, "Could not propose block correctly")
}
func TestComputeStateRoot_OK(t *testing.T) {
db, sc := dbutil.SetupDB(t)
ctx := context.Background()
params.SetupTestConfigCleanup(t)
params.OverrideBeaconConfig(params.MainnetConfig())
beaconState, privKeys := testutil.DeterministicGenesisState(t, 100)
stateRoot, err := beaconState.HashTreeRoot(ctx)
require.NoError(t, err, "Could not hash genesis state")
genesis := b.NewGenesisBlock(stateRoot[:])
require.NoError(t, db.SaveBlock(ctx, genesis), "Could not save genesis block")
parentRoot, err := genesis.Block.HashTreeRoot()
require.NoError(t, err, "Could not get signing root")
require.NoError(t, db.SaveState(ctx, beaconState, parentRoot), "Could not save genesis state")
require.NoError(t, db.SaveHeadBlockRoot(ctx, parentRoot), "Could not save genesis state")
proposerServer := &Server{
BeaconDB: db,
ChainStartFetcher: &mockPOW.POWChain{},
Eth1InfoFetcher: &mockPOW.POWChain{},
Eth1BlockFetcher: &mockPOW.POWChain{},
StateGen: stategen.New(db, sc),
}
req := testutil.NewBeaconBlock()
req.Block.ProposerIndex = 21
req.Block.ParentRoot = parentRoot[:]
req.Block.Slot = 1
require.NoError(t, beaconState.SetSlot(beaconState.Slot()+1))
randaoReveal, err := testutil.RandaoReveal(beaconState, 0, privKeys)
require.NoError(t, err)
proposerIdx, err := helpers.BeaconProposerIndex(beaconState)
require.NoError(t, err)
require.NoError(t, beaconState.SetSlot(beaconState.Slot()-1))
req.Block.Body.RandaoReveal = randaoReveal[:]
currentEpoch := helpers.CurrentEpoch(beaconState)
req.Signature, err = helpers.ComputeDomainAndSign(beaconState, currentEpoch, req.Block, params.BeaconConfig().DomainBeaconProposer, privKeys[proposerIdx])
require.NoError(t, err)
_, err = proposerServer.computeStateRoot(context.Background(), req)
require.NoError(t, err)
}
func TestPendingDeposits_Eth1DataVoteOK(t *testing.T) {
ctx := context.Background()
height := big.NewInt(int64(params.BeaconConfig().Eth1FollowDistance))
newHeight := big.NewInt(height.Int64() + 11000)
p := &mockPOW.POWChain{
LatestBlockNumber: height,
HashesByHeight: map[int][]byte{
int(height.Int64()): []byte("0x0"),
int(newHeight.Int64()): []byte("0x1"),
},
}
var votes []*ethpb.Eth1Data
blockHash := make([]byte, 32)
copy(blockHash, "0x1")
vote := &ethpb.Eth1Data{
DepositRoot: make([]byte, 32),
BlockHash: blockHash,
DepositCount: 3,
}
period := params.BeaconConfig().EpochsPerEth1VotingPeriod * params.BeaconConfig().SlotsPerEpoch
for i := 0; i <= int(period/2); i++ {
votes = append(votes, vote)
}
blockHash = make([]byte, 32)
copy(blockHash, "0x0")
beaconState := testutil.NewBeaconState()
require.NoError(t, beaconState.SetEth1DepositIndex(2))
require.NoError(t, beaconState.SetEth1Data(&ethpb.Eth1Data{
DepositRoot: make([]byte, 32),
BlockHash: blockHash,
DepositCount: 2,
}))
require.NoError(t, beaconState.SetEth1DataVotes(votes))
blk := testutil.NewBeaconBlock()
blkRoot, err := blk.Block.HashTreeRoot()
require.NoError(t, err)
bs := &Server{
ChainStartFetcher: p,
Eth1InfoFetcher: p,
Eth1BlockFetcher: p,
BlockReceiver: &mock.ChainService{State: beaconState, Root: blkRoot[:]},
HeadFetcher: &mock.ChainService{State: beaconState, Root: blkRoot[:]},
}
// It should also return the recent deposits after their follow window.
p.LatestBlockNumber = big.NewInt(0).Add(p.LatestBlockNumber, big.NewInt(10000))
_, eth1Height, err := bs.canonicalEth1Data(ctx, beaconState, &ethpb.Eth1Data{})
require.NoError(t, err)
assert.Equal(t, 0, eth1Height.Cmp(height))
newState, err := b.ProcessEth1DataInBlock(beaconState, blk.Block)
require.NoError(t, err)
if proto.Equal(newState.Eth1Data(), vote) {
t.Errorf("eth1data in the state equal to vote, when not expected to"+
"have majority: Got %v", vote)
}
blk.Block.Body.Eth1Data = vote
_, eth1Height, err = bs.canonicalEth1Data(ctx, beaconState, vote)
require.NoError(t, err)
assert.Equal(t, 0, eth1Height.Cmp(newHeight))
newState, err = b.ProcessEth1DataInBlock(beaconState, blk.Block)
require.NoError(t, err)
if !proto.Equal(newState.Eth1Data(), vote) {
t.Errorf("eth1data in the state not of the expected kind: Got %v but wanted %v", newState.Eth1Data(), vote)
}
}
func TestPendingDeposits_OutsideEth1FollowWindow(t *testing.T) {
ctx := context.Background()
height := big.NewInt(int64(params.BeaconConfig().Eth1FollowDistance))
p := &mockPOW.POWChain{
LatestBlockNumber: height,
HashesByHeight: map[int][]byte{
int(height.Int64()): []byte("0x0"),
},
}
beaconState, err := beaconstate.InitializeFromProto(&pbp2p.BeaconState{
Eth1Data: &ethpb.Eth1Data{
BlockHash: bytesutil.PadTo([]byte("0x0"), 32),
DepositRoot: make([]byte, 32),
},
Eth1DepositIndex: 2,
})
require.NoError(t, err)
var mockSig [96]byte
var mockCreds [32]byte
// Using the merkleTreeIndex as the block number for this test...
readyDeposits := []*dbpb.DepositContainer{
{
Index: 0,
Eth1BlockHeight: 2,
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: bytesutil.PadTo([]byte("a"), 48),
Signature: mockSig[:],
WithdrawalCredentials: mockCreds[:],
}},
},
{
Index: 1,
Eth1BlockHeight: 8,
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: bytesutil.PadTo([]byte("b"), 48),
Signature: mockSig[:],
WithdrawalCredentials: mockCreds[:],
}},
},
}
recentDeposits := []*dbpb.DepositContainer{
{
Index: 2,
Eth1BlockHeight: 400,
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: bytesutil.PadTo([]byte("c"), 48),
Signature: mockSig[:],
WithdrawalCredentials: mockCreds[:],
}},
},
{
Index: 3,
Eth1BlockHeight: 600,
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: bytesutil.PadTo([]byte("d"), 48),
Signature: mockSig[:],
WithdrawalCredentials: mockCreds[:],
}},
},
}
depositCache, err := depositcache.NewDepositCache()
require.NoError(t, err)
depositTrie, err := trieutil.NewTrie(int(params.BeaconConfig().DepositContractTreeDepth))
require.NoError(t, err, "Could not setup deposit trie")
for _, dp := range append(readyDeposits, recentDeposits...) {
depositHash, err := dp.Deposit.Data.HashTreeRoot()
require.NoError(t, err, "Unable to determine hashed value of deposit")
depositTrie.Insert(depositHash[:], int(dp.Index))
depositCache.InsertDeposit(ctx, dp.Deposit, dp.Eth1BlockHeight, dp.Index, depositTrie.Root())
}
for _, dp := range recentDeposits {
depositCache.InsertPendingDeposit(ctx, dp.Deposit, dp.Eth1BlockHeight, dp.Index, depositTrie.Root())
}
blk := testutil.NewBeaconBlock()
blk.Block.Slot = beaconState.Slot()
blkRoot, err := blk.HashTreeRoot()
require.NoError(t, err)
bs := &Server{
ChainStartFetcher: p,
Eth1InfoFetcher: p,
Eth1BlockFetcher: p,
DepositFetcher: depositCache,
PendingDepositsFetcher: depositCache,
BlockReceiver: &mock.ChainService{State: beaconState, Root: blkRoot[:]},
HeadFetcher: &mock.ChainService{State: beaconState, Root: blkRoot[:]},
}
deposits, err := bs.deposits(ctx, beaconState, &ethpb.Eth1Data{})
require.NoError(t, err)
assert.Equal(t, 0, len(deposits), "Received unexpected list of deposits")
// It should not return the recent deposits after their follow window.
// as latest block number makes no difference in retrieval of deposits
p.LatestBlockNumber = big.NewInt(0).Add(p.LatestBlockNumber, big.NewInt(10000))
deposits, err = bs.deposits(ctx, beaconState, &ethpb.Eth1Data{})
require.NoError(t, err)
assert.Equal(t, 0, len(deposits), "Received unexpected number of pending deposits")
}
func TestPendingDeposits_FollowsCorrectEth1Block(t *testing.T) {
ctx := context.Background()
height := big.NewInt(int64(params.BeaconConfig().Eth1FollowDistance))
newHeight := big.NewInt(height.Int64() + 11000)
p := &mockPOW.POWChain{
LatestBlockNumber: height,
HashesByHeight: map[int][]byte{
int(height.Int64()): []byte("0x0"),
int(newHeight.Int64()): []byte("0x1"),
},
}
var votes []*ethpb.Eth1Data
vote := &ethpb.Eth1Data{
BlockHash: bytesutil.PadTo([]byte("0x1"), 32),
DepositRoot: make([]byte, 32),
DepositCount: 7,
}
period := params.BeaconConfig().EpochsPerEth1VotingPeriod * params.BeaconConfig().SlotsPerEpoch
for i := 0; i <= int(period/2); i++ {
votes = append(votes, vote)
}
beaconState, err := beaconstate.InitializeFromProto(&pbp2p.BeaconState{
Eth1Data: &ethpb.Eth1Data{
BlockHash: []byte("0x0"),
DepositRoot: make([]byte, 32),
DepositCount: 5,
},
Eth1DepositIndex: 1,
Eth1DataVotes: votes,
})
require.NoError(t, err)
blk := testutil.NewBeaconBlock()
blk.Block.Slot = beaconState.Slot()
blkRoot, err := blk.HashTreeRoot()
require.NoError(t, err)
var mockSig [96]byte
var mockCreds [32]byte
// Using the merkleTreeIndex as the block number for this test...
readyDeposits := []*dbpb.DepositContainer{
{
Index: 0,
Eth1BlockHeight: 8,
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: bytesutil.PadTo([]byte("a"), 48),
Signature: mockSig[:],
WithdrawalCredentials: mockCreds[:],
}},
},
{
Index: 1,
Eth1BlockHeight: 14,
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: bytesutil.PadTo([]byte("b"), 48),
Signature: mockSig[:],
WithdrawalCredentials: mockCreds[:],
}},
},
}
recentDeposits := []*dbpb.DepositContainer{
{
Index: 2,
Eth1BlockHeight: 5000,
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: bytesutil.PadTo([]byte("c"), 48),
Signature: mockSig[:],
WithdrawalCredentials: mockCreds[:],
}},
},
{
Index: 3,
Eth1BlockHeight: 6000,
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: bytesutil.PadTo([]byte("d"), 48),
Signature: mockSig[:],
WithdrawalCredentials: mockCreds[:],
}},
},
}
depositCache, err := depositcache.NewDepositCache()
require.NoError(t, err)
depositTrie, err := trieutil.NewTrie(int(params.BeaconConfig().DepositContractTreeDepth))
require.NoError(t, err, "Could not setup deposit trie")
for _, dp := range append(readyDeposits, recentDeposits...) {
depositHash, err := dp.Deposit.Data.HashTreeRoot()
require.NoError(t, err, "Unable to determine hashed value of deposit")
depositTrie.Insert(depositHash[:], int(dp.Index))
depositCache.InsertDeposit(ctx, dp.Deposit, dp.Eth1BlockHeight, dp.Index, depositTrie.Root())
}
for _, dp := range recentDeposits {
depositCache.InsertPendingDeposit(ctx, dp.Deposit, dp.Eth1BlockHeight, dp.Index, depositTrie.Root())
}
bs := &Server{
ChainStartFetcher: p,
Eth1InfoFetcher: p,
Eth1BlockFetcher: p,
DepositFetcher: depositCache,
PendingDepositsFetcher: depositCache,
BlockReceiver: &mock.ChainService{State: beaconState, Root: blkRoot[:]},
HeadFetcher: &mock.ChainService{State: beaconState, Root: blkRoot[:]},
}
deposits, err := bs.deposits(ctx, beaconState, &ethpb.Eth1Data{})
require.NoError(t, err)
assert.Equal(t, 0, len(deposits), "Received unexpected list of deposits")
// It should also return the recent deposits after their follow window.
p.LatestBlockNumber = big.NewInt(0).Add(p.LatestBlockNumber, big.NewInt(10000))
// we should get our pending deposits once this vote pushes the vote tally to include
// the updated eth1 data.
deposits, err = bs.deposits(ctx, beaconState, vote)
require.NoError(t, err)
assert.Equal(t, len(recentDeposits), len(deposits), "Received unexpected number of pending deposits")
}
func TestPendingDeposits_CantReturnBelowStateEth1DepositIndex(t *testing.T) {
ctx := context.Background()
height := big.NewInt(int64(params.BeaconConfig().Eth1FollowDistance))
p := &mockPOW.POWChain{
LatestBlockNumber: height,
HashesByHeight: map[int][]byte{
int(height.Int64()): []byte("0x0"),
},
}
beaconState := testutil.NewBeaconState()
require.NoError(t, beaconState.SetEth1Data(&ethpb.Eth1Data{
BlockHash: bytesutil.PadTo([]byte("0x0"), 32),
DepositRoot: make([]byte, 32),
DepositCount: 100,
}))
require.NoError(t, beaconState.SetEth1DepositIndex(10))
blk := testutil.NewBeaconBlock()
blk.Block.Slot = beaconState.Slot()
blkRoot, err := blk.HashTreeRoot()
require.NoError(t, err)
var mockSig [96]byte
var mockCreds [32]byte
readyDeposits := []*dbpb.DepositContainer{
{
Index: 0,
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: bytesutil.PadTo([]byte("a"), 48),
Signature: mockSig[:],
WithdrawalCredentials: mockCreds[:],
}},
},
{
Index: 1,
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: bytesutil.PadTo([]byte("b"), 48),
Signature: mockSig[:],
WithdrawalCredentials: mockCreds[:],
}},
},
}
var recentDeposits []*dbpb.DepositContainer
for i := int64(2); i < 16; i++ {
recentDeposits = append(recentDeposits, &dbpb.DepositContainer{
Index: i,
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: bytesutil.PadTo([]byte{byte(i)}, 48),
Signature: mockSig[:],
WithdrawalCredentials: mockCreds[:],
}},
})
}
depositTrie, err := trieutil.NewTrie(int(params.BeaconConfig().DepositContractTreeDepth))
require.NoError(t, err, "Could not setup deposit trie")
depositCache, err := depositcache.NewDepositCache()
require.NoError(t, err)
for _, dp := range append(readyDeposits, recentDeposits...) {
depositHash, err := dp.Deposit.Data.HashTreeRoot()
require.NoError(t, err, "Unable to determine hashed value of deposit")
depositTrie.Insert(depositHash[:], int(dp.Index))
depositCache.InsertDeposit(ctx, dp.Deposit, uint64(dp.Index), dp.Index, depositTrie.Root())
}
for _, dp := range recentDeposits {
depositCache.InsertPendingDeposit(ctx, dp.Deposit, uint64(dp.Index), dp.Index, depositTrie.Root())
}
bs := &Server{
ChainStartFetcher: p,
Eth1InfoFetcher: p,
Eth1BlockFetcher: p,
DepositFetcher: depositCache,
PendingDepositsFetcher: depositCache,
BlockReceiver: &mock.ChainService{State: beaconState, Root: blkRoot[:]},
HeadFetcher: &mock.ChainService{State: beaconState, Root: blkRoot[:]},
}
// It should also return the recent deposits after their follow window.
p.LatestBlockNumber = big.NewInt(0).Add(p.LatestBlockNumber, big.NewInt(10000))
deposits, err := bs.deposits(ctx, beaconState, &ethpb.Eth1Data{})
require.NoError(t, err)
expectedDeposits := 6
assert.Equal(t, expectedDeposits, len(deposits), "Received unexpected number of pending deposits")
}
func TestPendingDeposits_CantReturnMoreThanMax(t *testing.T) {
ctx := context.Background()
height := big.NewInt(int64(params.BeaconConfig().Eth1FollowDistance))
p := &mockPOW.POWChain{
LatestBlockNumber: height,
HashesByHeight: map[int][]byte{
int(height.Int64()): []byte("0x0"),
},
}
beaconState, err := beaconstate.InitializeFromProto(&pbp2p.BeaconState{
Eth1Data: &ethpb.Eth1Data{
BlockHash: bytesutil.PadTo([]byte("0x0"), 32),
DepositRoot: make([]byte, 32),
DepositCount: 100,
},
Eth1DepositIndex: 2,
})
require.NoError(t, err)
blk := testutil.NewBeaconBlock()
blk.Block.Slot = beaconState.Slot()
blkRoot, err := blk.HashTreeRoot()
require.NoError(t, err)
var mockSig [96]byte
var mockCreds [32]byte
readyDeposits := []*dbpb.DepositContainer{
{
Index: 0,
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: bytesutil.PadTo([]byte("a"), 48),
Signature: mockSig[:],
WithdrawalCredentials: mockCreds[:],
}},
},
{
Index: 1,
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: bytesutil.PadTo([]byte("b"), 48),
Signature: mockSig[:],
WithdrawalCredentials: mockCreds[:],
}},
},
}
var recentDeposits []*dbpb.DepositContainer
for i := int64(2); i < 22; i++ {
recentDeposits = append(recentDeposits, &dbpb.DepositContainer{
Index: i,
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: bytesutil.PadTo([]byte{byte(i)}, 48),
Signature: mockSig[:],
WithdrawalCredentials: mockCreds[:],
}},
})
}
depositTrie, err := trieutil.NewTrie(int(params.BeaconConfig().DepositContractTreeDepth))
require.NoError(t, err, "Could not setup deposit trie")
depositCache, err := depositcache.NewDepositCache()
require.NoError(t, err)
for _, dp := range append(readyDeposits, recentDeposits...) {
depositHash, err := dp.Deposit.Data.HashTreeRoot()
require.NoError(t, err, "Unable to determine hashed value of deposit")
depositTrie.Insert(depositHash[:], int(dp.Index))
depositCache.InsertDeposit(ctx, dp.Deposit, height.Uint64(), dp.Index, depositTrie.Root())
}
for _, dp := range recentDeposits {
depositCache.InsertPendingDeposit(ctx, dp.Deposit, height.Uint64(), dp.Index, depositTrie.Root())
}
bs := &Server{
ChainStartFetcher: p,
Eth1InfoFetcher: p,
Eth1BlockFetcher: p,
DepositFetcher: depositCache,
PendingDepositsFetcher: depositCache,
BlockReceiver: &mock.ChainService{State: beaconState, Root: blkRoot[:]},
HeadFetcher: &mock.ChainService{State: beaconState, Root: blkRoot[:]},
}
// It should also return the recent deposits after their follow window.
p.LatestBlockNumber = big.NewInt(0).Add(p.LatestBlockNumber, big.NewInt(10000))
deposits, err := bs.deposits(ctx, beaconState, &ethpb.Eth1Data{})
require.NoError(t, err)
assert.Equal(t, params.BeaconConfig().MaxDeposits, uint64(len(deposits)), "Received unexpected number of pending deposits")
}
func TestPendingDeposits_CantReturnMoreThanDepositCount(t *testing.T) {
ctx := context.Background()
height := big.NewInt(int64(params.BeaconConfig().Eth1FollowDistance))
p := &mockPOW.POWChain{
LatestBlockNumber: height,
HashesByHeight: map[int][]byte{
int(height.Int64()): []byte("0x0"),
},
}
beaconState, err := beaconstate.InitializeFromProto(&pbp2p.BeaconState{
Eth1Data: &ethpb.Eth1Data{
BlockHash: bytesutil.PadTo([]byte("0x0"), 32),
DepositRoot: make([]byte, 32),
DepositCount: 5,
},
Eth1DepositIndex: 2,
})
require.NoError(t, err)
blk := testutil.NewBeaconBlock()
blk.Block.Slot = beaconState.Slot()
blkRoot, err := blk.HashTreeRoot()
require.NoError(t, err)
var mockSig [96]byte
var mockCreds [32]byte
readyDeposits := []*dbpb.DepositContainer{
{
Index: 0,
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: bytesutil.PadTo([]byte("a"), 48),
Signature: mockSig[:],
WithdrawalCredentials: mockCreds[:],
}},
},
{
Index: 1,
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: bytesutil.PadTo([]byte("b"), 48),
Signature: mockSig[:],
WithdrawalCredentials: mockCreds[:],
}},
},
}
var recentDeposits []*dbpb.DepositContainer
for i := int64(2); i < 22; i++ {
recentDeposits = append(recentDeposits, &dbpb.DepositContainer{
Index: i,
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: bytesutil.PadTo([]byte{byte(i)}, 48),
Signature: mockSig[:],
WithdrawalCredentials: mockCreds[:],
}},
})
}
depositTrie, err := trieutil.NewTrie(int(params.BeaconConfig().DepositContractTreeDepth))
require.NoError(t, err, "Could not setup deposit trie")
depositCache, err := depositcache.NewDepositCache()
require.NoError(t, err)
for _, dp := range append(readyDeposits, recentDeposits...) {
depositHash, err := dp.Deposit.Data.HashTreeRoot()
require.NoError(t, err, "Unable to determine hashed value of deposit")
depositTrie.Insert(depositHash[:], int(dp.Index))
depositCache.InsertDeposit(ctx, dp.Deposit, uint64(dp.Index), dp.Index, depositTrie.Root())
}
for _, dp := range recentDeposits {
depositCache.InsertPendingDeposit(ctx, dp.Deposit, uint64(dp.Index), dp.Index, depositTrie.Root())
}
bs := &Server{
BlockReceiver: &mock.ChainService{State: beaconState, Root: blkRoot[:]},
HeadFetcher: &mock.ChainService{State: beaconState, Root: blkRoot[:]},
ChainStartFetcher: p,
Eth1InfoFetcher: p,
Eth1BlockFetcher: p,
DepositFetcher: depositCache,
PendingDepositsFetcher: depositCache,
}
// It should also return the recent deposits after their follow window.
p.LatestBlockNumber = big.NewInt(0).Add(p.LatestBlockNumber, big.NewInt(10000))
deposits, err := bs.deposits(ctx, beaconState, &ethpb.Eth1Data{})
require.NoError(t, err)
assert.Equal(t, 3, len(deposits), "Received unexpected number of pending deposits")
}
func TestDepositTrie_UtilizesCachedFinalizedDeposits(t *testing.T) {
ctx := context.Background()
resetCfg := featureconfig.InitWithReset(&featureconfig.Flags{EnableFinalizedDepositsCache: true})
defer resetCfg()
height := big.NewInt(int64(params.BeaconConfig().Eth1FollowDistance))
p := &mockPOW.POWChain{
LatestBlockNumber: height,
HashesByHeight: map[int][]byte{
int(height.Int64()): []byte("0x0"),
},
}
beaconState, err := beaconstate.InitializeFromProto(&pbp2p.BeaconState{
Eth1Data: &ethpb.Eth1Data{
BlockHash: bytesutil.PadTo([]byte("0x0"), 32),
DepositRoot: make([]byte, 32),
DepositCount: 4,
},
Eth1DepositIndex: 1,
})
require.NoError(t, err)
blk := testutil.NewBeaconBlock()
blk.Block.Slot = beaconState.Slot()
blkRoot, err := blk.Block.HashTreeRoot()
require.NoError(t, err)
var mockSig [96]byte
var mockCreds [32]byte
// Using the merkleTreeIndex as the block number for this test...
finalizedDeposits := []*dbpb.DepositContainer{
{
Index: 0,
Eth1BlockHeight: 10,
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: bytesutil.PadTo([]byte("a"), 48),
Signature: mockSig[:],
WithdrawalCredentials: mockCreds[:],
}},
},
{
Index: 1,
Eth1BlockHeight: 10,
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: bytesutil.PadTo([]byte("b"), 48),
Signature: mockSig[:],
WithdrawalCredentials: mockCreds[:],
}},
},
}
recentDeposits := []*dbpb.DepositContainer{
{
Index: 2,
Eth1BlockHeight: 11,
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: bytesutil.PadTo([]byte("c"), 48),
Signature: mockSig[:],
WithdrawalCredentials: mockCreds[:],
}},
},
{
Index: 3,
Eth1BlockHeight: 11,
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: bytesutil.PadTo([]byte("d"), 48),
Signature: mockSig[:],
WithdrawalCredentials: mockCreds[:],
}},
},
}
depositCache, err := depositcache.NewDepositCache()
require.NoError(t, err)
depositTrie, err := trieutil.NewTrie(int(params.BeaconConfig().DepositContractTreeDepth))
require.NoError(t, err, "Could not setup deposit trie")
for _, dp := range append(finalizedDeposits, recentDeposits...) {
depositHash, err := dp.Deposit.Data.HashTreeRoot()
require.NoError(t, err, "Unable to determine hashed value of deposit")
depositTrie.Insert(depositHash[:], int(dp.Index))
depositCache.InsertDeposit(ctx, dp.Deposit, dp.Eth1BlockHeight, dp.Index, depositTrie.Root())
}
depositCache.InsertFinalizedDeposits(ctx, 2)
for _, dp := range recentDeposits {
depositCache.InsertPendingDeposit(ctx, dp.Deposit, dp.Eth1BlockHeight, dp.Index, depositTrie.Root())
}
bs := &Server{
ChainStartFetcher: p,
Eth1InfoFetcher: p,
Eth1BlockFetcher: p,
DepositFetcher: depositCache,
PendingDepositsFetcher: depositCache,
BlockReceiver: &mock.ChainService{State: beaconState, Root: blkRoot[:]},
HeadFetcher: &mock.ChainService{State: beaconState, Root: blkRoot[:]},
}
trie, err := bs.depositTrie(ctx, big.NewInt(int64(params.BeaconConfig().Eth1FollowDistance)))
require.NoError(t, err)
actualRoot := trie.HashTreeRoot()
expectedRoot := depositTrie.HashTreeRoot()
assert.Equal(t, expectedRoot, actualRoot, "Incorrect deposit trie root")
}
func TestEth1Data_EmptyVotesFetchBlockHashFailure(t *testing.T) {
beaconState, err := beaconstate.InitializeFromProto(&pbp2p.BeaconState{
Eth1Data: &ethpb.Eth1Data{
BlockHash: []byte{'a'},
},
Eth1DataVotes: []*ethpb.Eth1Data{},
})
require.NoError(t, err)
p := &mockPOW.FaultyMockPOWChain{
HashesByHeight: make(map[int][]byte),
}
proposerServer := &Server{
ChainStartFetcher: p,
Eth1InfoFetcher: p,
Eth1BlockFetcher: p,
BlockReceiver: &mock.ChainService{State: beaconState},
HeadFetcher: &mock.ChainService{State: beaconState},
}
_, err = proposerServer.eth1Data(context.Background(), beaconState.Slot()+1)
assert.NoError(t, err, "A failed request should not have returned an error, got %v")
}
func TestDefaultEth1Data_NoBlockExists(t *testing.T) {
ctx := context.Background()
height := big.NewInt(int64(params.BeaconConfig().Eth1FollowDistance))
deps := []*dbpb.DepositContainer{
{
Index: 0,
Eth1BlockHeight: 8,
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: bytesutil.PadTo([]byte("a"), 48),
Signature: make([]byte, 96),
WithdrawalCredentials: make([]byte, 32),
}},
},
{
Index: 1,
Eth1BlockHeight: 14,
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: bytesutil.PadTo([]byte("b"), 48),
Signature: make([]byte, 96),
WithdrawalCredentials: make([]byte, 32),
}},
},
}
depositTrie, err := trieutil.NewTrie(int(params.BeaconConfig().DepositContractTreeDepth))
require.NoError(t, err, "Could not setup deposit trie")
depositCache, err := depositcache.NewDepositCache()
require.NoError(t, err)
for _, dp := range deps {
depositCache.InsertDeposit(context.Background(), dp.Deposit, dp.Eth1BlockHeight, dp.Index, depositTrie.Root())
}
p := &mockPOW.POWChain{
LatestBlockNumber: height,
HashesByHeight: map[int][]byte{
0: []byte("hash0"),
12: []byte("hash12"),
},
}
proposerServer := &Server{
ChainStartFetcher: p,
Eth1InfoFetcher: p,
Eth1BlockFetcher: p,
DepositFetcher: depositCache,
PendingDepositsFetcher: depositCache,
}
defEth1Data := &ethpb.Eth1Data{
DepositCount: 10,
BlockHash: []byte{'t', 'e', 's', 't'},
DepositRoot: []byte{'r', 'o', 'o', 't'},
}
p.Eth1Data = defEth1Data
result, err := proposerServer.defaultEth1DataResponse(ctx, big.NewInt(16))
require.NoError(t, err)
if !proto.Equal(result, defEth1Data) {
t.Errorf("Did not receive default eth1data. Wanted %v but got %v", defEth1Data, result)
}
}
func TestEth1Data(t *testing.T) {
slot := uint64(20000)
p := &mockPOW.POWChain{
BlockNumberByTime: map[uint64]*big.Int{
slot * params.BeaconConfig().SecondsPerSlot: big.NewInt(8196),
},
HashesByHeight: map[int][]byte{
8180: []byte("8180"),
},
Eth1Data: &ethpb.Eth1Data{
DepositCount: 55,
},
}
headState := testutil.NewBeaconState()
require.NoError(t, headState.SetEth1Data(&ethpb.Eth1Data{DepositCount: 55}))
depositCache, err := depositcache.NewDepositCache()
require.NoError(t, err)
ps := &Server{
ChainStartFetcher: p,
Eth1InfoFetcher: p,
Eth1BlockFetcher: p,
DepositFetcher: depositCache,
HeadFetcher: &mock.ChainService{State: headState},
}
ctx := context.Background()
eth1Data, err := ps.eth1Data(ctx, slot)
require.NoError(t, err)
assert.Equal(t, uint64(55), eth1Data.DepositCount)
}
func TestEth1Data_SmallerDepositCount(t *testing.T) {
slot := uint64(20000)
deps := []*dbpb.DepositContainer{
{
Index: 0,
Eth1BlockHeight: 8,
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: bytesutil.PadTo([]byte("a"), 48),
Signature: make([]byte, 96),
WithdrawalCredentials: make([]byte, 32),
}},
},
{
Index: 1,
Eth1BlockHeight: 14,
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: bytesutil.PadTo([]byte("b"), 48),
Signature: make([]byte, 96),
WithdrawalCredentials: make([]byte, 32),
}},
},
}
depositTrie, err := trieutil.NewTrie(int(params.BeaconConfig().DepositContractTreeDepth))
require.NoError(t, err, "Could not setup deposit trie")
depositCache, err := depositcache.NewDepositCache()
require.NoError(t, err)
for _, dp := range deps {
depositCache.InsertDeposit(context.Background(), dp.Deposit, dp.Eth1BlockHeight, dp.Index, depositTrie.Root())
}
p := &mockPOW.POWChain{
BlockNumberByTime: map[uint64]*big.Int{
slot * params.BeaconConfig().SecondsPerSlot: big.NewInt(4096),
},
HashesByHeight: map[int][]byte{
4080: []byte("4080"),
},
Eth1Data: &ethpb.Eth1Data{
DepositCount: 55,
},
}
ps := &Server{
ChainStartFetcher: p,
Eth1InfoFetcher: p,
Eth1BlockFetcher: p,
HeadFetcher: &mock.ChainService{ETH1Data: &ethpb.Eth1Data{DepositCount: 10}},
DepositFetcher: depositCache,
}
ctx := context.Background()
eth1Data, err := ps.eth1Data(ctx, slot)
require.NoError(t, err)
// Will default to 10 as the current deposit count in the
// cache is only 2.
assert.Equal(t, uint64(10), eth1Data.DepositCount)
}
func TestEth1Data_MockEnabled(t *testing.T) {
db, _ := dbutil.SetupDB(t)
// If a mock eth1 data votes is specified, we use the following for the
// eth1data we provide to every proposer based on https://github.com/ethereum/eth2.0-pm/issues/62:
//
// slot_in_voting_period = current_slot % SLOTS_PER_ETH1_VOTING_PERIOD
// Eth1Data(
// DepositRoot = hash(current_epoch + slot_in_voting_period),
// DepositCount = state.eth1_deposit_index,
// BlockHash = hash(hash(current_epoch + slot_in_voting_period)),
// )
ctx := context.Background()
headState := testutil.NewBeaconState()
require.NoError(t, headState.SetEth1DepositIndex(64))
ps := &Server{
HeadFetcher: &mock.ChainService{State: headState},
BeaconDB: db,
MockEth1Votes: true,
}
headBlockRoot := [32]byte{1, 2, 3}
require.NoError(t, db.SaveState(ctx, headState, headBlockRoot))
require.NoError(t, db.SaveHeadBlockRoot(ctx, headBlockRoot))
eth1Data, err := ps.eth1Data(ctx, 100)
require.NoError(t, err)
period := params.BeaconConfig().EpochsPerEth1VotingPeriod * params.BeaconConfig().SlotsPerEpoch
wantedSlot := 100 % period
currentEpoch := helpers.SlotToEpoch(100)
var enc []byte
enc = fastssz.MarshalUint64(enc, currentEpoch+wantedSlot)
depRoot := hashutil.Hash(enc)
blockHash := hashutil.Hash(depRoot[:])
want := &ethpb.Eth1Data{
DepositRoot: depRoot[:],
BlockHash: blockHash[:],
DepositCount: 64,
}
if !proto.Equal(eth1Data, want) {
t.Errorf("Wanted %v, received %v", want, eth1Data)
}
}
func TestEth1DataMajorityVote_ChooseHighestCount(t *testing.T) {
p := &mockPOW.POWChain{
BlockNumberByTime: map[uint64]*big.Int{
32 * params.BeaconConfig().SecondsPerSlot: big.NewInt(50),
64 * params.BeaconConfig().SecondsPerSlot: big.NewInt(100),
},
HashesByHeight: map[int][]byte{
int(100 - params.BeaconConfig().Eth1FollowDistance - 1): []byte("first"),
int(100 - params.BeaconConfig().Eth1FollowDistance): []byte("second"),
},
}
dc := dbpb.DepositContainer{
Index: 0,
Eth1BlockHeight: 0,
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: bytesutil.PadTo([]byte("a"), 48),
Signature: make([]byte, 96),
WithdrawalCredentials: make([]byte, 32),
}},
}
depositTrie, err := trieutil.NewTrie(int(params.BeaconConfig().DepositContractTreeDepth))
require.NoError(t, err)
depositCache, err := depositcache.NewDepositCache()
require.NoError(t, err)
depositCache.InsertDeposit(context.Background(), dc.Deposit, dc.Eth1BlockHeight, dc.Index, depositTrie.Root())
beaconState, err := beaconstate.InitializeFromProto(&pbp2p.BeaconState{
Slot: 64,
Eth1DataVotes: []*ethpb.Eth1Data{
{BlockHash: []byte("first"), DepositCount: 1},
{BlockHash: []byte("first"), DepositCount: 1},
{BlockHash: []byte("second"), DepositCount: 1},
},
})
require.NoError(t, err)
ps := &Server{
ChainStartFetcher: p,
Eth1InfoFetcher: p,
Eth1BlockFetcher: p,
BlockFetcher: p,
DepositFetcher: depositCache,
HeadFetcher: &mock.ChainService{ETH1Data: &ethpb.Eth1Data{DepositCount: 1}},
}
ctx := context.Background()
majorityVoteEth1Data, err := ps.eth1DataMajorityVote(ctx, beaconState)
require.NoError(t, err)
hash := majorityVoteEth1Data.BlockHash
expectedHash := []byte("first")
if !bytes.Equal(hash, expectedHash) {
t.Errorf("Chosen eth1data for block hash %v vs expected %v", hash, expectedHash)
}
}
func TestEth1DataMajorityVote_HighestCountBeforeRange_ChooseHighestCountWithinRange(t *testing.T) {
p := &mockPOW.POWChain{
BlockNumberByTime: map[uint64]*big.Int{
32 * params.BeaconConfig().SecondsPerSlot: big.NewInt(50),
64 * params.BeaconConfig().SecondsPerSlot: big.NewInt(100),
},
HashesByHeight: map[int][]byte{
int(50 - params.BeaconConfig().Eth1FollowDistance - 1): []byte("before_range"),
int(100 - params.BeaconConfig().Eth1FollowDistance - 1): []byte("first"),
int(100 - params.BeaconConfig().Eth1FollowDistance): []byte("second"),
},
}
dc := dbpb.DepositContainer{
Index: 0,
Eth1BlockHeight: 0,
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: bytesutil.PadTo([]byte("a"), 48),
Signature: make([]byte, 96),
WithdrawalCredentials: make([]byte, 32),
}},
}
depositTrie, err := trieutil.NewTrie(int(params.BeaconConfig().DepositContractTreeDepth))
require.NoError(t, err)
depositCache, err := depositcache.NewDepositCache()
require.NoError(t, err)
depositCache.InsertDeposit(context.Background(), dc.Deposit, dc.Eth1BlockHeight, dc.Index, depositTrie.Root())
beaconState, err := beaconstate.InitializeFromProto(&pbp2p.BeaconState{
Slot: 64,
Eth1DataVotes: []*ethpb.Eth1Data{
{BlockHash: []byte("before_range"), DepositCount: 1},
{BlockHash: []byte("before_range"), DepositCount: 1},
{BlockHash: []byte("first"), DepositCount: 1},
},
})
require.NoError(t, err)
ps := &Server{
ChainStartFetcher: p,
Eth1InfoFetcher: p,
Eth1BlockFetcher: p,
BlockFetcher: p,
DepositFetcher: depositCache,
HeadFetcher: &mock.ChainService{ETH1Data: &ethpb.Eth1Data{DepositCount: 1}},
}
ctx := context.Background()
majorityVoteEth1Data, err := ps.eth1DataMajorityVote(ctx, beaconState)
require.NoError(t, err)
hash := majorityVoteEth1Data.BlockHash
expectedHash := []byte("first")
if !bytes.Equal(hash, expectedHash) {
t.Errorf("Chosen eth1data for block hash %v vs expected %v", hash, expectedHash)
}
}
func TestEth1DataMajorityVote_HighestCountAfterRange_ChooseHighestCountWithinRange(t *testing.T) {
p := &mockPOW.POWChain{
BlockNumberByTime: map[uint64]*big.Int{
32 * params.BeaconConfig().SecondsPerSlot: big.NewInt(50),
64 * params.BeaconConfig().SecondsPerSlot: big.NewInt(100),
},
HashesByHeight: map[int][]byte{
int(100 - params.BeaconConfig().Eth1FollowDistance): []byte("first"),
int(100 - params.BeaconConfig().Eth1FollowDistance + 1): []byte("after_range"),
},
}
dc := dbpb.DepositContainer{
Index: 0,
Eth1BlockHeight: 0,
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: bytesutil.PadTo([]byte("a"), 48),
Signature: make([]byte, 96),
WithdrawalCredentials: make([]byte, 32),
}},
}
depositTrie, err := trieutil.NewTrie(int(params.BeaconConfig().DepositContractTreeDepth))
require.NoError(t, err)
depositCache, err := depositcache.NewDepositCache()
require.NoError(t, err)
depositCache.InsertDeposit(context.Background(), dc.Deposit, dc.Eth1BlockHeight, dc.Index, depositTrie.Root())
beaconState, err := beaconstate.InitializeFromProto(&pbp2p.BeaconState{
Slot: 64,
Eth1DataVotes: []*ethpb.Eth1Data{
{BlockHash: []byte("first"), DepositCount: 1},
{BlockHash: []byte("after_range"), DepositCount: 1},
{BlockHash: []byte("after_range"), DepositCount: 1},
},
})
require.NoError(t, err)
ps := &Server{
ChainStartFetcher: p,
Eth1InfoFetcher: p,
Eth1BlockFetcher: p,
BlockFetcher: p,
DepositFetcher: depositCache,
HeadFetcher: &mock.ChainService{ETH1Data: &ethpb.Eth1Data{DepositCount: 1}},
}
ctx := context.Background()
majorityVoteEth1Data, err := ps.eth1DataMajorityVote(ctx, beaconState)
require.NoError(t, err)
hash := majorityVoteEth1Data.BlockHash
expectedHash := []byte("first")
if !bytes.Equal(hash, expectedHash) {
t.Errorf("Chosen eth1data for block hash %v vs expected %v", hash, expectedHash)
}
}
func TestEth1DataMajorityVote_HighestCountOnUnknownBlock_ChooseKnownBlockWithHighestCount(t *testing.T) {
p := &mockPOW.POWChain{
BlockNumberByTime: map[uint64]*big.Int{
32 * params.BeaconConfig().SecondsPerSlot: big.NewInt(50),
64 * params.BeaconConfig().SecondsPerSlot: big.NewInt(100),
},
HashesByHeight: map[int][]byte{
int(100 - params.BeaconConfig().Eth1FollowDistance - 1): []byte("first"),
int(100 - params.BeaconConfig().Eth1FollowDistance): []byte("second"),
},
}
dc := dbpb.DepositContainer{
Index: 0,
Eth1BlockHeight: 0,
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: bytesutil.PadTo([]byte("a"), 48),
Signature: make([]byte, 96),
WithdrawalCredentials: make([]byte, 32),
}},
}
depositTrie, err := trieutil.NewTrie(int(params.BeaconConfig().DepositContractTreeDepth))
require.NoError(t, err)
depositCache, err := depositcache.NewDepositCache()
require.NoError(t, err)
depositCache.InsertDeposit(context.Background(), dc.Deposit, dc.Eth1BlockHeight, dc.Index, depositTrie.Root())
beaconState, err := beaconstate.InitializeFromProto(&pbp2p.BeaconState{
Slot: 64,
Eth1DataVotes: []*ethpb.Eth1Data{
{BlockHash: []byte("unknown"), DepositCount: 1},
{BlockHash: []byte("unknown"), DepositCount: 1},
{BlockHash: []byte("first"), DepositCount: 1},
},
})
require.NoError(t, err)
ps := &Server{
ChainStartFetcher: p,
Eth1InfoFetcher: p,
Eth1BlockFetcher: p,
BlockFetcher: p,
DepositFetcher: depositCache,
HeadFetcher: &mock.ChainService{ETH1Data: &ethpb.Eth1Data{DepositCount: 1}},
}
ctx := context.Background()
majorityVoteEth1Data, err := ps.eth1DataMajorityVote(ctx, beaconState)
require.NoError(t, err)
hash := majorityVoteEth1Data.BlockHash
expectedHash := []byte("first")
if !bytes.Equal(hash, expectedHash) {
t.Errorf("Chosen eth1data for block hash %v vs expected %v", hash, expectedHash)
}
}
func TestEth1DataMajorityVote_NoVotesInRange_ChooseDefault(t *testing.T) {
p := &mockPOW.POWChain{
BlockNumberByTime: map[uint64]*big.Int{
32 * params.BeaconConfig().SecondsPerSlot: big.NewInt(50),
64 * params.BeaconConfig().SecondsPerSlot: big.NewInt(100),
},
HashesByHeight: map[int][]byte{
int(50 - params.BeaconConfig().Eth1FollowDistance - 1): []byte("before_range"),
int(100 - params.BeaconConfig().Eth1FollowDistance - 1): []byte("first"),
int(100 - params.BeaconConfig().Eth1FollowDistance): []byte("second"),
int(100 - params.BeaconConfig().Eth1FollowDistance + 1): []byte("after_range"),
},
}
dc := dbpb.DepositContainer{
Index: 0,
Eth1BlockHeight: 0,
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: bytesutil.PadTo([]byte("a"), 48),
Signature: make([]byte, 96),
WithdrawalCredentials: make([]byte, 32),
}},
}
depositTrie, err := trieutil.NewTrie(int(params.BeaconConfig().DepositContractTreeDepth))
require.NoError(t, err)
depositCache, err := depositcache.NewDepositCache()
require.NoError(t, err)
depositCache.InsertDeposit(context.Background(), dc.Deposit, dc.Eth1BlockHeight, dc.Index, depositTrie.Root())
beaconState, err := beaconstate.InitializeFromProto(&pbp2p.BeaconState{
Slot: 64,
Eth1DataVotes: []*ethpb.Eth1Data{
{BlockHash: []byte("before_range"), DepositCount: 1},
{BlockHash: []byte("after_range"), DepositCount: 1},
},
})
require.NoError(t, err)
ps := &Server{
ChainStartFetcher: p,
Eth1InfoFetcher: p,
Eth1BlockFetcher: p,
BlockFetcher: p,
DepositFetcher: depositCache,
HeadFetcher: &mock.ChainService{ETH1Data: &ethpb.Eth1Data{DepositCount: 1}},
}
ctx := context.Background()
majorityVoteEth1Data, err := ps.eth1DataMajorityVote(ctx, beaconState)
require.NoError(t, err)
hash := majorityVoteEth1Data.BlockHash
expectedHash := make([]byte, 32)
copy(expectedHash, "second")
if !bytes.Equal(hash, expectedHash) {
t.Errorf("Chosen eth1data for block hash %v vs expected %v", hash, expectedHash)
}
}
func TestEth1DataMajorityVote_NoVotes_ChooseDefault(t *testing.T) {
p := &mockPOW.POWChain{
BlockNumberByTime: map[uint64]*big.Int{
32 * params.BeaconConfig().SecondsPerSlot: big.NewInt(50),
64 * params.BeaconConfig().SecondsPerSlot: big.NewInt(100),
},
HashesByHeight: map[int][]byte{
int(100 - params.BeaconConfig().Eth1FollowDistance - 1): []byte("first"),
int(100 - params.BeaconConfig().Eth1FollowDistance): []byte("second"),
},
}
dc := dbpb.DepositContainer{
Index: 0,
Eth1BlockHeight: 0,
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: bytesutil.PadTo([]byte("a"), 48),
Signature: make([]byte, 96),
WithdrawalCredentials: make([]byte, 32),
}},
}
depositTrie, err := trieutil.NewTrie(int(params.BeaconConfig().DepositContractTreeDepth))
require.NoError(t, err)
depositCache, err := depositcache.NewDepositCache()
require.NoError(t, err)
depositCache.InsertDeposit(context.Background(), dc.Deposit, dc.Eth1BlockHeight, dc.Index, depositTrie.Root())
beaconState, err := beaconstate.InitializeFromProto(&pbp2p.BeaconState{
Slot: 64,
Eth1DataVotes: []*ethpb.Eth1Data{}})
require.NoError(t, err)
ps := &Server{
ChainStartFetcher: p,
Eth1InfoFetcher: p,
Eth1BlockFetcher: p,
BlockFetcher: p,
DepositFetcher: depositCache,
HeadFetcher: &mock.ChainService{ETH1Data: &ethpb.Eth1Data{DepositCount: 1}},
}
ctx := context.Background()
majorityVoteEth1Data, err := ps.eth1DataMajorityVote(ctx, beaconState)
require.NoError(t, err)
hash := majorityVoteEth1Data.BlockHash
expectedHash := make([]byte, 32)
copy(expectedHash, "second")
if !bytes.Equal(hash, expectedHash) {
t.Errorf("Chosen eth1data for block hash %v vs expected %v", hash, expectedHash)
}
}
func TestEth1DataMajorityVote_SameCount_ChooseMoreRecentBlock(t *testing.T) {
p := &mockPOW.POWChain{
BlockNumberByTime: map[uint64]*big.Int{
32 * params.BeaconConfig().SecondsPerSlot: big.NewInt(50),
64 * params.BeaconConfig().SecondsPerSlot: big.NewInt(100),
},
HashesByHeight: map[int][]byte{
int(100 - params.BeaconConfig().Eth1FollowDistance - 1): []byte("first"),
int(100 - params.BeaconConfig().Eth1FollowDistance): []byte("second"),
},
}
dc := dbpb.DepositContainer{
Index: 0,
Eth1BlockHeight: 0,
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: bytesutil.PadTo([]byte("a"), 48),
Signature: make([]byte, 96),
WithdrawalCredentials: make([]byte, 32),
}},
}
depositTrie, err := trieutil.NewTrie(int(params.BeaconConfig().DepositContractTreeDepth))
require.NoError(t, err)
depositCache, err := depositcache.NewDepositCache()
require.NoError(t, err)
depositCache.InsertDeposit(context.Background(), dc.Deposit, dc.Eth1BlockHeight, dc.Index, depositTrie.Root())
beaconState, err := beaconstate.InitializeFromProto(&pbp2p.BeaconState{
Slot: 64,
Eth1DataVotes: []*ethpb.Eth1Data{
{BlockHash: []byte("first"), DepositCount: 1},
{BlockHash: []byte("second"), DepositCount: 1},
},
})
require.NoError(t, err)
ps := &Server{
ChainStartFetcher: p,
Eth1InfoFetcher: p,
Eth1BlockFetcher: p,
BlockFetcher: p,
DepositFetcher: depositCache,
HeadFetcher: &mock.ChainService{ETH1Data: &ethpb.Eth1Data{DepositCount: 1}},
}
ctx := context.Background()
majorityVoteEth1Data, err := ps.eth1DataMajorityVote(ctx, beaconState)
require.NoError(t, err)
hash := majorityVoteEth1Data.BlockHash
expectedHash := []byte("second")
if !bytes.Equal(hash, expectedHash) {
t.Errorf("Chosen eth1data for block hash %v vs expected %v", hash, expectedHash)
}
}
func TestEth1DataMajorityVote_HighestCountOnBlockWithLessDeposits_ChooseAnotherBlock(t *testing.T) {
p := &mockPOW.POWChain{
BlockNumberByTime: map[uint64]*big.Int{
32 * params.BeaconConfig().SecondsPerSlot: big.NewInt(50),
64 * params.BeaconConfig().SecondsPerSlot: big.NewInt(100),
},
HashesByHeight: map[int][]byte{
int(50 - params.BeaconConfig().Eth1FollowDistance): []byte("no_new_deposits"),
int(100 - params.BeaconConfig().Eth1FollowDistance): []byte("second"),
},
}
dc := dbpb.DepositContainer{
Index: 0,
Eth1BlockHeight: 0,
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: []byte("a"),
Signature: make([]byte, 96),
WithdrawalCredentials: make([]byte, 32),
}},
}
depositTrie, err := trieutil.NewTrie(int(params.BeaconConfig().DepositContractTreeDepth))
require.NoError(t, err)
depositCache, err := depositcache.NewDepositCache()
require.NoError(t, err)
depositCache.InsertDeposit(context.Background(), dc.Deposit, dc.Eth1BlockHeight, dc.Index, depositTrie.Root())
beaconState, err := beaconstate.InitializeFromProto(&pbp2p.BeaconState{
Slot: 64,
Eth1DataVotes: []*ethpb.Eth1Data{
{BlockHash: []byte("no_new_deposits"), DepositCount: 0},
{BlockHash: []byte("no_new_deposits"), DepositCount: 0},
{BlockHash: []byte("second"), DepositCount: 1},
},
})
require.NoError(t, err)
ps := &Server{
ChainStartFetcher: p,
Eth1InfoFetcher: p,
Eth1BlockFetcher: p,
BlockFetcher: p,
DepositFetcher: depositCache,
HeadFetcher: &mock.ChainService{ETH1Data: &ethpb.Eth1Data{DepositCount: 1}},
}
ctx := context.Background()
majorityVoteEth1Data, err := ps.eth1DataMajorityVote(ctx, beaconState)
require.NoError(t, err)
hash := majorityVoteEth1Data.BlockHash
expectedHash := []byte("second")
if bytes.Compare(hash, expectedHash) != 0 {
t.Errorf("Chosen eth1data for block hash %v vs expected %v", hash, expectedHash)
}
}
func TestEth1DataMajorityVote_NoDeposits_ChooseChainStartEth1Data(t *testing.T) {
p := &mockPOW.POWChain{
BlockNumberByTime: map[uint64]*big.Int{
32 * params.BeaconConfig().SecondsPerSlot: big.NewInt(50),
64 * params.BeaconConfig().SecondsPerSlot: big.NewInt(100),
},
HashesByHeight: map[int][]byte{
int(100 - params.BeaconConfig().Eth1FollowDistance - 1): []byte("first"),
int(100 - params.BeaconConfig().Eth1FollowDistance): []byte("second"),
},
Eth1Data: &ethpb.Eth1Data{
BlockHash: []byte("eth1data"),
},
}
depositCache, err := depositcache.NewDepositCache()
require.NoError(t, err)
beaconState, err := beaconstate.InitializeFromProto(&pbp2p.BeaconState{
Slot: 64,
Eth1DataVotes: []*ethpb.Eth1Data{
{BlockHash: []byte("first"), DepositCount: 1},
},
})
require.NoError(t, err)
ps := &Server{
ChainStartFetcher: p,
Eth1InfoFetcher: p,
Eth1BlockFetcher: p,
BlockFetcher: p,
DepositFetcher: depositCache,
HeadFetcher: &mock.ChainService{ETH1Data: &ethpb.Eth1Data{DepositCount: 0}},
}
ctx := context.Background()
majorityVoteEth1Data, err := ps.eth1DataMajorityVote(ctx, beaconState)
require.NoError(t, err)
hash := majorityVoteEth1Data.BlockHash
expectedHash := []byte("eth1data")
if bytes.Compare(hash, expectedHash) != 0 {
t.Errorf("Chosen eth1data for block hash %v vs expected %v", hash, expectedHash)
}
}
func TestFilterAttestation_OK(t *testing.T) {
db, _ := dbutil.SetupDB(t)
ctx := context.Background()
params.SetupTestConfigCleanup(t)
params.OverrideBeaconConfig(params.MainnetConfig())
genesis := testutil.NewBeaconBlock()
require.NoError(t, db.SaveBlock(context.Background(), genesis), "Could not save genesis block")
numDeposits := uint64(64)
state, privKeys := testutil.DeterministicGenesisState(t, numDeposits)
require.NoError(t, state.SetGenesisValidatorRoot(params.BeaconConfig().ZeroHash[:]))
assert.NoError(t, state.SetSlot(1))
genesisRoot, err := genesis.Block.HashTreeRoot()
require.NoError(t, err)
require.NoError(t, db.SaveState(ctx, state, genesisRoot), "Could not save genesis state")
require.NoError(t, db.SaveHeadBlockRoot(ctx, genesisRoot), "Could not save genesis state")
proposerServer := &Server{
BeaconDB: db,
AttPool: attestations.NewPool(),
HeadFetcher: &mock.ChainService{State: state, Root: genesisRoot[:]},
}
atts := make([]*ethpb.Attestation, 10)
for i := 0; i < len(atts); i++ {
atts[i] = &ethpb.Attestation{
Data: &ethpb.AttestationData{
CommitteeIndex: uint64(i),
Target: &ethpb.Checkpoint{Root: make([]byte, 32)},
Source: &ethpb.Checkpoint{Root: make([]byte, 32)},
BeaconBlockRoot: make([]byte, 32),
},
Signature: make([]byte, 96),
}
}
received, err := proposerServer.filterAttestationsForBlockInclusion(context.Background(), state, atts)
require.NoError(t, err)
if len(received) > 0 {
t.Error("Invalid attestations were filtered")
}
for i := 0; i < len(atts); i++ {
aggBits := bitfield.NewBitlist(2)
aggBits.SetBitAt(0, true)
atts[i] = &ethpb.Attestation{
Data: &ethpb.AttestationData{
CommitteeIndex: uint64(i),
Target: &ethpb.Checkpoint{Root: make([]byte, 32)},
Source: &ethpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]},
BeaconBlockRoot: make([]byte, 32),
},
AggregationBits: aggBits,
Signature: make([]byte, 96),
}
committee, err := helpers.BeaconCommitteeFromState(state, atts[i].Data.Slot, atts[i].Data.CommitteeIndex)
assert.NoError(t, err)
attestingIndices := attestationutil.AttestingIndices(atts[i].AggregationBits, committee)
assert.NoError(t, err)
domain, err := helpers.Domain(state.Fork(), 0, params.BeaconConfig().DomainBeaconAttester, params.BeaconConfig().ZeroHash[:])
require.NoError(t, err)
sigs := make([]bls.Signature, len(attestingIndices))
zeroSig := [96]byte{}
atts[i].Signature = zeroSig[:]
for i, indice := range attestingIndices {
hashTreeRoot, err := helpers.ComputeSigningRoot(atts[i].Data, domain)
require.NoError(t, err)
sig := privKeys[indice].Sign(hashTreeRoot[:])
sigs[i] = sig
}
atts[i].Signature = bls.AggregateSignatures(sigs).Marshal()[:]
}
received, err = proposerServer.filterAttestationsForBlockInclusion(context.Background(), state, atts)
require.NoError(t, err)
assert.Equal(t, 1, len(received), "Did not filter correctly")
}
func Benchmark_Eth1Data(b *testing.B) {
ctx := context.Background()
hashesByHeight := make(map[int][]byte)
beaconState, err := beaconstate.InitializeFromProto(&pbp2p.BeaconState{
Eth1DataVotes: []*ethpb.Eth1Data{},
Eth1Data: &ethpb.Eth1Data{
BlockHash: []byte("stub"),
},
})
require.NoError(b, err)
var mockSig [96]byte
var mockCreds [32]byte
deposits := []*dbpb.DepositContainer{
{
Index: 0,
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: bytesutil.PadTo([]byte("a"), 48),
Signature: mockSig[:],
WithdrawalCredentials: mockCreds[:],
}},
},
{
Index: 1,
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: bytesutil.PadTo([]byte("b"), 48),
Signature: mockSig[:],
WithdrawalCredentials: mockCreds[:],
}},
},
}
depositCache, err := depositcache.NewDepositCache()
require.NoError(b, err)
for i, dp := range deposits {
var root [32]byte
copy(root[:], []byte{'d', 'e', 'p', 'o', 's', 'i', 't', byte(i)})
depositCache.InsertDeposit(ctx, dp.Deposit, uint64(dp.Index), dp.Index, root)
}
numOfVotes := 1000
for i := 0; i < numOfVotes; i++ {
blockhash := []byte{'b', 'l', 'o', 'c', 'k', byte(i)}
deposit := []byte{'d', 'e', 'p', 'o', 's', 'i', 't', byte(i)}
err := beaconState.SetEth1DataVotes(append(beaconState.Eth1DataVotes(), &ethpb.Eth1Data{
BlockHash: blockhash,
DepositRoot: deposit,
}))
require.NoError(b, err)
hashesByHeight[i] = blockhash
}
hashesByHeight[numOfVotes+1] = []byte("stub")
blk := testutil.NewBeaconBlock()
blk.Block.Slot = beaconState.Slot()
blkRoot, err := blk.HashTreeRoot()
require.NoError(b, err)
currentHeight := params.BeaconConfig().Eth1FollowDistance + 5
p := &mockPOW.POWChain{
LatestBlockNumber: big.NewInt(int64(currentHeight)),
HashesByHeight: hashesByHeight,
}
proposerServer := &Server{
BlockReceiver: &mock.ChainService{State: beaconState, Root: blkRoot[:]},
HeadFetcher: &mock.ChainService{State: beaconState, Root: blkRoot[:]},
ChainStartFetcher: p,
Eth1InfoFetcher: p,
Eth1BlockFetcher: p,
DepositFetcher: depositCache,
PendingDepositsFetcher: depositCache,
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err := proposerServer.eth1Data(context.Background(), beaconState.Slot()+1)
require.NoError(b, err)
}
}
func TestDeposits_ReturnsEmptyList_IfLatestEth1DataEqGenesisEth1Block(t *testing.T) {
ctx := context.Background()
height := big.NewInt(int64(params.BeaconConfig().Eth1FollowDistance))
p := &mockPOW.POWChain{
LatestBlockNumber: height,
HashesByHeight: map[int][]byte{
int(height.Int64()): []byte("0x0"),
},
GenesisEth1Block: height,
}
beaconState, err := beaconstate.InitializeFromProto(&pbp2p.BeaconState{
Eth1Data: &ethpb.Eth1Data{
BlockHash: bytesutil.PadTo([]byte("0x0"), 32),
DepositRoot: make([]byte, 32),
},
Eth1DepositIndex: 2,
})
require.NoError(t, err)
blk := testutil.NewBeaconBlock()
blk.Block.Slot = beaconState.Slot()
blkRoot, err := blk.Block.HashTreeRoot()
require.NoError(t, err)
var mockSig [96]byte
var mockCreds [32]byte
readyDeposits := []*dbpb.DepositContainer{
{
Index: 0,
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: bytesutil.PadTo([]byte("a"), 48),
Signature: mockSig[:],
WithdrawalCredentials: mockCreds[:],
}},
},
{
Index: 1,
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: bytesutil.PadTo([]byte("b"), 48),
Signature: mockSig[:],
WithdrawalCredentials: mockCreds[:],
}},
},
}
var recentDeposits []*dbpb.DepositContainer
for i := int64(2); i < 22; i++ {
recentDeposits = append(recentDeposits, &dbpb.DepositContainer{
Index: i,
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: bytesutil.PadTo([]byte{byte(i)}, 48),
Signature: mockSig[:],
WithdrawalCredentials: mockCreds[:],
}},
})
}
depositTrie, err := trieutil.NewTrie(int(params.BeaconConfig().DepositContractTreeDepth))
require.NoError(t, err, "Could not setup deposit trie")
depositCache, err := depositcache.NewDepositCache()
require.NoError(t, err)
for _, dp := range append(readyDeposits, recentDeposits...) {
depositHash, err := dp.Deposit.Data.HashTreeRoot()
require.NoError(t, err, "Unable to determine hashed value of deposit")
depositTrie.Insert(depositHash[:], int(dp.Index))
depositCache.InsertDeposit(ctx, dp.Deposit, uint64(dp.Index), dp.Index, depositTrie.Root())
}
for _, dp := range recentDeposits {
depositCache.InsertPendingDeposit(ctx, dp.Deposit, uint64(dp.Index), dp.Index, depositTrie.Root())
}
bs := &Server{
BlockReceiver: &mock.ChainService{State: beaconState, Root: blkRoot[:]},
HeadFetcher: &mock.ChainService{State: beaconState, Root: blkRoot[:]},
ChainStartFetcher: p,
Eth1InfoFetcher: p,
Eth1BlockFetcher: p,
DepositFetcher: depositCache,
PendingDepositsFetcher: depositCache,
}
// It should also return the recent deposits after their follow window.
p.LatestBlockNumber = big.NewInt(0).Add(p.LatestBlockNumber, big.NewInt(10000))
deposits, err := bs.deposits(ctx, beaconState, &ethpb.Eth1Data{})
require.NoError(t, err)
assert.Equal(t, 0, len(deposits), "Received unexpected number of pending deposits")
}
func TestDeleteAttsInPool_Aggregated(t *testing.T) {
s := &Server{
AttPool: attestations.NewPool(),
}
sig := bls.RandKey().Sign([]byte("foo")).Marshal()
aggregatedAtts := []*ethpb.Attestation{{Data: &ethpb.AttestationData{Slot: 1, BeaconBlockRoot: make([]byte, 32), Target: &ethpb.Checkpoint{Root: make([]byte, 32)}, Source: &ethpb.Checkpoint{Root: make([]byte, 32)}}, AggregationBits: bitfield.Bitlist{0b10101}, Signature: sig}, {Data: &ethpb.AttestationData{Slot: 1, BeaconBlockRoot: make([]byte, 32), Target: &ethpb.Checkpoint{Root: make([]byte, 32)}, Source: &ethpb.Checkpoint{Root: make([]byte, 32)}}, AggregationBits: bitfield.Bitlist{0b11010}, Signature: sig}}
unaggregatedAtts := []*ethpb.Attestation{{Data: &ethpb.AttestationData{Slot: 1, BeaconBlockRoot: make([]byte, 32), Target: &ethpb.Checkpoint{Root: make([]byte, 32)}, Source: &ethpb.Checkpoint{Root: make([]byte, 32)}}, AggregationBits: bitfield.Bitlist{0b1001}, Signature: sig}, {Data: &ethpb.AttestationData{Slot: 1, BeaconBlockRoot: make([]byte, 32), Target: &ethpb.Checkpoint{Root: make([]byte, 32)}, Source: &ethpb.Checkpoint{Root: make([]byte, 32)}}, AggregationBits: bitfield.Bitlist{0b0001}, Signature: sig}}
require.NoError(t, s.AttPool.SaveAggregatedAttestations(aggregatedAtts))
require.NoError(t, s.AttPool.SaveUnaggregatedAttestations(unaggregatedAtts))
aa, err := attaggregation.Aggregate(aggregatedAtts)
require.NoError(t, err)
require.NoError(t, s.deleteAttsInPool(context.Background(), append(aa, unaggregatedAtts...)))
assert.Equal(t, 0, len(s.AttPool.AggregatedAttestations()), "Did not delete aggregated attestation")
atts, err := s.AttPool.UnaggregatedAttestations()
require.NoError(t, err)
assert.Equal(t, 0, len(atts), "Did not delete unaggregated attestation")
}
func TestSortProfitableAtts(t *testing.T) {
atts := []*ethpb.Attestation{
{Data: &ethpb.AttestationData{Slot: 4, BeaconBlockRoot: make([]byte, 32), Target: &ethpb.Checkpoint{Root: make([]byte, 32)}, Source: &ethpb.Checkpoint{Root: make([]byte, 32)}}, AggregationBits: bitfield.Bitlist{0b11100000}},
{Data: &ethpb.AttestationData{Slot: 1, BeaconBlockRoot: make([]byte, 32), Target: &ethpb.Checkpoint{Root: make([]byte, 32)}, Source: &ethpb.Checkpoint{Root: make([]byte, 32)}}, AggregationBits: bitfield.Bitlist{0b11000000}},
{Data: &ethpb.AttestationData{Slot: 2, BeaconBlockRoot: make([]byte, 32), Target: &ethpb.Checkpoint{Root: make([]byte, 32)}, Source: &ethpb.Checkpoint{Root: make([]byte, 32)}}, AggregationBits: bitfield.Bitlist{0b11100000}},
{Data: &ethpb.AttestationData{Slot: 4, BeaconBlockRoot: make([]byte, 32), Target: &ethpb.Checkpoint{Root: make([]byte, 32)}, Source: &ethpb.Checkpoint{Root: make([]byte, 32)}}, AggregationBits: bitfield.Bitlist{0b11110000}},
{Data: &ethpb.AttestationData{Slot: 1, BeaconBlockRoot: make([]byte, 32), Target: &ethpb.Checkpoint{Root: make([]byte, 32)}, Source: &ethpb.Checkpoint{Root: make([]byte, 32)}}, AggregationBits: bitfield.Bitlist{0b11100000}},
{Data: &ethpb.AttestationData{Slot: 3, BeaconBlockRoot: make([]byte, 32), Target: &ethpb.Checkpoint{Root: make([]byte, 32)}, Source: &ethpb.Checkpoint{Root: make([]byte, 32)}}, AggregationBits: bitfield.Bitlist{0b11000000}},
}
sort.Sort(profitableAtts{atts: atts})
want := []*ethpb.Attestation{
{Data: &ethpb.AttestationData{Slot: 4, BeaconBlockRoot: make([]byte, 32), Target: &ethpb.Checkpoint{Root: make([]byte, 32)}, Source: &ethpb.Checkpoint{Root: make([]byte, 32)}}, AggregationBits: bitfield.Bitlist{0b11110000}},
{Data: &ethpb.AttestationData{Slot: 4, BeaconBlockRoot: make([]byte, 32), Target: &ethpb.Checkpoint{Root: make([]byte, 32)}, Source: &ethpb.Checkpoint{Root: make([]byte, 32)}}, AggregationBits: bitfield.Bitlist{0b11100000}},
{Data: &ethpb.AttestationData{Slot: 3, BeaconBlockRoot: make([]byte, 32), Target: &ethpb.Checkpoint{Root: make([]byte, 32)}, Source: &ethpb.Checkpoint{Root: make([]byte, 32)}}, AggregationBits: bitfield.Bitlist{0b11000000}},
{Data: &ethpb.AttestationData{Slot: 2, BeaconBlockRoot: make([]byte, 32), Target: &ethpb.Checkpoint{Root: make([]byte, 32)}, Source: &ethpb.Checkpoint{Root: make([]byte, 32)}}, AggregationBits: bitfield.Bitlist{0b11100000}},
{Data: &ethpb.AttestationData{Slot: 1, BeaconBlockRoot: make([]byte, 32), Target: &ethpb.Checkpoint{Root: make([]byte, 32)}, Source: &ethpb.Checkpoint{Root: make([]byte, 32)}}, AggregationBits: bitfield.Bitlist{0b11100000}},
{Data: &ethpb.AttestationData{Slot: 1, BeaconBlockRoot: make([]byte, 32), Target: &ethpb.Checkpoint{Root: make([]byte, 32)}, Source: &ethpb.Checkpoint{Root: make([]byte, 32)}}, AggregationBits: bitfield.Bitlist{0b11000000}},
}
require.DeepEqual(t, want, atts)
}