Bounded withdrawals and spec v1.3.0-alpha.2 (#3802)
This commit is contained in:
parent
37f735058a
commit
558367ab8c
@ -466,7 +466,9 @@ pub fn compute_timestamp_at_slot<T: EthSpec>(
|
|||||||
.and_then(|since_genesis| state.genesis_time().safe_add(since_genesis))
|
.and_then(|since_genesis| state.genesis_time().safe_add(since_genesis))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// FIXME: add link to this function once the spec is stable
|
/// Compute the next batch of withdrawals which should be included in a block.
|
||||||
|
///
|
||||||
|
/// https://github.com/ethereum/consensus-specs/blob/dev/specs/capella/beacon-chain.md#new-get_expected_withdrawals
|
||||||
#[cfg(feature = "withdrawals")]
|
#[cfg(feature = "withdrawals")]
|
||||||
pub fn get_expected_withdrawals<T: EthSpec>(
|
pub fn get_expected_withdrawals<T: EthSpec>(
|
||||||
state: &BeaconState<T>,
|
state: &BeaconState<T>,
|
||||||
@ -481,7 +483,11 @@ pub fn get_expected_withdrawals<T: EthSpec>(
|
|||||||
return Ok(withdrawals.into());
|
return Ok(withdrawals.into());
|
||||||
}
|
}
|
||||||
|
|
||||||
for _ in 0..state.validators().len() {
|
let bound = std::cmp::min(
|
||||||
|
state.validators().len() as u64,
|
||||||
|
spec.max_validators_per_withdrawals_sweep,
|
||||||
|
);
|
||||||
|
for _ in 0..bound {
|
||||||
let validator = state.get_validator(validator_index as usize)?;
|
let validator = state.get_validator(validator_index as usize)?;
|
||||||
let balance = *state.balances().get(validator_index as usize).ok_or(
|
let balance = *state.balances().get(validator_index as usize).ok_or(
|
||||||
BeaconStateError::BalancesOutOfBounds(validator_index as usize),
|
BeaconStateError::BalancesOutOfBounds(validator_index as usize),
|
||||||
@ -518,7 +524,7 @@ pub fn get_expected_withdrawals<T: EthSpec>(
|
|||||||
Ok(withdrawals.into())
|
Ok(withdrawals.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// FIXME: add link to this function once the spec is stable
|
/// Apply withdrawals to the state.
|
||||||
#[cfg(all(feature = "withdrawals", feature = "withdrawals-processing"))]
|
#[cfg(all(feature = "withdrawals", feature = "withdrawals-processing"))]
|
||||||
pub fn process_withdrawals<'payload, T: EthSpec, Payload: AbstractExecPayload<T>>(
|
pub fn process_withdrawals<'payload, T: EthSpec, Payload: AbstractExecPayload<T>>(
|
||||||
state: &mut BeaconState<T>,
|
state: &mut BeaconState<T>,
|
||||||
@ -547,11 +553,26 @@ pub fn process_withdrawals<'payload, T: EthSpec, Payload: AbstractExecPayload<T>
|
|||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update the next withdrawal index if this block contained withdrawals
|
||||||
if let Some(latest_withdrawal) = expected_withdrawals.last() {
|
if let Some(latest_withdrawal) = expected_withdrawals.last() {
|
||||||
*state.next_withdrawal_index_mut()? = latest_withdrawal.index.safe_add(1)?;
|
*state.next_withdrawal_index_mut()? = latest_withdrawal.index.safe_add(1)?;
|
||||||
let next_validator_index = latest_withdrawal
|
|
||||||
.validator_index
|
// Update the next validator index to start the next withdrawal sweep
|
||||||
.safe_add(1)?
|
if expected_withdrawals.len() == T::max_withdrawals_per_payload() {
|
||||||
|
// Next sweep starts after the latest withdrawal's validator index
|
||||||
|
let next_validator_index = latest_withdrawal
|
||||||
|
.validator_index
|
||||||
|
.safe_add(1)?
|
||||||
|
.safe_rem(state.validators().len() as u64)?;
|
||||||
|
*state.next_withdrawal_validator_index_mut()? = next_validator_index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Advance sweep by the max length of the sweep if there was not a full set of withdrawals
|
||||||
|
if expected_withdrawals.len() != T::max_withdrawals_per_payload() {
|
||||||
|
let next_validator_index = state
|
||||||
|
.next_withdrawal_validator_index()?
|
||||||
|
.safe_add(spec.max_validators_per_withdrawals_sweep)?
|
||||||
.safe_rem(state.validators().len() as u64)?;
|
.safe_rem(state.validators().len() as u64)?;
|
||||||
*state.next_withdrawal_validator_index_mut()? = next_validator_index;
|
*state.next_withdrawal_validator_index_mut()? = next_validator_index;
|
||||||
}
|
}
|
||||||
|
17
consensus/types/presets/gnosis/capella.yaml
Normal file
17
consensus/types/presets/gnosis/capella.yaml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
# Mainnet preset - Capella
|
||||||
|
|
||||||
|
# Misc
|
||||||
|
# Max operations per block
|
||||||
|
# ---------------------------------------------------------------
|
||||||
|
# 2**4 (= 16)
|
||||||
|
MAX_BLS_TO_EXECUTION_CHANGES: 16
|
||||||
|
|
||||||
|
# Execution
|
||||||
|
# ---------------------------------------------------------------
|
||||||
|
# 2**4 (= 16) withdrawals
|
||||||
|
MAX_WITHDRAWALS_PER_PAYLOAD: 16
|
||||||
|
|
||||||
|
# Withdrawals processing
|
||||||
|
# ---------------------------------------------------------------
|
||||||
|
# 2**14 (= 16384) validators
|
||||||
|
MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP: 16384
|
@ -9,4 +9,9 @@ MAX_BLS_TO_EXECUTION_CHANGES: 16
|
|||||||
# Execution
|
# Execution
|
||||||
# ---------------------------------------------------------------
|
# ---------------------------------------------------------------
|
||||||
# 2**4 (= 16) withdrawals
|
# 2**4 (= 16) withdrawals
|
||||||
MAX_WITHDRAWALS_PER_PAYLOAD: 16
|
MAX_WITHDRAWALS_PER_PAYLOAD: 16
|
||||||
|
|
||||||
|
# Withdrawals processing
|
||||||
|
# ---------------------------------------------------------------
|
||||||
|
# 2**14 (= 16384) validators
|
||||||
|
MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP: 16384
|
||||||
|
@ -9,4 +9,9 @@ MAX_BLS_TO_EXECUTION_CHANGES: 16
|
|||||||
# Execution
|
# Execution
|
||||||
# ---------------------------------------------------------------
|
# ---------------------------------------------------------------
|
||||||
# [customized] 2**2 (= 4)
|
# [customized] 2**2 (= 4)
|
||||||
MAX_WITHDRAWALS_PER_PAYLOAD: 4
|
MAX_WITHDRAWALS_PER_PAYLOAD: 4
|
||||||
|
|
||||||
|
# Withdrawals processing
|
||||||
|
# ---------------------------------------------------------------
|
||||||
|
# [customized] 2**4 (= 16) validators
|
||||||
|
MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP: 16
|
||||||
|
@ -158,8 +158,9 @@ pub struct ChainSpec {
|
|||||||
* Capella hard fork params
|
* Capella hard fork params
|
||||||
*/
|
*/
|
||||||
pub capella_fork_version: [u8; 4],
|
pub capella_fork_version: [u8; 4],
|
||||||
/// The Capella fork epoch is optional, with `None` representing "Merge never happens".
|
/// The Capella fork epoch is optional, with `None` representing "Capella never happens".
|
||||||
pub capella_fork_epoch: Option<Epoch>,
|
pub capella_fork_epoch: Option<Epoch>,
|
||||||
|
pub max_validators_per_withdrawals_sweep: u64,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Eip4844 hard fork params
|
* Eip4844 hard fork params
|
||||||
@ -634,6 +635,7 @@ impl ChainSpec {
|
|||||||
*/
|
*/
|
||||||
capella_fork_version: [0x03, 00, 00, 00],
|
capella_fork_version: [0x03, 00, 00, 00],
|
||||||
capella_fork_epoch: None,
|
capella_fork_epoch: None,
|
||||||
|
max_validators_per_withdrawals_sweep: 16384,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Eip4844 hard fork params
|
* Eip4844 hard fork params
|
||||||
@ -707,6 +709,7 @@ impl ChainSpec {
|
|||||||
// Capella
|
// Capella
|
||||||
capella_fork_version: [0x03, 0x00, 0x00, 0x01],
|
capella_fork_version: [0x03, 0x00, 0x00, 0x01],
|
||||||
capella_fork_epoch: None,
|
capella_fork_epoch: None,
|
||||||
|
max_validators_per_withdrawals_sweep: 16,
|
||||||
// Eip4844
|
// Eip4844
|
||||||
eip4844_fork_version: [0x04, 0x00, 0x00, 0x01],
|
eip4844_fork_version: [0x04, 0x00, 0x00, 0x01],
|
||||||
eip4844_fork_epoch: None,
|
eip4844_fork_epoch: None,
|
||||||
@ -869,6 +872,7 @@ impl ChainSpec {
|
|||||||
*/
|
*/
|
||||||
capella_fork_version: [0x03, 0x00, 0x00, 0x64],
|
capella_fork_version: [0x03, 0x00, 0x00, 0x64],
|
||||||
capella_fork_epoch: None,
|
capella_fork_epoch: None,
|
||||||
|
max_validators_per_withdrawals_sweep: 16384,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Eip4844 hard fork params
|
* Eip4844 hard fork params
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
consts::altair, AltairPreset, BasePreset, BellatrixPreset, ChainSpec, Config, EthSpec, ForkName,
|
consts::altair, AltairPreset, BasePreset, BellatrixPreset, CapellaPreset, ChainSpec, Config,
|
||||||
|
EthSpec, ForkName,
|
||||||
};
|
};
|
||||||
use maplit::hashmap;
|
use maplit::hashmap;
|
||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
@ -11,7 +12,7 @@ use superstruct::superstruct;
|
|||||||
///
|
///
|
||||||
/// Mostly useful for the API.
|
/// Mostly useful for the API.
|
||||||
#[superstruct(
|
#[superstruct(
|
||||||
variants(Altair, Bellatrix),
|
variants(Bellatrix, Capella),
|
||||||
variant_attributes(derive(Serialize, Deserialize, Debug, PartialEq, Clone))
|
variant_attributes(derive(Serialize, Deserialize, Debug, PartialEq, Clone))
|
||||||
)]
|
)]
|
||||||
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
|
||||||
@ -24,9 +25,10 @@ pub struct ConfigAndPreset {
|
|||||||
pub base_preset: BasePreset,
|
pub base_preset: BasePreset,
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub altair_preset: AltairPreset,
|
pub altair_preset: AltairPreset,
|
||||||
#[superstruct(only(Bellatrix))]
|
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub bellatrix_preset: BellatrixPreset,
|
pub bellatrix_preset: BellatrixPreset,
|
||||||
|
#[superstruct(only(Capella))]
|
||||||
|
pub capella_preset: CapellaPreset,
|
||||||
/// The `extra_fields` map allows us to gracefully decode fields intended for future hard forks.
|
/// The `extra_fields` map allows us to gracefully decode fields intended for future hard forks.
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub extra_fields: HashMap<String, Value>,
|
pub extra_fields: HashMap<String, Value>,
|
||||||
@ -37,14 +39,24 @@ impl ConfigAndPreset {
|
|||||||
let config = Config::from_chain_spec::<T>(spec);
|
let config = Config::from_chain_spec::<T>(spec);
|
||||||
let base_preset = BasePreset::from_chain_spec::<T>(spec);
|
let base_preset = BasePreset::from_chain_spec::<T>(spec);
|
||||||
let altair_preset = AltairPreset::from_chain_spec::<T>(spec);
|
let altair_preset = AltairPreset::from_chain_spec::<T>(spec);
|
||||||
|
let bellatrix_preset = BellatrixPreset::from_chain_spec::<T>(spec);
|
||||||
let extra_fields = get_extra_fields(spec);
|
let extra_fields = get_extra_fields(spec);
|
||||||
|
|
||||||
if spec.bellatrix_fork_epoch.is_some()
|
if spec.capella_fork_epoch.is_some()
|
||||||
|| fork_name.is_none()
|
|| fork_name.is_none()
|
||||||
|| fork_name == Some(ForkName::Merge)
|
|| fork_name == Some(ForkName::Capella)
|
||||||
{
|
{
|
||||||
let bellatrix_preset = BellatrixPreset::from_chain_spec::<T>(spec);
|
let capella_preset = CapellaPreset::from_chain_spec::<T>(spec);
|
||||||
|
|
||||||
|
ConfigAndPreset::Capella(ConfigAndPresetCapella {
|
||||||
|
config,
|
||||||
|
base_preset,
|
||||||
|
altair_preset,
|
||||||
|
bellatrix_preset,
|
||||||
|
capella_preset,
|
||||||
|
extra_fields,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
ConfigAndPreset::Bellatrix(ConfigAndPresetBellatrix {
|
ConfigAndPreset::Bellatrix(ConfigAndPresetBellatrix {
|
||||||
config,
|
config,
|
||||||
base_preset,
|
base_preset,
|
||||||
@ -52,13 +64,6 @@ impl ConfigAndPreset {
|
|||||||
bellatrix_preset,
|
bellatrix_preset,
|
||||||
extra_fields,
|
extra_fields,
|
||||||
})
|
})
|
||||||
} else {
|
|
||||||
ConfigAndPreset::Altair(ConfigAndPresetAltair {
|
|
||||||
config,
|
|
||||||
base_preset,
|
|
||||||
altair_preset,
|
|
||||||
extra_fields,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -131,8 +136,8 @@ mod test {
|
|||||||
.write(false)
|
.write(false)
|
||||||
.open(tmp_file.as_ref())
|
.open(tmp_file.as_ref())
|
||||||
.expect("error while opening the file");
|
.expect("error while opening the file");
|
||||||
let from: ConfigAndPresetBellatrix =
|
let from: ConfigAndPresetCapella =
|
||||||
serde_yaml::from_reader(reader).expect("error while deserializing");
|
serde_yaml::from_reader(reader).expect("error while deserializing");
|
||||||
assert_eq!(ConfigAndPreset::Bellatrix(from), yamlconfig);
|
assert_eq!(ConfigAndPreset::Capella(from), yamlconfig);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -124,7 +124,7 @@ pub use crate::bls_to_execution_change::BlsToExecutionChange;
|
|||||||
pub use crate::chain_spec::{ChainSpec, Config, Domain};
|
pub use crate::chain_spec::{ChainSpec, Config, Domain};
|
||||||
pub use crate::checkpoint::Checkpoint;
|
pub use crate::checkpoint::Checkpoint;
|
||||||
pub use crate::config_and_preset::{
|
pub use crate::config_and_preset::{
|
||||||
ConfigAndPreset, ConfigAndPresetAltair, ConfigAndPresetBellatrix,
|
ConfigAndPreset, ConfigAndPresetBellatrix, ConfigAndPresetCapella,
|
||||||
};
|
};
|
||||||
pub use crate::contribution_and_proof::ContributionAndProof;
|
pub use crate::contribution_and_proof::ContributionAndProof;
|
||||||
pub use crate::deposit::{Deposit, DEPOSIT_TREE_DEPTH};
|
pub use crate::deposit::{Deposit, DEPOSIT_TREE_DEPTH};
|
||||||
@ -163,7 +163,7 @@ pub use crate::payload::{
|
|||||||
FullPayloadCapella, FullPayloadEip4844, FullPayloadMerge, FullPayloadRef, OwnedExecPayload,
|
FullPayloadCapella, FullPayloadEip4844, FullPayloadMerge, FullPayloadRef, OwnedExecPayload,
|
||||||
};
|
};
|
||||||
pub use crate::pending_attestation::PendingAttestation;
|
pub use crate::pending_attestation::PendingAttestation;
|
||||||
pub use crate::preset::{AltairPreset, BasePreset, BellatrixPreset};
|
pub use crate::preset::{AltairPreset, BasePreset, BellatrixPreset, CapellaPreset};
|
||||||
pub use crate::proposer_preparation_data::ProposerPreparationData;
|
pub use crate::proposer_preparation_data::ProposerPreparationData;
|
||||||
pub use crate::proposer_slashing::ProposerSlashing;
|
pub use crate::proposer_slashing::ProposerSlashing;
|
||||||
pub use crate::relative_epoch::{Error as RelativeEpochError, RelativeEpoch};
|
pub use crate::relative_epoch::{Error as RelativeEpochError, RelativeEpoch};
|
||||||
|
@ -184,6 +184,27 @@ impl BellatrixPreset {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "UPPERCASE")]
|
||||||
|
pub struct CapellaPreset {
|
||||||
|
#[serde(with = "eth2_serde_utils::quoted_u64")]
|
||||||
|
pub max_bls_to_execution_changes: u64,
|
||||||
|
#[serde(with = "eth2_serde_utils::quoted_u64")]
|
||||||
|
pub max_withdrawals_per_payload: u64,
|
||||||
|
#[serde(with = "eth2_serde_utils::quoted_u64")]
|
||||||
|
pub max_validators_per_withdrawals_sweep: u64,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CapellaPreset {
|
||||||
|
pub fn from_chain_spec<T: EthSpec>(spec: &ChainSpec) -> Self {
|
||||||
|
Self {
|
||||||
|
max_bls_to_execution_changes: T::max_bls_to_execution_changes() as u64,
|
||||||
|
max_withdrawals_per_payload: T::max_withdrawals_per_payload() as u64,
|
||||||
|
max_validators_per_withdrawals_sweep: spec.max_validators_per_withdrawals_sweep,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
@ -219,6 +240,9 @@ mod test {
|
|||||||
|
|
||||||
let bellatrix: BellatrixPreset = preset_from_file(&preset_name, "bellatrix.yaml");
|
let bellatrix: BellatrixPreset = preset_from_file(&preset_name, "bellatrix.yaml");
|
||||||
assert_eq!(bellatrix, BellatrixPreset::from_chain_spec::<E>(&spec));
|
assert_eq!(bellatrix, BellatrixPreset::from_chain_spec::<E>(&spec));
|
||||||
|
|
||||||
|
let capella: CapellaPreset = preset_from_file(&preset_name, "capella.yaml");
|
||||||
|
assert_eq!(capella, CapellaPreset::from_chain_spec::<E>(&spec));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
TESTS_TAG := v1.3.0-alpha.1
|
TESTS_TAG := v1.3.0-alpha.2
|
||||||
TESTS = general minimal mainnet
|
TESTS = general minimal mainnet
|
||||||
TARBALLS = $(patsubst %,%-$(TESTS_TAG).tar.gz,$(TESTS))
|
TARBALLS = $(patsubst %,%-$(TESTS_TAG).tar.gz,$(TESTS))
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user