Skip to content

Commit b09a52d

Browse files
committed
feat: env task
1 parent b82e6fc commit b09a52d

File tree

4 files changed

+120
-6
lines changed

4 files changed

+120
-6
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,3 +62,4 @@ tokio = { version = "1.36.0", features = ["full", "macros", "rt-multi-thread"] }
6262
async-trait = "0.1.80"
6363
oauth2 = "4.4.2"
6464
chrono = "0.4.41"
65+
tokio-stream = "0.1.17"

src/config.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ use oauth2::url;
2020
use signet_zenith::Zenith;
2121
use std::borrow::Cow;
2222

23+
/// Type alias for the provider used to simulate against rollup state.
24+
pub type RuProvider = RootProvider<Ethereum>;
25+
26+
/// A [`Zenith`] contract instance using [`Provider`] as the provider.
27+
pub type ZenithInstance<P = HostProvider> = Zenith::ZenithInstance<(), P, alloy::network::Ethereum>;
28+
2329
/// Type alias for the provider used to build and submit blocks to the host.
2430
pub type HostProvider = FillProvider<
2531
JoinFill<
@@ -158,12 +164,6 @@ pub struct BuilderConfig {
158164
pub slot_calculator: SlotCalculator,
159165
}
160166

161-
/// Type alias for the provider used to simulate against rollup state.
162-
pub type RuProvider = RootProvider<Ethereum>;
163-
164-
/// A [`Zenith`] contract instance using [`Provider`] as the provider.
165-
pub type ZenithInstance<P = HostProvider> = Zenith::ZenithInstance<(), P, alloy::network::Ethereum>;
166-
167167
impl BuilderConfig {
168168
/// Connect to the Builder signer.
169169
pub async fn connect_builder_signer(&self) -> Result<LocalOrAws, SignerError> {

src/tasks/env.rs

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
use crate::config::{BuilderConfig, RuProvider};
2+
use alloy::{
3+
consensus::Header,
4+
eips::eip1559::BaseFeeParams,
5+
primitives::{B256, U256},
6+
providers::Provider,
7+
};
8+
use init4_bin_base::deps::tracing::{self, Instrument, debug, error, info_span};
9+
use std::time::Duration;
10+
use tokio::sync::watch;
11+
use tokio_stream::StreamExt;
12+
use trevm::revm::{context::BlockEnv, context_interface::block::BlobExcessGasAndPrice};
13+
14+
/// A task that constructs a BlockEnv for the next block in the rollup chain.
15+
#[derive(Debug, Clone)]
16+
pub struct EnvTask {
17+
config: BuilderConfig,
18+
provider: RuProvider,
19+
}
20+
21+
impl EnvTask {
22+
/// Create a new EnvTask with the given config and provider.
23+
pub fn new(config: BuilderConfig, provider: RuProvider) -> Self {
24+
Self { config, provider }
25+
}
26+
27+
/// Construct a BlockEnv by making calls to the provider.
28+
pub fn construct_block_env(&self, previous: &Header) -> BlockEnv {
29+
BlockEnv {
30+
number: previous.number + 1,
31+
beneficiary: self.config.builder_rewards_address,
32+
// NB: EXACTLY the same as the previous block
33+
timestamp: previous.number + self.config.slot_calculator.slot_duration(),
34+
gas_limit: self.config.rollup_block_gas_limit,
35+
basefee: previous
36+
.next_block_base_fee(BaseFeeParams::ethereum())
37+
.expect("signet has no non-1559 headers"),
38+
difficulty: U256::ZERO,
39+
prevrandao: Some(B256::random()),
40+
blob_excess_gas_and_price: Some(BlobExcessGasAndPrice {
41+
excess_blob_gas: 0,
42+
blob_gasprice: 0,
43+
}),
44+
}
45+
}
46+
47+
/// Construct the BlockEnv and send it to the sender.
48+
pub async fn task_fut(self, sender: watch::Sender<BlockEnv>) {
49+
let span = info_span!("EnvTask::task_fut::init");
50+
let mut poller = match self.provider.watch_blocks().instrument(span.clone()).await {
51+
Ok(poller) => poller,
52+
Err(err) => {
53+
let _span = span.enter();
54+
error!(%err, "Failed to watch blocks");
55+
return;
56+
}
57+
};
58+
59+
poller.set_poll_interval(Duration::from_millis(250));
60+
61+
let mut blocks = poller.into_stream();
62+
63+
while let Some(blocks) =
64+
blocks.next().instrument(info_span!("EnvTask::task_fut::stream")).await
65+
{
66+
let Some(block) = blocks.last() else {
67+
debug!("empty filter changes");
68+
continue;
69+
};
70+
let span = info_span!("EnvTask::task_fut::loop", hash = %block, number = tracing::field::Empty);
71+
72+
let previous = match self
73+
.provider
74+
.get_block((*block).into())
75+
.into_future()
76+
.instrument(span.clone())
77+
.await
78+
{
79+
Ok(Some(block)) => block.header.inner,
80+
Ok(None) => {
81+
let _span = span.enter();
82+
debug!("block not found");
83+
continue;
84+
}
85+
Err(err) => {
86+
let _span = span.enter();
87+
error!(%err, "Failed to get latest block");
88+
break;
89+
}
90+
};
91+
span.record("number", previous.number);
92+
93+
let env = self.construct_block_env(&previous);
94+
debug!(?env, "constructed block env");
95+
if let Err(_) = sender.send(env) {
96+
// The receiver has been dropped, so we can stop the task.
97+
break;
98+
}
99+
}
100+
}
101+
102+
/// Spawn the task and return a watch::Receiver for the BlockEnv.
103+
pub fn spawn(self) -> watch::Receiver<BlockEnv> {
104+
let (sender, receiver) = watch::channel(BlockEnv::default());
105+
let fut = self.task_fut(sender);
106+
tokio::spawn(fut);
107+
108+
receiver
109+
}
110+
}

src/tasks/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,6 @@ pub mod submit;
1515

1616
/// Tx polling task
1717
pub mod tx_poller;
18+
19+
/// Constructs the simualtion environment.
20+
pub mod env;

0 commit comments

Comments
 (0)