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 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) state_gas_used: Histogram,
46 pub(crate) state_gas_used_last: Gauge,
48 pub(crate) general_gas_used_last: Gauge,
50 pub(crate) payment_gas_used_last: Gauge,
52 pub(crate) general_gas_limit_last: Gauge,
54 pub(crate) payment_gas_limit_last: Gauge,
56 pub(crate) shared_gas_limit_last: Gauge,
58 pub(crate) pool_fetch_duration_seconds: Histogram,
60 pub(crate) state_setup_duration_seconds: Histogram,
62 pub(crate) prepare_system_transactions_duration_seconds: Histogram,
64 pub(crate) transaction_execution_duration_seconds: Histogram,
66 pub(crate) total_normal_transaction_execution_duration_seconds: Histogram,
68 pub(crate) total_subblock_transaction_execution_duration_seconds: Histogram,
70 pub(crate) subblock_execution_duration_seconds: Histogram,
72 pub(crate) subblock_transaction_count: Histogram,
74 pub(crate) total_transaction_execution_duration_seconds: Histogram,
76 pub(crate) system_transactions_execution_duration_seconds: Histogram,
78 pub(crate) payload_finalization_duration_seconds: Histogram,
80 pub(crate) payload_build_duration_seconds: Histogram,
82 pub(crate) gas_per_second: Histogram,
84 pub(crate) gas_per_second_last: Gauge,
86 pub(crate) rlp_block_size_bytes: Histogram,
88 pub(crate) rlp_block_size_bytes_last: Gauge,
90 pub(crate) hashed_post_state_duration_seconds: Histogram,
92 pub(crate) state_root_with_updates_duration_seconds: Histogram,
94}
95
96impl TempoPayloadBuilderMetrics {
97 #[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 #[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 #[inline]
116 pub(crate) fn inc_subblocks_expired(&self) {
117 metrics::counter!("tempo_payload_builder_subblocks_expired_total").increment(1);
118 }
119}
120
121pub(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}