prysm-pulse/beacon-chain/core/blocks/withdrawals.go
Potuz de73baa4a7
Update 3068 (#11656)
* rename last_withdrawal_validator_index

* Update Capella methods to Specs #3068

* Add missing renames

* rename minimal state

Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2022-11-12 18:38:21 +00:00

124 lines
4.6 KiB
Go

package blocks
import (
"bytes"
"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"
"github.com/prysmaticlabs/prysm/v3/config/params"
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
"github.com/prysmaticlabs/prysm/v3/crypto/hash/htr"
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
enginev1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v3/time/slots"
)
const executionToBLSPadding = 12
// ProcessBLSToExecutionChange validates a SignedBLSToExecution message and
// changes the validator's withdrawal address accordingly.
//
// Spec pseudocode definition:
//
//def process_bls_to_execution_change(state: BeaconState, signed_address_change: SignedBLSToExecutionChange) -> None:
// validator = state.validators[address_change.validator_index]
//
// assert validator.withdrawal_credentials[:1] == BLS_WITHDRAWAL_PREFIX
// assert validator.withdrawal_credentials[1:] == hash(address_change.from_bls_pubkey)[1:]
//
// domain = get_domain(state, DOMAIN_BLS_TO_EXECUTION_CHANGE)
// signing_root = compute_signing_root(address_change, domain)
// assert bls.Verify(address_change.from_bls_pubkey, signing_root, signed_address_change.signature)
//
// validator.withdrawal_credentials = (
// ETH1_ADDRESS_WITHDRAWAL_PREFIX
// + b'\x00' * 11
// + address_change.to_execution_address
// )
//
func ProcessBLSToExecutionChange(st state.BeaconState, signed *ethpb.SignedBLSToExecutionChange) (state.BeaconState, error) {
if signed == nil {
return st, errNilSignedWithdrawalMessage
}
message := signed.Message
if message == nil {
return st, errNilWithdrawalMessage
}
val, err := st.ValidatorAtIndex(message.ValidatorIndex)
if err != nil {
return nil, err
}
cred := val.WithdrawalCredentials
if cred[0] != params.BeaconConfig().BLSWithdrawalPrefixByte {
return nil, errInvalidBLSPrefix
}
// hash the public key and verify it matches the withdrawal credentials
fromPubkey := message.FromBlsPubkey
pubkeyChunks := [][32]byte{bytesutil.ToBytes32(fromPubkey[:32]), bytesutil.ToBytes32(fromPubkey[32:])}
digest := make([][32]byte, 1)
htr.VectorizedSha256(pubkeyChunks, digest)
if !bytes.Equal(digest[0][1:], cred[1:]) {
return nil, errInvalidWithdrawalCredentials
}
epoch := slots.ToEpoch(st.Slot())
domain, err := signing.Domain(st.Fork(), epoch, params.BeaconConfig().DomainBLSToExecutionChange, st.GenesisValidatorsRoot())
if err != nil {
return nil, err
}
if err := signing.VerifySigningRoot(message, fromPubkey, signed.Signature, domain); err != nil {
return nil, signing.ErrSigFailedToVerify
}
newCredentials := make([]byte, executionToBLSPadding)
newCredentials[0] = params.BeaconConfig().ETH1AddressWithdrawalPrefixByte
val.WithdrawalCredentials = append(newCredentials, message.ToExecutionAddress...)
err = st.UpdateValidatorAtIndex(message.ValidatorIndex, val)
return st, err
}
func ProcessWithdrawals(st state.BeaconState, withdrawals []*enginev1.Withdrawal) (state.BeaconState, error) {
expected, err := st.ExpectedWithdrawals()
if err != nil {
return nil, errors.Wrap(err, "could not get expected withdrawals")
}
if len(expected) != len(withdrawals) {
return nil, errInvalidWithdrawalNumber
}
for i, withdrawal := range withdrawals {
if withdrawal.WithdrawalIndex != expected[i].WithdrawalIndex {
return nil, errInvalidWithdrawalIndex
}
if withdrawal.ValidatorIndex != expected[i].ValidatorIndex {
return nil, errInvalidValidatorIndex
}
if !bytes.Equal(withdrawal.ExecutionAddress, expected[i].ExecutionAddress) {
return nil, errInvalidExecutionAddress
}
if withdrawal.Amount != expected[i].Amount {
return nil, errInvalidWithdrawalAmount
}
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].WithdrawalIndex + 1); err != nil {
return nil, errors.Wrap(err, "could not set next withdrawal index")
}
nextValidatorIndex := withdrawals[len(withdrawals)-1].ValidatorIndex + 1
if nextValidatorIndex == types.ValidatorIndex(st.NumValidators()) {
nextValidatorIndex = 0
}
if err := st.SetNextWithdrawalValidatorIndex(nextValidatorIndex); err != nil {
return nil, errors.Wrap(err, "could not set latest withdrawal validator index")
}
}
return st, nil
}