1use crate::{RecoveredBundle, SignetEthBundleError};
2use alloy::{hex, primitives::U256};
3use signet_evm::{DriveBundleResult, EvmErrored, EvmNeedsTx, SignetInspector, SignetLayered};
4use signet_types::{AggregateFills, AggregateOrders};
5use std::borrow::Cow;
6use tracing::{debug, debug_span, enabled, error};
7use trevm::{
8 helpers::Ctx,
9 inspectors::{Layered, TimeLimit},
10 revm::{
11 context::result::EVMError, inspector::InspectorEvmTr, Database, DatabaseCommit, Inspector,
12 },
13 trevm_bail, trevm_ensure, trevm_try, BundleDriver, BundleError,
14};
15
16pub type SignetEthBundleInsp<I> = Layered<TimeLimit, I>;
19
20#[derive(Debug)]
22pub struct DriverOutput<Db, Insp>
23where
24 Db: Database,
25 Insp: Inspector<Ctx<Db>>,
26{
27 pub host_evm: Option<signet_evm::EvmNeedsTx<Db, Insp>>,
29
30 pub total_gas_used: u64,
32
33 pub total_host_gas_used: u64,
35
36 pub beneficiary_balance_increase: U256,
38
39 pub bundle_fills: AggregateFills,
41
42 pub bundle_orders: AggregateOrders,
44}
45
46impl<Db, Insp> DriverOutput<Db, Insp>
47where
48 Db: Database,
49 Insp: Inspector<Ctx<Db>>,
50{
51 pub const fn use_gas(&mut self, gas: u64) {
53 self.total_gas_used = self.total_gas_used.saturating_add(gas);
54 }
55
56 pub const fn use_host_gas(&mut self, gas: u64) {
58 self.total_host_gas_used = self.total_host_gas_used.saturating_add(gas);
59 }
60
61 pub fn absorb(&mut self, fills: &AggregateFills, orders: &AggregateOrders) {
63 self.bundle_fills.absorb(fills);
64 self.bundle_orders.absorb(orders);
65 }
66
67 pub const fn record_beneficiary_increase(&mut self, increase: U256) {
69 self.beneficiary_balance_increase =
70 self.beneficiary_balance_increase.saturating_add(increase);
71 }
72}
73
74#[derive(Debug)]
76pub struct SignetEthBundleDriver<'a, 'b, Db, Insp>
77where
78 Db: Database,
79 Insp: Inspector<Ctx<Db>>,
80{
81 bundle: &'a RecoveredBundle,
83
84 pub fill_state: Cow<'b, AggregateFills>,
86
87 deadline: tokio::time::Instant,
90
91 output: DriverOutput<Db, Insp>,
93}
94
95impl<'a, 'b, Db, Insp> SignetEthBundleDriver<'a, 'b, Db, Insp>
96where
97 Db: Database,
98 Insp: Inspector<Ctx<Db>>,
99{
100 pub fn new(
103 bundle: &'a RecoveredBundle,
104 host_evm: signet_evm::EvmNeedsTx<Db, Insp>,
105 deadline: tokio::time::Instant,
106 ) -> Self {
107 Self::new_with_fill_state(bundle, host_evm, deadline, Default::default())
108 }
109
110 pub fn new_with_fill_state(
115 bundle: &'a RecoveredBundle,
116 host_evm: signet_evm::EvmNeedsTx<Db, Insp>,
117 deadline: tokio::time::Instant,
118 fill_state: Cow<'b, AggregateFills>,
119 ) -> Self {
120 Self {
121 bundle,
122 fill_state,
123 deadline,
124 output: DriverOutput {
125 host_evm: Some(host_evm),
126 total_gas_used: 0,
127 total_host_gas_used: 0,
128 beneficiary_balance_increase: U256::ZERO,
129 bundle_fills: AggregateFills::default(),
130 bundle_orders: AggregateOrders::default(),
131 },
132 }
133 }
134
135 pub const fn bundle(&self) -> &RecoveredBundle {
137 self.bundle
138 }
139
140 pub const fn deadline(&self) -> tokio::time::Instant {
142 self.deadline
143 }
144
145 pub const fn total_gas_used(&self) -> u64 {
147 self.output.total_gas_used
148 }
149
150 pub const fn beneficiary_balance_increase(&self) -> U256 {
152 self.output.beneficiary_balance_increase
153 }
154
155 pub fn into_outputs(self) -> DriverOutput<Db, Insp> {
157 self.output
158 }
159}
160
161impl<RuDb, HostDb, RuInsp, HostInsp> BundleDriver<RuDb, SignetLayered<Layered<TimeLimit, RuInsp>>>
162 for SignetEthBundleDriver<'_, '_, HostDb, HostInsp>
163where
164 RuDb: Database + DatabaseCommit,
165 RuInsp: Inspector<Ctx<RuDb>>,
166 HostDb: Database + DatabaseCommit,
167 HostInsp: Inspector<Ctx<HostDb>>,
168{
169 type Error = SignetEthBundleError<RuDb>;
170
171 fn run_bundle(
172 &mut self,
173 mut trevm: EvmNeedsTx<RuDb, SignetEthBundleInsp<RuInsp>>,
174 ) -> DriveBundleResult<Self, RuDb, SignetEthBundleInsp<RuInsp>> {
175 trevm_ensure!(!self.bundle.txs.is_empty(), trevm, BundleError::BundleEmpty.into());
179
180 trevm_ensure!(
182 trevm.block_number().to::<u64>() == self.bundle.block_number,
183 trevm,
184 BundleError::BlockNumberMismatch.into()
185 );
186
187 let timestamp = trevm.block_timestamp();
189 trevm_ensure!(
190 self.bundle.is_valid_at_timestamp(timestamp.to()),
191 trevm,
192 BundleError::TimestampOutOfRange.into()
193 );
194
195 let beneficiary = trevm.beneficiary();
199 let inital_beneficiary_balance =
200 trevm_try!(trevm.try_read_balance(beneficiary).map_err(EVMError::Database), trevm);
201
202 for tx in self.bundle.host_txs().iter() {
208 self.output.host_evm = Some(trevm_try!(
209 self.output
210 .host_evm
211 .take()
212 .expect("host_evm missing")
213 .run_tx(tx)
214 .and_then(|mut htrevm| {
215 let result = htrevm.result();
216 if let Some(output) = result.output() {
217 if !result.is_success() {
218 debug!(
219 tx_hash = %tx.hash(),
220 callee = ?htrevm.callee(),
221 sender = ?htrevm.caller(),
222 input = hex::encode(htrevm.input()),
223 output = hex::encode(output),
224 "host transaction reverted"
225 );
226 }
227 }
228
229 trevm_ensure!(
230 result.is_success(),
231 htrevm,
232 EVMError::Custom("host transaction reverted".to_string())
233 );
234
235 self.output.use_host_gas(result.gas_used());
237
238 let host_fills = htrevm
240 .inner_mut_unchecked()
241 .inspector
242 .as_mut_detector()
243 .take_aggregates()
244 .0;
245 self.output.bundle_fills.absorb(&host_fills);
246
247 Ok(htrevm.accept_state())
248 })
249 .map_err(|err| {
250 debug!(err = %err.error(), err_dbg = ?err.error(), "error while running host transaction");
251 SignetEthBundleError::HostSimulation("host simulation error")
252 }),
253 trevm
254 ));
255 }
256
257 for tx in self.bundle.txs().iter() {
259 let span = debug_span!(
260 "bundle_tx_loop",
261 tx_hash = %tx.hash(),
262 caller = tracing::field::Empty,
263 callee = tracing::field::Empty,
264 input = tracing::field::Empty,
265 );
266 let _guard = span.enter();
267
268 let limit = trevm.inner_mut_unchecked().ctx_inspector().1.outer_mut().outer_mut();
270 *limit = TimeLimit::new(self.deadline - tokio::time::Instant::now());
271
272 let tx_hash = tx.hash();
273
274 let mut t = trevm.run_tx(tx).map_err(EvmErrored::err_into).inspect_err(
278 |err| error!(err = %err.error(), "error while running rollup transaction"),
279 )?;
280
281 if enabled!(tracing::Level::DEBUG) {
283 span.record("caller", t.caller().to_string());
284 span.record(
285 "callee",
286 t.callee().map(|c| c.to_string()).unwrap_or_else(|| "CREATE".to_string()),
287 );
288 span.record("input", hex::encode(t.input()));
289 }
290
291 let result = t.result();
293 let gas_used = result.gas_used();
294
295 if result.is_success() {
300 let (tx_fills, tx_orders) =
301 t.inner_mut_unchecked().inspector.as_mut_detector().take_aggregates();
302
303 let mut candidate_fills = self.output.bundle_fills.clone();
306 let mut candidate_orders = self.output.bundle_orders.clone();
307
308 candidate_fills.absorb(&tx_fills);
310 candidate_orders.absorb(&tx_orders);
311
312 if self.fill_state.check_ru_tx_events(&candidate_fills, &candidate_orders).is_err()
315 {
316 if self.bundle.reverting_tx_hashes().contains(tx_hash) {
317 debug!("transaction marked as revertible, reverting");
318 trevm = t.reject();
319 continue;
320 } else {
321 debug!("transaction dropped due to insufficient fills, not marked as revertible");
322 return Err(t.errored(BundleError::BundleReverted.into()));
323 }
324 }
325
326 self.output.bundle_fills = candidate_fills;
328 self.output.bundle_orders = candidate_orders;
329 } else {
330 if !self.bundle.reverting_tx_hashes().contains(tx_hash) {
335 debug!(
336 output = result.output().map(hex::encode),
337 "transaction reverted, not marked as revertible"
338 );
339 return Err(t.errored(BundleError::BundleReverted.into()));
340 }
341 }
342
343 self.output.use_gas(gas_used);
346 trevm = t.accept_state()
347 }
348
349 let beneficiary_balance =
352 trevm_try!(trevm.try_read_balance(beneficiary).map_err(EVMError::Database), trevm);
353
354 self.output.record_beneficiary_increase(
355 beneficiary_balance.saturating_sub(inital_beneficiary_balance),
356 );
357
358 Ok(trevm)
359 }
360
361 fn post_bundle(
362 &mut self,
363 _trevm: &EvmNeedsTx<RuDb, SignetEthBundleInsp<RuInsp>>,
364 ) -> Result<(), Self::Error> {
365 Ok(())
366 }
367}