diff --git a/crates/rbuilder/src/bin/dummy-builder.rs b/crates/rbuilder/src/bin/dummy-builder.rs index 011683c0d..88773bf9e 100644 --- a/crates/rbuilder/src/bin/dummy-builder.rs +++ b/crates/rbuilder/src/bin/dummy-builder.rs @@ -34,7 +34,9 @@ use rbuilder::{ LiveBuilder, }, mev_boost::RelayClient, - primitives::{mev_boost::MevBoostRelaySlotInfoProvider, SimulatedOrder}, + primitives::{ + mev_boost::MevBoostRelaySlotInfoProvider, order_statistics::OrderStatistics, SimulatedOrder, + }, provider::StateProviderFactory, utils::{ProviderFactoryReopener, Signer}, }; @@ -213,13 +215,17 @@ impl DummyBuildingAlgorithm { let block_state = provider .history_by_block_hash(ctx.attributes.parent)? .into(); - + let mut order_statistics = OrderStatistics::new(); + for sim_order in &orders { + order_statistics.add(&sim_order.order); + } let mut block_building_helper = BlockBuildingHelperFromProvider::new( block_state, ctx.clone(), &mut local_ctx, BUILDER_NAME.to_string(), false, + order_statistics, CancellationToken::new(), )?; diff --git a/crates/rbuilder/src/building/block_orders/prioritized_order_store.rs b/crates/rbuilder/src/building/block_orders/prioritized_order_store.rs index 91c5e45a6..c663421c5 100644 --- a/crates/rbuilder/src/building/block_orders/prioritized_order_store.rs +++ b/crates/rbuilder/src/building/block_orders/prioritized_order_store.rs @@ -5,7 +5,7 @@ use alloy_primitives::Address; use priority_queue::PriorityQueue; use crate::{ - primitives::{AccountNonce, Nonce, OrderId, SimulatedOrder}, + primitives::{order_statistics::OrderStatistics, AccountNonce, Nonce, OrderId, SimulatedOrder}, telemetry::mark_order_not_ready_for_immediate_inclusion, }; @@ -39,6 +39,8 @@ pub struct PrioritizedOrderStore { pending_orders: HashMap>, /// Id -> order for all orders we manage. Carefully maintained by remove/insert orders: HashMap>, + /// Everything in orders + orders_statistics: OrderStatistics, } impl PrioritizedOrderStore { @@ -53,9 +55,14 @@ impl PrioritizedOrderStore onchain_nonces, pending_orders: HashMap::default(), orders: HashMap::default(), + orders_statistics: Default::default(), } } + pub fn orders_statistics(&self) -> OrderStatistics { + self.orders_statistics.clone() + } + pub fn pop_order(&mut self) -> Option> { let (id, _) = self.main_queue.pop()?; @@ -67,7 +74,7 @@ impl PrioritizedOrderStore /// Clean up after some order was removed from main_queue fn remove_poped_order(&mut self, id: &OrderId) -> Option> { - let sim_order = self.orders.remove(id)?; + let sim_order = self.remove_from_orders(id)?; for Nonce { address, .. } in sim_order.order.nonces() { match self.main_queue_nonces.entry(address) { Entry::Occupied(mut entry) => { @@ -135,7 +142,7 @@ impl PrioritizedOrderStore if let Some(pending) = self.pending_orders.remove(new_nonce) { let orders = pending .iter() - .filter_map(|id| self.orders.remove(id)) + .filter_map(|id| self.remove_from_orders(id)) .collect::>(); for order in orders { self.insert_order(order); @@ -147,6 +154,15 @@ impl PrioritizedOrderStore pub fn get_all_orders(&self) -> Vec> { self.orders.values().cloned().collect() } + + /// Removes from self.orders and updates statistics + fn remove_from_orders(&mut self, id: &OrderId) -> Option> { + let res = self.orders.remove(id); + if let Some(sim_order) = &res { + self.orders_statistics.remove(&sim_order.order); + } + res + } } impl SimulatedOrderSink @@ -196,6 +212,8 @@ impl SimulatedOrderSink } } } + self.orders_statistics.add(&sim_order.order); + // We don't check the result to update orders_statistics since we already checked !self.orders.contains_key self.orders.insert(sim_order.id(), sim_order); } @@ -204,6 +222,6 @@ impl SimulatedOrderSink if self.main_queue.remove(&id).is_some() { self.remove_poped_order(&id); } - self.orders.remove(&id) + self.remove_from_orders(&id) } } diff --git a/crates/rbuilder/src/building/builders/block_building_helper.rs b/crates/rbuilder/src/building/builders/block_building_helper.rs index 3358815ac..a53030ab3 100644 --- a/crates/rbuilder/src/building/builders/block_building_helper.rs +++ b/crates/rbuilder/src/building/builders/block_building_helper.rs @@ -16,7 +16,7 @@ use crate::{ EstimatePayoutGasErr, ExecutionError, ExecutionResult, FinalizeError, FinalizeResult, PartialBlock, ThreadBlockBuildingContext, }, - primitives::{SimValue, SimulatedOrder}, + primitives::{order_statistics::OrderStatistics, SimValue, SimulatedOrder}, telemetry::{self, add_block_fill_time, add_order_simulation_time}, utils::{check_block_hash_reader_health, elapsed_ms, HistoricalBlockError}, }; @@ -192,6 +192,7 @@ impl BlockBuildingHelperFromProvider { local_ctx: &mut ThreadBlockBuildingContext, builder_name: String, discard_txs: bool, + available_orders_statistics: OrderStatistics, cancel_on_fatal_error: CancellationToken, ) -> Result { let last_committed_block = building_ctx.block() - 1; @@ -220,6 +221,8 @@ impl BlockBuildingHelperFromProvider { Some(payout_tx_gas) }; + let mut built_block_trace = BuiltBlockTrace::new(); + built_block_trace.available_orders_statistics = available_orders_statistics; Ok(Self { _fee_recipient_balance_start: fee_recipient_balance_start, block_state, @@ -227,7 +230,7 @@ impl BlockBuildingHelperFromProvider { payout_tx_gas, builder_name, building_ctx, - built_block_trace: BuiltBlockTrace::new(), + built_block_trace, cancel_on_fatal_error, }) } @@ -338,6 +341,7 @@ impl BlockBuildingHelper for BlockBuildingHelperFromProvider { order: &SimulatedOrder, result_filter: &dyn Fn(&SimValue) -> Result<(), ExecutionError>, ) -> Result, CriticalCommitOrderError> { + self.built_block_trace.add_considered_order(order); let start = Instant::now(); let result = self.partial_block.commit_order( order, @@ -359,6 +363,7 @@ impl BlockBuildingHelper for BlockBuildingHelperFromProvider { Err(err) => { self.built_block_trace .modify_payment_when_no_signer_error(&err); + self.built_block_trace.add_failed_order(order); (Ok(Err(err)), false) } }, diff --git a/crates/rbuilder/src/building/builders/ordering_builder.rs b/crates/rbuilder/src/building/builders/ordering_builder.rs index f56583db6..20bef0fdb 100644 --- a/crates/rbuilder/src/building/builders/ordering_builder.rs +++ b/crates/rbuilder/src/building/builders/ordering_builder.rs @@ -253,6 +253,7 @@ impl OrderingBuilderContext { &mut self.local_ctx, self.builder_name.clone(), self.config.discard_txs, + block_orders.orders_statistics(), cancel_block, )?; diff --git a/crates/rbuilder/src/building/builders/parallel_builder/block_building_result_assembler.rs b/crates/rbuilder/src/building/builders/parallel_builder/block_building_result_assembler.rs index 906c53659..9f379a368 100644 --- a/crates/rbuilder/src/building/builders/parallel_builder/block_building_result_assembler.rs +++ b/crates/rbuilder/src/building/builders/parallel_builder/block_building_result_assembler.rs @@ -20,6 +20,7 @@ use crate::{ }, BlockBuildingContext, ThreadBlockBuildingContext, }, + primitives::order_statistics::OrderStatistics, telemetry::mark_builder_considers_order, utils::elapsed_ms, }; @@ -200,6 +201,7 @@ impl BlockBuildingResultAssembler { &mut self.local_ctx, self.builder_name.clone(), self.discard_txs, + OrderStatistics::default(), self.cancellation_token.clone(), )?; block_building_helper.set_trace_orders_closed_at(orders_closed_at); @@ -272,6 +274,7 @@ impl BlockBuildingResultAssembler { &mut self.local_ctx, String::from("backtest_builder"), self.discard_txs, + OrderStatistics::default(), CancellationToken::new(), )?; diff --git a/crates/rbuilder/src/building/built_block_trace.rs b/crates/rbuilder/src/building/built_block_trace.rs index bbc9bcb2f..0eae39b3b 100644 --- a/crates/rbuilder/src/building/built_block_trace.rs +++ b/crates/rbuilder/src/building/built_block_trace.rs @@ -1,5 +1,7 @@ use super::{BundleErr, ExecutionError, ExecutionResult, OrderErr}; -use crate::primitives::{Order, OrderId, OrderReplacementKey}; +use crate::primitives::{ + order_statistics::OrderStatistics, Order, OrderId, OrderReplacementKey, SimulatedOrder, +}; use ahash::{AHasher, HashMap, HashSet}; use alloy_primitives::{Address, TxHash, U256}; use std::{collections::hash_map, hash::Hasher, time::Duration}; @@ -8,7 +10,7 @@ use time::OffsetDateTime; /// Structs for recording data about a built block, such as what bundles were included, and where txs came from. /// Trace can be used to verify bundle invariants. -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone)] pub struct BuiltBlockTrace { pub included_orders: Vec, /// How much we bid (pay to the validator) @@ -28,6 +30,12 @@ pub struct BuiltBlockTrace { pub root_hash_time: Duration, /// Value we saw in the competition when we decided to make this bid. pub seen_competition_bid: Option, + /// Orders we had available to build the block (we might have not use all of them because of timeouts) + pub available_orders_statistics: OrderStatistics, + /// Every call to BlockBuildingHelper::commit_order impacts here. + pub considered_orders_statistics: OrderStatistics, + /// Anything we call BlockBuildingHelper::commit_order on but didn't include (redundant with considered_orders_statistics-included_orders) + pub failed_orders_statistics: OrderStatistics, } impl Default for BuiltBlockTrace { @@ -62,6 +70,9 @@ impl BuiltBlockTrace { finalize_time: Duration::from_secs(0), root_hash_time: Duration::from_secs(0), seen_competition_bid: None, + considered_orders_statistics: Default::default(), + failed_orders_statistics: Default::default(), + available_orders_statistics: Default::default(), } } @@ -77,6 +88,16 @@ impl BuiltBlockTrace { self.included_orders.push(execution_result); } + /// Call before commit_order + pub fn add_considered_order(&mut self, sim_order: &SimulatedOrder) { + self.considered_orders_statistics.add(&sim_order.order); + } + + /// Call after a commit_order Err + pub fn add_failed_order(&mut self, sim_order: &SimulatedOrder) { + self.failed_orders_statistics.add(&sim_order.order); + } + /// Call after a commit_order error pub fn modify_payment_when_no_signer_error(&mut self, err: &ExecutionError) { if let ExecutionError::OrderError(OrderErr::Bundle(BundleErr::NoSigner)) = err { diff --git a/crates/rbuilder/src/live_builder/block_output/relay_submit.rs b/crates/rbuilder/src/live_builder/block_output/relay_submit.rs index 34d36341f..89d44f75b 100644 --- a/crates/rbuilder/src/live_builder/block_output/relay_submit.rs +++ b/crates/rbuilder/src/live_builder/block_output/relay_submit.rs @@ -242,6 +242,9 @@ async fn run_submit_to_relays_job( ); info!( parent: &submission_span, + available_orders_statistics = ?block.trace.available_orders_statistics, + considered_orders_statistics = ?block.trace.considered_orders_statistics, + failed_orders_statistics = ?block.trace.failed_orders_statistics, "Submitting bid", ); let relay_filter = get_relay_filter_and_update_metrics( diff --git a/crates/rbuilder/src/primitives/mod.rs b/crates/rbuilder/src/primitives/mod.rs index 9e6209add..c789ba59b 100644 --- a/crates/rbuilder/src/primitives/mod.rs +++ b/crates/rbuilder/src/primitives/mod.rs @@ -3,6 +3,7 @@ pub mod fmt; pub mod mev_boost; pub mod order_builder; +pub mod order_statistics; pub mod serialize; mod test_data_generator; diff --git a/crates/rbuilder/src/primitives/order_statistics.rs b/crates/rbuilder/src/primitives/order_statistics.rs new file mode 100644 index 000000000..73a051303 --- /dev/null +++ b/crates/rbuilder/src/primitives/order_statistics.rs @@ -0,0 +1,31 @@ +use crate::primitives::Order; + +/// Simple struct to count orders by type. +#[derive(Clone, Debug, Default)] +pub struct OrderStatistics { + tx_count: i32, + bundle_count: i32, + sbundle_count: i32, +} + +impl OrderStatistics { + pub fn new() -> Self { + Self::default() + } + + pub fn add(&mut self, order: &Order) { + match order { + Order::Bundle(_) => self.tx_count += 1, + Order::Tx(_) => self.bundle_count += 1, + Order::ShareBundle(_) => self.sbundle_count += 1, + } + } + + pub fn remove(&mut self, order: &Order) { + match order { + Order::Bundle(_) => self.tx_count -= 1, + Order::Tx(_) => self.bundle_count -= 1, + Order::ShareBundle(_) => self.sbundle_count -= 1, + } + } +}