mirror of
https://github.com/sigp/lighthouse.git
synced 2026-06-29 10:54:24 +00:00
Merge branch 'empty-requests' of https://github.com/pawanjay176/lighthouse into electra-devnet-5
This commit is contained in:
@@ -7,7 +7,7 @@ use superstruct::superstruct;
|
||||
use types::beacon_block_body::KzgCommitments;
|
||||
use types::blob_sidecar::BlobsList;
|
||||
use types::execution_requests::{
|
||||
ConsolidationRequests, DepositRequests, RequestPrefix, WithdrawalRequests,
|
||||
ConsolidationRequests, DepositRequests, RequestType, WithdrawalRequests,
|
||||
};
|
||||
use types::{Blob, FixedVector, KzgProof, Unsigned};
|
||||
|
||||
@@ -341,47 +341,80 @@ impl<E: EthSpec> From<JsonExecutionPayload<E>> for ExecutionPayload<E> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum RequestsError {
|
||||
InvalidHex(hex::FromHexError),
|
||||
EmptyRequest(usize),
|
||||
InvalidOrdering,
|
||||
InvalidPrefix(u8),
|
||||
DecodeError(String),
|
||||
}
|
||||
|
||||
/// Format of `ExecutionRequests` received over the engine api.
|
||||
///
|
||||
/// Array of ssz-encoded requests list encoded as hex bytes.
|
||||
/// The prefix of the request type is used to index into the array.
|
||||
///
|
||||
/// For e.g. [0xab, 0xcd, 0xef]
|
||||
/// Here, 0xab are the deposits bytes (prefix and index == 0)
|
||||
/// 0xcd are the withdrawals bytes (prefix and index == 1)
|
||||
/// 0xef are the consolidations bytes (prefix and index == 2)
|
||||
/// Array of ssz-encoded requests list encoded as hex bytes prefixed
|
||||
/// with a `RequestType`
|
||||
#[derive(Debug, Default, Clone, PartialEq, Serialize, Deserialize)]
|
||||
#[serde(transparent)]
|
||||
pub struct JsonExecutionRequests(pub Vec<String>);
|
||||
|
||||
impl<E: EthSpec> TryFrom<JsonExecutionRequests> for ExecutionRequests<E> {
|
||||
type Error = String;
|
||||
type Error = RequestsError;
|
||||
|
||||
fn try_from(value: JsonExecutionRequests) -> Result<Self, Self::Error> {
|
||||
let mut requests = ExecutionRequests::default();
|
||||
|
||||
let mut prev_prefix: Option<RequestType> = None;
|
||||
for (i, request) in value.0.into_iter().enumerate() {
|
||||
// hex string
|
||||
let decoded_bytes = hex::decode(request.strip_prefix("0x").unwrap_or(&request))
|
||||
.map_err(|e| format!("Invalid hex {:?}", e))?;
|
||||
match RequestPrefix::from_prefix(i as u8) {
|
||||
Some(RequestPrefix::Deposit) => {
|
||||
requests.deposits = DepositRequests::<E>::from_ssz_bytes(&decoded_bytes)
|
||||
.map_err(|e| format!("Failed to decode DepositRequest from EL: {:?}", e))?;
|
||||
.map_err(RequestsError::InvalidHex)?;
|
||||
|
||||
// The first byte of each element is the `request_type` and the remaining bytes are the `request_data`.
|
||||
// Elements with empty `request_data` **MUST** be excluded from the list.
|
||||
let Some((prefix_byte, request_bytes)) = decoded_bytes.split_first() else {
|
||||
return Err(RequestsError::EmptyRequest(i));
|
||||
};
|
||||
if request_bytes.is_empty() {
|
||||
return Err(RequestsError::EmptyRequest(i));
|
||||
}
|
||||
// Elements of the list **MUST** be ordered by `request_type` in ascending order
|
||||
let current_prefix = RequestType::from_u8(*prefix_byte)
|
||||
.ok_or(RequestsError::InvalidPrefix(*prefix_byte))?;
|
||||
if let Some(prev) = prev_prefix {
|
||||
if prev.to_u8() >= current_prefix.to_u8() {
|
||||
return Err(RequestsError::InvalidOrdering);
|
||||
}
|
||||
Some(RequestPrefix::Withdrawal) => {
|
||||
requests.withdrawals = WithdrawalRequests::<E>::from_ssz_bytes(&decoded_bytes)
|
||||
}
|
||||
prev_prefix = Some(current_prefix);
|
||||
|
||||
match current_prefix {
|
||||
RequestType::Deposit => {
|
||||
requests.deposits = DepositRequests::<E>::from_ssz_bytes(request_bytes)
|
||||
.map_err(|e| {
|
||||
format!("Failed to decode WithdrawalRequest from EL: {:?}", e)
|
||||
RequestsError::DecodeError(format!(
|
||||
"Failed to decode DepositRequest from EL: {:?}",
|
||||
e
|
||||
))
|
||||
})?;
|
||||
}
|
||||
Some(RequestPrefix::Consolidation) => {
|
||||
requests.consolidations =
|
||||
ConsolidationRequests::<E>::from_ssz_bytes(&decoded_bytes).map_err(
|
||||
|e| format!("Failed to decode ConsolidationRequest from EL: {:?}", e),
|
||||
)?;
|
||||
RequestType::Withdrawal => {
|
||||
requests.withdrawals = WithdrawalRequests::<E>::from_ssz_bytes(request_bytes)
|
||||
.map_err(|e| {
|
||||
RequestsError::DecodeError(format!(
|
||||
"Failed to decode WithdrawalRequest from EL: {:?}",
|
||||
e
|
||||
))
|
||||
})?;
|
||||
}
|
||||
RequestType::Consolidation => {
|
||||
requests.consolidations =
|
||||
ConsolidationRequests::<E>::from_ssz_bytes(request_bytes).map_err(|e| {
|
||||
RequestsError::DecodeError(format!(
|
||||
"Failed to decode ConsolidationRequest from EL: {:?}",
|
||||
e
|
||||
))
|
||||
})?;
|
||||
}
|
||||
None => return Err("Empty requests string".to_string()),
|
||||
}
|
||||
}
|
||||
Ok(requests)
|
||||
@@ -448,7 +481,9 @@ impl<E: EthSpec> TryFrom<JsonGetPayloadResponse<E>> for GetPayloadResponse<E> {
|
||||
block_value: response.block_value,
|
||||
blobs_bundle: response.blobs_bundle.into(),
|
||||
should_override_builder: response.should_override_builder,
|
||||
requests: response.execution_requests.try_into()?,
|
||||
requests: response.execution_requests.try_into().map_err(|e| {
|
||||
format!("Failed to convert json to execution requests : {:?}", e)
|
||||
})?,
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,6 +121,11 @@ impl<'block, E: EthSpec> NewPayloadRequest<'block, E> {
|
||||
|
||||
let _timer = metrics::start_timer(&metrics::EXECUTION_LAYER_VERIFY_BLOCK_HASH);
|
||||
|
||||
// Check that no transactions in the payload are zero length
|
||||
if payload.transactions().iter().any(|slice| slice.is_empty()) {
|
||||
return Err(Error::ZeroLengthTransaction);
|
||||
}
|
||||
|
||||
let (header_hash, rlp_transactions_root) = calculate_execution_block_hash(
|
||||
payload,
|
||||
parent_beacon_block_root,
|
||||
|
||||
@@ -149,6 +149,7 @@ pub enum Error {
|
||||
payload: ExecutionBlockHash,
|
||||
transactions_root: Hash256,
|
||||
},
|
||||
ZeroLengthTransaction,
|
||||
PayloadBodiesByRangeNotSupported,
|
||||
InvalidJWTSecret(String),
|
||||
InvalidForkForPayload,
|
||||
|
||||
@@ -1226,6 +1226,10 @@ async fn progressive_balances_cache_attester_slashing() {
|
||||
.apply_blocks_while(|_, state| state.finalized_checkpoint().epoch == 0)
|
||||
.await
|
||||
.unwrap()
|
||||
// TODO(electra) The shuffling calculations changed between Altair and Electra. Without
|
||||
// skipping slots this test breaks. For some reason `fork_name_unchecked` returns Altair
|
||||
// initially, even though this test harness should be initialized with the most recent fork, i.e. Electra
|
||||
.skip_slots(32)
|
||||
// Note: This test may fail if the shuffling used changes, right now it re-runs with
|
||||
// deterministic shuffling. A shuffling change my cause the slashed proposer to propose
|
||||
// again in the next epoch, which results in a block processing failure
|
||||
|
||||
@@ -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;
|
||||
@@ -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
|
||||
@@ -522,8 +522,8 @@ pub fn get_expected_withdrawals<E: EthSpec>(
|
||||
break;
|
||||
}
|
||||
|
||||
let withdrawal_balance = state.get_balance(withdrawal.index as usize)?;
|
||||
let validator = state.get_validator(withdrawal.index as usize)?;
|
||||
let withdrawal_balance = state.get_balance(withdrawal.validator_index as usize)?;
|
||||
let validator = state.get_validator(withdrawal.validator_index as usize)?;
|
||||
|
||||
let has_sufficient_effective_balance =
|
||||
validator.effective_balance >= spec.min_activation_balance;
|
||||
@@ -539,7 +539,7 @@ pub fn get_expected_withdrawals<E: EthSpec>(
|
||||
);
|
||||
withdrawals.push(Withdrawal {
|
||||
index: withdrawal_index,
|
||||
validator_index: withdrawal.index,
|
||||
validator_index: withdrawal.validator_index,
|
||||
address: validator
|
||||
.get_execution_withdrawal_address(spec)
|
||||
.ok_or(BeaconStateError::NonExecutionAddresWithdrawalCredential)?,
|
||||
@@ -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
|
||||
};
|
||||
@@ -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,
|
||||
@@ -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.
|
||||
|
||||
@@ -514,11 +514,11 @@ pub fn process_withdrawal_requests<E: EthSpec>(
|
||||
}
|
||||
|
||||
// Verify pubkey exists
|
||||
let Some(index) = state.pubkey_cache().get(&request.validator_pubkey) else {
|
||||
let Some(validator_index) = state.pubkey_cache().get(&request.validator_pubkey) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
let validator = state.get_validator(index)?;
|
||||
let validator = state.get_validator(validator_index)?;
|
||||
// Verify withdrawal credentials
|
||||
let has_correct_credential = validator.has_execution_withdrawal_credential(spec);
|
||||
let is_correct_source_address = validator
|
||||
@@ -549,16 +549,16 @@ pub fn process_withdrawal_requests<E: EthSpec>(
|
||||
continue;
|
||||
}
|
||||
|
||||
let pending_balance_to_withdraw = state.get_pending_balance_to_withdraw(index)?;
|
||||
let pending_balance_to_withdraw = state.get_pending_balance_to_withdraw(validator_index)?;
|
||||
if is_full_exit_request {
|
||||
// Only exit validator if it has no pending withdrawals in the queue
|
||||
if pending_balance_to_withdraw == 0 {
|
||||
initiate_validator_exit(state, index, spec)?
|
||||
initiate_validator_exit(state, validator_index, spec)?
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
let balance = state.get_balance(index)?;
|
||||
let balance = state.get_balance(validator_index)?;
|
||||
let has_sufficient_effective_balance =
|
||||
validator.effective_balance >= spec.min_activation_balance;
|
||||
let has_excess_balance = balance
|
||||
@@ -583,7 +583,7 @@ pub fn process_withdrawal_requests<E: EthSpec>(
|
||||
state
|
||||
.pending_partial_withdrawals_mut()?
|
||||
.push(PendingPartialWithdrawal {
|
||||
index: index as u64,
|
||||
validator_index: validator_index as u64,
|
||||
amount: to_withdraw,
|
||||
withdrawable_epoch,
|
||||
})?;
|
||||
@@ -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(());
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -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(())
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
# ---------------------------------------------------------------
|
||||
|
||||
@@ -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
|
||||
# ---------------------------------------------------------------
|
||||
|
||||
@@ -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
|
||||
# ---------------------------------------------------------------
|
||||
|
||||
@@ -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>;
|
||||
@@ -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 {
|
||||
@@ -908,10 +914,10 @@ 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);
|
||||
}
|
||||
@@ -919,6 +925,14 @@ impl<E: EthSpec> BeaconState<E> {
|
||||
}
|
||||
}
|
||||
|
||||
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.
|
||||
@@ -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 {
|
||||
@@ -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());
|
||||
@@ -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);
|
||||
}
|
||||
@@ -2159,7 +2193,7 @@ impl<E: EthSpec> BeaconState<E> {
|
||||
for withdrawal in self
|
||||
.pending_partial_withdrawals()?
|
||||
.iter()
|
||||
.filter(|withdrawal| withdrawal.index as usize == validator_index)
|
||||
.filter(|withdrawal| withdrawal.validator_index as usize == validator_index)
|
||||
{
|
||||
pending_balance.safe_add_assign(withdrawal.amount)?;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
|
||||
@@ -43,10 +43,29 @@ impl<E: EthSpec> ExecutionRequests<E> {
|
||||
/// Returns the encoding according to EIP-7685 to send
|
||||
/// to the execution layer over the engine api.
|
||||
pub fn get_execution_requests_list(&self) -> Vec<Bytes> {
|
||||
let deposit_bytes = Bytes::from(self.deposits.as_ssz_bytes());
|
||||
let withdrawal_bytes = Bytes::from(self.withdrawals.as_ssz_bytes());
|
||||
let consolidation_bytes = Bytes::from(self.consolidations.as_ssz_bytes());
|
||||
vec![deposit_bytes, withdrawal_bytes, consolidation_bytes]
|
||||
let mut requests_list = Vec::new();
|
||||
if !self.deposits.is_empty() {
|
||||
requests_list.push(Bytes::from_iter(
|
||||
[RequestType::Deposit.to_u8()]
|
||||
.into_iter()
|
||||
.chain(self.deposits.as_ssz_bytes()),
|
||||
));
|
||||
}
|
||||
if !self.withdrawals.is_empty() {
|
||||
requests_list.push(Bytes::from_iter(
|
||||
[RequestType::Withdrawal.to_u8()]
|
||||
.into_iter()
|
||||
.chain(self.withdrawals.as_ssz_bytes()),
|
||||
));
|
||||
}
|
||||
if !self.consolidations.is_empty() {
|
||||
requests_list.push(Bytes::from_iter(
|
||||
[RequestType::Consolidation.to_u8()]
|
||||
.into_iter()
|
||||
.chain(self.consolidations.as_ssz_bytes()),
|
||||
));
|
||||
}
|
||||
requests_list
|
||||
}
|
||||
|
||||
/// Generate the execution layer `requests_hash` based on EIP-7685.
|
||||
@@ -55,9 +74,8 @@ impl<E: EthSpec> ExecutionRequests<E> {
|
||||
pub fn requests_hash(&self) -> Hash256 {
|
||||
let mut hasher = DynamicContext::new();
|
||||
|
||||
for (i, request) in self.get_execution_requests_list().iter().enumerate() {
|
||||
for request in self.get_execution_requests_list().iter() {
|
||||
let mut request_hasher = DynamicContext::new();
|
||||
request_hasher.update(&[i as u8]);
|
||||
request_hasher.update(request);
|
||||
let request_hash = request_hasher.finalize();
|
||||
|
||||
@@ -68,16 +86,16 @@ impl<E: EthSpec> ExecutionRequests<E> {
|
||||
}
|
||||
}
|
||||
|
||||
/// This is used to index into the `execution_requests` array.
|
||||
/// The prefix types for `ExecutionRequest` objects.
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum RequestPrefix {
|
||||
pub enum RequestType {
|
||||
Deposit,
|
||||
Withdrawal,
|
||||
Consolidation,
|
||||
}
|
||||
|
||||
impl RequestPrefix {
|
||||
pub fn from_prefix(prefix: u8) -> Option<Self> {
|
||||
impl RequestType {
|
||||
pub fn from_u8(prefix: u8) -> Option<Self> {
|
||||
match prefix {
|
||||
0 => Some(Self::Deposit),
|
||||
1 => Some(Self::Withdrawal),
|
||||
@@ -85,6 +103,13 @@ impl RequestPrefix {
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
pub fn to_u8(&self) -> u8 {
|
||||
match self {
|
||||
Self::Deposit => 0,
|
||||
Self::Withdrawal => 1,
|
||||
Self::Consolidation => 2,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -170,7 +170,7 @@ pub use crate::execution_payload_header::{
|
||||
ExecutionPayloadHeaderDeneb, ExecutionPayloadHeaderElectra, ExecutionPayloadHeaderRef,
|
||||
ExecutionPayloadHeaderRefMut,
|
||||
};
|
||||
pub use crate::execution_requests::{ExecutionRequests, RequestPrefix};
|
||||
pub use crate::execution_requests::{ExecutionRequests, RequestType};
|
||||
pub use crate::fork::Fork;
|
||||
pub use crate::fork_context::ForkContext;
|
||||
pub use crate::fork_data::ForkData;
|
||||
|
||||
@@ -21,7 +21,7 @@ use tree_hash_derive::TreeHash;
|
||||
)]
|
||||
pub struct PendingPartialWithdrawal {
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
pub index: u64,
|
||||
pub validator_index: u64,
|
||||
#[serde(with = "serde_utils::quoted_u64")]
|
||||
pub amount: u64,
|
||||
pub withdrawable_epoch: Epoch,
|
||||
|
||||
@@ -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))
|
||||
|
||||
|
||||
Reference in New Issue
Block a user