mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-10 13:58:09 -05:00
Compare commits
4 Commits
peerdas-ge
...
eip-7251
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c5ad54fe31 | ||
|
|
452f6c3460 | ||
|
|
a0d5882315 | ||
|
|
345a1f6e7f |
@@ -28,6 +28,7 @@ type MockBuilderService struct {
|
||||
Payload *v1.ExecutionPayload
|
||||
PayloadCapella *v1.ExecutionPayloadCapella
|
||||
PayloadDeneb *v1.ExecutionPayloadDeneb
|
||||
PayloadElectra *v1.ExecutionPayloadElectra
|
||||
BlobBundle *v1.BlobsBundle
|
||||
ErrSubmitBlindedBlock error
|
||||
Bid *ethpb.SignedBuilderBid
|
||||
@@ -65,6 +66,12 @@ func (s *MockBuilderService) SubmitBlindedBlock(_ context.Context, b interfaces.
|
||||
return nil, nil, errors.Wrap(err, "could not wrap deneb payload")
|
||||
}
|
||||
return w, s.BlobBundle, s.ErrSubmitBlindedBlock
|
||||
case version.Electra:
|
||||
w, err := blocks.WrappedExecutionPayloadElectra(s.PayloadElectra)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "could not wrap electra payload")
|
||||
}
|
||||
return w, s.BlobBundle, s.ErrSubmitBlindedBlock
|
||||
default:
|
||||
return nil, nil, errors.New("unknown block version for mocking")
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/signing"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/params"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
|
||||
"github.com/prysmaticlabs/prysm/v5/container/trie"
|
||||
"github.com/prysmaticlabs/prysm/v5/contracts/deposit"
|
||||
"github.com/prysmaticlabs/prysm/v5/crypto/bls"
|
||||
@@ -136,26 +137,25 @@ func BatchVerifyDepositsSignatures(ctx context.Context, deposits []*ethpb.Deposi
|
||||
//
|
||||
// pubkey = deposit.data.pubkey
|
||||
// amount = deposit.data.amount
|
||||
// validator_pubkeys = [v.pubkey for v in state.validators]
|
||||
// if pubkey not in validator_pubkeys:
|
||||
// # Verify the deposit signature (proof of possession) which is not checked by the deposit contract
|
||||
// deposit_message = DepositMessage(
|
||||
// pubkey=deposit.data.pubkey,
|
||||
// withdrawal_credentials=deposit.data.withdrawal_credentials,
|
||||
// amount=deposit.data.amount,
|
||||
// )
|
||||
// domain = compute_domain(DOMAIN_DEPOSIT) # Fork-agnostic domain since deposits are valid across forks
|
||||
// signing_root = compute_signing_root(deposit_message, domain)
|
||||
// if not bls.Verify(pubkey, signing_root, deposit.data.signature):
|
||||
// return
|
||||
//
|
||||
// # Add validator and balance entries
|
||||
// state.validators.append(get_validator_from_deposit(state, deposit))
|
||||
// state.balances.append(amount)
|
||||
// else:
|
||||
// # Increase balance by deposit amount
|
||||
// index = ValidatorIndex(validator_pubkeys.index(pubkey))
|
||||
// increase_balance(state, index, amount)
|
||||
// TODO: This is apply_deposit, refactor to another function for readability.
|
||||
//
|
||||
// validator_pubkeys = [v.pubkey for v in state.validators]
|
||||
// if pubkey not in validator_pubkeys:
|
||||
// # Verify the deposit signature (proof of possession) which is not checked by the deposit contract
|
||||
// deposit_message = DepositMessage(
|
||||
// pubkey=deposit.data.pubkey,
|
||||
// withdrawal_credentials=deposit.data.withdrawal_credentials,
|
||||
// amount=deposit.data.amount,
|
||||
// )
|
||||
// domain = compute_domain(DOMAIN_DEPOSIT) # Fork-agnostic domain since deposits are valid across forks
|
||||
// signing_root = compute_signing_root(deposit_message, domain)
|
||||
// if bls.Verify(pubkey, signing_root, signature):
|
||||
// add_validator_to_registry(state, pubkey, withdrawal_credentials, amount) // TODO: Missing spec def here
|
||||
// else:
|
||||
// # Increase balance by deposit amount
|
||||
// index = ValidatorIndex(validator_pubkeys.index(pubkey))
|
||||
// state.pending_balance_deposits.append(PendingBalanceDeposit(index, amount)) # [Modified in EIP-7251]
|
||||
func ProcessDeposit(beaconState state.BeaconState, deposit *ethpb.Deposit, verifySignature bool) (state.BeaconState, bool, error) {
|
||||
var newValidator bool
|
||||
if err := verifyDeposit(beaconState, deposit); err != nil {
|
||||
@@ -167,6 +167,7 @@ func ProcessDeposit(beaconState state.BeaconState, deposit *ethpb.Deposit, verif
|
||||
if err := beaconState.SetEth1DepositIndex(beaconState.Eth1DepositIndex() + 1); err != nil {
|
||||
return nil, newValidator, err
|
||||
}
|
||||
isElectraOrLater := beaconState.Fork() != nil && beaconState.Fork().Epoch >= params.BeaconConfig().ElectraForkEpoch
|
||||
pubKey := deposit.Data.PublicKey
|
||||
amount := deposit.Data.Amount
|
||||
index, ok := beaconState.ValidatorIndexByPubkey(bytesutil.ToBytes48(pubKey))
|
||||
@@ -183,10 +184,16 @@ func ProcessDeposit(beaconState state.BeaconState, deposit *ethpb.Deposit, verif
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE: This is get_validator_from_deposit. There are changes in EIP-7251.
|
||||
effectiveBalance := amount - (amount % params.BeaconConfig().EffectiveBalanceIncrement)
|
||||
if params.BeaconConfig().MaxEffectiveBalance < effectiveBalance {
|
||||
effectiveBalance = params.BeaconConfig().MaxEffectiveBalance
|
||||
}
|
||||
if isElectraOrLater {
|
||||
// In EIP-7251, the balance updates happen in the process_pending_balance_deposits method of
|
||||
// the epoch transition function.
|
||||
effectiveBalance = 0 // New in EIP-7251
|
||||
}
|
||||
if err := beaconState.AppendValidator(ðpb.Validator{
|
||||
PublicKey: pubKey,
|
||||
WithdrawalCredentials: deposit.Data.WithdrawalCredentials,
|
||||
@@ -202,10 +209,24 @@ func ProcessDeposit(beaconState state.BeaconState, deposit *ethpb.Deposit, verif
|
||||
if err := beaconState.AppendBalance(amount); err != nil {
|
||||
return nil, newValidator, err
|
||||
}
|
||||
} else if err := helpers.IncreaseBalance(beaconState, index, amount); err != nil {
|
||||
return nil, newValidator, err
|
||||
numVals := beaconState.NumValidators()
|
||||
if numVals == 0 { // Cautiously prevent impossible underflow
|
||||
return nil, false, errors.New("underflow: zero validators")
|
||||
}
|
||||
index = primitives.ValidatorIndex(numVals - 1)
|
||||
} else {
|
||||
if !isElectraOrLater {
|
||||
if err := helpers.IncreaseBalance(beaconState, index, amount); err != nil {
|
||||
return nil, newValidator, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if isElectraOrLater {
|
||||
if err := beaconState.AppendPendingBalanceDeposit(index, amount); err != nil {
|
||||
return nil, newValidator, err
|
||||
}
|
||||
}
|
||||
return beaconState, newValidator, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -40,6 +40,8 @@ var ValidatorCannotExitYetMsg = "validator has not been active long enough to ex
|
||||
// assert get_current_epoch(state) >= voluntary_exit.epoch
|
||||
// # Verify the validator has been active long enough
|
||||
// assert get_current_epoch(state) >= validator.activation_epoch + SHARD_COMMITTEE_PERIOD
|
||||
// # Only exit validator if it has no pending withdrawals in the queue
|
||||
// assert get_pending_balance_to_withdraw(state, voluntary_exit.validator_index) == 0 # [New in EIP7251]
|
||||
// # Verify signature
|
||||
// domain = get_domain(state, DOMAIN_VOLUNTARY_EXIT, voluntary_exit.epoch)
|
||||
// signing_root = compute_signing_root(voluntary_exit, domain)
|
||||
@@ -98,6 +100,8 @@ func ProcessVoluntaryExits(
|
||||
// assert get_current_epoch(state) >= voluntary_exit.epoch
|
||||
// # Verify the validator has been active long enough
|
||||
// assert get_current_epoch(state) >= validator.activation_epoch + SHARD_COMMITTEE_PERIOD
|
||||
// # Only exit validator if it has no pending withdrawals in the queue
|
||||
// assert get_pending_balance_to_withdraw(state, voluntary_exit.validator_index) == 0 # [New in EIP7251]
|
||||
// # Verify signature
|
||||
// domain = get_domain(state, DOMAIN_VOLUNTARY_EXIT, voluntary_exit.epoch)
|
||||
// signing_root = compute_signing_root(voluntary_exit, domain)
|
||||
@@ -128,7 +132,7 @@ func VerifyExitAndSignature(
|
||||
}
|
||||
|
||||
exit := signed.Exit
|
||||
if err := verifyExitConditions(validator, currentSlot, exit); err != nil {
|
||||
if err := verifyExitConditions(state, validator, currentSlot, exit); err != nil {
|
||||
return err
|
||||
}
|
||||
domain, err := signing.Domain(fork, exit.Epoch, params.BeaconConfig().DomainVoluntaryExit, genesisRoot)
|
||||
@@ -157,13 +161,15 @@ func VerifyExitAndSignature(
|
||||
// assert get_current_epoch(state) >= voluntary_exit.epoch
|
||||
// # Verify the validator has been active long enough
|
||||
// assert get_current_epoch(state) >= validator.activation_epoch + SHARD_COMMITTEE_PERIOD
|
||||
// # Only exit validator if it has no pending withdrawals in the queue
|
||||
// assert get_pending_balance_to_withdraw(state, voluntary_exit.validator_index) == 0 # [New in Electra:EIP7251]
|
||||
// # Verify signature
|
||||
// domain = get_domain(state, DOMAIN_VOLUNTARY_EXIT, voluntary_exit.epoch)
|
||||
// signing_root = compute_signing_root(voluntary_exit, domain)
|
||||
// assert bls.Verify(validator.pubkey, signing_root, signed_voluntary_exit.signature)
|
||||
// # Initiate exit
|
||||
// initiate_validator_exit(state, voluntary_exit.validator_index)
|
||||
func verifyExitConditions(validator state.ReadOnlyValidator, currentSlot primitives.Slot, exit *ethpb.VoluntaryExit) error {
|
||||
func verifyExitConditions(st state.ReadOnlyBeaconState, validator state.ReadOnlyValidator, currentSlot primitives.Slot, exit *ethpb.VoluntaryExit) error {
|
||||
currentEpoch := slots.ToEpoch(currentSlot)
|
||||
// Verify the validator is active.
|
||||
if !helpers.IsActiveValidatorUsingTrie(validator, currentEpoch) {
|
||||
@@ -187,5 +193,14 @@ func verifyExitConditions(validator state.ReadOnlyValidator, currentSlot primiti
|
||||
validator.ActivationEpoch()+params.BeaconConfig().ShardCommitteePeriod,
|
||||
)
|
||||
}
|
||||
if st.Version() >= version.Electra {
|
||||
pending, err := st.PendingBalanceToWithdraw(exit.ValidatorIndex)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if pending != 0 {
|
||||
return fmt.Errorf("validator with index %d has pending balance to withdraw and cannot exit", exit.ValidatorIndex)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -118,56 +118,46 @@ func ValidateBLSToExecutionChange(st state.ReadOnlyBeaconState, signed *ethpb.Si
|
||||
// ProcessWithdrawals processes the validator withdrawals from the provided execution payload
|
||||
// into the beacon state.
|
||||
//
|
||||
// Spec pseudocode definition:
|
||||
// Spec definition:
|
||||
//
|
||||
// def process_withdrawals(state: BeaconState, payload: ExecutionPayload) -> None:
|
||||
// def process_withdrawals(state: BeaconState, payload: ExecutionPayload) -> None:
|
||||
// expected_withdrawals, partial_withdrawals_count = get_expected_withdrawals(state) # [Modified in Electra:EIP7251]
|
||||
//
|
||||
// expected_withdrawals = get_expected_withdrawals(state)
|
||||
// assert len(payload.withdrawals) == len(expected_withdrawals)
|
||||
// assert len(payload.withdrawals) == len(expected_withdrawals)
|
||||
//
|
||||
// for expected_withdrawal, withdrawal in zip(expected_withdrawals, payload.withdrawals):
|
||||
// assert withdrawal == expected_withdrawal
|
||||
// decrease_balance(state, withdrawal.validator_index, withdrawal.amount)
|
||||
// for expected_withdrawal, withdrawal in zip(expected_withdrawals, payload.withdrawals):
|
||||
// assert withdrawal == expected_withdrawal
|
||||
// decrease_balance(state, withdrawal.validator_index, withdrawal.amount)
|
||||
//
|
||||
// # Update the next withdrawal index if this block contained withdrawals
|
||||
// if len(expected_withdrawals) != 0:
|
||||
// latest_withdrawal = expected_withdrawals[-1]
|
||||
// state.next_withdrawal_index = WithdrawalIndex(latest_withdrawal.index + 1)
|
||||
// # Update pending partial withdrawals [New in Electra:EIP7251]
|
||||
// state.pending_partial_withdrawals = state.pending_partial_withdrawals[partial_withdrawals_count:]
|
||||
//
|
||||
// # Update the next validator index to start the next withdrawal sweep
|
||||
// if len(expected_withdrawals) == MAX_WITHDRAWALS_PER_PAYLOAD:
|
||||
// # Next sweep starts after the latest withdrawal's validator index
|
||||
// next_validator_index = ValidatorIndex((expected_withdrawals[-1].validator_index + 1) % len(state.validators))
|
||||
// state.next_withdrawal_validator_index = next_validator_index
|
||||
// else:
|
||||
// # Advance sweep by the max length of the sweep if there was not a full set of withdrawals
|
||||
// next_index = state.next_withdrawal_validator_index + MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP
|
||||
// next_validator_index = ValidatorIndex(next_index % len(state.validators))
|
||||
// state.next_withdrawal_validator_index = next_validator_index
|
||||
// # Update the next withdrawal index if this block contained withdrawals
|
||||
// if len(expected_withdrawals) != 0:
|
||||
// latest_withdrawal = expected_withdrawals[-1]
|
||||
// state.next_withdrawal_index = WithdrawalIndex(latest_withdrawal.index + 1)
|
||||
//
|
||||
// # Update the next validator index to start the next withdrawal sweep
|
||||
// if len(expected_withdrawals) == MAX_WITHDRAWALS_PER_PAYLOAD:
|
||||
// # Next sweep starts after the latest withdrawal's validator index
|
||||
// next_validator_index = ValidatorIndex((expected_withdrawals[-1].validator_index + 1) % len(state.validators))
|
||||
// state.next_withdrawal_validator_index = next_validator_index
|
||||
// else:
|
||||
// # Advance sweep by the max length of the sweep if there was not a full set of withdrawals
|
||||
// next_index = state.next_withdrawal_validator_index + MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP
|
||||
// next_validator_index = ValidatorIndex(next_index % len(state.validators))
|
||||
// state.next_withdrawal_validator_index = next_validator_index
|
||||
func ProcessWithdrawals(st state.BeaconState, executionData interfaces.ExecutionData) (state.BeaconState, error) {
|
||||
expectedWithdrawals, _, err := st.ExpectedWithdrawals()
|
||||
expectedWithdrawals, partials, err := st.ExpectedWithdrawals()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get expected withdrawals")
|
||||
}
|
||||
|
||||
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(wds, fieldparams.MaxWithdrawalsPerPayload)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get withdrawals root")
|
||||
}
|
||||
// Instead of checking "assert withdrawal == expected_withdrawal", we check the withdrawals root.
|
||||
wdRoot, err := withdrawalsRootFromMaybeBlindedExecutionData(executionData)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get withdrawals root")
|
||||
}
|
||||
|
||||
expectedRoot, err := ssz.WithdrawalSliceRoot(expectedWithdrawals, fieldparams.MaxWithdrawalsPerPayload)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get expected withdrawals root")
|
||||
@@ -182,6 +172,13 @@ func ProcessWithdrawals(st state.BeaconState, executionData interfaces.Execution
|
||||
return nil, errors.Wrap(err, "could not decrease balance")
|
||||
}
|
||||
}
|
||||
|
||||
if partials > 0 {
|
||||
if err := st.DequeuePartialWithdrawals(partials); err != nil {
|
||||
return nil, fmt.Errorf("could not dequeue partial withdrawals: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
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")
|
||||
@@ -207,6 +204,21 @@ func ProcessWithdrawals(st state.BeaconState, executionData interfaces.Execution
|
||||
return st, nil
|
||||
}
|
||||
|
||||
func withdrawalsRootFromMaybeBlindedExecutionData(ed interfaces.ExecutionData) ([32]byte, error) {
|
||||
if ed.IsBlinded() {
|
||||
r, err := ed.WithdrawalsRoot()
|
||||
if err != nil {
|
||||
return [32]byte{}, errors.Wrap(err, "could not get withdrawals root from blinded execution data")
|
||||
}
|
||||
return bytesutil.ToBytes32(r), nil
|
||||
}
|
||||
wds, err := ed.Withdrawals()
|
||||
if err != nil {
|
||||
return [32]byte{}, errors.Wrap(err, "could not get withdrawals")
|
||||
}
|
||||
return ssz.WithdrawalSliceRoot(wds, fieldparams.MaxWithdrawalsPerPayload)
|
||||
}
|
||||
|
||||
// BLSChangesSignatureBatch extracts the relevant signatures from the provided execution change
|
||||
// messages and transforms them into a signature batch object.
|
||||
func BLSChangesSignatureBatch(
|
||||
|
||||
@@ -7,6 +7,7 @@ go_library(
|
||||
"consolidations.go",
|
||||
"deposits.go",
|
||||
"effective_balance_updates.go",
|
||||
"epoch_processing.go",
|
||||
"registry_updates.go",
|
||||
"transition.go",
|
||||
"upgrade.go",
|
||||
@@ -22,6 +23,7 @@ go_library(
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/core/signing:go_default_library",
|
||||
"//beacon-chain/core/time:go_default_library",
|
||||
"//beacon-chain/core/validators:go_default_library",
|
||||
"//beacon-chain/state:go_default_library",
|
||||
"//beacon-chain/state/state-native:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
@@ -43,6 +45,7 @@ go_test(
|
||||
"churn_test.go",
|
||||
"consolidations_test.go",
|
||||
"deposits_test.go",
|
||||
"effective_balance_updates_test.go",
|
||||
"upgrade_test.go",
|
||||
"validator_test.go",
|
||||
],
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
package electra
|
||||
|
||||
import "github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/params"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
)
|
||||
|
||||
// ProcessEffectiveBalanceUpdates processes effective balance updates during epoch processing.
|
||||
//
|
||||
@@ -24,6 +31,35 @@ import "github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
|
||||
// ):
|
||||
// validator.effective_balance = min(balance - balance % EFFECTIVE_BALANCE_INCREMENT, EFFECTIVE_BALANCE_LIMIT)
|
||||
func ProcessEffectiveBalanceUpdates(state state.BeaconState) error {
|
||||
// TODO: replace with real implementation
|
||||
return nil
|
||||
effBalanceInc := params.BeaconConfig().EffectiveBalanceIncrement
|
||||
hysteresisInc := effBalanceInc / params.BeaconConfig().HysteresisQuotient
|
||||
downwardThreshold := hysteresisInc * params.BeaconConfig().HysteresisDownwardMultiplier
|
||||
upwardThreshold := hysteresisInc * params.BeaconConfig().HysteresisUpwardMultiplier
|
||||
|
||||
bals := state.Balances()
|
||||
|
||||
// Update effective balances with hysteresis.
|
||||
validatorFunc := func(idx int, val *ethpb.Validator) (bool, *ethpb.Validator, error) {
|
||||
if val == nil {
|
||||
return false, nil, fmt.Errorf("validator %d is nil in state", idx)
|
||||
}
|
||||
if idx >= len(bals) {
|
||||
return false, nil, fmt.Errorf("validator index exceeds validator length in state %d >= %d", idx, len(state.Balances()))
|
||||
}
|
||||
balance := bals[idx]
|
||||
|
||||
effectiveBalanceLimit := params.BeaconConfig().MinActivationBalance
|
||||
if helpers.HasCompoundingWithdrawalCredential(val) {
|
||||
effectiveBalanceLimit = params.BeaconConfig().MaxEffectiveBalanceElectra
|
||||
}
|
||||
|
||||
if balance+downwardThreshold < val.EffectiveBalance || val.EffectiveBalance+upwardThreshold < balance {
|
||||
effectiveBal := min(balance-balance%effBalanceInc, effectiveBalanceLimit)
|
||||
val.EffectiveBalance = effectiveBal
|
||||
return false, val, nil
|
||||
}
|
||||
return false, val, nil
|
||||
}
|
||||
|
||||
return state.ApplyToEveryValidator(validatorFunc)
|
||||
}
|
||||
|
||||
144
beacon-chain/core/electra/effective_balance_updates_test.go
Normal file
144
beacon-chain/core/electra/effective_balance_updates_test.go
Normal file
@@ -0,0 +1,144 @@
|
||||
package electra_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/electra"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
|
||||
state_native "github.com/prysmaticlabs/prysm/v5/beacon-chain/state/state-native"
|
||||
"github.com/prysmaticlabs/prysm/v5/config/params"
|
||||
eth "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||
)
|
||||
|
||||
func TestProcessEffectiveBalnceUpdates(t *testing.T) {
|
||||
effBalanceInc := params.BeaconConfig().EffectiveBalanceIncrement
|
||||
hysteresisInc := effBalanceInc / params.BeaconConfig().HysteresisQuotient
|
||||
downwardThreshold := hysteresisInc * params.BeaconConfig().HysteresisDownwardMultiplier
|
||||
upwardThreshold := hysteresisInc * params.BeaconConfig().HysteresisUpwardMultiplier
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
state state.BeaconState
|
||||
wantErr bool
|
||||
check func(*testing.T, state.BeaconState)
|
||||
}{
|
||||
{
|
||||
name: "validator with compounding withdrawal credentials updates effective balance",
|
||||
state: func() state.BeaconState {
|
||||
pb := ð.BeaconStateElectra{
|
||||
Validators: []*eth.Validator{
|
||||
{
|
||||
EffectiveBalance: params.BeaconConfig().MinActivationBalance,
|
||||
WithdrawalCredentials: []byte{params.BeaconConfig().CompoundingWithdrawalPrefixByte, 0x11},
|
||||
},
|
||||
},
|
||||
Balances: []uint64{
|
||||
params.BeaconConfig().MaxEffectiveBalanceElectra * 2,
|
||||
},
|
||||
}
|
||||
st, err := state_native.InitializeFromProtoElectra(pb)
|
||||
require.NoError(t, err)
|
||||
return st
|
||||
}(),
|
||||
check: func(t *testing.T, bs state.BeaconState) {
|
||||
val, err := bs.ValidatorAtIndex(0)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, params.BeaconConfig().MaxEffectiveBalanceElectra, val.EffectiveBalance)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "validator without compounding withdrawal credentials updates effective balance",
|
||||
state: func() state.BeaconState {
|
||||
pb := ð.BeaconStateElectra{
|
||||
Validators: []*eth.Validator{
|
||||
{
|
||||
EffectiveBalance: params.BeaconConfig().MinActivationBalance / 2,
|
||||
WithdrawalCredentials: nil,
|
||||
},
|
||||
},
|
||||
Balances: []uint64{
|
||||
params.BeaconConfig().MaxEffectiveBalanceElectra,
|
||||
},
|
||||
}
|
||||
st, err := state_native.InitializeFromProtoElectra(pb)
|
||||
require.NoError(t, err)
|
||||
return st
|
||||
}(),
|
||||
check: func(t *testing.T, bs state.BeaconState) {
|
||||
val, err := bs.ValidatorAtIndex(0)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, params.BeaconConfig().MinActivationBalance, val.EffectiveBalance)
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "validator effective balance moves only when outside of threshold",
|
||||
state: func() state.BeaconState {
|
||||
pb := ð.BeaconStateElectra{
|
||||
Validators: []*eth.Validator{
|
||||
{
|
||||
EffectiveBalance: params.BeaconConfig().MinActivationBalance,
|
||||
WithdrawalCredentials: []byte{params.BeaconConfig().CompoundingWithdrawalPrefixByte, 0x11},
|
||||
},
|
||||
{
|
||||
EffectiveBalance: params.BeaconConfig().MinActivationBalance,
|
||||
WithdrawalCredentials: []byte{params.BeaconConfig().CompoundingWithdrawalPrefixByte, 0x11},
|
||||
},
|
||||
{
|
||||
EffectiveBalance: params.BeaconConfig().MinActivationBalance,
|
||||
WithdrawalCredentials: []byte{params.BeaconConfig().CompoundingWithdrawalPrefixByte, 0x11},
|
||||
},
|
||||
{
|
||||
EffectiveBalance: params.BeaconConfig().MinActivationBalance,
|
||||
WithdrawalCredentials: []byte{params.BeaconConfig().CompoundingWithdrawalPrefixByte, 0x11},
|
||||
},
|
||||
},
|
||||
Balances: []uint64{
|
||||
params.BeaconConfig().MinActivationBalance - downwardThreshold - 1, // beyond downward threshold
|
||||
params.BeaconConfig().MinActivationBalance - downwardThreshold + 1, // within downward threshold
|
||||
params.BeaconConfig().MinActivationBalance + upwardThreshold + 1, // beyond upward threshold
|
||||
params.BeaconConfig().MinActivationBalance + upwardThreshold - 1, // within upward threshold
|
||||
},
|
||||
}
|
||||
st, err := state_native.InitializeFromProtoElectra(pb)
|
||||
require.NoError(t, err)
|
||||
return st
|
||||
}(),
|
||||
check: func(t *testing.T, bs state.BeaconState) {
|
||||
// validator 0 has a balance diff exceeding the threshold so a diff should be applied to
|
||||
// effective balance and it moves by effective balance increment.
|
||||
val, err := bs.ValidatorAtIndex(0)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, params.BeaconConfig().MinActivationBalance-params.BeaconConfig().EffectiveBalanceIncrement, val.EffectiveBalance)
|
||||
|
||||
// validator 1 has a balance diff within the threshold so the effective balance should not
|
||||
// have changed.
|
||||
val, err = bs.ValidatorAtIndex(1)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, params.BeaconConfig().MinActivationBalance, val.EffectiveBalance)
|
||||
|
||||
// Validator 2 has a balance diff exceeding the threshold so a diff should be applied to the
|
||||
// effective balance and it moves by effective balance increment.
|
||||
val, err = bs.ValidatorAtIndex(2)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, params.BeaconConfig().MinActivationBalance+params.BeaconConfig().EffectiveBalanceIncrement, val.EffectiveBalance)
|
||||
|
||||
// Validator 3 has a balance diff within the threshold so the effective balance should not
|
||||
// have changed.
|
||||
val, err = bs.ValidatorAtIndex(3)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, params.BeaconConfig().MinActivationBalance, val.EffectiveBalance)
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
err := electra.ProcessEffectiveBalanceUpdates(tt.state)
|
||||
require.Equal(t, tt.wantErr, err != nil, "unexpected error returned wanted error=nil (%s), got error=%s", tt.wantErr, err)
|
||||
if tt.check != nil {
|
||||
tt.check(t, tt.state)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
27
beacon-chain/core/electra/epoch_processing.go
Normal file
27
beacon-chain/core/electra/epoch_processing.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package electra
|
||||
|
||||
import (
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/primitives"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
)
|
||||
|
||||
// sortableIndices implements the Sort interface to sort newly activated validator indices
|
||||
// by activation epoch and by index number.
|
||||
type sortableIndices struct {
|
||||
indices []primitives.ValidatorIndex
|
||||
validators []*ethpb.Validator
|
||||
}
|
||||
|
||||
// Len is the number of elements in the collection.
|
||||
func (s sortableIndices) Len() int { return len(s.indices) }
|
||||
|
||||
// Swap swaps the elements with indexes i and j.
|
||||
func (s sortableIndices) Swap(i, j int) { s.indices[i], s.indices[j] = s.indices[j], s.indices[i] }
|
||||
|
||||
// Less reports whether the element with index i must sort before the element with index j.
|
||||
func (s sortableIndices) Less(i, j int) bool {
|
||||
if s.validators[s.indices[i]].ActivationEligibilityEpoch == s.validators[s.indices[j]].ActivationEligibilityEpoch {
|
||||
return s.indices[i] < s.indices[j]
|
||||
}
|
||||
return s.validators[s.indices[i]].ActivationEligibilityEpoch < s.validators[s.indices[j]].ActivationEligibilityEpoch
|
||||
}
|
||||
@@ -27,6 +27,10 @@ var (
|
||||
ProcessSyncCommitteeUpdates = altair.ProcessSyncCommitteeUpdates
|
||||
AttestationsDelta = altair.AttestationsDelta
|
||||
ProcessSyncAggregate = altair.ProcessSyncAggregate
|
||||
|
||||
// These need to be rewritten for electra.
|
||||
ProcessDeposits = altair.ProcessDeposits
|
||||
ProcessAttestationsNoVerifySignature = altair.ProcessAttestationsNoVerifySignature
|
||||
)
|
||||
|
||||
// ProcessEpoch describes the per epoch operations that are performed on the beacon state.
|
||||
@@ -47,7 +51,7 @@ var (
|
||||
// process_slashings_reset(state)
|
||||
// process_randao_mixes_reset(state)
|
||||
func ProcessEpoch(ctx context.Context, state state.BeaconState) (state.BeaconState, error) {
|
||||
_, span := trace.StartSpan(ctx, "electra.ProcessEpoch")
|
||||
ctx, span := trace.StartSpan(ctx, "electra.ProcessEpoch")
|
||||
defer span.End()
|
||||
|
||||
if state == nil || state.IsNil() {
|
||||
|
||||
@@ -95,8 +95,8 @@ func CanUpgradeToDeneb(slot primitives.Slot) bool {
|
||||
// If state.slot % SLOTS_PER_EPOCH == 0 and compute_epoch_at_slot(state.slot) == ELECTRA_FORK_EPOCH
|
||||
func CanUpgradeToElectra(slot primitives.Slot) bool {
|
||||
epochStart := slots.IsEpochStart(slot)
|
||||
electraEpoch := slots.ToEpoch(slot) == params.BeaconConfig().ElectraForkEpoch
|
||||
return epochStart && electraEpoch
|
||||
ElectraEpoch := slots.ToEpoch(slot) == params.BeaconConfig().ElectraForkEpoch
|
||||
return epochStart && ElectraEpoch
|
||||
}
|
||||
|
||||
// CanProcessEpoch checks the eligibility to process epoch.
|
||||
|
||||
@@ -453,7 +453,6 @@ func electraOperations(
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not process deposit receipts")
|
||||
}
|
||||
|
||||
if err := electra.ProcessConsolidations(ctx, st, bod.Consolidations()); err != nil {
|
||||
return nil, errors.Wrap(err, "could not process consolidations")
|
||||
}
|
||||
|
||||
@@ -89,6 +89,8 @@ func (s *Server) getBeaconStateV2(ctx context.Context, w http.ResponseWriter, id
|
||||
httputil.HandleError(w, errMsgStateFromConsensus+": "+err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
case version.Electra:
|
||||
panic("implement me")
|
||||
default:
|
||||
httputil.HandleError(w, "Unsupported state version", http.StatusInternalServerError)
|
||||
return
|
||||
|
||||
@@ -475,6 +475,8 @@ func (s *Server) sendPayloadAttributes(ctx context.Context, w http.ResponseWrite
|
||||
Withdrawals: structs.WithdrawalsFromConsensus(withdrawals),
|
||||
ParentBeaconBlockRoot: hexutil.Encode(parentRoot[:]),
|
||||
}
|
||||
case version.Electra:
|
||||
panic("implement me")
|
||||
default:
|
||||
return write(w, flusher, "Payload version %s is not supported", version.String(headState.Version()))
|
||||
}
|
||||
|
||||
@@ -209,3 +209,4 @@ message SyncAggregate {
|
||||
// BLS aggregated signature of the sync committee for the ones that voted.
|
||||
bytes sync_committee_signature = 2 [(ethereum.eth.ext.ssz_size) = "96"];
|
||||
}
|
||||
|
||||
|
||||
@@ -156,6 +156,11 @@ func (s *PremineGenesisConfig) empty() (state.BeaconState, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
case version.Electra:
|
||||
e, err = state_native.InitializeFromProtoElectra(ðpb.BeaconStateElectra{})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
default:
|
||||
return nil, errUnsupportedVersion
|
||||
}
|
||||
@@ -335,6 +340,8 @@ func (s *PremineGenesisConfig) setFork(g state.BeaconState) error {
|
||||
pv, cv = params.BeaconConfig().BellatrixForkVersion, params.BeaconConfig().CapellaForkVersion
|
||||
case version.Deneb:
|
||||
pv, cv = params.BeaconConfig().CapellaForkVersion, params.BeaconConfig().DenebForkVersion
|
||||
case version.Electra:
|
||||
pv, cv = params.BeaconConfig().DenebForkVersion, params.BeaconConfig().ElectraForkVersion
|
||||
default:
|
||||
return errUnsupportedVersion
|
||||
}
|
||||
@@ -523,6 +530,37 @@ func (s *PremineGenesisConfig) setLatestBlockHeader(g state.BeaconState) error {
|
||||
BlsToExecutionChanges: make([]*ethpb.SignedBLSToExecutionChange, 0),
|
||||
BlobKzgCommitments: make([][]byte, 0),
|
||||
}
|
||||
case version.Electra:
|
||||
body = ðpb.BeaconBlockBodyElectra{
|
||||
RandaoReveal: make([]byte, 96),
|
||||
Eth1Data: ðpb.Eth1Data{
|
||||
DepositRoot: make([]byte, 32),
|
||||
BlockHash: make([]byte, 32),
|
||||
},
|
||||
Graffiti: make([]byte, 32),
|
||||
SyncAggregate: ðpb.SyncAggregate{
|
||||
SyncCommitteeBits: make([]byte, fieldparams.SyncCommitteeLength/8),
|
||||
SyncCommitteeSignature: make([]byte, fieldparams.BLSSignatureLength),
|
||||
},
|
||||
ExecutionPayload: &enginev1.ExecutionPayloadElectra{
|
||||
ParentHash: make([]byte, 32),
|
||||
FeeRecipient: make([]byte, 20),
|
||||
StateRoot: make([]byte, 32),
|
||||
ReceiptsRoot: make([]byte, 32),
|
||||
LogsBloom: make([]byte, 256),
|
||||
PrevRandao: make([]byte, 32),
|
||||
ExtraData: make([]byte, 0),
|
||||
BaseFeePerGas: make([]byte, 32),
|
||||
BlockHash: make([]byte, 32),
|
||||
Transactions: make([][]byte, 0),
|
||||
Withdrawals: make([]*enginev1.Withdrawal, 0),
|
||||
DepositReceipts: make([]*enginev1.DepositReceipt, 0),
|
||||
WithdrawalRequests: make([]*enginev1.ExecutionLayerWithdrawalRequest, 0),
|
||||
},
|
||||
BlsToExecutionChanges: make([]*ethpb.SignedBLSToExecutionChange, 0),
|
||||
BlobKzgCommitments: make([][]byte, 0),
|
||||
Consolidations: make([]*ethpb.SignedConsolidation, 0),
|
||||
}
|
||||
default:
|
||||
return errUnsupportedVersion
|
||||
}
|
||||
@@ -639,6 +677,44 @@ func (s *PremineGenesisConfig) setExecutionPayload(g state.BeaconState) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case version.Electra:
|
||||
payload := &enginev1.ExecutionPayloadElectra{
|
||||
ParentHash: gb.ParentHash().Bytes(),
|
||||
FeeRecipient: gb.Coinbase().Bytes(),
|
||||
StateRoot: gb.Root().Bytes(),
|
||||
ReceiptsRoot: gb.ReceiptHash().Bytes(),
|
||||
LogsBloom: gb.Bloom().Bytes(),
|
||||
PrevRandao: params.BeaconConfig().ZeroHash[:],
|
||||
BlockNumber: gb.NumberU64(),
|
||||
GasLimit: gb.GasLimit(),
|
||||
GasUsed: gb.GasUsed(),
|
||||
Timestamp: gb.Time(),
|
||||
ExtraData: gb.Extra()[:32],
|
||||
BaseFeePerGas: bytesutil.PadTo(bytesutil.ReverseByteOrder(gb.BaseFee().Bytes()), fieldparams.RootLength),
|
||||
BlockHash: gb.Hash().Bytes(),
|
||||
Transactions: make([][]byte, 0),
|
||||
Withdrawals: make([]*enginev1.Withdrawal, 0),
|
||||
ExcessBlobGas: *gb.ExcessBlobGas(),
|
||||
BlobGasUsed: *gb.BlobGasUsed(),
|
||||
DepositReceipts: make([]*enginev1.DepositReceipt, 0),
|
||||
WithdrawalRequests: make([]*enginev1.ExecutionLayerWithdrawalRequest, 0),
|
||||
}
|
||||
wep, err := blocks.WrappedExecutionPayloadElectra(payload)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
wepe, ok := wep.(interfaces.ExecutionDataElectra)
|
||||
if !ok {
|
||||
return errors.New("unexpected execution type data is not electra")
|
||||
}
|
||||
eph, err := blocks.PayloadToHeaderElectra(wepe)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ed, err = blocks.WrappedExecutionPayloadHeaderElectra(eph)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
default:
|
||||
return errUnsupportedVersion
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ load("@prysm//tools/go:def.bzl", "go_test")
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"effective_balance_updates_test.go",
|
||||
"eth1_data_reset_test.go",
|
||||
"historical_summaries_update_test.go",
|
||||
"inactivity_updates_test.go",
|
||||
@@ -11,6 +12,7 @@ go_test(
|
||||
"pending_balance_updates_test.go",
|
||||
"pending_consolidations_test.go",
|
||||
"randao_mixes_reset_test.go",
|
||||
"registry_updates_test.go",
|
||||
"rewards_and_penalties_test.go",
|
||||
"slashings_reset_test.go",
|
||||
"slashings_test.go",
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package epoch_processing
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/spectest/shared/electra/epoch_processing"
|
||||
)
|
||||
|
||||
func TestMainnet_electra_EpochProcessing_EffectiveBalanceUpdates(t *testing.T) {
|
||||
epoch_processing.RunEffectiveBalanceUpdatesTests(t, "mainnet")
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package epoch_processing
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/spectest/shared/electra/epoch_processing"
|
||||
)
|
||||
|
||||
func TestMainnet_Electra_EpochProcessing_ResetRegistryUpdates(t *testing.T) {
|
||||
epoch_processing.RunRegistryUpdatesTests(t, "mainnet")
|
||||
}
|
||||
@@ -7,6 +7,5 @@ import (
|
||||
)
|
||||
|
||||
func TestMainnet_Electra_Finality(t *testing.T) {
|
||||
t.Skip("TODO: Electra")
|
||||
finality.RunFinalityTest(t, "mainnet")
|
||||
}
|
||||
|
||||
@@ -7,6 +7,5 @@ import (
|
||||
)
|
||||
|
||||
func TestMainnet_Electra_Transition(t *testing.T) {
|
||||
t.Skip("TODO: Electra")
|
||||
fork.RunForkTransitionTest(t, "mainnet")
|
||||
}
|
||||
|
||||
@@ -8,6 +8,5 @@ import (
|
||||
)
|
||||
|
||||
func TestMainnet_Electra_Forkchoice(t *testing.T) {
|
||||
t.Skip("TODO: Electra")
|
||||
forkchoice.Run(t, "mainnet", version.Electra)
|
||||
}
|
||||
|
||||
@@ -3,10 +3,12 @@ load("@prysm//tools/go:def.bzl", "go_test")
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"attestation_test.go",
|
||||
"attester_slashing_test.go",
|
||||
"block_header_test.go",
|
||||
"bls_to_execution_change_test.go",
|
||||
"consolidation_test.go",
|
||||
"deposit_test.go",
|
||||
"execution_payload_test.go",
|
||||
"proposer_slashing_test.go",
|
||||
"sync_committee_test.go",
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package operations
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/spectest/shared/electra/operations"
|
||||
)
|
||||
|
||||
func TestMainnet_Electra_Operations_Attestation(t *testing.T) {
|
||||
operations.RunAttestationTest(t, "mainnet")
|
||||
}
|
||||
11
testing/spectest/mainnet/electra/operations/deposit_test.go
Normal file
11
testing/spectest/mainnet/electra/operations/deposit_test.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package operations
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/spectest/shared/electra/operations"
|
||||
)
|
||||
|
||||
func TestMainnet_Electra_Operations_Deposit(t *testing.T) {
|
||||
operations.RunDepositTest(t, "mainnet")
|
||||
}
|
||||
@@ -7,6 +7,5 @@ import (
|
||||
)
|
||||
|
||||
func TestMainnet_Electra_Operations_VoluntaryExit(t *testing.T) {
|
||||
t.Skip("TODO: Electra")
|
||||
operations.RunVoluntaryExitTest(t, "mainnet")
|
||||
}
|
||||
|
||||
@@ -7,6 +7,5 @@ import (
|
||||
)
|
||||
|
||||
func TestMainnet_Electra_Random(t *testing.T) {
|
||||
t.Skip("TODO: Electra")
|
||||
sanity.RunBlockProcessingTest(t, "mainnet", "random/random/pyspec_tests")
|
||||
}
|
||||
|
||||
@@ -7,6 +7,5 @@ import (
|
||||
)
|
||||
|
||||
func TestMainnet_Electra_Sanity_Blocks(t *testing.T) {
|
||||
t.Skip("TODO: Electra")
|
||||
sanity.RunBlockProcessingTest(t, "mainnet", "sanity/blocks/pyspec_tests")
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ load("@prysm//tools/go:def.bzl", "go_test")
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"effective_balance_updates_test.go",
|
||||
"eth1_data_reset_test.go",
|
||||
"historical_summaries_update_test.go",
|
||||
"inactivity_updates_test.go",
|
||||
@@ -11,6 +12,7 @@ go_test(
|
||||
"pending_balance_updates_test.go",
|
||||
"pending_consolidations_test.go",
|
||||
"randao_mixes_reset_test.go",
|
||||
"registry_updates_test.go",
|
||||
"rewards_and_penalties_test.go",
|
||||
"slashings_reset_test.go",
|
||||
"slashings_test.go",
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package epoch_processing
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/spectest/shared/electra/epoch_processing"
|
||||
)
|
||||
|
||||
func TestMinimal_electra_EpochProcessing_EffectiveBalanceUpdates(t *testing.T) {
|
||||
epoch_processing.RunEffectiveBalanceUpdatesTests(t, "minimal")
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package epoch_processing
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/spectest/shared/electra/epoch_processing"
|
||||
)
|
||||
|
||||
func TestMinimal_Electra_EpochProcessing_ResetRegistryUpdates(t *testing.T) {
|
||||
epoch_processing.RunRegistryUpdatesTests(t, "minimal")
|
||||
}
|
||||
@@ -7,6 +7,5 @@ import (
|
||||
)
|
||||
|
||||
func TestMinimal_Electra_Finality(t *testing.T) {
|
||||
t.Skip("TODO: Electra")
|
||||
finality.RunFinalityTest(t, "minimal")
|
||||
}
|
||||
|
||||
@@ -8,6 +8,5 @@ import (
|
||||
)
|
||||
|
||||
func TestMinimal_Electra_Forkchoice(t *testing.T) {
|
||||
t.Skip("TODO: Electra")
|
||||
forkchoice.Run(t, "minimal", version.Electra)
|
||||
}
|
||||
|
||||
@@ -3,10 +3,12 @@ load("@prysm//tools/go:def.bzl", "go_test")
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = [
|
||||
"attestation_test.go",
|
||||
"attester_slashing_test.go",
|
||||
"block_header_test.go",
|
||||
"bls_to_execution_change_test.go",
|
||||
"consolidation_test.go",
|
||||
"deposit_test.go",
|
||||
"execution_payload_test.go",
|
||||
"proposer_slashing_test.go",
|
||||
"sync_committee_test.go",
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package operations
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/spectest/shared/electra/operations"
|
||||
)
|
||||
|
||||
func TestMinimal_Electra_Operations_Attestation(t *testing.T) {
|
||||
operations.RunAttestationTest(t, "minimal")
|
||||
}
|
||||
11
testing/spectest/minimal/electra/operations/deposit_test.go
Normal file
11
testing/spectest/minimal/electra/operations/deposit_test.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package operations
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/spectest/shared/electra/operations"
|
||||
)
|
||||
|
||||
func TestMinimal_Electra_Operations_Deposit(t *testing.T) {
|
||||
operations.RunDepositTest(t, "minimal")
|
||||
}
|
||||
@@ -7,6 +7,5 @@ import (
|
||||
)
|
||||
|
||||
func TestMinimal_Electra_Operations_VoluntaryExit(t *testing.T) {
|
||||
t.Skip("TODO: Electra")
|
||||
operations.RunVoluntaryExitTest(t, "minimal")
|
||||
}
|
||||
|
||||
@@ -7,6 +7,5 @@ import (
|
||||
)
|
||||
|
||||
func TestMinimal_Electra_Random(t *testing.T) {
|
||||
t.Skip("TODO: Electra")
|
||||
sanity.RunBlockProcessingTest(t, "minimal", "random/random/pyspec_tests")
|
||||
}
|
||||
|
||||
@@ -7,6 +7,5 @@ import (
|
||||
)
|
||||
|
||||
func TestMinimal_Electra_Sanity_Blocks(t *testing.T) {
|
||||
t.Skip("TODO: Electra")
|
||||
sanity.RunBlockProcessingTest(t, "minimal", "sanity/blocks/pyspec_tests")
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ go_library(
|
||||
name = "go_default_library",
|
||||
testonly = True,
|
||||
srcs = [
|
||||
"effective_balance_updates.go",
|
||||
"eth1_data_reset.go",
|
||||
"helpers.go",
|
||||
"historical_summaries_update.go",
|
||||
@@ -13,6 +14,7 @@ go_library(
|
||||
"pending_balance_updates.go",
|
||||
"pending_consolidations.go",
|
||||
"randao_mixes_reset.go",
|
||||
"registry_updates.go",
|
||||
"rewards_and_penalties.go",
|
||||
"slashings.go",
|
||||
"slashings_reset.go",
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
package epoch_processing
|
||||
|
||||
import (
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/electra"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/spectest/utils"
|
||||
)
|
||||
|
||||
// RunEffectiveBalanceUpdatesTests executes "epoch_processing/effective_balance_updates" tests.
|
||||
func RunEffectiveBalanceUpdatesTests(t *testing.T, config string) {
|
||||
require.NoError(t, utils.SetConfig(t, config))
|
||||
|
||||
testFolders, testsFolderPath := utils.TestFolders(t, config, "electra", "epoch_processing/effective_balance_updates/pyspec_tests")
|
||||
for _, folder := range testFolders {
|
||||
t.Run(folder.Name(), func(t *testing.T) {
|
||||
folderPath := path.Join(testsFolderPath, folder.Name())
|
||||
RunEpochOperationTest(t, folderPath, processEffectiveBalanceUpdatesWrapper)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func processEffectiveBalanceUpdatesWrapper(t *testing.T, st state.BeaconState) (state.BeaconState, error) {
|
||||
err := electra.ProcessEffectiveBalanceUpdates(st)
|
||||
require.NoError(t, err, "Could not process final updates")
|
||||
return st, nil
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package epoch_processing
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/electra"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/spectest/utils"
|
||||
)
|
||||
|
||||
// RunRegistryUpdatesTests executes "epoch_processing/registry_updates" tests.
|
||||
func RunRegistryUpdatesTests(t *testing.T, config string) {
|
||||
require.NoError(t, utils.SetConfig(t, config))
|
||||
|
||||
testFolders, testsFolderPath := utils.TestFolders(t, config, "electra", "epoch_processing/registry_updates/pyspec_tests")
|
||||
for _, folder := range testFolders {
|
||||
t.Run(folder.Name(), func(t *testing.T) {
|
||||
// Important to clear cache for every test or else the old value of active validator count gets reused.
|
||||
helpers.ClearCache()
|
||||
folderPath := path.Join(testsFolderPath, folder.Name())
|
||||
RunEpochOperationTest(t, folderPath, processRegistryUpdatesWrapper)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func processRegistryUpdatesWrapper(_ *testing.T, state state.BeaconState) (state.BeaconState, error) {
|
||||
return electra.ProcessRegistryUpdates(context.Background(), state)
|
||||
}
|
||||
@@ -4,10 +4,12 @@ go_library(
|
||||
name = "go_default_library",
|
||||
testonly = True,
|
||||
srcs = [
|
||||
"attestation.go",
|
||||
"attester_slashing.go",
|
||||
"block_header.go",
|
||||
"bls_to_execution_changes.go",
|
||||
"consolidations.go",
|
||||
"deposit.go",
|
||||
"deposit_receipt.go",
|
||||
"execution_layer_withdrawal_request.go",
|
||||
"execution_payload.go",
|
||||
|
||||
56
testing/spectest/shared/electra/operations/attestation.go
Normal file
56
testing/spectest/shared/electra/operations/attestation.go
Normal file
@@ -0,0 +1,56 @@
|
||||
package operations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/snappy"
|
||||
b "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/blocks"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/electra"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/spectest/utils"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/util"
|
||||
)
|
||||
|
||||
func RunAttestationTest(t *testing.T, config string) {
|
||||
require.NoError(t, utils.SetConfig(t, config))
|
||||
testFolders, testsFolderPath := utils.TestFolders(t, config, "electra", "operations/attestation/pyspec_tests")
|
||||
for _, folder := range testFolders {
|
||||
t.Run(folder.Name(), func(t *testing.T) {
|
||||
folderPath := path.Join(testsFolderPath, folder.Name())
|
||||
attestationFile, err := util.BazelFileBytes(folderPath, "attestation.ssz_snappy")
|
||||
require.NoError(t, err)
|
||||
attestationSSZ, err := snappy.Decode(nil /* dst */, attestationFile)
|
||||
require.NoError(t, err, "Failed to decompress")
|
||||
att := ðpb.AttestationElectra{}
|
||||
require.NoError(t, att.UnmarshalSSZ(attestationSSZ), "Failed to unmarshal")
|
||||
|
||||
body := ðpb.BeaconBlockBodyElectra{Attestations: []*ethpb.AttestationElectra{att}}
|
||||
processAtt := func(ctx context.Context, st state.BeaconState, blk interfaces.SignedBeaconBlock) (state.BeaconState, error) {
|
||||
st, err = electra.ProcessAttestationsNoVerifySignature(ctx, st, blk.Block())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
aSet, err := b.AttestationSignatureBatch(ctx, st, blk.Block().Body().Attestations())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
verified, err := aSet.Verify()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !verified {
|
||||
return nil, errors.New("could not batch verify attestation signature")
|
||||
}
|
||||
return st, nil
|
||||
}
|
||||
|
||||
RunBlockOperationTest(t, folderPath, body, processAtt)
|
||||
})
|
||||
}
|
||||
}
|
||||
38
testing/spectest/shared/electra/operations/deposit.go
Normal file
38
testing/spectest/shared/electra/operations/deposit.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package operations
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/snappy"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/core/electra"
|
||||
"github.com/prysmaticlabs/prysm/v5/beacon-chain/state"
|
||||
"github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v5/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/spectest/utils"
|
||||
"github.com/prysmaticlabs/prysm/v5/testing/util"
|
||||
)
|
||||
|
||||
func RunDepositTest(t *testing.T, config string) {
|
||||
require.NoError(t, utils.SetConfig(t, config))
|
||||
testFolders, testsFolderPath := utils.TestFolders(t, config, "electra", "operations/deposit/pyspec_tests")
|
||||
for _, folder := range testFolders {
|
||||
t.Run(folder.Name(), func(t *testing.T) {
|
||||
folderPath := path.Join(testsFolderPath, folder.Name())
|
||||
depositFile, err := util.BazelFileBytes(folderPath, "deposit.ssz_snappy")
|
||||
require.NoError(t, err)
|
||||
depositSSZ, err := snappy.Decode(nil /* dst */, depositFile)
|
||||
require.NoError(t, err, "Failed to decompress")
|
||||
deposit := ðpb.Deposit{}
|
||||
require.NoError(t, deposit.UnmarshalSSZ(depositSSZ), "Failed to unmarshal")
|
||||
|
||||
body := ðpb.BeaconBlockBodyElectra{Deposits: []*ethpb.Deposit{deposit}}
|
||||
processDepositsFunc := func(ctx context.Context, s state.BeaconState, b interfaces.SignedBeaconBlock) (state.BeaconState, error) {
|
||||
return electra.ProcessDeposits(ctx, s, b.Block().Body().Deposits())
|
||||
}
|
||||
RunBlockOperationTest(t, folderPath, body, processDepositsFunc)
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user