mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2025-01-01 07:51:21 +00:00
b7175b3482
* 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
2053 lines
70 KiB
Go
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 := ðpb.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 := ðpb.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 := ðpb.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(ðpb.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, ðpb.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: ðpb.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: ðpb.Deposit{
|
|
Data: ðpb.Deposit_Data{
|
|
PublicKey: bytesutil.PadTo([]byte("a"), 48),
|
|
Signature: mockSig[:],
|
|
WithdrawalCredentials: mockCreds[:],
|
|
}},
|
|
},
|
|
{
|
|
Index: 1,
|
|
Eth1BlockHeight: 8,
|
|
Deposit: ðpb.Deposit{
|
|
Data: ðpb.Deposit_Data{
|
|
PublicKey: bytesutil.PadTo([]byte("b"), 48),
|
|
Signature: mockSig[:],
|
|
WithdrawalCredentials: mockCreds[:],
|
|
}},
|
|
},
|
|
}
|
|
|
|
recentDeposits := []*dbpb.DepositContainer{
|
|
{
|
|
Index: 2,
|
|
Eth1BlockHeight: 400,
|
|
Deposit: ðpb.Deposit{
|
|
Data: ðpb.Deposit_Data{
|
|
PublicKey: bytesutil.PadTo([]byte("c"), 48),
|
|
Signature: mockSig[:],
|
|
WithdrawalCredentials: mockCreds[:],
|
|
}},
|
|
},
|
|
{
|
|
Index: 3,
|
|
Eth1BlockHeight: 600,
|
|
Deposit: ðpb.Deposit{
|
|
Data: ðpb.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, ðpb.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, ðpb.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 := ðpb.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: ðpb.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: ðpb.Deposit{
|
|
Data: ðpb.Deposit_Data{
|
|
PublicKey: bytesutil.PadTo([]byte("a"), 48),
|
|
Signature: mockSig[:],
|
|
WithdrawalCredentials: mockCreds[:],
|
|
}},
|
|
},
|
|
{
|
|
Index: 1,
|
|
Eth1BlockHeight: 14,
|
|
Deposit: ðpb.Deposit{
|
|
Data: ðpb.Deposit_Data{
|
|
PublicKey: bytesutil.PadTo([]byte("b"), 48),
|
|
Signature: mockSig[:],
|
|
WithdrawalCredentials: mockCreds[:],
|
|
}},
|
|
},
|
|
}
|
|
|
|
recentDeposits := []*dbpb.DepositContainer{
|
|
{
|
|
Index: 2,
|
|
Eth1BlockHeight: 5000,
|
|
Deposit: ðpb.Deposit{
|
|
Data: ðpb.Deposit_Data{
|
|
PublicKey: bytesutil.PadTo([]byte("c"), 48),
|
|
Signature: mockSig[:],
|
|
WithdrawalCredentials: mockCreds[:],
|
|
}},
|
|
},
|
|
{
|
|
Index: 3,
|
|
Eth1BlockHeight: 6000,
|
|
Deposit: ðpb.Deposit{
|
|
Data: ðpb.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, ðpb.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(ðpb.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: ðpb.Deposit{
|
|
Data: ðpb.Deposit_Data{
|
|
PublicKey: bytesutil.PadTo([]byte("a"), 48),
|
|
Signature: mockSig[:],
|
|
WithdrawalCredentials: mockCreds[:],
|
|
}},
|
|
},
|
|
{
|
|
Index: 1,
|
|
Deposit: ðpb.Deposit{
|
|
Data: ðpb.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: ðpb.Deposit{
|
|
Data: ðpb.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, ðpb.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: ðpb.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: ðpb.Deposit{
|
|
Data: ðpb.Deposit_Data{
|
|
PublicKey: bytesutil.PadTo([]byte("a"), 48),
|
|
Signature: mockSig[:],
|
|
WithdrawalCredentials: mockCreds[:],
|
|
}},
|
|
},
|
|
{
|
|
Index: 1,
|
|
Deposit: ðpb.Deposit{
|
|
Data: ðpb.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: ðpb.Deposit{
|
|
Data: ðpb.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, ðpb.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: ðpb.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: ðpb.Deposit{
|
|
Data: ðpb.Deposit_Data{
|
|
PublicKey: bytesutil.PadTo([]byte("a"), 48),
|
|
Signature: mockSig[:],
|
|
WithdrawalCredentials: mockCreds[:],
|
|
}},
|
|
},
|
|
{
|
|
Index: 1,
|
|
Deposit: ðpb.Deposit{
|
|
Data: ðpb.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: ðpb.Deposit{
|
|
Data: ðpb.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, ðpb.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: ðpb.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: ðpb.Deposit{
|
|
Data: ðpb.Deposit_Data{
|
|
PublicKey: bytesutil.PadTo([]byte("a"), 48),
|
|
Signature: mockSig[:],
|
|
WithdrawalCredentials: mockCreds[:],
|
|
}},
|
|
},
|
|
{
|
|
Index: 1,
|
|
Eth1BlockHeight: 10,
|
|
Deposit: ðpb.Deposit{
|
|
Data: ðpb.Deposit_Data{
|
|
PublicKey: bytesutil.PadTo([]byte("b"), 48),
|
|
Signature: mockSig[:],
|
|
WithdrawalCredentials: mockCreds[:],
|
|
}},
|
|
},
|
|
}
|
|
|
|
recentDeposits := []*dbpb.DepositContainer{
|
|
{
|
|
Index: 2,
|
|
Eth1BlockHeight: 11,
|
|
Deposit: ðpb.Deposit{
|
|
Data: ðpb.Deposit_Data{
|
|
PublicKey: bytesutil.PadTo([]byte("c"), 48),
|
|
Signature: mockSig[:],
|
|
WithdrawalCredentials: mockCreds[:],
|
|
}},
|
|
},
|
|
{
|
|
Index: 3,
|
|
Eth1BlockHeight: 11,
|
|
Deposit: ðpb.Deposit{
|
|
Data: ðpb.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: ðpb.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: ðpb.Deposit{
|
|
Data: ðpb.Deposit_Data{
|
|
PublicKey: bytesutil.PadTo([]byte("a"), 48),
|
|
Signature: make([]byte, 96),
|
|
WithdrawalCredentials: make([]byte, 32),
|
|
}},
|
|
},
|
|
{
|
|
Index: 1,
|
|
Eth1BlockHeight: 14,
|
|
Deposit: ðpb.Deposit{
|
|
Data: ðpb.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 := ðpb.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: ðpb.Eth1Data{
|
|
DepositCount: 55,
|
|
},
|
|
}
|
|
|
|
headState := testutil.NewBeaconState()
|
|
require.NoError(t, headState.SetEth1Data(ðpb.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: ðpb.Deposit{
|
|
Data: ðpb.Deposit_Data{
|
|
PublicKey: bytesutil.PadTo([]byte("a"), 48),
|
|
Signature: make([]byte, 96),
|
|
WithdrawalCredentials: make([]byte, 32),
|
|
}},
|
|
},
|
|
{
|
|
Index: 1,
|
|
Eth1BlockHeight: 14,
|
|
Deposit: ðpb.Deposit{
|
|
Data: ðpb.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: ðpb.Eth1Data{
|
|
DepositCount: 55,
|
|
},
|
|
}
|
|
ps := &Server{
|
|
ChainStartFetcher: p,
|
|
Eth1InfoFetcher: p,
|
|
Eth1BlockFetcher: p,
|
|
HeadFetcher: &mock.ChainService{ETH1Data: ðpb.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 := ðpb.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: ðpb.Deposit{
|
|
Data: ðpb.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: ðpb.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: ðpb.Deposit{
|
|
Data: ðpb.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: ðpb.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: ðpb.Deposit{
|
|
Data: ðpb.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: ðpb.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: ðpb.Deposit{
|
|
Data: ðpb.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: ðpb.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: ðpb.Deposit{
|
|
Data: ðpb.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: ðpb.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: ðpb.Deposit{
|
|
Data: ðpb.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: ðpb.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: ðpb.Deposit{
|
|
Data: ðpb.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: ðpb.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: ðpb.Deposit{
|
|
Data: ðpb.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: ðpb.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: ðpb.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: ðpb.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] = ðpb.Attestation{
|
|
Data: ðpb.AttestationData{
|
|
CommitteeIndex: uint64(i),
|
|
Target: ðpb.Checkpoint{Root: make([]byte, 32)},
|
|
Source: ðpb.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] = ðpb.Attestation{
|
|
Data: ðpb.AttestationData{
|
|
CommitteeIndex: uint64(i),
|
|
Target: ðpb.Checkpoint{Root: make([]byte, 32)},
|
|
Source: ðpb.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: ðpb.Eth1Data{
|
|
BlockHash: []byte("stub"),
|
|
},
|
|
})
|
|
require.NoError(b, err)
|
|
var mockSig [96]byte
|
|
var mockCreds [32]byte
|
|
deposits := []*dbpb.DepositContainer{
|
|
{
|
|
Index: 0,
|
|
Deposit: ðpb.Deposit{
|
|
Data: ðpb.Deposit_Data{
|
|
PublicKey: bytesutil.PadTo([]byte("a"), 48),
|
|
Signature: mockSig[:],
|
|
WithdrawalCredentials: mockCreds[:],
|
|
}},
|
|
},
|
|
{
|
|
Index: 1,
|
|
Deposit: ðpb.Deposit{
|
|
Data: ðpb.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(), ðpb.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: ðpb.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: ðpb.Deposit{
|
|
Data: ðpb.Deposit_Data{
|
|
PublicKey: bytesutil.PadTo([]byte("a"), 48),
|
|
Signature: mockSig[:],
|
|
WithdrawalCredentials: mockCreds[:],
|
|
}},
|
|
},
|
|
{
|
|
Index: 1,
|
|
Deposit: ðpb.Deposit{
|
|
Data: ðpb.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: ðpb.Deposit{
|
|
Data: ðpb.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, ðpb.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: ðpb.AttestationData{Slot: 1, BeaconBlockRoot: make([]byte, 32), Target: ðpb.Checkpoint{Root: make([]byte, 32)}, Source: ðpb.Checkpoint{Root: make([]byte, 32)}}, AggregationBits: bitfield.Bitlist{0b10101}, Signature: sig}, {Data: ðpb.AttestationData{Slot: 1, BeaconBlockRoot: make([]byte, 32), Target: ðpb.Checkpoint{Root: make([]byte, 32)}, Source: ðpb.Checkpoint{Root: make([]byte, 32)}}, AggregationBits: bitfield.Bitlist{0b11010}, Signature: sig}}
|
|
unaggregatedAtts := []*ethpb.Attestation{{Data: ðpb.AttestationData{Slot: 1, BeaconBlockRoot: make([]byte, 32), Target: ðpb.Checkpoint{Root: make([]byte, 32)}, Source: ðpb.Checkpoint{Root: make([]byte, 32)}}, AggregationBits: bitfield.Bitlist{0b1001}, Signature: sig}, {Data: ðpb.AttestationData{Slot: 1, BeaconBlockRoot: make([]byte, 32), Target: ðpb.Checkpoint{Root: make([]byte, 32)}, Source: ðpb.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: ðpb.AttestationData{Slot: 4, BeaconBlockRoot: make([]byte, 32), Target: ðpb.Checkpoint{Root: make([]byte, 32)}, Source: ðpb.Checkpoint{Root: make([]byte, 32)}}, AggregationBits: bitfield.Bitlist{0b11100000}},
|
|
{Data: ðpb.AttestationData{Slot: 1, BeaconBlockRoot: make([]byte, 32), Target: ðpb.Checkpoint{Root: make([]byte, 32)}, Source: ðpb.Checkpoint{Root: make([]byte, 32)}}, AggregationBits: bitfield.Bitlist{0b11000000}},
|
|
{Data: ðpb.AttestationData{Slot: 2, BeaconBlockRoot: make([]byte, 32), Target: ðpb.Checkpoint{Root: make([]byte, 32)}, Source: ðpb.Checkpoint{Root: make([]byte, 32)}}, AggregationBits: bitfield.Bitlist{0b11100000}},
|
|
{Data: ðpb.AttestationData{Slot: 4, BeaconBlockRoot: make([]byte, 32), Target: ðpb.Checkpoint{Root: make([]byte, 32)}, Source: ðpb.Checkpoint{Root: make([]byte, 32)}}, AggregationBits: bitfield.Bitlist{0b11110000}},
|
|
{Data: ðpb.AttestationData{Slot: 1, BeaconBlockRoot: make([]byte, 32), Target: ðpb.Checkpoint{Root: make([]byte, 32)}, Source: ðpb.Checkpoint{Root: make([]byte, 32)}}, AggregationBits: bitfield.Bitlist{0b11100000}},
|
|
{Data: ðpb.AttestationData{Slot: 3, BeaconBlockRoot: make([]byte, 32), Target: ðpb.Checkpoint{Root: make([]byte, 32)}, Source: ðpb.Checkpoint{Root: make([]byte, 32)}}, AggregationBits: bitfield.Bitlist{0b11000000}},
|
|
}
|
|
sort.Sort(profitableAtts{atts: atts})
|
|
want := []*ethpb.Attestation{
|
|
{Data: ðpb.AttestationData{Slot: 4, BeaconBlockRoot: make([]byte, 32), Target: ðpb.Checkpoint{Root: make([]byte, 32)}, Source: ðpb.Checkpoint{Root: make([]byte, 32)}}, AggregationBits: bitfield.Bitlist{0b11110000}},
|
|
{Data: ðpb.AttestationData{Slot: 4, BeaconBlockRoot: make([]byte, 32), Target: ðpb.Checkpoint{Root: make([]byte, 32)}, Source: ðpb.Checkpoint{Root: make([]byte, 32)}}, AggregationBits: bitfield.Bitlist{0b11100000}},
|
|
{Data: ðpb.AttestationData{Slot: 3, BeaconBlockRoot: make([]byte, 32), Target: ðpb.Checkpoint{Root: make([]byte, 32)}, Source: ðpb.Checkpoint{Root: make([]byte, 32)}}, AggregationBits: bitfield.Bitlist{0b11000000}},
|
|
{Data: ðpb.AttestationData{Slot: 2, BeaconBlockRoot: make([]byte, 32), Target: ðpb.Checkpoint{Root: make([]byte, 32)}, Source: ðpb.Checkpoint{Root: make([]byte, 32)}}, AggregationBits: bitfield.Bitlist{0b11100000}},
|
|
{Data: ðpb.AttestationData{Slot: 1, BeaconBlockRoot: make([]byte, 32), Target: ðpb.Checkpoint{Root: make([]byte, 32)}, Source: ðpb.Checkpoint{Root: make([]byte, 32)}}, AggregationBits: bitfield.Bitlist{0b11100000}},
|
|
{Data: ðpb.AttestationData{Slot: 1, BeaconBlockRoot: make([]byte, 32), Target: ðpb.Checkpoint{Root: make([]byte, 32)}, Source: ðpb.Checkpoint{Root: make([]byte, 32)}}, AggregationBits: bitfield.Bitlist{0b11000000}},
|
|
}
|
|
require.DeepEqual(t, want, atts)
|
|
}
|