2020-07-06 22:27:42 +00:00
|
|
|
package blocks_test
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"testing"
|
|
|
|
|
2021-02-16 07:45:34 +00:00
|
|
|
types "github.com/prysmaticlabs/eth2-types"
|
2020-07-06 22:27:42 +00:00
|
|
|
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
|
|
|
"github.com/prysmaticlabs/prysm/beacon-chain/core/blocks"
|
|
|
|
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
2021-03-17 19:49:49 +00:00
|
|
|
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateV0"
|
2020-07-06 22:27:42 +00:00
|
|
|
pb "github.com/prysmaticlabs/prysm/proto/beacon/p2p/v1"
|
|
|
|
"github.com/prysmaticlabs/prysm/shared/bls"
|
|
|
|
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
|
|
|
"github.com/prysmaticlabs/prysm/shared/params"
|
|
|
|
"github.com/prysmaticlabs/prysm/shared/testutil"
|
2020-08-08 19:06:04 +00:00
|
|
|
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
|
|
|
|
"github.com/prysmaticlabs/prysm/shared/testutil/require"
|
2020-07-06 22:27:42 +00:00
|
|
|
"github.com/prysmaticlabs/prysm/shared/trieutil"
|
|
|
|
)
|
|
|
|
|
|
|
|
func TestProcessDeposits_SameValidatorMultipleDepositsSameBlock(t *testing.T) {
|
|
|
|
// Same validator created 3 valid deposits within the same block
|
|
|
|
testutil.ResetCache()
|
|
|
|
dep, _, err := testutil.DeterministicDepositsAndKeysSameValidator(3)
|
2020-08-08 19:06:04 +00:00
|
|
|
require.NoError(t, err)
|
2020-07-06 22:27:42 +00:00
|
|
|
eth1Data, err := testutil.DeterministicEth1Data(len(dep))
|
2020-08-08 19:06:04 +00:00
|
|
|
require.NoError(t, err)
|
2020-09-01 01:29:27 +00:00
|
|
|
b := testutil.NewBeaconBlock()
|
|
|
|
b.Block = ðpb.BeaconBlock{
|
2020-07-06 22:27:42 +00:00
|
|
|
Body: ðpb.BeaconBlockBody{
|
|
|
|
// 3 deposits from the same validator
|
|
|
|
Deposits: []*ethpb.Deposit{dep[0], dep[1], dep[2]},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
registry := []*ethpb.Validator{
|
|
|
|
{
|
|
|
|
PublicKey: []byte{1},
|
|
|
|
WithdrawalCredentials: []byte{1, 2, 3},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
balances := []uint64{0}
|
2021-03-17 19:49:49 +00:00
|
|
|
beaconState, err := stateV0.InitializeFromProto(&pb.BeaconState{
|
2020-07-06 22:27:42 +00:00
|
|
|
Validators: registry,
|
|
|
|
Balances: balances,
|
|
|
|
Eth1Data: eth1Data,
|
|
|
|
Fork: &pb.Fork{
|
|
|
|
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
|
|
|
|
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
|
|
|
|
},
|
|
|
|
})
|
2020-08-08 19:06:04 +00:00
|
|
|
require.NoError(t, err)
|
2021-04-02 14:48:41 +00:00
|
|
|
newState, err := blocks.ProcessDeposits(context.Background(), beaconState, b.Block.Body.Deposits)
|
2020-08-08 19:06:04 +00:00
|
|
|
require.NoError(t, err, "Expected block deposits to process correctly")
|
2020-07-06 22:27:42 +00:00
|
|
|
|
2020-08-08 19:06:04 +00:00
|
|
|
assert.Equal(t, 2, len(newState.Validators()), "Incorrect validator count")
|
2020-07-06 22:27:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestProcessDeposits_MerkleBranchFailsVerification(t *testing.T) {
|
|
|
|
deposit := ðpb.Deposit{
|
|
|
|
Data: ðpb.Deposit_Data{
|
2020-08-27 18:13:32 +00:00
|
|
|
PublicKey: bytesutil.PadTo([]byte{1, 2, 3}, 48),
|
|
|
|
WithdrawalCredentials: make([]byte, 32),
|
|
|
|
Signature: make([]byte, 96),
|
2020-07-06 22:27:42 +00:00
|
|
|
},
|
|
|
|
}
|
2020-08-27 18:13:32 +00:00
|
|
|
leaf, err := deposit.Data.HashTreeRoot()
|
2020-08-08 19:06:04 +00:00
|
|
|
require.NoError(t, err)
|
2020-07-06 22:27:42 +00:00
|
|
|
|
|
|
|
// We then create a merkle branch for the test.
|
2020-10-13 12:43:49 +00:00
|
|
|
depositTrie, err := trieutil.GenerateTrieFromItems([][]byte{leaf[:]}, params.BeaconConfig().DepositContractTreeDepth)
|
2020-08-08 19:06:04 +00:00
|
|
|
require.NoError(t, err, "Could not generate trie")
|
2020-07-06 22:27:42 +00:00
|
|
|
proof, err := depositTrie.MerkleProof(0)
|
2020-08-08 19:06:04 +00:00
|
|
|
require.NoError(t, err, "Could not generate proof")
|
2020-07-06 22:27:42 +00:00
|
|
|
|
|
|
|
deposit.Proof = proof
|
2020-09-01 01:29:27 +00:00
|
|
|
b := testutil.NewBeaconBlock()
|
|
|
|
b.Block = ðpb.BeaconBlock{
|
2020-07-06 22:27:42 +00:00
|
|
|
Body: ðpb.BeaconBlockBody{
|
|
|
|
Deposits: []*ethpb.Deposit{deposit},
|
|
|
|
},
|
|
|
|
}
|
2021-03-17 19:49:49 +00:00
|
|
|
beaconState, err := stateV0.InitializeFromProto(&pb.BeaconState{
|
2020-07-06 22:27:42 +00:00
|
|
|
Eth1Data: ðpb.Eth1Data{
|
|
|
|
DepositRoot: []byte{0},
|
|
|
|
BlockHash: []byte{1},
|
|
|
|
},
|
|
|
|
})
|
2020-08-08 19:06:04 +00:00
|
|
|
require.NoError(t, err)
|
2020-07-06 22:27:42 +00:00
|
|
|
want := "deposit root did not verify"
|
2021-04-02 14:48:41 +00:00
|
|
|
_, err = blocks.ProcessDeposits(context.Background(), beaconState, b.Block.Body.Deposits)
|
2020-08-08 19:06:04 +00:00
|
|
|
assert.ErrorContains(t, want, err)
|
2020-07-06 22:27:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestProcessDeposits_AddsNewValidatorDeposit(t *testing.T) {
|
|
|
|
dep, _, err := testutil.DeterministicDepositsAndKeys(1)
|
2020-08-08 19:06:04 +00:00
|
|
|
require.NoError(t, err)
|
2020-07-06 22:27:42 +00:00
|
|
|
eth1Data, err := testutil.DeterministicEth1Data(len(dep))
|
2020-08-08 19:06:04 +00:00
|
|
|
require.NoError(t, err)
|
2020-07-06 22:27:42 +00:00
|
|
|
|
2020-09-01 01:29:27 +00:00
|
|
|
b := testutil.NewBeaconBlock()
|
|
|
|
b.Block = ðpb.BeaconBlock{
|
2020-07-06 22:27:42 +00:00
|
|
|
Body: ðpb.BeaconBlockBody{
|
|
|
|
Deposits: []*ethpb.Deposit{dep[0]},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
registry := []*ethpb.Validator{
|
|
|
|
{
|
|
|
|
PublicKey: []byte{1},
|
|
|
|
WithdrawalCredentials: []byte{1, 2, 3},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
balances := []uint64{0}
|
2021-03-17 19:49:49 +00:00
|
|
|
beaconState, err := stateV0.InitializeFromProto(&pb.BeaconState{
|
2020-07-06 22:27:42 +00:00
|
|
|
Validators: registry,
|
|
|
|
Balances: balances,
|
|
|
|
Eth1Data: eth1Data,
|
|
|
|
Fork: &pb.Fork{
|
|
|
|
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
|
|
|
|
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
|
|
|
|
},
|
|
|
|
})
|
2020-08-08 19:06:04 +00:00
|
|
|
require.NoError(t, err)
|
2021-04-02 14:48:41 +00:00
|
|
|
newState, err := blocks.ProcessDeposits(context.Background(), beaconState, b.Block.Body.Deposits)
|
2020-08-08 19:06:04 +00:00
|
|
|
require.NoError(t, err, "Expected block deposits to process correctly")
|
2020-07-06 22:27:42 +00:00
|
|
|
if newState.Balances()[1] != dep[0].Data.Amount {
|
|
|
|
t.Errorf(
|
|
|
|
"Expected state validator balances index 0 to equal %d, received %d",
|
|
|
|
dep[0].Data.Amount,
|
|
|
|
newState.Balances()[1],
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestProcessDeposits_RepeatedDeposit_IncreasesValidatorBalance(t *testing.T) {
|
2020-10-30 19:06:33 +00:00
|
|
|
sk, err := bls.RandKey()
|
|
|
|
require.NoError(t, err)
|
2020-07-06 22:27:42 +00:00
|
|
|
deposit := ðpb.Deposit{
|
|
|
|
Data: ðpb.Deposit_Data{
|
2020-08-27 18:13:32 +00:00
|
|
|
PublicKey: sk.PublicKey().Marshal(),
|
|
|
|
Amount: 1000,
|
|
|
|
WithdrawalCredentials: make([]byte, 32),
|
|
|
|
Signature: make([]byte, 96),
|
2020-07-06 22:27:42 +00:00
|
|
|
},
|
|
|
|
}
|
2020-08-27 18:13:32 +00:00
|
|
|
sr, err := helpers.ComputeSigningRoot(deposit.Data, bytesutil.ToBytes(3, 32))
|
2020-08-08 19:06:04 +00:00
|
|
|
require.NoError(t, err)
|
2020-07-06 22:27:42 +00:00
|
|
|
sig := sk.Sign(sr[:])
|
|
|
|
deposit.Data.Signature = sig.Marshal()
|
2020-08-27 18:13:32 +00:00
|
|
|
leaf, err := deposit.Data.HashTreeRoot()
|
2020-08-08 19:06:04 +00:00
|
|
|
require.NoError(t, err)
|
2020-07-06 22:27:42 +00:00
|
|
|
|
|
|
|
// We then create a merkle branch for the test.
|
2020-10-13 12:43:49 +00:00
|
|
|
depositTrie, err := trieutil.GenerateTrieFromItems([][]byte{leaf[:]}, params.BeaconConfig().DepositContractTreeDepth)
|
2020-08-08 19:06:04 +00:00
|
|
|
require.NoError(t, err, "Could not generate trie")
|
2020-07-06 22:27:42 +00:00
|
|
|
proof, err := depositTrie.MerkleProof(0)
|
2020-08-08 19:06:04 +00:00
|
|
|
require.NoError(t, err, "Could not generate proof")
|
2020-07-06 22:27:42 +00:00
|
|
|
|
|
|
|
deposit.Proof = proof
|
2020-09-01 01:29:27 +00:00
|
|
|
b := testutil.NewBeaconBlock()
|
|
|
|
b.Block = ðpb.BeaconBlock{
|
2020-07-06 22:27:42 +00:00
|
|
|
Body: ðpb.BeaconBlockBody{
|
|
|
|
Deposits: []*ethpb.Deposit{deposit},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
registry := []*ethpb.Validator{
|
|
|
|
{
|
|
|
|
PublicKey: []byte{1, 2, 3},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
PublicKey: sk.PublicKey().Marshal(),
|
|
|
|
WithdrawalCredentials: []byte{1},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
balances := []uint64{0, 50}
|
|
|
|
root := depositTrie.Root()
|
2021-03-17 19:49:49 +00:00
|
|
|
beaconState, err := stateV0.InitializeFromProto(&pb.BeaconState{
|
2020-07-06 22:27:42 +00:00
|
|
|
Validators: registry,
|
|
|
|
Balances: balances,
|
|
|
|
Eth1Data: ðpb.Eth1Data{
|
|
|
|
DepositRoot: root[:],
|
|
|
|
BlockHash: root[:],
|
|
|
|
},
|
|
|
|
})
|
2020-08-08 19:06:04 +00:00
|
|
|
require.NoError(t, err)
|
2021-04-02 14:48:41 +00:00
|
|
|
newState, err := blocks.ProcessDeposits(context.Background(), beaconState, b.Block.Body.Deposits)
|
2020-08-08 19:06:04 +00:00
|
|
|
require.NoError(t, err, "Process deposit failed")
|
|
|
|
assert.Equal(t, uint64(1000+50), newState.Balances()[1], "Expected balance at index 1 to be 1050")
|
2020-07-06 22:27:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestProcessDeposit_AddsNewValidatorDeposit(t *testing.T) {
|
2021-01-05 13:09:41 +00:00
|
|
|
// Similar to TestProcessDeposits_AddsNewValidatorDeposit except that this test directly calls ProcessDeposit
|
2020-07-06 22:27:42 +00:00
|
|
|
dep, _, err := testutil.DeterministicDepositsAndKeys(1)
|
2020-08-08 19:06:04 +00:00
|
|
|
require.NoError(t, err)
|
2020-07-06 22:27:42 +00:00
|
|
|
eth1Data, err := testutil.DeterministicEth1Data(len(dep))
|
2020-08-08 19:06:04 +00:00
|
|
|
require.NoError(t, err)
|
2020-07-06 22:27:42 +00:00
|
|
|
|
|
|
|
registry := []*ethpb.Validator{
|
|
|
|
{
|
|
|
|
PublicKey: []byte{1},
|
|
|
|
WithdrawalCredentials: []byte{1, 2, 3},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
balances := []uint64{0}
|
2021-03-17 19:49:49 +00:00
|
|
|
beaconState, err := stateV0.InitializeFromProto(&pb.BeaconState{
|
2020-07-06 22:27:42 +00:00
|
|
|
Validators: registry,
|
|
|
|
Balances: balances,
|
|
|
|
Eth1Data: eth1Data,
|
|
|
|
Fork: &pb.Fork{
|
|
|
|
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
|
|
|
|
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
|
|
|
|
},
|
|
|
|
})
|
2020-08-08 19:06:04 +00:00
|
|
|
require.NoError(t, err)
|
2020-07-06 22:27:42 +00:00
|
|
|
newState, err := blocks.ProcessDeposit(beaconState, dep[0], true)
|
2020-08-08 19:06:04 +00:00
|
|
|
require.NoError(t, err, "Process deposit failed")
|
|
|
|
assert.Equal(t, 2, len(newState.Validators()), "Expected validator list to have length 2")
|
|
|
|
assert.Equal(t, 2, len(newState.Balances()), "Expected validator balances list to have length 2")
|
2020-07-06 22:27:42 +00:00
|
|
|
if newState.Balances()[1] != dep[0].Data.Amount {
|
|
|
|
t.Errorf(
|
|
|
|
"Expected state validator balances index 1 to equal %d, received %d",
|
|
|
|
dep[0].Data.Amount,
|
|
|
|
newState.Balances()[1],
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestProcessDeposit_SkipsInvalidDeposit(t *testing.T) {
|
|
|
|
// Same test settings as in TestProcessDeposit_AddsNewValidatorDeposit, except that we use an invalid signature
|
|
|
|
dep, _, err := testutil.DeterministicDepositsAndKeys(1)
|
2020-08-08 19:06:04 +00:00
|
|
|
require.NoError(t, err)
|
2020-07-06 22:27:42 +00:00
|
|
|
dep[0].Data.Signature = make([]byte, 96)
|
|
|
|
trie, _, err := testutil.DepositTrieFromDeposits(dep)
|
2020-08-08 19:06:04 +00:00
|
|
|
require.NoError(t, err)
|
2020-07-06 22:27:42 +00:00
|
|
|
root := trie.Root()
|
|
|
|
eth1Data := ðpb.Eth1Data{
|
|
|
|
DepositRoot: root[:],
|
|
|
|
DepositCount: 1,
|
|
|
|
}
|
|
|
|
registry := []*ethpb.Validator{
|
|
|
|
{
|
|
|
|
PublicKey: []byte{1},
|
|
|
|
WithdrawalCredentials: []byte{1, 2, 3},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
balances := []uint64{0}
|
2021-03-17 19:49:49 +00:00
|
|
|
beaconState, err := stateV0.InitializeFromProto(&pb.BeaconState{
|
2020-07-06 22:27:42 +00:00
|
|
|
Validators: registry,
|
|
|
|
Balances: balances,
|
|
|
|
Eth1Data: eth1Data,
|
|
|
|
Fork: &pb.Fork{
|
|
|
|
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
|
|
|
|
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
|
|
|
|
},
|
|
|
|
})
|
2020-08-08 19:06:04 +00:00
|
|
|
require.NoError(t, err)
|
2020-07-06 22:27:42 +00:00
|
|
|
newState, err := blocks.ProcessDeposit(beaconState, dep[0], true)
|
2020-08-08 19:06:04 +00:00
|
|
|
require.NoError(t, err, "Expected invalid block deposit to be ignored without error")
|
2020-07-06 22:27:42 +00:00
|
|
|
|
|
|
|
if newState.Eth1DepositIndex() != 1 {
|
|
|
|
t.Errorf(
|
|
|
|
"Expected Eth1DepositIndex to be increased by 1 after processing an invalid deposit, received change: %v",
|
|
|
|
newState.Eth1DepositIndex(),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
if len(newState.Validators()) != 1 {
|
|
|
|
t.Errorf("Expected validator list to have length 1, received: %v", len(newState.Validators()))
|
|
|
|
}
|
|
|
|
if len(newState.Balances()) != 1 {
|
|
|
|
t.Errorf("Expected validator balances list to have length 1, received: %v", len(newState.Balances()))
|
|
|
|
}
|
|
|
|
if newState.Balances()[0] != 0 {
|
|
|
|
t.Errorf("Expected validator balance at index 0 to stay 0, received: %v", newState.Balances()[0])
|
|
|
|
}
|
|
|
|
}
|
2020-11-02 16:34:37 +00:00
|
|
|
|
|
|
|
func TestPreGenesisDeposits_SkipInvalidDeposit(t *testing.T) {
|
|
|
|
testutil.ResetCache()
|
|
|
|
dep, _, err := testutil.DeterministicDepositsAndKeys(100)
|
|
|
|
require.NoError(t, err)
|
2021-01-04 18:16:18 +00:00
|
|
|
defer testutil.ResetCache()
|
2020-11-02 16:34:37 +00:00
|
|
|
dep[0].Data.Signature = make([]byte, 96)
|
|
|
|
trie, _, err := testutil.DepositTrieFromDeposits(dep)
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
for i := range dep {
|
|
|
|
proof, err := trie.MerkleProof(i)
|
|
|
|
require.NoError(t, err)
|
|
|
|
dep[i].Proof = proof
|
|
|
|
}
|
|
|
|
root := trie.Root()
|
|
|
|
eth1Data := ðpb.Eth1Data{
|
|
|
|
DepositRoot: root[:],
|
|
|
|
DepositCount: 1,
|
|
|
|
}
|
|
|
|
registry := []*ethpb.Validator{
|
|
|
|
{
|
|
|
|
PublicKey: []byte{1},
|
|
|
|
WithdrawalCredentials: []byte{1, 2, 3},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
balances := []uint64{0}
|
2021-03-17 19:49:49 +00:00
|
|
|
beaconState, err := stateV0.InitializeFromProto(&pb.BeaconState{
|
2020-11-02 16:34:37 +00:00
|
|
|
Validators: registry,
|
|
|
|
Balances: balances,
|
|
|
|
Eth1Data: eth1Data,
|
|
|
|
Fork: &pb.Fork{
|
|
|
|
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
|
|
|
|
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
|
|
|
|
},
|
|
|
|
})
|
|
|
|
require.NoError(t, err)
|
|
|
|
newState, err := blocks.ProcessPreGenesisDeposits(context.Background(), beaconState, dep)
|
|
|
|
require.NoError(t, err, "Expected invalid block deposit to be ignored without error")
|
|
|
|
|
|
|
|
_, ok := newState.ValidatorIndexByPubkey(bytesutil.ToBytes48(dep[0].Data.PublicKey))
|
|
|
|
require.Equal(t, false, ok, "bad pubkey should not exist in state")
|
|
|
|
|
|
|
|
for i := 1; i < newState.NumValidators(); i++ {
|
2021-02-23 00:14:50 +00:00
|
|
|
val, err := newState.ValidatorAtIndex(types.ValidatorIndex(i))
|
2020-11-02 16:34:37 +00:00
|
|
|
require.NoError(t, err)
|
|
|
|
require.Equal(t, params.BeaconConfig().MaxEffectiveBalance, val.EffectiveBalance, "unequal effective balance")
|
2021-02-09 10:05:22 +00:00
|
|
|
require.Equal(t, types.Epoch(0), val.ActivationEpoch)
|
|
|
|
require.Equal(t, types.Epoch(0), val.ActivationEligibilityEpoch)
|
2020-11-02 16:34:37 +00:00
|
|
|
}
|
|
|
|
if newState.Eth1DepositIndex() != 100 {
|
|
|
|
t.Errorf(
|
|
|
|
"Expected Eth1DepositIndex to be increased by 99 after processing an invalid deposit, received change: %v",
|
|
|
|
newState.Eth1DepositIndex(),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
if len(newState.Validators()) != 100 {
|
|
|
|
t.Errorf("Expected validator list to have length 100, received: %v", len(newState.Validators()))
|
|
|
|
}
|
|
|
|
if len(newState.Balances()) != 100 {
|
|
|
|
t.Errorf("Expected validator balances list to have length 100, received: %v", len(newState.Balances()))
|
|
|
|
}
|
|
|
|
if newState.Balances()[0] != 0 {
|
|
|
|
t.Errorf("Expected validator balance at index 0 to stay 0, received: %v", newState.Balances()[0])
|
|
|
|
}
|
|
|
|
}
|