Sitelet https://github.com/init4tech/builder/pull/100/commits/4fc47f9d618663eb99fa2c996d589280d8b5b7b1
Skip to content
Prev Previous commit
Next Next commit
refactor: attach host block header to SimEnv
  • Loading branch information
dylanlott committed Jun 13, 2025
commit 4fc47f9d618663eb99fa2c996d589280d8b5b7b1
2 changes: 1 addition & 1 deletion bin/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ async fn main() -> eyre::Result<()> {
let constants = SignetSystemConstants::pecorino();

// Spawn the EnvTask
let env_task = config.env_task();
let env_task = config.env_task().await;
let (block_env, env_jh) = env_task.spawn();

// Spawn the cache system
Expand Down
13 changes: 7 additions & 6 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::{
tasks::{
block::cfg::SignetCfgEnv,
cache::{BundlePoller, CacheSystem, CacheTask, TxPoller},
env::EnvTask,
env::{EnvTask, SimEnv},
},
};
use alloy::{
Expand All @@ -29,7 +29,6 @@ use init4_bin_base::{
use signet_zenith::Zenith;
use std::borrow::Cow;
use tokio::sync::watch;
use trevm::revm::context::BlockEnv;

/// Type alias for the provider used to simulate against rollup state.
pub type RuProvider = RootProvider<Ethereum>;
Expand Down Expand Up @@ -246,17 +245,19 @@ impl BuilderConfig {
}

/// Create an [`EnvTask`] using this config.
pub fn env_task(&self) -> EnvTask {
let provider = self.connect_ru_provider();
EnvTask::new(self.clone(), provider)
pub async fn env_task(&self) -> EnvTask {
let ru_provider = self.connect_ru_provider();
let host_provider =
self.connect_host_provider().await.expect("failed to configure host provider");
EnvTask::new(self.clone(), ru_provider, host_provider)
}

/// Spawn a new [`CacheSystem`] using this config. This contains the
/// joinhandles for [`TxPoller`] and [`BundlePoller`] and [`CacheTask`], as
/// well as the [`SimCache`] and the block env watcher.
///
/// [`SimCache`]: signet_sim::SimCache
pub fn spawn_cache_system(&self, block_env: watch::Receiver<Option<BlockEnv>>) -> CacheSystem {
pub fn spawn_cache_system(&self, block_env: watch::Receiver<Option<SimEnv>>) -> CacheSystem {
// Tx Poller pulls transactions from the cache
let tx_poller = TxPoller::new(self);
let (tx_receiver, tx_poller) = tx_poller.spawn();
Expand Down
65 changes: 41 additions & 24 deletions src/tasks/block/sim.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
//! `block.rs` contains the Simulator and everything that wires it into an
//! actor that handles the simulation of a stream of bundles and transactions
//! and turns them into valid Pecorino blocks for network submission.
use crate::config::{BuilderConfig, RuProvider};
use alloy::{eips::BlockId, network::Ethereum, providers::Provider};
use crate::{
config::{BuilderConfig, RuProvider},
tasks::env::SimEnv,
};
use alloy::{
eips::BlockId,
network::Ethereum,
providers::Provider,
};
use init4_bin_base::{
deps::tracing::{debug, error},
utils::calc::SlotCalculator,
};
use signet_sim::{BlockBuild, BuiltBlock, SimCache};
use signet_types::constants::SignetSystemConstants;
use tracing::info;
use std::time::{Duration, Instant};
use tokio::{
sync::{
Expand All @@ -35,7 +43,7 @@ pub struct Simulator {
/// A provider that cannot sign transactions, used for interacting with the rollup.
pub ru_provider: RuProvider,
/// The block configuration environment on which to simulate
pub block_env: watch::Receiver<Option<BlockEnv>>,
pub sim_env: watch::Receiver<Option<SimEnv>>,
}

/// SimResult bundles a BuiltBlock to the BlockEnv it was simulated against.
Expand All @@ -44,7 +52,7 @@ pub struct SimResult {
/// The block built with the successfully simulated transactions
pub block: BuiltBlock,
/// The block environment the transactions were simulated against.
pub env: BlockEnv,
pub env: SimEnv,
}

impl Simulator {
Expand All @@ -62,9 +70,9 @@ impl Simulator {
pub fn new(
config: &BuilderConfig,
ru_provider: RuProvider,
block_env: watch::Receiver<Option<BlockEnv>>,
sim_env: watch::Receiver<Option<SimEnv>>,
) -> Self {
Self { config: config.clone(), ru_provider, block_env }
Self { config: config.clone(), ru_provider, sim_env }
}

/// Get the slot calculator.
Expand All @@ -74,6 +82,10 @@ impl Simulator {

/// Handles building a single block.
///
/// Builds a block in the block environment with items from the simulation cache
/// against the database state. When the `finish_by` deadline is reached, it
/// stops simulating and returns the block.
///
/// # Arguments
///
/// - `constants`: The system constants for the rollup.
Expand All @@ -93,7 +105,6 @@ impl Simulator {
) -> eyre::Result<BuiltBlock> {
debug!(
block_number = block_env.number,
?finish_by,
tx_count = sim_items.len(),
"starting block build",
);
Expand All @@ -114,15 +125,15 @@ impl Simulator {
let built_block = block_build.build().await;
debug!(
tx_count = built_block.tx_count(),
block_number = ?built_block.block_number(),
block_number = built_block.block_number(),
"block simulation completed",
);

Ok(built_block)
}

/// Spawns the simulator task, which handles the setup and sets the deadline
/// for the each round of simulation.
/// Spawns the simulator task, which ticks along the simulation loop
/// as it receives block environments.
///
/// # Arguments
///
Expand All @@ -144,14 +155,16 @@ impl Simulator {
tokio::spawn(async move { self.run_simulator(constants, cache, submit_sender).await })
}

/// Continuously runs the block simulation and submission loop.
/// This function runs indefinitely, waiting for the block environment to be set and checking
/// if the current slot is valid before building a block and sending it along for to the submit channel.
///
/// This function clones the simulation cache, calculates a deadline for block building,
/// attempts to build a block using the latest cache and constants, and submits the built
/// block through the provided channel. If an error occurs during block building or submission,
/// it logs the error and continues the loop.
///
/// This function runs indefinitely and never returns.
/// If it is authorized for the current slot, then the simulator task
/// - clones the simulation cache,
/// - calculates a deadline for block building,
/// - attempts to build a block using the latest cache and constants,
/// - then submits the built block through the provided channel.
///
/// If an error occurs during block building or submission, it logs the error and continues the loop.
///
/// # Arguments
///
Expand All @@ -166,19 +179,23 @@ impl Simulator {
) {
loop {
// Wait for the block environment to be set
if self.block_env.changed().await.is_err() {
error!("block_env channel closed");
if self.sim_env.changed().await.is_err() {
error!("block_env channel closed - shutting down simulator task");
return;
}
let Some(sim_env) = self.sim_env.borrow_and_update().clone() else { return };
info!(block_number = sim_env.signet.number, "new block environment received");

let Some(block_env) = self.block_env.borrow_and_update().clone() else { return };

// Calculate the deadline for this block simulation.
// NB: This must happen _after_ taking a reference to the sim cache,
// waiting for a new block, and checking current slot authorization.
let finish_by = self.calculate_deadline();
let sim_cache = cache.clone();
match self.handle_build(constants, sim_cache, finish_by, block_env.clone()).await {
match self.handle_build(constants, sim_cache, finish_by, sim_env.signet.clone()).await
{
Ok(block) => {
debug!(block = ?block.block_number(), tx_count = block.transactions().len(), "built block");
let _ = submit_sender.send(SimResult { block, env: block_env });
debug!(block = ?block.block_number(), tx_count = block.transactions().len(), "built simulated block");
let _ = submit_sender.send(SimResult { block, env: sim_env });
}
Err(e) => {
error!(err = %e, "failed to build block");
Expand Down
14 changes: 7 additions & 7 deletions src/tasks/cache/task.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ use tokio::{
sync::{mpsc, watch},
task::JoinHandle,
};
use trevm::revm::context::BlockEnv;

Comment thread
dylanlott marked this conversation as resolved.
use crate::tasks::env::SimEnv;

/// Cache task for the block builder.
///
Expand All @@ -16,8 +17,7 @@ use trevm::revm::context::BlockEnv;
#[derive(Debug)]
pub struct CacheTask {
/// The channel to receive the block environment.
env: watch::Receiver<Option<BlockEnv>>,

env: watch::Receiver<Option<SimEnv>>,
/// The channel to receive the transaction bundles.
bundles: mpsc::UnboundedReceiver<TxCacheBundle>,
/// The channel to receive the transactions.
Expand All @@ -27,7 +27,7 @@ pub struct CacheTask {
impl CacheTask {
/// Create a new cache task with the given cache and channels.
pub const fn new(
env: watch::Receiver<Option<BlockEnv>>,
env: watch::Receiver<Option<SimEnv>>,
bundles: mpsc::UnboundedReceiver<TxCacheBundle>,
txns: mpsc::UnboundedReceiver<TxEnvelope>,
) -> Self {
Expand All @@ -45,10 +45,10 @@ impl CacheTask {
break;
}
if let Some(env) = self.env.borrow_and_update().as_ref() {
basefee = env.basefee;
info!(basefee, number = env.number, timestamp = env.timestamp, "block env changed, clearing cache");
basefee = env.signet.basefee;
info!(basefee, env.signet.number, env.signet.timestamp, "rollup block env changed, clearing cache");
cache.clean(
env.number, env.timestamp
env.signet.number, env.signet.timestamp
);
}
}
Expand Down
Loading