Skip to content

Commit df3f9a2

Browse files
committed
passes sim result to the submit tasks
- adds a SimResult type that binds a BlockEnv to a BuiltBlock - passess that SimResult to the SubmitTask for gas calculations
1 parent 2718b07 commit df3f9a2

File tree

3 files changed

+80
-51
lines changed

3 files changed

+80
-51
lines changed

src/tasks/block/sim.rs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,15 @@ pub struct Simulator {
3939
pub block_env: watch::Receiver<Option<BlockEnv>>,
4040
}
4141

42+
/// SimResult bundles a BuiltBlock to the BlockEnv it was simulated against.
43+
#[derive(Debug, Clone)]
44+
pub struct SimResult {
45+
/// The block built with the successfully simulated transactions
46+
pub block: BuiltBlock,
47+
/// The block environment the transactions were simulated against.
48+
pub env: BlockEnv,
49+
}
50+
4251
impl Simulator {
4352
/// Creates a new `Simulator` instance.
4453
///
@@ -116,7 +125,7 @@ impl Simulator {
116125
self,
117126
constants: SignetSystemConstants,
118127
cache: SimCache,
119-
submit_sender: mpsc::UnboundedSender<BuiltBlock>,
128+
submit_sender: mpsc::UnboundedSender<SimResult>,
120129
) -> JoinHandle<()> {
121130
debug!("starting simulator task");
122131

@@ -141,7 +150,7 @@ impl Simulator {
141150
mut self,
142151
constants: SignetSystemConstants,
143152
cache: SimCache,
144-
submit_sender: mpsc::UnboundedSender<BuiltBlock>,
153+
submit_sender: mpsc::UnboundedSender<SimResult>,
145154
) {
146155
loop {
147156
let sim_cache = cache.clone();
@@ -157,10 +166,10 @@ impl Simulator {
157166
let Some(block_env) = self.block_env.borrow_and_update().clone() else { return };
158167
debug!(block_env = ?block_env, "building on block env");
159168

160-
match self.handle_build(constants, sim_cache, finish_by, block_env).await {
169+
match self.handle_build(constants, sim_cache, finish_by, block_env.clone()).await {
161170
Ok(block) => {
162-
debug!(block = ?block, "built block");
163-
let _ = submit_sender.send(block);
171+
debug!(block = ?block.block_number(), "built block");
172+
let _ = submit_sender.send(SimResult { block, env: block_env });
164173
}
165174
Err(e) => {
166175
error!(err = %e, "failed to build block");

src/tasks/submit.rs

Lines changed: 65 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -25,14 +25,13 @@ use signet_zenith::{
2525
Zenith::{self, IncorrectHostBlock},
2626
};
2727
use std::time::{Instant, UNIX_EPOCH};
28-
use tokio::{sync::mpsc, task::JoinHandle};
28+
use tokio::{
29+
sync::mpsc::{self},
30+
task::JoinHandle,
31+
};
32+
use trevm::revm::context::BlockEnv;
2933

30-
/// Base maximum fee per gas to use as a starting point for retry bumps
31-
pub const BASE_FEE_PER_GAS: u128 = 10 * GWEI_TO_WEI as u128;
32-
/// Base max priority fee per gas to use as a starting point for retry bumps
33-
pub const BASE_MAX_PRIORITY_FEE_PER_GAS: u128 = 2 * GWEI_TO_WEI as u128;
34-
/// Base maximum fee per blob gas to use as a starting point for retry bumps
35-
pub const BASE_MAX_FEE_PER_BLOB_GAS: u128 = GWEI_TO_WEI as u128;
34+
use super::block::sim::SimResult;
3635

3736
macro_rules! spawn_provider_send {
3837
($provider:expr, $tx:expr) => {
@@ -95,7 +94,7 @@ impl SubmitTask {
9594
})
9695
}
9796

98-
/// Builds blob transaction and encodes the sidecar for it from the provided header and signature values
97+
/// Encodes the sidecar and then builds the 4844 blob transaction from the provided header and signature values.
9998
fn build_blob_tx(
10099
&self,
101100
fills: Vec<FillPermit2>,
@@ -118,8 +117,9 @@ impl SubmitTask {
118117
retry_count: usize,
119118
resp: &SignResponse,
120119
block: &BuiltBlock,
120+
block_env: &BlockEnv,
121121
) -> eyre::Result<ControlFlow> {
122-
let tx = self.prepare_tx(retry_count, resp, block).await?;
122+
let tx = self.prepare_tx(retry_count, resp, block, block_env).await?;
123123

124124
self.send_transaction(resp, tx).await
125125
}
@@ -131,9 +131,11 @@ impl SubmitTask {
131131
retry_count: usize,
132132
resp: &SignResponse,
133133
block: &BuiltBlock,
134+
block_env: &BlockEnv,
134135
) -> Result<TransactionRequest, eyre::Error> {
135136
// Create the transaction request with the signature values
136-
let tx: TransactionRequest = self.new_tx_request(retry_count, resp, block).await?;
137+
let tx: TransactionRequest =
138+
self.new_tx_request(retry_count, resp, block, block_env).await?;
137139

138140
// Simulate the transaction with a call to the host provider and report any errors
139141
if let Err(err) = self.sim_with_call(&tx).await {
@@ -191,6 +193,7 @@ impl SubmitTask {
191193
retry_count: usize,
192194
resp: &SignResponse,
193195
block: &BuiltBlock,
196+
block_env: &BlockEnv,
194197
) -> Result<TransactionRequest, eyre::Error> {
195198
// manually retrieve nonce
196199
let nonce =
@@ -200,14 +203,8 @@ impl SubmitTask {
200203
// Extract the signature components from the response
201204
let (v, r, s) = extract_signature_components(&resp.sig);
202205

203-
// Calculate gas limits based on retry attempts
204206
let (max_fee_per_gas, max_priority_fee_per_gas, max_fee_per_blob_gas) =
205-
calculate_gas_limits(
206-
retry_count,
207-
BASE_FEE_PER_GAS,
208-
BASE_MAX_PRIORITY_FEE_PER_GAS,
209-
BASE_MAX_FEE_PER_BLOB_GAS,
210-
);
207+
calculate_gas(retry_count, block_env);
211208

212209
// Build the block header
213210
let header: BlockHeader = BlockHeader {
@@ -289,6 +286,7 @@ impl SubmitTask {
289286
&self,
290287
retry_count: usize,
291288
block: &BuiltBlock,
289+
block_env: &BlockEnv,
292290
) -> eyre::Result<ControlFlow> {
293291
info!(retry_count, txns = block.tx_count(), "handling inbound block");
294292
let Ok(sig_request) = self.construct_sig_request(block).await.inspect_err(|e| {
@@ -305,13 +303,14 @@ impl SubmitTask {
305303

306304
let signed = self.quincey.get_signature(&sig_request).await?;
307305

308-
self.submit_transaction(retry_count, &signed, block).await
306+
self.submit_transaction(retry_count, &signed, block, block_env).await
309307
}
310308

311309
/// Handles the retry logic for the inbound block.
312310
async fn retrying_handle_inbound(
313311
&self,
314312
block: &BuiltBlock,
313+
block_env: &BlockEnv,
315314
retry_limit: usize,
316315
) -> eyre::Result<ControlFlow> {
317316
let mut retries = 0;
@@ -325,7 +324,8 @@ impl SubmitTask {
325324
let span = debug_span!("SubmitTask::retrying_handle_inbound", retries);
326325

327326
let inbound_result =
328-
match self.handle_inbound(retries, block).instrument(span.clone()).await {
327+
match self.handle_inbound(retries, block, block_env).instrument(span.clone()).await
328+
{
329329
Ok(control_flow) => control_flow,
330330
Err(err) => {
331331
// Delay until next slot if we get a 403 error
@@ -403,66 +403,86 @@ impl SubmitTask {
403403
/// Task future for the submit task
404404
/// NB: This task assumes that the simulator will only send it blocks for
405405
/// slots that it's assigned.
406-
async fn task_future(self, mut inbound: mpsc::UnboundedReceiver<BuiltBlock>) {
406+
async fn task_future(self, mut inbound: mpsc::UnboundedReceiver<SimResult>) {
407407
// Holds a reference to the last block we attempted to submit
408408
let mut last_block_attempted: u64 = 0;
409409

410410
loop {
411411
// Wait to receive a new block
412-
let Some(block) = inbound.recv().await else {
412+
let Some(result) = inbound.recv().await else {
413413
debug!("upstream task gone");
414414
break;
415415
};
416-
debug!(block_number = block.block_number(), ?block, "submit channel received block");
416+
417+
debug!(block_number = result.block.block_number(), "submit channel received block");
417418

418419
// Only attempt each block number once
419-
if block.block_number() == last_block_attempted {
420+
if result.block.block_number() == last_block_attempted {
420421
debug!("block number is unchanged from last attempt - skipping");
421422
continue;
422423
}
423424

424425
// This means we have encountered a new block, so reset the last block attempted
425-
last_block_attempted = block.block_number();
426+
last_block_attempted = result.block.block_number();
426427
debug!(last_block_attempted, "resetting last block attempted");
427428

428-
if self.retrying_handle_inbound(&block, 3).await.is_err() {
429+
if self.retrying_handle_inbound(&result.block, &result.env, 3).await.is_err() {
429430
debug!("error handling inbound block");
430431
continue;
431432
};
432433
}
433434
}
434435

435436
/// Spawns the in progress block building task
436-
pub fn spawn(self) -> (mpsc::UnboundedSender<BuiltBlock>, JoinHandle<()>) {
437-
let (sender, inbound) = mpsc::unbounded_channel();
437+
pub fn spawn(self) -> (mpsc::UnboundedSender<SimResult>, JoinHandle<()>) {
438+
let (sender, inbound) = mpsc::unbounded_channel::<SimResult>();
438439
let handle = tokio::spawn(self.task_future(inbound));
439440

440441
(sender, handle)
441442
}
442443
}
443444

444-
// Returns gas parameters based on retry counts.
445-
fn calculate_gas_limits(
445+
/// Calculates gas parameters based on the block environment and retry count.
446+
fn calculate_gas(retry_count: usize, block_env: &BlockEnv) -> (u128, u128, u128) {
447+
if let Some(blob_excess) = block_env.blob_excess_gas_and_price {
448+
debug!(?blob_excess, "using blob excess gas and price from block env");
449+
let blob_basefee = blob_excess.blob_gasprice;
450+
451+
let (max_fee_per_gas, max_priority_fee_per_gas, max_fee_per_blob_gas) =
452+
bump_gas_from_retries(retry_count, block_env.basefee, blob_basefee);
453+
454+
(max_fee_per_gas as u128, max_priority_fee_per_gas as u128, max_fee_per_blob_gas as u128)
455+
} else {
456+
warn!("no blob excess gas and price in block env, using defaults");
457+
let (max_fee_per_gas, max_priority_fee_per_gas, max_fee_per_blob_gas) =
458+
bump_gas_from_retries(retry_count, block_env.basefee, 500);
459+
460+
(max_fee_per_gas as u128, max_priority_fee_per_gas as u128, max_fee_per_blob_gas)
461+
}
462+
}
463+
464+
/// Bumps the gas parameters based on the retry count, base fee, and blob base fee.
465+
pub fn bump_gas_from_retries(
446466
retry_count: usize,
447-
base_max_fee_per_gas: u128,
448-
base_max_priority_fee_per_gas: u128,
449-
base_max_fee_per_blob_gas: u128,
450-
) -> (u128, u128, u128) {
451-
let bump_multiplier = 1150u128.pow(retry_count as u32); // 15% bump
452-
let blob_bump_multiplier = 2000u128.pow(retry_count as u32); // 100% bump (double each time) for blob gas
453-
let bump_divisor = 1000u128.pow(retry_count as u32);
454-
455-
let max_fee_per_gas = base_max_fee_per_gas * bump_multiplier / bump_divisor;
456-
let max_priority_fee_per_gas = base_max_priority_fee_per_gas * bump_multiplier / bump_divisor;
457-
let max_fee_per_blob_gas = base_max_fee_per_blob_gas * blob_bump_multiplier / bump_divisor;
467+
basefee: u64,
468+
blob_basefee: u128,
469+
) -> (u64, u64, u128) {
470+
const PRIORITY_FEE_BASE: u64 = 2 * GWEI_TO_WEI;
471+
const BASE_MULTIPLIER: u64 = 2;
472+
const BLOB_MULTIPLIER: u128 = 2;
473+
474+
// Increase priority fee by 20% per retry
475+
let priority_fee =
476+
PRIORITY_FEE_BASE * (12u64.pow(retry_count as u32) / 10u64.pow(retry_count as u32));
477+
478+
// Max fee includes basefee + priority + headroom (double basefee, etc.)
479+
let max_fee_per_gas = basefee * BASE_MULTIPLIER + priority_fee;
480+
let max_fee_per_blob_gas = blob_basefee * BLOB_MULTIPLIER * (retry_count as u128 + 1);
458481

459482
debug!(
460483
retry_count,
461-
max_fee_per_gas,
462-
max_priority_fee_per_gas,
463-
max_fee_per_blob_gas,
464-
"calculated bumped gas parameters"
484+
max_fee_per_gas, priority_fee, max_fee_per_blob_gas, "calculated bumped gas parameters"
465485
);
466486

467-
(max_fee_per_gas, max_priority_fee_per_gas, max_fee_per_blob_gas)
487+
(max_fee_per_gas, priority_fee, max_fee_per_blob_gas)
468488
}

tests/block_builder_test.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -126,5 +126,5 @@ async fn test_spawn() {
126126
// Assert on the block
127127
let block = result.unwrap();
128128
assert!(block.is_some(), "Block channel closed without receiving a block");
129-
assert!(block.unwrap().tx_count() == 2); // TODO: Why is this failing? I'm seeing EVM errors but haven't tracked them down yet.
129+
assert!(block.unwrap().block.tx_count() == 2); // TODO: Why is this failing? I'm seeing EVM errors but haven't tracked them down yet.
130130
}

0 commit comments

Comments
 (0)