From 76d66a0bc70f91ea1fab8c3288280054cabcd8a4 Mon Sep 17 00:00:00 2001 From: Gregory Edison Date: Thu, 16 Oct 2025 19:08:45 +0200 Subject: [PATCH 1/4] feat: update metrics in chain orchestrator --- crates/chain-orchestrator/src/lib.rs | 102 +++++++++-------------- crates/chain-orchestrator/src/metrics.rs | 88 +++++++++++++++---- crates/derivation-pipeline/src/lib.rs | 2 +- crates/sequencer/src/lib.rs | 10 +-- 4 files changed, 118 insertions(+), 84 deletions(-) diff --git a/crates/chain-orchestrator/src/lib.rs b/crates/chain-orchestrator/src/lib.rs index 35f3ab72..0526eaa1 100644 --- a/crates/chain-orchestrator/src/lib.rs +++ b/crates/chain-orchestrator/src/lib.rs @@ -35,13 +35,7 @@ use scroll_engine::Engine; use scroll_network::{ BlockImportOutcome, NewBlockWithPeer, ScrollNetwork, ScrollNetworkManagerEvent, }; -use std::{ - collections::{HashMap, VecDeque}, - sync::Arc, - time::Instant, - vec, -}; -use strum::IntoEnumIterator; +use std::{collections::VecDeque, sync::Arc, time::Instant, vec}; use tokio::sync::mpsc::{self, Receiver, UnboundedReceiver}; mod config; @@ -51,7 +45,7 @@ mod consensus; pub use consensus::{Consensus, NoopConsensus, SystemContractConsensus}; mod consolidation; -use consolidation::reconcile_batch; +use consolidation::{reconcile_batch, BlockConsolidationAction}; mod event; pub use event::ChainOrchestratorEvent; @@ -63,7 +57,7 @@ mod handle; pub use handle::{ChainOrchestratorCommand, ChainOrchestratorHandle}; mod metrics; -pub use metrics::{ChainOrchestratorItem, ChainOrchestratorMetrics}; +pub use metrics::{ChainOrchestratorMetrics, MetricsHandler, Task}; mod retry; pub use retry::Retry; @@ -74,7 +68,18 @@ pub use sync::SyncState; mod status; pub use status::ChainOrchestratorStatus; -use crate::consolidation::BlockConsolidationAction; +/// Wraps a future, metering the completion of it. +macro_rules! metered { + ($task:expr, $self:ident, $method:ident($($args:expr),*)) => { + { + let metric = $self.metric_handler.get($task).expect("metric exists").clone(); + let now = Instant::now(); + let res =$self.$method($($args),*).await; + metric.task_duration.record(now.elapsed().as_secs_f64()); + res + } + }; +} /// The mask used to mask the L1 message queue hash. const L1_MESSAGE_QUEUE_HASH_MASK: B256 = @@ -106,8 +111,6 @@ pub struct ChainOrchestrator< l2_client: Arc, /// A reference to the database used to persist the indexed data. database: Arc, - /// The metrics for the chain orchestrator. - metrics: HashMap, /// The current sync state of the [`ChainOrchestrator`]. sync_state: SyncState, /// A receiver for [`L1Notification`]s from the [`rollup_node_watcher::L1Watcher`]. @@ -126,6 +129,8 @@ pub struct ChainOrchestrator< derivation_pipeline: DerivationPipeline, /// Optional event sender for broadcasting events to listeners. event_sender: Option>, + /// The metrics handler. + metric_handler: MetricsHandler, } impl< @@ -159,12 +164,6 @@ impl< l2_client: Arc::new(l2_provider), database, config, - metrics: ChainOrchestratorItem::iter() - .map(|i| { - let label = i.as_str(); - (i, ChainOrchestratorMetrics::new_with_labels(&[("item", label)])) - }) - .collect(), sync_state: SyncState::default(), l1_notification_rx, network, @@ -175,6 +174,7 @@ impl< derivation_pipeline, handle_rx, event_sender: None, + metric_handler: MetricsHandler::default(), }, handle, )) @@ -215,7 +215,7 @@ impl< self.handle_outcome(res); } Some(batch) = self.derivation_pipeline.next() => { - let res = self.handle_derived_batch(batch).await; + let res = metered!(Task::BatchReconciliation, self, handle_derived_batch(batch)); self.handle_outcome(res); } Some(event) = self.network.events().next() => { @@ -249,7 +249,7 @@ impl< /// Handles an event from the signer. async fn handle_signer_event( &self, - event: rollup_node_signer::SignerEvent, + event: SignerEvent, ) -> Result, ChainOrchestratorError> { tracing::info!(target: "scroll::chain_orchestrator", ?event, "Handling signer event"); match event { @@ -267,7 +267,7 @@ impl< /// Handles an event from the sequencer. async fn handle_sequencer_event( &mut self, - event: rollup_node_sequencer::SequencerEvent, + event: SequencerEvent, ) -> Result, ChainOrchestratorError> { tracing::info!(target: "scroll::chain_orchestrator", ?event, "Handling sequencer event"); match event { @@ -278,6 +278,7 @@ impl< .map(|s| &s.address) .expect("signer must be set if sequencer is present"), ) { + self.metric_handler.start_block_building_recording(); self.sequencer .as_mut() .expect("sequencer must be present") @@ -301,6 +302,7 @@ impl< .as_mut() .expect("signer must be present") .sign_block(block.clone())?; + self.metric_handler.finish_block_building_recording(); return Ok(Some(ChainOrchestratorEvent::BlockSequenced(block))) } } @@ -497,30 +499,38 @@ impl< tx.commit().await?; Ok(None) } - L1Notification::Reorg(block_number) => self.handle_l1_reorg(*block_number).await, + L1Notification::Reorg(block_number) => { + metered!(Task::L1Reorg, self, handle_l1_reorg(*block_number)) + } L1Notification::Consensus(update) => { self.consensus.update_config(update); Ok(None) } L1Notification::NewBlock(block_number) => self.handle_l1_new_block(*block_number).await, L1Notification::Finalized(block_number) => { - self.handle_l1_finalized(*block_number).await + metered!(Task::L1Finalization, self, handle_l1_finalized(*block_number)) + } + L1Notification::BatchCommit(batch) => { + metered!(Task::BatchCommit, self, handle_batch_commit(batch.clone())) } - L1Notification::BatchCommit(batch) => self.handle_batch_commit(batch.clone()).await, L1Notification::L1Message { message, block_number, block_timestamp: _ } => { - self.handle_l1_message(message.clone(), *block_number).await + metered!(Task::L1Message, self, handle_l1_message(message.clone(), *block_number)) } L1Notification::Synced => { tracing::info!(target: "scroll::chain_orchestrator", "L1 is now synced"); self.sync_state.l1_mut().set_synced(); if self.sync_state.is_synced() { - self.consolidate_chain().await?; + metered!(Task::L1Consolidation, self, consolidate_chain())?; } self.notify(ChainOrchestratorEvent::L1Synced); Ok(None) } L1Notification::BatchFinalization { hash: _hash, index, block_number } => { - self.handle_l1_batch_finalization(*index, *block_number).await + metered!( + Task::BatchFinalization, + self, + handle_batch_finalization(*index, *block_number) + ) } } } @@ -547,8 +557,6 @@ impl< &mut self, block_number: u64, ) -> Result, ChainOrchestratorError> { - let metric = self.metrics.get(&ChainOrchestratorItem::L1Reorg).expect("metric exists"); - let now = Instant::now(); let UnwindResult { l1_block_number, queue_index, l2_head_block_number, l2_safe_block_info } = Retry::default() .retry("unwind", || async { @@ -598,8 +606,6 @@ impl< self.engine.update_fcs(l2_head_block_info, l2_safe_block_info, None).await?; } - metric.task_duration.record(now.elapsed().as_secs_f64()); - let event = ChainOrchestratorEvent::L1Reorg { l1_block_number, queue_index, @@ -616,10 +622,6 @@ impl< &mut self, block_number: u64, ) -> Result, ChainOrchestratorError> { - let metric = - self.metrics.get(&ChainOrchestratorItem::L1Finalization).expect("metric exists"); - let now = Instant::now(); - let finalized_batches = Retry::default() .retry("handle_finalized", || async { let tx = self.database.tx_mut().await?; @@ -642,8 +644,6 @@ impl< self.derivation_pipeline.push_batch(Arc::new(*batch)).await; } - metric.task_duration.record(now.elapsed().as_secs_f64()); - Ok(Some(ChainOrchestratorEvent::L1BlockFinalized(block_number, finalized_batches))) } @@ -652,9 +652,6 @@ impl< &self, batch: BatchCommitData, ) -> Result, ChainOrchestratorError> { - let metric = self.metrics.get(&ChainOrchestratorItem::BatchCommit).expect("metric exists"); - let now = Instant::now(); - let event = Retry::default() .retry("handle_batch_commit", || async { let tx = self.database.tx_mut().await?; @@ -692,13 +689,11 @@ impl< }) .await?; - metric.task_duration.record(now.elapsed().as_secs_f64()); - Ok(event) } /// Handles a batch finalization event by updating the batch input in the database. - async fn handle_l1_batch_finalization( + async fn handle_batch_finalization( &mut self, batch_index: u64, block_number: u64, @@ -745,9 +740,6 @@ impl< l1_message: TxL1Message, l1_block_number: u64, ) -> Result, ChainOrchestratorError> { - let metric = self.metrics.get(&ChainOrchestratorItem::L1Message).expect("metric exists"); - let now = Instant::now(); - let event = ChainOrchestratorEvent::L1MessageCommitted(l1_message.queue_index); let queue_hash = compute_l1_message_queue_hash( &self.database, @@ -777,27 +769,9 @@ impl< }) .await?; - metric.task_duration.record(now.elapsed().as_secs_f64()); - Ok(Some(event)) } - // /// Wraps a pending chain orchestrator future, metering the completion of it. - // pub fn handle_metered( - // &mut self, - // item: ChainOrchestratorItem, - // chain_orchestrator_fut: PendingChainOrchestratorFuture, - // ) -> PendingChainOrchestratorFuture { - // let metric = self.metrics.get(&item).expect("metric exists").clone(); - // let fut_wrapper = Box::pin(async move { - // let now = Instant::now(); - // let res = chain_orchestrator_fut.await; - // metric.task_duration.record(now.elapsed().as_secs_f64()); - // res - // }); - // fut_wrapper - // } - async fn handle_network_event( &mut self, event: ScrollNetworkManagerEvent, diff --git a/crates/chain-orchestrator/src/metrics.rs b/crates/chain-orchestrator/src/metrics.rs index c71b4841..8142a67d 100644 --- a/crates/chain-orchestrator/src/metrics.rs +++ b/crates/chain-orchestrator/src/metrics.rs @@ -1,16 +1,61 @@ use metrics::Histogram; use metrics_derive::Metrics; -use strum::EnumIter; +use std::{collections::HashMap, time::Instant}; +use strum::{EnumIter, IntoEnumIterator}; -/// An enum representing the items the chain orchestrator can handle. +/// The metric handler for the chain orchestrator. Tracks execution duration of various tasks. +#[derive(Debug)] +pub struct MetricsHandler { + /// The chain orchestrator metrics. + chain_orchestrator_tasks_metrics: HashMap, + /// The inflight block building meter. + block_building_meter: BlockBuildingMeter, +} + +impl MetricsHandler { + /// Returns the [`ChainOrchestratorMetrics`] for the provided task. + pub fn get(&self, task: Task) -> Option<&ChainOrchestratorMetrics> { + self.chain_orchestrator_tasks_metrics.get(&task) + } + + /// Starts tracking a new block building task. + pub(crate) fn start_block_building_recording(&mut self) { + if self.block_building_meter.start.is_some() { + tracing::warn!(target: "scroll::chain_orchestrator", "block building recording is already ongoing, overwriting"); + } + self.block_building_meter.start = Some(Instant::now()); + } + + /// The duration of the current block building task if any. + pub(crate) fn finish_block_building_recording(&mut self) { + let duration = self.block_building_meter.start.take().map(|start| start.elapsed()); + if let Some(duration) = duration { + self.block_building_meter.metric.block_building_duration.record(duration.as_secs_f64()); + } + } +} + +impl Default for MetricsHandler { + fn default() -> Self { + Self { + chain_orchestrator_tasks_metrics: Task::iter() + .map(|i| { + let label = i.as_str(); + (i, ChainOrchestratorMetrics::new_with_labels(&[("task", label)])) + }) + .collect(), + block_building_meter: BlockBuildingMeter::default(), + } + } +} + +/// An enum representing the chain orchestrator tasks #[derive(Debug, PartialEq, Eq, Hash, EnumIter)] -pub enum ChainOrchestratorItem { - /// Handle a block received from the network. - NewBlock, - /// Insert consolidated L2 blocks into the database. - InsertConsolidatedL2Blocks, - /// L2 block. - InsertL2Block, +pub enum Task { + /// Batch reconciliation with the unsafe L2 chain. + BatchReconciliation, + /// L1 consolidation. + L1Consolidation, /// L1 reorg. L1Reorg, /// L1 finalization. @@ -23,26 +68,41 @@ pub enum ChainOrchestratorItem { BatchFinalization, } -impl ChainOrchestratorItem { +impl Task { /// Returns the str representation of the [`ChainOrchestratorItem`]. pub const fn as_str(&self) -> &'static str { match self { - Self::NewBlock => "new_block", - Self::InsertConsolidatedL2Blocks => "insert_consolidated_l2_blocks", - Self::InsertL2Block => "l2_block", Self::L1Reorg => "l1_reorg", Self::L1Finalization => "l1_finalization", Self::L1Message => "l1_message", Self::BatchCommit => "batch_commit", Self::BatchFinalization => "batch_finalization", + Self::BatchReconciliation => "batch_reconciliation", + Self::L1Consolidation => "l1_consolidation", } } } /// The metrics for the [`super::ChainOrchestrator`]. #[derive(Metrics, Clone)] -#[metrics(scope = "indexer")] +#[metrics(scope = "chain_orchestrator")] pub struct ChainOrchestratorMetrics { /// The duration of the task for the chain orchestrator. pub task_duration: Histogram, } + +/// Block building related metric. + +#[derive(Metrics, Clone)] +#[metrics(scope = "chain_orchestrator")] +pub(crate) struct BlockBuildingMetric { + /// The duration of the block building task. + block_building_duration: Histogram, +} + +/// A block building meter. +#[derive(Debug, Default)] +pub(crate) struct BlockBuildingMeter { + metric: BlockBuildingMetric, + start: Option, +} diff --git a/crates/derivation-pipeline/src/lib.rs b/crates/derivation-pipeline/src/lib.rs index 06d950f4..47b3ffc5 100644 --- a/crates/derivation-pipeline/src/lib.rs +++ b/crates/derivation-pipeline/src/lib.rs @@ -82,7 +82,7 @@ impl Stream for DerivationPipeline { fn poll_next( self: Pin<&mut Self>, cx: &mut std::task::Context<'_>, - ) -> std::task::Poll> { + ) -> Poll> { let this = self.get_mut(); match Pin::new(&mut this.result_receiver).poll_recv(cx) { Poll::Ready(Some(result)) => { diff --git a/crates/sequencer/src/lib.rs b/crates/sequencer/src/lib.rs index 6376aefb..286bdca0 100644 --- a/crates/sequencer/src/lib.rs +++ b/crates/sequencer/src/lib.rs @@ -101,6 +101,7 @@ where engine: &mut Engine, ) -> Result<(), SequencerError> { tracing::info!(target: "rollup_node::sequencer", "New payload attributes request received."); + let now = Instant::now(); let timestamp = SystemTime::now() .duration_since(UNIX_EPOCH) @@ -114,7 +115,6 @@ where withdrawals: None, }; - let now = Instant::now(); let mut l1_messages = vec![]; let mut cumulative_gas_used = 0; @@ -212,8 +212,8 @@ pub struct PayloadBuildingJob { future: PayloadBuildingJobFuture, } -impl std::fmt::Debug for PayloadBuildingJob { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl fmt::Debug for PayloadBuildingJob { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("PayloadBuildingJob") .field("l1_origin", &self.l1_origin) .field("future", &"PayloadBuildingJobFuture") @@ -265,8 +265,8 @@ impl Stream for Sequencer { } } -impl fmt::Debug for Sequencer { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { +impl fmt::Debug for Sequencer { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Sequencer") .field("provider", &"SequencerMessageProvider") .field("config", &self.config) From e990ebb90866c37a5006b07ba19008b58e34efae Mon Sep 17 00:00:00 2001 From: Gregory Edison Date: Thu, 16 Oct 2025 19:20:37 +0200 Subject: [PATCH 2/4] feat: meter l2 block imports --- crates/chain-orchestrator/src/lib.rs | 2 +- crates/chain-orchestrator/src/metrics.rs | 17 ++++++++++------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/crates/chain-orchestrator/src/lib.rs b/crates/chain-orchestrator/src/lib.rs index 0526eaa1..83250272 100644 --- a/crates/chain-orchestrator/src/lib.rs +++ b/crates/chain-orchestrator/src/lib.rs @@ -779,7 +779,7 @@ impl< match event { ScrollNetworkManagerEvent::NewBlock(block_with_peer) => { self.notify(ChainOrchestratorEvent::NewBlockReceived(block_with_peer.clone())); - Ok(self.handle_block_from_peer(block_with_peer).await?) + metered!(Task::L2BlockImport, self, handle_block_from_peer(block_with_peer)) } } } diff --git a/crates/chain-orchestrator/src/metrics.rs b/crates/chain-orchestrator/src/metrics.rs index 8142a67d..3d793f06 100644 --- a/crates/chain-orchestrator/src/metrics.rs +++ b/crates/chain-orchestrator/src/metrics.rs @@ -49,22 +49,24 @@ impl Default for MetricsHandler { } } -/// An enum representing the chain orchestrator tasks +/// An enum representing the chain orchestrator tasks. #[derive(Debug, PartialEq, Eq, Hash, EnumIter)] pub enum Task { /// Batch reconciliation with the unsafe L2 chain. BatchReconciliation, - /// L1 consolidation. + /// Import of an L2 block received over p2p. + L2BlockImport, + /// Consolidation of the L2 ledger by validating unsafe blocks. L1Consolidation, - /// L1 reorg. + /// L1 reorg handling. L1Reorg, - /// L1 finalization. + /// L1 finalization handling. L1Finalization, - /// L1 message. + /// L1 message handling. L1Message, - /// Batch commit. + /// Batch commit event handling. BatchCommit, - /// Batch finalization. + /// Batch finalization event handling. BatchFinalization, } @@ -79,6 +81,7 @@ impl Task { Self::BatchFinalization => "batch_finalization", Self::BatchReconciliation => "batch_reconciliation", Self::L1Consolidation => "l1_consolidation", + Self::L2BlockImport => "l2_block_import", } } } From 0bc546c0bd5946e96c7cbbc7b089f5dc7c1b9c79 Mon Sep 17 00:00:00 2001 From: Gregory Edison Date: Thu, 16 Oct 2025 19:22:26 +0200 Subject: [PATCH 3/4] fix: change metric visibility --- crates/chain-orchestrator/src/lib.rs | 2 +- crates/chain-orchestrator/src/metrics.rs | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/chain-orchestrator/src/lib.rs b/crates/chain-orchestrator/src/lib.rs index 83250272..914bb661 100644 --- a/crates/chain-orchestrator/src/lib.rs +++ b/crates/chain-orchestrator/src/lib.rs @@ -57,7 +57,7 @@ mod handle; pub use handle::{ChainOrchestratorCommand, ChainOrchestratorHandle}; mod metrics; -pub use metrics::{ChainOrchestratorMetrics, MetricsHandler, Task}; +use metrics::{MetricsHandler, Task}; mod retry; pub use retry::Retry; diff --git a/crates/chain-orchestrator/src/metrics.rs b/crates/chain-orchestrator/src/metrics.rs index 3d793f06..a37cef88 100644 --- a/crates/chain-orchestrator/src/metrics.rs +++ b/crates/chain-orchestrator/src/metrics.rs @@ -5,7 +5,7 @@ use strum::{EnumIter, IntoEnumIterator}; /// The metric handler for the chain orchestrator. Tracks execution duration of various tasks. #[derive(Debug)] -pub struct MetricsHandler { +pub(crate) struct MetricsHandler { /// The chain orchestrator metrics. chain_orchestrator_tasks_metrics: HashMap, /// The inflight block building meter. @@ -14,7 +14,7 @@ pub struct MetricsHandler { impl MetricsHandler { /// Returns the [`ChainOrchestratorMetrics`] for the provided task. - pub fn get(&self, task: Task) -> Option<&ChainOrchestratorMetrics> { + pub(crate) fn get(&self, task: Task) -> Option<&ChainOrchestratorMetrics> { self.chain_orchestrator_tasks_metrics.get(&task) } @@ -51,7 +51,7 @@ impl Default for MetricsHandler { /// An enum representing the chain orchestrator tasks. #[derive(Debug, PartialEq, Eq, Hash, EnumIter)] -pub enum Task { +pub(crate) enum Task { /// Batch reconciliation with the unsafe L2 chain. BatchReconciliation, /// Import of an L2 block received over p2p. @@ -72,7 +72,7 @@ pub enum Task { impl Task { /// Returns the str representation of the [`ChainOrchestratorItem`]. - pub const fn as_str(&self) -> &'static str { + pub(crate) const fn as_str(&self) -> &'static str { match self { Self::L1Reorg => "l1_reorg", Self::L1Finalization => "l1_finalization", @@ -89,7 +89,7 @@ impl Task { /// The metrics for the [`super::ChainOrchestrator`]. #[derive(Metrics, Clone)] #[metrics(scope = "chain_orchestrator")] -pub struct ChainOrchestratorMetrics { +pub(crate) struct ChainOrchestratorMetrics { /// The duration of the task for the chain orchestrator. pub task_duration: Histogram, } From b5388a65e9b69c96e29af6e85ad79fbe1f5cb504 Mon Sep 17 00:00:00 2001 From: Gregory Edison Date: Thu, 16 Oct 2025 19:23:59 +0200 Subject: [PATCH 4/4] chore: renaming --- crates/chain-orchestrator/src/lib.rs | 2 +- crates/chain-orchestrator/src/metrics.rs | 19 +++++++++---------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/crates/chain-orchestrator/src/lib.rs b/crates/chain-orchestrator/src/lib.rs index 914bb661..5f3dd9f8 100644 --- a/crates/chain-orchestrator/src/lib.rs +++ b/crates/chain-orchestrator/src/lib.rs @@ -520,7 +520,7 @@ impl< tracing::info!(target: "scroll::chain_orchestrator", "L1 is now synced"); self.sync_state.l1_mut().set_synced(); if self.sync_state.is_synced() { - metered!(Task::L1Consolidation, self, consolidate_chain())?; + metered!(Task::ChainConsolidation, self, consolidate_chain())?; } self.notify(ChainOrchestratorEvent::L1Synced); Ok(None) diff --git a/crates/chain-orchestrator/src/metrics.rs b/crates/chain-orchestrator/src/metrics.rs index a37cef88..1e5da569 100644 --- a/crates/chain-orchestrator/src/metrics.rs +++ b/crates/chain-orchestrator/src/metrics.rs @@ -57,7 +57,7 @@ pub(crate) enum Task { /// Import of an L2 block received over p2p. L2BlockImport, /// Consolidation of the L2 ledger by validating unsafe blocks. - L1Consolidation, + ChainConsolidation, /// L1 reorg handling. L1Reorg, /// L1 finalization handling. @@ -80,7 +80,7 @@ impl Task { Self::BatchCommit => "batch_commit", Self::BatchFinalization => "batch_finalization", Self::BatchReconciliation => "batch_reconciliation", - Self::L1Consolidation => "l1_consolidation", + Self::ChainConsolidation => "chain_consolidation", Self::L2BlockImport => "l2_block_import", } } @@ -94,18 +94,17 @@ pub(crate) struct ChainOrchestratorMetrics { pub task_duration: Histogram, } -/// Block building related metric. +/// A block building meter. +#[derive(Debug, Default)] +pub(crate) struct BlockBuildingMeter { + metric: BlockBuildingMetric, + start: Option, +} +/// Block building related metric. #[derive(Metrics, Clone)] #[metrics(scope = "chain_orchestrator")] pub(crate) struct BlockBuildingMetric { /// The duration of the block building task. block_building_duration: Histogram, } - -/// A block building meter. -#[derive(Debug, Default)] -pub(crate) struct BlockBuildingMeter { - metric: BlockBuildingMetric, - start: Option, -}