Skip to content
Merged
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
26 changes: 24 additions & 2 deletions crates/engine/tree/src/tree/metrics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,9 @@ impl EngineApiMetrics {
pub struct TreeMetrics {
/// The highest block number in the canonical chain
pub canonical_chain_height: Gauge,
/// The number of reorgs
pub reorgs: Counter,
/// Metrics for reorgs.
#[metric(skip)]
pub reorgs: ReorgMetrics,
/// The latest reorg depth
pub latest_reorg_depth: Gauge,
/// The current safe block height (this is required by optimism)
Expand All @@ -100,6 +101,27 @@ pub struct TreeMetrics {
pub finalized_block_height: Gauge,
}

/// Metrics for reorgs.
#[derive(Debug)]
pub struct ReorgMetrics {
/// The number of head block reorgs
pub head: Counter,
/// The number of safe block reorgs
pub safe: Counter,
/// The number of finalized block reorgs
pub finalized: Counter,
}

impl Default for ReorgMetrics {
fn default() -> Self {
Self {
head: metrics::counter!("blockchain_tree_reorgs", "commitment" => "head"),
safe: metrics::counter!("blockchain_tree_reorgs", "commitment" => "safe"),
finalized: metrics::counter!("blockchain_tree_reorgs", "commitment" => "finalized"),
}
}
}

/// Metrics for the `EngineApi`.
#[derive(Metrics)]
#[metrics(scope = "consensus.engine.beacon")]
Expand Down
23 changes: 19 additions & 4 deletions crates/engine/tree/src/tree/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ use reth_revm::database::StateProviderDatabase;
use reth_stages_api::ControlFlow;
use reth_tasks::spawn_os_thread;
use reth_trie_db::ChangesetCache;
use revm::interpreter::debug_unreachable;
use state::TreeState;
use std::{fmt::Debug, ops, sync::Arc, time::Instant};

Expand Down Expand Up @@ -2376,7 +2377,7 @@ where
let old_first = old.first().map(|first| first.recovered_block().num_hash());
trace!(target: "engine::tree", ?new_first, ?old_first, "Reorg detected, new and old first blocks");

self.update_reorg_metrics(old.len());
self.update_reorg_metrics(old.len(), old_first);
self.reinsert_reorged_blocks(new.clone());
self.reinsert_reorged_blocks(old.clone());
}
Expand All @@ -2398,9 +2399,23 @@ where
));
}

/// This updates metrics based on the given reorg length.
fn update_reorg_metrics(&self, old_chain_length: usize) {
self.metrics.tree.reorgs.increment(1);
/// This updates metrics based on the given reorg length and first reorged block number.
fn update_reorg_metrics(&self, old_chain_length: usize, first_reorged_block: Option<NumHash>) {
if let Some(first_reorged_block) = first_reorged_block.map(|block| block.number) {
if let Some(finalized) = self.canonical_in_memory_state.get_finalized_num_hash() &&
first_reorged_block <= finalized.number
{
self.metrics.tree.reorgs.finalized.increment(1);
} else if let Some(safe) = self.canonical_in_memory_state.get_safe_num_hash() &&
first_reorged_block <= safe.number
{
self.metrics.tree.reorgs.safe.increment(1);
} else {
self.metrics.tree.reorgs.head.increment(1);
}
} else {
debug_unreachable!("Reorged chain doesn't have any blocks");
}
self.metrics.tree.latest_reorg_depth.set(old_chain_length as f64);
}

Expand Down
23 changes: 23 additions & 0 deletions crates/engine/tree/src/tree/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1969,6 +1969,29 @@ mod forkchoice_updated_tests {
assert!(result.is_some(), "OpStack should handle canonical head");
}

#[test]
fn test_update_reorg_metrics() {
let chain_spec = MAINNET.clone();
let test_harness = TestHarness::new(chain_spec);

let seal_header = |number: u64| {
SealedHeader::seal_slow(alloy_consensus::Header { number, ..Default::default() })
};

// Set finalized=30, safe=50 to test all three commitment levels
test_harness.tree.canonical_in_memory_state.set_finalized(seal_header(30));
test_harness.tree.canonical_in_memory_state.set_safe(seal_header(50));

// Reorg at block 20 (below finalized=30) -> finalized reorg
test_harness.tree.update_reorg_metrics(5, Some(NumHash::new(20, B256::random())));

// Reorg at block 40 (below safe=50, above finalized=30) -> safe reorg
test_harness.tree.update_reorg_metrics(3, Some(NumHash::new(40, B256::random())));

// Reorg at block 60 (above safe=50) -> head reorg
test_harness.tree.update_reorg_metrics(2, Some(NumHash::new(60, B256::random())));
}

/// Test that engine termination persists all blocks and signals completion.
#[test]
fn test_engine_termination_with_everything_persisted() {
Expand Down
Loading