merge from unstable

This commit is contained in:
Daniel Knopik
2026-04-29 23:00:51 +02:00
43 changed files with 799 additions and 186 deletions

View File

@@ -105,12 +105,8 @@ CONTRIBUTION_DUE_BPS_GLOAS: 5000
PAYLOAD_ATTESTATION_DUE_BPS: 7500
# Heze
# 7500 basis points, 75% of SLOT_DURATION_MS
VIEW_FREEZE_CUTOFF_BPS: 7500
# 6667 basis points, ~67% of SLOT_DURATION_MS
INCLUSION_LIST_SUBMISSION_DUE_BPS: 6667
# 9167 basis points, ~92% of SLOT_DURATION_MS
PROPOSER_INCLUSION_LIST_CUTOFF_BPS: 9167
INCLUSION_LIST_DUE_BPS: 6667
# Validator cycle
# ---------------------------------------------------------------
@@ -135,6 +131,14 @@ MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA: 128000000000
# 2**8 * 10**9 (= 256,000,000,000) Gwei
MAX_PER_EPOCH_ACTIVATION_EXIT_CHURN_LIMIT: 256000000000
# Gloas
# 2**15 (= 32,768)
CHURN_LIMIT_QUOTIENT_GLOAS: 32768
# 2**16 (= 65,536)
CONSOLIDATION_CHURN_LIMIT_QUOTIENT: 65536
# 2**8 * 10**9 (= 256,000,000,000) Gwei
MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT_GLOAS: 256000000000
# Fork choice
# ---------------------------------------------------------------
# 40%

View File

@@ -101,12 +101,8 @@ CONTRIBUTION_DUE_BPS_GLOAS: 5000
PAYLOAD_ATTESTATION_DUE_BPS: 7500
# Heze
# 7500 basis points, 75% of SLOT_DURATION_MS
VIEW_FREEZE_CUTOFF_BPS: 7500
# 6667 basis points, ~67% of SLOT_DURATION_MS
INCLUSION_LIST_SUBMISSION_DUE_BPS: 6667
# 9167 basis points, ~92% of SLOT_DURATION_MS
PROPOSER_INCLUSION_LIST_CUTOFF_BPS: 9167
INCLUSION_LIST_DUE_BPS: 6667
# Validator cycle
# ---------------------------------------------------------------
@@ -131,6 +127,14 @@ MIN_PER_EPOCH_CHURN_LIMIT_ELECTRA: 64000000000
# [customized] 2**7 * 10**9 (= 128,000,000,000) Gwei
MAX_PER_EPOCH_ACTIVATION_EXIT_CHURN_LIMIT: 128000000000
# Gloas
# [customized] 2**4 (= 16)
CHURN_LIMIT_QUOTIENT_GLOAS: 16
# [customized] 2**5 (= 32)
CONSOLIDATION_CHURN_LIMIT_QUOTIENT: 32
# [customized] 2**7 * 10**9 (= 128,000,000,000) Gwei
MAX_PER_EPOCH_ACTIVATION_CHURN_LIMIT_GLOAS: 128000000000
# Fork choice
# ---------------------------------------------------------------
# 40%

View File

@@ -2,8 +2,8 @@
# Misc
# ---------------------------------------------------------------
# [customized] 2**1 (= 2) validators
PTC_SIZE: 2
# [customized] 2**4 (= 16) validators
PTC_SIZE: 16
# Max operations per block
# ---------------------------------------------------------------

View File

@@ -400,15 +400,13 @@ impl<E: EthSpec, Payload: AbstractExecPayload<E>> SignedBeaconBlock<E, Payload>
/// `block_hash` from the parent beacon block's bid. If the parent beacon state is available
/// this can alternatively be fetched from `state.latest_payload_bid`.
///
/// This function returns `false` for all blocks prior to Gloas and for the zero
/// `parent_block_hash`.
/// This function returns `false` for all blocks prior to Gloas.
pub fn is_parent_block_full(&self, parent_block_hash: ExecutionBlockHash) -> bool {
let Ok(signed_payload_bid) = self.message().body().signed_execution_payload_bid() else {
// Prior to Gloas.
return false;
};
parent_block_hash != ExecutionBlockHash::zero()
&& signed_payload_bid.message.parent_block_hash == parent_block_hash
signed_payload_bid.message.parent_block_hash == parent_block_hash
}
}

View File

@@ -1,5 +1,5 @@
use crate::test_utils::TestRandom;
use crate::{Address, ForkName, SignedRoot, Slot};
use crate::{Address, ForkName, Hash256, SignedRoot, Slot};
use bls::Signature;
use context_deserialize::context_deserialize;
use educe::Educe;
@@ -16,6 +16,7 @@ use tree_hash_derive::TreeHash;
#[context_deserialize(ForkName)]
// https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/p2p-interface.md#new-proposerpreferences
pub struct ProposerPreferences {
pub checkpoint_root: Hash256,
pub proposal_slot: Slot,
pub validator_index: u64,
pub fee_recipient: Address,

View File

@@ -251,6 +251,9 @@ pub struct ChainSpec {
pub builder_payment_threshold_numerator: u64,
pub builder_payment_threshold_denominator: u64,
pub min_builder_withdrawability_delay: Epoch,
pub churn_limit_quotient_gloas: u64,
pub consolidation_churn_limit_quotient: u64,
pub max_per_epoch_activation_churn_limit_gloas: u64,
/*
* Networking
@@ -1268,6 +1271,14 @@ impl ChainSpec {
builder_payment_threshold_numerator: 6,
builder_payment_threshold_denominator: 10,
min_builder_withdrawability_delay: Epoch::new(64),
churn_limit_quotient_gloas: option_wrapper(|| u64::checked_pow(2, 15))
.expect("calculation does not overflow"),
consolidation_churn_limit_quotient: option_wrapper(|| u64::checked_pow(2, 16))
.expect("calculation does not overflow"),
max_per_epoch_activation_churn_limit_gloas: option_wrapper(|| {
u64::checked_pow(2, 8)?.checked_mul(u64::checked_pow(10, 9)?)
})
.expect("calculation does not overflow"),
max_request_payloads: 128,
/*
@@ -1414,6 +1425,14 @@ impl ChainSpec {
gloas_fork_version: [0x07, 0x00, 0x00, 0x01],
gloas_fork_epoch: None,
min_builder_withdrawability_delay: Epoch::new(2),
churn_limit_quotient_gloas: option_wrapper(|| u64::checked_pow(2, 4))
.expect("calculation does not overflow"),
consolidation_churn_limit_quotient: option_wrapper(|| u64::checked_pow(2, 5))
.expect("calculation does not overflow"),
max_per_epoch_activation_churn_limit_gloas: option_wrapper(|| {
u64::checked_pow(2, 7)?.checked_mul(u64::checked_pow(10, 9)?)
})
.expect("calculation does not overflow"),
/*
* Derived time values (set by `compute_derived_values()`)
@@ -1675,6 +1694,14 @@ impl ChainSpec {
builder_payment_threshold_numerator: 6,
builder_payment_threshold_denominator: 10,
min_builder_withdrawability_delay: Epoch::new(64),
churn_limit_quotient_gloas: option_wrapper(|| u64::checked_pow(2, 15))
.expect("calculation does not overflow"),
consolidation_churn_limit_quotient: option_wrapper(|| u64::checked_pow(2, 16))
.expect("calculation does not overflow"),
max_per_epoch_activation_churn_limit_gloas: option_wrapper(|| {
u64::checked_pow(2, 8)?.checked_mul(u64::checked_pow(10, 9)?)
})
.expect("calculation does not overflow"),
max_request_payloads: 128,
/*
@@ -2125,6 +2152,16 @@ pub struct Config {
#[serde(default = "default_min_builder_withdrawability_delay")]
#[serde(with = "serde_utils::quoted_u64")]
min_builder_withdrawability_delay: u64,
#[serde(default = "default_churn_limit_quotient_gloas")]
#[serde(with = "serde_utils::quoted_u64")]
churn_limit_quotient_gloas: u64,
#[serde(default = "default_consolidation_churn_limit_quotient")]
#[serde(with = "serde_utils::quoted_u64")]
consolidation_churn_limit_quotient: u64,
#[serde(default = "default_max_per_epoch_activation_churn_limit_gloas")]
#[serde(with = "serde_utils::quoted_u64")]
max_per_epoch_activation_churn_limit_gloas: u64,
}
fn default_bellatrix_fork_version() -> [u8; 4] {
@@ -2362,6 +2399,18 @@ const fn default_min_builder_withdrawability_delay() -> u64 {
64
}
const fn default_churn_limit_quotient_gloas() -> u64 {
32_768
}
const fn default_consolidation_churn_limit_quotient() -> u64 {
65_536
}
const fn default_max_per_epoch_activation_churn_limit_gloas() -> u64 {
256_000_000_000
}
fn max_blocks_by_root_request_common(max_request_blocks: u64) -> usize {
let max_request_blocks = max_request_blocks as usize;
RuntimeVariableList::<Hash256>::new(
@@ -2613,6 +2662,11 @@ impl Config {
contribution_due_bps: spec.contribution_due_bps,
min_builder_withdrawability_delay: spec.min_builder_withdrawability_delay.as_u64(),
churn_limit_quotient_gloas: spec.churn_limit_quotient_gloas,
consolidation_churn_limit_quotient: spec.consolidation_churn_limit_quotient,
max_per_epoch_activation_churn_limit_gloas: spec
.max_per_epoch_activation_churn_limit_gloas,
}
}
@@ -2710,6 +2764,9 @@ impl Config {
sync_message_due_bps,
contribution_due_bps,
min_builder_withdrawability_delay,
churn_limit_quotient_gloas,
consolidation_churn_limit_quotient,
max_per_epoch_activation_churn_limit_gloas,
} = self;
if preset_base != E::spec_name().to_string().as_str() {
@@ -2817,6 +2874,10 @@ impl Config {
min_builder_withdrawability_delay: Epoch::new(min_builder_withdrawability_delay),
churn_limit_quotient_gloas,
consolidation_churn_limit_quotient,
max_per_epoch_activation_churn_limit_gloas,
..chain_spec.clone()
};
Some(spec.compute_derived_values::<E>())
@@ -3719,9 +3780,7 @@ mod yaml_tests {
"CONTRIBUTION_DUE_BPS_GLOAS",
"MAX_REQUEST_PAYLOADS",
// Heze networking
"VIEW_FREEZE_CUTOFF_BPS",
"INCLUSION_LIST_SUBMISSION_DUE_BPS",
"PROPOSER_INCLUSION_LIST_CUTOFF_BPS",
"INCLUSION_LIST_DUE_BPS",
"MAX_REQUEST_INCLUSION_LIST",
"MAX_BYTES_PER_INCLUSION_LIST",
];

View File

@@ -572,7 +572,7 @@ impl EthSpec for MinimalEthSpec {
type NumberOfColumns = U128;
type ProposerLookaheadSlots = U16; // Derived from (MIN_SEED_LOOKAHEAD + 1) * SLOTS_PER_EPOCH
type BuilderPendingPaymentsLimit = U16; // 2 * SLOTS_PER_EPOCH = 2 * 8 = 16
type PTCSize = U2;
type PTCSize = U16;
type PtcWindowLength = U24; // (2 + MIN_SEED_LOOKAHEAD) * SLOTS_PER_EPOCH
type MaxBuildersPerWithdrawalsSweep = U16;

View File

@@ -20,6 +20,7 @@ pub struct ExecutionPayloadEnvelope<E: EthSpec> {
#[serde(with = "serde_utils::quoted_u64")]
pub builder_index: u64,
pub beacon_block_root: Hash256,
pub parent_beacon_block_root: Hash256,
}
impl<E: EthSpec> ExecutionPayloadEnvelope<E> {
@@ -30,6 +31,7 @@ impl<E: EthSpec> ExecutionPayloadEnvelope<E> {
execution_requests: ExecutionRequests::default(),
builder_index: 0,
beacon_block_root: Hash256::zero(),
parent_beacon_block_root: Hash256::zero(),
}
}

View File

@@ -2762,29 +2762,55 @@ impl<E: EthSpec> BeaconState<E> {
/// Return the churn limit for the current epoch.
pub fn get_balance_churn_limit(&self, spec: &ChainSpec) -> Result<u64, BeaconStateError> {
let total_active_balance = self.get_total_active_balance()?;
let quotient = if self.fork_name_unchecked().gloas_enabled() {
spec.churn_limit_quotient_gloas
} else {
spec.churn_limit_quotient
};
let churn = std::cmp::max(
spec.min_per_epoch_churn_limit_electra,
total_active_balance.safe_div(spec.churn_limit_quotient)?,
total_active_balance.safe_div(quotient)?,
);
Ok(churn.safe_sub(churn.safe_rem(spec.effective_balance_increment)?)?)
}
/// Return the churn limit for the current epoch dedicated to activations and exits.
///
/// From Gloas onwards this is the activation-only churn limit (EIP-8061); exits use
/// [`Self::get_exit_churn_limit`].
pub fn get_activation_exit_churn_limit(
&self,
spec: &ChainSpec,
) -> Result<u64, BeaconStateError> {
let max_limit = if self.fork_name_unchecked().gloas_enabled() {
spec.max_per_epoch_activation_churn_limit_gloas
} else {
spec.max_per_epoch_activation_exit_churn_limit
};
Ok(std::cmp::min(
spec.max_per_epoch_activation_exit_churn_limit,
max_limit,
self.get_balance_churn_limit(spec)?,
))
}
/// Return the Gloas (EIP-8061) exit churn limit for the current epoch.
///
/// Unlike [`Self::get_activation_exit_churn_limit`], this is uncapped.
pub fn get_exit_churn_limit(&self, spec: &ChainSpec) -> Result<u64, BeaconStateError> {
self.get_balance_churn_limit(spec)
}
pub fn get_consolidation_churn_limit(&self, spec: &ChainSpec) -> Result<u64, BeaconStateError> {
self.get_balance_churn_limit(spec)?
.safe_sub(self.get_activation_exit_churn_limit(spec)?)
.map_err(Into::into)
if self.fork_name_unchecked().gloas_enabled() {
let total_active_balance = self.get_total_active_balance()?;
let churn = total_active_balance.safe_div(spec.consolidation_churn_limit_quotient)?;
Ok(churn.safe_sub(churn.safe_rem(spec.effective_balance_increment)?)?)
} else {
self.get_balance_churn_limit(spec)?
.safe_sub(self.get_activation_exit_churn_limit(spec)?)
.map_err(Into::into)
}
}
pub fn get_pending_balance_to_withdraw(
@@ -2879,7 +2905,11 @@ impl<E: EthSpec> BeaconState<E> {
self.compute_activation_exit_epoch(self.current_epoch(), spec)?,
);
let per_epoch_churn = self.get_activation_exit_churn_limit(spec)?;
let per_epoch_churn = if self.fork_name_unchecked().gloas_enabled() {
self.get_exit_churn_limit(spec)?
} else {
self.get_activation_exit_churn_limit(spec)?
};
// New epoch for exits
let mut exit_balance_to_consume = if self.earliest_exit_epoch()? < earliest_exit_epoch {
per_epoch_churn
@@ -3103,7 +3133,19 @@ impl<E: EthSpec> BeaconState<E> {
let total_active_balance = self.get_total_active_balance()?;
let fork_name = self.fork_name_unchecked();
if fork_name.electra_enabled() {
if fork_name.gloas_enabled() {
// [Modified in Gloas:EIP8061]
let exit_churn = self.get_exit_churn_limit(spec)?;
let activation_churn = self.get_activation_exit_churn_limit(spec)?;
let consolidation_churn = self.get_consolidation_churn_limit(spec)?;
compute_weak_subjectivity_period_gloas(
total_active_balance,
exit_churn,
activation_churn,
consolidation_churn,
spec,
)
} else if fork_name.electra_enabled() {
let balance_churn_limit = self.get_balance_churn_limit(spec)?;
compute_weak_subjectivity_period_electra(
total_active_balance,
@@ -3601,6 +3643,30 @@ pub fn compute_weak_subjectivity_period_electra(
Ok(ws_period)
}
/// Spec: https://github.com/ethereum/consensus-specs/blob/v1.7.0-alpha.6/specs/gloas/weak-subjectivity.md
pub fn compute_weak_subjectivity_period_gloas(
total_active_balance: u64,
exit_churn_limit: u64,
activation_churn_limit: u64,
consolidation_churn_limit: u64,
spec: &ChainSpec,
) -> Result<Epoch, BeaconStateError> {
// delta = 2 * exit_churn // 3 + activation_churn // 3 + consolidation_churn
let delta = exit_churn_limit
.safe_mul(2)?
.safe_div(3)?
.safe_add(activation_churn_limit.safe_div(3)?)?
.safe_add(consolidation_churn_limit)?;
let epochs_for_validator_set_churn = SAFETY_DECAY
.safe_mul(total_active_balance)?
.safe_div(delta.safe_mul(200)?)?;
let ws_period = spec
.min_validator_withdrawability_delay
.safe_add(epochs_for_validator_set_churn)?;
Ok(ws_period)
}
#[cfg(test)]
mod weak_subjectivity_tests {
use crate::state::beacon_state::compute_weak_subjectivity_period_electra;