diff --git a/crates/op-rbuilder/src/backrun_bundle/mod.rs b/crates/op-rbuilder/src/backrun_bundle/mod.rs index 6f4621253..877f72d52 100644 --- a/crates/op-rbuilder/src/backrun_bundle/mod.rs +++ b/crates/op-rbuilder/src/backrun_bundle/mod.rs @@ -41,8 +41,9 @@ //! processing backruns. //! //! Backrun transactions also increment the shared builder counters -//! (`num_txs_considered`, `num_txs_simulated_success`, `num_bundles_reverted`, -//! etc.) so they are reflected in overall payload build statistics. +//! (`num_txs_considered`, `num_txs_simulated_success`, `num_txs_simulated_fail`, +//! etc.) and the source/result-labeled payload simulation metrics, so they are +//! reflected in overall payload build statistics. mod args; mod global_pool; diff --git a/crates/op-rbuilder/src/builder/context.rs b/crates/op-rbuilder/src/builder/context.rs index 39fdc7c2e..2ea45cf6a 100644 --- a/crates/op-rbuilder/src/builder/context.rs +++ b/crates/op-rbuilder/src/builder/context.rs @@ -37,7 +37,9 @@ use crate::{ evm::OpBlockEvmFactory, gas_limiter::AddressGasLimiter, hardforks::ActiveHardforks, - metrics::OpRBuilderMetrics, + metrics::{ + OpRBuilderMetrics, TxResult, TxSource, record_tx_gas_used, record_tx_simulation_duration, + }, primitives::reth::{ExecutionInfo, TxnExecutionResult}, traits::PayloadTxsBounds, }; @@ -387,10 +389,17 @@ impl OpPayloadJobCtx { ) -> Result, PayloadBuilderError> { let execute_txs_start_time = Instant::now(); let mut num_txs_considered = 0; - let mut num_txs_simulated = 0; let mut num_txs_simulated_success = 0; let mut num_txs_simulated_fail = 0; - let mut num_bundles_reverted = 0; + let mut num_mempool_txs_simulated_success = 0; + let mut num_mempool_txs_simulated_revert = 0; + let mut num_mempool_txs_simulated_halt = 0; + let mut num_bundle_txs_simulated_success = 0; + let mut num_bundle_txs_simulated_revert = 0; + let mut num_bundle_txs_simulated_halt = 0; + let mut num_backrun_txs_simulated_success = 0; + let mut num_backrun_txs_simulated_revert = 0; + let mut num_backrun_txs_simulated_halt = 0; let mut reverted_gas_used: u64 = 0; let mut num_backruns_considered = 0usize; let mut num_backruns_successful = 0usize; @@ -420,7 +429,12 @@ impl OpPayloadJobCtx { let tx_da_size = tx.estimated_da_size(); let is_bundle_tx = tx.is_bundle(); - let exclude_reverting_txs = tx.revert_protected(); + let revert_protected = tx.revert_protected(); + let tx_source = if is_bundle_tx { + TxSource::Bundle + } else { + TxSource::Mempool + }; let tx = tx.into_consensus(); let tx_hash = tx.tx_hash(); @@ -443,7 +457,7 @@ impl OpPayloadJobCtx { id = %self.payload_id(), tx_hash = %tx_hash, tx_da_size, - exclude_reverting_txs, + revert_protected, result = %result, "Considering transaction", ); @@ -528,11 +542,15 @@ impl OpPayloadJobCtx { } }; - self.metrics - .tx_simulation_duration - .record(tx_simulation_start_time.elapsed()); + let tx_simulation_elapsed = tx_simulation_start_time.elapsed(); + let tx_result = TxResult::from_execution_result(&result); + record_tx_simulation_duration( + tx_simulation_elapsed, + tx_source, + tx_result, + revert_protected, + ); self.metrics.tx_byte_size.record(tx.inner().size() as f64); - num_txs_simulated += 1; // Run the per-address gas limiting before checking if the tx has // reverted or not, as this is a check against maliciously searchers @@ -546,7 +564,7 @@ impl OpPayloadJobCtx { flashblock_index, gas_used, success = result.is_success(), - evm_duration_us = tx_simulation_start_time.elapsed().as_micros() as u64, + evm_duration_us = tx_simulation_elapsed.as_micros() as u64, stage = "evm_executed" ); } @@ -561,18 +579,36 @@ impl OpPayloadJobCtx { continue; } + record_tx_gas_used(gas_used, tx_source, tx_result, revert_protected); if result.is_success() { log_txn(TxnExecutionResult::Success); num_txs_simulated_success += 1; - self.metrics.successful_tx_gas_used.record(gas_used as f64); + match tx_source { + TxSource::Mempool => num_mempool_txs_simulated_success += 1, + TxSource::Bundle => num_bundle_txs_simulated_success += 1, + TxSource::Backrun => unreachable!("backruns are handled in the backrun loop"), + } } else { num_txs_simulated_fail += 1; reverted_gas_used += gas_used; - self.metrics.reverted_tx_gas_used.record(gas_used as f64); - if is_bundle_tx { - num_bundles_reverted += 1; + match tx_source { + TxSource::Mempool => match tx_result { + TxResult::Revert => num_mempool_txs_simulated_revert += 1, + TxResult::Halt => num_mempool_txs_simulated_halt += 1, + TxResult::Success => { + unreachable!("successes are handled in the success branch") + } + }, + TxSource::Bundle => match tx_result { + TxResult::Revert => num_bundle_txs_simulated_revert += 1, + TxResult::Halt => num_bundle_txs_simulated_halt += 1, + TxResult::Success => { + unreachable!("successes are handled in the success branch") + } + }, + TxSource::Backrun => unreachable!("backruns are handled in the backrun loop"), } - if exclude_reverting_txs { + if revert_protected { log_txn(TxnExecutionResult::RevertedAndExcluded); trace!( target: "payload_builder", @@ -699,8 +735,8 @@ impl OpPayloadJobCtx { // - [x] log when tx execution fails // - [x] inc num_txs_simulated_success or num_txs_simulated_fail // - [x] inc reverted_gas_used - // - [x] metrics use successful_tx_gas_used and reverted_tx_gas_used - // - [x] inc num_bundles_reverted + // - [x] meter tx_gas_used + // - [x] meter payload simulated counts by source/result // - [x] enforce self.max_gas_per_txn // - [x] increase info.{cumulative_gas_used, cumulative_da_bytes_used} // - [x] push receipt to info.receipts @@ -809,13 +845,16 @@ impl OpPayloadJobCtx { continue; } }; - self.metrics - .tx_simulation_duration - .record(br_simulation_start.elapsed()); + let br_tx_result = TxResult::from_execution_result(&br_result); + record_tx_simulation_duration( + br_simulation_start.elapsed(), + TxSource::Backrun, + br_tx_result, + true, + ); self.metrics .tx_byte_size .record(bundle.backrun_tx.inner().size() as f64); - num_txs_simulated += 1; let br_gas_used = br_result.gas_used(); @@ -828,11 +867,17 @@ impl OpPayloadJobCtx { continue; } + record_tx_gas_used(br_gas_used, TxSource::Backrun, br_tx_result, true); if !br_result.is_success() { num_txs_simulated_fail += 1; - num_bundles_reverted += 1; reverted_gas_used += br_gas_used; - self.metrics.reverted_tx_gas_used.record(br_gas_used as f64); + match br_tx_result { + TxResult::Revert => num_backrun_txs_simulated_revert += 1, + TxResult::Halt => num_backrun_txs_simulated_halt += 1, + TxResult::Success => { + unreachable!("successes are handled in the success branch") + } + } log_br_txn(TxnExecutionResult::RevertedAndExcluded); continue; } @@ -861,10 +906,8 @@ impl OpPayloadJobCtx { } num_txs_simulated_success += 1; + num_backrun_txs_simulated_success += 1; num_backruns_successful += 1; - self.metrics - .successful_tx_gas_used - .record(br_gas_used as f64); log_br_txn(TxnExecutionResult::Success); info.cumulative_gas_used += br_gas_used; info.cumulative_da_bytes_used += br_tx_da_size; @@ -901,10 +944,15 @@ impl OpPayloadJobCtx { self.metrics.set_payload_builder_metrics( payload_transaction_simulation_time, num_txs_considered, - num_txs_simulated, - num_txs_simulated_success, - num_txs_simulated_fail, - num_bundles_reverted, + num_mempool_txs_simulated_success, + num_mempool_txs_simulated_revert, + num_mempool_txs_simulated_halt, + num_bundle_txs_simulated_success, + num_bundle_txs_simulated_revert, + num_bundle_txs_simulated_halt, + num_backrun_txs_simulated_success, + num_backrun_txs_simulated_revert, + num_backrun_txs_simulated_halt, reverted_gas_used, num_backruns_considered as f64, num_backruns_successful as f64, @@ -917,7 +965,10 @@ impl OpPayloadJobCtx { txs_executed = num_txs_considered, txs_applied = num_txs_simulated_success, txs_rejected = num_txs_simulated_fail, - bundles_reverted = num_bundles_reverted, + bundle_txs_reverted = num_bundle_txs_simulated_revert, + bundle_txs_halted = num_bundle_txs_simulated_halt, + backrun_txs_reverted = num_backrun_txs_simulated_revert, + backrun_txs_halted = num_backrun_txs_simulated_halt, backruns_considered = num_backruns_considered, backruns_successful = num_backruns_successful, "Completed executing best transactions", diff --git a/crates/op-rbuilder/src/builder/payload.rs b/crates/op-rbuilder/src/builder/payload.rs index c7f1acb3c..3adc428bf 100644 --- a/crates/op-rbuilder/src/builder/payload.rs +++ b/crates/op-rbuilder/src/builder/payload.rs @@ -998,7 +998,6 @@ where .transaction_pool_fetch_gauge .set(transaction_pool_fetch_time); - let tx_execution_start_time = Instant::now(); ctx.execute_best_transactions( info, state, @@ -1029,14 +1028,6 @@ where return Ok(None); } - let payload_transaction_simulation_time = tx_execution_start_time.elapsed(); - ctx.metrics - .payload_transaction_simulation_duration - .record(payload_transaction_simulation_time); - ctx.metrics - .payload_transaction_simulation_gauge - .set(payload_transaction_simulation_time); - if let Err(e) = self.builder_tx.add_builder_txs( &state_provider, info, diff --git a/crates/op-rbuilder/src/metrics.rs b/crates/op-rbuilder/src/metrics.rs index 20c692a02..e3a9c0e77 100644 --- a/crates/op-rbuilder/src/metrics.rs +++ b/crates/op-rbuilder/src/metrics.rs @@ -4,6 +4,7 @@ use reth_metrics::{ Metrics, metrics::{Counter, Gauge, Histogram, gauge, histogram}, }; +use revm::context::result::ExecutionResult; use crate::{ args::OpRbuilderArgs, @@ -121,26 +122,8 @@ pub struct OpRBuilderMetrics { pub payload_num_tx: Histogram, /// Latest number of transactions in the payload pub payload_num_tx_gauge: Gauge, - /// Histogram of transactions in the payload that were successfully simulated - pub payload_num_tx_simulated: Histogram, - /// Latest number of transactions in the payload that were successfully simulated - pub payload_num_tx_simulated_gauge: Gauge, - /// Histogram of transactions in the payload that were successfully simulated - pub payload_num_tx_simulated_success: Histogram, - /// Latest number of transactions in the payload that were successfully simulated - pub payload_num_tx_simulated_success_gauge: Gauge, - /// Histogram of transactions in the payload that failed simulation - pub payload_num_tx_simulated_fail: Histogram, - /// Latest number of transactions in the payload that failed simulation - pub payload_num_tx_simulated_fail_gauge: Gauge, - /// Histogram of gas used by successful transactions - pub successful_tx_gas_used: Histogram, - /// Histogram of gas used by reverted transactions - pub reverted_tx_gas_used: Histogram, /// Gas used by reverted transactions in the latest block pub payload_reverted_tx_gas_used: Gauge, - /// Histogram of tx simulation duration - pub tx_simulation_duration: Histogram, /// Byte size of transactions pub tx_byte_size: Histogram, /// How much less flashblocks we issue to be on time with block construction @@ -155,8 +138,6 @@ pub struct OpRBuilderMetrics { pub valid_bundles: Counter, /// Number of bundles that failed to execute pub failed_bundles: Counter, - /// Number of reverted bundles - pub bundles_reverted: Histogram, /// Histogram of eth_sendBundle request duration pub bundle_receive_duration: Histogram, /// Number of bundles dropped by pre-simulation (reverted) @@ -211,10 +192,15 @@ impl OpRBuilderMetrics { &self, payload_transaction_simulation_time: impl IntoF64 + Copy, num_txs_considered: impl IntoF64 + Copy, - num_txs_simulated: impl IntoF64 + Copy, - num_txs_simulated_success: impl IntoF64 + Copy, - num_txs_simulated_fail: impl IntoF64 + Copy, - num_bundles_reverted: impl IntoF64, + num_mempool_txs_simulated_success: impl IntoF64 + Copy, + num_mempool_txs_simulated_revert: impl IntoF64 + Copy, + num_mempool_txs_simulated_halt: impl IntoF64 + Copy, + num_bundle_txs_simulated_success: impl IntoF64 + Copy, + num_bundle_txs_simulated_revert: impl IntoF64 + Copy, + num_bundle_txs_simulated_halt: impl IntoF64 + Copy, + num_backrun_txs_simulated_success: impl IntoF64 + Copy, + num_backrun_txs_simulated_revert: impl IntoF64 + Copy, + num_backrun_txs_simulated_halt: impl IntoF64 + Copy, reverted_gas_used: u64, num_backruns_considered: impl IntoF64 + Copy, num_backruns_successful: impl IntoF64 + Copy, @@ -226,17 +212,96 @@ impl OpRBuilderMetrics { .set(payload_transaction_simulation_time); self.payload_num_tx_considered.record(num_txs_considered); self.payload_num_tx_considered_gauge.set(num_txs_considered); - self.payload_num_tx_simulated.record(num_txs_simulated); - self.payload_num_tx_simulated_gauge.set(num_txs_simulated); - self.payload_num_tx_simulated_success - .record(num_txs_simulated_success); - self.payload_num_tx_simulated_success_gauge - .set(num_txs_simulated_success); - self.payload_num_tx_simulated_fail - .record(num_txs_simulated_fail); - self.payload_num_tx_simulated_fail_gauge - .set(num_txs_simulated_fail); - self.bundles_reverted.record(num_bundles_reverted); + record_payload_num_tx_simulated( + num_mempool_txs_simulated_success, + TxSource::Mempool, + TxResult::Success, + ); + set_payload_num_tx_simulated_gauge( + num_mempool_txs_simulated_success, + TxSource::Mempool, + TxResult::Success, + ); + record_payload_num_tx_simulated( + num_mempool_txs_simulated_revert, + TxSource::Mempool, + TxResult::Revert, + ); + set_payload_num_tx_simulated_gauge( + num_mempool_txs_simulated_revert, + TxSource::Mempool, + TxResult::Revert, + ); + record_payload_num_tx_simulated( + num_mempool_txs_simulated_halt, + TxSource::Mempool, + TxResult::Halt, + ); + set_payload_num_tx_simulated_gauge( + num_mempool_txs_simulated_halt, + TxSource::Mempool, + TxResult::Halt, + ); + record_payload_num_tx_simulated( + num_bundle_txs_simulated_success, + TxSource::Bundle, + TxResult::Success, + ); + set_payload_num_tx_simulated_gauge( + num_bundle_txs_simulated_success, + TxSource::Bundle, + TxResult::Success, + ); + record_payload_num_tx_simulated( + num_bundle_txs_simulated_revert, + TxSource::Bundle, + TxResult::Revert, + ); + set_payload_num_tx_simulated_gauge( + num_bundle_txs_simulated_revert, + TxSource::Bundle, + TxResult::Revert, + ); + record_payload_num_tx_simulated( + num_bundle_txs_simulated_halt, + TxSource::Bundle, + TxResult::Halt, + ); + set_payload_num_tx_simulated_gauge( + num_bundle_txs_simulated_halt, + TxSource::Bundle, + TxResult::Halt, + ); + record_payload_num_tx_simulated( + num_backrun_txs_simulated_success, + TxSource::Backrun, + TxResult::Success, + ); + set_payload_num_tx_simulated_gauge( + num_backrun_txs_simulated_success, + TxSource::Backrun, + TxResult::Success, + ); + record_payload_num_tx_simulated( + num_backrun_txs_simulated_revert, + TxSource::Backrun, + TxResult::Revert, + ); + set_payload_num_tx_simulated_gauge( + num_backrun_txs_simulated_revert, + TxSource::Backrun, + TxResult::Revert, + ); + record_payload_num_tx_simulated( + num_backrun_txs_simulated_halt, + TxSource::Backrun, + TxResult::Halt, + ); + set_payload_num_tx_simulated_gauge( + num_backrun_txs_simulated_halt, + TxSource::Backrun, + TxResult::Halt, + ); self.payload_reverted_tx_gas_used .set(reverted_gas_used as f64); self.payload_num_backruns_considered @@ -254,6 +319,108 @@ impl OpRBuilderMetrics { } } +/// Origin of a transaction processed by the builder, used as the `source` +/// label on per-tx metrics. +#[derive(Copy, Clone, Debug)] +pub enum TxSource { + /// Public mempool transaction. + Mempool, + /// Transaction from an `eth_sendBundle` bundle. + Bundle, + /// Backrun transaction from the backrun bundle pool. + Backrun, +} + +impl TxSource { + fn as_label(self) -> &'static str { + match self { + Self::Mempool => "mempool", + Self::Bundle => "bundle", + Self::Backrun => "backrun", + } + } +} + +/// Outcome of EVM execution for a transaction +#[derive(Copy, Clone, Debug)] +pub enum TxResult { + Success, + Revert, + Halt, +} + +impl TxResult { + fn as_label(self) -> &'static str { + match self { + Self::Success => "success", + Self::Revert => "revert", + Self::Halt => "halt", + } + } + + pub fn from_execution_result(result: &ExecutionResult) -> Self { + match result { + ExecutionResult::Success { .. } => Self::Success, + ExecutionResult::Halt { .. } => Self::Halt, + ExecutionResult::Revert { .. } => Self::Revert, + } + } +} + +fn revert_protected_label(revert_protected: bool) -> &'static str { + if revert_protected { "true" } else { "false" } +} + +/// Record tx simulation duration with source/result/revert_protected labels. +pub fn record_tx_simulation_duration( + duration: std::time::Duration, + source: TxSource, + result: TxResult, + revert_protected: bool, +) { + histogram!( + "op_rbuilder_tx_simulation_duration", + "source" => source.as_label(), + "result" => result.as_label(), + "revert_protected" => revert_protected_label(revert_protected), + ) + .record(duration.as_secs_f64()); +} + +/// Record gas used by a transaction with source/result/revert_protected labels. +pub fn record_tx_gas_used( + gas_used: u64, + source: TxSource, + result: TxResult, + revert_protected: bool, +) { + histogram!( + "op_rbuilder_tx_gas_used", + "source" => source.as_label(), + "result" => result.as_label(), + "revert_protected" => revert_protected_label(revert_protected), + ) + .record(gas_used as f64); +} + +pub fn record_payload_num_tx_simulated(count: impl IntoF64, source: TxSource, result: TxResult) { + histogram!( + "op_rbuilder_payload_num_tx_simulated", + "source" => source.as_label(), + "result" => result.as_label(), + ) + .record(count); +} + +pub fn set_payload_num_tx_simulated_gauge(count: impl IntoF64, source: TxSource, result: TxResult) { + gauge!( + "op_rbuilder_payload_num_tx_simulated_gauge", + "source" => source.as_label(), + "result" => result.as_label(), + ) + .set(count); +} + /// Record the slot-relative time at which a flashblock was published. /// `offset_ms` is the time elapsed since slot start (payload_timestamp - block_time) pub fn record_flashblock_publish_timing(flashblock_index: u64, offset_ms: f64) {