From 47108ccbaa1a6f41c1e762d4926d7f94f63363d2 Mon Sep 17 00:00:00 2001 From: James Date: Mon, 5 Jan 2026 15:25:18 -0500 Subject: [PATCH] feat: add a transactions fn to the bundle driver trait --- Cargo.toml | 2 +- src/driver/alloy.rs | 54 ++++++++++++++++++++++++++++++-------------- src/driver/bundle.rs | 29 +++++++++++++++++++++++- 3 files changed, 66 insertions(+), 19 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4461682..b63730e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "trevm" -version = "0.31.2" +version = "0.31.3" rust-version = "1.83.0" edition = "2021" authors = ["init4"] diff --git a/src/driver/alloy.rs b/src/driver/alloy.rs index ade1d62..dbd1371 100644 --- a/src/driver/alloy.rs +++ b/src/driver/alloy.rs @@ -38,9 +38,9 @@ pub enum BundleError { /// An unsupported transaction type was encountered. UnsupportedTransactionType, /// An error occurred while decoding a transaction contained in the bundle. - TransactionDecodingError(alloy::eips::eip2718::Eip2718Error), + TransactionDecoding(alloy::eips::eip2718::Eip2718Error), /// An error occurred while recovering the sender of a transaction. - TransactionSenderRecoveryError(alloy::consensus::crypto::RecoveryError), + TransactionSenderRecovery(alloy::consensus::crypto::RecoveryError), /// An error occurred while running the EVM. EVMError { /// The error that occurred while running the EVM. @@ -59,8 +59,8 @@ impl core::fmt::Display for BundleError { Self::BundleEmpty => write!(f, "bundle has no transactions"), Self::Eip4844BlobGasExceeded => write!(f, "max blob gas limit exceeded"), Self::UnsupportedTransactionType => write!(f, "unsupported transaction type"), - Self::TransactionDecodingError(err) => write!(f, "transaction decoding error: {err}"), - Self::TransactionSenderRecoveryError(err) => { + Self::TransactionDecoding(err) => write!(f, "transaction decoding error: {err}"), + Self::TransactionSenderRecovery(err) => { write!(f, "transaction sender recovery error: {err}") } Self::EVMError { inner } => write!(f, "internal EVM error: {inner}"), @@ -70,13 +70,13 @@ impl core::fmt::Display for BundleError { impl From for BundleError { fn from(err: alloy::eips::eip2718::Eip2718Error) -> Self { - Self::TransactionDecodingError(err) + Self::TransactionDecoding(err) } } impl From for BundleError { fn from(err: alloy::primitives::SignatureError) -> Self { - Self::TransactionSenderRecoveryError(err.into()) + Self::TransactionSenderRecovery(err.into()) } } @@ -89,8 +89,8 @@ impl From> for BundleError { impl std::error::Error for BundleError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match self { - Self::TransactionDecodingError(err) => Some(err), - Self::TransactionSenderRecoveryError(err) => Some(err), + Self::TransactionDecoding(err) => Some(err), + Self::TransactionSenderRecovery(err) => Some(err), _ => None, } } @@ -98,7 +98,7 @@ impl std::error::Error for BundleError { impl From for BundleError { fn from(err: RecoveryError) -> Self { - Self::TransactionSenderRecoveryError(err) + Self::TransactionSenderRecovery(err) } } @@ -109,10 +109,10 @@ impl core::fmt::Debug for BundleError { Self::BlockNumberMismatch => write!(f, "BlockNumberMismatch"), Self::BundleEmpty => write!(f, "BundleEmpty"), Self::BundleReverted => write!(f, "BundleReverted"), - Self::TransactionDecodingError(e) => write!(f, "TransactionDecodingError({e:?})"), + Self::TransactionDecoding(e) => write!(f, "TransactionDecodingError({e:?})"), Self::UnsupportedTransactionType => write!(f, "UnsupportedTransactionType"), Self::Eip4844BlobGasExceeded => write!(f, "Eip4844BlobGasExceeded"), - Self::TransactionSenderRecoveryError(e) => { + Self::TransactionSenderRecovery(e) => { write!(f, "TransactionSenderRecoveryError({e:?})") } Self::EVMError { .. } => write!(f, "EVMError"), @@ -120,7 +120,7 @@ impl core::fmt::Debug for BundleError { } } -/// A bundle processor which can be used to drive a bundle with a [BundleDriver], accumulate the results of the bundle and dispatch +/// A bundle processor which can be used to drive a bundle with a [`BundleDriver`], accumulate the results of the bundle and dispatch /// a response. #[derive(Debug)] pub struct BundleProcessor { @@ -156,7 +156,8 @@ where } impl BundleProcessor { - /// Decode and validate the transactions in the bundle, performing EIP4844 gas checks. + /// Decode and validate the transactions in the bundle, performing EIP4844 + /// gas checks. pub fn decode_and_validate_txs( txs: &[Bytes], ) -> Result, BundleError> { @@ -190,7 +191,8 @@ impl BundleProcessor { Self::new(bundle) } - /// Process a bundle transaction and accumulate the results into a [EthCallBundleTransactionResult]. + /// Process a bundle transaction and accumulate the results into a + /// [`EthCallBundleTransactionResult`]. pub fn process_call_bundle_tx( tx: &TxEnvelope, pre_sim_coinbase_balance: U256, @@ -274,6 +276,10 @@ where { type Error = BundleError; + fn transactions(&self) -> impl IntoIterator { + self.bundle.txs.iter().map(|b| b.as_ref()) + } + fn run_bundle( &mut self, trevm: crate::EvmNeedsTx, @@ -411,6 +417,10 @@ where { type Error = BundleError; + fn transactions(&self) -> impl IntoIterator { + self.bundle.txs.iter().map(|b| b.as_ref()) + } + fn run_bundle( &mut self, trevm: crate::EvmNeedsTx, @@ -555,6 +565,10 @@ where { type Error = BundleError; + fn transactions(&self) -> impl IntoIterator { + self.txs.iter().map(|b| b.as_ref()) + } + fn run_bundle( &mut self, trevm: crate::EvmNeedsTx, @@ -637,9 +651,11 @@ where } } -/// An implementation of [BundleDriver] for [EthSendBundle]. -/// This allows us to drive a bundle of transactions and accumulate the resulting state in the EVM. -/// Allows to simply take an [EthSendBundle] and get the resulting EVM state. +/// An implementation of [`BundleDriver`] for [`EthSendBundle`]. +/// This allows us to drive a bundle of transactions and accumulate the +/// resulting state in the EVM. +/// +/// Allows to simply take an [`EthSendBundle`] and get the resulting EVM state. impl BundleDriver for EthSendBundle where Db: Database + DatabaseCommit, @@ -647,6 +663,10 @@ where { type Error = BundleError; + fn transactions(&self) -> impl IntoIterator { + self.txs.iter().map(|b| b.as_ref()) + } + fn run_bundle( &mut self, trevm: crate::EvmNeedsTx, diff --git a/src/driver/bundle.rs b/src/driver/bundle.rs index ac1c946..c54696c 100644 --- a/src/driver/bundle.rs +++ b/src/driver/bundle.rs @@ -1,4 +1,11 @@ -use crate::{helpers::Ctx, EvmBundleDriverErrored, EvmNeedsTx}; +use crate::{helpers::Ctx, BundleError, EvmBundleDriverErrored, EvmNeedsTx}; +use alloy::{ + consensus::{ + transaction::{Recovered, SignerRecoverable}, + TxEnvelope, + }, + eips::Decodable2718, +}; use revm::{ context::result::EVMError, inspector::NoOpInspector, Database, DatabaseCommit, Inspector, }; @@ -17,6 +24,26 @@ where /// An error type for this driver. type Error: core::error::Error + From>; + /// Get an iterator over the raw transaction bytes in this bundle. + fn transactions(&self) -> impl IntoIterator; + + /// Recover the transactions in this bundle. + fn recovered_transactions( + &self, + ) -> impl IntoIterator, BundleError>> + where + Self: Sized, + Db: Database, + { + self.transactions().into_iter().map(|tx_bytes| { + TxEnvelope::decode_2718_exact(tx_bytes) + .map_err(BundleError::TransactionDecoding) + .and_then(|envelope| { + envelope.try_into_recovered().map_err(BundleError::TransactionSenderRecovery) + }) + }) + } + /// Run the transactions contained in the bundle. fn run_bundle(&mut self, trevm: EvmNeedsTx) -> DriveBundleResult;