Skip to content

Commit cdfff7b

Browse files
committed
fix: handle sender nonces for bundles
1 parent 643ab88 commit cdfff7b

File tree

7 files changed

+72
-33
lines changed

7 files changed

+72
-33
lines changed

based/crates/common/src/communication/messages.rs

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use tokio::sync::oneshot::{self};
2222

2323
use crate::{
2424
custom_v4::OpExecutionPayloadEnvelopeV4Patch,
25-
db::{DBFrag, DBSorting},
25+
db::{DBFrag, DBSorting, sorting::StateId},
2626
order::{SimulatedBundle, ValidatedBundle, bundle::BundleValidationError},
2727
time::{Duration, IngestionTime, Instant, Nanos},
2828
transaction::{SimulatedTx, Transaction},
@@ -365,39 +365,40 @@ pub enum SequencerToSimulator<Db> {
365365
/// Simulate a bundle Top of frag
366366
SimulateBundleTof(Arc<ValidatedBundle>, DBFrag<Db>),
367367
}
368+
368369
impl<Db> SequencerToSimulator<Db> {
369370
/// Returns simulation info.
370-
/// TODO(mempirate): return type for bundle?
371-
pub fn sim_info(&self) -> (Address, u64, u64) {
371+
pub fn sim_info(&self) -> (StateId, Vec<(Address, u64)>) {
372372
match self {
373-
SequencerToSimulator::SimulateTx(t, db) => (t.sender(), t.nonce(), db.state_id()),
374-
SequencerToSimulator::SimulateTxTof(t, db) => (t.sender(), t.nonce(), db.state_id()),
375-
SequencerToSimulator::SimulateBundle(b, db) => todo!("What to return here?"),
376-
SequencerToSimulator::SimulateBundleTof(b, db) => todo!("What to return here?"),
373+
SequencerToSimulator::SimulateTx(t, db) => (db.state_id(), vec![(t.sender(), t.nonce())]),
374+
SequencerToSimulator::SimulateTxTof(t, db) => (db.state_id(), vec![(t.sender(), t.nonce())]),
375+
SequencerToSimulator::SimulateBundle(b, db) => (db.state_id(), b.sender_nonces().collect()),
376+
SequencerToSimulator::SimulateBundleTof(b, db) => (db.state_id(), b.sender_nonces().collect()),
377377
}
378378
}
379379
}
380380

381381
#[derive(Debug)]
382382
pub struct SimulatorToSequencer {
383383
/// Sender address and nonce
384-
pub sender_info: (Address, u64),
384+
pub sender_nonces: Vec<(Address, u64)>,
385385
pub state_id: u64,
386386
pub simtime: Duration,
387387
pub msg: SimulatorToSequencerMsg,
388388
}
389389

390390
impl SimulatorToSequencer {
391-
pub fn new(sender_info: (Address, u64), state_id: u64, simtime: Duration, msg: SimulatorToSequencerMsg) -> Self {
392-
Self { sender_info, state_id, simtime, msg }
393-
}
394-
395-
pub fn sender(&self) -> &Address {
396-
&self.sender_info.0
391+
pub fn new(
392+
sender_nonces: Vec<(Address, u64)>,
393+
state_id: u64,
394+
simtime: Duration,
395+
msg: SimulatorToSequencerMsg,
396+
) -> Self {
397+
Self { sender_nonces, state_id, simtime, msg }
397398
}
398399

399-
pub fn nonce(&self) -> u64 {
400-
self.sender_info.1
400+
pub fn sender_nonces(&self) -> &[(Address, u64)] {
401+
&self.sender_nonces
401402
}
402403
}
403404

based/crates/common/src/db/sorting.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,22 @@ use parking_lot::RwLock;
55
use super::{DBFrag, State};
66
use crate::typedefs::*;
77

8+
pub type StateId = u64;
9+
810
/// DB That is used when sorting a new frag
911
/// Thread safe
1012
#[derive(Clone, Debug)]
1113
pub struct DBSorting<Db> {
1214
pub db: Arc<RwLock<State<DBFrag<Db>>>>,
13-
state_id: u64,
15+
state_id: StateId,
1416
}
1517

1618
impl<Db> DBSorting<Db> {
1719
pub fn new(frag_db: DBFrag<Db>) -> Self {
1820
Self { db: Arc::new(RwLock::new(State::new(frag_db))), state_id: rand::random() }
1921
}
2022

21-
pub fn state_id(&self) -> u64 {
23+
pub fn state_id(&self) -> StateId {
2224
self.state_id
2325
}
2426
}

based/crates/common/src/order/bundle.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,11 @@ impl ValidatedBundle {
164164
// SAFETY: At this point, the bundle hash is guaranteed to be initialized.
165165
*self.bundle_hash.get().expect("bundle hash is not initialized")
166166
}
167+
168+
/// Returns an iterator over the senders and nonces of the transactions in the bundle.
169+
pub fn sender_nonces(&self) -> impl Iterator<Item = (Address, u64)> {
170+
self.transactions.iter().map(|tx| (tx.sender(), tx.nonce()))
171+
}
167172
}
168173

169174
/// A simulated bundle.

based/crates/common/src/order/mod.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,13 @@ impl SimulatedOrder {
140140
SimulatedOrder::Bundle(bundle) => bundle.estimated_da(),
141141
}
142142
}
143+
144+
pub fn included_telemetry(&self, frag: Uuid, id_in_frag: usize) -> Telemetry {
145+
match self {
146+
SimulatedOrder::Tx(tx) => tx.to_included_telemetry(frag, id_in_frag),
147+
SimulatedOrder::Bundle(bundle) => todo!(),
148+
}
149+
}
143150
}
144151

145152
/// An order that is ready to be executed in the next block.

based/crates/sequencer/src/lib.rs

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -508,10 +508,11 @@ where
508508
/// Processes transaction simulation results from the simulator actor.
509509
///
510510
/// Handles both block transaction simulations during sorting and
511-
/// transaction pool simulations for future inclusion.
511+
/// order pool simulations for future inclusion.
512512
fn handle_sim_result(mut self, result: SimulatorToSequencer, data: &mut SequencerContext<Db>) -> Self {
513-
let (sender, nonce) = result.sender_info;
514513
let state_id = result.state_id;
514+
let sender_nonces = result.sender_nonces;
515+
515516
let simtime = result.simtime;
516517
// TODO(mempirate): Handle bundle simulations.
517518
match result.msg {
@@ -526,10 +527,12 @@ where
526527
}
527528

528529
data.timers.handle_sim.start();
529-
sort_data.handle_sim(simulated_tx.map(SimulatedOrder::Tx), sender, data.base_fee(), simtime);
530+
sort_data.handle_sim(simulated_tx.map(SimulatedOrder::Tx), sender_nonces, data.base_fee(), simtime);
530531
data.timers.handle_sim.stop();
531532
}
532533
SimulatorToSequencerMsg::TxPoolTopOfFrag(simulated_tx) => {
534+
let (sender, nonce) = sender_nonces.first().expect("no sender nonces");
535+
533536
match simulated_tx {
534537
Ok(res) if data.shared_state.as_ref().is_valid(state_id) => {
535538
data.tx_pool.handle_simulated(SimulatedOrder::Tx(res))
@@ -539,7 +542,7 @@ where
539542
// We would have already re-sent the tx for sim on the correct fragment.
540543
}
541544
Err(_e) => {
542-
data.tx_pool.remove(&sender, nonce, &mut data.telemetry);
545+
data.tx_pool.remove(sender, *nonce, &mut data.telemetry);
543546
}
544547
}
545548
}
@@ -554,7 +557,12 @@ where
554557
}
555558

556559
data.timers.handle_sim.start();
557-
sort_data.handle_sim(simulated_bundle.map(SimulatedOrder::Bundle), sender, data.base_fee(), simtime);
560+
sort_data.handle_sim(
561+
simulated_bundle.map(SimulatedOrder::Bundle),
562+
sender_nonces,
563+
data.base_fee(),
564+
simtime,
565+
);
558566
data.timers.handle_sim.stop();
559567
}
560568
SimulatorToSequencerMsg::BundleTopOfFrag(simulated_bundle) => match simulated_bundle {
@@ -566,7 +574,9 @@ where
566574
// We would have already re-sent the bundle for sim on the correct fragment.
567575
}
568576
Err(_e) => {
569-
data.tx_pool.remove(&sender, nonce, &mut data.telemetry);
577+
for (sender, nonce) in sender_nonces {
578+
data.tx_pool.remove(&sender, nonce, &mut data.telemetry);
579+
}
570580
}
571581
},
572582
}

based/crates/sequencer/src/simulator.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,7 @@ where
167167

168168
// Get initial coinbase balance BEFORE any transactions
169169
let start_balance = balance_from_db(evm.db_mut(), coinbase);
170+
let mut intermediate_balance = start_balance;
170171

171172
// The post-state of the bundle.
172173
let mut post_state = ResultVecAndState::<ExecutionResult<OpHaltReason>, EvmState>::new(
@@ -187,6 +188,14 @@ where
187188
return Err(SimulationError::RevertWithDisallowedRevert);
188189
}
189190

191+
// Update intermediate balance and payment.
192+
// NOTE: If a transaction does not touch the coinbase, this falls back to the intermediate balance (instead of
193+
// 0, which would be incorrect)
194+
let end_balance =
195+
result_and_state.state.get(&coinbase).map(|a| a.info.balance).unwrap_or_else(|| intermediate_balance);
196+
let payment = end_balance.saturating_sub(intermediate_balance);
197+
intermediate_balance = end_balance;
198+
190199
// Commit to State's in-memory cache (not the underlying db)
191200
// so subsequent transactions see these state changes
192201
// TODO(mempirate): validate that this is actually the case and we're not committing to underlying db
@@ -198,7 +207,7 @@ where
198207
simulated.push(SimulatedTx::new(
199208
tx.clone().into(),
200209
result_and_state,
201-
U256::ZERO, // Per-tx payment not meaningful for bundles
210+
payment,
202211
deposit_nonce,
203212
sim_start.elapsed(),
204213
));
@@ -248,7 +257,7 @@ where
248257
});
249258

250259
connections.receive(|msg: SequencerToSimulator<Db>, senders| {
251-
let (sender, nonce, state_id) = msg.sim_info();
260+
let (state_id, sender_nonces) = msg.sim_info();
252261
let curt = Instant::now();
253262
let msg = match msg {
254263
SequencerToSimulator::SimulateTx(tx, db) => SimulatorToSequencerMsg::Tx(Self::simulate_transaction(
@@ -291,7 +300,7 @@ where
291300
}
292301
};
293302
let _ = senders.send_timeout(
294-
SimulatorToSequencer::new((sender, nonce), state_id, curt.elapsed(), msg),
303+
SimulatorToSequencer::new(sender_nonces, state_id, curt.elapsed(), msg),
295304
Duration::from_millis(10),
296305
);
297306
});

based/crates/sequencer/src/sorting/sorting_data.rs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -207,32 +207,37 @@ impl<Db> SortingData<Db> {
207207
pub fn handle_sim(
208208
&mut self,
209209
simulated_order: SimulationResult<SimulatedOrder>,
210-
sender: Address,
210+
sender_nonces: Vec<(Address, u64)>,
211211
base_fee: u64,
212212
simtime: Duration,
213213
) {
214214
self.in_flight_sims -= 1;
215215
self.telemetry.tot_sim_time += simtime;
216216

217-
tracing::trace!(%sender, "handling simulation result");
217+
tracing::trace!(?sender_nonces, "handling simulation result");
218218

219219
// handle errored sim
220220
let Ok(order) = simulated_order.inspect_err(|e| {
221-
tracing::trace!(%sender, error = ?e, "error handling simulation result");
221+
tracing::trace!(?sender_nonces, error = ?e, "error handling simulation result");
222222
// Send metric for simulation error
223223
MetricsUpdate::send(
224224
self.uuid,
225225
Metric::IncrementCounter(Counter::SimulationErrors, 1),
226226
&mut self.metrics_producer,
227227
);
228228
}) else {
229-
self.tof_snapshot.remove_from_sender(sender, base_fee);
229+
for (sender, _) in &sender_nonces {
230+
self.tof_snapshot.remove_from_sender(*sender, base_fee);
231+
}
232+
230233
self.telemetry.n_sims_errored += 1;
231234
return;
232235
};
233236

234237
if self.gas_remaining < order.gas_used() {
235-
self.tof_snapshot.remove_from_sender(sender, base_fee);
238+
for (sender, _) in &sender_nonces {
239+
self.tof_snapshot.remove_from_sender(*sender, base_fee);
240+
}
236241
return;
237242
}
238243
self.telemetry.n_sims_succesful += 1;
@@ -439,7 +444,7 @@ impl<Db: DatabaseRef> SortingData<Db> {
439444
self.db.commit_ref(result_and_state.state());
440445
TelemetryUpdate::send(
441446
order.uuid(),
442-
tx.to_included_telemetry(self.uuid, self.transactions.len()),
447+
order.to_included_telemetry(self.uuid, self.transactions.len()),
443448
&mut self.telemetry_producer,
444449
);
445450

0 commit comments

Comments
 (0)