Merge remote-tracking branch 'origin/release-v7.0.0' into unstable

This commit is contained in:
Michael Sproul
2025-03-10 15:21:24 +11:00
19 changed files with 154 additions and 36 deletions

View File

@@ -144,11 +144,6 @@ pub const FORK_CHOICE_DB_KEY: Hash256 = Hash256::ZERO;
/// Defines how old a block can be before it's no longer a candidate for the early attester cache.
const EARLY_ATTESTER_CACHE_HISTORIC_SLOTS: u64 = 4;
/// Defines a distance between the head block slot and the current slot.
///
/// If the head block is older than this value, don't bother preparing beacon proposers.
const PREPARE_PROPOSER_HISTORIC_EPOCHS: u64 = 4;
/// If the head is more than `MAX_PER_SLOT_FORK_CHOICE_DISTANCE` slots behind the wall-clock slot, DO NOT
/// run the per-slot tasks (primarily fork choice).
///
@@ -4848,7 +4843,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
let proposer_index = if let Some(proposer) = cached_proposer {
proposer.index as u64
} else {
if head_epoch + 2 < proposal_epoch {
if head_epoch + self.config.sync_tolerance_epochs < proposal_epoch {
warn!(
self.log,
"Skipping proposer preparation";
@@ -6079,19 +6074,18 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
// Use a blocking task since blocking the core executor on the canonical head read lock can
// block the core tokio executor.
let chain = self.clone();
let tolerance_slots = self.config.sync_tolerance_epochs * T::EthSpec::slots_per_epoch();
let maybe_prep_data = self
.spawn_blocking_handle(
move || {
let cached_head = chain.canonical_head.cached_head();
// Don't bother with proposer prep if the head is more than
// `PREPARE_PROPOSER_HISTORIC_EPOCHS` prior to the current slot.
// `sync_tolerance_epochs` prior to the current slot.
//
// This prevents the routine from running during sync.
let head_slot = cached_head.head_slot();
if head_slot + T::EthSpec::slots_per_epoch() * PREPARE_PROPOSER_HISTORIC_EPOCHS
< current_slot
{
if head_slot + tolerance_slots < current_slot {
debug!(
chain.log,
"Head too old for proposer prep";

View File

@@ -171,7 +171,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
return BellatrixReadiness::NotSynced;
}
let params = MergeConfig::from_chainspec(&self.spec);
let current_difficulty = el.get_current_difficulty().await.ok();
let current_difficulty = el.get_current_difficulty().await.ok().flatten();
BellatrixReadiness::Ready {
config: params,
current_difficulty,

View File

@@ -16,6 +16,9 @@ pub const DEFAULT_PREPARE_PAYLOAD_LOOKAHEAD_FACTOR: u32 = 3;
/// Fraction of a slot lookahead for fork choice in the state advance timer (500ms on mainnet).
pub const FORK_CHOICE_LOOKAHEAD_FACTOR: u32 = 24;
/// Default sync tolerance epochs.
pub const DEFAULT_SYNC_TOLERANCE_EPOCHS: u64 = 2;
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
pub struct ChainConfig {
/// Maximum number of slots to skip when importing an attestation.
@@ -94,6 +97,9 @@ pub struct ChainConfig {
/// The delay in milliseconds applied by the node between sending each blob or data column batch.
/// This doesn't apply if the node is the block proposer.
pub blob_publication_batch_interval: Duration,
/// The max distance between the head block and the current slot at which Lighthouse will
/// consider itself synced and still serve validator-related requests.
pub sync_tolerance_epochs: u64,
/// Artificial delay for block publishing. For PeerDAS testing only.
pub block_publishing_delay: Option<Duration>,
/// Artificial delay for data column publishing. For PeerDAS testing only.
@@ -133,6 +139,7 @@ impl Default for ChainConfig {
enable_sampling: false,
blob_publication_batches: 4,
blob_publication_batch_interval: Duration::from_millis(300),
sync_tolerance_epochs: DEFAULT_SYNC_TOLERANCE_EPOCHS,
block_publishing_delay: None,
data_column_publishing_delay: None,
}

View File

@@ -142,11 +142,18 @@ pub struct ExecutionBlock {
pub block_number: u64,
pub parent_hash: ExecutionBlockHash,
pub total_difficulty: Uint256,
pub total_difficulty: Option<Uint256>,
#[serde(with = "serde_utils::u64_hex_be")]
pub timestamp: u64,
}
impl ExecutionBlock {
pub fn terminal_total_difficulty_reached(&self, terminal_total_difficulty: Uint256) -> bool {
self.total_difficulty
.is_none_or(|td| td >= terminal_total_difficulty)
}
}
#[superstruct(
variants(V1, V2, V3),
variant_attributes(derive(Clone, Debug, Eq, Hash, PartialEq),),

View File

@@ -621,7 +621,7 @@ impl<E: EthSpec> ExecutionLayer<E> {
}
/// Get the current difficulty of the PoW chain.
pub async fn get_current_difficulty(&self) -> Result<Uint256, ApiError> {
pub async fn get_current_difficulty(&self) -> Result<Option<Uint256>, ApiError> {
let block = self
.engine()
.api
@@ -1680,7 +1680,8 @@ impl<E: EthSpec> ExecutionLayer<E> {
self.execution_blocks().await.put(block.block_hash, block);
loop {
let block_reached_ttd = block.total_difficulty >= spec.terminal_total_difficulty;
let block_reached_ttd =
block.terminal_total_difficulty_reached(spec.terminal_total_difficulty);
if block_reached_ttd {
if block.parent_hash == ExecutionBlockHash::zero() {
return Ok(Some(block));
@@ -1689,7 +1690,8 @@ impl<E: EthSpec> ExecutionLayer<E> {
.get_pow_block(engine, block.parent_hash)
.await?
.ok_or(ApiError::ExecutionBlockNotFound(block.parent_hash))?;
let parent_reached_ttd = parent.total_difficulty >= spec.terminal_total_difficulty;
let parent_reached_ttd =
parent.terminal_total_difficulty_reached(spec.terminal_total_difficulty);
if block_reached_ttd && !parent_reached_ttd {
return Ok(Some(block));
@@ -1765,9 +1767,11 @@ impl<E: EthSpec> ExecutionLayer<E> {
parent: ExecutionBlock,
spec: &ChainSpec,
) -> bool {
let is_total_difficulty_reached = block.total_difficulty >= spec.terminal_total_difficulty;
let is_parent_total_difficulty_valid =
parent.total_difficulty < spec.terminal_total_difficulty;
let is_total_difficulty_reached =
block.terminal_total_difficulty_reached(spec.terminal_total_difficulty);
let is_parent_total_difficulty_valid = parent
.total_difficulty
.is_some_and(|td| td < spec.terminal_total_difficulty);
is_total_difficulty_reached && is_parent_total_difficulty_valid
}

View File

@@ -84,14 +84,14 @@ impl<E: EthSpec> Block<E> {
block_hash: block.block_hash,
block_number: block.block_number,
parent_hash: block.parent_hash,
total_difficulty: block.total_difficulty,
total_difficulty: Some(block.total_difficulty),
timestamp: block.timestamp,
},
Block::PoS(payload) => ExecutionBlock {
block_hash: payload.block_hash(),
block_number: payload.block_number(),
parent_hash: payload.parent_hash(),
total_difficulty,
total_difficulty: Some(total_difficulty),
timestamp: payload.timestamp(),
},
}

View File

@@ -107,13 +107,6 @@ use warp_utils::{query::multi_key_query, reject::convert_rejection, uor::Unifyin
const API_PREFIX: &str = "eth";
/// If the node is within this many epochs from the head, we declare it to be synced regardless of
/// the network sync state.
///
/// This helps prevent attacks where nodes can convince us that we're syncing some non-existent
/// finalized head.
const DEFAULT_SYNC_TOLERANCE_EPOCHS: u64 = 8;
/// A custom type which allows for both unsecured and TLS-enabled HTTP servers.
type HttpServer = (SocketAddr, Pin<Box<dyn Future<Output = ()> + Send>>);
@@ -461,10 +454,8 @@ pub fn serve<T: BeaconChainTypes>(
)
})?;
let sync_tolerance_epochs = config
.sync_tolerance_epochs
.unwrap_or(DEFAULT_SYNC_TOLERANCE_EPOCHS);
let tolerance = sync_tolerance_epochs * T::EthSpec::slots_per_epoch();
let tolerance =
chain.config.sync_tolerance_epochs * T::EthSpec::slots_per_epoch();
if head_slot + tolerance >= current_slot {
Ok(())

View File

@@ -191,6 +191,12 @@ pub fn get_config<E: EthSpec>(
client_config.chain.enable_light_client_server = false;
}
if let Some(sync_tolerance_epochs) =
clap_utils::parse_optional(cli_args, "sync-tolerance-epochs")?
{
client_config.chain.sync_tolerance_epochs = sync_tolerance_epochs;
}
if let Some(cache_size) = clap_utils::parse_optional(cli_args, "shuffling-cache-size")? {
client_config.chain.shuffling_cache_size = cache_size;
}