prysm-pulse/beacon-chain/rpc/prysm/v1alpha1/validator/proposer_test.go
Raul Jordan d077483577
Add V3 Suffix to All Prysm Packages (#11083)
* v3 import renamings

* tidy

* fmt

* rev

* Update beacon-chain/core/epoch/precompute/reward_penalty_test.go

* Update beacon-chain/core/helpers/validators_test.go

* Update beacon-chain/db/alias.go

* Update beacon-chain/db/alias.go

* Update beacon-chain/db/alias.go

* Update beacon-chain/db/iface/BUILD.bazel

* Update beacon-chain/db/kv/kv.go

* Update beacon-chain/db/kv/state.go

* Update beacon-chain/rpc/prysm/v1alpha1/validator/attester_test.go

* Update beacon-chain/rpc/prysm/v1alpha1/validator/attester_test.go

* Update beacon-chain/sync/initial-sync/service.go

* fix deps

* fix bad replacements

* fix bad replacements

* change back

* gohashtree version

* fix deps

Co-authored-by: Nishant Das <nishdas93@gmail.com>
Co-authored-by: Potuz <potuz@prysmaticlabs.com>
2022-08-16 12:20:13 +00:00

2385 lines
82 KiB
Go

package validator
import (
"context"
"math/big"
"testing"
"time"
"github.com/ethereum/go-ethereum/common"
"github.com/pkg/errors"
"github.com/prysmaticlabs/go-bitfield"
mock "github.com/prysmaticlabs/prysm/v3/beacon-chain/blockchain/testing"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/builder"
builderTest "github.com/prysmaticlabs/prysm/v3/beacon-chain/builder/testing"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/cache"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/cache/depositcache"
b "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/blocks"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/helpers"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/signing"
coretime "github.com/prysmaticlabs/prysm/v3/beacon-chain/core/time"
dbutil "github.com/prysmaticlabs/prysm/v3/beacon-chain/db/testing"
mockExecution "github.com/prysmaticlabs/prysm/v3/beacon-chain/execution/testing"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/attestations"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/slashings"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/synccommittee"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/operations/voluntaryexits"
mockp2p "github.com/prysmaticlabs/prysm/v3/beacon-chain/p2p/testing"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state/stategen"
v1 "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/v1"
mockSync "github.com/prysmaticlabs/prysm/v3/beacon-chain/sync/initial-sync/testing"
fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams"
"github.com/prysmaticlabs/prysm/v3/config/params"
"github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v3/container/trie"
"github.com/prysmaticlabs/prysm/v3/crypto/bls"
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
enginev1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1/attestation"
attaggregation "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1/attestation/aggregation/attestations"
"github.com/prysmaticlabs/prysm/v3/testing/assert"
"github.com/prysmaticlabs/prysm/v3/testing/require"
"github.com/prysmaticlabs/prysm/v3/testing/util"
"github.com/prysmaticlabs/prysm/v3/time/slots"
logTest "github.com/sirupsen/logrus/hooks/test"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/proto"
)
func TestProposer_ProposeBlock_OK(t *testing.T) {
tests := []struct {
name string
block func([32]byte) *ethpb.GenericSignedBeaconBlock
}{
{
name: "phase0",
block: func(parent [32]byte) *ethpb.GenericSignedBeaconBlock {
blockToPropose := util.NewBeaconBlock()
blockToPropose.Block.Slot = 5
blockToPropose.Block.ParentRoot = parent[:]
blk := &ethpb.GenericSignedBeaconBlock_Phase0{Phase0: blockToPropose}
return &ethpb.GenericSignedBeaconBlock{Block: blk}
},
},
{
name: "altair",
block: func(parent [32]byte) *ethpb.GenericSignedBeaconBlock {
blockToPropose := util.NewBeaconBlockAltair()
blockToPropose.Block.Slot = 5
blockToPropose.Block.ParentRoot = parent[:]
blk := &ethpb.GenericSignedBeaconBlock_Altair{Altair: blockToPropose}
return &ethpb.GenericSignedBeaconBlock{Block: blk}
},
},
{
name: "bellatrix",
block: func(parent [32]byte) *ethpb.GenericSignedBeaconBlock {
blockToPropose := util.NewBeaconBlockBellatrix()
blockToPropose.Block.Slot = 5
blockToPropose.Block.ParentRoot = parent[:]
blk := &ethpb.GenericSignedBeaconBlock_Bellatrix{Bellatrix: blockToPropose}
return &ethpb.GenericSignedBeaconBlock{Block: blk}
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
db := dbutil.SetupDB(t)
ctx := context.Background()
params.SetupTestConfigCleanup(t)
params.OverrideBeaconConfig(params.MainnetConfig())
genesis := util.NewBeaconBlock()
util.SaveBlock(t, ctx, db, genesis)
numDeposits := uint64(64)
beaconState, _ := util.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{
ChainStartFetcher: &mockExecution.Chain{},
Eth1InfoFetcher: &mockExecution.Chain{},
Eth1BlockFetcher: &mockExecution.Chain{},
BlockReceiver: c,
HeadFetcher: c,
BlockNotifier: c.BlockNotifier(),
P2P: mockp2p.NewTestP2P(t),
}
blockToPropose := tt.block(bsRoot)
res, err := proposerServer.ProposeBeaconBlock(context.Background(), blockToPropose)
assert.NoError(t, err, "Could not propose block correctly")
if res == nil || len(res.BlockRoot) == 0 {
t.Error("No block root was returned")
}
})
}
}
func TestProposer_ComputeStateRoot_OK(t *testing.T) {
db := dbutil.SetupDB(t)
ctx := context.Background()
params.SetupTestConfigCleanup(t)
params.OverrideBeaconConfig(params.MainnetConfig())
beaconState, parentRoot, privKeys := util.DeterministicGenesisStateWithGenesisBlock(t, ctx, db, 100)
proposerServer := &Server{
ChainStartFetcher: &mockExecution.Chain{},
Eth1InfoFetcher: &mockExecution.Chain{},
Eth1BlockFetcher: &mockExecution.Chain{},
StateGen: stategen.New(db),
}
req := util.NewBeaconBlock()
req.Block.ProposerIndex = 21
req.Block.ParentRoot = parentRoot[:]
req.Block.Slot = 1
require.NoError(t, beaconState.SetSlot(beaconState.Slot()+1))
randaoReveal, err := util.RandaoReveal(beaconState, 0, privKeys)
require.NoError(t, err)
proposerIdx, err := helpers.BeaconProposerIndex(ctx, beaconState)
require.NoError(t, err)
require.NoError(t, beaconState.SetSlot(beaconState.Slot()-1))
req.Block.Body.RandaoReveal = randaoReveal
currentEpoch := coretime.CurrentEpoch(beaconState)
req.Signature, err = signing.ComputeDomainAndSign(beaconState, currentEpoch, req.Block, params.BeaconConfig().DomainBeaconProposer, privKeys[proposerIdx])
require.NoError(t, err)
wsb, err := blocks.NewSignedBeaconBlock(req)
require.NoError(t, err)
_, err = proposerServer.computeStateRoot(context.Background(), wsb)
require.NoError(t, err)
}
func TestProposer_PendingDeposits_Eth1DataVoteOK(t *testing.T) {
ctx := context.Background()
height := big.NewInt(int64(params.BeaconConfig().Eth1FollowDistance))
newHeight := big.NewInt(height.Int64() + 11000)
p := &mockExecution.Chain{
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 := uint64(params.BeaconConfig().SlotsPerEpoch.Mul(uint64(params.BeaconConfig().EpochsPerEth1VotingPeriod)))
for i := 0; i <= int(period/2); i++ {
votes = append(votes, vote)
}
blockHash = make([]byte, 32)
copy(blockHash, "0x0")
beaconState, err := util.NewBeaconState()
require.NoError(t, err)
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 := util.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(ctx, beaconState, blk.Block.Body.Eth1Data)
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(ctx, beaconState, blk.Block.Body.Eth1Data)
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 TestProposer_PendingDeposits_OutsideEth1FollowWindow(t *testing.T) {
ctx := context.Background()
height := big.NewInt(int64(params.BeaconConfig().Eth1FollowDistance))
p := &mockExecution.Chain{
LatestBlockNumber: height,
HashesByHeight: map[int][]byte{
int(height.Int64()): []byte("0x0"),
},
}
beaconState, err := v1.InitializeFromProto(&ethpb.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 := []*ethpb.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 := []*ethpb.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.New()
require.NoError(t, err)
depositTrie, err := trie.NewTrie(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")
assert.NoError(t, depositTrie.Insert(depositHash[:], int(dp.Index)))
root, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
assert.NoError(t, depositCache.InsertDeposit(ctx, dp.Deposit, dp.Eth1BlockHeight, dp.Index, root))
}
for _, dp := range recentDeposits {
root, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
depositCache.InsertPendingDeposit(ctx, dp.Deposit, dp.Eth1BlockHeight, dp.Index, root)
}
blk := util.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 TestProposer_PendingDeposits_FollowsCorrectEth1Block(t *testing.T) {
ctx := context.Background()
height := big.NewInt(int64(params.BeaconConfig().Eth1FollowDistance))
newHeight := big.NewInt(height.Int64() + 11000)
p := &mockExecution.Chain{
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 := uint64(params.BeaconConfig().SlotsPerEpoch.Mul(uint64(params.BeaconConfig().EpochsPerEth1VotingPeriod)))
for i := 0; i <= int(period/2); i++ {
votes = append(votes, vote)
}
beaconState, err := v1.InitializeFromProto(&ethpb.BeaconState{
Eth1Data: &ethpb.Eth1Data{
BlockHash: []byte("0x0"),
DepositRoot: make([]byte, 32),
DepositCount: 5,
},
Eth1DepositIndex: 1,
Eth1DataVotes: votes,
})
require.NoError(t, err)
blk := util.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 := []*ethpb.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 := []*ethpb.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.New()
require.NoError(t, err)
depositTrie, err := trie.NewTrie(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")
assert.NoError(t, depositTrie.Insert(depositHash[:], int(dp.Index)))
root, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
assert.NoError(t, depositCache.InsertDeposit(ctx, dp.Deposit, dp.Eth1BlockHeight, dp.Index, root))
}
for _, dp := range recentDeposits {
root, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
depositCache.InsertPendingDeposit(ctx, dp.Deposit, dp.Eth1BlockHeight, dp.Index, 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 TestProposer_PendingDeposits_CantReturnBelowStateEth1DepositIndex(t *testing.T) {
ctx := context.Background()
height := big.NewInt(int64(params.BeaconConfig().Eth1FollowDistance))
p := &mockExecution.Chain{
LatestBlockNumber: height,
HashesByHeight: map[int][]byte{
int(height.Int64()): []byte("0x0"),
},
}
beaconState, err := util.NewBeaconState()
require.NoError(t, err)
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 := util.NewBeaconBlock()
blk.Block.Slot = beaconState.Slot()
blkRoot, err := blk.HashTreeRoot()
require.NoError(t, err)
var mockSig [96]byte
var mockCreds [32]byte
readyDeposits := []*ethpb.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 []*ethpb.DepositContainer
for i := int64(2); i < 16; i++ {
recentDeposits = append(recentDeposits, &ethpb.DepositContainer{
Index: i,
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: bytesutil.PadTo([]byte{byte(i)}, 48),
Signature: mockSig[:],
WithdrawalCredentials: mockCreds[:],
}},
})
}
depositTrie, err := trie.NewTrie(params.BeaconConfig().DepositContractTreeDepth)
require.NoError(t, err, "Could not setup deposit trie")
depositCache, err := depositcache.New()
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")
assert.NoError(t, depositTrie.Insert(depositHash[:], int(dp.Index)))
root, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
assert.NoError(t, depositCache.InsertDeposit(ctx, dp.Deposit, uint64(dp.Index), dp.Index, root))
}
for _, dp := range recentDeposits {
root, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
depositCache.InsertPendingDeposit(ctx, dp.Deposit, uint64(dp.Index), dp.Index, 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 TestProposer_PendingDeposits_CantReturnMoreThanMax(t *testing.T) {
ctx := context.Background()
height := big.NewInt(int64(params.BeaconConfig().Eth1FollowDistance))
p := &mockExecution.Chain{
LatestBlockNumber: height,
HashesByHeight: map[int][]byte{
int(height.Int64()): []byte("0x0"),
},
}
beaconState, err := v1.InitializeFromProto(&ethpb.BeaconState{
Eth1Data: &ethpb.Eth1Data{
BlockHash: bytesutil.PadTo([]byte("0x0"), 32),
DepositRoot: make([]byte, 32),
DepositCount: 100,
},
Eth1DepositIndex: 2,
})
require.NoError(t, err)
blk := util.NewBeaconBlock()
blk.Block.Slot = beaconState.Slot()
blkRoot, err := blk.HashTreeRoot()
require.NoError(t, err)
var mockSig [96]byte
var mockCreds [32]byte
readyDeposits := []*ethpb.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 []*ethpb.DepositContainer
for i := int64(2); i < 22; i++ {
recentDeposits = append(recentDeposits, &ethpb.DepositContainer{
Index: i,
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: bytesutil.PadTo([]byte{byte(i)}, 48),
Signature: mockSig[:],
WithdrawalCredentials: mockCreds[:],
}},
})
}
depositTrie, err := trie.NewTrie(params.BeaconConfig().DepositContractTreeDepth)
require.NoError(t, err, "Could not setup deposit trie")
depositCache, err := depositcache.New()
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")
assert.NoError(t, depositTrie.Insert(depositHash[:], int(dp.Index)))
root, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
assert.NoError(t, depositCache.InsertDeposit(ctx, dp.Deposit, height.Uint64(), dp.Index, root))
}
for _, dp := range recentDeposits {
root, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
depositCache.InsertPendingDeposit(ctx, dp.Deposit, height.Uint64(), dp.Index, 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 TestProposer_PendingDeposits_CantReturnMoreThanDepositCount(t *testing.T) {
ctx := context.Background()
height := big.NewInt(int64(params.BeaconConfig().Eth1FollowDistance))
p := &mockExecution.Chain{
LatestBlockNumber: height,
HashesByHeight: map[int][]byte{
int(height.Int64()): []byte("0x0"),
},
}
beaconState, err := v1.InitializeFromProto(&ethpb.BeaconState{
Eth1Data: &ethpb.Eth1Data{
BlockHash: bytesutil.PadTo([]byte("0x0"), 32),
DepositRoot: make([]byte, 32),
DepositCount: 5,
},
Eth1DepositIndex: 2,
})
require.NoError(t, err)
blk := util.NewBeaconBlock()
blk.Block.Slot = beaconState.Slot()
blkRoot, err := blk.HashTreeRoot()
require.NoError(t, err)
var mockSig [96]byte
var mockCreds [32]byte
readyDeposits := []*ethpb.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 []*ethpb.DepositContainer
for i := int64(2); i < 22; i++ {
recentDeposits = append(recentDeposits, &ethpb.DepositContainer{
Index: i,
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: bytesutil.PadTo([]byte{byte(i)}, 48),
Signature: mockSig[:],
WithdrawalCredentials: mockCreds[:],
}},
})
}
depositTrie, err := trie.NewTrie(params.BeaconConfig().DepositContractTreeDepth)
require.NoError(t, err, "Could not setup deposit trie")
depositCache, err := depositcache.New()
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")
assert.NoError(t, depositTrie.Insert(depositHash[:], int(dp.Index)))
root, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
assert.NoError(t, depositCache.InsertDeposit(ctx, dp.Deposit, uint64(dp.Index), dp.Index, root))
}
for _, dp := range recentDeposits {
root, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
depositCache.InsertPendingDeposit(ctx, dp.Deposit, uint64(dp.Index), dp.Index, 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 TestProposer_DepositTrie_UtilizesCachedFinalizedDeposits(t *testing.T) {
ctx := context.Background()
height := big.NewInt(int64(params.BeaconConfig().Eth1FollowDistance))
p := &mockExecution.Chain{
LatestBlockNumber: height,
HashesByHeight: map[int][]byte{
int(height.Int64()): []byte("0x0"),
},
}
beaconState, err := v1.InitializeFromProto(&ethpb.BeaconState{
Eth1Data: &ethpb.Eth1Data{
BlockHash: bytesutil.PadTo([]byte("0x0"), 32),
DepositRoot: make([]byte, 32),
DepositCount: 4,
},
Eth1DepositIndex: 1,
})
require.NoError(t, err)
blk := util.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 := []*ethpb.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 := []*ethpb.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.New()
require.NoError(t, err)
depositTrie, err := trie.NewTrie(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")
assert.NoError(t, depositTrie.Insert(depositHash[:], int(dp.Index)))
root, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
assert.NoError(t, depositCache.InsertDeposit(ctx, dp.Deposit, dp.Eth1BlockHeight, dp.Index, root))
}
for _, dp := range recentDeposits {
root, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
depositCache.InsertPendingDeposit(ctx, dp.Deposit, dp.Eth1BlockHeight, dp.Index, 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[:]},
}
dt, err := bs.depositTrie(ctx, &ethpb.Eth1Data{}, big.NewInt(int64(params.BeaconConfig().Eth1FollowDistance)))
require.NoError(t, err)
actualRoot, err := dt.HashTreeRoot()
require.NoError(t, err)
expectedRoot, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
assert.Equal(t, expectedRoot, actualRoot, "Incorrect deposit trie root")
}
func TestProposer_DepositTrie_RebuildTrie(t *testing.T) {
ctx := context.Background()
height := big.NewInt(int64(params.BeaconConfig().Eth1FollowDistance))
p := &mockExecution.Chain{
LatestBlockNumber: height,
HashesByHeight: map[int][]byte{
int(height.Int64()): []byte("0x0"),
},
}
beaconState, err := v1.InitializeFromProto(&ethpb.BeaconState{
Eth1Data: &ethpb.Eth1Data{
BlockHash: bytesutil.PadTo([]byte("0x0"), 32),
DepositRoot: make([]byte, 32),
DepositCount: 4,
},
Eth1DepositIndex: 1,
})
require.NoError(t, err)
blk := util.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 := []*ethpb.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 := []*ethpb.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.New()
require.NoError(t, err)
depositTrie, err := trie.NewTrie(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")
assert.NoError(t, depositTrie.Insert(depositHash[:], int(dp.Index)))
root, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
assert.NoError(t, depositCache.InsertDeposit(ctx, dp.Deposit, dp.Eth1BlockHeight, dp.Index, root))
}
for _, dp := range recentDeposits {
root, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
depositCache.InsertPendingDeposit(ctx, dp.Deposit, dp.Eth1BlockHeight, dp.Index, root)
}
d := depositCache.AllDepositContainers(ctx)
origDeposit, ok := proto.Clone(d[0].Deposit).(*ethpb.Deposit)
assert.Equal(t, true, ok)
junkCreds := mockCreds
copy(junkCreds[:1], []byte{'A'})
// Mutate it since its a pointer
d[0].Deposit.Data.WithdrawalCredentials = junkCreds[:]
// Insert junk to corrupt trie.
depositCache.InsertFinalizedDeposits(ctx, 2)
// Add original back
d[0].Deposit = origDeposit
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[:]},
}
dt, err := bs.depositTrie(ctx, &ethpb.Eth1Data{}, big.NewInt(int64(params.BeaconConfig().Eth1FollowDistance)))
require.NoError(t, err)
expectedRoot, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
actualRoot, err := dt.HashTreeRoot()
require.NoError(t, err)
assert.Equal(t, expectedRoot, actualRoot, "Incorrect deposit trie root")
}
func TestProposer_ValidateDepositTrie(t *testing.T) {
tt := []struct {
name string
eth1dataCreator func() *ethpb.Eth1Data
trieCreator func() *trie.SparseMerkleTrie
success bool
}{
{
name: "invalid trie items",
eth1dataCreator: func() *ethpb.Eth1Data {
return &ethpb.Eth1Data{DepositRoot: []byte{}, DepositCount: 10, BlockHash: []byte{}}
},
trieCreator: func() *trie.SparseMerkleTrie {
newTrie, err := trie.NewTrie(params.BeaconConfig().DepositContractTreeDepth)
assert.NoError(t, err)
return newTrie
},
success: false,
},
{
name: "invalid deposit root",
eth1dataCreator: func() *ethpb.Eth1Data {
newTrie, err := trie.NewTrie(params.BeaconConfig().DepositContractTreeDepth)
assert.NoError(t, err)
assert.NoError(t, newTrie.Insert([]byte{'a'}, 0))
assert.NoError(t, newTrie.Insert([]byte{'b'}, 1))
assert.NoError(t, newTrie.Insert([]byte{'c'}, 2))
return &ethpb.Eth1Data{DepositRoot: []byte{'B'}, DepositCount: 3, BlockHash: []byte{}}
},
trieCreator: func() *trie.SparseMerkleTrie {
newTrie, err := trie.NewTrie(params.BeaconConfig().DepositContractTreeDepth)
assert.NoError(t, err)
assert.NoError(t, newTrie.Insert([]byte{'a'}, 0))
assert.NoError(t, newTrie.Insert([]byte{'b'}, 1))
assert.NoError(t, newTrie.Insert([]byte{'c'}, 2))
return newTrie
},
success: false,
},
{
name: "valid deposit trie",
eth1dataCreator: func() *ethpb.Eth1Data {
newTrie, err := trie.NewTrie(params.BeaconConfig().DepositContractTreeDepth)
assert.NoError(t, err)
assert.NoError(t, newTrie.Insert([]byte{'a'}, 0))
assert.NoError(t, newTrie.Insert([]byte{'b'}, 1))
assert.NoError(t, newTrie.Insert([]byte{'c'}, 2))
rt, err := newTrie.HashTreeRoot()
require.NoError(t, err)
return &ethpb.Eth1Data{DepositRoot: rt[:], DepositCount: 3, BlockHash: []byte{}}
},
trieCreator: func() *trie.SparseMerkleTrie {
newTrie, err := trie.NewTrie(params.BeaconConfig().DepositContractTreeDepth)
assert.NoError(t, err)
assert.NoError(t, newTrie.Insert([]byte{'a'}, 0))
assert.NoError(t, newTrie.Insert([]byte{'b'}, 1))
assert.NoError(t, newTrie.Insert([]byte{'c'}, 2))
return newTrie
},
success: true,
},
}
for _, test := range tt {
t.Run(test.name, func(t *testing.T) {
valid, err := validateDepositTrie(test.trieCreator(), test.eth1dataCreator())
assert.Equal(t, test.success, valid)
if valid {
assert.NoError(t, err)
}
})
}
}
func TestProposer_Eth1Data_MajorityVote(t *testing.T) {
slot := types.Slot(64)
earliestValidTime, latestValidTime := majorityVoteBoundaryTime(slot)
dc := ethpb.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 := trie.NewTrie(params.BeaconConfig().DepositContractTreeDepth)
require.NoError(t, err)
depositCache, err := depositcache.New()
require.NoError(t, err)
root, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
assert.NoError(t, depositCache.InsertDeposit(context.Background(), dc.Deposit, dc.Eth1BlockHeight, dc.Index, root))
t.Run("choose highest count", func(t *testing.T) {
t.Skip()
p := mockExecution.New().
InsertBlock(50, earliestValidTime, []byte("earliest")).
InsertBlock(51, earliestValidTime+1, []byte("first")).
InsertBlock(52, earliestValidTime+2, []byte("second")).
InsertBlock(100, latestValidTime, []byte("latest"))
beaconState, err := v1.InitializeFromProto(&ethpb.BeaconState{
Slot: slot,
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")
assert.DeepEqual(t, expectedHash, hash)
})
t.Run("highest count at earliest valid time - choose highest count", func(t *testing.T) {
t.Skip()
p := mockExecution.New().
InsertBlock(50, earliestValidTime, []byte("earliest")).
InsertBlock(52, earliestValidTime+2, []byte("second")).
InsertBlock(100, latestValidTime, []byte("latest"))
beaconState, err := v1.InitializeFromProto(&ethpb.BeaconState{
Slot: slot,
Eth1DataVotes: []*ethpb.Eth1Data{
{BlockHash: []byte("earliest"), DepositCount: 1},
{BlockHash: []byte("earliest"), 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("earliest")
assert.DeepEqual(t, expectedHash, hash)
})
t.Run("highest count at latest valid time - choose highest count", func(t *testing.T) {
t.Skip()
p := mockExecution.New().
InsertBlock(50, earliestValidTime, []byte("earliest")).
InsertBlock(51, earliestValidTime+1, []byte("first")).
InsertBlock(100, latestValidTime, []byte("latest"))
beaconState, err := v1.InitializeFromProto(&ethpb.BeaconState{
Slot: slot,
Eth1DataVotes: []*ethpb.Eth1Data{
{BlockHash: []byte("first"), DepositCount: 1},
{BlockHash: []byte("latest"), DepositCount: 1},
{BlockHash: []byte("latest"), 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("latest")
assert.DeepEqual(t, expectedHash, hash)
})
t.Run("highest count before range - choose highest count within range", func(t *testing.T) {
t.Skip()
p := mockExecution.New().
InsertBlock(49, earliestValidTime-1, []byte("before_range")).
InsertBlock(50, earliestValidTime, []byte("earliest")).
InsertBlock(51, earliestValidTime+1, []byte("first")).
InsertBlock(100, latestValidTime, []byte("latest"))
beaconState, err := v1.InitializeFromProto(&ethpb.BeaconState{
Slot: slot,
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")
assert.DeepEqual(t, expectedHash, hash)
})
t.Run("highest count after range - choose highest count within range", func(t *testing.T) {
t.Skip()
p := mockExecution.New().
InsertBlock(50, earliestValidTime, []byte("earliest")).
InsertBlock(51, earliestValidTime+1, []byte("first")).
InsertBlock(100, latestValidTime, []byte("latest")).
InsertBlock(101, latestValidTime+1, []byte("after_range"))
beaconState, err := v1.InitializeFromProto(&ethpb.BeaconState{
Slot: slot,
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")
assert.DeepEqual(t, expectedHash, hash)
})
t.Run("highest count on unknown block - choose known block with highest count", func(t *testing.T) {
t.Skip()
p := mockExecution.New().
InsertBlock(50, earliestValidTime, []byte("earliest")).
InsertBlock(51, earliestValidTime+1, []byte("first")).
InsertBlock(52, earliestValidTime+2, []byte("second")).
InsertBlock(100, latestValidTime, []byte("latest"))
beaconState, err := v1.InitializeFromProto(&ethpb.BeaconState{
Slot: slot,
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")
assert.DeepEqual(t, expectedHash, hash)
})
t.Run("no blocks in range - choose current eth1data", func(t *testing.T) {
p := mockExecution.New().
InsertBlock(49, earliestValidTime-1, []byte("before_range")).
InsertBlock(101, latestValidTime+1, []byte("after_range"))
beaconState, err := v1.InitializeFromProto(&ethpb.BeaconState{
Slot: slot,
})
require.NoError(t, err)
currentEth1Data := &ethpb.Eth1Data{DepositCount: 1, BlockHash: []byte("current")}
ps := &Server{
ChainStartFetcher: p,
Eth1InfoFetcher: p,
Eth1BlockFetcher: p,
BlockFetcher: p,
DepositFetcher: depositCache,
HeadFetcher: &mock.ChainService{ETH1Data: currentEth1Data},
}
ctx := context.Background()
majorityVoteEth1Data, err := ps.eth1DataMajorityVote(ctx, beaconState)
require.NoError(t, err)
hash := majorityVoteEth1Data.BlockHash
expectedHash := []byte("current")
assert.DeepEqual(t, expectedHash, hash)
})
t.Run("no votes in range - choose most recent block", func(t *testing.T) {
p := mockExecution.New().
InsertBlock(49, earliestValidTime-1, []byte("before_range")).
InsertBlock(51, earliestValidTime+1, []byte("first")).
InsertBlock(52, earliestValidTime+2, []byte("second")).
InsertBlock(101, latestValidTime+1, []byte("after_range"))
beaconState, err := v1.InitializeFromProto(&ethpb.BeaconState{
Slot: slot,
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")
assert.DeepEqual(t, expectedHash, hash)
})
t.Run("no votes - choose more recent block", func(t *testing.T) {
p := mockExecution.New().
InsertBlock(50, earliestValidTime, []byte("earliest")).
InsertBlock(100, latestValidTime, []byte("latest"))
beaconState, err := v1.InitializeFromProto(&ethpb.BeaconState{
Slot: slot,
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, "latest")
assert.DeepEqual(t, expectedHash, hash)
})
t.Run("no votes and more recent block has less deposits - choose current eth1data", func(t *testing.T) {
p := mockExecution.New().
InsertBlock(50, earliestValidTime, []byte("earliest")).
InsertBlock(100, latestValidTime, []byte("latest"))
beaconState, err := v1.InitializeFromProto(&ethpb.BeaconState{
Slot: slot,
})
require.NoError(t, err)
// Set the deposit count in current eth1data to exceed the latest most recent block's deposit count.
currentEth1Data := &ethpb.Eth1Data{DepositCount: 2, BlockHash: []byte("current")}
ps := &Server{
ChainStartFetcher: p,
Eth1InfoFetcher: p,
Eth1BlockFetcher: p,
BlockFetcher: p,
DepositFetcher: depositCache,
HeadFetcher: &mock.ChainService{ETH1Data: currentEth1Data},
}
ctx := context.Background()
majorityVoteEth1Data, err := ps.eth1DataMajorityVote(ctx, beaconState)
require.NoError(t, err)
hash := majorityVoteEth1Data.BlockHash
expectedHash := []byte("current")
assert.DeepEqual(t, expectedHash, hash)
})
t.Run("same count - choose more recent block", func(t *testing.T) {
t.Skip()
p := mockExecution.New().
InsertBlock(50, earliestValidTime, []byte("earliest")).
InsertBlock(51, earliestValidTime+1, []byte("first")).
InsertBlock(52, earliestValidTime+2, []byte("second")).
InsertBlock(100, latestValidTime, []byte("latest"))
beaconState, err := v1.InitializeFromProto(&ethpb.BeaconState{
Slot: slot,
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")
assert.DeepEqual(t, expectedHash, hash)
})
t.Run("highest count on block with less deposits - choose another block", func(t *testing.T) {
t.Skip()
p := mockExecution.New().
InsertBlock(50, earliestValidTime, []byte("earliest")).
InsertBlock(51, earliestValidTime+1, []byte("first")).
InsertBlock(52, earliestValidTime+2, []byte("second")).
InsertBlock(100, latestValidTime, []byte("latest"))
beaconState, err := v1.InitializeFromProto(&ethpb.BeaconState{
Slot: slot,
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")
assert.DeepEqual(t, expectedHash, hash)
})
t.Run("only one block at earliest valid time - choose this block", func(t *testing.T) {
t.Skip()
p := mockExecution.New().InsertBlock(50, earliestValidTime, []byte("earliest"))
beaconState, err := v1.InitializeFromProto(&ethpb.BeaconState{
Slot: slot,
Eth1DataVotes: []*ethpb.Eth1Data{
{BlockHash: []byte("earliest"), 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("earliest")
assert.DeepEqual(t, expectedHash, hash)
})
t.Run("vote on last block before range - choose next block", func(t *testing.T) {
p := mockExecution.New().
InsertBlock(49, earliestValidTime-1, []byte("before_range")).
// It is important to have height `50` with time `earliestValidTime+1` and not `earliestValidTime`
// because of earliest block increment in the algorithm.
InsertBlock(50, earliestValidTime+1, []byte("first"))
beaconState, err := v1.InitializeFromProto(&ethpb.BeaconState{
Slot: slot,
Eth1DataVotes: []*ethpb.Eth1Data{
{BlockHash: []byte("before_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, "first")
assert.DeepEqual(t, expectedHash, hash)
})
t.Run("no deposits - choose chain start eth1data", func(t *testing.T) {
p := mockExecution.New().
InsertBlock(50, earliestValidTime, []byte("earliest")).
InsertBlock(100, latestValidTime, []byte("latest"))
p.Eth1Data = &ethpb.Eth1Data{
BlockHash: []byte("eth1data"),
}
depositCache, err := depositcache.New()
require.NoError(t, err)
beaconState, err := v1.InitializeFromProto(&ethpb.BeaconState{
Slot: slot,
Eth1DataVotes: []*ethpb.Eth1Data{
{BlockHash: []byte("earliest"), 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")
assert.DeepEqual(t, expectedHash, hash)
})
}
func TestProposer_FilterAttestation(t *testing.T) {
params.SetupTestConfigCleanup(t)
params.OverrideBeaconConfig(params.MainnetConfig())
genesis := util.NewBeaconBlock()
numValidators := uint64(64)
st, privKeys := util.DeterministicGenesisState(t, numValidators)
require.NoError(t, st.SetGenesisValidatorsRoot(params.BeaconConfig().ZeroHash[:]))
assert.NoError(t, st.SetSlot(1))
genesisRoot, err := genesis.Block.HashTreeRoot()
require.NoError(t, err)
tests := []struct {
name string
wantedErr string
inputAtts func() []*ethpb.Attestation
expectedAtts func(inputAtts []*ethpb.Attestation) []*ethpb.Attestation
}{
{
name: "nil attestations",
inputAtts: func() []*ethpb.Attestation {
return nil
},
expectedAtts: func(inputAtts []*ethpb.Attestation) []*ethpb.Attestation {
return []*ethpb.Attestation{}
},
},
{
name: "invalid attestations",
inputAtts: func() []*ethpb.Attestation {
atts := make([]*ethpb.Attestation, 10)
for i := 0; i < len(atts); i++ {
atts[i] = util.HydrateAttestation(&ethpb.Attestation{
Data: &ethpb.AttestationData{
CommitteeIndex: types.CommitteeIndex(i),
},
})
}
return atts
},
expectedAtts: func(inputAtts []*ethpb.Attestation) []*ethpb.Attestation {
return []*ethpb.Attestation{}
},
},
{
name: "filter aggregates ok",
inputAtts: func() []*ethpb.Attestation {
atts := make([]*ethpb.Attestation, 10)
for i := 0; i < len(atts); i++ {
atts[i] = util.HydrateAttestation(&ethpb.Attestation{
Data: &ethpb.AttestationData{
CommitteeIndex: types.CommitteeIndex(i),
Source: &ethpb.Checkpoint{Root: params.BeaconConfig().ZeroHash[:]},
},
AggregationBits: bitfield.Bitlist{0b00000110},
})
committee, err := helpers.BeaconCommitteeFromState(context.Background(), st, atts[i].Data.Slot, atts[i].Data.CommitteeIndex)
assert.NoError(t, err)
attestingIndices, err := attestation.AttestingIndices(atts[i].AggregationBits, committee)
require.NoError(t, err)
assert.NoError(t, err)
domain, err := signing.Domain(st.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 := signing.ComputeSigningRoot(atts[i].Data, domain)
require.NoError(t, err)
sig := privKeys[indice].Sign(hashTreeRoot[:])
sigs[i] = sig
}
atts[i].Signature = bls.AggregateSignatures(sigs).Marshal()
}
return atts
},
expectedAtts: func(inputAtts []*ethpb.Attestation) []*ethpb.Attestation {
return []*ethpb.Attestation{inputAtts[0]}
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
proposerServer := &Server{
AttPool: attestations.NewPool(),
HeadFetcher: &mock.ChainService{State: st, Root: genesisRoot[:]},
}
atts := tt.inputAtts()
received, err := proposerServer.validateAndDeleteAttsInPool(context.Background(), st, atts)
if tt.wantedErr != "" {
assert.ErrorContains(t, tt.wantedErr, err)
assert.Equal(t, nil, received)
} else {
assert.NoError(t, err)
assert.DeepEqual(t, tt.expectedAtts(atts), received)
}
})
}
}
func TestProposer_Deposits_ReturnsEmptyList_IfLatestEth1DataEqGenesisEth1Block(t *testing.T) {
ctx := context.Background()
height := big.NewInt(int64(params.BeaconConfig().Eth1FollowDistance))
p := &mockExecution.Chain{
LatestBlockNumber: height,
HashesByHeight: map[int][]byte{
int(height.Int64()): []byte("0x0"),
},
GenesisEth1Block: height,
}
beaconState, err := v1.InitializeFromProto(&ethpb.BeaconState{
Eth1Data: &ethpb.Eth1Data{
BlockHash: bytesutil.PadTo([]byte("0x0"), 32),
DepositRoot: make([]byte, 32),
},
Eth1DepositIndex: 2,
})
require.NoError(t, err)
blk := util.NewBeaconBlock()
blk.Block.Slot = beaconState.Slot()
blkRoot, err := blk.Block.HashTreeRoot()
require.NoError(t, err)
var mockSig [96]byte
var mockCreds [32]byte
readyDeposits := []*ethpb.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 []*ethpb.DepositContainer
for i := int64(2); i < 22; i++ {
recentDeposits = append(recentDeposits, &ethpb.DepositContainer{
Index: i,
Deposit: &ethpb.Deposit{
Data: &ethpb.Deposit_Data{
PublicKey: bytesutil.PadTo([]byte{byte(i)}, 48),
Signature: mockSig[:],
WithdrawalCredentials: mockCreds[:],
}},
})
}
depositTrie, err := trie.NewTrie(params.BeaconConfig().DepositContractTreeDepth)
require.NoError(t, err, "Could not setup deposit trie")
depositCache, err := depositcache.New()
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")
assert.NoError(t, depositTrie.Insert(depositHash[:], int(dp.Index)))
root, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
assert.NoError(t, depositCache.InsertDeposit(ctx, dp.Deposit, uint64(dp.Index), dp.Index, root))
}
for _, dp := range recentDeposits {
root, err := depositTrie.HashTreeRoot()
require.NoError(t, err)
depositCache.InsertPendingDeposit(ctx, dp.Deposit, uint64(dp.Index), dp.Index, 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 TestProposer_DeleteAttsInPool_Aggregated(t *testing.T) {
s := &Server{
AttPool: attestations.NewPool(),
}
priv, err := bls.RandKey()
require.NoError(t, err)
sig := priv.Sign([]byte("foo")).Marshal()
aggregatedAtts := []*ethpb.Attestation{
util.HydrateAttestation(&ethpb.Attestation{Data: &ethpb.AttestationData{Slot: 1}, AggregationBits: bitfield.Bitlist{0b10101}, Signature: sig}),
util.HydrateAttestation(&ethpb.Attestation{Data: &ethpb.AttestationData{Slot: 1}, AggregationBits: bitfield.Bitlist{0b11010}, Signature: sig})}
unaggregatedAtts := []*ethpb.Attestation{
util.HydrateAttestation(&ethpb.Attestation{Data: &ethpb.AttestationData{Slot: 1}, AggregationBits: bitfield.Bitlist{0b10010}, Signature: sig}),
util.HydrateAttestation(&ethpb.Attestation{Data: &ethpb.AttestationData{Slot: 1}, AggregationBits: bitfield.Bitlist{0b10100}, 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 TestProposer_GetBeaconBlock_PreForkEpoch(t *testing.T) {
db := dbutil.SetupDB(t)
ctx := context.Background()
params.SetupTestConfigCleanup(t)
params.OverrideBeaconConfig(params.MainnetConfig())
beaconState, privKeys := util.DeterministicGenesisState(t, 64)
stateRoot, err := beaconState.HashTreeRoot(ctx)
require.NoError(t, err, "Could not hash genesis state")
genesis := b.NewGenesisBlock(stateRoot[:])
genBlk := &ethpb.SignedBeaconBlock{
Block: &ethpb.BeaconBlock{
Slot: genesis.Block.Slot,
ParentRoot: genesis.Block.ParentRoot,
StateRoot: genesis.Block.StateRoot,
Body: &ethpb.BeaconBlockBody{
RandaoReveal: genesis.Block.Body.RandaoReveal,
Graffiti: genesis.Block.Body.Graffiti,
Eth1Data: genesis.Block.Body.Eth1Data,
},
},
Signature: genesis.Signature,
}
util.SaveBlock(t, ctx, db, genBlk)
parentRoot, err := genBlk.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")
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{
HeadFetcher: &mock.ChainService{State: beaconState, Root: parentRoot[:]},
SyncChecker: &mockSync.Sync{IsSyncing: false},
BlockReceiver: &mock.ChainService{},
HeadUpdater: &mock.ChainService{},
ChainStartFetcher: &mockExecution.Chain{},
Eth1InfoFetcher: &mockExecution.Chain{},
Eth1BlockFetcher: &mockExecution.Chain{},
MockEth1Votes: true,
AttPool: attestations.NewPool(),
SlashingsPool: slashings.NewPool(),
ExitPool: voluntaryexits.NewPool(),
StateGen: stategen.New(db),
SyncCommitteePool: synccommittee.NewStore(),
}
randaoReveal, err := util.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 := types.ValidatorIndex(0); uint64(i) < params.BeaconConfig().MaxProposerSlashings; i++ {
proposerSlashing, err := util.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 := util.GenerateAttesterSlashingForValidator(
beaconState,
privKeys[i+params.BeaconConfig().MaxProposerSlashings],
types.ValidatorIndex(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.GetBeaconBlock(ctx, req)
require.NoError(t, err)
phase0Blk, ok := block.GetBlock().(*ethpb.GenericBeaconBlock_Phase0)
require.Equal(t, true, ok)
assert.Equal(t, req.Slot, phase0Blk.Phase0.Slot)
assert.DeepEqual(t, parentRoot[:], phase0Blk.Phase0.ParentRoot, "Expected block to have correct parent root")
assert.DeepEqual(t, randaoReveal, phase0Blk.Phase0.Body.RandaoReveal, "Expected block to have correct randao reveal")
assert.DeepEqual(t, req.Graffiti, phase0Blk.Phase0.Body.Graffiti, "Expected block to have correct Graffiti")
assert.Equal(t, params.BeaconConfig().MaxProposerSlashings, uint64(len(phase0Blk.Phase0.Body.ProposerSlashings)))
assert.DeepEqual(t, proposerSlashings, phase0Blk.Phase0.Body.ProposerSlashings)
assert.Equal(t, params.BeaconConfig().MaxAttesterSlashings, uint64(len(phase0Blk.Phase0.Body.AttesterSlashings)))
assert.DeepEqual(t, attSlashings, phase0Blk.Phase0.Body.AttesterSlashings)
}
func TestProposer_GetBeaconBlock_PostForkEpoch(t *testing.T) {
db := dbutil.SetupDB(t)
ctx := context.Background()
params.SetupTestConfigCleanup(t)
cfg := params.MainnetConfig().Copy()
cfg.AltairForkEpoch = 1
params.OverrideBeaconConfig(cfg)
beaconState, privKeys := util.DeterministicGenesisState(t, 64)
stateRoot, err := beaconState.HashTreeRoot(ctx)
require.NoError(t, err, "Could not hash genesis state")
genesis := b.NewGenesisBlock(stateRoot[:])
util.SaveBlock(t, ctx, db, genesis)
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")
altairSlot, err := slots.EpochStart(params.BeaconConfig().AltairForkEpoch)
require.NoError(t, err)
genAltair := &ethpb.SignedBeaconBlockAltair{
Block: &ethpb.BeaconBlockAltair{
Slot: altairSlot + 1,
ParentRoot: parentRoot[:],
StateRoot: genesis.Block.StateRoot,
Body: &ethpb.BeaconBlockBodyAltair{
RandaoReveal: genesis.Block.Body.RandaoReveal,
Graffiti: genesis.Block.Body.Graffiti,
Eth1Data: genesis.Block.Body.Eth1Data,
SyncAggregate: &ethpb.SyncAggregate{SyncCommitteeBits: bitfield.NewBitvector512(), SyncCommitteeSignature: make([]byte, 96)},
},
},
Signature: genesis.Signature,
}
blkRoot, err := genAltair.Block.HashTreeRoot()
require.NoError(t, err)
require.NoError(t, err, "Could not get signing root")
require.NoError(t, db.SaveState(ctx, beaconState, blkRoot), "Could not save genesis state")
require.NoError(t, db.SaveHeadBlockRoot(ctx, blkRoot), "Could not save genesis state")
proposerServer := &Server{
HeadFetcher: &mock.ChainService{State: beaconState, Root: parentRoot[:]},
SyncChecker: &mockSync.Sync{IsSyncing: false},
BlockReceiver: &mock.ChainService{},
HeadUpdater: &mock.ChainService{},
ChainStartFetcher: &mockExecution.Chain{},
Eth1InfoFetcher: &mockExecution.Chain{},
Eth1BlockFetcher: &mockExecution.Chain{},
MockEth1Votes: true,
AttPool: attestations.NewPool(),
SlashingsPool: slashings.NewPool(),
ExitPool: voluntaryexits.NewPool(),
StateGen: stategen.New(db),
SyncCommitteePool: synccommittee.NewStore(),
}
randaoReveal, err := util.RandaoReveal(beaconState, 0, privKeys)
require.NoError(t, err)
graffiti := bytesutil.ToBytes32([]byte("eth2"))
require.NoError(t, err)
req := &ethpb.BlockRequest{
Slot: altairSlot + 1,
RandaoReveal: randaoReveal,
Graffiti: graffiti[:],
}
proposerSlashings := make([]*ethpb.ProposerSlashing, params.BeaconConfig().MaxProposerSlashings)
for i := types.ValidatorIndex(0); uint64(i) < params.BeaconConfig().MaxProposerSlashings; i++ {
proposerSlashing, err := util.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 := util.GenerateAttesterSlashingForValidator(
beaconState,
privKeys[i+params.BeaconConfig().MaxProposerSlashings],
types.ValidatorIndex(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.GetBeaconBlock(ctx, req)
require.NoError(t, err)
altairBlk, ok := block.GetBlock().(*ethpb.GenericBeaconBlock_Altair)
require.Equal(t, true, ok)
assert.Equal(t, req.Slot, altairBlk.Altair.Slot)
assert.DeepEqual(t, parentRoot[:], altairBlk.Altair.ParentRoot, "Expected block to have correct parent root")
assert.DeepEqual(t, randaoReveal, altairBlk.Altair.Body.RandaoReveal, "Expected block to have correct randao reveal")
assert.DeepEqual(t, req.Graffiti, altairBlk.Altair.Body.Graffiti, "Expected block to have correct Graffiti")
assert.Equal(t, params.BeaconConfig().MaxProposerSlashings, uint64(len(altairBlk.Altair.Body.ProposerSlashings)))
assert.DeepEqual(t, proposerSlashings, altairBlk.Altair.Body.ProposerSlashings)
assert.Equal(t, params.BeaconConfig().MaxAttesterSlashings, uint64(len(altairBlk.Altair.Body.AttesterSlashings)))
assert.DeepEqual(t, attSlashings, altairBlk.Altair.Body.AttesterSlashings)
}
func TestProposer_GetBeaconBlock_BellatrixEpoch(t *testing.T) {
db := dbutil.SetupDB(t)
ctx := context.Background()
hook := logTest.NewGlobal()
terminalBlockHash := bytesutil.PadTo([]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, 32)
params.SetupTestConfigCleanup(t)
cfg := params.MainnetConfig().Copy()
cfg.BellatrixForkEpoch = 2
cfg.AltairForkEpoch = 1
cfg.TerminalBlockHash = common.BytesToHash(terminalBlockHash)
cfg.TerminalBlockHashActivationEpoch = 2
params.OverrideBeaconConfig(cfg)
beaconState, privKeys := util.DeterministicGenesisState(t, 64)
stateRoot, err := beaconState.HashTreeRoot(ctx)
require.NoError(t, err, "Could not hash genesis state")
genesis := b.NewGenesisBlock(stateRoot[:])
util.SaveBlock(t, ctx, db, genesis)
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")
bellatrixSlot, err := slots.EpochStart(params.BeaconConfig().BellatrixForkEpoch)
require.NoError(t, err)
blk := &ethpb.SignedBeaconBlockBellatrix{
Block: &ethpb.BeaconBlockBellatrix{
Slot: bellatrixSlot + 1,
ParentRoot: parentRoot[:],
StateRoot: genesis.Block.StateRoot,
Body: &ethpb.BeaconBlockBodyBellatrix{
RandaoReveal: genesis.Block.Body.RandaoReveal,
Graffiti: genesis.Block.Body.Graffiti,
Eth1Data: genesis.Block.Body.Eth1Data,
SyncAggregate: &ethpb.SyncAggregate{SyncCommitteeBits: bitfield.NewBitvector512(), SyncCommitteeSignature: make([]byte, 96)},
ExecutionPayload: &enginev1.ExecutionPayload{
ParentHash: make([]byte, fieldparams.RootLength),
FeeRecipient: make([]byte, fieldparams.FeeRecipientLength),
StateRoot: make([]byte, fieldparams.RootLength),
ReceiptsRoot: make([]byte, fieldparams.RootLength),
LogsBloom: make([]byte, fieldparams.LogsBloomLength),
PrevRandao: make([]byte, fieldparams.RootLength),
BaseFeePerGas: make([]byte, fieldparams.RootLength),
BlockHash: make([]byte, fieldparams.RootLength),
},
},
},
Signature: genesis.Signature,
}
blkRoot, err := blk.Block.HashTreeRoot()
require.NoError(t, err)
require.NoError(t, err, "Could not get signing root")
require.NoError(t, db.SaveState(ctx, beaconState, blkRoot), "Could not save genesis state")
require.NoError(t, db.SaveHeadBlockRoot(ctx, blkRoot), "Could not save genesis state")
c := mockExecution.New()
c.HashesByHeight[0] = terminalBlockHash
random, err := helpers.RandaoMix(beaconState, slots.ToEpoch(beaconState.Slot()))
require.NoError(t, err)
timeStamp, err := slots.ToTime(beaconState.GenesisTime(), bellatrixSlot+1)
require.NoError(t, err)
payload := &enginev1.ExecutionPayload{
ParentHash: make([]byte, fieldparams.RootLength),
FeeRecipient: make([]byte, fieldparams.FeeRecipientLength),
StateRoot: make([]byte, fieldparams.RootLength),
ReceiptsRoot: make([]byte, fieldparams.RootLength),
LogsBloom: make([]byte, fieldparams.LogsBloomLength),
PrevRandao: random,
BaseFeePerGas: make([]byte, fieldparams.RootLength),
BlockHash: make([]byte, fieldparams.RootLength),
Transactions: make([][]byte, 0),
ExtraData: make([]byte, 0),
BlockNumber: 1,
GasLimit: 2,
GasUsed: 3,
Timestamp: uint64(timeStamp.Unix()),
}
proposerServer := &Server{
HeadFetcher: &mock.ChainService{State: beaconState, Root: parentRoot[:], Optimistic: false},
TimeFetcher: &mock.ChainService{Genesis: time.Now()},
SyncChecker: &mockSync.Sync{IsSyncing: false},
BlockReceiver: &mock.ChainService{},
HeadUpdater: &mock.ChainService{},
ChainStartFetcher: &mockExecution.Chain{},
Eth1InfoFetcher: &mockExecution.Chain{},
Eth1BlockFetcher: c,
MockEth1Votes: true,
AttPool: attestations.NewPool(),
SlashingsPool: slashings.NewPool(),
ExitPool: voluntaryexits.NewPool(),
StateGen: stategen.New(db),
SyncCommitteePool: synccommittee.NewStore(),
ExecutionEngineCaller: &mockExecution.EngineClient{
PayloadIDBytes: &enginev1.PayloadIDBytes{1},
ExecutionPayload: payload,
},
BeaconDB: db,
ProposerSlotIndexCache: cache.NewProposerPayloadIDsCache(),
}
randaoReveal, err := util.RandaoReveal(beaconState, 0, privKeys)
require.NoError(t, err)
graffiti := bytesutil.ToBytes32([]byte("eth2"))
require.NoError(t, err)
req := &ethpb.BlockRequest{
Slot: bellatrixSlot + 1,
RandaoReveal: randaoReveal,
Graffiti: graffiti[:],
}
block, err := proposerServer.GetBeaconBlock(ctx, req)
require.NoError(t, err)
bellatrixBlk, ok := block.GetBlock().(*ethpb.GenericBeaconBlock_Bellatrix)
require.Equal(t, true, ok)
assert.Equal(t, req.Slot, bellatrixBlk.Bellatrix.Slot)
assert.DeepEqual(t, parentRoot[:], bellatrixBlk.Bellatrix.ParentRoot, "Expected block to have correct parent root")
assert.DeepEqual(t, randaoReveal, bellatrixBlk.Bellatrix.Body.RandaoReveal, "Expected block to have correct randao reveal")
assert.DeepEqual(t, req.Graffiti, bellatrixBlk.Bellatrix.Body.Graffiti, "Expected block to have correct Graffiti")
require.LogsContain(t, hook, "Fee recipient is currently using the burn address")
require.DeepEqual(t, payload, bellatrixBlk.Bellatrix.Body.ExecutionPayload) // Payload should equal.
// Operator sets default fee recipient to not be burned through beacon node cli.
newHook := logTest.NewGlobal()
params.SetupTestConfigCleanup(t)
cfg = params.MainnetConfig().Copy()
cfg.DefaultFeeRecipient = common.Address{'b'}
params.OverrideBeaconConfig(cfg)
_, err = proposerServer.GetBeaconBlock(ctx, req)
require.NoError(t, err)
require.LogsDoNotContain(t, newHook, "Fee recipient is currently using the burn address")
}
func TestProposer_GetBeaconBlock_Optimistic(t *testing.T) {
params.SetupTestConfigCleanup(t)
cfg := params.MainnetConfig().Copy()
cfg.BellatrixForkEpoch = 2
cfg.AltairForkEpoch = 1
params.OverrideBeaconConfig(cfg)
bellatrixSlot, err := slots.EpochStart(params.BeaconConfig().BellatrixForkEpoch)
require.NoError(t, err)
proposerServer := &Server{OptimisticModeFetcher: &mock.ChainService{Optimistic: true}, TimeFetcher: &mock.ChainService{}}
req := &ethpb.BlockRequest{
Slot: bellatrixSlot + 1,
}
_, err = proposerServer.GetBeaconBlock(context.Background(), req)
s, ok := status.FromError(err)
require.Equal(t, true, ok)
require.DeepEqual(t, codes.Unavailable, s.Code())
require.ErrorContains(t, errOptimisticMode.Error(), err)
}
func TestProposer_GetSyncAggregate_OK(t *testing.T) {
proposerServer := &Server{
SyncChecker: &mockSync.Sync{IsSyncing: false},
SyncCommitteePool: synccommittee.NewStore(),
}
r := params.BeaconConfig().ZeroHash
conts := []*ethpb.SyncCommitteeContribution{
{Slot: 1, SubcommitteeIndex: 0, Signature: bls.NewAggregateSignature().Marshal(), AggregationBits: []byte{0b0001}, BlockRoot: r[:]},
{Slot: 1, SubcommitteeIndex: 0, Signature: bls.NewAggregateSignature().Marshal(), AggregationBits: []byte{0b1001}, BlockRoot: r[:]},
{Slot: 1, SubcommitteeIndex: 0, Signature: bls.NewAggregateSignature().Marshal(), AggregationBits: []byte{0b1110}, BlockRoot: r[:]},
{Slot: 1, SubcommitteeIndex: 1, Signature: bls.NewAggregateSignature().Marshal(), AggregationBits: []byte{0b0001}, BlockRoot: r[:]},
{Slot: 1, SubcommitteeIndex: 1, Signature: bls.NewAggregateSignature().Marshal(), AggregationBits: []byte{0b1001}, BlockRoot: r[:]},
{Slot: 1, SubcommitteeIndex: 1, Signature: bls.NewAggregateSignature().Marshal(), AggregationBits: []byte{0b1110}, BlockRoot: r[:]},
{Slot: 1, SubcommitteeIndex: 2, Signature: bls.NewAggregateSignature().Marshal(), AggregationBits: []byte{0b0001}, BlockRoot: r[:]},
{Slot: 1, SubcommitteeIndex: 2, Signature: bls.NewAggregateSignature().Marshal(), AggregationBits: []byte{0b1001}, BlockRoot: r[:]},
{Slot: 1, SubcommitteeIndex: 2, Signature: bls.NewAggregateSignature().Marshal(), AggregationBits: []byte{0b1110}, BlockRoot: r[:]},
{Slot: 1, SubcommitteeIndex: 3, Signature: bls.NewAggregateSignature().Marshal(), AggregationBits: []byte{0b0001}, BlockRoot: r[:]},
{Slot: 1, SubcommitteeIndex: 3, Signature: bls.NewAggregateSignature().Marshal(), AggregationBits: []byte{0b1001}, BlockRoot: r[:]},
{Slot: 1, SubcommitteeIndex: 3, Signature: bls.NewAggregateSignature().Marshal(), AggregationBits: []byte{0b1110}, BlockRoot: r[:]},
{Slot: 2, SubcommitteeIndex: 0, Signature: bls.NewAggregateSignature().Marshal(), AggregationBits: []byte{0b10101010}, BlockRoot: r[:]},
{Slot: 2, SubcommitteeIndex: 1, Signature: bls.NewAggregateSignature().Marshal(), AggregationBits: []byte{0b10101010}, BlockRoot: r[:]},
{Slot: 2, SubcommitteeIndex: 2, Signature: bls.NewAggregateSignature().Marshal(), AggregationBits: []byte{0b10101010}, BlockRoot: r[:]},
{Slot: 2, SubcommitteeIndex: 3, Signature: bls.NewAggregateSignature().Marshal(), AggregationBits: []byte{0b10101010}, BlockRoot: r[:]},
}
for _, cont := range conts {
require.NoError(t, proposerServer.SyncCommitteePool.SaveSyncCommitteeContribution(cont))
}
aggregate, err := proposerServer.getSyncAggregate(context.Background(), 1, bytesutil.ToBytes32(conts[0].BlockRoot))
require.NoError(t, err)
require.DeepEqual(t, bitfield.Bitvector512{0xf, 0xf, 0xf, 0xf}, aggregate.SyncCommitteeBits)
aggregate, err = proposerServer.getSyncAggregate(context.Background(), 2, bytesutil.ToBytes32(conts[0].BlockRoot))
require.NoError(t, err)
require.DeepEqual(t, bitfield.Bitvector512{0xaa, 0xaa, 0xaa, 0xaa}, aggregate.SyncCommitteeBits)
aggregate, err = proposerServer.getSyncAggregate(context.Background(), 3, bytesutil.ToBytes32(conts[0].BlockRoot))
require.NoError(t, err)
require.DeepEqual(t, bitfield.NewBitvector512(), aggregate.SyncCommitteeBits)
}
func TestProposer_PrepareBeaconProposer(t *testing.T) {
type args struct {
request *ethpb.PrepareBeaconProposerRequest
}
tests := []struct {
name string
args args
wantErr string
}{
{
name: "Happy Path",
args: args{
request: &ethpb.PrepareBeaconProposerRequest{
Recipients: []*ethpb.PrepareBeaconProposerRequest_FeeRecipientContainer{
{
FeeRecipient: make([]byte, fieldparams.FeeRecipientLength),
ValidatorIndex: 1,
},
},
},
},
wantErr: "",
},
{
name: "invalid fee recipient length",
args: args{
request: &ethpb.PrepareBeaconProposerRequest{
Recipients: []*ethpb.PrepareBeaconProposerRequest_FeeRecipientContainer{
{
FeeRecipient: make([]byte, fieldparams.BLSPubkeyLength),
ValidatorIndex: 1,
},
},
},
},
wantErr: "Invalid fee recipient address",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
db := dbutil.SetupDB(t)
ctx := context.Background()
proposerServer := &Server{BeaconDB: db}
_, err := proposerServer.PrepareBeaconProposer(ctx, tt.args.request)
if tt.wantErr != "" {
require.ErrorContains(t, tt.wantErr, err)
return
}
require.NoError(t, err)
address, err := proposerServer.BeaconDB.FeeRecipientByValidatorID(ctx, 1)
require.NoError(t, err)
require.Equal(t, common.BytesToAddress(tt.args.request.Recipients[0].FeeRecipient), address)
})
}
}
func TestProposer_SubmitValidatorRegistrations(t *testing.T) {
ctx := context.Background()
proposerServer := &Server{}
reg := &ethpb.SignedValidatorRegistrationsV1{}
_, err := proposerServer.SubmitValidatorRegistrations(ctx, reg)
require.ErrorContains(t, builder.ErrNoBuilder.Error(), err)
proposerServer = &Server{BlockBuilder: &builderTest.MockBuilderService{}}
_, err = proposerServer.SubmitValidatorRegistrations(ctx, reg)
require.ErrorContains(t, builder.ErrNoBuilder.Error(), err)
proposerServer = &Server{BlockBuilder: &builderTest.MockBuilderService{HasConfigured: true}}
_, err = proposerServer.SubmitValidatorRegistrations(ctx, reg)
require.NoError(t, err)
proposerServer = &Server{BlockBuilder: &builderTest.MockBuilderService{HasConfigured: true, ErrRegisterValidator: errors.New("bad")}}
_, err = proposerServer.SubmitValidatorRegistrations(ctx, reg)
require.ErrorContains(t, "bad", err)
}
func majorityVoteBoundaryTime(slot types.Slot) (uint64, uint64) {
s := params.BeaconConfig().SlotsPerEpoch.Mul(uint64(params.BeaconConfig().EpochsPerEth1VotingPeriod))
slotStartTime := uint64(mockExecution.GenesisTime) + uint64((slot - (slot % (s))).Mul(params.BeaconConfig().SecondsPerSlot))
earliestValidTime := slotStartTime - 2*params.BeaconConfig().SecondsPerETH1Block*params.BeaconConfig().Eth1FollowDistance
latestValidTime := slotStartTime - params.BeaconConfig().SecondsPerETH1Block*params.BeaconConfig().Eth1FollowDistance
return earliestValidTime, latestValidTime
}