Skip to content

Commit 74e8d0b

Browse files
authored
fix: driver maintenance (#17)
* fix: driver maintenance * refactor: bundle driver now outputs necessary fills * fix: tests * chore: remove outdated comment * refactor: remove bundle error * chore: remove dead comment * chore: rename AggregateFills * fix: finish rename
1 parent 38af4ee commit 74e8d0b

File tree

20 files changed

+172
-259
lines changed

20 files changed

+172
-259
lines changed

crates/bundle/Cargo.toml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ signet-zenith.workspace = true
1818
alloy.workspace = true
1919

2020
serde.workspace = true
21-
thiserror.workspace = true
2221
tracing.workspace = true
2322

2423
[dev-dependencies]

crates/bundle/src/call/driver.rs

Lines changed: 46 additions & 85 deletions
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,35 @@
11
use crate::{SignetCallBundle, SignetCallBundleResponse};
22
use alloy::{consensus::TxEnvelope, primitives::U256};
33
use signet_evm::OrderDetector;
4-
use signet_types::{MarketContext, MarketError};
54
use std::fmt::Debug;
5+
use tracing::{debug_span, instrument, Level};
66
use trevm::{
77
revm::{primitives::EVMError, Database, DatabaseCommit},
88
trevm_bail, trevm_ensure, unwrap_or_trevm_err, BundleDriver, BundleError,
99
};
1010

11-
/// Errors that can occur when running a bundle on the Signet EVM.
12-
#[derive(thiserror::Error)]
13-
pub enum SignetBundleError<Db: Database> {
14-
/// A primitive [`BundleError`] error ocurred.
15-
#[error(transparent)]
16-
BundleError(#[from] BundleError<Db>),
17-
/// A [`MarketError`] ocurred.
18-
#[error(transparent)]
19-
MarketError(#[from] MarketError),
20-
}
21-
22-
impl<Db: Database> Debug for SignetBundleError<Db> {
23-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24-
match self {
25-
SignetBundleError::BundleError(e) => write!(f, "BundleError({:?})", e),
26-
SignetBundleError::MarketError(e) => write!(f, "MarketError({:?})", e),
27-
}
28-
}
29-
}
30-
31-
impl<Db: Database> From<EVMError<Db::Error>> for SignetBundleError<Db> {
32-
fn from(e: EVMError<Db::Error>) -> Self {
33-
SignetBundleError::BundleError(BundleError::EVMError { inner: e })
34-
}
35-
}
36-
37-
impl<Db: Database> SignetBundleError<Db> {
38-
/// Instantiate a new [`SignetBundleError`] from a [`Database::Error`].
39-
pub const fn evm_db(e: Db::Error) -> Self {
40-
SignetBundleError::BundleError(BundleError::EVMError { inner: EVMError::Database(e) })
41-
}
42-
}
43-
4411
/// A bundle driver for the Signet EVM.
12+
///
13+
/// This type allows for the simulation of a [`SignetCallBundle`], outputting
14+
/// the results of the simulation in a [`SignetCallBundleResponse`].
4515
#[derive(Debug)]
4616
pub struct SignetBundleDriver<'a> {
4717
/// The bundle to drive.
4818
bundle: &'a SignetCallBundle,
4919
/// The accumulated results of the bundle, if applicable.
5020
response: SignetCallBundleResponse,
51-
/// The market context.
52-
context: MarketContext,
53-
/// The host chain id.
54-
host_chain_id: u64,
21+
}
22+
23+
impl<'a> From<&'a SignetCallBundle> for SignetBundleDriver<'a> {
24+
fn from(bundle: &'a SignetCallBundle) -> Self {
25+
Self::new(bundle)
26+
}
5527
}
5628

5729
impl<'a> SignetBundleDriver<'a> {
5830
/// Create a new bundle driver with the given bundle and response.
59-
pub fn new(bundle: &'a SignetCallBundle, host_chain_id: u64) -> Self {
60-
let context = bundle.make_context(host_chain_id);
61-
Self { bundle, response: Default::default(), context, host_chain_id }
31+
pub fn new(bundle: &'a SignetCallBundle) -> Self {
32+
Self { bundle, response: Default::default() }
6233
}
6334
}
6435

@@ -73,55 +44,32 @@ impl SignetBundleDriver<'_> {
7344
&self.response
7445
}
7546

76-
/// Get a reference to the market context.
77-
pub const fn context(&self) -> &MarketContext {
78-
&self.context
79-
}
80-
8147
/// Take the response from the bundle driver. This consumes
8248
pub fn into_response(self) -> SignetCallBundleResponse {
8349
self.response
8450
}
8551

86-
/// Clear the driver, resetting the response and the market context. This
87-
/// reset the driver, allowing for resimulation of the same bundle.
88-
///
89-
/// The returned context contains the amount of overfill, i.e. the amount
90-
/// that was filled, but not required by the orders in the bundle.
91-
pub fn clear(&mut self) -> (SignetCallBundleResponse, MarketContext) {
92-
let r = std::mem::take(&mut self.response);
93-
let context = self.bundle.make_context(self.host_chain_id);
94-
let c = std::mem::replace(&mut self.context, context);
95-
(r, c)
52+
/// Clear the driver, resetting the response.
53+
pub fn clear(&mut self) -> SignetCallBundleResponse {
54+
std::mem::take(&mut self.response)
9655
}
9756

98-
/// Check the market context, accept the result, accumulate the transaction
57+
/// Check the aggregate fills, accept the result, accumulate the transaction
9958
/// details into the response.
100-
fn check_market_and_accept<'a, Db: Database + DatabaseCommit, I>(
59+
fn accept_and_accumulate<'a, Db: Database + DatabaseCommit, I>(
10160
&mut self,
102-
mut trevm: signet_evm::EvmTransacted<'a, Db, I>,
61+
trevm: signet_evm::EvmTransacted<'a, Db, I>,
10362
tx: &TxEnvelope,
10463
pre_sim_coinbase_balance: &mut U256,
10564
basefee: U256,
10665
) -> signet_evm::DriveBundleResult<'a, Db, Self, I> {
10766
let coinbase = trevm.inner().block().coinbase;
10867

109-
// Taking these clears the context for reuse.
110-
let (aggregate, market_context) =
111-
trevm.inner_mut_unchecked().context.external.take_aggregate();
112-
113-
// We check the market context here, and if it fails, we discard the
114-
// transaction outcome and push a failure receipt.
115-
if let Err(err) = self.context.checked_remove_ru_tx_events(&aggregate, &market_context) {
116-
tracing::debug!(%err, "Discarding transaction outcome due to market error");
117-
return Err(trevm.errored(SignetBundleError::MarketError(err)));
118-
}
119-
12068
let (execution_result, mut trevm) = trevm.accept();
12169

12270
// Get the post simulation coinbase balance
12371
let post_sim_coinbase_balance = unwrap_or_trevm_err!(
124-
trevm.try_read_balance(coinbase).map_err(SignetBundleError::evm_db),
72+
trevm.try_read_balance(coinbase).map_err(EVMError::Database).map_err(BundleError::from),
12573
trevm
12674
);
12775

@@ -143,10 +91,11 @@ impl SignetBundleDriver<'_> {
14391

14492
// [`BundleDriver`] Implementation for [`SignetCallBundle`].
14593
// This is useful mainly for the `signet_simBundle` endpoint,
146-
// which is used to simulate a signet bundle while respecting market context.
94+
// which is used to simulate a signet bundle while respecting aggregate fills.
14795
impl<I> BundleDriver<OrderDetector<I>> for SignetBundleDriver<'_> {
148-
type Error<Db: Database + DatabaseCommit> = SignetBundleError<Db>;
96+
type Error<Db: Database + DatabaseCommit> = BundleError<Db>;
14997

98+
#[instrument(skip_all, level = Level::DEBUG)]
15099
fn run_bundle<'a, Db: Database + DatabaseCommit>(
151100
&mut self,
152101
trevm: signet_evm::EvmNeedsTx<'a, Db, I>,
@@ -155,56 +104,63 @@ impl<I> BundleDriver<OrderDetector<I>> for SignetBundleDriver<'_> {
155104
let bundle = &self.bundle.bundle;
156105

157106
// Ensure that the bundle has transactions
158-
trevm_ensure!(!bundle.txs.is_empty(), trevm, BundleError::BundleEmpty.into());
107+
trevm_ensure!(!bundle.txs.is_empty(), trevm, BundleError::BundleEmpty);
159108

160109
// Check if the block we're in is valid for this bundle. Both must match
161110
trevm_ensure!(
162-
trevm.inner().block().number.to::<u64>() == bundle.block_number,
111+
trevm.block_number().to::<u64>() == bundle.block_number,
163112
trevm,
164-
BundleError::BlockNumberMismatch.into()
113+
BundleError::BlockNumberMismatch
165114
);
115+
// Set the state block number this simulation was based on
116+
self.response.state_block_number = trevm.block_number().to::<u64>();
166117

167118
// Check if the state block number is valid (not 0, and not a tag)
168119
trevm_ensure!(
169120
bundle.state_block_number.is_number()
170121
&& bundle.state_block_number.as_number().unwrap_or_default() != 0,
171122
trevm,
172-
BundleError::BlockNumberMismatch.into()
123+
BundleError::BlockNumberMismatch
173124
);
174125

175126
// Decode and validate the transactions in the bundle
176127
let txs = unwrap_or_trevm_err!(self.bundle.decode_and_validate_txs(), trevm);
177128

178129
trevm.try_with_block(self.bundle, |mut trevm| {
179130
// Get the coinbase and basefee from the block
180-
let coinbase = trevm.inner().block().coinbase;
181-
let basefee = trevm.inner().block().basefee;
182-
183-
// Set the state block number this simulation was based on
184-
self.response.state_block_number = trevm.inner().block().number.to::<u64>();
131+
// NB: Do not move these outside the `try_with_block` closure, as
132+
// they may be rewritten by the bundle
133+
let coinbase = trevm.block().coinbase;
134+
let basefee = trevm.block().basefee;
185135

186136
// Cache the pre simulation coinbase balance, so we can use it to calculate the coinbase diff after every tx simulated.
187137
let initial_coinbase_balance = unwrap_or_trevm_err!(
188-
trevm.try_read_balance(coinbase).map_err(SignetBundleError::evm_db),
138+
trevm
139+
.try_read_balance(coinbase)
140+
.map_err(EVMError::Database)
141+
.map_err(BundleError::from),
189142
trevm
190143
);
191144

192145
// Stack vars to keep track of the coinbase balance across txs.
193146
let mut pre_sim_coinbase_balance = initial_coinbase_balance;
194147

195-
for tx in txs.iter() {
148+
let span = debug_span!("bundle loop", count = txs.len()).entered();
149+
for (idx, tx) in txs.iter().enumerate() {
150+
let _span = debug_span!("tx loop", tx = %tx.tx_hash(), idx).entered();
196151
let run_result = trevm.run_tx(tx);
197152

198153
let transacted_trevm = run_result.map_err(|e| e.map_err(Into::into))?;
199154

200155
// Set the trevm instance to the committed one
201-
trevm = self.check_market_and_accept(
156+
trevm = self.accept_and_accumulate(
202157
transacted_trevm,
203158
tx,
204159
&mut pre_sim_coinbase_balance,
205160
basefee,
206161
)?;
207162
}
163+
drop(span);
208164

209165
// Accumulate the total results
210166
self.response.coinbase_diff =
@@ -218,6 +174,11 @@ impl<I> BundleDriver<OrderDetector<I>> for SignetBundleDriver<'_> {
218174
.unwrap_or_default();
219175
self.response.bundle_hash = self.bundle.bundle_hash();
220176

177+
// Taking these clears the order detector
178+
let (orders, fills) = trevm.inner_mut_unchecked().context.external.take_aggregates();
179+
self.response.orders = orders;
180+
self.response.fills = fills;
181+
221182
// return the final state
222183
Ok(trevm)
223184
})

crates/bundle/src/call/error.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+

crates/bundle/src/call/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
mod driver;
2-
pub use driver::{SignetBundleDriver, SignetBundleError};
2+
pub use driver::SignetBundleDriver;
33

44
mod trevm;
55

crates/bundle/src/call/trevm.rs

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,22 @@ use trevm::{revm::primitives::BlockEnv, Block};
44

55
impl Block for SignetCallBundle {
66
fn fill_block_env(&self, block_env: &mut BlockEnv) {
7-
block_env.number =
8-
self.bundle.state_block_number.as_number().map(U256::from).unwrap_or(block_env.number);
9-
block_env.timestamp = self.bundle.timestamp.map(U256::from).unwrap_or(block_env.timestamp);
10-
block_env.gas_limit = self.bundle.gas_limit.map(U256::from).unwrap_or(block_env.gas_limit);
11-
block_env.difficulty =
12-
self.bundle.difficulty.map(U256::from).unwrap_or(block_env.difficulty);
13-
block_env.basefee = self.bundle.base_fee.map(U256::from).unwrap_or(block_env.basefee);
7+
let BlockEnv {
8+
number,
9+
coinbase,
10+
timestamp,
11+
gas_limit,
12+
basefee,
13+
difficulty,
14+
prevrandao: _,
15+
blob_excess_gas_and_price: _,
16+
} = block_env;
17+
18+
*number = self.bundle.state_block_number.as_number().map(U256::from).unwrap_or(*number);
19+
*coinbase = self.bundle.coinbase.unwrap_or(*coinbase);
20+
*timestamp = self.bundle.timestamp.map(U256::from).unwrap_or(*timestamp);
21+
*gas_limit = self.bundle.gas_limit.map(U256::from).unwrap_or(*gas_limit);
22+
*difficulty = self.bundle.difficulty.map(U256::from).unwrap_or(*difficulty);
23+
*basefee = self.bundle.base_fee.map(U256::from).unwrap_or(*basefee);
1424
}
1525
}

0 commit comments

Comments
 (0)