signet_bundle/call/
driver.rs1use crate::{SignetCallBundle, SignetCallBundleResponse};
2use alloy::{consensus::TxEnvelope, primitives::U256};
3use signet_evm::{DriveBundleResult, EvmNeedsTx, EvmTransacted, SignetInspector, SignetLayered};
4use std::fmt::Debug;
5use tracing::{debug_span, instrument, Level};
6use trevm::{
7 helpers::Ctx,
8 revm::{context::result::EVMError, Database, DatabaseCommit, Inspector},
9 trevm_bail, trevm_ensure, trevm_try, BundleDriver, BundleError,
10};
11
12#[derive(Debug)]
17pub struct SignetBundleDriver<'a> {
18 bundle: &'a SignetCallBundle,
20 response: SignetCallBundleResponse,
22}
23
24impl<'a> From<&'a SignetCallBundle> for SignetBundleDriver<'a> {
25 fn from(bundle: &'a SignetCallBundle) -> Self {
26 Self::new(bundle)
27 }
28}
29
30impl<'a> SignetBundleDriver<'a> {
31 pub fn new(bundle: &'a SignetCallBundle) -> Self {
33 Self { bundle, response: Default::default() }
34 }
35}
36
37impl SignetBundleDriver<'_> {
38 pub const fn bundle(&self) -> &SignetCallBundle {
40 self.bundle
41 }
42
43 pub const fn response(&self) -> &SignetCallBundleResponse {
45 &self.response
46 }
47
48 pub fn into_response(self) -> SignetCallBundleResponse {
50 self.response
51 }
52
53 pub fn clear(&mut self) -> SignetCallBundleResponse {
55 std::mem::take(&mut self.response)
56 }
57
58 fn accept_and_accumulate<Db, Insp>(
61 &mut self,
62 trevm: EvmTransacted<Db, Insp>,
63 tx: &TxEnvelope,
64 pre_sim_coinbase_balance: &mut U256,
65 basefee: u64,
66 ) -> DriveBundleResult<Self, Db, Insp>
67 where
68 Db: Database + DatabaseCommit,
69 Insp: Inspector<Ctx<Db>>,
70 {
71 let beneficiary = trevm.beneficiary();
72
73 let (execution_result, mut trevm) = trevm.accept();
74
75 let post_sim_coinbase_balance = trevm_try!(
77 trevm
78 .try_read_balance(beneficiary)
79 .map_err(EVMError::Database)
80 .map_err(BundleError::from),
81 trevm
82 );
83
84 let coinbase_diff = post_sim_coinbase_balance.saturating_sub(*pre_sim_coinbase_balance);
86
87 trevm_try!(
89 self.response.accumulate_tx(tx, coinbase_diff, basefee, execution_result),
90 trevm
91 );
92
93 *pre_sim_coinbase_balance = post_sim_coinbase_balance;
95
96 Ok(trevm)
97 }
98}
99
100impl<Db, Insp> BundleDriver<Db, SignetLayered<Insp>> for SignetBundleDriver<'_>
104where
105 Db: Database + DatabaseCommit,
106 Insp: Inspector<Ctx<Db>>,
107{
108 type Error = BundleError<Db>;
109
110 #[instrument(skip_all, level = Level::DEBUG)]
111 fn run_bundle(&mut self, trevm: EvmNeedsTx<Db, Insp>) -> DriveBundleResult<Self, Db, Insp> {
112 let bundle = &self.bundle.bundle;
114
115 trevm_ensure!(!bundle.txs.is_empty(), trevm, BundleError::BundleEmpty);
117
118 trevm_ensure!(
120 trevm.block_number() == bundle.block_number,
121 trevm,
122 BundleError::BlockNumberMismatch
123 );
124 self.response.state_block_number = trevm.block_number();
126
127 trevm_ensure!(
129 bundle.state_block_number.is_number()
130 && bundle.state_block_number.as_number().unwrap_or_default() != 0,
131 trevm,
132 BundleError::BlockNumberMismatch
133 );
134
135 let txs = trevm_try!(self.bundle.decode_and_validate_txs(), trevm);
137
138 trevm.try_with_block(self.bundle, |mut trevm| {
139 let coinbase = trevm.beneficiary();
143 let basefee = trevm.block().basefee;
144
145 let initial_coinbase_balance = trevm_try!(
147 trevm
148 .try_read_balance(coinbase)
149 .map_err(EVMError::Database)
150 .map_err(BundleError::from),
151 trevm
152 );
153
154 let mut pre_sim_coinbase_balance = initial_coinbase_balance;
156
157 let span = debug_span!("bundle loop", count = txs.len()).entered();
158 for (idx, tx) in txs.iter().enumerate() {
159 let _span = debug_span!("tx loop", tx = %tx.tx_hash(), idx).entered();
160 let run_result = trevm.run_tx(tx);
161
162 let transacted_trevm = run_result.map_err(|e| e.map_err(Into::into))?;
163
164 trevm = self.accept_and_accumulate(
166 transacted_trevm,
167 tx,
168 &mut pre_sim_coinbase_balance,
169 basefee,
170 )?;
171 }
172 drop(span);
173
174 self.response.coinbase_diff =
176 pre_sim_coinbase_balance.saturating_sub(initial_coinbase_balance);
177 self.response.eth_sent_to_coinbase =
178 self.response.coinbase_diff.saturating_sub(self.response.gas_fees);
179 self.response.bundle_gas_price = self
180 .response
181 .coinbase_diff
182 .checked_div(U256::from(self.response.total_gas_used))
183 .unwrap_or_default();
184 self.response.bundle_hash = self.bundle.bundle_hash();
185
186 let (orders, fills) =
188 trevm.inner_mut_unchecked().inspector.as_mut_detector().take_aggregates();
189 self.response.orders = orders;
190 self.response.fills = fills;
191
192 Ok(trevm)
194 })
195 }
196
197 fn post_bundle(&mut self, _trevm: &EvmNeedsTx<Db, Insp>) -> Result<(), Self::Error> {
198 Ok(())
199 }
200}