signet_bundle/send/
driver.rs1use crate::send::SignetEthBundle;
2use alloy::primitives::U256;
3use signet_evm::{DriveBundleResult, EvmNeedsTx, SignetLayered};
4use signet_types::SignedPermitError;
5use trevm::{
6 helpers::Ctx,
7 inspectors::{Layered, TimeLimit},
8 revm::{
9 context::result::{EVMError, ExecutionResult, HaltReason},
10 inspector::InspectorEvmTr,
11 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(thiserror::Error)]
22pub enum SignetEthBundleError<Db: Database> {
23 #[error(transparent)]
25 BundleError(#[from] BundleError<Db>),
26
27 #[error(transparent)]
29 SignedPermitError(#[from] SignedPermitError),
30
31 #[error(transparent)]
33 ContractError(#[from] alloy::contract::Error),
34}
35
36impl<Db: Database> core::fmt::Debug for SignetEthBundleError<Db> {
37 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
38 match self {
39 SignetEthBundleError::BundleError(bundle_error) => {
40 f.debug_tuple("BundleError").field(bundle_error).finish()
41 }
42 SignetEthBundleError::SignedPermitError(signed_order_error) => {
43 f.debug_tuple("SignedPermitError").field(signed_order_error).finish()
44 }
45 SignetEthBundleError::ContractError(contract_error) => {
46 f.debug_tuple("ContractError").field(contract_error).finish()
47 }
48 }
49 }
50}
51
52impl<Db: Database> From<EVMError<Db::Error>> for SignetEthBundleError<Db> {
53 fn from(err: EVMError<Db::Error>) -> Self {
54 Self::BundleError(BundleError::from(err))
55 }
56}
57
58#[derive(Debug, Clone)]
60pub struct SignetEthBundleDriver<'a> {
61 bundle: &'a SignetEthBundle,
62 deadline: std::time::Instant,
63
64 total_gas_used: u64,
65 beneficiary_balance_increase: U256,
66}
67
68impl<'a> SignetEthBundleDriver<'a> {
69 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 }
73 }
74
75 pub const fn bundle(&self) -> &SignetEthBundle {
77 self.bundle
78 }
79
80 pub const fn deadline(&self) -> std::time::Instant {
82 self.deadline
83 }
84
85 pub const fn total_gas_used(&self) -> u64 {
87 self.total_gas_used
88 }
89
90 pub const fn beneficiary_balance_increase(&self) -> U256 {
92 self.beneficiary_balance_increase
93 }
94}
95
96impl<Db, Insp> BundleDriver<Db, SignetLayered<Layered<TimeLimit, Insp>>>
97 for SignetEthBundleDriver<'_>
98where
99 Db: Database + DatabaseCommit,
100 Insp: Inspector<Ctx<Db>>,
101{
102 type Error = SignetEthBundleError<Db>;
103
104 fn run_bundle(
105 &mut self,
106 mut trevm: EvmNeedsTx<Db, SignetEthBundleInsp<Insp>>,
107 ) -> DriveBundleResult<Self, Db, SignetEthBundleInsp<Insp>> {
108 let bundle = &self.bundle.bundle;
109
110 self.total_gas_used = 0;
113 self.beneficiary_balance_increase = U256::ZERO;
114
115 let beneficiary = trevm.beneficiary();
117 let inital_beneficiary_balance =
118 trevm_try!(trevm.try_read_balance(beneficiary).map_err(EVMError::Database), trevm);
119
120 trevm_ensure!(!bundle.txs.is_empty(), trevm, BundleError::BundleEmpty.into());
122
123 trevm_ensure!(
125 trevm.block_number() == bundle.block_number,
126 trevm,
127 BundleError::BlockNumberMismatch.into()
128 );
129
130 let timestamp = trevm.block_timestamp();
132 trevm_ensure!(
133 timestamp >= bundle.min_timestamp.unwrap_or_default()
134 && timestamp <= bundle.max_timestamp.unwrap_or(u64::MAX),
135 trevm,
136 BundleError::TimestampOutOfRange.into()
137 );
138
139 if self.bundle().validate_fills_offchain(timestamp).is_err() {
141 return Err(trevm.errored(BundleError::BundleReverted.into()));
142 }
143
144 let txs = trevm_try!(self.bundle.decode_and_validate_txs(), trevm);
146
147 for tx in txs.into_iter() {
148 let limit = trevm.inner_mut_unchecked().ctx_inspector().1.outer_mut().outer_mut();
150 *limit = TimeLimit::new(self.deadline - std::time::Instant::now());
151
152 let tx_hash = tx.hash();
153
154 trevm = match trevm.run_tx(&tx) {
155 Ok(trevm) => {
156 let result = trevm.result();
158
159 match result {
160 ExecutionResult::Success { gas_used, .. } => {
161 self.total_gas_used = self.total_gas_used.saturating_add(*gas_used);
162 }
163 ExecutionResult::Halt { reason, .. }
165 if *reason == HaltReason::CallTooDeep =>
166 {
167 return Err(trevm.errored(BundleError::BundleReverted.into()));
168 }
169 ExecutionResult::Halt { gas_used, .. }
170 | ExecutionResult::Revert { gas_used, .. } => {
171 if !self.bundle.reverting_tx_hashes().contains(tx_hash) {
172 return Err(trevm.errored(BundleError::BundleReverted.into()));
173 }
174 self.total_gas_used = self.total_gas_used.saturating_add(*gas_used);
175 }
176 }
177 trevm.accept_state()
178 }
179 Err(err) => return Err(err.err_into()),
180 };
181 }
182
183 let beneficiary_balance =
184 trevm_try!(trevm.try_read_balance(beneficiary).map_err(EVMError::Database), trevm);
185
186 self.beneficiary_balance_increase =
187 beneficiary_balance.saturating_sub(inital_beneficiary_balance);
188
189 Ok(trevm)
190 }
191
192 fn post_bundle(
193 &mut self,
194 _trevm: &EvmNeedsTx<Db, SignetEthBundleInsp<Insp>>,
195 ) -> Result<(), Self::Error> {
196 Ok(())
197 }
198}