Add Withdrawal helpers (#11552)

* Add Withdrawal helpers

* Review

Co-authored-by: terencechain <terence@prysmaticlabs.com>
This commit is contained in:
Potuz
2022-10-12 08:44:41 -05:00
committed by GitHub
parent 974cf51a8c
commit ce7f042974
3 changed files with 103 additions and 0 deletions

View File

@@ -96,6 +96,9 @@ type ReadOnlyValidator interface {
ExitEpoch() types.Epoch
PublicKey() [fieldparams.BLSPubkeyLength]byte
WithdrawalCredentials() []byte
HasETH1WithdrawalCredential() bool
IsFullyWithdrawable(types.Epoch) bool
IsPartiallyWithdrawable(uint64) bool
Slashed() bool
IsNil() bool
}

View File

@@ -4,6 +4,7 @@ import (
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/state"
fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams"
"github.com/prysmaticlabs/prysm/v3/config/params"
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
)
@@ -78,6 +79,28 @@ func (v readOnlyValidator) WithdrawalCredentials() []byte {
return creds
}
// HasETH1WithdrawalCredential returns whether the validator has an ETH1
// Withdrawal prefix.
func (v readOnlyValidator) HasETH1WithdrawalCredential() bool {
cred := v.WithdrawalCredentials()
return len(cred) > 0 && cred[0] == params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
}
// IsFullyWithdrawable returns whether the validator is able to perform a full
// withdrawal. This differ from the spec helper in that the balance > 0 is not
// checked.
func (v readOnlyValidator) IsFullyWithdrawable(epoch types.Epoch) bool {
return v.HasETH1WithdrawalCredential() && v.WithdrawableEpoch() <= epoch
}
// IsPartiallyWithdrawable returns whether the validator is able to perform a
// partial withdrawal.
func (v readOnlyValidator) IsPartiallyWithdrawable(balance uint64) bool {
hasMaxBalance := v.EffectiveBalance() == params.BeaconConfig().MaxEffectiveBalance
hasExcessBalance := balance > params.BeaconConfig().MaxEffectiveBalance
return v.HasETH1WithdrawalCredential() && hasExcessBalance && hasMaxBalance
}
// Slashed returns the read only validator is slashed.
func (v readOnlyValidator) Slashed() bool {
return v.validator.Slashed

View File

@@ -5,6 +5,7 @@ import (
statenative "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"
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v3/testing/assert"
@@ -66,6 +67,82 @@ func TestReadOnlyValidator_WithdrawalCredentials(t *testing.T) {
assert.DeepEqual(t, creds, v.WithdrawalCredentials())
}
func TestReadOnlyValidator_HasETH1WithdrawalCredentials(t *testing.T) {
creds := []byte{0xFA, 0xCC}
v, err := statenative.NewValidator(&ethpb.Validator{WithdrawalCredentials: creds})
require.NoError(t, err)
require.Equal(t, false, v.HasETH1WithdrawalCredential())
creds = []byte{params.BeaconConfig().ETH1AddressWithdrawalPrefixByte, 0xCC}
v, err = statenative.NewValidator(&ethpb.Validator{WithdrawalCredentials: creds})
require.NoError(t, err)
require.Equal(t, true, v.HasETH1WithdrawalCredential())
// No Withdrawal cred
v, err = statenative.NewValidator(&ethpb.Validator{})
require.NoError(t, err)
require.Equal(t, false, v.HasETH1WithdrawalCredential())
}
func TestReadOnlyValidator_IsFullyWithdrawable(t *testing.T) {
// No ETH1 prefix
creds := []byte{0xFA, 0xCC}
v, err := statenative.NewValidator(&ethpb.Validator{
WithdrawalCredentials: creds,
WithdrawableEpoch: 2,
})
require.NoError(t, err)
require.Equal(t, false, v.IsFullyWithdrawable(3))
// Wrong withdrawable epoch
creds = []byte{params.BeaconConfig().ETH1AddressWithdrawalPrefixByte, 0xCC}
v, err = statenative.NewValidator(&ethpb.Validator{
WithdrawalCredentials: creds,
WithdrawableEpoch: 2,
})
require.NoError(t, err)
require.Equal(t, false, v.IsFullyWithdrawable(1))
// Fully withdrawable
creds = []byte{params.BeaconConfig().ETH1AddressWithdrawalPrefixByte, 0xCC}
v, err = statenative.NewValidator(&ethpb.Validator{
WithdrawalCredentials: creds,
WithdrawableEpoch: 2,
})
require.NoError(t, err)
require.Equal(t, true, v.IsFullyWithdrawable(3))
}
func TestReadOnlyValidator_IsPartiallyWithdrawable(t *testing.T) {
// No ETH1 prefix
creds := []byte{0xFA, 0xCC}
v, err := statenative.NewValidator(&ethpb.Validator{
WithdrawalCredentials: creds,
})
require.NoError(t, err)
require.Equal(t, false, v.IsPartiallyWithdrawable(params.BeaconConfig().MaxEffectiveBalance+1))
// Not the right effective balance
creds = []byte{params.BeaconConfig().ETH1AddressWithdrawalPrefixByte, 0xCC}
v, err = statenative.NewValidator(&ethpb.Validator{
WithdrawalCredentials: creds,
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance - 1,
})
require.NoError(t, err)
require.Equal(t, false, v.IsPartiallyWithdrawable(params.BeaconConfig().MaxEffectiveBalance+1))
// Not enough balance
creds = []byte{params.BeaconConfig().ETH1AddressWithdrawalPrefixByte, 0xCC}
v, err = statenative.NewValidator(&ethpb.Validator{
WithdrawalCredentials: creds,
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
})
require.NoError(t, err)
require.Equal(t, false, v.IsPartiallyWithdrawable(params.BeaconConfig().MaxEffectiveBalance))
// Partially Withdrawable
creds = []byte{params.BeaconConfig().ETH1AddressWithdrawalPrefixByte, 0xCC}
v, err = statenative.NewValidator(&ethpb.Validator{
WithdrawalCredentials: creds,
EffectiveBalance: params.BeaconConfig().MaxEffectiveBalance,
})
require.NoError(t, err)
require.Equal(t, true, v.IsPartiallyWithdrawable(params.BeaconConfig().MaxEffectiveBalance+1))
}
func TestReadOnlyValidator_Slashed(t *testing.T) {
v, err := statenative.NewValidator(&ethpb.Validator{Slashed: true})
require.NoError(t, err)