11use crate :: send:: SignetEthBundle ;
22use alloy:: primitives:: U256 ;
3- use signet_evm:: { DriveBundleResult , EvmNeedsTx , SignetLayered } ;
4- use signet_types:: SignedPermitError ;
3+ use signet_evm:: { DriveBundleResult , EvmNeedsTx , EvmTransacted , SignetInspector , SignetLayered } ;
4+ use signet_types:: { AggregateFills , MarketError , SignedPermitError } ;
5+ use tracing:: debug;
56use trevm:: {
67 helpers:: Ctx ,
78 inspectors:: { Layered , TimeLimit } ,
89 revm:: {
9- context:: result:: { EVMError , ExecutionResult , HaltReason } ,
10- inspector:: InspectorEvmTr ,
11- Database , DatabaseCommit , Inspector ,
10+ context:: result:: EVMError , inspector:: InspectorEvmTr , Database , DatabaseCommit , Inspector ,
1211 } ,
1312 trevm_bail, trevm_ensure, trevm_try, BundleDriver , BundleError ,
1413} ;
@@ -58,18 +57,42 @@ impl<Db: Database> From<EVMError<Db::Error>> for SignetEthBundleError<Db> {
5857/// Driver for applying a Signet Ethereum bundle to an EVM.
5958#[ derive( Debug , Clone ) ]
6059pub struct SignetEthBundleDriver < ' a > {
60+ /// The bundle to apply.
6161 bundle : & ' a SignetEthBundle ,
62+
63+ /// Execution deadline for this bundle. This limits the total WALLCLOCK
64+ /// time spent simulating the bundle.
6265 deadline : std:: time:: Instant ,
6366
67+ /// Aggregate fills derived from the bundle's host fills.
68+ agg_fills : AggregateFills ,
69+
70+ /// Total gas used by this bundle during execution, an output of the driver.
6471 total_gas_used : u64 ,
72+ /// Beneficiary balance increase during execution, an output of the driver.
6573 beneficiary_balance_increase : U256 ,
6674}
6775
6876impl < ' a > SignetEthBundleDriver < ' a > {
6977 /// Creates a new [`SignetEthBundleDriver`] with the given bundle and
7078 /// response.
71- pub const fn new ( bundle : & ' a SignetEthBundle , deadline : std:: time:: Instant ) -> Self {
72- Self { bundle, deadline, total_gas_used : 0 , beneficiary_balance_increase : U256 :: ZERO }
79+ pub fn new (
80+ bundle : & ' a SignetEthBundle ,
81+ host_chain_id : u64 ,
82+ deadline : std:: time:: Instant ,
83+ ) -> Self {
84+ let mut agg_fills = AggregateFills :: default ( ) ;
85+ if let Some ( host_fills) = & bundle. host_fills {
86+ agg_fills. add_signed_fill ( host_chain_id, host_fills) ;
87+ }
88+
89+ Self {
90+ bundle,
91+ deadline,
92+ agg_fills,
93+ total_gas_used : 0 ,
94+ beneficiary_balance_increase : U256 :: ZERO ,
95+ }
7396 }
7497
7598 /// Get a reference to the bundle.
@@ -91,6 +114,39 @@ impl<'a> SignetEthBundleDriver<'a> {
91114 pub const fn beneficiary_balance_increase ( & self ) -> U256 {
92115 self . beneficiary_balance_increase
93116 }
117+
118+ /// Get the aggregate fills for this driver.
119+ ///
120+ /// This may be used to check that the bundle does not overfill, by
121+ /// inspecting the agg fills after execution.
122+ pub const fn agg_fills ( & self ) -> & AggregateFills {
123+ & self . agg_fills
124+ }
125+
126+ /// Check the [`AggregateFills`], discard if invalid, otherwise accumulate
127+ /// payable gas and call [`Self::accept_tx`].
128+ ///
129+ /// This path is used by
130+ /// - [`TransactionSigned`] objects
131+ /// - [`Transactor::Transact`] events
132+ pub ( crate ) fn check_fills < Db , Insp > (
133+ & mut self ,
134+ trevm : & mut EvmTransacted < Db , Insp > ,
135+ ) -> Result < ( ) , MarketError >
136+ where
137+ Db : Database + DatabaseCommit ,
138+ Insp : Inspector < Ctx < Db > > ,
139+ {
140+ // Taking these clears the context for reuse.
141+ let ( agg_orders, agg_fills) =
142+ trevm. inner_mut_unchecked ( ) . inspector . as_mut_detector ( ) . take_aggregates ( ) ;
143+
144+ // We check the AggregateFills here, and if it fails, we discard the
145+ // transaction outcome and push a failure receipt.
146+ self . agg_fills . checked_remove_ru_tx_events ( & agg_orders, & agg_fills) . inspect_err ( |err| {
147+ debug ! ( %err, "Discarding transaction outcome due to market error" ) ;
148+ } )
149+ }
94150}
95151
96152impl < Db , Insp > BundleDriver < Db , SignetLayered < Layered < TimeLimit , Insp > > >
@@ -150,33 +206,41 @@ where
150206
151207 let tx_hash = tx. hash ( ) ;
152208
153- trevm = match trevm. run_tx ( & tx) {
154- Ok ( trevm) => {
155- // Check if the transaction was reverted or halted
156- let result = trevm. result ( ) ;
157-
158- match result {
159- ExecutionResult :: Success { gas_used, .. } => {
160- self . total_gas_used = self . total_gas_used . saturating_add ( * gas_used) ;
161- }
162- // `CallTooDeep` represents the timelimit being reached
163- ExecutionResult :: Halt { reason, .. }
164- if * reason == HaltReason :: CallTooDeep =>
165- {
166- return Err ( trevm. errored ( BundleError :: BundleReverted . into ( ) ) ) ;
167- }
168- ExecutionResult :: Halt { gas_used, .. }
169- | ExecutionResult :: Revert { gas_used, .. } => {
170- if !self . bundle . reverting_tx_hashes ( ) . contains ( tx_hash) {
171- return Err ( trevm. errored ( BundleError :: BundleReverted . into ( ) ) ) ;
172- }
173- self . total_gas_used = self . total_gas_used . saturating_add ( * gas_used) ;
174- }
175- }
176- trevm. accept_state ( )
209+ // Temporary rebinding of trevm within each loop iteration.
210+ // The type of t is `EvmTransacted`, while the type of trevm is
211+ // `EvmNeedsTx`.
212+ let mut t = trevm. run_tx ( & tx) . map_err ( |err| err. err_into ( ) ) ?;
213+
214+ // Check the result of the transaction.
215+ let result = t. result ( ) ;
216+
217+ let gas_used = result. gas_used ( ) ;
218+
219+ // EVM Execution succeeded.
220+ // We now check if the orders are valid with the bundle's fills. If
221+ // not, and the tx is not marked as revertible by the bundle, we
222+ // error our simulation.
223+ if result. is_success ( ) {
224+ if self . check_fills ( & mut t) . is_err ( )
225+ && !self . bundle . reverting_tx_hashes ( ) . contains ( tx_hash)
226+ {
227+ return Err ( t. errored ( BundleError :: BundleReverted . into ( ) ) ) ;
177228 }
178- Err ( err) => return Err ( err. err_into ( ) ) ,
179- } ;
229+
230+ self . total_gas_used = self . total_gas_used . saturating_add ( gas_used) ;
231+ } else {
232+ // If not success, we are in a revert or halt. If the tx is
233+ // not marked as revertible by the bundle, we error our
234+ // simulation.
235+ if !self . bundle . reverting_tx_hashes ( ) . contains ( tx_hash) {
236+ return Err ( t. errored ( BundleError :: BundleReverted . into ( ) ) ) ;
237+ }
238+ self . total_gas_used = self . total_gas_used . saturating_add ( gas_used) ;
239+ }
240+
241+ // If we did not shortcut return, we accept the state changes
242+ // from this transaction.
243+ trevm = t. accept_state ( )
180244 }
181245
182246 let beneficiary_balance =
0 commit comments