Skip to main content

tempo_payload_builder/
metrics.rs

1use alloy_primitives::{Address, B256, BlockNumber, Bytes, StorageKey, StorageValue};
2use metrics::Gauge;
3use reth_errors::ProviderResult;
4use reth_metrics::{Metrics, metrics::Histogram};
5use reth_primitives_traits::{Account, Bytecode};
6use reth_storage_api::{
7    AccountReader, BlockHashReader, BytecodeReader, HashedPostStateProvider, StateProofProvider,
8    StateProvider, StateRootProvider, StorageRootProvider,
9};
10use reth_trie_common::{
11    AccountProof, ExecutionWitnessMode, HashedPostState, HashedStorage, MultiProof,
12    MultiProofTargets, StorageMultiProof, StorageProof, TrieInput, updates::TrieUpdates,
13};
14use std::time::Instant;
15use tracing::debug_span;
16
17#[derive(Metrics, Clone)]
18#[metrics(scope = "tempo_payload_builder")]
19pub(crate) struct TempoPayloadBuilderMetrics {
20    /// Block time in milliseconds.
21    pub(crate) block_time_millis: Histogram,
22    /// Block time in milliseconds.
23    pub(crate) block_time_millis_last: Gauge,
24    /// Number of transactions in the payload.
25    pub(crate) total_transactions: Histogram,
26    /// Number of transactions in the payload.
27    pub(crate) total_transactions_last: Gauge,
28    /// Number of payment transactions in the payload.
29    pub(crate) payment_transactions: Histogram,
30    /// Number of payment transactions in the payload.
31    pub(crate) payment_transactions_last: Gauge,
32    /// Number of subblocks in the payload.
33    pub(crate) subblocks: Histogram,
34    /// Number of subblocks in the payload.
35    pub(crate) subblocks_last: Gauge,
36    /// Number of subblock transactions in the payload.
37    pub(crate) subblock_transactions: Histogram,
38    /// Number of subblock transactions in the payload.
39    pub(crate) subblock_transactions_last: Gauge,
40    /// Amount of gas used in the payload.
41    pub(crate) gas_used: Histogram,
42    /// Amount of gas used in the payload.
43    pub(crate) gas_used_last: Gauge,
44    /// State gas used in the payload (TIP-1016).
45    pub(crate) state_gas_used: Histogram,
46    /// State gas used in the last payload (TIP-1016).
47    pub(crate) state_gas_used_last: Gauge,
48    /// Gas used by general (non-payment) transactions in the payload.
49    pub(crate) general_gas_used_last: Gauge,
50    /// Gas used by payment transactions in the payload.
51    pub(crate) payment_gas_used_last: Gauge,
52    /// General lane gas limit.
53    pub(crate) general_gas_limit_last: Gauge,
54    /// Payment lane gas limit.
55    pub(crate) payment_gas_limit_last: Gauge,
56    /// Shared (subblock) gas limit.
57    pub(crate) shared_gas_limit_last: Gauge,
58    /// Time to create the pool's `BestTransactions` iterator, including lock acquisition and snapshot.
59    pub(crate) pool_fetch_duration_seconds: Histogram,
60    /// Time to acquire the state provider and initialize the state DB.
61    pub(crate) state_setup_duration_seconds: Histogram,
62    /// The time it took to prepare system transactions in seconds.
63    pub(crate) prepare_system_transactions_duration_seconds: Histogram,
64    /// The time it took to execute one transaction in seconds.
65    pub(crate) transaction_execution_duration_seconds: Histogram,
66    /// The time it took to execute normal transactions in seconds.
67    pub(crate) total_normal_transaction_execution_duration_seconds: Histogram,
68    /// The time it took to execute subblock transactions in seconds.
69    pub(crate) total_subblock_transaction_execution_duration_seconds: Histogram,
70    /// Execution time for a single subblock.
71    pub(crate) subblock_execution_duration_seconds: Histogram,
72    /// Number of transactions in a single subblock.
73    pub(crate) subblock_transaction_count: Histogram,
74    /// The time it took to execute all transactions in seconds.
75    pub(crate) total_transaction_execution_duration_seconds: Histogram,
76    /// The time it took to execute system transactions in seconds.
77    pub(crate) system_transactions_execution_duration_seconds: Histogram,
78    /// The time it took to finalize the payload in seconds. Includes merging transitions and calculating the state root.
79    pub(crate) payload_finalization_duration_seconds: Histogram,
80    /// Total time it took to build the payload in seconds.
81    pub(crate) payload_build_duration_seconds: Histogram,
82    /// Gas per second calculated as gas_used / payload_build_duration.
83    pub(crate) gas_per_second: Histogram,
84    /// Gas per second for the last payload calculated as gas_used / payload_build_duration.
85    pub(crate) gas_per_second_last: Gauge,
86    /// RLP-encoded block size in bytes.
87    pub(crate) rlp_block_size_bytes: Histogram,
88    /// RLP-encoded block size in bytes for the last payload.
89    pub(crate) rlp_block_size_bytes_last: Gauge,
90    /// Time to compute the hashed post-state from the bundle state.
91    pub(crate) hashed_post_state_duration_seconds: Histogram,
92    /// Time to compute the state root and trie updates via `state_root_with_updates`.
93    pub(crate) state_root_with_updates_duration_seconds: Histogram,
94}
95
96impl TempoPayloadBuilderMetrics {
97    /// Increments the unified pool transaction skip counter with the given reason label.
98    ///
99    /// Note: `mark_invalid` may also prune descendant transactions from the iterator,
100    /// so the skip count represents skip *events*, not total transactions removed.
101    #[inline]
102    pub(crate) fn inc_pool_tx_skipped(&self, reason: &'static str) {
103        metrics::counter!("tempo_payload_builder_pool_transactions_skipped_total", "reason" => reason)
104            .increment(1);
105    }
106
107    /// Increments the build failure counter for a given reason.
108    #[inline]
109    pub(crate) fn inc_build_failure(&self, reason: &'static str) {
110        metrics::counter!("tempo_payload_builder_build_failures_total", "reason" => reason)
111            .increment(1);
112    }
113
114    /// Increments the counter for subblocks dropped due to expired transactions.
115    #[inline]
116    pub(crate) fn inc_subblocks_expired(&self) {
117        metrics::counter!("tempo_payload_builder_subblocks_expired_total").increment(1);
118    }
119}
120
121/// Wraps a [`StateProvider`] reference to instrument `hashed_post_state` and
122/// `state_root_with_updates` with tracing spans and histogram metrics during `builder.finish()`.
123pub(crate) struct InstrumentedFinishProvider<'a> {
124    pub(crate) inner: &'a dyn StateProvider,
125    pub(crate) metrics: TempoPayloadBuilderMetrics,
126}
127
128impl<'a> AsRef<dyn StateProvider + 'a> for InstrumentedFinishProvider<'a> {
129    fn as_ref(&self) -> &(dyn StateProvider + 'a) {
130        self.inner
131    }
132}
133
134reth_storage_api::delegate_impls_to_as_ref!(
135    for InstrumentedFinishProvider<'_> =>
136    AccountReader {
137        fn basic_account(&self, address: &Address) -> ProviderResult<Option<Account>>;
138    }
139    BlockHashReader {
140        fn block_hash(&self, number: u64) -> ProviderResult<Option<B256>>;
141        fn canonical_hashes_range(&self, start: BlockNumber, end: BlockNumber) -> ProviderResult<Vec<B256>>;
142    }
143    StateProvider {
144        fn storage(&self, account: Address, storage_key: StorageKey) -> ProviderResult<Option<StorageValue>>;
145    }
146    BytecodeReader {
147        fn bytecode_by_hash(&self, code_hash: &B256) -> ProviderResult<Option<Bytecode>>;
148    }
149    StorageRootProvider {
150        fn storage_root(&self, address: Address, storage: HashedStorage) -> ProviderResult<B256>;
151        fn storage_proof(&self, address: Address, slot: B256, storage: HashedStorage) -> ProviderResult<StorageProof>;
152        fn storage_multiproof(&self, address: Address, slots: &[B256], storage: HashedStorage) -> ProviderResult<StorageMultiProof>;
153    }
154    StateProofProvider {
155        fn proof(&self, input: TrieInput, address: Address, slots: &[B256]) -> ProviderResult<AccountProof>;
156        fn multiproof(&self, input: TrieInput, targets: MultiProofTargets) -> ProviderResult<MultiProof>;
157        fn witness(&self, input: TrieInput, target: HashedPostState, mode: ExecutionWitnessMode) -> ProviderResult<Vec<Bytes>>;
158    }
159);
160
161impl HashedPostStateProvider for InstrumentedFinishProvider<'_> {
162    fn hashed_post_state(&self, bundle_state: &reth_revm::db::BundleState) -> HashedPostState {
163        let start = Instant::now();
164        let _span = debug_span!(target: "payload_builder", "hashed_post_state").entered();
165        let result = self.inner.hashed_post_state(bundle_state);
166        drop(_span);
167        self.metrics
168            .hashed_post_state_duration_seconds
169            .record(start.elapsed());
170        result
171    }
172}
173
174impl StateRootProvider for InstrumentedFinishProvider<'_> {
175    fn state_root(&self, hashed_state: HashedPostState) -> ProviderResult<B256> {
176        let start = Instant::now();
177        let _span = debug_span!(target: "payload_builder", "state_root").entered();
178        let result = self.inner.state_root(hashed_state);
179        drop(_span);
180        self.metrics
181            .state_root_with_updates_duration_seconds
182            .record(start.elapsed());
183        result
184    }
185
186    fn state_root_from_nodes(&self, input: TrieInput) -> ProviderResult<B256> {
187        self.inner.state_root_from_nodes(input)
188    }
189
190    fn state_root_with_updates(
191        &self,
192        hashed_state: HashedPostState,
193    ) -> ProviderResult<(B256, TrieUpdates)> {
194        let start = Instant::now();
195        let _span = debug_span!(target: "payload_builder", "state_root_with_updates").entered();
196        let result = self.inner.state_root_with_updates(hashed_state);
197        drop(_span);
198        self.metrics
199            .state_root_with_updates_duration_seconds
200            .record(start.elapsed());
201        result
202    }
203
204    fn state_root_from_nodes_with_updates(
205        &self,
206        input: TrieInput,
207    ) -> ProviderResult<(B256, TrieUpdates)> {
208        self.inner.state_root_from_nodes_with_updates(input)
209    }
210}