From 3df32d004070a2f357f568063f285afd7f8609d0 Mon Sep 17 00:00:00 2001 From: fahimahmedx Date: Wed, 12 Nov 2025 15:09:40 -0500 Subject: [PATCH 1/3] Allow to allow score() to access &self --- src/steps/ordering/mod.rs | 35 ++++++++++++++++++++++++++++------- src/steps/ordering/profit.rs | 2 +- src/steps/ordering/tip.rs | 2 +- 3 files changed, 30 insertions(+), 9 deletions(-) diff --git a/src/steps/ordering/mod.rs b/src/steps/ordering/mod.rs index 7603a9a..4694bbb 100644 --- a/src/steps/ordering/mod.rs +++ b/src/steps/ordering/mod.rs @@ -25,7 +25,7 @@ pub trait OrderScore: type Score: Clone + Ord + Eq + core::hash::Hash; type Error: core::error::Error + Send + Sync + 'static; - fn score(_: &Checkpoint

) -> Result; + fn score(&self, checkpoint: &Checkpoint

) -> Result; } /// A generic implementation of a step that will order checkpoints based on a @@ -36,8 +36,29 @@ pub trait OrderScore: /// Sorting happens only for the mutable part of the payload, i.e. after /// the last barrier checkpoint. Anything prior to the last barrier /// checkpoint is considered immutable and will not be reordered. -#[derive(Debug, Clone, Default)] -pub struct OrderBy>(PhantomData<(P, S)>); +#[derive(Debug, Clone)] +pub struct OrderBy> { + scorer: S, + _phantom: PhantomData

, +} + +impl> Default for OrderBy { + fn default() -> Self { + Self { + scorer: S::default(), + _phantom: PhantomData, + } + } +} + +impl> OrderBy { + pub fn new(scorer: S) -> Self { + Self { + scorer, + _phantom: PhantomData, + } + } +} impl> Step

for OrderBy { async fn step( self: Arc, @@ -50,7 +71,7 @@ impl> Step

for OrderBy { let history = payload.history_staging(); // Find the correct order of orders in the payload. - let ordered = match SortedOrders::::try_from(&history) { + let ordered = match SortedOrders::::try_from((&history, &self.scorer)) { Ok(ordered) => ordered.into_iter(), // when the step started running, the payload had no nonce conflicts and // all orders were able to construct valid checkpoints. After reordering, @@ -115,12 +136,12 @@ struct SortedOrders<'a, P: Platform, S: OrderScore

> { _scoring: PhantomData, } -impl<'a, P: Platform, S: OrderScore

> TryFrom<&'a Span

> +impl<'a, P: Platform, S: OrderScore

> TryFrom<(&'a Span

, &'a S)> for SortedOrders<'a, P, S> { type Error = S::Error; - fn try_from(span: &'a Span

) -> Result { + fn try_from((span, scorer): (&'a Span

, &'a S)) -> Result { let executables = span.iter().filter(|checkpoint| !checkpoint.is_barrier()); let all_orders: HashMap> = executables .map(|checkpoint| (checkpoint.hash().unwrap(), checkpoint)) @@ -141,7 +162,7 @@ impl<'a, P: Platform, S: OrderScore

> TryFrom<&'a Span

> let mut by_score = BTreeMap::<_, BTreeSet<_>>::default(); for (hash, checkpoint) in &all_orders { - let score = S::score(checkpoint)?; + let score = scorer.score(checkpoint)?; by_score.entry(score).or_default().insert(*hash); } diff --git a/src/steps/ordering/profit.rs b/src/steps/ordering/profit.rs index 1ecef75..c552da4 100644 --- a/src/steps/ordering/profit.rs +++ b/src/steps/ordering/profit.rs @@ -13,7 +13,7 @@ impl OrderScore

for CoinbaseProfitScore

{ type Error = ProviderError; type Score = U256; - fn score(checkpoint: &Checkpoint

) -> Result { + fn score(&self, checkpoint: &Checkpoint

) -> Result { let fee_recipient = checkpoint.block().coinbase(); let current_balance = checkpoint.balance_of(fee_recipient)?; diff --git a/src/steps/ordering/tip.rs b/src/steps/ordering/tip.rs index 9d89110..98de72f 100644 --- a/src/steps/ordering/tip.rs +++ b/src/steps/ordering/tip.rs @@ -11,7 +11,7 @@ impl OrderScore

for PriorityFeeScore

{ type Error = Infallible; type Score = u128; - fn score(checkpoint: &Checkpoint

) -> Result { + fn score(&self, checkpoint: &Checkpoint

) -> Result { Ok(checkpoint.effective_tip_per_gas()) } } From 331af785c2daae4d815145eba03bd66ed2864b23 Mon Sep 17 00:00:00 2001 From: fahimahmedx Date: Wed, 12 Nov 2025 15:28:19 -0500 Subject: [PATCH 2/3] add OrderByDestinationAndPriorityFee --- src/steps/ordering/destination.rs | 52 +++++++++++++++++++++++++++++++ src/steps/ordering/mod.rs | 7 ++++- 2 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 src/steps/ordering/destination.rs diff --git a/src/steps/ordering/destination.rs b/src/steps/ordering/destination.rs new file mode 100644 index 0000000..1e32403 --- /dev/null +++ b/src/steps/ordering/destination.rs @@ -0,0 +1,52 @@ +use { + super::{OrderBy, OrderScore}, + crate::{ + alloy::{consensus::Transaction, primitives::Address}, + prelude::*, + }, + core::{convert::Infallible, marker::PhantomData}, +}; + +#[derive(Debug, Clone)] +pub struct DestinationAndPriorityFeeScore { + destination_address: Address, + _phantom: PhantomData

, +} + +impl Default for DestinationAndPriorityFeeScore

{ + fn default() -> Self { + Self { + destination_address: Address::ZERO, + _phantom: PhantomData, + } + } +} + +impl DestinationAndPriorityFeeScore

{ + pub fn new(destination_address: Address) -> Self { + Self { + destination_address, + _phantom: PhantomData, + } + } +} + +impl OrderScore

for DestinationAndPriorityFeeScore

{ + type Error = Infallible; + type Score = (u8, u128); + + // Since this implementation of score() returns a tuple, this creates a + // two-tier priority system which we want: Transactions going to the + // destination address are always prioritized over transactions that aren't. + // Within each tier, they're ordered by effective tip. + fn score(&self, checkpoint: &Checkpoint

) -> Result { + let all_destination = checkpoint + .transactions() + .iter() + .all(|tx| tx.to() == Some(self.destination_address)); + let tip_sum = CheckpointExt::effective_tip_per_gas(checkpoint); + Ok((all_destination as u8, tip_sum)) + } +} + +pub type OrderByDestinationAndPriorityFee

= OrderBy>; diff --git a/src/steps/ordering/mod.rs b/src/steps/ordering/mod.rs index 4694bbb..a9bc553 100644 --- a/src/steps/ordering/mod.rs +++ b/src/steps/ordering/mod.rs @@ -11,10 +11,15 @@ use { }, }; +mod destination; mod profit; mod tip; -pub use {profit::OrderByCoinbaseProfit, tip::OrderByPriorityFee}; +pub use { + destination::{DestinationAndPriorityFeeScore, OrderByDestinationAndPriorityFee}, + profit::OrderByCoinbaseProfit, + tip::OrderByPriorityFee, +}; /// A trait that implements logic for assigning a score to an order. /// Different implementations of this trait provide different ordering From 9ad1b21e0d8c0274549dae51286f85af3ec252bf Mon Sep 17 00:00:00 2001 From: fahimahmedx Date: Wed, 12 Nov 2025 16:16:49 -0500 Subject: [PATCH 3/3] fix lints --- src/steps/ordering/destination.rs | 10 +++++++--- src/steps/ordering/mod.rs | 17 +++++++++++++---- src/steps/ordering/profit.rs | 5 ++++- src/steps/ordering/tip.rs | 5 ++++- 4 files changed, 28 insertions(+), 9 deletions(-) diff --git a/src/steps/ordering/destination.rs b/src/steps/ordering/destination.rs index 1e32403..ce14753 100644 --- a/src/steps/ordering/destination.rs +++ b/src/steps/ordering/destination.rs @@ -39,14 +39,18 @@ impl OrderScore

for DestinationAndPriorityFeeScore

{ // two-tier priority system which we want: Transactions going to the // destination address are always prioritized over transactions that aren't. // Within each tier, they're ordered by effective tip. - fn score(&self, checkpoint: &Checkpoint

) -> Result { + fn score( + &self, + checkpoint: &Checkpoint

, + ) -> Result { let all_destination = checkpoint .transactions() .iter() .all(|tx| tx.to() == Some(self.destination_address)); let tip_sum = CheckpointExt::effective_tip_per_gas(checkpoint); - Ok((all_destination as u8, tip_sum)) + Ok((u8::from(all_destination), tip_sum)) } } -pub type OrderByDestinationAndPriorityFee

= OrderBy>; +pub type OrderByDestinationAndPriorityFee

= + OrderBy>; diff --git a/src/steps/ordering/mod.rs b/src/steps/ordering/mod.rs index a9bc553..27410cc 100644 --- a/src/steps/ordering/mod.rs +++ b/src/steps/ordering/mod.rs @@ -16,7 +16,10 @@ mod profit; mod tip; pub use { - destination::{DestinationAndPriorityFeeScore, OrderByDestinationAndPriorityFee}, + destination::{ + DestinationAndPriorityFeeScore, + OrderByDestinationAndPriorityFee, + }, profit::OrderByCoinbaseProfit, tip::OrderByPriorityFee, }; @@ -30,7 +33,10 @@ pub trait OrderScore: type Score: Clone + Ord + Eq + core::hash::Hash; type Error: core::error::Error + Send + Sync + 'static; - fn score(&self, checkpoint: &Checkpoint

) -> Result; + fn score( + &self, + checkpoint: &Checkpoint

, + ) -> Result; } /// A generic implementation of a step that will order checkpoints based on a @@ -76,7 +82,8 @@ impl> Step

for OrderBy { let history = payload.history_staging(); // Find the correct order of orders in the payload. - let ordered = match SortedOrders::::try_from((&history, &self.scorer)) { + let ordered = match SortedOrders::::try_from((&history, &self.scorer)) + { Ok(ordered) => ordered.into_iter(), // when the step started running, the payload had no nonce conflicts and // all orders were able to construct valid checkpoints. After reordering, @@ -146,7 +153,9 @@ impl<'a, P: Platform, S: OrderScore

> TryFrom<(&'a Span

, &'a S)> { type Error = S::Error; - fn try_from((span, scorer): (&'a Span

, &'a S)) -> Result { + fn try_from( + (span, scorer): (&'a Span

, &'a S), + ) -> Result { let executables = span.iter().filter(|checkpoint| !checkpoint.is_barrier()); let all_orders: HashMap> = executables .map(|checkpoint| (checkpoint.hash().unwrap(), checkpoint)) diff --git a/src/steps/ordering/profit.rs b/src/steps/ordering/profit.rs index c552da4..a0bbf0f 100644 --- a/src/steps/ordering/profit.rs +++ b/src/steps/ordering/profit.rs @@ -13,7 +13,10 @@ impl OrderScore

for CoinbaseProfitScore

{ type Error = ProviderError; type Score = U256; - fn score(&self, checkpoint: &Checkpoint

) -> Result { + fn score( + &self, + checkpoint: &Checkpoint

, + ) -> Result { let fee_recipient = checkpoint.block().coinbase(); let current_balance = checkpoint.balance_of(fee_recipient)?; diff --git a/src/steps/ordering/tip.rs b/src/steps/ordering/tip.rs index 98de72f..f32507e 100644 --- a/src/steps/ordering/tip.rs +++ b/src/steps/ordering/tip.rs @@ -11,7 +11,10 @@ impl OrderScore

for PriorityFeeScore

{ type Error = Infallible; type Score = u128; - fn score(&self, checkpoint: &Checkpoint

) -> Result { + fn score( + &self, + checkpoint: &Checkpoint

, + ) -> Result { Ok(checkpoint.effective_tip_per_gas()) } }