mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2025-01-15 06:28:20 +00:00
cc741ed8af
* begin state service * begin on the state trie idea * created beacon state structure * add in the full clone getter * return by value instead * add all setters * new state setters are being completed * arrays roots exposed * close to finishing all these headerssss * functionality complete * added in proto benchmark test * test for compatibility * add test for compat * comments fixed * add clone * add clone * remove underlying copies * make it immutable * integrate it into chainservice * revert * wrap up comments for package * address all comments and godocs * address all comments * clone the pending attestation properly * properly clone remaining items * tests pass fixed bug * begin using it instead of head state * prevent nil pointer exceptions * begin using new struct in db * integrated new type into db package * add proper nil checks * using new state in archiver * refactored much of core * editing all the precompute functions * done with most core refactor * fixed up some bugs in the clone comparisons * append current epoch atts * add missing setters * add new setters * fix other core methods * fix up transition * main service and forkchoice * fix rpc * integrated to powchain * some more changes * fix build * improve processing of deposits * fix error * prevent panic * comment * fix process att * gaz * fix up att process * resolve existing review comments * resolve another batch of gh comments * resolve broken cpt state * revise testutil to use the new state * begin updating the state transition func to pass in more compartmentalized args * finish editing transition function to return errors * block operations pretty much done with refactor * state transition fully refactored * got epoch processing completed * fix build in fork choice * fixing more of the build * fix up broken sync package * it builds nowww it buildssss * revert registry changes * Recompute on Read (#4627) * compute on read * fix up eth1 data votes * looking into slashings bug introduced in core/ * able to advance more slots * add logging * can now sync with testnet yay * remove the leaves algorithm and other merkle imports * expose initialize unsafe funcs * Update beacon-chain/db/kv/state.go * lint Co-authored-by: Raul Jordan <raul@prysmaticlabs.com> * More Optimizations for New State (#4641) * map optimization * more optimizations * use a custom hasher * comment * block operations optimizations * Update beacon-chain/state/types.go Co-Authored-By: Raul Jordan <raul@prysmaticlabs.com> * fixed up various operations to use the validator index map access Co-authored-by: Raul Jordan <raul@prysmaticlabs.com> * archiver tests pass * fixing cache tests * cache tests passing * edited validator tests * powchain tests passing * halfway thru sync tests * more sync test fixes * add in tests for state/ * working through rpc tests * assignments tests passed * almost done with rpc/beacon tests * resolved painful validator test * fixed up even more tests * resolve tests * fix build * reduce a randao mixes copy * fixes under //beacon-chain/blockchain/... * build //beacon-chain/core/... * fixes * Runtime Optimizations (#4648) * parallelize shuffling * clean up * lint * fix build * use callback to read from registry * fix array roots and size map * new improvements * reduce hash allocs * improved shuffling * terence's review * use different method * raul's comment * new array roots * remove clone in pre-compute * Update beacon-chain/state/types.go Co-Authored-By: Raul Jordan <raul@prysmaticlabs.com> * raul's review * lint * fix build issues * fix visibility Co-authored-by: Raul Jordan <raul@prysmaticlabs.com> * fix visibility * build works for all * fix blockchain test * fix a few tests * fix more tests * update validator in slashing * archiver passing * fixed rpc/validator * progress on core tests * resolve broken rpc tests * blockchain tests passed * fix up some tests in core * fix message diff * remove unnecessary save * Save validator after slashing * Update validators one by one * another update * fix everything * fix more precompute tests * fix blocks tests * more elegant fix * more helper fixes * change back ? * fix test * fix skip slot * fix test * reset caches * fix testutil * raceoff fixed * passing * Retrieve cached state in the beginning * lint * Fixed tests part 1 * Fixed rest of the tests * Minor changes to avoid copying, small refactor to reduce deplicated code * Handle att req for slot 0 * New beacon state: Only populate merkle layers as needed, copy merkle layers on copy/clone. (#4689) * Only populate merkle layers as needed, copy merkle layers on copy/clone. * use custom copy * Make maps of correct size * slightly fast, doesn't wait for lock Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com> * Target root can't be 0x00 * Don't use cache for current slot (may not be the right fix) * fixed up tests * Remove some copy for init sync. Not sure if it is safe enough for runtime though... testing... * Align with prev logic for process slots cachedState.Slot() < slot * Fix Initial Sync Flag (#4692) * fixes * fix up some test failures due to lack of nil checks * fix up some test failures due to lack of nil checks * fix up imports * revert some changes * imports Co-authored-by: Raul Jordan <raul@prysmaticlabs.com> * resolving further conflicts * Better skip slot cache (#4694) * Return copy of skip slot cache state, disable skip slot cache on sync * fix * Fix pruning * fix up issues with broken tests Co-authored-by: Nishant Das <nish1993@hotmail.com> Co-authored-by: Preston Van Loon <preston@prysmaticlabs.com> Co-authored-by: shayzluf <thezluf@gmail.com> Co-authored-by: terence tsao <terence@prysmaticlabs.com> Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
870 lines
26 KiB
Go
870 lines
26 KiB
Go
package validator
|
|
|
|
import (
|
|
"context"
|
|
"math/big"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/gogo/protobuf/proto"
|
|
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
|
"github.com/prysmaticlabs/go-ssz"
|
|
mockChain "github.com/prysmaticlabs/prysm/beacon-chain/blockchain/testing"
|
|
"github.com/prysmaticlabs/prysm/beacon-chain/cache/depositcache"
|
|
blk "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"
|
|
mockPOW "github.com/prysmaticlabs/prysm/beacon-chain/powchain/testing"
|
|
stateTrie "github.com/prysmaticlabs/prysm/beacon-chain/state"
|
|
pbp2p "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
|
"github.com/prysmaticlabs/prysm/shared/params"
|
|
"github.com/prysmaticlabs/prysm/shared/testutil"
|
|
"github.com/prysmaticlabs/prysm/shared/trieutil"
|
|
)
|
|
|
|
func TestValidatorStatus_Deposited(t *testing.T) {
|
|
db := dbutil.SetupDB(t)
|
|
defer dbutil.TeardownDB(t, db)
|
|
ctx := context.Background()
|
|
|
|
pubKey := pubKey(1)
|
|
depData := ðpb.Deposit_Data{
|
|
PublicKey: pubKey,
|
|
Signature: []byte("hi"),
|
|
WithdrawalCredentials: []byte("hey"),
|
|
}
|
|
deposit := ðpb.Deposit{
|
|
Data: depData,
|
|
}
|
|
depositTrie, err := trieutil.NewTrie(int(params.BeaconConfig().DepositContractTreeDepth))
|
|
if err != nil {
|
|
t.Fatalf("Could not setup deposit trie: %v", err)
|
|
}
|
|
depositCache := depositcache.NewDepositCache()
|
|
depositCache.InsertDeposit(ctx, deposit, 0 /*blockNum*/, 0, depositTrie.Root())
|
|
height := time.Unix(int64(params.BeaconConfig().Eth1FollowDistance), 0).Unix()
|
|
p := &mockPOW.POWChain{
|
|
TimesByHeight: map[int]uint64{
|
|
0: uint64(height),
|
|
},
|
|
}
|
|
stateObj, err := stateTrie.InitializeFromProtoUnsafe(&pbp2p.BeaconState{})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
vs := &Server{
|
|
BeaconDB: db,
|
|
DepositFetcher: depositCache,
|
|
BlockFetcher: p,
|
|
HeadFetcher: &mockChain.ChainService{
|
|
State: stateObj,
|
|
},
|
|
Eth1InfoFetcher: p,
|
|
}
|
|
req := ðpb.ValidatorStatusRequest{
|
|
PublicKey: pubKey,
|
|
}
|
|
resp, err := vs.ValidatorStatus(context.Background(), req)
|
|
if err != nil {
|
|
t.Fatalf("Could not get validator status %v", err)
|
|
}
|
|
if resp.Status != ethpb.ValidatorStatus_DEPOSITED {
|
|
t.Errorf("Wanted %v, got %v", ethpb.ValidatorStatus_DEPOSITED, resp.Status)
|
|
}
|
|
}
|
|
|
|
func TestValidatorStatus_Pending(t *testing.T) {
|
|
db := dbutil.SetupDB(t)
|
|
defer dbutil.TeardownDB(t, db)
|
|
ctx := context.Background()
|
|
|
|
pubKey := pubKey(1)
|
|
if err := db.SaveValidatorIndex(ctx, pubKey, 0); err != nil {
|
|
t.Fatalf("Could not save validator index: %v", err)
|
|
}
|
|
block := blk.NewGenesisBlock([]byte{})
|
|
if err := db.SaveBlock(ctx, block); err != nil {
|
|
t.Fatalf("Could not save genesis block: %v", err)
|
|
}
|
|
genesisRoot, err := ssz.HashTreeRoot(block.Block)
|
|
if err != nil {
|
|
t.Fatalf("Could not get signing root %v", err)
|
|
}
|
|
// Pending active because activation epoch is still defaulted at far future slot.
|
|
state, _ := stateTrie.InitializeFromProto(&pbp2p.BeaconState{
|
|
Validators: []*ethpb.Validator{
|
|
{
|
|
ActivationEpoch: params.BeaconConfig().FarFutureEpoch,
|
|
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
|
WithdrawableEpoch: params.BeaconConfig().FarFutureEpoch,
|
|
PublicKey: pubKey,
|
|
},
|
|
},
|
|
Slot: 5000,
|
|
})
|
|
if err := db.SaveState(ctx, state, genesisRoot); err != nil {
|
|
t.Fatalf("could not save state: %v", err)
|
|
}
|
|
if err := db.SaveHeadBlockRoot(ctx, genesisRoot); err != nil {
|
|
t.Fatalf("Could not save genesis state: %v", err)
|
|
}
|
|
|
|
depData := ðpb.Deposit_Data{
|
|
PublicKey: pubKey,
|
|
Signature: []byte("hi"),
|
|
WithdrawalCredentials: []byte("hey"),
|
|
}
|
|
|
|
deposit := ðpb.Deposit{
|
|
Data: depData,
|
|
}
|
|
depositTrie, err := trieutil.NewTrie(int(params.BeaconConfig().DepositContractTreeDepth))
|
|
if err != nil {
|
|
t.Fatalf("Could not setup deposit trie: %v", err)
|
|
}
|
|
depositCache := depositcache.NewDepositCache()
|
|
depositCache.InsertDeposit(ctx, deposit, 0 /*blockNum*/, 0, depositTrie.Root())
|
|
|
|
height := time.Unix(int64(params.BeaconConfig().Eth1FollowDistance), 0).Unix()
|
|
p := &mockPOW.POWChain{
|
|
TimesByHeight: map[int]uint64{
|
|
0: uint64(height),
|
|
},
|
|
}
|
|
vs := &Server{
|
|
BeaconDB: db,
|
|
ChainStartFetcher: p,
|
|
BlockFetcher: p,
|
|
Eth1InfoFetcher: p,
|
|
DepositFetcher: depositCache,
|
|
HeadFetcher: &mockChain.ChainService{State: state, Root: genesisRoot[:]},
|
|
}
|
|
req := ðpb.ValidatorStatusRequest{
|
|
PublicKey: pubKey,
|
|
}
|
|
resp, err := vs.ValidatorStatus(context.Background(), req)
|
|
if err != nil {
|
|
t.Fatalf("Could not get validator status %v", err)
|
|
}
|
|
if resp.Status != ethpb.ValidatorStatus_PENDING {
|
|
t.Errorf("Wanted %v, got %v", ethpb.ValidatorStatus_PENDING, resp.Status)
|
|
}
|
|
}
|
|
|
|
func TestValidatorStatus_Active(t *testing.T) {
|
|
db := dbutil.SetupDB(t)
|
|
defer dbutil.TeardownDB(t, db)
|
|
// This test breaks if it doesnt use mainnet config
|
|
params.OverrideBeaconConfig(params.MainnetConfig())
|
|
defer params.OverrideBeaconConfig(params.MinimalSpecConfig())
|
|
ctx := context.Background()
|
|
|
|
pubKey := pubKey(1)
|
|
if err := db.SaveValidatorIndex(ctx, pubKey, 0); err != nil {
|
|
t.Fatalf("Could not save validator index: %v", err)
|
|
}
|
|
|
|
depData := ðpb.Deposit_Data{
|
|
PublicKey: pubKey,
|
|
Signature: []byte("hi"),
|
|
WithdrawalCredentials: []byte("hey"),
|
|
}
|
|
|
|
deposit := ðpb.Deposit{
|
|
Data: depData,
|
|
}
|
|
depositTrie, err := trieutil.NewTrie(int(params.BeaconConfig().DepositContractTreeDepth))
|
|
if err != nil {
|
|
t.Fatalf("Could not setup deposit trie: %v", err)
|
|
}
|
|
depositCache := depositcache.NewDepositCache()
|
|
depositCache.InsertDeposit(ctx, deposit, 0 /*blockNum*/, 0, depositTrie.Root())
|
|
|
|
// Active because activation epoch <= current epoch < exit epoch.
|
|
activeEpoch := helpers.DelayedActivationExitEpoch(0)
|
|
|
|
block := blk.NewGenesisBlock([]byte{})
|
|
if err := db.SaveBlock(ctx, block); err != nil {
|
|
t.Fatalf("Could not save genesis block: %v", err)
|
|
}
|
|
genesisRoot, err := ssz.HashTreeRoot(block.Block)
|
|
if err != nil {
|
|
t.Fatalf("Could not get signing root %v", err)
|
|
}
|
|
|
|
state := &pbp2p.BeaconState{
|
|
GenesisTime: uint64(time.Unix(0, 0).Unix()),
|
|
Slot: 10000,
|
|
Validators: []*ethpb.Validator{{
|
|
ActivationEpoch: activeEpoch,
|
|
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
|
WithdrawableEpoch: params.BeaconConfig().FarFutureEpoch,
|
|
PublicKey: pubKey},
|
|
}}
|
|
stateObj, err := stateTrie.InitializeFromProtoUnsafe(state)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
timestamp := time.Unix(int64(params.BeaconConfig().Eth1FollowDistance), 0).Unix()
|
|
p := &mockPOW.POWChain{
|
|
TimesByHeight: map[int]uint64{
|
|
int(params.BeaconConfig().Eth1FollowDistance): uint64(timestamp),
|
|
},
|
|
}
|
|
vs := &Server{
|
|
BeaconDB: db,
|
|
ChainStartFetcher: p,
|
|
BlockFetcher: p,
|
|
Eth1InfoFetcher: p,
|
|
DepositFetcher: depositCache,
|
|
HeadFetcher: &mockChain.ChainService{State: stateObj, Root: genesisRoot[:]},
|
|
}
|
|
req := ðpb.ValidatorStatusRequest{
|
|
PublicKey: pubKey,
|
|
}
|
|
resp, err := vs.ValidatorStatus(context.Background(), req)
|
|
if err != nil {
|
|
t.Fatalf("Could not get validator status %v", err)
|
|
}
|
|
|
|
expected := ðpb.ValidatorStatusResponse{
|
|
Status: ethpb.ValidatorStatus_ACTIVE,
|
|
ActivationEpoch: 5,
|
|
DepositInclusionSlot: 2218,
|
|
}
|
|
if !proto.Equal(resp, expected) {
|
|
t.Errorf("Wanted %v, got %v", expected, resp)
|
|
}
|
|
}
|
|
|
|
func TestValidatorStatus_Exiting(t *testing.T) {
|
|
db := dbutil.SetupDB(t)
|
|
defer dbutil.TeardownDB(t, db)
|
|
ctx := context.Background()
|
|
|
|
pubKey := pubKey(1)
|
|
if err := db.SaveValidatorIndex(ctx, pubKey, 0); err != nil {
|
|
t.Fatalf("Could not save validator index: %v", err)
|
|
}
|
|
|
|
// Initiated exit because validator exit epoch and withdrawable epoch are not FAR_FUTURE_EPOCH
|
|
slot := uint64(10000)
|
|
epoch := helpers.SlotToEpoch(slot)
|
|
exitEpoch := helpers.DelayedActivationExitEpoch(epoch)
|
|
withdrawableEpoch := exitEpoch + params.BeaconConfig().MinValidatorWithdrawabilityDelay
|
|
block := blk.NewGenesisBlock([]byte{})
|
|
if err := db.SaveBlock(ctx, block); err != nil {
|
|
t.Fatalf("Could not save genesis block: %v", err)
|
|
}
|
|
genesisRoot, err := ssz.HashTreeRoot(block.Block)
|
|
if err != nil {
|
|
t.Fatalf("Could not get signing root %v", err)
|
|
}
|
|
|
|
state := &pbp2p.BeaconState{
|
|
Slot: slot,
|
|
Validators: []*ethpb.Validator{{
|
|
PublicKey: pubKey,
|
|
ActivationEpoch: 0,
|
|
ExitEpoch: exitEpoch,
|
|
WithdrawableEpoch: withdrawableEpoch},
|
|
}}
|
|
stateObj, err := stateTrie.InitializeFromProtoUnsafe(state)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
depData := ðpb.Deposit_Data{
|
|
PublicKey: pubKey,
|
|
Signature: []byte("hi"),
|
|
WithdrawalCredentials: []byte("hey"),
|
|
}
|
|
|
|
deposit := ðpb.Deposit{
|
|
Data: depData,
|
|
}
|
|
depositTrie, err := trieutil.NewTrie(int(params.BeaconConfig().DepositContractTreeDepth))
|
|
if err != nil {
|
|
t.Fatalf("Could not setup deposit trie: %v", err)
|
|
}
|
|
depositCache := depositcache.NewDepositCache()
|
|
depositCache.InsertDeposit(ctx, deposit, 0 /*blockNum*/, 0, depositTrie.Root())
|
|
height := time.Unix(int64(params.BeaconConfig().Eth1FollowDistance), 0).Unix()
|
|
p := &mockPOW.POWChain{
|
|
TimesByHeight: map[int]uint64{
|
|
0: uint64(height),
|
|
},
|
|
}
|
|
vs := &Server{
|
|
BeaconDB: db,
|
|
ChainStartFetcher: p,
|
|
BlockFetcher: p,
|
|
Eth1InfoFetcher: p,
|
|
DepositFetcher: depositCache,
|
|
HeadFetcher: &mockChain.ChainService{State: stateObj, Root: genesisRoot[:]},
|
|
}
|
|
req := ðpb.ValidatorStatusRequest{
|
|
PublicKey: pubKey,
|
|
}
|
|
resp, err := vs.ValidatorStatus(context.Background(), req)
|
|
if err != nil {
|
|
t.Fatalf("Could not get validator status %v", err)
|
|
}
|
|
if resp.Status != ethpb.ValidatorStatus_EXITING {
|
|
t.Errorf("Wanted %v, got %v", ethpb.ValidatorStatus_EXITING, resp.Status)
|
|
}
|
|
}
|
|
|
|
func TestValidatorStatus_Slashing(t *testing.T) {
|
|
db := dbutil.SetupDB(t)
|
|
defer dbutil.TeardownDB(t, db)
|
|
ctx := context.Background()
|
|
|
|
pubKey := pubKey(1)
|
|
if err := db.SaveValidatorIndex(ctx, pubKey, 0); err != nil {
|
|
t.Fatalf("Could not save validator index: %v", err)
|
|
}
|
|
|
|
// Exit slashed because slashed is true, exit epoch is =< current epoch and withdrawable epoch > epoch .
|
|
slot := uint64(10000)
|
|
epoch := helpers.SlotToEpoch(slot)
|
|
block := blk.NewGenesisBlock([]byte{})
|
|
if err := db.SaveBlock(ctx, block); err != nil {
|
|
t.Fatalf("Could not save genesis block: %v", err)
|
|
}
|
|
genesisRoot, err := ssz.HashTreeRoot(block.Block)
|
|
if err != nil {
|
|
t.Fatalf("Could not get signing root %v", err)
|
|
}
|
|
|
|
state := &pbp2p.BeaconState{
|
|
Slot: slot,
|
|
Validators: []*ethpb.Validator{{
|
|
Slashed: true,
|
|
PublicKey: pubKey,
|
|
WithdrawableEpoch: epoch + 1},
|
|
}}
|
|
stateObj, err := stateTrie.InitializeFromProtoUnsafe(state)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
depData := ðpb.Deposit_Data{
|
|
PublicKey: pubKey,
|
|
Signature: []byte("hi"),
|
|
WithdrawalCredentials: []byte("hey"),
|
|
}
|
|
|
|
deposit := ðpb.Deposit{
|
|
Data: depData,
|
|
}
|
|
depositTrie, err := trieutil.NewTrie(int(params.BeaconConfig().DepositContractTreeDepth))
|
|
if err != nil {
|
|
t.Fatalf("Could not setup deposit trie: %v", err)
|
|
}
|
|
depositCache := depositcache.NewDepositCache()
|
|
depositCache.InsertDeposit(ctx, deposit, 0 /*blockNum*/, 0, depositTrie.Root())
|
|
height := time.Unix(int64(params.BeaconConfig().Eth1FollowDistance), 0).Unix()
|
|
p := &mockPOW.POWChain{
|
|
TimesByHeight: map[int]uint64{
|
|
0: uint64(height),
|
|
},
|
|
}
|
|
vs := &Server{
|
|
BeaconDB: db,
|
|
ChainStartFetcher: p,
|
|
Eth1InfoFetcher: p,
|
|
DepositFetcher: depositCache,
|
|
BlockFetcher: p,
|
|
HeadFetcher: &mockChain.ChainService{State: stateObj, Root: genesisRoot[:]},
|
|
}
|
|
req := ðpb.ValidatorStatusRequest{
|
|
PublicKey: pubKey,
|
|
}
|
|
resp, err := vs.ValidatorStatus(context.Background(), req)
|
|
if err != nil {
|
|
t.Fatalf("Could not get validator status %v", err)
|
|
}
|
|
if resp.Status != ethpb.ValidatorStatus_EXITED {
|
|
t.Errorf("Wanted %v, got %v", ethpb.ValidatorStatus_EXITED, resp.Status)
|
|
}
|
|
}
|
|
|
|
func TestValidatorStatus_Exited(t *testing.T) {
|
|
db := dbutil.SetupDB(t)
|
|
defer dbutil.TeardownDB(t, db)
|
|
ctx := context.Background()
|
|
|
|
pubKey := pubKey(1)
|
|
if err := db.SaveValidatorIndex(ctx, pubKey, 0); err != nil {
|
|
t.Fatalf("Could not save validator index: %v", err)
|
|
}
|
|
|
|
// Exit because only exit epoch is =< current epoch.
|
|
slot := uint64(10000)
|
|
epoch := helpers.SlotToEpoch(slot)
|
|
block := blk.NewGenesisBlock([]byte{})
|
|
if err := db.SaveBlock(ctx, block); err != nil {
|
|
t.Fatalf("Could not save genesis block: %v", err)
|
|
}
|
|
genesisRoot, err := ssz.HashTreeRoot(block.Block)
|
|
if err != nil {
|
|
t.Fatalf("Could not get signing root %v", err)
|
|
}
|
|
numDeposits := params.BeaconConfig().MinGenesisActiveValidatorCount
|
|
beaconState, _ := testutil.DeterministicGenesisState(t, numDeposits)
|
|
if err := db.SaveState(ctx, beaconState, genesisRoot); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := db.SaveHeadBlockRoot(ctx, genesisRoot); err != nil {
|
|
t.Fatalf("Could not save genesis state: %v", err)
|
|
}
|
|
state, _ := stateTrie.InitializeFromProto(&pbp2p.BeaconState{
|
|
Slot: slot,
|
|
Validators: []*ethpb.Validator{{
|
|
PublicKey: pubKey,
|
|
WithdrawableEpoch: epoch + 1},
|
|
},
|
|
})
|
|
depData := ðpb.Deposit_Data{
|
|
PublicKey: pubKey,
|
|
Signature: []byte("hi"),
|
|
WithdrawalCredentials: []byte("hey"),
|
|
}
|
|
|
|
deposit := ðpb.Deposit{
|
|
Data: depData,
|
|
}
|
|
depositTrie, err := trieutil.NewTrie(int(params.BeaconConfig().DepositContractTreeDepth))
|
|
if err != nil {
|
|
t.Fatalf("Could not setup deposit trie: %v", err)
|
|
}
|
|
depositCache := depositcache.NewDepositCache()
|
|
depositCache.InsertDeposit(ctx, deposit, 0 /*blockNum*/, 0, depositTrie.Root())
|
|
height := time.Unix(int64(params.BeaconConfig().Eth1FollowDistance), 0).Unix()
|
|
p := &mockPOW.POWChain{
|
|
TimesByHeight: map[int]uint64{
|
|
0: uint64(height),
|
|
},
|
|
}
|
|
vs := &Server{
|
|
BeaconDB: db,
|
|
ChainStartFetcher: p,
|
|
Eth1InfoFetcher: p,
|
|
BlockFetcher: p,
|
|
DepositFetcher: depositCache,
|
|
HeadFetcher: &mockChain.ChainService{State: state, Root: genesisRoot[:]},
|
|
}
|
|
req := ðpb.ValidatorStatusRequest{
|
|
PublicKey: pubKey,
|
|
}
|
|
resp, err := vs.ValidatorStatus(context.Background(), req)
|
|
if err != nil {
|
|
t.Fatalf("Could not get validator status %v", err)
|
|
}
|
|
if resp.Status != ethpb.ValidatorStatus_EXITED {
|
|
t.Errorf("Wanted %v, got %v", ethpb.ValidatorStatus_EXITED, resp.Status)
|
|
}
|
|
}
|
|
|
|
func TestValidatorStatus_UnknownStatus(t *testing.T) {
|
|
db := dbutil.SetupDB(t)
|
|
defer dbutil.TeardownDB(t, db)
|
|
pubKey := pubKey(1)
|
|
depositCache := depositcache.NewDepositCache()
|
|
stateObj, err := stateTrie.InitializeFromProtoUnsafe(&pbp2p.BeaconState{
|
|
Slot: 0,
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
vs := &Server{
|
|
DepositFetcher: depositCache,
|
|
Eth1InfoFetcher: &mockPOW.POWChain{},
|
|
HeadFetcher: &mockChain.ChainService{
|
|
State: stateObj,
|
|
},
|
|
BeaconDB: db,
|
|
}
|
|
req := ðpb.ValidatorStatusRequest{
|
|
PublicKey: pubKey,
|
|
}
|
|
resp, err := vs.ValidatorStatus(context.Background(), req)
|
|
if err != nil {
|
|
t.Fatalf("Could not get validator status %v", err)
|
|
}
|
|
if resp.Status != ethpb.ValidatorStatus_UNKNOWN_STATUS {
|
|
t.Errorf("Wanted %v, got %v", ethpb.ValidatorStatus_UNKNOWN_STATUS, resp.Status)
|
|
}
|
|
}
|
|
|
|
func TestMultipleValidatorStatus_OK(t *testing.T) {
|
|
db := dbutil.SetupDB(t)
|
|
defer dbutil.TeardownDB(t, db)
|
|
ctx := context.Background()
|
|
|
|
pubKeys := [][]byte{pubKey(1), pubKey(2), pubKey(3)}
|
|
stateObj, err := stateTrie.InitializeFromProtoUnsafe(&pbp2p.BeaconState{
|
|
Slot: 4000,
|
|
Validators: []*ethpb.Validator{
|
|
{
|
|
ActivationEpoch: 0,
|
|
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
|
PublicKey: pubKeys[0],
|
|
},
|
|
{
|
|
ActivationEpoch: 0,
|
|
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
|
PublicKey: pubKeys[1],
|
|
},
|
|
},
|
|
})
|
|
block := blk.NewGenesisBlock([]byte{})
|
|
genesisRoot, err := ssz.HashTreeRoot(block.Block)
|
|
if err != nil {
|
|
t.Fatalf("Could not get signing root %v", err)
|
|
}
|
|
depData := ðpb.Deposit_Data{
|
|
PublicKey: pubKey(1),
|
|
Signature: []byte("hi"),
|
|
WithdrawalCredentials: []byte("hey"),
|
|
Amount: 10,
|
|
}
|
|
|
|
dep := ðpb.Deposit{
|
|
Data: depData,
|
|
}
|
|
depositTrie, err := trieutil.NewTrie(int(params.BeaconConfig().DepositContractTreeDepth))
|
|
if err != nil {
|
|
t.Fatalf("Could not setup deposit trie: %v", err)
|
|
}
|
|
depositCache := depositcache.NewDepositCache()
|
|
depositCache.InsertDeposit(ctx, dep, 10 /*blockNum*/, 0, depositTrie.Root())
|
|
depData = ðpb.Deposit_Data{
|
|
PublicKey: pubKey(3),
|
|
Signature: []byte("hi"),
|
|
WithdrawalCredentials: []byte("hey"),
|
|
Amount: 10,
|
|
}
|
|
|
|
dep = ðpb.Deposit{
|
|
Data: depData,
|
|
}
|
|
depositTrie.Insert(dep.Data.Signature, 15)
|
|
depositCache.InsertDeposit(context.Background(), dep, 0, 0, depositTrie.Root())
|
|
|
|
if err := db.SaveValidatorIndex(ctx, pubKeys[0], 0); err != nil {
|
|
t.Fatalf("could not save validator index: %v", err)
|
|
}
|
|
if err := db.SaveValidatorIndex(ctx, pubKeys[1], 1); err != nil {
|
|
t.Fatalf("could not save validator index: %v", err)
|
|
}
|
|
vs := &Server{
|
|
BeaconDB: db,
|
|
Ctx: context.Background(),
|
|
CanonicalStateChan: make(chan *pbp2p.BeaconState, 1),
|
|
ChainStartFetcher: &mockPOW.POWChain{},
|
|
BlockFetcher: &mockPOW.POWChain{},
|
|
Eth1InfoFetcher: &mockPOW.POWChain{},
|
|
DepositFetcher: depositCache,
|
|
HeadFetcher: &mockChain.ChainService{State: stateObj, Root: genesisRoot[:]},
|
|
}
|
|
activeExists, response, err := vs.multipleValidatorStatus(context.Background(), pubKeys)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !activeExists {
|
|
t.Fatal("No activated validator exists when there was supposed to be 2")
|
|
}
|
|
if response[0].Status.Status != ethpb.ValidatorStatus_ACTIVE {
|
|
t.Errorf("Validator with pubkey %#x is not activated and instead has this status: %s",
|
|
response[0].PublicKey, response[0].Status.Status.String())
|
|
}
|
|
|
|
if response[1].Status.Status != ethpb.ValidatorStatus_ACTIVE {
|
|
t.Errorf("Validator with pubkey %#x was activated when not supposed to",
|
|
response[1].PublicKey)
|
|
}
|
|
|
|
if response[2].Status.Status != ethpb.ValidatorStatus_DEPOSITED {
|
|
t.Errorf("Validator with pubkey %#x is not activated and instead has this status: %s",
|
|
response[2].PublicKey, response[2].Status.Status.String())
|
|
}
|
|
}
|
|
|
|
func TestValidatorStatus_CorrectActivationQueue(t *testing.T) {
|
|
db := dbutil.SetupDB(t)
|
|
defer dbutil.TeardownDB(t, db)
|
|
ctx := context.Background()
|
|
|
|
pbKey := pubKey(5)
|
|
if err := db.SaveValidatorIndex(ctx, pbKey, 5); err != nil {
|
|
t.Fatalf("Could not save validator index: %v", err)
|
|
}
|
|
block := blk.NewGenesisBlock([]byte{})
|
|
if err := db.SaveBlock(ctx, block); err != nil {
|
|
t.Fatalf("Could not save genesis block: %v", err)
|
|
}
|
|
genesisRoot, err := ssz.HashTreeRoot(block.Block)
|
|
if err != nil {
|
|
t.Fatalf("Could not get signing root %v", err)
|
|
}
|
|
currentSlot := uint64(5000)
|
|
// Pending active because activation epoch is still defaulted at far future slot.
|
|
state, err := stateTrie.InitializeFromProtoUnsafe(&pbp2p.BeaconState{
|
|
Validators: []*ethpb.Validator{
|
|
{
|
|
ActivationEpoch: 0,
|
|
PublicKey: pubKey(0),
|
|
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
|
WithdrawableEpoch: params.BeaconConfig().FarFutureEpoch,
|
|
},
|
|
{
|
|
ActivationEpoch: 0,
|
|
PublicKey: pubKey(1),
|
|
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
|
WithdrawableEpoch: params.BeaconConfig().FarFutureEpoch,
|
|
},
|
|
{
|
|
ActivationEpoch: 0,
|
|
PublicKey: pubKey(2),
|
|
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
|
WithdrawableEpoch: params.BeaconConfig().FarFutureEpoch,
|
|
},
|
|
{
|
|
ActivationEpoch: 0,
|
|
PublicKey: pubKey(3),
|
|
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
|
WithdrawableEpoch: params.BeaconConfig().FarFutureEpoch,
|
|
},
|
|
{
|
|
ActivationEpoch: currentSlot/params.BeaconConfig().SlotsPerEpoch + 1,
|
|
PublicKey: pbKey,
|
|
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
|
WithdrawableEpoch: params.BeaconConfig().FarFutureEpoch,
|
|
},
|
|
{
|
|
ActivationEpoch: currentSlot/params.BeaconConfig().SlotsPerEpoch + 4,
|
|
PublicKey: pubKey(5),
|
|
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
|
WithdrawableEpoch: params.BeaconConfig().FarFutureEpoch,
|
|
},
|
|
},
|
|
Slot: currentSlot,
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := db.SaveState(ctx, state, genesisRoot); err != nil {
|
|
t.Fatalf("could not save state: %v", err)
|
|
}
|
|
if err := db.SaveHeadBlockRoot(ctx, genesisRoot); err != nil {
|
|
t.Fatalf("Could not save genesis state: %v", err)
|
|
}
|
|
|
|
depositTrie, err := trieutil.NewTrie(int(params.BeaconConfig().DepositContractTreeDepth))
|
|
if err != nil {
|
|
t.Fatalf("Could not setup deposit trie: %v", err)
|
|
}
|
|
depositCache := depositcache.NewDepositCache()
|
|
|
|
for i := 0; i < 6; i++ {
|
|
depData := ðpb.Deposit_Data{
|
|
PublicKey: pubKey(uint64(i)),
|
|
Signature: []byte("hi"),
|
|
WithdrawalCredentials: []byte("hey"),
|
|
}
|
|
|
|
deposit := ðpb.Deposit{
|
|
Data: depData,
|
|
}
|
|
depositCache.InsertDeposit(ctx, deposit, 0 /*blockNum*/, 0, depositTrie.Root())
|
|
|
|
}
|
|
|
|
height := time.Unix(int64(params.BeaconConfig().Eth1FollowDistance), 0).Unix()
|
|
p := &mockPOW.POWChain{
|
|
TimesByHeight: map[int]uint64{
|
|
0: uint64(height),
|
|
},
|
|
}
|
|
vs := &Server{
|
|
BeaconDB: db,
|
|
ChainStartFetcher: p,
|
|
BlockFetcher: p,
|
|
Eth1InfoFetcher: p,
|
|
DepositFetcher: depositCache,
|
|
HeadFetcher: &mockChain.ChainService{State: state, Root: genesisRoot[:]},
|
|
}
|
|
req := ðpb.ValidatorStatusRequest{
|
|
PublicKey: pbKey,
|
|
}
|
|
resp, err := vs.ValidatorStatus(context.Background(), req)
|
|
if err != nil {
|
|
t.Fatalf("Could not get validator status %v", err)
|
|
}
|
|
if resp.Status != ethpb.ValidatorStatus_PENDING {
|
|
t.Errorf("Wanted %v, got %v", ethpb.ValidatorStatus_PENDING, resp.Status)
|
|
}
|
|
if resp.PositionInActivationQueue != 2 {
|
|
t.Errorf("Expected Position in activation queue of %d but instead got %d", 2, resp.PositionInActivationQueue)
|
|
}
|
|
}
|
|
|
|
func TestDepositBlockSlotAfterGenesisTime(t *testing.T) {
|
|
db := dbutil.SetupDB(t)
|
|
defer dbutil.TeardownDB(t, db)
|
|
ctx := context.Background()
|
|
|
|
pubKey := pubKey(1)
|
|
if err := db.SaveValidatorIndex(ctx, pubKey, 0); err != nil {
|
|
t.Fatalf("Could not save validator index: %v", err)
|
|
}
|
|
|
|
depData := ðpb.Deposit_Data{
|
|
PublicKey: pubKey,
|
|
Signature: []byte("hi"),
|
|
WithdrawalCredentials: []byte("hey"),
|
|
}
|
|
|
|
deposit := ðpb.Deposit{
|
|
Data: depData,
|
|
}
|
|
depositTrie, err := trieutil.NewTrie(int(params.BeaconConfig().DepositContractTreeDepth))
|
|
if err != nil {
|
|
t.Fatalf("Could not setup deposit trie: %v", err)
|
|
}
|
|
depositCache := depositcache.NewDepositCache()
|
|
depositCache.InsertDeposit(ctx, deposit, 0 /*blockNum*/, 0, depositTrie.Root())
|
|
|
|
timestamp := time.Unix(int64(params.BeaconConfig().Eth1FollowDistance), 0).Unix()
|
|
p := &mockPOW.POWChain{
|
|
TimesByHeight: map[int]uint64{
|
|
int(params.BeaconConfig().Eth1FollowDistance): uint64(timestamp),
|
|
},
|
|
}
|
|
|
|
block := blk.NewGenesisBlock([]byte{})
|
|
if err := db.SaveBlock(ctx, block); err != nil {
|
|
t.Fatalf("Could not save genesis block: %v", err)
|
|
}
|
|
genesisRoot, err := ssz.HashTreeRoot(block.Block)
|
|
if err != nil {
|
|
t.Fatalf("Could not get signing root %v", err)
|
|
}
|
|
|
|
activeEpoch := helpers.DelayedActivationExitEpoch(0)
|
|
|
|
state, err := stateTrie.InitializeFromProtoUnsafe(&pbp2p.BeaconState{
|
|
GenesisTime: uint64(time.Unix(0, 0).Unix()),
|
|
Slot: 10000,
|
|
Validators: []*ethpb.Validator{{
|
|
ActivationEpoch: activeEpoch,
|
|
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
|
PublicKey: pubKey},
|
|
}})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
vs := &Server{
|
|
BeaconDB: db,
|
|
ChainStartFetcher: p,
|
|
BlockFetcher: p,
|
|
Eth1InfoFetcher: p,
|
|
DepositFetcher: depositCache,
|
|
HeadFetcher: &mockChain.ChainService{State: state, Root: genesisRoot[:]},
|
|
}
|
|
|
|
eth1BlockNumBigInt := big.NewInt(1000000)
|
|
|
|
resp, err := vs.depositBlockSlot(context.Background(), eth1BlockNumBigInt, state)
|
|
if err != nil {
|
|
t.Fatalf("Could not get the deposit block slot %v", err)
|
|
}
|
|
|
|
expected := uint64(53)
|
|
|
|
if resp != expected {
|
|
t.Errorf("Wanted %v, got %v", expected, resp)
|
|
}
|
|
}
|
|
|
|
func TestDepositBlockSlotBeforeGenesisTime(t *testing.T) {
|
|
db := dbutil.SetupDB(t)
|
|
defer dbutil.TeardownDB(t, db)
|
|
ctx := context.Background()
|
|
|
|
pubKey := pubKey(1)
|
|
if err := db.SaveValidatorIndex(ctx, pubKey, 0); err != nil {
|
|
t.Fatalf("Could not save validator index: %v", err)
|
|
}
|
|
|
|
depData := ðpb.Deposit_Data{
|
|
PublicKey: pubKey,
|
|
Signature: []byte("hi"),
|
|
WithdrawalCredentials: []byte("hey"),
|
|
}
|
|
|
|
deposit := ðpb.Deposit{
|
|
Data: depData,
|
|
}
|
|
depositTrie, err := trieutil.NewTrie(int(params.BeaconConfig().DepositContractTreeDepth))
|
|
if err != nil {
|
|
t.Fatalf("Could not setup deposit trie: %v", err)
|
|
}
|
|
depositCache := depositcache.NewDepositCache()
|
|
depositCache.InsertDeposit(ctx, deposit, 0 /*blockNum*/, 0, depositTrie.Root())
|
|
|
|
timestamp := time.Unix(int64(params.BeaconConfig().Eth1FollowDistance), 0).Unix()
|
|
p := &mockPOW.POWChain{
|
|
TimesByHeight: map[int]uint64{
|
|
int(params.BeaconConfig().Eth1FollowDistance): uint64(timestamp),
|
|
},
|
|
}
|
|
|
|
block := blk.NewGenesisBlock([]byte{})
|
|
if err := db.SaveBlock(ctx, block); err != nil {
|
|
t.Fatalf("Could not save genesis block: %v", err)
|
|
}
|
|
genesisRoot, err := ssz.HashTreeRoot(block.Block)
|
|
if err != nil {
|
|
t.Fatalf("Could not get signing root %v", err)
|
|
}
|
|
|
|
activeEpoch := helpers.DelayedActivationExitEpoch(0)
|
|
|
|
state, err := stateTrie.InitializeFromProtoUnsafe(&pbp2p.BeaconState{
|
|
GenesisTime: uint64(time.Unix(25000, 0).Unix()),
|
|
Slot: 10000,
|
|
Validators: []*ethpb.Validator{{
|
|
ActivationEpoch: activeEpoch,
|
|
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
|
PublicKey: pubKey},
|
|
}})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
vs := &Server{
|
|
BeaconDB: db,
|
|
ChainStartFetcher: p,
|
|
BlockFetcher: p,
|
|
Eth1InfoFetcher: p,
|
|
DepositFetcher: depositCache,
|
|
HeadFetcher: &mockChain.ChainService{State: state, Root: genesisRoot[:]},
|
|
}
|
|
|
|
eth1BlockNumBigInt := big.NewInt(1000000)
|
|
|
|
resp, err := vs.depositBlockSlot(context.Background(), eth1BlockNumBigInt, state)
|
|
if err != nil {
|
|
t.Fatalf("Could not get the deposit block slot %v", err)
|
|
}
|
|
|
|
expected := uint64(0)
|
|
|
|
if resp != expected {
|
|
t.Errorf("Wanted %v, got %v", expected, resp)
|
|
}
|
|
}
|