Skip to content

[feat] adds simulation to block loop #71

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 44 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
ef6b734
updates the tx-poller to stream transactions
dylanlott Mar 7, 2025
1ad6e14
refactors
dylanlott Mar 17, 2025
b5a5cf4
Fix: various updates to the tx poller (#67)
prestwich Apr 8, 2025
3117b85
updates bundler to streaming actor pattern
dylanlott Mar 17, 2025
96dce04
refactors
dylanlott Mar 17, 2025
5cfbdc9
fmt
dylanlott Mar 19, 2025
c4522ee
fix: remove eq/partial eq
prestwich Apr 7, 2025
01a11e6
fix: various improvements to bundler tasks (#68)
prestwich Apr 8, 2025
6374238
chore: update to [email protected]
dylanlott Mar 17, 2025
b1324b0
refactors to account for init4 bin base in builder craate
dylanlott Mar 17, 2025
976dd03
use signet-sdk
dylanlott Mar 27, 2025
b229996
fix: update bin-base import
dylanlott Mar 27, 2025
bafe07f
nits: doc updates
prestwich Apr 7, 2025
e0c79f7
lint: fmt
prestwich Apr 7, 2025
785172b
feat: implements simulation for block building
dylanlott Apr 15, 2025
ff5cb31
lint: fmt
dylanlott Apr 15, 2025
a142314
cleanup
dylanlott Apr 15, 2025
9d812ce
WIP: adding a block builder loop test
dylanlott Apr 17, 2025
bf75913
tests are passing now
dylanlott Apr 18, 2025
55b2193
adds slot calculator to block builder
dylanlott Apr 19, 2025
fd4bdcd
refactors test utils across tasks
dylanlott Apr 19, 2025
dd4b377
fmt
dylanlott Apr 19, 2025
1ee991f
fixup clippy and fmt
dylanlott Apr 19, 2025
50162b7
update cargo paths to sdk
dylanlott Apr 19, 2025
14a0a62
mark block builder test as integration test
dylanlott Apr 23, 2025
1125f4d
cleanup
dylanlott Apr 23, 2025
acb3d42
clippy + fmt
dylanlott Apr 23, 2025
4639365
cleanup
dylanlott Apr 23, 2025
9e1bc74
adds basefee checker to sim cache handling
dylanlott Apr 24, 2025
06da0b5
fix pointer changes
dylanlott Apr 24, 2025
70fdac1
ignore test spawn
dylanlott Apr 24, 2025
6b59e39
update signet-sim deps to main branch
dylanlott Apr 28, 2025
09fc552
try_join the setup of host, rollup, and sequencer services
dylanlott Apr 28, 2025
830f297
removes unused error from ConfigError
dylanlott Apr 28, 2025
1ad4974
use AtomicU64 instead of RwLock in cache task handler
dylanlott Apr 28, 2025
b4c64da
cleanup & refactors
dylanlott Apr 28, 2025
8300f03
removes unnecessary `SimItem` usage from cache updater
dylanlott Apr 28, 2025
f27dde8
makes tx-pool hold a `Client` reference for reuse
dylanlott Apr 28, 2025
f63fe6b
update comment
dylanlott Apr 28, 2025
79977bd
sets concurrency limit by calling `available_parallelism` or overridi…
dylanlott Apr 28, 2025
c8deba9
refactors the rollup provider type
dylanlott Apr 28, 2025
8980e23
creates mod consts
dylanlott Apr 28, 2025
4e97d89
pulls chain configs out into constants module
dylanlott Apr 29, 2025
31d62d6
clippy + fmt
dylanlott Apr 29, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 17 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,24 @@ name = "transaction-submitter"
path = "bin/submit_transaction.rs"

[dependencies]
init4-bin-base = "0.1.0"
init4-bin-base = { git = "https://github.com/init4tech/bin-base.git" }

zenith-types = "0.13"
signet-zenith = { git = "https://github.com/init4tech/signet-sdk", branch = "main" }
signet-types = { git = "https://github.com/init4tech/signet-sdk", branch = "main" }
signet-bundle = { git = "https://github.com/init4tech/signet-sdk", branch = "main" }
signet-sim = { git = "https://github.com/init4tech/signet-sdk", branch = "main" }

alloy = { version = "0.7.3", features = ["full", "json-rpc", "signer-aws", "rpc-types-mev", "rlp"] }
trevm = { version = "0.20.10", features = ["concurrent-db", "test-utils"] }

alloy = { version = "0.12.6", features = [
"full",
"json-rpc",
"signer-aws",
"rpc-types-mev",
"rlp",
"node-bindings",
"serde",
] }

aws-config = "1.1.7"
aws-sdk-kms = "1.15.0"
Expand All @@ -48,3 +61,4 @@ tokio = { version = "1.36.0", features = ["full", "macros", "rt-multi-thread"] }

async-trait = "0.1.80"
oauth2 = "4.4.2"
tracing-subscriber = "0.3.19"
62 changes: 47 additions & 15 deletions bin/builder.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
#![allow(dead_code)]

use builder::config::BuilderConfig;
use builder::service::serve_builder_with_span;
use builder::tasks::block::BlockBuilder;
use builder::tasks::metrics::MetricsTask;
use builder::tasks::oauth::Authenticator;
use builder::tasks::submit::SubmitTask;

use builder::{
config::BuilderConfig,
service::serve_builder_with_span,
tasks::{
block::Simulator, bundler, metrics::MetricsTask, oauth::Authenticator, submit::SubmitTask,
tx_poller,
},
};
use signet_sim::SimCache;
use signet_types::SlotCalculator;
use std::sync::Arc;
use tokio::select;

#[tokio::main]
Expand All @@ -16,19 +18,20 @@ async fn main() -> eyre::Result<()> {
let span = tracing::info_span!("zenith-builder");

let config = BuilderConfig::load_from_env()?.clone();
let host_provider = config.connect_host_provider().await?;
let ru_provider = config.connect_ru_provider().await?;
let constants = config.load_pecorino_constants();
let authenticator = Authenticator::new(&config);

tracing::debug!(rpc_url = config.host_rpc_url.as_ref(), "instantiated provider");
let (host_provider, ru_provider, sequencer_signer) = tokio::try_join!(
config.connect_host_provider(),
config.connect_ru_provider(),
config.connect_sequencer_signer(),
)?;

let sequencer_signer = config.connect_sequencer_signer().await?;
let zenith = config.connect_zenith(host_provider.clone());

let metrics = MetricsTask { host_provider: host_provider.clone() };
let (tx_channel, metrics_jh) = metrics.spawn();

let builder = BlockBuilder::new(&config, authenticator.clone(), ru_provider.clone());
let submit = SubmitTask {
authenticator: authenticator.clone(),
host_provider,
Expand All @@ -39,14 +42,43 @@ async fn main() -> eyre::Result<()> {
outbound_tx_channel: tx_channel,
};

let tx_poller = tx_poller::TxPoller::new(&config);
let (tx_receiver, tx_poller_jh) = tx_poller.spawn();

let bundle_poller = bundler::BundlePoller::new(&config, authenticator.clone());
let (bundle_receiver, bundle_poller_jh) = bundle_poller.spawn();

let authenticator_jh = authenticator.spawn();

let (submit_channel, submit_jh) = submit.spawn();
let build_jh = builder.spawn(submit_channel);

let sim_items = SimCache::new();
let slot_calculator =
SlotCalculator::new(config.start_timestamp, config.chain_offset, config.target_slot_time);

let sim = Arc::new(Simulator::new(&config, ru_provider.clone(), slot_calculator));

let (basefee_jh, sim_cache_jh) =
sim.clone().spawn_cache_task(tx_receiver, bundle_receiver, sim_items.clone());

let build_jh = sim.clone().spawn_simulator_task(constants, sim_items.clone(), submit_channel);

let port = config.builder_port;
let server = serve_builder_with_span(([0, 0, 0, 0], port), span);

select! {
_ = tx_poller_jh => {
tracing::info!("tx_poller finished");
},
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i miss is cooked :(

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is cooked got cooked

_ = bundle_poller_jh => {
tracing::info!("bundle_poller finished");
},
_ = sim_cache_jh => {
tracing::info!("sim cache task finished");
}
_ = basefee_jh => {
tracing::info!("basefee task finished");
}
_ = submit_jh => {
tracing::info!("submit finished");
},
Expand Down
9 changes: 4 additions & 5 deletions bin/submit_transaction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use alloy::{
signers::aws::AwsSigner,
};
use aws_config::BehaviorVersion;
use builder::config::{Provider, load_address, load_string, load_u64, load_url};
use builder::config::{HostProvider, load_address, load_string, load_u64, load_url};
use init4_bin_base::{
deps::metrics::{counter, histogram},
init4,
Expand All @@ -30,7 +30,7 @@ async fn main() {
}
}

async fn send_transaction(provider: Provider, recipient_address: Address) {
async fn send_transaction(provider: HostProvider, recipient_address: Address) {
// construct simple transaction to send ETH to a recipient
let tx = TransactionRequest::default()
.with_from(provider.default_signer_address())
Expand Down Expand Up @@ -67,7 +67,7 @@ async fn send_transaction(provider: Provider, recipient_address: Address) {
histogram!("txn_submitter.tx_mine_time").record(mine_time as f64);
}

async fn connect_from_config() -> (Provider, Address, u64) {
async fn connect_from_config() -> (HostProvider, Address, u64) {
// load signer config values from .env
let rpc_url = load_url("RPC_URL").unwrap();
let chain_id = load_u64("CHAIN_ID").unwrap();
Expand All @@ -82,9 +82,8 @@ async fn connect_from_config() -> (Provider, Address, u64) {
let signer = AwsSigner::new(client, kms_key_id.to_string(), Some(chain_id)).await.unwrap();

let provider = ProviderBuilder::new()
.with_recommended_fillers()
.wallet(EthereumWallet::from(signer))
.on_builtin(&rpc_url)
.connect(&rpc_url)
.await
.unwrap();

Expand Down
125 changes: 84 additions & 41 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use crate::signer::{LocalOrAws, SignerError};
use crate::{
constants,
signer::{LocalOrAws, SignerError},
};
use alloy::{
network::{Ethereum, EthereumWallet},
primitives::Address,
Expand All @@ -9,10 +12,12 @@ use alloy::{
WalletFiller,
},
},
transports::BoxTransport,
};
use eyre::Result;
use oauth2::url;
use signet_types::config::{HostConfig, PredeployTokens, RollupConfig, SignetSystemConstants};
use signet_zenith::Zenith;
use std::{borrow::Cow, env, num, str::FromStr};
use zenith_types::Zenith;

// Keys for .env variables that need to be set to configure the builder.
const HOST_CHAIN_ID: &str = "HOST_CHAIN_ID";
Expand All @@ -38,6 +43,8 @@ const OAUTH_CLIENT_ID: &str = "OAUTH_CLIENT_ID";
const OAUTH_CLIENT_SECRET: &str = "OAUTH_CLIENT_SECRET";
const OAUTH_AUTHENTICATE_URL: &str = "OAUTH_AUTHENTICATE_URL";
const OAUTH_TOKEN_URL: &str = "OAUTH_TOKEN_URL";
const CONCURRENCY_LIMIT: &str = "CONCURRENCY_LIMIT";
const START_TIMESTAMP: &str = "START_TIMESTAMP";

/// Configuration for a builder running a specific rollup on a specific host
/// chain.
Expand Down Expand Up @@ -93,6 +100,10 @@ pub struct BuilderConfig {
pub oauth_token_url: String,
/// The oauth token refresh interval in seconds.
pub oauth_token_refresh_interval: u64,
/// The max number of simultaneous block simulations to run.
pub concurrency_limit: usize,
/// The anchor for slot time and number calculations before adjusting for chain offset.
pub start_timestamp: u64,
}

/// Error loading the configuration.
Expand All @@ -116,6 +127,9 @@ pub enum ConfigError {
/// Error connecting to the signer
#[error("failed to connect to signer: {0}")]
Signer(#[from] SignerError),
/// Error checking available system concurrency
#[error("failed to determine system concurrency: {0}")]
Io(#[from] std::io::Error),
}
Comment on lines +130 to +132
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so, i think the error thrown when checking concurrency will add the specific info; therefore, we can keep this general as an "I/O error" instead of using Io to describe the specific concurrency check error.


impl ConfigError {
Expand All @@ -125,35 +139,24 @@ impl ConfigError {
}
}

/// Provider type used to read & write.
pub type Provider = FillProvider<
/// Type alias for the provider used to build and submit blocks to the host.
pub type HostProvider = FillProvider<
JoinFill<
JoinFill<
Identity,
JoinFill<GasFiller, JoinFill<BlobGasFiller, JoinFill<NonceFiller, ChainIdFiller>>>,
>,
WalletFiller<EthereumWallet>,
>,
RootProvider<BoxTransport>,
BoxTransport,
RootProvider,
Ethereum,
>;

/// Provider type used to read-only.
pub type WalletlessProvider = FillProvider<
JoinFill<
Identity,
JoinFill<GasFiller, JoinFill<BlobGasFiller, JoinFill<NonceFiller, ChainIdFiller>>>,
>,
RootProvider<BoxTransport>,
BoxTransport,
Ethereum,
>;
/// Type alias for the provider used to simulate against rollup state.
pub type RuProvider = RootProvider<Ethereum>;

/// A Zenith contract instance, using some provider `P` (defaults to
/// [`Provider`]).
pub type ZenithInstance<P = Provider> =
Zenith::ZenithInstance<BoxTransport, P, alloy::network::Ethereum>;
/// A [`Zenith`] contract instance using [`Provider`] as the provider.
pub type ZenithInstance<P = HostProvider> = Zenith::ZenithInstance<(), P, alloy::network::Ethereum>;

impl BuilderConfig {
/// Load the builder configuration from environment variables.
Expand Down Expand Up @@ -189,6 +192,8 @@ impl BuilderConfig {
oauth_authenticate_url: load_string(OAUTH_AUTHENTICATE_URL)?,
oauth_token_url: load_string(OAUTH_TOKEN_URL)?,
oauth_token_refresh_interval: load_u64(AUTH_TOKEN_REFRESH_INTERVAL)?,
concurrency_limit: load_concurrency_limit()?,
start_timestamp: load_u64(START_TIMESTAMP)?,
})
}

Expand All @@ -209,42 +214,67 @@ impl BuilderConfig {
}

/// Connect to the Rollup rpc provider.
pub async fn connect_ru_provider(&self) -> Result<WalletlessProvider, ConfigError> {
ProviderBuilder::new()
.with_recommended_fillers()
.on_builtin(&self.ru_rpc_url)
.await
.map_err(Into::into)
pub async fn connect_ru_provider(&self) -> Result<RootProvider<Ethereum>, ConfigError> {
let url = url::Url::parse(&self.ru_rpc_url).expect("failed to parse URL");
let provider = RootProvider::<Ethereum>::new_http(url);
Ok(provider)
}

/// Connect to the Host rpc provider.
pub async fn connect_host_provider(&self) -> Result<Provider, ConfigError> {
pub async fn connect_host_provider(&self) -> Result<HostProvider, ConfigError> {
let builder_signer = self.connect_builder_signer().await?;
ProviderBuilder::new()
.with_recommended_fillers()
let provider = ProviderBuilder::new()
.wallet(EthereumWallet::from(builder_signer))
.on_builtin(&self.host_rpc_url)
.connect(&self.host_rpc_url)
.await
.map_err(Into::into)
.map_err(ConfigError::Provider)?;

Ok(provider)
}

/// Connect additional broadcast providers.
pub async fn connect_additional_broadcast(
&self,
) -> Result<Vec<RootProvider<BoxTransport>>, ConfigError> {
let mut providers = Vec::with_capacity(self.tx_broadcast_urls.len());
for url in self.tx_broadcast_urls.iter() {
let provider =
ProviderBuilder::new().on_builtin(url).await.map_err(Into::<ConfigError>::into)?;
pub async fn connect_additional_broadcast(&self) -> Result<Vec<RootProvider>, ConfigError> {
let mut providers: Vec<RootProvider> = Vec::with_capacity(self.tx_broadcast_urls.len());

for url_str in self.tx_broadcast_urls.iter() {
let url = url::Url::parse(url_str).expect("failed to parse URL");
let provider = RootProvider::new_http(url);
providers.push(provider);
}

Ok(providers)
}

/// Connect to the Zenith instance, using the specified provider.
pub const fn connect_zenith(&self, provider: Provider) -> ZenithInstance {
pub const fn connect_zenith(&self, provider: HostProvider) -> ZenithInstance {
Zenith::new(self.zenith_address, provider)
}

/// Loads the Signet system constants for Pecorino.
pub const fn load_pecorino_constants(&self) -> SignetSystemConstants {
let host = HostConfig::new(
self.host_chain_id,
constants::PECORINO_DEPLOY_HEIGHT,
self.zenith_address,
constants::HOST_ORDERS,
constants::HOST_PASSAGE,
constants::HOST_TRANSACTOR,
PredeployTokens::new(constants::HOST_USDC, constants::HOST_USDT, constants::HOST_WBTC),
);
let rollup = RollupConfig::new(
self.ru_chain_id,
constants::ROLLUP_ORDERS,
constants::ROLLUP_PASSAGE,
constants::BASE_FEE_RECIPIENT,
PredeployTokens::new(
constants::ROLLUP_USDC,
constants::ROLLUP_USDT,
constants::ROLLUP_WBTC,
),
);

SignetSystemConstants::new(host, rollup)
}
}

/// Load a string from an environment variable.
Expand Down Expand Up @@ -278,5 +308,18 @@ pub fn load_url(key: &str) -> Result<Cow<'static, str>, ConfigError> {
/// Load an address from an environment variable.
pub fn load_address(key: &str) -> Result<Address, ConfigError> {
let address = load_string(key)?;
Address::from_str(&address).map_err(Into::into)
Address::from_str(&address)
.map_err(|_| ConfigError::Var(format!("Invalid address format for {}", key)))
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's include the actual error source


/// Checks the configured concurrency parameter and, if none is set, checks the available
/// system concurrency with `std::thread::available_parallelism` and returns that.
pub fn load_concurrency_limit() -> Result<usize, ConfigError> {
match load_u16(CONCURRENCY_LIMIT) {
Ok(env) => Ok(env as usize),
Err(_) => {
let limit = std::thread::available_parallelism()?.get();
Ok(limit)
}
}
}
Loading
Loading