8000 feat: passes sim result to the submit tasks (#100) · init4tech/builder@afa4447 · GitHub
[go: up one dir, main page]

Skip to content

Commit afa4447

Browse files
authored
feat: passes sim result to the submit tasks (#100)
* 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 * better logging * cleanup * fmt * remove verbose logging * clippy * fix: don't submit empty blocks * bump trevm to include bugfix * refactor: attach host block header to SimEnv * clippy + fmt * refactor: fetch header in submit task instead of passing through from env task * fmt * nits + cleanup * fmt + clippy
1 parent a3a7796 commit afa4447

File tree

10 files changed

+278
-216
lines changed

10 files changed

+278
-216
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ signet-tx-cache = { git = "https://github.com/init4tech/signet-sdk", branch = "m
3333
signet-types = { git = "https://github.com/init4tech/signet-sdk", branch = "main" }
3434
signet-zenith = { git = "https://github.com/init4tech/signet-sdk", branch = "main" }
3535

36-
trevm = { version = "0.23.4", features = ["concurrent-db", "test-utils"] }
36+
trevm = { version = "0.23.6", features = ["concurrent-db", "test-utils"] }
3737

3838
alloy = { version = "1.0.5", features = [
3939
"full",

bin/builder.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,17 @@ async fn main() -> eyre::Result<()> {
3535
let zenith = config.connect_zenith(host_provider.clone());
3636

3737
// Set up the metrics task
38-
let metrics = MetricsTask { host_provider };
38+
let metrics = MetricsTask { host_provider: host_provider.clone() };
3939
let (tx_channel, metrics_jh) = metrics.spawn();
4040

4141
// Make a Tx submission task
42-
let submit =
43-
SubmitTask { zenith, quincey, config: config.clone(), outbound_tx_channel: tx_channel };
42+
let submit = SubmitTask {
43+
zenith,
44+
quincey,
45+
config: config.clone(),
46+
outbound_tx_channel: tx_channel,
47+
host_provider: host_provider.clone(),
48+
};
4449

4550
// Set up tx submission
4651
let (submit_channel, submit_jh) = submit.spawn();

bin/submit_transaction.rs

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
//! A simple transaction submitter that sends a transaction to a recipient address
2+
//! on a regular interval for the purposes of roughly testing rollup mining.
13
use alloy::{
24
network::{EthereumWallet, TransactionBuilder},
35
primitives::{Address, U256},
@@ -67,18 +69,29 @@ async fn main() {
6769
}
6870
}
6971

72+
/// Sends a transaction to the specified recipient address
7073
async fn send_transaction(provider: &HostProvider, recipient_address: Address) {
7174
// construct simple transaction to send ETH to a recipient
75+
let nonce = match provider.get_transaction_count(provider.default_signer_address()).await {
76+
Ok(count) => count,
77+< F438 /span>
Err(e) => {
78+
error!(error = ?e, "failed to get transaction count");
79+
return;
80+
}
81+
};
82+
7283
let tx = TransactionRequest::default()
7384
.with_from(provider.default_signer_address())
7485
.with_to(recipient_address)
7586
.with_value(U256::from(1))
87+
.with_nonce(nonce)
7688
.with_gas_limit(30_000);
7789

7890
// start timer to measure how long it takes to mine the transaction
7991
let dispatch_start_time: Instant = Instant::now();
8092

8193
// dispatch the transaction
94+
debug!(?tx.nonce, "sending transaction with nonce");
8295
let result = provider.send_transaction(tx).await.unwrap();
8396

8497
// wait for the transaction to mine
@@ -95,10 +108,13 @@ async fn send_transaction(provider: &HostProvider, recipient_address: Address) {
95108
}
96109
};
97110

98-
let hash = receipt.transaction_hash.to_string();
111+
record_metrics(dispatch_start_time, receipt);
112+
}
99113

100-
// record metrics for how long it took to mine the transaction
114+
/// Record metrics for how long it took to mine the transaction
115+
fn record_metrics(dispatch_start_time: Instant, receipt: alloy::rpc::types::TransactionReceipt) {
101116
let mine_time = dispatch_start_time.elapsed().as_secs();
117+
let hash = receipt.transaction_hash.to_string();
102118
debug!(success = receipt.status(), mine_time, hash, "transaction mined");
103119
histogram!("txn_submitter.tx_mine_time").record(mine_time as f64);
104120
}

src/config.rs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::{
33
tasks::{
44
block::cfg::SignetCfgEnv,
55
cache::{BundlePoller, CacheSystem, CacheTask, TxPoller},
6-
env::EnvTask,
6+
env::{EnvTask, SimEnv},
77
},
88
};
99
use alloy::{
@@ -29,7 +29,6 @@ use init4_bin_base::{
2929
use signet_zenith::Zenith;
3030
use std::borrow::Cow;
3131
use tokio::sync::watch;
32-
use trevm::revm::context::BlockEnv;
3332

3433
/// Type alias for the provider used to simulate against rollup state.
3534
pub type RuProvider = RootProvider<Ethereum>;
@@ -247,16 +246,16 @@ impl BuilderConfig {
247246

248247
/// Create an [`EnvTask`] using this config.
249248
pub fn env_task(&self) -> EnvTask {
250-
let provider = self.connect_ru_provider();
251-
EnvTask::new(self.clone(), provider)
249+
let ru_provider = self.connect_ru_provider();
250+
EnvTask::new(self.clone(), ru_provider)
252251
}
253252

254253
/// Spawn a new [`CacheSystem`] using this config. This contains the
255254
/// joinhandles for [`TxPoller`] and [`BundlePoller`] and [`CacheTask`], as
256255
/// well as the [`SimCache`] and the block env watcher.
257256
///
258257
/// [`SimCache`]: signet_sim::SimCache
259-
pub fn spawn_cache_system(&self, block_env: watch::Receiver<Option<BlockEnv>>) -> CacheSystem {
258+
pub fn spawn_cache_system(&self, block_env: watch::Receiver<Option<SimEnv>>) -> CacheSystem {
260259
// Tx Poller pulls transactions from the cache
261260
let tx_poller = TxPoller::new(self);
262261
let (tx_receiver, tx_poller) = tx_poller.spawn();

src/tasks/block/sim.rs

Lines changed: 62 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
//! `block.rs` contains the Simulator and everything that wires it into an
22
//! actor that handles the simulation of a stream of bundles and transactions
33
//! and turns them into valid Pecorino blocks for network submission.
4-
use crate::config::{BuilderConfig, RuProvider};
4+
use crate::{
5+
config::{BuilderConfig, RuProvider},
6+
tasks::env::SimEnv,
7+
};
58
use alloy::{eips::BlockId, network::Ethereum, providers::Provider};
69
use init4_bin_base::{
710
deps::tracing::{debug, error},
@@ -17,6 +20,7 @@ use tokio::{
1720
},
1821
task::JoinHandle,
1922
};
23+
use tracing::info;
2024
use trevm::revm::{
2125
context::BlockEnv,
2226
database::{AlloyDB, WrapDatabaseAsync},
@@ -34,9 +38,17 @@ pub struct Simulator {
3438
pub config: BuilderConfig,
3539
/// A provider that cannot sign transactions, used for interacting with the rollup.
3640
pub ru_provider: RuProvider,
37-
3841
/// The block configuration environment on which to simulate
39-
pub block_env: watch::Receiver<Option<BlockEnv>>,
42+
pub sim_env: watch::Receiver<Option<SimEnv>>,
43+
}
44+
45+
/// SimResult bundles a BuiltBlock to the BlockEnv it was simulated against.
46+
#[derive(Debug, Clone)]
47+
pub struct SimResult {
48+
/// The block built with the successfully simulated transactions
49+
pub block: BuiltBlock,
50+
/// The block environment the transactions were simulated against.
51+
pub env: SimEnv,
4052
}
4153

4254
impl Simulator {
@@ -46,16 +58,17 @@ impl Simulator {
4658
///
4759
/// - `config`: The configuration for the builder.
4860
/// - `ru_provider`: A provider for interacting with the rollup.
61+
/// - `block_env`: A receiver for the block environment to simulate against.
4962
///
5063
/// # Returns
5164
///
5265
/// A new `Simulator` instance.
5366
pub fn new(
5467
config: &BuilderConfig,
5568
ru_provider: RuProvider,
56-
block_env: wa F440 tch::Receiver<Option<BlockEnv>>,
69+
sim_env: watch::Receiver<Option<SimEnv>>,
5770
) -> Self {
58-
Self { config: config.clone(), ru_provider, block_env }
71+
Self { config: config.clone(), ru_provider, sim_env }
5972
}
6073

6174
/// Get the slot calculator.
@@ -65,11 +78,16 @@ impl Simulator {
6578

6679
/// Handles building a single block.
6780
///
81+
/// Builds a block in the block environment with items from the simulation cache
82+
/// against the database state. When the `finish_by` deadline is reached, it
83+
/// stops simulating and returns the block.
84+
///
6885
/// # Arguments
6986
///
7087
/// - `constants`: The system constants for the rollup.
7188
/// - `sim_items`: The simulation cache containing transactions and bundles.
7289
/// - `finish_by`: The deadline by which the block must be built.
90+
/// - `block_env`: The block environment to simulate against.
7391
///
7492
/// # Returns
7593
///
@@ -79,28 +97,35 @@ impl Simulator {
7997
constants: SignetSystemConstants,
8098
sim_items: SimCache,
8199
finish_by: Instant,
82-
block: BlockEnv,
100+
block_env: BlockEnv,
83101
) -> eyre::Result<BuiltBlock> {
102+
debug!(block_number = block_env.number, tx_count = sim_items.len(), "starting block build",);
103+
84104
let db = self.create_db().await.unwrap();
105+
85106
let block_build: BlockBuild<_, NoOpInspector> = BlockBuild::new(
86107
db,
87108
constants,
88109
self.config.cfg_env(),
89-
block,
110+
block_env,
90111
finish_by,
91112
self.config.concurrency_limit,
92113
sim_items,
93114
self.config.rollup_block_gas_limit,
94115
);
95116

96117
let built_block = block_build.build().await;
97-
debug!(block_number = ?built_block.block_number(), "finished building block");
118+
debug!(
119+
tx_count = built_block.tx_count(),
120+
block_number = built_block.block_number(),
121+
"block simulation completed",
122+
);
98123

99124
Ok(built_block)
100125
}
101126

102-
/// Spawns the simulator task, which handles the setup and sets the deadline
103-
/// for the each round of simulation.
127+
/// Spawns the simulator task, which ticks along the simulation loop
128+
/// as it receives block environments.
104129
///
105130
/// # Arguments
106131
///
@@ -115,21 +140,23 @@ impl Simulator {
115140
self,
116141
constants: SignetSystemConstants,
117142
cache: SimCache,
118-
submit_sender: mpsc::UnboundedSender<BuiltBlock>,
143+
submit_sender: mpsc::UnboundedSender<SimResult>,
119144
) -> JoinHandle<()> {
120145
debug!("starting simulator task");
121146

122147
tokio::spawn(async move { self.run_simulator(constants, cache, submit_sender).await })
123148
}
124149

125-
/// Continuously runs the block simulation and submission loop.
150+
/// This function runs indefinitely, waiting for the block environment to be set and checking
151+
/// if the current slot is valid before building a block and sending it along for to the submit channel.
126152
///
127-
/// This function clones the simulation cache, calculates a deadline for block building,
128-
/// attempts to build a block using the latest cache and constants, and submits the built
129-
/// block through the provided channel. If an error occurs during block building or submission,
130-
/// it logs the error and continues the loop.
153+
/// If it is authorized for the current slot, then the simulator task
154+
/// - clones the simulation cache,
155+
/// - calculates a deadline for block building,
156+
/// - attempts to build a block using the latest cache and constants,
157+
/// - then submits the built block through the provided channel.
131158
///
132-
/// This function runs indefinitely and never returns.
159+
/// If an error occurs during block building or submission, it logs the error and continues the loop.
133160
///
134161
/// # Arguments
135162
///
@@ -140,26 +167,29 @@ impl Simulator {
140167
mut self,
141168
constants: SignetSystemConstants,
142169
cache: SimCache,
143-
submit_sender: mpsc::UnboundedSender<BuiltBlock>,
170+
submit_sender: mpsc::UnboundedSender<SimResult>,
144171
) {
145172
loop {
146-
let sim_cache = cache.clone();
147-
let finish_by = self.calculate_deadline();
148-
149173
// Wait for the block environment to be set
150-
if self.block_env.changed().await.is_err() {
151-
error!("block_env channel closed");
174+
if self.sim_env.changed().await.is_err() {
175+
error!("block_env channel closed - shutting down simulator task");
152176
return;
153177
}
178+
let Some(sim_env) = self.sim_env.borrow_and_update().clone() else { return };
179+
info!(sim_env.block_env.number, "new block environment received");
154180

155-
// If no env, skip this run
156-
let Some(block_env) = self.block_env.borrow_and_update().clone() else { return };
157-
debug!(block_env = ?block_env, "building on block env");
158-
159-
match self.handle_build(constants, sim_cache, finish_by, block_env).await {
181+
// Calculate the deadline for this block simulation.
182+
// NB: This must happen _after_ taking a reference to the sim cache,
183+
// waiting for a new block, and checking current slot authorization.
184+
let finish_by = self.calculate_deadline();
185+
let sim_cache = cache.clone();
186+
match self
187+
.handle_build(constants, sim_cache, finish_by, sim_env.block_env.clone())
188+
.await
189+
{
160190
Ok(block) => {
161-
debug!(block = ?block, "built block");
162-
let _ = submit_sender.send(block);
191+
debug!(block = ?block.block_number(), tx_count = block.transactions().len(), "built simulated block");
192+
let _ = submit_sender.send(SimResult { block, env: sim_env });
163193
}
164194
Err(e) => {
165195
error!(err = %e, "failed to build block");
@@ -184,11 +214,10 @@ impl Simulator {
184214
let remaining = self.slot_calculator().slot_duration() - timepoint;
185215

186216
// We add a 1500 ms buffer to account for sequencer stopping signing.
187-
188-
let candidate =
217+
let deadline =
189218
Instant::now() + Duration::from_secs(remaining) - Duration::from_millis(1500);
190219

191-
candidate.max(Instant::now())
220+
deadline.max(Instant::now())
192221
}
193222

194223
/// Creates an `AlloyDB` instance from the rollup provider.

src/tasks/cache/task.rs

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::tasks::env::SimEnv;
12
use alloy::consensus::TxEnvelope;
23
use init4_bin_base::deps::tracing::{debug, info};
34
use signet_sim::SimCache;
@@ -6,7 +7,6 @@ use tokio::{
67
sync::{mpsc, watch},
78
task::JoinHandle,
89
};
9-
use trevm::revm::context::BlockEnv;
1010

1111
/// Cache task for the block builder.
1212
///
@@ -16,8 +16,7 @@ use trevm::revm::context::BlockEnv;
1616
#[derive(Debug)]
1717
pub struct CacheTask {
1818
/// The channel to receive the block environment.
19-
env: watch::Receiver<Option<BlockEnv>>,
20-
19+
env: watch::Receiver<Option<SimEnv>>,
2120
/// The channel to receive the transaction bundles.
2221
bundles: mpsc::UnboundedReceiver<TxCacheBundle>,
2322
/// The channel to receive the transactions.
@@ -27,7 +26,7 @@ pub struct CacheTask {
2726
impl CacheTask {
2827
/// Create a new cache task with the given cache and channels.
2928
pub const fn new(
30-
env: watch::Receiver<Option<BlockEnv>>,
29+
env: watch::Receiver<Option<SimEnv>>,
3130
bundles: mpsc::UnboundedReceiver<TxCacheBundle>,
3231
txns: mpsc::UnboundedReceiver<TxEnvelope>,
3332
) -> Self {
@@ -45,10 +44,10 @@ impl CacheTask {
4544
break;
4645
}
4746
if let Some(env) = self.env.borrow_and_update().as_ref() {
48-
basefee = env.basefee;
49-
info!(basefee, number = env.number, timestamp = env.timestamp, "block env changed, clearing cache");
47+
basefee = env.block_env.basefee;
48+
info!(basefee, env.block_env.number, env.block_env.timestamp, "rollup block env changed, clearing cache");
5049
cache.clean(
51-
env.number, env.timestamp
50+
env.block_env.number, env.block_env.timestamp
5251
);
5352
}
5453
}

0 commit comments

Comments
 (0)
0