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, HashedPostState, HashedStorage, MultiProof, MultiProofTargets, StorageMultiProof,
12 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 pub(crate) block_time_millis: Histogram,
22 pub(crate) block_time_millis_last: Gauge,
24 pub(crate) total_transactions: Histogram,
26 pub(crate) total_transactions_last: Gauge,
28 pub(crate) payment_transactions: Histogram,
30 pub(crate) payment_transactions_last: Gauge,
32 pub(crate) subblocks: Histogram,
34 pub(crate) subblocks_last: Gauge,
36 pub(crate) subblock_transactions: Histogram,
38 pub(crate) subblock_transactions_last: Gauge,
40 pub(crate) gas_used: Histogram,
42 pub(crate) gas_used_last: Gauge,
44 pub(crate) general_gas_used_last: Gauge,
46 pub(crate) payment_gas_used_last: Gauge,
48 pub(crate) general_gas_limit_last: Gauge,
50 pub(crate) payment_gas_limit_last: Gauge,
52 pub(crate) shared_gas_limit_last: Gauge,
54 pub(crate) pool_fetch_duration_seconds: Histogram,
56 pub(crate) state_setup_duration_seconds: Histogram,
58 pub(crate) prepare_system_transactions_duration_seconds: Histogram,
60 pub(crate) transaction_execution_duration_seconds: Histogram,
62 pub(crate) total_normal_transaction_execution_duration_seconds: Histogram,
64 pub(crate) total_subblock_transaction_execution_duration_seconds: Histogram,
66 pub(crate) subblock_execution_duration_seconds: Histogram,
68 pub(crate) subblock_transaction_count: Histogram,
70 pub(crate) total_transaction_execution_duration_seconds: Histogram,
72 pub(crate) system_transactions_execution_duration_seconds: Histogram,
74 pub(crate) payload_finalization_duration_seconds: Histogram,
76 pub(crate) payload_build_duration_seconds: Histogram,
78 pub(crate) gas_per_second: Histogram,
80 pub(crate) gas_per_second_last: Gauge,
82 pub(crate) rlp_block_size_bytes: Histogram,
84 pub(crate) rlp_block_size_bytes_last: Gauge,
86 pub(crate) hashed_post_state_duration_seconds: Histogram,
88 pub(crate) state_root_with_updates_duration_seconds: Histogram,
90}
91
92impl TempoPayloadBuilderMetrics {
93 #[inline]
98 pub(crate) fn inc_pool_tx_skipped(&self, reason: &'static str) {
99 metrics::counter!("tempo_payload_builder_pool_transactions_skipped_total", "reason" => reason)
100 .increment(1);
101 }
102
103 #[inline]
105 pub(crate) fn inc_build_failure(&self, reason: &'static str) {
106 metrics::counter!("tempo_payload_builder_build_failures_total", "reason" => reason)
107 .increment(1);
108 }
109
110 #[inline]
112 pub(crate) fn inc_subblocks_expired(&self) {
113 metrics::counter!("tempo_payload_builder_subblocks_expired_total").increment(1);
114 }
115}
116
117pub(crate) struct InstrumentedFinishProvider<'a> {
120 pub(crate) inner: &'a dyn StateProvider,
121 pub(crate) metrics: TempoPayloadBuilderMetrics,
122}
123
124impl<'a> AsRef<dyn StateProvider + 'a> for InstrumentedFinishProvider<'a> {
125 fn as_ref(&self) -> &(dyn StateProvider + 'a) {
126 self.inner
127 }
128}
129
130reth_storage_api::delegate_impls_to_as_ref!(
131 for InstrumentedFinishProvider<'_> =>
132 AccountReader {
133 fn basic_account(&self, address: &Address) -> ProviderResult<Option<Account>>;
134 }
135 BlockHashReader {
136 fn block_hash(&self, number: u64) -> ProviderResult<Option<B256>>;
137 fn canonical_hashes_range(&self, start: BlockNumber, end: BlockNumber) -> ProviderResult<Vec<B256>>;
138 }
139 StateProvider {
140 fn storage(&self, account: Address, storage_key: StorageKey) -> ProviderResult<Option<StorageValue>>;
141 }
142 BytecodeReader {
143 fn bytecode_by_hash(&self, code_hash: &B256) -> ProviderResult<Option<Bytecode>>;
144 }
145 StorageRootProvider {
146 fn storage_root(&self, address: Address, storage: HashedStorage) -> ProviderResult<B256>;
147 fn storage_proof(&self, address: Address, slot: B256, storage: HashedStorage) -> ProviderResult<StorageProof>;
148 fn storage_multiproof(&self, address: Address, slots: &[B256], storage: HashedStorage) -> ProviderResult<StorageMultiProof>;
149 }
150 StateProofProvider {
151 fn proof(&self, input: TrieInput, address: Address, slots: &[B256]) -> ProviderResult<AccountProof>;
152 fn multiproof(&self, input: TrieInput, targets: MultiProofTargets) -> ProviderResult<MultiProof>;
153 fn witness(&self, input: TrieInput, target: HashedPostState) -> ProviderResult<Vec<Bytes>>;
154 }
155);
156
157impl HashedPostStateProvider for InstrumentedFinishProvider<'_> {
158 fn hashed_post_state(&self, bundle_state: &reth_revm::db::BundleState) -> HashedPostState {
159 let start = Instant::now();
160 let _span = debug_span!(target: "payload_builder", "hashed_post_state").entered();
161 let result = self.inner.hashed_post_state(bundle_state);
162 drop(_span);
163 self.metrics
164 .hashed_post_state_duration_seconds
165 .record(start.elapsed());
166 result
167 }
168}
169
170impl StateRootProvider for InstrumentedFinishProvider<'_> {
171 fn state_root(&self, hashed_state: HashedPostState) -> ProviderResult<B256> {
172 let start = Instant::now();
173 let _span = debug_span!(target: "payload_builder", "state_root").entered();
174 let result = self.inner.state_root(hashed_state);
175 drop(_span);
176 self.metrics
177 .state_root_with_updates_duration_seconds
178 .record(start.elapsed());
179 result
180 }
181
182 fn state_root_from_nodes(&self, input: TrieInput) -> ProviderResult<B256> {
183 self.inner.state_root_from_nodes(input)
184 }
185
186 fn state_root_with_updates(
187 &self,
188 hashed_state: HashedPostState,
189 ) -> ProviderResult<(B256, TrieUpdates)> {
190 let start = Instant::now();
191 let _span = debug_span!(target: "payload_builder", "state_root_with_updates").entered();
192 let result = self.inner.state_root_with_updates(hashed_state);
193 drop(_span);
194 self.metrics
195 .state_root_with_updates_duration_seconds
196 .record(start.elapsed());
197 result
198 }
199
200 fn state_root_from_nodes_with_updates(
201 &self,
202 input: TrieInput,
203 ) -> ProviderResult<(B256, TrieUpdates)> {
204 self.inner.state_root_from_nodes_with_updates(input)
205 }
206}