mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-06 22:23:56 -05:00
* Ran gopls modernize to fix everything go run golang.org/x/tools/gopls/internal/analysis/modernize/cmd/modernize@latest -fix -test ./... * Override rules_go provided dependency for golang.org/x/tools to v0.38.0. To update this, checked out rules_go, then ran `bazel run //go/tools/releaser -- upgrade-dep -mirror=false org_golang_x_tools` and copied the patches. * Fix buildtag violations and ignore buildtag violations in external * Introduce modernize analyzer package. * Add modernize "any" analyzer. * Fix violations of any analyzer * Add modernize "appendclipped" analyzer. * Fix violations of appendclipped * Add modernize "bloop" analyzer. * Add modernize "fmtappendf" analyzer. * Add modernize "forvar" analyzer. * Add modernize "mapsloop" analyzer. * Add modernize "minmax" analyzer. * Fix violations of minmax analyzer * Add modernize "omitzero" analyzer. * Add modernize "rangeint" analyzer. * Fix violations of rangeint. * Add modernize "reflecttypefor" analyzer. * Fix violations of reflecttypefor analyzer. * Add modernize "slicescontains" analyzer. * Add modernize "slicessort" analyzer. * Add modernize "slicesdelete" analyzer. This is disabled by default for now. See https://go.dev/issue/73686. * Add modernize "stringscutprefix" analyzer. * Add modernize "stringsbuilder" analyzer. * Fix violations of stringsbuilder analyzer. * Add modernize "stringsseq" analyzer. * Add modernize "testingcontext" analyzer. * Add modernize "waitgroup" analyzer. * Changelog fragment * gofmt * gazelle * Add modernize "newexpr" analyzer. * Disable newexpr until go1.26 * Add more details in WORKSPACE on how to update the override * @nalepae feedback on min() * gofmt * Fix violations of forvar
639 lines
23 KiB
Go
639 lines
23 KiB
Go
package electra_test
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
|
|
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/electra"
|
|
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/helpers"
|
|
"github.com/OffchainLabs/prysm/v7/beacon-chain/core/signing"
|
|
"github.com/OffchainLabs/prysm/v7/beacon-chain/state"
|
|
state_native "github.com/OffchainLabs/prysm/v7/beacon-chain/state/state-native"
|
|
stateTesting "github.com/OffchainLabs/prysm/v7/beacon-chain/state/testing"
|
|
fieldparams "github.com/OffchainLabs/prysm/v7/config/fieldparams"
|
|
"github.com/OffchainLabs/prysm/v7/config/params"
|
|
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
|
|
"github.com/OffchainLabs/prysm/v7/crypto/bls"
|
|
"github.com/OffchainLabs/prysm/v7/encoding/bytesutil"
|
|
enginev1 "github.com/OffchainLabs/prysm/v7/proto/engine/v1"
|
|
eth "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
|
"github.com/OffchainLabs/prysm/v7/testing/require"
|
|
"github.com/OffchainLabs/prysm/v7/testing/util"
|
|
)
|
|
|
|
func TestProcessPendingDepositsMultiplesSameDeposits(t *testing.T) {
|
|
st := stateWithActiveBalanceETH(t, 1000)
|
|
deps := make([]*eth.PendingDeposit, 2) // Make same deposit twice
|
|
validators := st.Validators()
|
|
sk, err := bls.RandKey()
|
|
require.NoError(t, err)
|
|
for i := 0; i < len(deps); i += 1 {
|
|
wc := make([]byte, 32)
|
|
wc[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
|
|
wc[31] = byte(i)
|
|
validators[i].PublicKey = sk.PublicKey().Marshal()
|
|
validators[i].WithdrawalCredentials = wc
|
|
deps[i] = stateTesting.GeneratePendingDeposit(t, sk, 32, bytesutil.ToBytes32(wc), 0)
|
|
}
|
|
require.NoError(t, st.SetPendingDeposits(deps))
|
|
|
|
err = electra.ProcessPendingDeposits(context.TODO(), st, 10000)
|
|
require.NoError(t, err)
|
|
|
|
val := st.Validators()
|
|
seenPubkeys := make(map[string]struct{})
|
|
for i := 0; i < len(val); i += 1 {
|
|
if len(val[i].PublicKey) == 0 {
|
|
continue
|
|
}
|
|
_, ok := seenPubkeys[string(val[i].PublicKey)]
|
|
if ok {
|
|
t.Fatalf("duplicated pubkeys")
|
|
} else {
|
|
seenPubkeys[string(val[i].PublicKey)] = struct{}{}
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestProcessPendingDeposits(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
state state.BeaconState
|
|
wantErr bool
|
|
check func(*testing.T, state.BeaconState)
|
|
}{
|
|
{
|
|
name: "nil state fails",
|
|
state: nil,
|
|
wantErr: true,
|
|
},
|
|
{
|
|
name: "no deposits resets balance to consume",
|
|
state: func() state.BeaconState {
|
|
st := stateWithActiveBalanceETH(t, 1_000)
|
|
require.NoError(t, st.SetDepositBalanceToConsume(100))
|
|
return st
|
|
}(),
|
|
check: func(t *testing.T, st state.BeaconState) {
|
|
res, err := st.DepositBalanceToConsume()
|
|
require.NoError(t, err)
|
|
require.Equal(t, primitives.Gwei(0), res)
|
|
},
|
|
},
|
|
{
|
|
name: "more deposits than balance to consume processes partial deposits",
|
|
state: func() state.BeaconState {
|
|
amountAvailForProcessing := helpers.ActivationExitChurnLimit(1_000 * 1e9)
|
|
depositAmount := uint64(amountAvailForProcessing) / 10
|
|
st := stateWithPendingDeposits(t, 1_000, 20, depositAmount)
|
|
require.NoError(t, st.SetDepositBalanceToConsume(100))
|
|
return st
|
|
}(),
|
|
check: func(t *testing.T, st state.BeaconState) {
|
|
amountAvailForProcessing := helpers.ActivationExitChurnLimit(1_000 * 1e9)
|
|
res, err := st.DepositBalanceToConsume()
|
|
require.NoError(t, err)
|
|
require.Equal(t, primitives.Gwei(100), res)
|
|
// Validators 0..9 should have their balance increased
|
|
for i := range primitives.ValidatorIndex(10) {
|
|
b, err := st.BalanceAtIndex(i)
|
|
require.NoError(t, err)
|
|
require.Equal(t, params.BeaconConfig().MinActivationBalance+uint64(amountAvailForProcessing)/10, b)
|
|
}
|
|
|
|
// Half of the balance deposits should have been processed.
|
|
remaining, err := st.PendingDeposits()
|
|
require.NoError(t, err)
|
|
require.Equal(t, 10, len(remaining))
|
|
},
|
|
},
|
|
{
|
|
name: "withdrawn validators should not consume churn",
|
|
state: func() state.BeaconState {
|
|
amountAvailForProcessing := helpers.ActivationExitChurnLimit(1_000 * 1e9)
|
|
depositAmount := uint64(amountAvailForProcessing)
|
|
// set the pending deposits to the maximum churn limit
|
|
st := stateWithPendingDeposits(t, 1_000, 2, depositAmount)
|
|
vals := st.Validators()
|
|
vals[1].WithdrawableEpoch = 0
|
|
require.NoError(t, st.SetValidators(vals))
|
|
return st
|
|
}(),
|
|
check: func(t *testing.T, st state.BeaconState) {
|
|
amountAvailForProcessing := helpers.ActivationExitChurnLimit(1_000 * 1e9)
|
|
// Validators 0..9 should have their balance increased
|
|
for i := range primitives.ValidatorIndex(2) {
|
|
b, err := st.BalanceAtIndex(i)
|
|
require.NoError(t, err)
|
|
require.Equal(t, params.BeaconConfig().MinActivationBalance+uint64(amountAvailForProcessing), b)
|
|
}
|
|
|
|
// All pending deposits should have been processed
|
|
remaining, err := st.PendingDeposits()
|
|
require.NoError(t, err)
|
|
require.Equal(t, 0, len(remaining))
|
|
},
|
|
},
|
|
{
|
|
name: "less deposits than balance to consume processes all deposits",
|
|
state: func() state.BeaconState {
|
|
amountAvailForProcessing := helpers.ActivationExitChurnLimit(1_000 * 1e9)
|
|
depositAmount := uint64(amountAvailForProcessing) / 5
|
|
st := stateWithPendingDeposits(t, 1_000, 5, depositAmount)
|
|
require.NoError(t, st.SetDepositBalanceToConsume(0))
|
|
return st
|
|
}(),
|
|
check: func(t *testing.T, st state.BeaconState) {
|
|
amountAvailForProcessing := helpers.ActivationExitChurnLimit(1_000 * 1e9)
|
|
res, err := st.DepositBalanceToConsume()
|
|
require.NoError(t, err)
|
|
require.Equal(t, primitives.Gwei(0), res)
|
|
// Validators 0..4 should have their balance increased
|
|
for i := range primitives.ValidatorIndex(4) {
|
|
b, err := st.BalanceAtIndex(i)
|
|
require.NoError(t, err)
|
|
require.Equal(t, params.BeaconConfig().MinActivationBalance+uint64(amountAvailForProcessing)/5, b)
|
|
}
|
|
|
|
// All of the balance deposits should have been processed.
|
|
remaining, err := st.PendingDeposits()
|
|
require.NoError(t, err)
|
|
require.Equal(t, 0, len(remaining))
|
|
},
|
|
},
|
|
{
|
|
name: "process pending deposit for unknown key, activates new key",
|
|
state: func() state.BeaconState {
|
|
st := stateWithActiveBalanceETH(t, 0)
|
|
sk, err := bls.RandKey()
|
|
require.NoError(t, err)
|
|
wc := make([]byte, 32)
|
|
wc[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
|
|
wc[31] = byte(0)
|
|
dep := stateTesting.GeneratePendingDeposit(t, sk, params.BeaconConfig().MinActivationBalance, bytesutil.ToBytes32(wc), 0)
|
|
require.NoError(t, st.SetPendingDeposits([]*eth.PendingDeposit{dep}))
|
|
require.Equal(t, 0, len(st.Validators()))
|
|
require.Equal(t, 0, len(st.Balances()))
|
|
return st
|
|
}(),
|
|
check: func(t *testing.T, st state.BeaconState) {
|
|
res, err := st.DepositBalanceToConsume()
|
|
require.NoError(t, err)
|
|
require.Equal(t, primitives.Gwei(0), res)
|
|
b, err := st.BalanceAtIndex(0)
|
|
require.NoError(t, err)
|
|
require.Equal(t, params.BeaconConfig().MinActivationBalance, b)
|
|
|
|
// All of the balance deposits should have been processed.
|
|
remaining, err := st.PendingDeposits()
|
|
require.NoError(t, err)
|
|
require.Equal(t, 0, len(remaining))
|
|
|
|
// validator becomes active
|
|
require.Equal(t, 1, len(st.Validators()))
|
|
require.Equal(t, 1, len(st.Balances()))
|
|
},
|
|
},
|
|
{
|
|
name: "process excess balance as a topup",
|
|
state: func() state.BeaconState {
|
|
excessBalance := uint64(100)
|
|
st := stateWithActiveBalanceETH(t, 32)
|
|
validators := st.Validators()
|
|
sk, err := bls.RandKey()
|
|
require.NoError(t, err)
|
|
wc := make([]byte, 32)
|
|
wc[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
|
|
wc[31] = byte(0)
|
|
validators[0].PublicKey = sk.PublicKey().Marshal()
|
|
validators[0].WithdrawalCredentials = wc
|
|
dep := stateTesting.GeneratePendingDeposit(t, sk, excessBalance, bytesutil.ToBytes32(wc), 0)
|
|
require.NoError(t, st.SetValidators(validators))
|
|
require.NoError(t, st.SetPendingDeposits([]*eth.PendingDeposit{dep}))
|
|
return st
|
|
}(),
|
|
check: func(t *testing.T, st state.BeaconState) {
|
|
res, err := st.DepositBalanceToConsume()
|
|
require.NoError(t, err)
|
|
require.Equal(t, primitives.Gwei(0), res)
|
|
b, err := st.BalanceAtIndex(0)
|
|
require.NoError(t, err)
|
|
require.Equal(t, params.BeaconConfig().MinActivationBalance+uint64(100), b)
|
|
|
|
// All of the balance deposits should have been processed.
|
|
remaining, err := st.PendingDeposits()
|
|
require.NoError(t, err)
|
|
require.Equal(t, 0, len(remaining))
|
|
},
|
|
},
|
|
{
|
|
name: "exiting validator deposit postponed",
|
|
state: func() state.BeaconState {
|
|
amountAvailForProcessing := helpers.ActivationExitChurnLimit(1_000 * 1e9)
|
|
depositAmount := uint64(amountAvailForProcessing) / 5
|
|
st := stateWithPendingDeposits(t, 1_000, 5, depositAmount)
|
|
require.NoError(t, st.SetDepositBalanceToConsume(0))
|
|
v, err := st.ValidatorAtIndex(0)
|
|
require.NoError(t, err)
|
|
v.ExitEpoch = 10
|
|
v.WithdrawableEpoch = 20
|
|
require.NoError(t, st.UpdateValidatorAtIndex(0, v))
|
|
return st
|
|
}(),
|
|
check: func(t *testing.T, st state.BeaconState) {
|
|
amountAvailForProcessing := helpers.ActivationExitChurnLimit(1_000 * 1e9)
|
|
res, err := st.DepositBalanceToConsume()
|
|
require.NoError(t, err)
|
|
require.Equal(t, primitives.Gwei(0), res)
|
|
// Validators 1..4 should have their balance increased
|
|
for i := primitives.ValidatorIndex(1); i < 4; i++ {
|
|
b, err := st.BalanceAtIndex(i)
|
|
require.NoError(t, err)
|
|
require.Equal(t, params.BeaconConfig().MinActivationBalance+uint64(amountAvailForProcessing)/5, b)
|
|
}
|
|
|
|
// All of the balance deposits should have been processed, except validator index 0 was
|
|
// added back to the pending deposits queue.
|
|
remaining, err := st.PendingDeposits()
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1, len(remaining))
|
|
},
|
|
},
|
|
{
|
|
name: "exited validator balance increased",
|
|
state: func() state.BeaconState {
|
|
st := stateWithPendingDeposits(t, 1_000, 1, 1_000_000)
|
|
v, err := st.ValidatorAtIndex(0)
|
|
require.NoError(t, err)
|
|
v.ExitEpoch = 2
|
|
v.WithdrawableEpoch = 8
|
|
require.NoError(t, st.UpdateValidatorAtIndex(0, v))
|
|
require.NoError(t, st.UpdateBalancesAtIndex(0, 100_000))
|
|
return st
|
|
}(),
|
|
check: func(t *testing.T, st state.BeaconState) {
|
|
res, err := st.DepositBalanceToConsume()
|
|
require.NoError(t, err)
|
|
require.Equal(t, primitives.Gwei(0), res)
|
|
b, err := st.BalanceAtIndex(0)
|
|
require.NoError(t, err)
|
|
require.Equal(t, uint64(1_100_000), b)
|
|
|
|
// All of the balance deposits should have been processed.
|
|
remaining, err := st.PendingDeposits()
|
|
require.NoError(t, err)
|
|
require.Equal(t, 0, len(remaining))
|
|
},
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
var tab uint64
|
|
var err error
|
|
if tt.state != nil {
|
|
// The caller of this method would normally have the precompute balance values for total
|
|
// active balance for this epoch. For ease of test setup, we will compute total active
|
|
// balance from the given state.
|
|
tab, err = helpers.TotalActiveBalance(tt.state)
|
|
}
|
|
require.NoError(t, err)
|
|
err = electra.ProcessPendingDeposits(context.TODO(), tt.state, primitives.Gwei(tab))
|
|
require.Equal(t, tt.wantErr, err != nil, "wantErr=%v, got err=%s", tt.wantErr, err)
|
|
if tt.check != nil {
|
|
tt.check(t, tt.state)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestBatchProcessNewPendingDeposits(t *testing.T) {
|
|
t.Run("one valid deposit one garbage deposit", func(t *testing.T) {
|
|
st := stateWithActiveBalanceETH(t, 0)
|
|
require.Equal(t, 0, len(st.Validators()))
|
|
require.Equal(t, 0, len(st.Balances()))
|
|
sk, err := bls.RandKey()
|
|
require.NoError(t, err)
|
|
wc := make([]byte, 32)
|
|
wc[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
|
|
wc[31] = byte(0)
|
|
validDep := stateTesting.GeneratePendingDeposit(t, sk, params.BeaconConfig().MinActivationBalance, bytesutil.ToBytes32(wc), 0)
|
|
invalidDep := ð.PendingDeposit{PublicKey: make([]byte, 48)}
|
|
deps := []*eth.PendingDeposit{validDep, invalidDep}
|
|
require.NoError(t, electra.BatchProcessNewPendingDeposits(t.Context(), st, deps))
|
|
require.Equal(t, 1, len(st.Validators()))
|
|
require.Equal(t, 1, len(st.Balances()))
|
|
})
|
|
|
|
t.Run("two valid deposits from same key", func(t *testing.T) {
|
|
st := stateWithActiveBalanceETH(t, 0)
|
|
require.Equal(t, 0, len(st.Validators()))
|
|
require.Equal(t, 0, len(st.Balances()))
|
|
sk, err := bls.RandKey()
|
|
require.NoError(t, err)
|
|
wc := make([]byte, 32)
|
|
wc[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
|
|
wc[31] = byte(0)
|
|
validDep := stateTesting.GeneratePendingDeposit(t, sk, params.BeaconConfig().MinActivationBalance, bytesutil.ToBytes32(wc), 0)
|
|
deps := []*eth.PendingDeposit{validDep, validDep}
|
|
require.NoError(t, electra.BatchProcessNewPendingDeposits(t.Context(), st, deps))
|
|
require.Equal(t, 1, len(st.Validators()))
|
|
require.Equal(t, 1, len(st.Balances()))
|
|
require.Equal(t, params.BeaconConfig().MinActivationBalance*2, st.Balances()[0])
|
|
})
|
|
|
|
t.Run("one valid one with invalid signature deposit", func(t *testing.T) {
|
|
st := stateWithActiveBalanceETH(t, 0)
|
|
require.Equal(t, 0, len(st.Validators()))
|
|
require.Equal(t, 0, len(st.Balances()))
|
|
sk, err := bls.RandKey()
|
|
require.NoError(t, err)
|
|
wc := make([]byte, 32)
|
|
wc[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
|
|
wc[31] = byte(0)
|
|
validDep := stateTesting.GeneratePendingDeposit(t, sk, params.BeaconConfig().MinActivationBalance, bytesutil.ToBytes32(wc), 0)
|
|
invalidSigDep := stateTesting.GeneratePendingDeposit(t, sk, params.BeaconConfig().MinActivationBalance, bytesutil.ToBytes32(wc), 0)
|
|
invalidSigDep.Signature = make([]byte, 96)
|
|
deps := []*eth.PendingDeposit{validDep, invalidSigDep}
|
|
require.NoError(t, electra.BatchProcessNewPendingDeposits(t.Context(), st, deps))
|
|
require.Equal(t, 1, len(st.Validators()))
|
|
require.Equal(t, 1, len(st.Balances()))
|
|
require.Equal(t, 2*params.BeaconConfig().MinActivationBalance, st.Balances()[0])
|
|
})
|
|
}
|
|
|
|
func TestProcessDepositRequests(t *testing.T) {
|
|
st, _ := util.DeterministicGenesisStateElectra(t, 1)
|
|
sk, err := bls.RandKey()
|
|
require.NoError(t, err)
|
|
require.NoError(t, st.SetDepositRequestsStartIndex(1))
|
|
|
|
t.Run("empty requests continues", func(t *testing.T) {
|
|
newSt, err := electra.ProcessDepositRequests(t.Context(), st, []*enginev1.DepositRequest{})
|
|
require.NoError(t, err)
|
|
require.DeepEqual(t, newSt, st)
|
|
})
|
|
t.Run("nil request errors", func(t *testing.T) {
|
|
_, err = electra.ProcessDepositRequests(t.Context(), st, []*enginev1.DepositRequest{nil})
|
|
require.ErrorContains(t, "nil deposit request", err)
|
|
})
|
|
|
|
vals := st.Validators()
|
|
vals[0].PublicKey = sk.PublicKey().Marshal()
|
|
vals[0].WithdrawalCredentials[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
|
|
require.NoError(t, st.SetValidators(vals))
|
|
bals := st.Balances()
|
|
bals[0] = params.BeaconConfig().MinActivationBalance + 2000
|
|
require.NoError(t, st.SetBalances(bals))
|
|
require.NoError(t, st.SetPendingDeposits(make([]*eth.PendingDeposit, 0))) // reset pbd as the determinitstic state populates this already
|
|
withdrawalCred := make([]byte, 32)
|
|
withdrawalCred[0] = params.BeaconConfig().CompoundingWithdrawalPrefixByte
|
|
depositMessage := ð.DepositMessage{
|
|
PublicKey: sk.PublicKey().Marshal(),
|
|
Amount: 1000,
|
|
WithdrawalCredentials: withdrawalCred,
|
|
}
|
|
domain, err := signing.ComputeDomain(params.BeaconConfig().DomainDeposit, nil, nil)
|
|
require.NoError(t, err)
|
|
sr, err := signing.ComputeSigningRoot(depositMessage, domain)
|
|
require.NoError(t, err)
|
|
sig := sk.Sign(sr[:])
|
|
requests := []*enginev1.DepositRequest{
|
|
{
|
|
Pubkey: depositMessage.PublicKey,
|
|
Index: 0,
|
|
WithdrawalCredentials: depositMessage.WithdrawalCredentials,
|
|
Amount: depositMessage.Amount,
|
|
Signature: sig.Marshal(),
|
|
},
|
|
}
|
|
st, err = electra.ProcessDepositRequests(t.Context(), st, requests)
|
|
require.NoError(t, err)
|
|
|
|
pbd, err := st.PendingDeposits()
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1, len(pbd))
|
|
require.Equal(t, uint64(1000), pbd[0].Amount)
|
|
}
|
|
|
|
func TestProcessDeposit_Electra_Simple(t *testing.T) {
|
|
deps, _, err := util.DeterministicDepositsAndKeysSameValidator(3)
|
|
require.NoError(t, err)
|
|
eth1Data, err := util.DeterministicEth1Data(len(deps))
|
|
require.NoError(t, err)
|
|
registry := []*eth.Validator{
|
|
{
|
|
PublicKey: []byte{1},
|
|
WithdrawalCredentials: []byte{1, 2, 3},
|
|
},
|
|
}
|
|
balances := []uint64{0}
|
|
st, err := state_native.InitializeFromProtoElectra(ð.BeaconStateElectra{
|
|
Validators: registry,
|
|
Balances: balances,
|
|
Eth1Data: eth1Data,
|
|
Fork: ð.Fork{
|
|
PreviousVersion: params.BeaconConfig().ElectraForkVersion,
|
|
CurrentVersion: params.BeaconConfig().ElectraForkVersion,
|
|
},
|
|
})
|
|
require.NoError(t, err)
|
|
pdSt, err := electra.ProcessDeposits(t.Context(), st, deps)
|
|
require.NoError(t, err)
|
|
pbd, err := pdSt.PendingDeposits()
|
|
require.NoError(t, err)
|
|
require.Equal(t, params.BeaconConfig().MinActivationBalance, pbd[2].Amount)
|
|
require.Equal(t, 3, len(pbd))
|
|
}
|
|
|
|
func TestProcessDeposit_SkipsInvalidDeposit(t *testing.T) {
|
|
// Same test settings as in TestProcessDeposit_AddsNewValidatorDeposit, except that we use an invalid signature
|
|
dep, _, err := util.DeterministicDepositsAndKeys(1)
|
|
require.NoError(t, err)
|
|
dep[0].Data.Signature = make([]byte, 96)
|
|
dt, _, err := util.DepositTrieFromDeposits(dep)
|
|
require.NoError(t, err)
|
|
root, err := dt.HashTreeRoot()
|
|
require.NoError(t, err)
|
|
eth1Data := ð.Eth1Data{
|
|
DepositRoot: root[:],
|
|
DepositCount: 1,
|
|
}
|
|
registry := []*eth.Validator{
|
|
{
|
|
PublicKey: []byte{1},
|
|
WithdrawalCredentials: []byte{1, 2, 3},
|
|
},
|
|
}
|
|
balances := []uint64{0}
|
|
beaconState, err := state_native.InitializeFromProtoElectra(ð.BeaconStateElectra{
|
|
Validators: registry,
|
|
Balances: balances,
|
|
Eth1Data: eth1Data,
|
|
Fork: ð.Fork{
|
|
PreviousVersion: params.BeaconConfig().GenesisForkVersion,
|
|
CurrentVersion: params.BeaconConfig().GenesisForkVersion,
|
|
},
|
|
})
|
|
require.NoError(t, err)
|
|
newState, err := electra.ProcessDeposit(beaconState, dep[0], false)
|
|
require.NoError(t, err, "Expected invalid block deposit to be ignored without error")
|
|
|
|
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])
|
|
}
|
|
}
|
|
|
|
func TestApplyDeposit_TopUps_WithBadSignature(t *testing.T) {
|
|
st, _ := util.DeterministicGenesisStateElectra(t, 3)
|
|
sk, err := bls.RandKey()
|
|
require.NoError(t, err)
|
|
withdrawalCred := make([]byte, 32)
|
|
withdrawalCred[0] = params.BeaconConfig().CompoundingWithdrawalPrefixByte
|
|
topUpAmount := uint64(1234)
|
|
depositData := ð.Deposit_Data{
|
|
PublicKey: sk.PublicKey().Marshal(),
|
|
Amount: topUpAmount,
|
|
WithdrawalCredentials: withdrawalCred,
|
|
Signature: make([]byte, fieldparams.BLSSignatureLength),
|
|
}
|
|
vals := st.Validators()
|
|
vals[0].PublicKey = sk.PublicKey().Marshal()
|
|
vals[0].WithdrawalCredentials[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
|
|
require.NoError(t, st.SetValidators(vals))
|
|
adSt, err := electra.ApplyDeposit(st, depositData, false)
|
|
require.NoError(t, err)
|
|
pbd, err := adSt.PendingDeposits()
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1, len(pbd))
|
|
require.Equal(t, topUpAmount, pbd[0].Amount)
|
|
}
|
|
|
|
// stateWithActiveBalanceETH generates a mock beacon state given a balance in eth
|
|
func stateWithActiveBalanceETH(t *testing.T, balETH uint64) state.BeaconState {
|
|
gwei := balETH * 1_000_000_000
|
|
balPerVal := params.BeaconConfig().MinActivationBalance
|
|
numVals := gwei / balPerVal
|
|
|
|
vals := make([]*eth.Validator, numVals)
|
|
bals := make([]uint64, numVals)
|
|
for i := range numVals {
|
|
wc := make([]byte, 32)
|
|
wc[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
|
|
wc[31] = byte(i)
|
|
vals[i] = ð.Validator{
|
|
ActivationEpoch: 0,
|
|
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
|
EffectiveBalance: balPerVal,
|
|
WithdrawalCredentials: wc,
|
|
WithdrawableEpoch: params.BeaconConfig().FarFutureEpoch,
|
|
}
|
|
bals[i] = balPerVal
|
|
}
|
|
st, err := state_native.InitializeFromProtoUnsafeElectra(ð.BeaconStateElectra{
|
|
Slot: 10 * params.BeaconConfig().SlotsPerEpoch,
|
|
Validators: vals,
|
|
Balances: bals,
|
|
Fork: ð.Fork{
|
|
CurrentVersion: params.BeaconConfig().ElectraForkVersion,
|
|
},
|
|
})
|
|
require.NoError(t, err)
|
|
// set some fake finalized checkpoint
|
|
require.NoError(t, st.SetFinalizedCheckpoint(ð.Checkpoint{
|
|
Epoch: 0,
|
|
Root: make([]byte, 32),
|
|
}))
|
|
return st
|
|
}
|
|
|
|
// stateWithPendingDeposits with pending deposits and existing ethbalance
|
|
func stateWithPendingDeposits(t *testing.T, balETH uint64, numDeposits, amount uint64) state.BeaconState {
|
|
st := stateWithActiveBalanceETH(t, balETH)
|
|
deps := make([]*eth.PendingDeposit, numDeposits)
|
|
validators := st.Validators()
|
|
for i := 0; i < len(deps); i += 1 {
|
|
sk, err := bls.RandKey()
|
|
require.NoError(t, err)
|
|
wc := make([]byte, 32)
|
|
wc[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
|
|
wc[31] = byte(i)
|
|
validators[i].PublicKey = sk.PublicKey().Marshal()
|
|
validators[i].WithdrawalCredentials = wc
|
|
deps[i] = stateTesting.GeneratePendingDeposit(t, sk, amount, bytesutil.ToBytes32(wc), 0)
|
|
}
|
|
require.NoError(t, st.SetValidators(validators))
|
|
require.NoError(t, st.SetPendingDeposits(deps))
|
|
return st
|
|
}
|
|
|
|
func TestApplyPendingDeposit_TopUp(t *testing.T) {
|
|
excessBalance := uint64(100)
|
|
st := stateWithActiveBalanceETH(t, 32)
|
|
validators := st.Validators()
|
|
sk, err := bls.RandKey()
|
|
require.NoError(t, err)
|
|
wc := make([]byte, 32)
|
|
wc[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
|
|
wc[31] = byte(0)
|
|
validators[0].PublicKey = sk.PublicKey().Marshal()
|
|
validators[0].WithdrawalCredentials = wc
|
|
dep := stateTesting.GeneratePendingDeposit(t, sk, excessBalance, bytesutil.ToBytes32(wc), 0)
|
|
require.NoError(t, st.SetValidators(validators))
|
|
|
|
require.NoError(t, electra.ApplyPendingDeposit(t.Context(), st, dep))
|
|
|
|
b, err := st.BalanceAtIndex(0)
|
|
require.NoError(t, err)
|
|
require.Equal(t, params.BeaconConfig().MinActivationBalance+uint64(excessBalance), b)
|
|
}
|
|
|
|
func TestApplyPendingDeposit_UnknownKey(t *testing.T) {
|
|
st := stateWithActiveBalanceETH(t, 0)
|
|
sk, err := bls.RandKey()
|
|
require.NoError(t, err)
|
|
wc := make([]byte, 32)
|
|
wc[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
|
|
wc[31] = byte(0)
|
|
dep := stateTesting.GeneratePendingDeposit(t, sk, params.BeaconConfig().MinActivationBalance, bytesutil.ToBytes32(wc), 0)
|
|
require.Equal(t, 0, len(st.Validators()))
|
|
require.NoError(t, electra.ApplyPendingDeposit(t.Context(), st, dep))
|
|
// activates new validator
|
|
require.Equal(t, 1, len(st.Validators()))
|
|
b, err := st.BalanceAtIndex(0)
|
|
require.NoError(t, err)
|
|
require.Equal(t, params.BeaconConfig().MinActivationBalance, b)
|
|
}
|
|
|
|
func TestApplyPendingDeposit_InvalidSignature(t *testing.T) {
|
|
st := stateWithActiveBalanceETH(t, 0)
|
|
|
|
sk, err := bls.RandKey()
|
|
require.NoError(t, err)
|
|
wc := make([]byte, 32)
|
|
wc[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
|
|
wc[31] = byte(0)
|
|
dep := ð.PendingDeposit{
|
|
PublicKey: sk.PublicKey().Marshal(),
|
|
WithdrawalCredentials: wc,
|
|
Amount: 100,
|
|
}
|
|
require.Equal(t, 0, len(st.Validators()))
|
|
require.NoError(t, electra.ApplyPendingDeposit(t.Context(), st, dep))
|
|
// no validator added
|
|
require.Equal(t, 0, len(st.Validators()))
|
|
// no topup either
|
|
require.Equal(t, 0, len(st.Balances()))
|
|
}
|