diff --git a/crates/op-rbuilder/src/builders/context.rs b/crates/op-rbuilder/src/builders/context.rs index 120aab46..b0355a94 100644 --- a/crates/op-rbuilder/src/builders/context.rs +++ b/crates/op-rbuilder/src/builders/context.rs @@ -49,7 +49,6 @@ use crate::{ metrics::OpRBuilderMetrics, primitives::reth::{ExecutionInfo, TxnExecutionResult}, traits::PayloadTxsBounds, - tx::MaybeRevertingTransaction, tx_signer::Signer, }; diff --git a/crates/op-rbuilder/src/mock_tx.rs b/crates/op-rbuilder/src/mock_tx.rs index 04c5f9f8..6c849506 100644 --- a/crates/op-rbuilder/src/mock_tx.rs +++ b/crates/op-rbuilder/src/mock_tx.rs @@ -1,21 +1,8 @@ -use crate::tx::MaybeFlashblockFilter; -use alloy_consensus::{ - EthereumTxEnvelope, TxEip4844, TxEip4844WithSidecar, TxType, error::ValueError, - transaction::Recovered, -}; -use alloy_eips::{ - Typed2718, - eip2930::AccessList, - eip4844::{BlobTransactionValidationError, env_settings::KzgSettings}, - eip7594::BlobTransactionSidecarVariant, - eip7702::SignedAuthorization, -}; -use alloy_primitives::{Address, B256, Bytes, TxHash, TxKind, U256}; -use reth::primitives::TransactionSigned; -use reth_primitives_traits::{InMemorySize, SignedTransaction}; +use crate::tx::{MaybeFlashblockFilter, WithFlashbotsMetadata}; +use alloy_consensus::TxEip4844WithSidecar; +use alloy_eips::eip7594::BlobTransactionSidecarVariant; use reth_transaction_pool::{ - EthBlobTransactionSidecar, EthPoolTransaction, PoolTransaction, TransactionOrigin, - ValidPoolTransaction, + TransactionOrigin, ValidPoolTransaction, identifier::TransactionId, test_utils::{MockTransaction, MockTransactionFactory}, }; @@ -32,7 +19,7 @@ pub struct MockFbTransactionFactory { impl MockFbTransactionFactory { /// Generates a transaction ID for the given [`MockTransaction`]. pub fn tx_id(&mut self, tx: &MockFbTransaction) -> TransactionId { - self.factory.tx_id(&tx.inner) + self.factory.tx_id(&tx) } /// Validates a [`MockTransaction`] and returns a [`MockValidFbTx`]. @@ -63,56 +50,30 @@ impl MockFbTransactionFactory { /// Creates a validated legacy [`MockTransaction`]. pub fn create_legacy(&mut self) -> MockValidFbTx { - self.validated(MockFbTransaction { - inner: MockTransaction::legacy(), - reverted_hashes: None, - max_flashblock_number: None, - min_flashblock_number: None, - }) + self.validated(MockTransaction::legacy().into()) } /// Creates a validated legacy [`MockTransaction`]. pub fn create_legacy_fb(&mut self, min: Option, max: Option) -> MockValidFbTx { - self.validated(MockFbTransaction { - inner: MockTransaction::legacy(), - reverted_hashes: None, - max_flashblock_number: max, - min_flashblock_number: min, - }) + self.validated( + MockFbTransaction::new(MockTransaction::legacy()) + .with_min_flashblock_number(min) + .with_max_flashblock_number(max), + ) } /// Creates a validated EIP-1559 [`MockTransaction`]. pub fn create_eip1559(&mut self) -> MockValidFbTx { - self.validated(MockFbTransaction { - inner: MockTransaction::eip1559(), - reverted_hashes: None, - max_flashblock_number: None, - min_flashblock_number: None, - }) + self.validated(MockTransaction::legacy().into()) } /// Creates a validated EIP-4844 [`MockTransaction`]. pub fn create_eip4844(&mut self) -> MockValidFbTx { - self.validated(MockFbTransaction { - inner: MockTransaction::eip4844(), - reverted_hashes: None, - max_flashblock_number: None, - min_flashblock_number: None, - }) + self.validated(MockTransaction::legacy().into()) } } -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct MockFbTransaction { - pub inner: MockTransaction, - /// reverted hashes for the transaction. If the transaction is a bundle, - /// this is the list of hashes of the transactions that reverted. If the - /// transaction is not a bundle, this is `None`. - pub reverted_hashes: Option>, - - pub min_flashblock_number: Option, - pub max_flashblock_number: Option, -} +pub type MockFbTransaction = WithFlashbotsMetadata; /// A validated transaction in the transaction pool, using [`MockTransaction`] as the transaction /// type. @@ -120,334 +81,5 @@ pub struct MockFbTransaction { /// This type is an alias for [`ValidPoolTransaction`]. pub type MockValidFbTx = ValidPoolTransaction; -impl PoolTransaction for MockFbTransaction { - type TryFromConsensusError = ValueError>; - - type Consensus = TransactionSigned; - - type Pooled = PooledTransactionVariant; - - fn into_consensus(self) -> Recovered { - self.inner.into() - } - - fn from_pooled(pooled: Recovered) -> Self { - Self { - inner: pooled.into(), - reverted_hashes: None, - min_flashblock_number: None, - max_flashblock_number: None, - } - } - - fn hash(&self) -> &TxHash { - self.inner.get_hash() - } - - fn sender(&self) -> Address { - *self.inner.get_sender() - } - - fn sender_ref(&self) -> &Address { - self.inner.get_sender() - } - - // Having `get_cost` from `make_setters_getters` would be cleaner but we didn't - // want to also generate the error-prone cost setters. For now cost should be - // correct at construction and auto-updated per field update via `update_cost`, - // not to be manually set. - fn cost(&self) -> &U256 { - match &self.inner { - MockTransaction::Legacy { cost, .. } - | MockTransaction::Eip2930 { cost, .. } - | MockTransaction::Eip1559 { cost, .. } - | MockTransaction::Eip4844 { cost, .. } - | MockTransaction::Eip7702 { cost, .. } => cost, - } - } - - /// Returns the encoded length of the transaction. - fn encoded_length(&self) -> usize { - self.inner.size() - } -} - -impl InMemorySize for MockFbTransaction { - fn size(&self) -> usize { - *self.inner.get_size() - } -} - -impl Typed2718 for MockFbTransaction { - fn ty(&self) -> u8 { - match self.inner { - MockTransaction::Legacy { .. } => TxType::Legacy.into(), - MockTransaction::Eip1559 { .. } => TxType::Eip1559.into(), - MockTransaction::Eip4844 { .. } => TxType::Eip4844.into(), - MockTransaction::Eip2930 { .. } => TxType::Eip2930.into(), - MockTransaction::Eip7702 { .. } => TxType::Eip7702.into(), - } - } -} - -impl alloy_consensus::Transaction for MockFbTransaction { - fn chain_id(&self) -> Option { - match &self.inner { - MockTransaction::Legacy { chain_id, .. } => *chain_id, - MockTransaction::Eip1559 { chain_id, .. } - | MockTransaction::Eip4844 { chain_id, .. } - | MockTransaction::Eip2930 { chain_id, .. } - | MockTransaction::Eip7702 { chain_id, .. } => Some(*chain_id), - } - } - - fn nonce(&self) -> u64 { - *self.inner.get_nonce() - } - - fn gas_limit(&self) -> u64 { - *self.inner.get_gas_limit() - } - - fn gas_price(&self) -> Option { - match &self.inner { - MockTransaction::Legacy { gas_price, .. } - | MockTransaction::Eip2930 { gas_price, .. } => Some(*gas_price), - _ => None, - } - } - - fn max_fee_per_gas(&self) -> u128 { - match &self.inner { - MockTransaction::Legacy { gas_price, .. } - | MockTransaction::Eip2930 { gas_price, .. } => *gas_price, - MockTransaction::Eip1559 { - max_fee_per_gas, .. - } - | MockTransaction::Eip4844 { - max_fee_per_gas, .. - } - | MockTransaction::Eip7702 { - max_fee_per_gas, .. - } => *max_fee_per_gas, - } - } - - fn max_priority_fee_per_gas(&self) -> Option { - match &self.inner { - MockTransaction::Legacy { .. } | MockTransaction::Eip2930 { .. } => None, - MockTransaction::Eip1559 { - max_priority_fee_per_gas, - .. - } - | MockTransaction::Eip4844 { - max_priority_fee_per_gas, - .. - } - | MockTransaction::Eip7702 { - max_priority_fee_per_gas, - .. - } => Some(*max_priority_fee_per_gas), - } - } - - fn max_fee_per_blob_gas(&self) -> Option { - match &self.inner { - MockTransaction::Eip4844 { - max_fee_per_blob_gas, - .. - } => Some(*max_fee_per_blob_gas), - _ => None, - } - } - - fn priority_fee_or_price(&self) -> u128 { - match &self.inner { - MockTransaction::Legacy { gas_price, .. } - | MockTransaction::Eip2930 { gas_price, .. } => *gas_price, - MockTransaction::Eip1559 { - max_priority_fee_per_gas, - .. - } - | MockTransaction::Eip4844 { - max_priority_fee_per_gas, - .. - } - | MockTransaction::Eip7702 { - max_priority_fee_per_gas, - .. - } => *max_priority_fee_per_gas, - } - } - - fn effective_gas_price(&self, base_fee: Option) -> u128 { - base_fee.map_or_else( - || self.max_fee_per_gas(), - |base_fee| { - // if the tip is greater than the max priority fee per gas, set it to the max - // priority fee per gas + base fee - let tip = self.max_fee_per_gas().saturating_sub(base_fee as u128); - if let Some(max_tip) = self.max_priority_fee_per_gas() { - if tip > max_tip { - max_tip + base_fee as u128 - } else { - // otherwise return the max fee per gas - self.max_fee_per_gas() - } - } else { - self.max_fee_per_gas() - } - }, - ) - } - - fn is_dynamic_fee(&self) -> bool { - !matches!( - self.inner, - MockTransaction::Legacy { .. } | MockTransaction::Eip2930 { .. } - ) - } - - fn kind(&self) -> TxKind { - match &self.inner { - MockTransaction::Legacy { to, .. } - | MockTransaction::Eip1559 { to, .. } - | MockTransaction::Eip2930 { to, .. } => *to, - MockTransaction::Eip4844 { to, .. } | MockTransaction::Eip7702 { to, .. } => { - TxKind::Call(*to) - } - } - } - - fn is_create(&self) -> bool { - match &self.inner { - MockTransaction::Legacy { to, .. } - | MockTransaction::Eip1559 { to, .. } - | MockTransaction::Eip2930 { to, .. } => to.is_create(), - MockTransaction::Eip4844 { .. } | MockTransaction::Eip7702 { .. } => false, - } - } - - fn value(&self) -> U256 { - match &self.inner { - MockTransaction::Legacy { value, .. } - | MockTransaction::Eip1559 { value, .. } - | MockTransaction::Eip2930 { value, .. } - | MockTransaction::Eip4844 { value, .. } - | MockTransaction::Eip7702 { value, .. } => *value, - } - } - - fn input(&self) -> &Bytes { - self.inner.get_input() - } - - fn access_list(&self) -> Option<&AccessList> { - match &self.inner { - MockTransaction::Legacy { .. } => None, - MockTransaction::Eip1559 { - access_list: accesslist, - .. - } - | MockTransaction::Eip4844 { - access_list: accesslist, - .. - } - | MockTransaction::Eip2930 { - access_list: accesslist, - .. - } - | MockTransaction::Eip7702 { - access_list: accesslist, - .. - } => Some(accesslist), - } - } - - fn blob_versioned_hashes(&self) -> Option<&[B256]> { - match &self.inner { - MockTransaction::Eip4844 { - blob_versioned_hashes, - .. - } => Some(blob_versioned_hashes), - _ => None, - } - } - - fn authorization_list(&self) -> Option<&[SignedAuthorization]> { - match &self.inner { - MockTransaction::Eip7702 { - authorization_list, .. - } => Some(authorization_list), - _ => None, - } - } -} - -impl EthPoolTransaction for MockFbTransaction { - fn take_blob(&mut self) -> EthBlobTransactionSidecar { - match &self.inner { - MockTransaction::Eip4844 { sidecar, .. } => { - EthBlobTransactionSidecar::Present(sidecar.clone()) - } - _ => EthBlobTransactionSidecar::None, - } - } - - fn try_into_pooled_eip4844( - self, - sidecar: Arc, - ) -> Option> { - let (tx, signer) = self.into_consensus().into_parts(); - tx.try_into_pooled_eip4844(Arc::unwrap_or_clone(sidecar)) - .map(|tx| tx.with_signer(signer)) - .ok() - } - - fn try_from_eip4844( - tx: Recovered, - sidecar: BlobTransactionSidecarVariant, - ) -> Option { - let (tx, signer) = tx.into_parts(); - tx.try_into_pooled_eip4844(sidecar) - .map(|tx| tx.with_signer(signer)) - .ok() - .map(Self::from_pooled) - } - - fn validate_blob( - &self, - _blob: &BlobTransactionSidecarVariant, - _settings: &KzgSettings, - ) -> Result<(), alloy_eips::eip4844::BlobTransactionValidationError> { - match &self.inner { - MockTransaction::Eip4844 { .. } => Ok(()), - _ => Err(BlobTransactionValidationError::NotBlobTransaction( - self.inner.tx_type(), - )), - } - } -} - pub type PooledTransactionVariant = alloy_consensus::EthereumTxEnvelope>; - -impl MaybeFlashblockFilter for MockFbTransaction { - fn with_min_flashblock_number(mut self, min_flashblock_number: Option) -> Self { - self.min_flashblock_number = min_flashblock_number; - self - } - - fn with_max_flashblock_number(mut self, max_flashblock_number: Option) -> Self { - self.max_flashblock_number = max_flashblock_number; - self - } - - fn min_flashblock_number(&self) -> Option { - self.min_flashblock_number - } - - fn max_flashblock_number(&self) -> Option { - self.max_flashblock_number - } -} diff --git a/crates/op-rbuilder/src/revert_protection.rs b/crates/op-rbuilder/src/revert_protection.rs index 93a95ad0..f722deed 100644 --- a/crates/op-rbuilder/src/revert_protection.rs +++ b/crates/op-rbuilder/src/revert_protection.rs @@ -3,7 +3,7 @@ use std::{sync::Arc, time::Instant}; use crate::{ metrics::OpRBuilderMetrics, primitives::bundle::{Bundle, BundleResult}, - tx::{FBPooledTransaction, MaybeFlashblockFilter, MaybeRevertingTransaction}, + tx::{FBPooledTransaction, MaybeFlashblockFilter}, }; use alloy_json_rpc::RpcObject; use alloy_primitives::B256; diff --git a/crates/op-rbuilder/src/traits.rs b/crates/op-rbuilder/src/traits.rs index ba51971a..2c769f2d 100644 --- a/crates/op-rbuilder/src/traits.rs +++ b/crates/op-rbuilder/src/traits.rs @@ -2,12 +2,12 @@ use alloy_consensus::Header; use reth_node_api::{FullNodeComponents, FullNodeTypes, NodeTypes}; use reth_optimism_chainspec::OpChainSpec; use reth_optimism_node::OpEngineTypes; -use reth_optimism_primitives::{OpPrimitives, OpTransactionSigned}; +use reth_optimism_primitives::OpPrimitives; use reth_payload_util::PayloadTransactions; use reth_provider::{BlockReaderIdExt, ChainSpecProvider, StateProviderFactory}; use reth_transaction_pool::TransactionPool; -use crate::tx::FBPoolTransaction; +use crate::tx::FBPooledTransaction; pub trait NodeBounds: FullNodeTypes< @@ -45,19 +45,10 @@ impl NodeComponents for T where { } -pub trait PoolBounds: - TransactionPool> + Unpin + 'static -where - ::Transaction: FBPoolTransaction, -{ -} +pub trait PoolBounds: TransactionPool + Unpin + 'static {} -impl PoolBounds for T -where - T: TransactionPool> - + Unpin - + 'static, - ::Transaction: FBPoolTransaction, +impl PoolBounds for T where + T: TransactionPool + Unpin + 'static { } @@ -79,12 +70,6 @@ impl ClientBounds for T where { } -pub trait PayloadTxsBounds: - PayloadTransactions> -{ -} +pub trait PayloadTxsBounds: PayloadTransactions {} -impl PayloadTxsBounds for T where - T: PayloadTransactions> -{ -} +impl PayloadTxsBounds for T where T: PayloadTransactions {} diff --git a/crates/op-rbuilder/src/tx.rs b/crates/op-rbuilder/src/tx.rs index 8447698c..9cfdf7da 100644 --- a/crates/op-rbuilder/src/tx.rs +++ b/crates/op-rbuilder/src/tx.rs @@ -1,10 +1,9 @@ -use std::{borrow::Cow, sync::Arc}; +use std::{borrow::Cow, ops::Deref, sync::Arc}; -use alloy_consensus::{BlobTransactionValidationError, conditional::BlockConditionalAttributes}; +use alloy_consensus::BlobTransactionValidationError; use alloy_eips::{Typed2718, eip7594::BlobTransactionSidecarVariant, eip7702::SignedAuthorization}; use alloy_primitives::{Address, B256, Bytes, TxHash, TxKind, U256}; use alloy_rpc_types_eth::{AccessList, erc4337::TransactionConditional}; -use reth_optimism_primitives::OpTransactionSigned; use reth_optimism_txpool::{ OpPooledTransaction, OpPooledTx, conditional::MaybeConditionalTransaction, estimated_da_size::DataAvailabilitySized, interop::MaybeInteropTransaction, @@ -13,56 +12,47 @@ use reth_primitives::{Recovered, kzg::KzgSettings}; use reth_primitives_traits::InMemorySize; use reth_transaction_pool::{EthBlobTransactionSidecar, EthPoolTransaction, PoolTransaction}; -pub trait FBPoolTransaction: - MaybeRevertingTransaction + OpPooledTx + MaybeFlashblockFilter -{ -} +pub type FBPooledTransaction = WithFlashbotsMetadata; +/// Generic wrapper that adds Flashbots-specific metadata to any transaction type #[derive(Clone, Debug)] -pub struct FBPooledTransaction { - pub inner: OpPooledTransaction, +pub struct WithFlashbotsMetadata { + inner: T, - /// reverted hashes for the transaction. If the transaction is a bundle, + /// Reverted hashes for bundle transactions. If the transaction is a bundle, /// this is the list of hashes of the transactions that reverted. If the /// transaction is not a bundle, this is `None`. - pub reverted_hashes: Option>, - - pub min_flashblock_number: Option, - pub max_flashblock_number: Option, -} + reverted_hashes: Option>, -impl FBPoolTransaction for FBPooledTransaction {} + /// Minimum flashblock number constraint + min_flashblock_number: Option, -impl OpPooledTx for FBPooledTransaction { - fn encoded_2718(&self) -> Cow<'_, Bytes> { - Cow::Borrowed(self.inner.encoded_2718()) - } + /// Maximum flashblock number constraint + max_flashblock_number: Option, } -pub trait MaybeRevertingTransaction { - fn with_reverted_hashes(self, reverted_hashes: Vec) -> Self; - fn reverted_hashes(&self) -> Option>; -} +impl WithFlashbotsMetadata { + /// Create a new wrapper with no metadata + pub fn new(inner: T) -> Self { + Self { + inner, + reverted_hashes: None, + min_flashblock_number: None, + max_flashblock_number: None, + } + } -impl MaybeRevertingTransaction for FBPooledTransaction { - fn with_reverted_hashes(mut self, reverted_hashes: Vec) -> Self { + pub fn with_reverted_hashes(mut self, reverted_hashes: Vec) -> Self { self.reverted_hashes = Some(reverted_hashes); self } - fn reverted_hashes(&self) -> Option> { - self.reverted_hashes.clone() + pub fn reverted_hashes(&self) -> &Option> { + &self.reverted_hashes } } -pub trait MaybeFlashblockFilter { - fn with_min_flashblock_number(self, min_flashblock_number: Option) -> Self; - fn with_max_flashblock_number(self, max_flashblock_number: Option) -> Self; - fn min_flashblock_number(&self) -> Option; - fn max_flashblock_number(&self) -> Option; -} - -impl MaybeFlashblockFilter for FBPooledTransaction { +impl MaybeFlashblockFilter for WithFlashbotsMetadata { fn with_min_flashblock_number(mut self, min_flashblock_number: Option) -> Self { self.min_flashblock_number = min_flashblock_number; self @@ -82,17 +72,21 @@ impl MaybeFlashblockFilter for FBPooledTransaction { } } -impl InMemorySize for FBPooledTransaction { +impl InMemorySize for WithFlashbotsMetadata { fn size(&self) -> usize { - self.inner.size() + core::mem::size_of::() + self.inner.size() + + core::mem::size_of::>>() + + core::mem::size_of::>() * 2 } } -impl PoolTransaction for FBPooledTransaction { - type TryFromConsensusError = - >::Error; - type Consensus = OpTransactionSigned; - type Pooled = op_alloy_consensus::OpPooledTransaction; +impl PoolTransaction for WithFlashbotsMetadata +where + T: PoolTransaction, +{ + type TryFromConsensusError = T::TryFromConsensusError; + type Consensus = T::Consensus; + type Pooled = T::Pooled; fn clone_into_consensus(&self) -> Recovered { self.inner.clone_into_consensus() @@ -103,13 +97,7 @@ impl PoolTransaction for FBPooledTransaction { } fn from_pooled(tx: Recovered) -> Self { - let inner = OpPooledTransaction::from_pooled(tx); - Self { - inner, - reverted_hashes: None, - min_flashblock_number: None, - max_flashblock_number: None, - } + Self::new(T::from_pooled(tx)) } fn hash(&self) -> &TxHash { @@ -133,13 +121,13 @@ impl PoolTransaction for FBPooledTransaction { } } -impl Typed2718 for FBPooledTransaction { +impl Typed2718 for WithFlashbotsMetadata { fn ty(&self) -> u8 { self.inner.ty() } } -impl alloy_consensus::Transaction for FBPooledTransaction { +impl alloy_consensus::Transaction for WithFlashbotsMetadata { fn chain_id(&self) -> Option { self.inner.chain_id() } @@ -209,9 +197,12 @@ impl alloy_consensus::Transaction for FBPooledTransaction { } } -impl EthPoolTransaction for FBPooledTransaction { +impl EthPoolTransaction for WithFlashbotsMetadata +where + T: PoolTransaction, +{ fn take_blob(&mut self) -> EthBlobTransactionSidecar { - EthBlobTransactionSidecar::None + self.inner.take_blob() } fn try_into_pooled_eip4844( @@ -239,7 +230,7 @@ impl EthPoolTransaction for FBPooledTransaction { } } -impl MaybeInteropTransaction for FBPooledTransaction { +impl MaybeInteropTransaction for WithFlashbotsMetadata { fn interop_deadline(&self) -> Option { self.inner.interop_deadline() } @@ -247,33 +238,15 @@ impl MaybeInteropTransaction for FBPooledTransaction { fn set_interop_deadline(&self, deadline: u64) { self.inner.set_interop_deadline(deadline); } - - fn with_interop_deadline(self, interop: u64) -> Self - where - Self: Sized, - { - self.inner.with_interop_deadline(interop).into() - } } -impl DataAvailabilitySized for FBPooledTransaction { +impl DataAvailabilitySized for WithFlashbotsMetadata { fn estimated_da_size(&self) -> u64 { self.inner.estimated_da_size() } } -impl From for FBPooledTransaction { - fn from(tx: OpPooledTransaction) -> Self { - Self { - inner: tx, - reverted_hashes: None, - min_flashblock_number: None, - max_flashblock_number: None, - } - } -} - -impl MaybeConditionalTransaction for FBPooledTransaction { +impl MaybeConditionalTransaction for WithFlashbotsMetadata { fn set_conditional(&mut self, conditional: TransactionConditional) { self.inner.set_conditional(conditional); } @@ -281,20 +254,31 @@ impl MaybeConditionalTransaction for FBPooledTransaction { fn conditional(&self) -> Option<&TransactionConditional> { self.inner.conditional() } +} - fn has_exceeded_block_attributes(&self, block_attr: &BlockConditionalAttributes) -> bool { - self.inner.has_exceeded_block_attributes(block_attr) +impl OpPooledTx for WithFlashbotsMetadata { + fn encoded_2718(&self) -> Cow<'_, Bytes> { + self.inner.encoded_2718() } +} - fn with_conditional(self, conditional: TransactionConditional) -> Self - where - Self: Sized, - { - FBPooledTransaction { - inner: self.inner.with_conditional(conditional), - reverted_hashes: self.reverted_hashes, - min_flashblock_number: self.min_flashblock_number, - max_flashblock_number: self.max_flashblock_number, - } +impl From for WithFlashbotsMetadata { + fn from(inner: T) -> Self { + Self::new(inner) } } + +impl Deref for WithFlashbotsMetadata { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.inner + } +} + +pub trait MaybeFlashblockFilter { + fn with_min_flashblock_number(self, min_flashblock_number: Option) -> Self; + fn with_max_flashblock_number(self, max_flashblock_number: Option) -> Self; + fn min_flashblock_number(&self) -> Option; + fn max_flashblock_number(&self) -> Option; +}