Skip to content

Commit f905e1b

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 2c09604 commit f905e1b

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
///
@@ -115,7 +124,7 @@ impl Simulator {
115124
self,
116125
constants: SignetSystemConstants,
117126
cache: SimCache,
118-
submit_sender: mpsc::UnboundedSender<BuiltBlock>,
127+
submit_sender: mpsc::UnboundedSender<SimResult>,
119128
) -> JoinHandle<()> {
120129
debug!("starting simulator task");
121130

@@ -140,7 +149,7 @@ impl Simulator {
140149
mut self,
141150
constants: SignetSystemConstants,
142151
cache: SimCache,
143-
submit_sender: mpsc::UnboundedSender<BuiltBlock>,
152+
submit_sender: mpsc::UnboundedSender<SimResult>,
144153
) {
145154
loop {
146155
let sim_cache = cache.clone();
@@ -156,10 +165,10 @@ impl Simulator {
156165
let Some(block_env) = self.block_env.borrow_and_update().clone() else { return };
157166
debug!(block_env = ?block_env, "building on block env");
158167

159-
match self.handle_build(constants, sim_cache, finish_by, block_env).await {
168+
match self.handle_build(constants, sim_cache, finish_by, block_env.clone()).await {
160169
Ok(block) => {
161-
debug!(block = ?block, "built block");
162-
let _ = submit_sender.send(block);
170+
debug!(block = ?block.block_number(), "built block");
171+
let _ = submit_sender.send(SimResult { block, env: block_env });
163172
}
164173
Err(e) => {
165174
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) => {
@@ -222,7 +221,7 @@ impl SubmitTask {
222221
})
223222
}
224223

225-
/// Builds blob transaction and encodes the sidecar for it from the provided header and signature values
224+
/// Encodes the sidecar and then builds the 4844 blob transaction from the provided header and signature values.
226225
fn build_blob_tx(
227226
&self,
228227
fills: Vec<FillPermit2>,
@@ -245,8 +244,9 @@ impl SubmitTask {
245244
retry_count: usize,
246245
resp: &SignResponse,
247246
block: &BuiltBlock,
247+
block_env: &BlockEnv,
248248
) -> eyre::Result<ControlFlow> {
249-
let tx = self.prepare_tx(retry_count, resp, block).await?;
249+
let tx = self.prepare_tx(retry_count, resp, block, block_env).await?;
250250

251251
self.send_transaction(resp, tx).await
252252
}
@@ -258,9 +258,11 @@ impl SubmitTask {
258258
retry_count: usize,
259259
resp: &SignResponse,
260260
block: &BuiltBlock,
261+
block_env: &BlockEnv,
261262
) -> Result<TransactionRequest, eyre::Error> {
262263
// Create the transaction request with the signature values
263-
let tx: TransactionRequest = self.new_tx_request(retry_count, resp, block).await?;
264+
let tx: TransactionRequest =
265+
self.new_tx_request(retry_count, resp, block, block_env).await?;
264266

265267
// Simulate the transaction with a call to the host provider and report any errors
266268
if let Err(err) = self.sim_with_call(&tx).await {
@@ -288,6 +290,7 @@ impl SubmitTask {
288290
retry_count: usize,
289291
resp: &SignResponse,
290292
block: &BuiltBlock,
293+
block_env: &BlockEnv,
291294
) -> Result<TransactionRequest, eyre::Error> {
292295
// manually retrieve nonce
293296
let nonce =
@@ -297,14 +300,8 @@ impl SubmitTask {
297300
// Extract the signature components from the response
298301
let (v, r, s) = extract_signature_components(&resp.sig);
299302

300-
// Calculate gas limits based on retry attempts
301303
let (max_fee_per_gas, max_priority_fee_per_gas, max_fee_per_blob_gas) =
302-
calculate_gas_limits(
303-
retry_count,
304-
BASE_FEE_PER_GAS,
305-
BASE_MAX_PRIORITY_FEE_PER_GAS,
306-
BASE_MAX_FEE_PER_BLOB_GAS,
307-
);
304+
calculate_gas(retry_count, block_env);
308305

309306
// Build the block header
310307
let header: BlockHeader = BlockHeader {
@@ -386,6 +383,7 @@ impl SubmitTask {
386383
&self,
387384
retry_count: usize,
388385
block: &BuiltBlock,
386+
block_env: &BlockEnv,
389387
) -> eyre::Result<ControlFlow> {
390388
info!(retry_count, txns = block.tx_count(), "handling inbound block");
391389
let Ok(sig_request) = self.construct_sig_request(block).await.inspect_err(|e| {
@@ -402,13 +400,14 @@ impl SubmitTask {
402400

403401
let signed = self.quincey.get_signature(&sig_request).await?;
404402

405-
self.submit_transaction(retry_count, &signed, block).await
403+
self.submit_transaction(retry_count, &signed, block, block_env).await
406404
}
407405

408406
/// Handles the retry logic for the inbound block.
409407
async fn retrying_handle_inbound(
410408
&self,
411409
block: &BuiltBlock,
410+
block_env: &BlockEnv,
412411
retry_limit: usize,
413412
) -> eyre::Result<ControlFlow> {
414413
let mut retries = 0;
@@ -422,7 +421,8 @@ impl SubmitTask {
422421
let span = debug_span!("SubmitTask::retrying_handle_inbound", retries);
423422

424423
let inbound_result =
425-
match self.handle_inbound(retries, block).instrument(span.clone()).await {
424+
match self.handle_inbound(retries, block, block_env).instrument(span.clone()).await
425+
{
426426
Ok(control_flow) => control_flow,
427427
Err(err) => {
428428
// Delay until next slot if we get a 403 error
@@ -500,66 +500,86 @@ impl SubmitTask {
500500
/// Task future for the submit task
501501
/// NB: This task assumes that the simulator will only send it blocks for
502502
/// slots that it's assigned.
503-
async fn task_future(self, mut inbound: mpsc::UnboundedReceiver<BuiltBlock>) {
503+
async fn task_future(self, mut inbound: mpsc::UnboundedReceiver<SimResult>) {
504504
// Holds a reference to the last block we attempted to submit
505505
let mut last_block_attempted: u64 = 0;
506506

507507
loop {
508508
// Wait to receive a new block
509-
let Some(block) = inbound.recv().await else {
509+
let Some(result) = inbound.recv().await else {
510510
debug!("upstream task gone");
511511
break;
512512
};
513-
debug!(block_number = block.block_number(), ?block, "submit channel received block");
513+
514+
debug!(block_number = result.block.block_number(), "submit channel received block");
514515

515516
// Only attempt each block number once
516-
if block.block_number() == last_block_attempted {
517+
if result.block.block_number() == last_block_attempted {
517518
debug!("block number is unchanged from last attempt - skipping");
518519
continue;
519520
}
520521

521522
// This means we have encountered a new block, so reset the last block attempted
522-
last_block_attempted = block.block_number();
523+
last_block_attempted = result.block.block_number();
523524
debug!(last_block_attempted, "resetting last block attempted");
524525

525-
if self.retrying_handle_inbound(&block, 3).await.is_err() {
526+
if self.retrying_handle_inbound(&result.block, &result.env, 3).await.is_err() {
526527
debug!("error handling inbound block");
527528
continue;
528529
};
529530
}
530531
}
531532

532533
/// Spawns the in progress block building task
533-
pub fn spawn(self) -> (mpsc::UnboundedSender<BuiltBlock>, JoinHandle<()>) {
534-
let (sender, inbound) = mpsc::unbounded_channel();
534+
pub fn spawn(self) -> (mpsc::UnboundedSender<SimResult>, JoinHandle<()>) {
535+
let (sender, inbound) = mpsc::unbounded_channel::<SimResult>();
535536
let handle = tokio::spawn(self.task_future(inbound));
536537

537538
(sender, handle)
538539
}
539540
}
540541

541-
// Returns gas parameters based on retry counts.
542-
fn calculate_gas_limits(
542+
/// Calculates gas parameters based on the block environment and retry count.
543+
fn calculate_gas(retry_count: usize, block_env: &BlockEnv) -> (u128, u128, u128) {
544+
if let Some(blob_excess) = block_env.blob_excess_gas_and_price {
545+
debug!(?blob_excess, "using blob excess gas and price from block env");
546+
let blob_basefee = blob_excess.blob_gasprice;
547+
548+
let (max_fee_per_gas, max_priority_fee_per_gas, max_fee_per_blob_gas) =
549+
bump_gas_from_retries(retry_count, block_env.basefee, blob_basefee);
550+
551+
(max_fee_per_gas as u128, max_priority_fee_per_gas as u128, max_fee_per_blob_gas as u128)
552+
} else {
553+
warn!("no blob excess gas and price in block env, using defaults");
554+
let (max_fee_per_gas, max_priority_fee_per_gas, max_fee_per_blob_gas) =
555+
bump_gas_from_retries(retry_count, block_env.basefee, 500);
556+
557+
(max_fee_per_gas as u128, max_priority_fee_per_gas as u128, max_fee_per_blob_gas)
558+
}
559+
}
560+
561+
/// Bumps the gas parameters based on the retry count, base fee, and blob base fee.
562+
pub fn bump_gas_from_retries(
543563
retry_count: usize,
544-
base_max_fee_per_gas: u128,
545-
base_max_priority_fee_per_gas: u128,
546-
base_max_fee_per_blob_gas: u128,
547-
) -> (u128, u128, u128) {
548-
let bump_multiplier = 1150u128.pow(retry_count as u32); // 15% bump
549-
let blob_bump_multiplier = 2000u128.pow(retry_count as u32); // 100% bump (double each time) for blob gas
550-
let bump_divisor = 1000u128.pow(retry_count as u32);
551-
552-
let max_fee_per_gas = base_max_fee_per_gas * bump_multiplier / bump_divisor;
553-
let max_priority_fee_per_gas = base_max_priority_fee_per_gas * bump_multiplier / bump_divisor;
554-
let max_fee_per_blob_gas = base_max_fee_per_blob_gas * blob_bump_multiplier / bump_divisor;
564+
basefee: u64,
565+
blob_basefee: u128,
566+
) -> (u64, u64, u128) {
567+
const PRIORITY_FEE_BASE: u64 = 2 * GWEI_TO_WEI;
568+
const BASE_MULTIPLIER: u64 = 2;
569+
const BLOB_MULTIPLIER: u128 = 2;
570+
571+
// Increase priority fee by 20% per retry
572+
let priority_fee =
573+
PRIORITY_FEE_BASE * (12u64.pow(retry_count as u32) / 10u64.pow(retry_count as u32));
574+
575+
// Max fee includes basefee + priority + headroom (double basefee, etc.)
576+
let max_fee_per_gas = basefee * BASE_MULTIPLIER + priority_fee;
577+
let max_fee_per_blob_gas = blob_basefee * BLOB_MULTIPLIER * (retry_count as u128 + 1);
555578

556579
debug!(
557580
retry_count,
558-
max_fee_per_gas,
559-
max_priority_fee_per_gas,
560-
max_fee_per_blob_gas,
561-
"calculated bumped gas parameters"
581+
max_fee_per_gas, priority_fee, max_fee_per_blob_gas, "calculated bumped gas parameters"
562582
);
563583

564-
(max_fee_per_gas, max_priority_fee_per_gas, max_fee_per_blob_gas)
584+
(max_fee_per_gas, priority_fee, max_fee_per_blob_gas)
565585
}

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)