mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2024-12-22 03:30:35 +00:00
Process blind withdrawals (#11995)
* Update head before block proposal * fix e2e runs * Can process blind withdrwals * Rm bad change * Should be in process payload header * Version check * Compare roots * Typo * Remove redundant checks * Add tests * Rm errors --------- Co-authored-by: nisdas <nishdas93@gmail.com> Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
This commit is contained in:
parent
c7f0a94b19
commit
a6dd561b9d
@ -6,8 +6,3 @@ var errNilSignedWithdrawalMessage = errors.New("nil SignedBLSToExecutionChange m
|
||||
var errNilWithdrawalMessage = errors.New("nil BLSToExecutionChange message")
|
||||
var errInvalidBLSPrefix = errors.New("withdrawal credential prefix is not a BLS prefix")
|
||||
var errInvalidWithdrawalCredentials = errors.New("withdrawal credentials do not match")
|
||||
var errInvalidWithdrawalIndex = errors.New("invalid withdrawal index")
|
||||
var errInvalidValidatorIndex = errors.New("invalid validator index")
|
||||
var errInvalidWithdrawalAmount = errors.New("invalid withdrawal amount")
|
||||
var errInvalidExecutionAddress = errors.New("invalid execution address")
|
||||
var errInvalidWithdrawalNumber = errors.New("invalid number of withdrawals")
|
||||
|
@ -200,12 +200,9 @@ func ValidatePayload(st state.BeaconState, payload interfaces.ExecutionData) err
|
||||
// transactions_root=hash_tree_root(payload.transactions),
|
||||
// )
|
||||
func ProcessPayload(st state.BeaconState, payload interfaces.ExecutionData) (state.BeaconState, error) {
|
||||
var err error
|
||||
if st.Version() >= version.Capella {
|
||||
withdrawals, err := payload.Withdrawals()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get payload withdrawals")
|
||||
}
|
||||
st, err = ProcessWithdrawals(st, withdrawals)
|
||||
st, err = ProcessWithdrawals(st, payload)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not process withdrawals")
|
||||
}
|
||||
@ -267,6 +264,13 @@ func ValidatePayloadHeader(st state.BeaconState, header interfaces.ExecutionData
|
||||
|
||||
// ProcessPayloadHeader processes the payload header.
|
||||
func ProcessPayloadHeader(st state.BeaconState, header interfaces.ExecutionData) (state.BeaconState, error) {
|
||||
var err error
|
||||
if st.Version() >= version.Capella {
|
||||
st, err = ProcessWithdrawals(st, header)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not process withdrawals")
|
||||
}
|
||||
}
|
||||
if err := ValidatePayloadHeaderWhenMergeCompletes(st, header); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@ -2,18 +2,20 @@ package blocks
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/signing"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||
"github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces"
|
||||
"github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||
"github.com/prysmaticlabs/prysm/v3/crypto/bls"
|
||||
"github.com/prysmaticlabs/prysm/v3/crypto/hash"
|
||||
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/v3/encoding/ssz"
|
||||
enginev1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
|
||||
ethpbv2 "github.com/prysmaticlabs/prysm/v3/proto/eth/v2"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v3/runtime/version"
|
||||
@ -110,39 +112,51 @@ func ValidateBLSToExecutionChange(st state.ReadOnlyBeaconState, signed *ethpb.Si
|
||||
return val, nil
|
||||
}
|
||||
|
||||
func ProcessWithdrawals(st state.BeaconState, withdrawals []*enginev1.Withdrawal) (state.BeaconState, error) {
|
||||
expected, err := st.ExpectedWithdrawals()
|
||||
func ProcessWithdrawals(st state.BeaconState, executionData interfaces.ExecutionData) (state.BeaconState, error) {
|
||||
expectedWithdrawals, err := st.ExpectedWithdrawals()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get expected withdrawals")
|
||||
}
|
||||
if len(expected) != len(withdrawals) {
|
||||
return nil, errInvalidWithdrawalNumber
|
||||
|
||||
var wdRoot [32]byte
|
||||
if executionData.IsBlinded() {
|
||||
r, err := executionData.WithdrawalsRoot()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get withdrawals root")
|
||||
}
|
||||
wdRoot = bytesutil.ToBytes32(r)
|
||||
} else {
|
||||
wds, err := executionData.Withdrawals()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get withdrawals")
|
||||
}
|
||||
wdRoot, err = ssz.WithdrawalSliceRoot(hash.CustomSHA256Hasher(), wds, fieldparams.MaxWithdrawalsPerPayload)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get withdrawals root")
|
||||
}
|
||||
}
|
||||
for i, withdrawal := range withdrawals {
|
||||
if withdrawal.Index != expected[i].Index {
|
||||
return nil, errInvalidWithdrawalIndex
|
||||
}
|
||||
if withdrawal.ValidatorIndex != expected[i].ValidatorIndex {
|
||||
return nil, errInvalidValidatorIndex
|
||||
}
|
||||
if !bytes.Equal(withdrawal.Address, expected[i].Address) {
|
||||
return nil, errInvalidExecutionAddress
|
||||
}
|
||||
if withdrawal.Amount != expected[i].Amount {
|
||||
return nil, errInvalidWithdrawalAmount
|
||||
}
|
||||
|
||||
expectedRoot, err := ssz.WithdrawalSliceRoot(hash.CustomSHA256Hasher(), expectedWithdrawals, fieldparams.MaxWithdrawalsPerPayload)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get expected withdrawals root")
|
||||
}
|
||||
if expectedRoot != wdRoot {
|
||||
return nil, fmt.Errorf("expected withdrawals root %#x, got %#x", expectedRoot, wdRoot)
|
||||
}
|
||||
|
||||
for _, withdrawal := range expectedWithdrawals {
|
||||
err := helpers.DecreaseBalance(st, withdrawal.ValidatorIndex, withdrawal.Amount)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not decrease balance")
|
||||
}
|
||||
}
|
||||
if len(withdrawals) > 0 {
|
||||
if err := st.SetNextWithdrawalIndex(withdrawals[len(withdrawals)-1].Index + 1); err != nil {
|
||||
if len(expectedWithdrawals) > 0 {
|
||||
if err := st.SetNextWithdrawalIndex(expectedWithdrawals[len(expectedWithdrawals)-1].Index + 1); err != nil {
|
||||
return nil, errors.Wrap(err, "could not set next withdrawal index")
|
||||
}
|
||||
}
|
||||
var nextValidatorIndex primitives.ValidatorIndex
|
||||
if uint64(len(withdrawals)) < params.BeaconConfig().MaxWithdrawalsPerPayload {
|
||||
if uint64(len(expectedWithdrawals)) < params.BeaconConfig().MaxWithdrawalsPerPayload {
|
||||
nextValidatorIndex, err = st.NextWithdrawalValidatorIndex()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get next withdrawal validator index")
|
||||
@ -150,7 +164,7 @@ func ProcessWithdrawals(st state.BeaconState, withdrawals []*enginev1.Withdrawal
|
||||
nextValidatorIndex += primitives.ValidatorIndex(params.BeaconConfig().MaxValidatorsPerWithdrawalsSweep)
|
||||
nextValidatorIndex = nextValidatorIndex % primitives.ValidatorIndex(st.NumValidators())
|
||||
} else {
|
||||
nextValidatorIndex = withdrawals[len(withdrawals)-1].ValidatorIndex + 1
|
||||
nextValidatorIndex = expectedWithdrawals[len(expectedWithdrawals)-1].ValidatorIndex + 1
|
||||
if nextValidatorIndex == primitives.ValidatorIndex(st.NumValidators()) {
|
||||
nextValidatorIndex = 0
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package blocks_test
|
||||
|
||||
import (
|
||||
"math/big"
|
||||
"math/rand"
|
||||
"testing"
|
||||
|
||||
@ -9,6 +10,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/time"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state"
|
||||
state_native "github.com/prysmaticlabs/prysm/v3/beacon-chain/state/state-native"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||
consensusblocks "github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||
@ -236,6 +238,425 @@ func TestProcessBLSToExecutionChange(t *testing.T) {
|
||||
|
||||
})
|
||||
}
|
||||
func TestProcessBlindWithdrawals(t *testing.T) {
|
||||
const (
|
||||
currentEpoch = primitives.Epoch(10)
|
||||
epochInFuture = primitives.Epoch(12)
|
||||
epochInPast = primitives.Epoch(8)
|
||||
numValidators = 128
|
||||
notWithdrawableIndex = 127
|
||||
notPartiallyWithdrawable = 126
|
||||
maxSweep = uint64(80)
|
||||
)
|
||||
maxEffectiveBalance := params.BeaconConfig().MaxEffectiveBalance
|
||||
|
||||
type args struct {
|
||||
Name string
|
||||
NextWithdrawalValidatorIndex primitives.ValidatorIndex
|
||||
NextWithdrawalIndex uint64
|
||||
FullWithdrawalIndices []primitives.ValidatorIndex
|
||||
PartialWithdrawalIndices []primitives.ValidatorIndex
|
||||
Withdrawals []*enginev1.Withdrawal
|
||||
}
|
||||
type control struct {
|
||||
NextWithdrawalValidatorIndex primitives.ValidatorIndex
|
||||
NextWithdrawalIndex uint64
|
||||
ExpectedError bool
|
||||
Balances map[uint64]uint64
|
||||
}
|
||||
type Test struct {
|
||||
Args args
|
||||
Control control
|
||||
}
|
||||
executionAddress := func(i primitives.ValidatorIndex) []byte {
|
||||
wc := make([]byte, 20)
|
||||
wc[19] = byte(i)
|
||||
return wc
|
||||
}
|
||||
withdrawalAmount := func(i primitives.ValidatorIndex) uint64 {
|
||||
return maxEffectiveBalance + uint64(i)*100000
|
||||
}
|
||||
fullWithdrawal := func(i primitives.ValidatorIndex, idx uint64) *enginev1.Withdrawal {
|
||||
return &enginev1.Withdrawal{
|
||||
Index: idx,
|
||||
ValidatorIndex: i,
|
||||
Address: executionAddress(i),
|
||||
Amount: withdrawalAmount(i),
|
||||
}
|
||||
}
|
||||
partialWithdrawal := func(i primitives.ValidatorIndex, idx uint64) *enginev1.Withdrawal {
|
||||
return &enginev1.Withdrawal{
|
||||
Index: idx,
|
||||
ValidatorIndex: i,
|
||||
Address: executionAddress(i),
|
||||
Amount: withdrawalAmount(i) - maxEffectiveBalance,
|
||||
}
|
||||
}
|
||||
tests := []Test{
|
||||
{
|
||||
Args: args{
|
||||
Name: "success no withdrawals",
|
||||
NextWithdrawalValidatorIndex: 10,
|
||||
NextWithdrawalIndex: 3,
|
||||
},
|
||||
Control: control{
|
||||
NextWithdrawalValidatorIndex: 90,
|
||||
NextWithdrawalIndex: 3,
|
||||
},
|
||||
},
|
||||
{
|
||||
Args: args{
|
||||
Name: "success one full withdrawal",
|
||||
NextWithdrawalIndex: 3,
|
||||
NextWithdrawalValidatorIndex: 5,
|
||||
FullWithdrawalIndices: []primitives.ValidatorIndex{70},
|
||||
Withdrawals: []*enginev1.Withdrawal{
|
||||
fullWithdrawal(70, 3),
|
||||
},
|
||||
},
|
||||
Control: control{
|
||||
NextWithdrawalValidatorIndex: 85,
|
||||
NextWithdrawalIndex: 4,
|
||||
Balances: map[uint64]uint64{70: 0},
|
||||
},
|
||||
},
|
||||
{
|
||||
Args: args{
|
||||
Name: "success one partial withdrawal",
|
||||
NextWithdrawalIndex: 21,
|
||||
NextWithdrawalValidatorIndex: 120,
|
||||
PartialWithdrawalIndices: []primitives.ValidatorIndex{7},
|
||||
Withdrawals: []*enginev1.Withdrawal{
|
||||
partialWithdrawal(7, 21),
|
||||
},
|
||||
},
|
||||
Control: control{
|
||||
NextWithdrawalValidatorIndex: 72,
|
||||
NextWithdrawalIndex: 22,
|
||||
Balances: map[uint64]uint64{7: maxEffectiveBalance},
|
||||
},
|
||||
},
|
||||
{
|
||||
Args: args{
|
||||
Name: "success many full withdrawals",
|
||||
NextWithdrawalIndex: 22,
|
||||
NextWithdrawalValidatorIndex: 4,
|
||||
FullWithdrawalIndices: []primitives.ValidatorIndex{7, 19, 28, 1},
|
||||
Withdrawals: []*enginev1.Withdrawal{
|
||||
fullWithdrawal(7, 22), fullWithdrawal(19, 23), fullWithdrawal(28, 24),
|
||||
},
|
||||
},
|
||||
Control: control{
|
||||
NextWithdrawalValidatorIndex: 84,
|
||||
NextWithdrawalIndex: 25,
|
||||
Balances: map[uint64]uint64{7: 0, 19: 0, 28: 0},
|
||||
},
|
||||
},
|
||||
{
|
||||
Args: args{
|
||||
Name: "Less than max sweep at end",
|
||||
NextWithdrawalIndex: 22,
|
||||
NextWithdrawalValidatorIndex: 4,
|
||||
FullWithdrawalIndices: []primitives.ValidatorIndex{80, 81, 82, 83},
|
||||
Withdrawals: []*enginev1.Withdrawal{
|
||||
fullWithdrawal(80, 22), fullWithdrawal(81, 23), fullWithdrawal(82, 24),
|
||||
fullWithdrawal(83, 25),
|
||||
},
|
||||
},
|
||||
Control: control{
|
||||
NextWithdrawalValidatorIndex: 84,
|
||||
NextWithdrawalIndex: 26,
|
||||
Balances: map[uint64]uint64{80: 0, 81: 0, 82: 0, 83: 0},
|
||||
},
|
||||
},
|
||||
{
|
||||
Args: args{
|
||||
Name: "Less than max sweep and beginning",
|
||||
NextWithdrawalIndex: 22,
|
||||
NextWithdrawalValidatorIndex: 4,
|
||||
FullWithdrawalIndices: []primitives.ValidatorIndex{4, 5, 6},
|
||||
Withdrawals: []*enginev1.Withdrawal{
|
||||
fullWithdrawal(4, 22), fullWithdrawal(5, 23), fullWithdrawal(6, 24),
|
||||
},
|
||||
},
|
||||
Control: control{
|
||||
NextWithdrawalValidatorIndex: 84,
|
||||
NextWithdrawalIndex: 25,
|
||||
Balances: map[uint64]uint64{4: 0, 5: 0, 6: 0},
|
||||
},
|
||||
},
|
||||
{
|
||||
Args: args{
|
||||
Name: "success many partial withdrawals",
|
||||
NextWithdrawalIndex: 22,
|
||||
NextWithdrawalValidatorIndex: 4,
|
||||
PartialWithdrawalIndices: []primitives.ValidatorIndex{7, 19, 28},
|
||||
Withdrawals: []*enginev1.Withdrawal{
|
||||
partialWithdrawal(7, 22), partialWithdrawal(19, 23), partialWithdrawal(28, 24),
|
||||
},
|
||||
},
|
||||
Control: control{
|
||||
NextWithdrawalValidatorIndex: 84,
|
||||
NextWithdrawalIndex: 25,
|
||||
Balances: map[uint64]uint64{
|
||||
7: maxEffectiveBalance,
|
||||
19: maxEffectiveBalance,
|
||||
28: maxEffectiveBalance,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Args: args{
|
||||
Name: "success many withdrawals",
|
||||
NextWithdrawalIndex: 22,
|
||||
NextWithdrawalValidatorIndex: 88,
|
||||
FullWithdrawalIndices: []primitives.ValidatorIndex{7, 19, 28},
|
||||
PartialWithdrawalIndices: []primitives.ValidatorIndex{2, 1, 89, 15},
|
||||
Withdrawals: []*enginev1.Withdrawal{
|
||||
partialWithdrawal(89, 22), partialWithdrawal(1, 23), partialWithdrawal(2, 24),
|
||||
fullWithdrawal(7, 25), partialWithdrawal(15, 26), fullWithdrawal(19, 27),
|
||||
fullWithdrawal(28, 28),
|
||||
},
|
||||
},
|
||||
Control: control{
|
||||
NextWithdrawalValidatorIndex: 40,
|
||||
NextWithdrawalIndex: 29,
|
||||
Balances: map[uint64]uint64{
|
||||
7: 0, 19: 0, 28: 0,
|
||||
2: maxEffectiveBalance, 1: maxEffectiveBalance, 89: maxEffectiveBalance,
|
||||
15: maxEffectiveBalance,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Args: args{
|
||||
Name: "success more than max fully withdrawals",
|
||||
NextWithdrawalIndex: 22,
|
||||
NextWithdrawalValidatorIndex: 0,
|
||||
FullWithdrawalIndices: []primitives.ValidatorIndex{1, 2, 3, 4, 5, 6, 7, 8, 9, 21, 22, 23, 24, 25, 26, 27, 29, 35, 89},
|
||||
Withdrawals: []*enginev1.Withdrawal{
|
||||
fullWithdrawal(1, 22), fullWithdrawal(2, 23), fullWithdrawal(3, 24),
|
||||
fullWithdrawal(4, 25), fullWithdrawal(5, 26), fullWithdrawal(6, 27),
|
||||
fullWithdrawal(7, 28), fullWithdrawal(8, 29), fullWithdrawal(9, 30),
|
||||
fullWithdrawal(21, 31), fullWithdrawal(22, 32), fullWithdrawal(23, 33),
|
||||
fullWithdrawal(24, 34), fullWithdrawal(25, 35), fullWithdrawal(26, 36),
|
||||
fullWithdrawal(27, 37),
|
||||
},
|
||||
},
|
||||
Control: control{
|
||||
NextWithdrawalValidatorIndex: 28,
|
||||
NextWithdrawalIndex: 38,
|
||||
Balances: map[uint64]uint64{
|
||||
1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0, 7: 0, 8: 0, 9: 0,
|
||||
21: 0, 22: 0, 23: 0, 24: 0, 25: 0, 26: 0, 27: 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Args: args{
|
||||
Name: "success more than max partially withdrawals",
|
||||
NextWithdrawalIndex: 22,
|
||||
NextWithdrawalValidatorIndex: 0,
|
||||
PartialWithdrawalIndices: []primitives.ValidatorIndex{1, 2, 3, 4, 5, 6, 7, 8, 9, 21, 22, 23, 24, 25, 26, 27, 29, 35, 89},
|
||||
Withdrawals: []*enginev1.Withdrawal{
|
||||
partialWithdrawal(1, 22), partialWithdrawal(2, 23), partialWithdrawal(3, 24),
|
||||
partialWithdrawal(4, 25), partialWithdrawal(5, 26), partialWithdrawal(6, 27),
|
||||
partialWithdrawal(7, 28), partialWithdrawal(8, 29), partialWithdrawal(9, 30),
|
||||
partialWithdrawal(21, 31), partialWithdrawal(22, 32), partialWithdrawal(23, 33),
|
||||
partialWithdrawal(24, 34), partialWithdrawal(25, 35), partialWithdrawal(26, 36),
|
||||
partialWithdrawal(27, 37),
|
||||
},
|
||||
},
|
||||
Control: control{
|
||||
NextWithdrawalValidatorIndex: 28,
|
||||
NextWithdrawalIndex: 38,
|
||||
Balances: map[uint64]uint64{
|
||||
1: maxEffectiveBalance,
|
||||
2: maxEffectiveBalance,
|
||||
3: maxEffectiveBalance,
|
||||
4: maxEffectiveBalance,
|
||||
5: maxEffectiveBalance,
|
||||
6: maxEffectiveBalance,
|
||||
7: maxEffectiveBalance,
|
||||
8: maxEffectiveBalance,
|
||||
9: maxEffectiveBalance,
|
||||
21: maxEffectiveBalance,
|
||||
22: maxEffectiveBalance,
|
||||
23: maxEffectiveBalance,
|
||||
24: maxEffectiveBalance,
|
||||
25: maxEffectiveBalance,
|
||||
26: maxEffectiveBalance,
|
||||
27: maxEffectiveBalance,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Args: args{
|
||||
Name: "failure wrong number of partial withdrawal",
|
||||
NextWithdrawalIndex: 21,
|
||||
NextWithdrawalValidatorIndex: 37,
|
||||
PartialWithdrawalIndices: []primitives.ValidatorIndex{7},
|
||||
Withdrawals: []*enginev1.Withdrawal{
|
||||
partialWithdrawal(7, 21), partialWithdrawal(9, 22),
|
||||
},
|
||||
},
|
||||
Control: control{
|
||||
ExpectedError: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
Args: args{
|
||||
Name: "failure invalid withdrawal index",
|
||||
NextWithdrawalIndex: 22,
|
||||
NextWithdrawalValidatorIndex: 4,
|
||||
FullWithdrawalIndices: []primitives.ValidatorIndex{7, 19, 28, 1},
|
||||
Withdrawals: []*enginev1.Withdrawal{
|
||||
fullWithdrawal(7, 22), fullWithdrawal(19, 23), fullWithdrawal(28, 25),
|
||||
fullWithdrawal(1, 25),
|
||||
},
|
||||
},
|
||||
Control: control{
|
||||
ExpectedError: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
Args: args{
|
||||
Name: "failure invalid validator index",
|
||||
NextWithdrawalIndex: 22,
|
||||
NextWithdrawalValidatorIndex: 4,
|
||||
FullWithdrawalIndices: []primitives.ValidatorIndex{7, 19, 28, 1},
|
||||
Withdrawals: []*enginev1.Withdrawal{
|
||||
fullWithdrawal(7, 22), fullWithdrawal(19, 23), fullWithdrawal(27, 24),
|
||||
fullWithdrawal(1, 25),
|
||||
},
|
||||
},
|
||||
Control: control{
|
||||
ExpectedError: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
Args: args{
|
||||
Name: "failure invalid withdrawal amount",
|
||||
NextWithdrawalIndex: 22,
|
||||
NextWithdrawalValidatorIndex: 4,
|
||||
FullWithdrawalIndices: []primitives.ValidatorIndex{7, 19, 28, 1},
|
||||
Withdrawals: []*enginev1.Withdrawal{
|
||||
fullWithdrawal(7, 22), fullWithdrawal(19, 23), partialWithdrawal(28, 24),
|
||||
fullWithdrawal(1, 25),
|
||||
},
|
||||
},
|
||||
Control: control{
|
||||
ExpectedError: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
Args: args{
|
||||
Name: "failure validator not fully withdrawable",
|
||||
NextWithdrawalIndex: 22,
|
||||
NextWithdrawalValidatorIndex: 4,
|
||||
FullWithdrawalIndices: []primitives.ValidatorIndex{notWithdrawableIndex},
|
||||
Withdrawals: []*enginev1.Withdrawal{
|
||||
fullWithdrawal(notWithdrawableIndex, 22),
|
||||
},
|
||||
},
|
||||
Control: control{
|
||||
ExpectedError: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
Args: args{
|
||||
Name: "failure validator not partially withdrawable",
|
||||
NextWithdrawalIndex: 22,
|
||||
NextWithdrawalValidatorIndex: 4,
|
||||
PartialWithdrawalIndices: []primitives.ValidatorIndex{notPartiallyWithdrawable},
|
||||
Withdrawals: []*enginev1.Withdrawal{
|
||||
fullWithdrawal(notPartiallyWithdrawable, 22),
|
||||
},
|
||||
},
|
||||
Control: control{
|
||||
ExpectedError: true,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
checkPostState := func(t *testing.T, expected control, st state.BeaconState) {
|
||||
l, err := st.NextWithdrawalValidatorIndex()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, expected.NextWithdrawalValidatorIndex, l)
|
||||
|
||||
n, err := st.NextWithdrawalIndex()
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, expected.NextWithdrawalIndex, n)
|
||||
balances := st.Balances()
|
||||
for idx, bal := range expected.Balances {
|
||||
require.Equal(t, bal, balances[idx])
|
||||
}
|
||||
}
|
||||
|
||||
prepareValidators := func(st *ethpb.BeaconStateCapella, arguments args) (state.BeaconState, error) {
|
||||
validators := make([]*ethpb.Validator, numValidators)
|
||||
st.Balances = make([]uint64, numValidators)
|
||||
for i := range validators {
|
||||
v := ðpb.Validator{}
|
||||
v.EffectiveBalance = maxEffectiveBalance
|
||||
v.WithdrawableEpoch = epochInFuture
|
||||
v.WithdrawalCredentials = make([]byte, 32)
|
||||
v.WithdrawalCredentials[31] = byte(i)
|
||||
st.Balances[i] = v.EffectiveBalance - uint64(rand.Intn(1000))
|
||||
validators[i] = v
|
||||
}
|
||||
for _, idx := range arguments.FullWithdrawalIndices {
|
||||
if idx != notWithdrawableIndex {
|
||||
validators[idx].WithdrawableEpoch = epochInPast
|
||||
}
|
||||
st.Balances[idx] = withdrawalAmount(idx)
|
||||
validators[idx].WithdrawalCredentials[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
|
||||
}
|
||||
for _, idx := range arguments.PartialWithdrawalIndices {
|
||||
validators[idx].WithdrawalCredentials[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
|
||||
st.Balances[idx] = withdrawalAmount(idx)
|
||||
}
|
||||
st.Validators = validators
|
||||
return state_native.InitializeFromProtoCapella(st)
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.Args.Name, func(t *testing.T) {
|
||||
saved := params.BeaconConfig().MaxValidatorsPerWithdrawalsSweep
|
||||
params.BeaconConfig().MaxValidatorsPerWithdrawalsSweep = maxSweep
|
||||
if test.Args.Withdrawals == nil {
|
||||
test.Args.Withdrawals = make([]*enginev1.Withdrawal, 0)
|
||||
}
|
||||
if test.Args.FullWithdrawalIndices == nil {
|
||||
test.Args.FullWithdrawalIndices = make([]primitives.ValidatorIndex, 0)
|
||||
}
|
||||
if test.Args.PartialWithdrawalIndices == nil {
|
||||
test.Args.PartialWithdrawalIndices = make([]primitives.ValidatorIndex, 0)
|
||||
}
|
||||
slot, err := slots.EpochStart(currentEpoch)
|
||||
require.NoError(t, err)
|
||||
spb := ðpb.BeaconStateCapella{
|
||||
Slot: slot,
|
||||
NextWithdrawalValidatorIndex: test.Args.NextWithdrawalValidatorIndex,
|
||||
NextWithdrawalIndex: test.Args.NextWithdrawalIndex,
|
||||
}
|
||||
st, err := prepareValidators(spb, test.Args)
|
||||
require.NoError(t, err)
|
||||
wdRoot, err := ssz.WithdrawalSliceRoot(hash.CustomSHA256Hasher(), test.Args.Withdrawals, fieldparams.MaxWithdrawalsPerPayload)
|
||||
require.NoError(t, err)
|
||||
p, err := consensusblocks.WrappedExecutionPayloadHeaderCapella(&enginev1.ExecutionPayloadHeaderCapella{WithdrawalsRoot: wdRoot[:]}, big.NewInt(0))
|
||||
require.NoError(t, err)
|
||||
post, err := blocks.ProcessWithdrawals(st, p)
|
||||
if test.Control.ExpectedError {
|
||||
require.NotNil(t, err)
|
||||
} else {
|
||||
require.NoError(t, err)
|
||||
checkPostState(t, test.Control, post)
|
||||
}
|
||||
params.BeaconConfig().MaxValidatorsPerWithdrawalsSweep = saved
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestProcessWithdrawals(t *testing.T) {
|
||||
const (
|
||||
@ -641,7 +1062,9 @@ func TestProcessWithdrawals(t *testing.T) {
|
||||
}
|
||||
st, err := prepareValidators(spb, test.Args)
|
||||
require.NoError(t, err)
|
||||
post, err := blocks.ProcessWithdrawals(st, test.Args.Withdrawals)
|
||||
p, err := consensusblocks.WrappedExecutionPayloadCapella(&enginev1.ExecutionPayloadCapella{Withdrawals: test.Args.Withdrawals}, big.NewInt(0))
|
||||
require.NoError(t, err)
|
||||
post, err := blocks.ProcessWithdrawals(st, p)
|
||||
if test.Control.ExpectedError {
|
||||
require.NotNil(t, err)
|
||||
} else {
|
||||
|
@ -2694,6 +2694,10 @@ func TestProduceBlindedBlock(t *testing.T) {
|
||||
require.NoError(t, beaconState.SetGenesisTime(uint64(ti.Unix())))
|
||||
random, err := helpers.RandaoMix(beaconState, coreTime.CurrentEpoch(beaconState))
|
||||
require.NoError(t, err)
|
||||
wds, err := beaconState.ExpectedWithdrawals()
|
||||
require.NoError(t, err)
|
||||
wr, err := ssz.WithdrawalSliceRoot(hash.CustomSHA256Hasher(), wds, fieldparams.MaxWithdrawalsPerPayload)
|
||||
require.NoError(t, err)
|
||||
bid := ðpbalpha.BuilderBidCapella{
|
||||
Header: &enginev1.ExecutionPayloadHeaderCapella{
|
||||
ParentHash: make([]byte, fieldparams.RootLength),
|
||||
@ -2707,7 +2711,7 @@ func TestProduceBlindedBlock(t *testing.T) {
|
||||
TransactionsRoot: make([]byte, fieldparams.RootLength),
|
||||
BlockNumber: 1,
|
||||
Timestamp: uint64(ts.Unix()),
|
||||
WithdrawalsRoot: make([]byte, fieldparams.RootLength),
|
||||
WithdrawalsRoot: wr[:],
|
||||
},
|
||||
Pubkey: sk.PublicKey().Marshal(),
|
||||
Value: bytesutil.PadTo([]byte{1, 2, 3}, 32),
|
||||
|
@ -62,7 +62,6 @@ func E2EMainnetTestConfig() *BeaconChainConfig {
|
||||
e2eConfig.MinGenesisActiveValidatorCount = 256
|
||||
e2eConfig.GenesisDelay = 25 // 25 seconds so E2E has enough time to process deposits and get started.
|
||||
e2eConfig.ChurnLimitQuotient = 65536
|
||||
e2eConfig.MaxValidatorsPerWithdrawalsSweep = 128
|
||||
|
||||
// Time parameters.
|
||||
e2eConfig.SecondsPerSlot = 6
|
||||
|
@ -36,6 +36,11 @@ func (e executionPayload) IsNil() bool {
|
||||
return e.p == nil
|
||||
}
|
||||
|
||||
// IsBlinded returns true if the underlying data is blinded.
|
||||
func (e executionPayload) IsBlinded() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// MarshalSSZ --
|
||||
func (e executionPayload) MarshalSSZ() ([]byte, error) {
|
||||
return e.p.MarshalSSZ()
|
||||
@ -192,6 +197,11 @@ func (e executionPayloadHeader) IsNil() bool {
|
||||
return e.p == nil
|
||||
}
|
||||
|
||||
// IsBlinded returns true if the underlying data is a header.
|
||||
func (e executionPayloadHeader) IsBlinded() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// MarshalSSZ --
|
||||
func (e executionPayloadHeader) MarshalSSZ() ([]byte, error) {
|
||||
return e.p.MarshalSSZ()
|
||||
@ -377,6 +387,11 @@ func (e executionPayloadCapella) IsNil() bool {
|
||||
return e.p == nil
|
||||
}
|
||||
|
||||
// IsBlinded returns true if the underlying data is blinded.
|
||||
func (e executionPayloadCapella) IsBlinded() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// MarshalSSZ --
|
||||
func (e executionPayloadCapella) MarshalSSZ() ([]byte, error) {
|
||||
return e.p.MarshalSSZ()
|
||||
@ -534,6 +549,11 @@ func (e executionPayloadHeaderCapella) IsNil() bool {
|
||||
return e.p == nil
|
||||
}
|
||||
|
||||
// IsBlinded returns true if the underlying data is blinded.
|
||||
func (e executionPayloadHeaderCapella) IsBlinded() bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// MarshalSSZ --
|
||||
func (e executionPayloadHeaderCapella) MarshalSSZ() ([]byte, error) {
|
||||
return e.p.MarshalSSZ()
|
||||
|
@ -102,6 +102,7 @@ type ExecutionData interface {
|
||||
ssz.Unmarshaler
|
||||
ssz.HashRoot
|
||||
IsNil() bool
|
||||
IsBlinded() bool
|
||||
Proto() proto.Message
|
||||
ParentHash() []byte
|
||||
FeeRecipient() []byte
|
||||
|
@ -611,6 +611,11 @@ func submitWithdrawal(ec *e2etypes.EvaluationContext, conns ...*grpc.ClientConn)
|
||||
}
|
||||
|
||||
func validatorsAreWithdrawn(ec *e2etypes.EvaluationContext, conns ...*grpc.ClientConn) error {
|
||||
// We skip this for multiclient runs as lighthouse does not have the ability
|
||||
// to configure the withdrawal sweep for the end to end test.
|
||||
if e2e.TestParams.LighthouseBeaconNodeCount > 0 {
|
||||
return nil
|
||||
}
|
||||
conn := conns[0]
|
||||
beaconClient := ethpb.NewBeaconChainClient(conn)
|
||||
debugClient := ethpb.NewDebugClient(conn)
|
||||
@ -642,7 +647,9 @@ func validatorsAreWithdrawn(ec *e2etypes.EvaluationContext, conns ...*grpc.Clien
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if bal != 0 {
|
||||
// Only return an error if the validator has more than 1 eth
|
||||
// in its balance.
|
||||
if bal > 1*params.BeaconConfig().GweiPerEth {
|
||||
return errors.Errorf("Validator index %d with key %#x hasn't withdrawn. Their balance is %d.", valIdx, key, bal)
|
||||
}
|
||||
|
||||
|
@ -2,12 +2,14 @@ package operations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"math/big"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/snappy"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state"
|
||||
consensusblocks "github.com/prysmaticlabs/prysm/v3/consensus-types/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v3/consensus-types/interfaces"
|
||||
enginev1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||
@ -42,7 +44,9 @@ func RunWithdrawalsTest(t *testing.T, config string) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return blocks.ProcessWithdrawals(s, withdrawals)
|
||||
p, err := consensusblocks.WrappedExecutionPayloadCapella(&enginev1.ExecutionPayloadCapella{Withdrawals: withdrawals}, big.NewInt(0))
|
||||
require.NoError(t, err)
|
||||
return blocks.ProcessWithdrawals(s, p)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user