mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-08 21:08:10 -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
453 lines
18 KiB
Go
453 lines
18 KiB
Go
package state_native_test
|
|
|
|
import (
|
|
"testing"
|
|
|
|
state_native "github.com/OffchainLabs/prysm/v7/beacon-chain/state/state-native"
|
|
"github.com/OffchainLabs/prysm/v7/config/params"
|
|
"github.com/OffchainLabs/prysm/v7/consensus-types/primitives"
|
|
enginev1 "github.com/OffchainLabs/prysm/v7/proto/engine/v1"
|
|
ethpb "github.com/OffchainLabs/prysm/v7/proto/prysm/v1alpha1"
|
|
"github.com/OffchainLabs/prysm/v7/runtime/version"
|
|
"github.com/OffchainLabs/prysm/v7/testing/assert"
|
|
"github.com/OffchainLabs/prysm/v7/testing/require"
|
|
"github.com/OffchainLabs/prysm/v7/testing/util"
|
|
"github.com/golang/snappy"
|
|
)
|
|
|
|
func TestNextWithdrawalIndex(t *testing.T) {
|
|
t.Run("ok for deneb", func(t *testing.T) {
|
|
s, err := state_native.InitializeFromProtoDeneb(ðpb.BeaconStateDeneb{NextWithdrawalIndex: 123})
|
|
require.NoError(t, err)
|
|
i, err := s.NextWithdrawalIndex()
|
|
require.NoError(t, err)
|
|
assert.Equal(t, uint64(123), i)
|
|
})
|
|
t.Run("ok", func(t *testing.T) {
|
|
s, err := state_native.InitializeFromProtoCapella(ðpb.BeaconStateCapella{NextWithdrawalIndex: 123})
|
|
require.NoError(t, err)
|
|
i, err := s.NextWithdrawalIndex()
|
|
require.NoError(t, err)
|
|
assert.Equal(t, uint64(123), i)
|
|
})
|
|
t.Run("version before Capella not supported", func(t *testing.T) {
|
|
s, err := state_native.InitializeFromProtoBellatrix(ðpb.BeaconStateBellatrix{})
|
|
require.NoError(t, err)
|
|
_, err = s.NextWithdrawalIndex()
|
|
assert.ErrorContains(t, "NextWithdrawalIndex is not supported", err)
|
|
})
|
|
}
|
|
|
|
func TestNextWithdrawalValidatorIndex(t *testing.T) {
|
|
t.Run("ok for deneb", func(t *testing.T) {
|
|
pb := ðpb.BeaconStateDeneb{NextWithdrawalValidatorIndex: 123}
|
|
s, err := state_native.InitializeFromProtoDeneb(pb)
|
|
require.NoError(t, err)
|
|
i, err := s.NextWithdrawalValidatorIndex()
|
|
require.NoError(t, err)
|
|
assert.Equal(t, primitives.ValidatorIndex(123), i)
|
|
})
|
|
t.Run("ok", func(t *testing.T) {
|
|
pb := ðpb.BeaconStateCapella{NextWithdrawalValidatorIndex: 123}
|
|
s, err := state_native.InitializeFromProtoCapella(pb)
|
|
require.NoError(t, err)
|
|
i, err := s.NextWithdrawalValidatorIndex()
|
|
require.NoError(t, err)
|
|
assert.Equal(t, primitives.ValidatorIndex(123), i)
|
|
})
|
|
t.Run("version before Capella not supported", func(t *testing.T) {
|
|
s, err := state_native.InitializeFromProtoBellatrix(ðpb.BeaconStateBellatrix{})
|
|
require.NoError(t, err)
|
|
_, err = s.NextWithdrawalValidatorIndex()
|
|
assert.ErrorContains(t, "NextWithdrawalValidatorIndex is not supported", err)
|
|
})
|
|
}
|
|
|
|
func TestExpectedWithdrawals(t *testing.T) {
|
|
for _, stateVersion := range []int{version.Capella, version.Deneb, version.Electra, version.Fulu} {
|
|
t.Run(version.String(stateVersion), func(t *testing.T) {
|
|
t.Run("no withdrawals", func(t *testing.T) {
|
|
s := state_native.EmptyStateFromVersion(t, stateVersion)
|
|
vals := make([]*ethpb.Validator, 100)
|
|
balances := make([]uint64, 100)
|
|
for i := range vals {
|
|
balances[i] = params.BeaconConfig().MaxEffectiveBalance
|
|
val := ðpb.Validator{
|
|
WithdrawalCredentials: make([]byte, 32),
|
|
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
|
|
WithdrawableEpoch: primitives.Epoch(1),
|
|
}
|
|
val.WithdrawalCredentials[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
|
|
vals[i] = val
|
|
}
|
|
require.NoError(t, s.SetValidators(vals))
|
|
require.NoError(t, s.SetBalances(balances))
|
|
expected, _, err := s.ExpectedWithdrawals()
|
|
require.NoError(t, err)
|
|
require.Equal(t, 0, len(expected))
|
|
})
|
|
t.Run("one fully withdrawable", func(t *testing.T) {
|
|
s := state_native.EmptyStateFromVersion(t, stateVersion)
|
|
require.NoError(t, s.SetNextWithdrawalValidatorIndex(20))
|
|
|
|
vals := make([]*ethpb.Validator, 100)
|
|
balances := make([]uint64, 100)
|
|
for i := range 100 {
|
|
balances[i] = params.BeaconConfig().MaxEffectiveBalance
|
|
val := ðpb.Validator{
|
|
WithdrawalCredentials: make([]byte, 32),
|
|
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
|
|
WithdrawableEpoch: primitives.Epoch(1),
|
|
}
|
|
val.WithdrawalCredentials[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
|
|
|
|
vals[i] = val
|
|
}
|
|
vals[3].WithdrawableEpoch = primitives.Epoch(0)
|
|
require.NoError(t, s.SetValidators(vals))
|
|
require.NoError(t, s.SetBalances(balances))
|
|
|
|
expected, _, err := s.ExpectedWithdrawals()
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1, len(expected))
|
|
withdrawal := &enginev1.Withdrawal{
|
|
Index: 0,
|
|
ValidatorIndex: 3,
|
|
Address: vals[3].WithdrawalCredentials[12:],
|
|
Amount: params.BeaconConfig().MaxEffectiveBalance,
|
|
}
|
|
require.DeepEqual(t, withdrawal, expected[0])
|
|
})
|
|
t.Run("one partially withdrawable", func(t *testing.T) {
|
|
s := state_native.EmptyStateFromVersion(t, stateVersion)
|
|
require.NoError(t, s.SetNextWithdrawalValidatorIndex(20))
|
|
|
|
vals := make([]*ethpb.Validator, 100)
|
|
balances := make([]uint64, 100)
|
|
for i := range 100 {
|
|
balances[i] = params.BeaconConfig().MaxEffectiveBalance
|
|
val := ðpb.Validator{
|
|
WithdrawalCredentials: make([]byte, 32),
|
|
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
|
|
WithdrawableEpoch: primitives.Epoch(1),
|
|
}
|
|
val.WithdrawalCredentials[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
|
|
|
|
vals[i] = val
|
|
}
|
|
balances[3] += params.BeaconConfig().MinDepositAmount
|
|
require.NoError(t, s.SetValidators(vals))
|
|
require.NoError(t, s.SetBalances(balances))
|
|
expected, _, err := s.ExpectedWithdrawals()
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1, len(expected))
|
|
withdrawal := &enginev1.Withdrawal{
|
|
Index: 0,
|
|
ValidatorIndex: 3,
|
|
Address: vals[3].WithdrawalCredentials[12:],
|
|
Amount: params.BeaconConfig().MinDepositAmount,
|
|
}
|
|
require.DeepEqual(t, withdrawal, expected[0])
|
|
})
|
|
t.Run("one partially and one fully withdrawable", func(t *testing.T) {
|
|
s := state_native.EmptyStateFromVersion(t, stateVersion)
|
|
vals := make([]*ethpb.Validator, 100)
|
|
balances := make([]uint64, 100)
|
|
for i := range vals {
|
|
balances[i] = params.BeaconConfig().MaxEffectiveBalance
|
|
val := ðpb.Validator{
|
|
WithdrawalCredentials: make([]byte, 32),
|
|
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
|
|
WithdrawableEpoch: primitives.Epoch(1),
|
|
}
|
|
val.WithdrawalCredentials[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
|
|
val.WithdrawalCredentials[31] = byte(i)
|
|
vals[i] = val
|
|
}
|
|
balances[3] += params.BeaconConfig().MinDepositAmount
|
|
vals[7].WithdrawableEpoch = primitives.Epoch(0)
|
|
require.NoError(t, s.SetValidators(vals))
|
|
require.NoError(t, s.SetBalances(balances))
|
|
expected, _, err := s.ExpectedWithdrawals()
|
|
require.NoError(t, err)
|
|
require.Equal(t, 2, len(expected))
|
|
|
|
withdrawalFull := &enginev1.Withdrawal{
|
|
Index: 1,
|
|
ValidatorIndex: 7,
|
|
Address: vals[7].WithdrawalCredentials[12:],
|
|
Amount: balances[7],
|
|
}
|
|
withdrawalPartial := &enginev1.Withdrawal{
|
|
Index: 0,
|
|
ValidatorIndex: 3,
|
|
Address: vals[3].WithdrawalCredentials[12:],
|
|
Amount: params.BeaconConfig().MinDepositAmount,
|
|
}
|
|
require.DeepEqual(t, withdrawalPartial, expected[0])
|
|
require.DeepEqual(t, withdrawalFull, expected[1])
|
|
})
|
|
t.Run("all partially withdrawable", func(t *testing.T) {
|
|
s := state_native.EmptyStateFromVersion(t, stateVersion)
|
|
vals := make([]*ethpb.Validator, 100)
|
|
balances := make([]uint64, 100)
|
|
for i := range vals {
|
|
balances[i] = params.BeaconConfig().MaxEffectiveBalance + 1
|
|
val := ðpb.Validator{
|
|
WithdrawalCredentials: make([]byte, 32),
|
|
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
|
|
WithdrawableEpoch: primitives.Epoch(1),
|
|
}
|
|
val.WithdrawalCredentials[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
|
|
val.WithdrawalCredentials[31] = byte(i)
|
|
vals[i] = val
|
|
}
|
|
require.NoError(t, s.SetValidators(vals))
|
|
require.NoError(t, s.SetBalances(balances))
|
|
expected, _, err := s.ExpectedWithdrawals()
|
|
require.NoError(t, err)
|
|
require.Equal(t, params.BeaconConfig().MaxWithdrawalsPerPayload, uint64(len(expected)))
|
|
withdrawal := &enginev1.Withdrawal{
|
|
Index: 0,
|
|
ValidatorIndex: 0,
|
|
Address: vals[0].WithdrawalCredentials[12:],
|
|
Amount: 1,
|
|
}
|
|
require.DeepEqual(t, withdrawal, expected[0])
|
|
})
|
|
t.Run("all fully withdrawable", func(t *testing.T) {
|
|
s := state_native.EmptyStateFromVersion(t, stateVersion)
|
|
vals := make([]*ethpb.Validator, 100)
|
|
balances := make([]uint64, 100)
|
|
for i := range vals {
|
|
balances[i] = params.BeaconConfig().MaxEffectiveBalance
|
|
val := ðpb.Validator{
|
|
WithdrawalCredentials: make([]byte, 32),
|
|
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
|
|
WithdrawableEpoch: primitives.Epoch(0),
|
|
}
|
|
val.WithdrawalCredentials[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
|
|
val.WithdrawalCredentials[31] = byte(i)
|
|
vals[i] = val
|
|
}
|
|
require.NoError(t, s.SetValidators(vals))
|
|
require.NoError(t, s.SetBalances(balances))
|
|
expected, _, err := s.ExpectedWithdrawals()
|
|
require.NoError(t, err)
|
|
require.Equal(t, params.BeaconConfig().MaxWithdrawalsPerPayload, uint64(len(expected)))
|
|
withdrawal := &enginev1.Withdrawal{
|
|
Index: 0,
|
|
ValidatorIndex: 0,
|
|
Address: vals[0].WithdrawalCredentials[12:],
|
|
Amount: params.BeaconConfig().MaxEffectiveBalance,
|
|
}
|
|
require.DeepEqual(t, withdrawal, expected[0])
|
|
})
|
|
t.Run("all fully and partially withdrawable", func(t *testing.T) {
|
|
s := state_native.EmptyStateFromVersion(t, stateVersion)
|
|
vals := make([]*ethpb.Validator, 100)
|
|
balances := make([]uint64, 100)
|
|
for i := range vals {
|
|
balances[i] = params.BeaconConfig().MaxEffectiveBalance + 1
|
|
val := ðpb.Validator{
|
|
WithdrawalCredentials: make([]byte, 32),
|
|
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
|
|
WithdrawableEpoch: primitives.Epoch(0),
|
|
}
|
|
val.WithdrawalCredentials[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
|
|
val.WithdrawalCredentials[31] = byte(i)
|
|
vals[i] = val
|
|
}
|
|
require.NoError(t, s.SetValidators(vals))
|
|
require.NoError(t, s.SetBalances(balances))
|
|
expected, _, err := s.ExpectedWithdrawals()
|
|
require.NoError(t, err)
|
|
require.Equal(t, params.BeaconConfig().MaxWithdrawalsPerPayload, uint64(len(expected)))
|
|
withdrawal := &enginev1.Withdrawal{
|
|
Index: 0,
|
|
ValidatorIndex: 0,
|
|
Address: vals[0].WithdrawalCredentials[12:],
|
|
Amount: params.BeaconConfig().MaxEffectiveBalance + 1,
|
|
}
|
|
require.DeepEqual(t, withdrawal, expected[0])
|
|
})
|
|
t.Run("one fully withdrawable but zero balance", func(t *testing.T) {
|
|
s := state_native.EmptyStateFromVersion(t, stateVersion)
|
|
require.NoError(t, s.SetNextWithdrawalValidatorIndex(20))
|
|
vals := make([]*ethpb.Validator, 100)
|
|
balances := make([]uint64, 100)
|
|
for i := range vals {
|
|
balances[i] = params.BeaconConfig().MaxEffectiveBalance
|
|
val := ðpb.Validator{
|
|
WithdrawalCredentials: make([]byte, 32),
|
|
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
|
|
WithdrawableEpoch: primitives.Epoch(1),
|
|
}
|
|
val.WithdrawalCredentials[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
|
|
val.WithdrawalCredentials[31] = byte(i)
|
|
vals[i] = val
|
|
}
|
|
vals[3].WithdrawableEpoch = primitives.Epoch(0)
|
|
balances[3] = 0
|
|
require.NoError(t, s.SetValidators(vals))
|
|
require.NoError(t, s.SetBalances(balances))
|
|
|
|
expected, _, err := s.ExpectedWithdrawals()
|
|
require.NoError(t, err)
|
|
require.Equal(t, 0, len(expected))
|
|
})
|
|
t.Run("one partially withdrawable, one above sweep bound", func(t *testing.T) {
|
|
s := state_native.EmptyStateFromVersion(t, stateVersion)
|
|
vals := make([]*ethpb.Validator, 100)
|
|
balances := make([]uint64, 100)
|
|
for i := range vals {
|
|
balances[i] = params.BeaconConfig().MaxEffectiveBalance
|
|
val := ðpb.Validator{
|
|
WithdrawalCredentials: make([]byte, 32),
|
|
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
|
|
WithdrawableEpoch: primitives.Epoch(1),
|
|
}
|
|
val.WithdrawalCredentials[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
|
|
val.WithdrawalCredentials[31] = byte(i)
|
|
vals[i] = val
|
|
}
|
|
balances[3] += params.BeaconConfig().MinDepositAmount
|
|
balances[10] += params.BeaconConfig().MinDepositAmount
|
|
require.NoError(t, s.SetValidators(vals))
|
|
require.NoError(t, s.SetBalances(balances))
|
|
saved := params.BeaconConfig().MaxValidatorsPerWithdrawalsSweep
|
|
params.BeaconConfig().MaxValidatorsPerWithdrawalsSweep = 10
|
|
expected, _, err := s.ExpectedWithdrawals()
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1, len(expected))
|
|
withdrawal := &enginev1.Withdrawal{
|
|
Index: 0,
|
|
ValidatorIndex: 3,
|
|
Address: vals[3].WithdrawalCredentials[12:],
|
|
Amount: params.BeaconConfig().MinDepositAmount,
|
|
}
|
|
require.DeepEqual(t, withdrawal, expected[0])
|
|
params.BeaconConfig().MaxValidatorsPerWithdrawalsSweep = saved
|
|
})
|
|
})
|
|
}
|
|
|
|
t.Run("electra all pending partial withdrawals", func(t *testing.T) {
|
|
// Load a serialized Electra state from disk.
|
|
// This spectest has a fully hydrated beacon state with partial pending withdrawals.
|
|
serializedBytes, err := util.BazelFileBytes("tests/mainnet/electra/operations/withdrawal_request/pyspec_tests/pending_withdrawals_consume_all_excess_balance/pre.ssz_snappy")
|
|
require.NoError(t, err)
|
|
serializedSSZ, err := snappy.Decode(nil /* dst */, serializedBytes)
|
|
require.NoError(t, err)
|
|
pb := ðpb.BeaconStateElectra{}
|
|
require.NoError(t, pb.UnmarshalSSZ(serializedSSZ))
|
|
s, err := state_native.InitializeFromProtoElectra(pb)
|
|
require.NoError(t, err)
|
|
expected, partialWithdrawalsCount, err := s.ExpectedWithdrawals()
|
|
require.NoError(t, err)
|
|
require.Equal(t, 8, len(expected))
|
|
require.Equal(t, uint64(8), partialWithdrawalsCount)
|
|
})
|
|
|
|
t.Run("electra some pending partial withdrawals", func(t *testing.T) {
|
|
// Load a serialized Electra state from disk.
|
|
// This spectest has a fully hydrated beacon state with partial pending withdrawals.
|
|
serializedBytes, err := util.BazelFileBytes("tests/mainnet/electra/operations/withdrawal_request/pyspec_tests/pending_withdrawals_consume_all_excess_balance/pre.ssz_snappy")
|
|
require.NoError(t, err)
|
|
serializedSSZ, err := snappy.Decode(nil /* dst */, serializedBytes)
|
|
require.NoError(t, err)
|
|
pb := ðpb.BeaconStateElectra{}
|
|
require.NoError(t, pb.UnmarshalSSZ(serializedSSZ))
|
|
s, err := state_native.InitializeFromProtoElectra(pb)
|
|
require.NoError(t, err)
|
|
p, err := s.PendingPartialWithdrawals()
|
|
require.NoError(t, err)
|
|
require.NoError(t, s.UpdateBalancesAtIndex(p[0].Index, 0)) // This should still count as partial withdrawal.
|
|
_, partialWithdrawalsCount, err := s.ExpectedWithdrawals()
|
|
require.NoError(t, err)
|
|
require.Equal(t, uint64(10), partialWithdrawalsCount)
|
|
})
|
|
t.Run("electra same validator has one partially and one fully withdrawable", func(t *testing.T) {
|
|
s, _ := util.DeterministicGenesisStateElectra(t, 1)
|
|
vals := make([]*ethpb.Validator, 100)
|
|
balances := make([]uint64, 100)
|
|
for i := range vals {
|
|
balances[i] = params.BeaconConfig().MaxEffectiveBalance
|
|
val := ðpb.Validator{
|
|
WithdrawalCredentials: make([]byte, 32),
|
|
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
|
|
WithdrawableEpoch: primitives.Epoch(1),
|
|
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
|
}
|
|
val.WithdrawalCredentials[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
|
|
val.WithdrawalCredentials[31] = byte(i)
|
|
vals[i] = val
|
|
}
|
|
balances[1] += params.BeaconConfig().MinDepositAmount
|
|
vals[1].WithdrawableEpoch = primitives.Epoch(0)
|
|
require.NoError(t, s.SetValidators(vals))
|
|
require.NoError(t, s.SetBalances(balances))
|
|
// Give validator a pending balance to withdraw.
|
|
require.NoError(t, s.AppendPendingPartialWithdrawal(ðpb.PendingPartialWithdrawal{
|
|
Index: 1,
|
|
Amount: balances[1], // will only deduct excess even though balance is more that minimum activation
|
|
WithdrawableEpoch: primitives.Epoch(0),
|
|
}))
|
|
p, err := s.PendingPartialWithdrawals()
|
|
require.NoError(t, err)
|
|
require.Equal(t, 1, len(p))
|
|
expected, _, err := s.ExpectedWithdrawals()
|
|
require.NoError(t, err)
|
|
require.Equal(t, 2, len(expected))
|
|
|
|
withdrawalFull := &enginev1.Withdrawal{
|
|
Index: 1,
|
|
ValidatorIndex: 1,
|
|
Address: vals[1].WithdrawalCredentials[12:],
|
|
Amount: balances[1] - params.BeaconConfig().MinDepositAmount, // subtract the partial from this
|
|
}
|
|
withdrawalPartial := &enginev1.Withdrawal{
|
|
Index: 0,
|
|
ValidatorIndex: 1,
|
|
Address: vals[1].WithdrawalCredentials[12:],
|
|
Amount: params.BeaconConfig().MinDepositAmount,
|
|
}
|
|
require.DeepEqual(t, withdrawalPartial, expected[0])
|
|
require.DeepEqual(t, withdrawalFull, expected[1])
|
|
})
|
|
}
|
|
|
|
func TestExpectedWithdrawals_underflow_electra(t *testing.T) {
|
|
s, err := state_native.InitializeFromProtoUnsafeElectra(ðpb.BeaconStateElectra{})
|
|
require.NoError(t, err)
|
|
vals := make([]*ethpb.Validator, 1)
|
|
balances := make([]uint64, 1)
|
|
balances[0] = 2015_000_000_000 //Validator A begins leaking ETH due to inactivity, and over time, its balance decreases to 2,015 ETH
|
|
val := ðpb.Validator{
|
|
WithdrawalCredentials: make([]byte, 32),
|
|
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalanceElectra,
|
|
WithdrawableEpoch: primitives.Epoch(0),
|
|
ExitEpoch: params.BeaconConfig().FarFutureEpoch,
|
|
}
|
|
val.WithdrawalCredentials[0] = params.BeaconConfig().CompoundingWithdrawalPrefixByte
|
|
val.WithdrawalCredentials[31] = byte(0)
|
|
vals[0] = val
|
|
|
|
require.NoError(t, s.SetValidators(vals))
|
|
require.NoError(t, s.SetBalances(balances))
|
|
require.NoError(t, s.AppendPendingPartialWithdrawal(ðpb.PendingPartialWithdrawal{
|
|
Amount: 1008_000_000_000,
|
|
WithdrawableEpoch: primitives.Epoch(0),
|
|
}))
|
|
require.NoError(t, s.AppendPendingPartialWithdrawal(ðpb.PendingPartialWithdrawal{
|
|
Amount: 1008_000_000_000,
|
|
WithdrawableEpoch: primitives.Epoch(0),
|
|
}))
|
|
expected, _, err := s.ExpectedWithdrawals()
|
|
require.NoError(t, err)
|
|
require.Equal(t, 3, len(expected)) // is a fully withdrawable validator
|
|
require.Equal(t, uint64(1008_000_000_000), expected[0].Amount)
|
|
require.Equal(t, uint64(975_000_000_000), expected[1].Amount)
|
|
require.Equal(t, uint64(32_000_000_000), expected[2].Amount)
|
|
}
|