Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Electra spec changes for v1.5.0-alpha.10 #6731

Open
wants to merge 6 commits into
base: unstable
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 19 additions & 9 deletions consensus/state_processing/src/per_block_processing.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::consensus_context::ConsensusContext;
use errors::{BlockOperationError, BlockProcessingError, HeaderInvalid};
use rayon::prelude::*;
use safe_arith::{ArithError, SafeArith};
use safe_arith::{ArithError, SafeArith, SafeArithIter};
use signature_sets::{block_proposal_signature_set, get_pubkey_from_state, randao_signature_set};
use std::borrow::Cow;
use tree_hash::TreeHash;
Expand Down Expand Up @@ -512,9 +512,9 @@ pub fn get_expected_withdrawals<E: EthSpec>(

// [New in Electra:EIP7251]
// Consume pending partial withdrawals
let partial_withdrawals_count =
let processed_partial_withdrawals_count =
if let Ok(partial_withdrawals) = state.pending_partial_withdrawals() {
let mut partial_withdrawals_count = 0;
let mut processed_partial_withdrawals_count = 0;
for withdrawal in partial_withdrawals {
if withdrawal.withdrawable_epoch > epoch
|| withdrawals.len() == spec.max_pending_partials_per_withdrawals_sweep as usize
Expand Down Expand Up @@ -547,9 +547,9 @@ pub fn get_expected_withdrawals<E: EthSpec>(
});
withdrawal_index.safe_add_assign(1)?;
}
partial_withdrawals_count.safe_add_assign(1)?;
processed_partial_withdrawals_count.safe_add_assign(1)?;
}
Some(partial_withdrawals_count)
Some(processed_partial_withdrawals_count)
} else {
None
};
Expand All @@ -560,9 +560,19 @@ pub fn get_expected_withdrawals<E: EthSpec>(
);
for _ in 0..bound {
let validator = state.get_validator(validator_index as usize)?;
let balance = *state.balances().get(validator_index as usize).ok_or(
BeaconStateError::BalancesOutOfBounds(validator_index as usize),
)?;
let partially_withdrawn_balance = withdrawals
.iter()
.filter_map(|withdrawal| {
(withdrawal.validator_index == validator_index).then_some(withdrawal.amount)
})
.safe_sum()?;
let balance = state
.balances()
.get(validator_index as usize)
.ok_or(BeaconStateError::BalancesOutOfBounds(
validator_index as usize,
))?
.safe_sub(partially_withdrawn_balance)?;
if validator.is_fully_withdrawable_at(balance, epoch, spec, fork_name) {
withdrawals.push(Withdrawal {
index: withdrawal_index,
Expand Down Expand Up @@ -594,7 +604,7 @@ pub fn get_expected_withdrawals<E: EthSpec>(
.safe_rem(state.validators().len() as u64)?;
}

Ok((withdrawals.into(), partial_withdrawals_count))
Ok((withdrawals.into(), processed_partial_withdrawals_count))
}

/// Apply withdrawals to the state.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -746,8 +746,8 @@ pub fn process_consolidation_request<E: EthSpec>(
}

let target_validator = state.get_validator(target_index)?;
// Verify the target has execution withdrawal credentials
if !target_validator.has_execution_withdrawal_credential(spec) {
// Verify the target has compounding withdrawal credentials
if !target_validator.has_compounding_withdrawal_credential(spec) {
return Ok(());
}

Expand All @@ -764,6 +764,18 @@ pub fn process_consolidation_request<E: EthSpec>(
{
return Ok(());
}
// Verify the source has been active long enough
if current_epoch
< source_validator
.activation_epoch
.safe_add(spec.shard_committee_period)?
{
return Ok(());
}
// Verify the source has no pending withdrawals in the queue
if state.get_pending_balance_to_withdraw(source_index)? > 0 {
return Ok(());
}

// Initiate source validator exit and append pending consolidation
let source_exit_epoch = state
Expand All @@ -779,10 +791,5 @@ pub fn process_consolidation_request<E: EthSpec>(
target_index: target_index as u64,
})?;

let target_validator = state.get_validator(target_index)?;
// Churn any target excess active balance of target and raise its max
if target_validator.has_eth1_withdrawal_credential(spec) {
state.switch_to_compounding_validator(target_index, spec)?;
}
Ok(())
}
Original file line number Diff line number Diff line change
Expand Up @@ -1057,14 +1057,12 @@ fn process_pending_consolidations<E: EthSpec>(
}

// Calculate the consolidated balance
let max_effective_balance =
source_validator.get_max_effective_balance(spec, state_ctxt.fork_name);
let source_effective_balance = std::cmp::min(
*state
.balances()
.get(source_index)
.ok_or(BeaconStateError::UnknownValidator(source_index))?,
max_effective_balance,
source_validator.effective_balance,
);

// Move active balance to target. Excess balance is withdrawable.
Expand Down
4 changes: 3 additions & 1 deletion consensus/state_processing/src/upgrade/electra.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@ pub fn upgrade_to_electra<E: EthSpec>(
) -> Result<(), Error> {
let epoch = pre_state.current_epoch();

let activation_exit_epoch = spec.compute_activation_exit_epoch(epoch)?;
let earliest_exit_epoch = pre_state
.validators()
.iter()
.filter(|v| v.exit_epoch != spec.far_future_epoch)
.map(|v| v.exit_epoch)
.max()
.unwrap_or(epoch)
.unwrap_or(activation_exit_epoch)
.max(activation_exit_epoch)
.safe_add(1)?;

// The total active balance cache must be built before the consolidation churn limit
Expand Down
2 changes: 1 addition & 1 deletion consensus/types/presets/gnosis/electra.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ MAX_ATTESTER_SLASHINGS_ELECTRA: 1
# `uint64(2**3)` (= 8)
MAX_ATTESTATIONS_ELECTRA: 8
# `uint64(2**0)` (= 1)
MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD: 1
MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD: 2

# Execution
# ---------------------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion consensus/types/presets/mainnet/electra.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ MAX_ATTESTER_SLASHINGS_ELECTRA: 1
# `uint64(2**3)` (= 8)
MAX_ATTESTATIONS_ELECTRA: 8
# `uint64(2**0)` (= 1)
MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD: 1
MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD: 2

# Execution
# ---------------------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion consensus/types/presets/minimal/electra.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ MAX_ATTESTER_SLASHINGS_ELECTRA: 1
# `uint64(2**3)` (= 8)
MAX_ATTESTATIONS_ELECTRA: 8
# `uint64(2**0)` (= 1)
MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD: 1
MAX_CONSOLIDATION_REQUESTS_PER_PAYLOAD: 2

# Execution
# ---------------------------------------------------------------
Expand Down
46 changes: 40 additions & 6 deletions consensus/types/src/beacon_state.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ mod tests;

pub const CACHED_EPOCHS: usize = 3;
const MAX_RANDOM_BYTE: u64 = (1 << 8) - 1;
const MAX_RANDOM_VALUE: u64 = (1 << 16) - 1;

pub type Validators<E> = List<Validator, <E as EthSpec>::ValidatorRegistryLimit>;
pub type Balances<E> = List<u64, <E as EthSpec>::ValidatorRegistryLimit>;
Expand Down Expand Up @@ -895,6 +896,11 @@ impl<E: EthSpec> BeaconState<E> {
}

let max_effective_balance = spec.max_effective_balance_for_fork(self.fork_name_unchecked());
let max_random_value = if self.fork_name_unchecked().electra_enabled() {
MAX_RANDOM_VALUE
} else {
MAX_RANDOM_BYTE
};

let mut i = 0;
loop {
Expand All @@ -908,17 +914,25 @@ impl<E: EthSpec> BeaconState<E> {
let candidate_index = *indices
.get(shuffled_index)
.ok_or(Error::ShuffleIndexOutOfBounds(shuffled_index))?;
let random_byte = Self::shuffling_random_byte(i, seed)?;
let random_value = self.shuffling_random_value(i, seed)?;
let effective_balance = self.get_effective_balance(candidate_index)?;
if effective_balance.safe_mul(MAX_RANDOM_BYTE)?
>= max_effective_balance.safe_mul(u64::from(random_byte))?
if effective_balance.safe_mul(max_random_value)?
>= max_effective_balance.safe_mul(random_value)?
{
return Ok(candidate_index);
}
i.safe_add_assign(1)?;
}
}

fn shuffling_random_value(&self, i: usize, seed: &[u8]) -> Result<u64, Error> {
if self.fork_name_unchecked().electra_enabled() {
Self::shuffling_random_u16_electra(i, seed).map(u64::from)
} else {
Self::shuffling_random_byte(i, seed).map(u64::from)
}
}

/// Get a random byte from the given `seed`.
///
/// Used by the proposer & sync committee selection functions.
Expand All @@ -932,6 +946,21 @@ impl<E: EthSpec> BeaconState<E> {
.ok_or(Error::ShuffleIndexOutOfBounds(index))
}

/// Get two random bytes from the given `seed`.
///
/// This is used in place of the
fn shuffling_random_u16_electra(i: usize, seed: &[u8]) -> Result<u16, Error> {
let mut preimage = seed.to_vec();
preimage.append(&mut int_to_bytes8(i.safe_div(16)? as u64));
let offset = i.safe_rem(16)?.safe_mul(2)?;
hash(&preimage)
.get(offset..offset.safe_add(2)?)
.ok_or(Error::ShuffleIndexOutOfBounds(offset))?
.try_into()
.map(u16::from_le_bytes)
.map_err(|_| Error::ShuffleIndexOutOfBounds(offset))
}

/// Convenience accessor for the `execution_payload_header` as an `ExecutionPayloadHeaderRef`.
pub fn latest_execution_payload_header(&self) -> Result<ExecutionPayloadHeaderRef<E>, Error> {
match self {
Expand Down Expand Up @@ -1093,6 +1122,11 @@ impl<E: EthSpec> BeaconState<E> {

let seed = self.get_seed(epoch, Domain::SyncCommittee, spec)?;
let max_effective_balance = spec.max_effective_balance_for_fork(self.fork_name_unchecked());
let max_random_value = if self.fork_name_unchecked().electra_enabled() {
MAX_RANDOM_VALUE
} else {
MAX_RANDOM_BYTE
};

let mut i = 0;
let mut sync_committee_indices = Vec::with_capacity(E::SyncCommitteeSize::to_usize());
Expand All @@ -1107,10 +1141,10 @@ impl<E: EthSpec> BeaconState<E> {
let candidate_index = *active_validator_indices
.get(shuffled_index)
.ok_or(Error::ShuffleIndexOutOfBounds(shuffled_index))?;
let random_byte = Self::shuffling_random_byte(i, seed.as_slice())?;
let random_value = self.shuffling_random_value(i, seed.as_slice())?;
let effective_balance = self.get_validator(candidate_index)?.effective_balance;
if effective_balance.safe_mul(MAX_RANDOM_BYTE)?
>= max_effective_balance.safe_mul(u64::from(random_byte))?
if effective_balance.safe_mul(max_random_value)?
>= max_effective_balance.safe_mul(random_value)?
{
sync_committee_indices.push(candidate_index);
}
Expand Down
4 changes: 2 additions & 2 deletions consensus/types/src/eth_spec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@ impl EthSpec for MainnetEthSpec {
type PendingDepositsLimit = U134217728;
type PendingPartialWithdrawalsLimit = U134217728;
type PendingConsolidationsLimit = U262144;
type MaxConsolidationRequestsPerPayload = U1;
type MaxConsolidationRequestsPerPayload = U2;
type MaxDepositRequestsPerPayload = U8192;
type MaxAttesterSlashingsElectra = U1;
type MaxAttestationsElectra = U8;
Expand Down Expand Up @@ -568,7 +568,7 @@ impl EthSpec for GnosisEthSpec {
type PendingDepositsLimit = U134217728;
type PendingPartialWithdrawalsLimit = U134217728;
type PendingConsolidationsLimit = U262144;
type MaxConsolidationRequestsPerPayload = U1;
type MaxConsolidationRequestsPerPayload = U2;
type MaxDepositRequestsPerPayload = U8192;
type MaxAttesterSlashingsElectra = U1;
type MaxAttestationsElectra = U8;
Expand Down
2 changes: 1 addition & 1 deletion testing/ef_tests/Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
TESTS_TAG := v1.5.0-alpha.8
TESTS_TAG := v1.5.0-alpha.10
TESTS = general minimal mainnet
TARBALLS = $(patsubst %,%-$(TESTS_TAG).tar.gz,$(TESTS))

Expand Down
Loading