From b7b455af9535ffd5b2a546fdfce05466d8b6609b Mon Sep 17 00:00:00 2001 From: dylan Date: Fri, 10 Jan 2025 11:55:24 -0700 Subject: [PATCH 01/20] feat: adds bundles to in progress block creation - checks the cache for bundles - ingests any new bundles that it finds into the in progress block - adds a unit test for bundle ingestion --- src/tasks/block.rs | 84 +++++++++++++++++++++++++++++++++++++++------ src/tasks/submit.rs | 20 ++++++++--- 2 files changed, 89 insertions(+), 15 deletions(-) diff --git a/src/tasks/block.rs b/src/tasks/block.rs index a3d6217..5ef2e9d 100644 --- a/src/tasks/block.rs +++ b/src/tasks/block.rs @@ -12,7 +12,7 @@ use alloy_rlp::Buf; use std::time::{SystemTime, UNIX_EPOCH}; use std::{sync::OnceLock, time::Duration}; use tokio::{sync::mpsc, task::JoinHandle}; -use tracing::Instrument; +use tracing::{debug, error, Instrument}; use zenith_types::{encode_txns, Alloy2718Coder}; /// Ethereum's slot time in seconds. @@ -71,7 +71,7 @@ impl InProgressBlock { /// Ingest a bundle into the in-progress block. /// Ignores Signed Orders for now. pub fn ingest_bundle(&mut self, bundle: Bundle) { - tracing::trace!(bundle = %bundle.id, "ingesting bundle"); + debug!(bundle = %bundle.id, "ingesting bundle"); let txs = bundle .bundle @@ -83,11 +83,9 @@ impl InProgressBlock { if let Ok(txs) = txs { self.unseal(); - // extend the transactions with the decoded transactions. - // As this builder does not provide bundles landing "top of block", its fine to just extend. self.transactions.extend(txs); } else { - tracing::error!("failed to decode bundle. dropping"); + error!("failed to decode bundle. dropping"); } } @@ -155,12 +153,12 @@ impl BlockBuilder { } } - async fn _get_bundles(&mut self, in_progress: &mut InProgressBlock) { + async fn get_bundles(&mut self, in_progress: &mut InProgressBlock) { tracing::trace!("query bundles from cache"); let bundles = self.bundle_poller.check_bundle_cache().await; + // OPTIMIZE: Sort bundles received from cache match bundles { Ok(bundles) => { - tracing::trace!("got bundles response"); for bundle in bundles { in_progress.ingest_bundle(bundle); } @@ -218,9 +216,7 @@ impl BlockBuilder { // Build a block let mut in_progress = InProgressBlock::default(); self.get_transactions(&mut in_progress).await; - - // TODO: Implement bundle ingestion #later - // self.get_bundles(&mut in_progress).await; + self.get_bundles(&mut in_progress).await; // Filter confirmed transactions from the block self.filter_transactions(&mut in_progress).await; @@ -242,3 +238,71 @@ impl BlockBuilder { ) } } + +#[cfg(test)] +mod tests { + use super::*; + use alloy::primitives::Address; + use alloy::{ + eips::eip2718::Encodable2718, + network::{EthereumWallet, TransactionBuilder}, + rpc::types::{mev::EthSendBundle, TransactionRequest}, + signers::local::PrivateKeySigner, + }; + use zenith_types::ZenithEthBundle; + + /// Create a mock bundle for testing with a single transaction + async fn create_mock_bundle(wallet: &EthereumWallet) -> Bundle { + let tx = TransactionRequest::default() + .to(Address::ZERO) + .from(wallet.default_signer().address()) + .nonce(1) + .max_fee_per_gas(2) + .max_priority_fee_per_gas(3) + .gas_limit(4) + .build(wallet) + .await + .unwrap() + .encoded_2718(); + + let eth_bundle = EthSendBundle { + txs: vec![tx.into()], + block_number: 1, + min_timestamp: Some(u64::MIN), + max_timestamp: Some(u64::MAX), + reverting_tx_hashes: vec![], + replacement_uuid: Some("replacement_uuid".to_owned()), + }; + + let zenith_bundle = ZenithEthBundle { bundle: eth_bundle, host_fills: None }; + + Bundle { id: "mock_bundle".to_owned(), bundle: zenith_bundle } + } + + #[tokio::test] + async fn test_ingest_bundle() { + // Setup random creds + let signer = PrivateKeySigner::random(); + let wallet = EthereumWallet::from(signer); + + // Create an empty InProgressBlock and bundle + let mut in_progress_block = InProgressBlock::new(); + let bundle = create_mock_bundle(&wallet).await; + + // Save previous hash for comparison + let prev_hash = in_progress_block.contents_hash(); + + // Ingest the bundle + in_progress_block.ingest_bundle(bundle); + + // Assert hash is changed after ingest + assert_ne!(prev_hash, in_progress_block.contents_hash(), "Bundle should change block hash"); + + // Assert that the transaction was persisted into block + assert_eq!(in_progress_block.len(), 1, "Bundle should be persisted"); + + // Assert that the block is properly sealed + let raw_encoding = in_progress_block.encode_raw(); + assert!(!raw_encoding.is_empty(), "Raw encoding should not be empty"); + } +} diff --git a/src/tasks/submit.rs b/src/tasks/submit.rs index b63abce..491ef80 100644 --- a/src/tasks/submit.rs +++ b/src/tasks/submit.rs @@ -21,7 +21,11 @@ use oauth2::TokenResponse; use std::time::Instant; use tokio::{sync::mpsc, task::JoinHandle}; use tracing::{debug, error, instrument, trace}; -use zenith_types::{SignRequest, SignResponse, Zenith, Zenith::IncorrectHostBlock}; +use zenith_types::{ + BundleHelper::{self, FillPermit2}, + SignRequest, SignResponse, + Zenith::IncorrectHostBlock, +}; macro_rules! spawn_provider_send { ($provider:expr, $tx:expr) => { @@ -110,13 +114,15 @@ impl SubmitTask { /// Builds blob transaction from the provided header and signature values fn build_blob_tx( &self, - header: Zenith::BlockHeader, + fills: Vec, + header: BundleHelper::BlockHeader, v: u8, r: FixedBytes<32>, s: FixedBytes<32>, in_progress: &InProgressBlock, ) -> eyre::Result { - let data = Zenith::submitBlockCall { header, v, r, s, _4: Default::default() }.abi_encode(); + let data = zenith_types::BundleHelper::submitCall { fills, header, v, r, s }.abi_encode(); + let sidecar = in_progress.encode_blob::().build()?; Ok(TransactionRequest::default() .with_blob_sidecar(sidecar) @@ -124,6 +130,7 @@ impl SubmitTask { .with_max_priority_fee_per_gas((GWEI_TO_WEI * 16) as u128)) } + /// Returns the next host block height async fn next_host_block_height(&self) -> eyre::Result { let result = self.host_provider.get_block_number().await?; let next = result.checked_add(1).ok_or_else(|| eyre!("next host block height overflow"))?; @@ -138,7 +145,7 @@ impl SubmitTask { ) -> eyre::Result { let (v, r, s) = extract_signature_components(&resp.sig); - let header = Zenith::BlockHeader { + let header = zenith_types::BundleHelper::BlockHeader { hostBlockNumber: resp.req.host_block_number, rollupChainId: U256::from(self.config.ru_chain_id), gasLimit: resp.req.gas_limit, @@ -146,8 +153,9 @@ impl SubmitTask { blockDataHash: in_progress.contents_hash(), }; + let fills = vec![]; // NB: ignored until fills are implemented let tx = self - .build_blob_tx(header, v, r, s, in_progress)? + .build_blob_tx(fills, header, v, r, s, in_progress)? .with_from(self.host_provider.default_signer_address()) .with_to(self.config.zenith_address) .with_gas_limit(1_000_000); @@ -168,6 +176,8 @@ impl SubmitTask { return Ok(ControlFlow::Skip); } + + // All validation checks have passed, send the transaction self.send_transaction(resp, tx).await } From 21c71e3cd5af1e182f0384a0ae5f1a66702c0caf Mon Sep 17 00:00:00 2001 From: dylan Date: Fri, 10 Jan 2025 12:51:41 -0700 Subject: [PATCH 02/20] add back httpmock dep --- Cargo.toml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 7d7704c..dcfe6b9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,4 +50,7 @@ tracing-subscriber = "0.3.18" async-trait = "0.1.80" oauth2 = "4.4.2" metrics = "0.24.1" -metrics-exporter-prometheus = "0.16.0" \ No newline at end of file +metrics-exporter-prometheus = "0.16.0" + +[dev-dependencies] +httpmock = "0.7.0" \ No newline at end of file From 60f8327549a517eba6fdce672ae9c2c5fce2f256 Mon Sep 17 00:00:00 2001 From: dylan Date: Fri, 10 Jan 2025 16:16:51 -0700 Subject: [PATCH 03/20] adds bundle simulation --- bin/builder.rs | 4 +-- src/tasks/block.rs | 87 +++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 81 insertions(+), 10 deletions(-) diff --git a/bin/builder.rs b/bin/builder.rs index 2b24056..3070cf0 100644 --- a/bin/builder.rs +++ b/bin/builder.rs @@ -34,7 +34,7 @@ async fn main() -> eyre::Result<()> { let submit = SubmitTask { authenticator: authenticator.clone(), - host_provider, + host_provider: host_provider.clone(), zenith, client: reqwest::Client::new(), sequencer_signer, @@ -44,7 +44,7 @@ async fn main() -> eyre::Result<()> { let authenticator_jh = authenticator.spawn(); let (submit_channel, submit_jh) = submit.spawn(); - let build_jh = builder.spawn(submit_channel); + let build_jh = builder.spawn(submit_channel, host_provider.clone()); let port = config.builder_port; let server = serve_builder_with_span(([0, 0, 0, 0], port), span); diff --git a/src/tasks/block.rs b/src/tasks/block.rs index 5ef2e9d..80ea3e7 100644 --- a/src/tasks/block.rs +++ b/src/tasks/block.rs @@ -1,19 +1,23 @@ use super::bundler::{Bundle, BundlePoller}; use super::oauth::Authenticator; use super::tx_poller::TxPoller; -use crate::config::{BuilderConfig, WalletlessProvider}; -use alloy::primitives::{keccak256, Bytes, B256}; -use alloy::providers::Provider; + +use crate::config::{BuilderConfig, Provider, WalletlessProvider}; + +use alloy::primitives::{keccak256, Bytes, FixedBytes, B256}; +use alloy::providers::Provider as _; +use alloy::rpc::types::TransactionRequest; use alloy::{ consensus::{SidecarBuilder, SidecarCoder, TxEnvelope}, eips::eip2718::Decodable2718, }; use alloy_rlp::Buf; +use eyre::{bail, eyre}; use std::time::{SystemTime, UNIX_EPOCH}; use std::{sync::OnceLock, time::Duration}; use tokio::{sync::mpsc, task::JoinHandle}; use tracing::{debug, error, Instrument}; -use zenith_types::{encode_txns, Alloy2718Coder}; +use zenith_types::{encode_txns, Alloy2718Coder, ZenithEthBundle}; /// Ethereum's slot time in seconds. pub const ETHEREUM_SLOT_TIME: u64 = 12; @@ -153,14 +157,17 @@ impl BlockBuilder { } } - async fn get_bundles(&mut self, in_progress: &mut InProgressBlock) { + async fn get_bundles(&mut self, host_provider: &Provider, in_progress: &mut InProgressBlock) { tracing::trace!("query bundles from cache"); let bundles = self.bundle_poller.check_bundle_cache().await; // OPTIMIZE: Sort bundles received from cache match bundles { Ok(bundles) => { for bundle in bundles { - in_progress.ingest_bundle(bundle); + let result = self.simulate_bundle(&bundle.bundle, host_provider).await; + if result.is_ok() { + in_progress.ingest_bundle(bundle.clone()); + } } } Err(e) => { @@ -170,6 +177,54 @@ impl BlockBuilder { self.bundle_poller.evict(); } + /// Simulates a Flashbots-style ZenithEthBundle, simualating each transaction in it's bundle + /// by calling it against the host provider at the current height against default storage (no state overrides) + /// and failing the whole bundle if any transaction not listed in the reverts list fails that call. + async fn simulate_bundle( + &mut self, + bundle: &ZenithEthBundle, + host_provider: &Provider, + ) -> eyre::Result<()> { + tracing::info!("simulating bundle"); + + let reverts = &bundle.bundle.reverting_tx_hashes; + tracing::debug!(reverts = ?reverts, "processing bundle with reverts"); + + for tx in &bundle.bundle.txs { + let (tx_env, hash) = self.parse_from_bundle(tx)?; + + // Simulate and check for reversion allowance + match self.simulate_transaction(host_provider, tx_env).await { + Ok(_) => { + // Passed, log trace and continue + tracing::debug!(tx = %hash, "tx passed simulation"); + continue; + } + Err(sim_err) => { + // Failed, only continfue if tx is marked in revert list + tracing::debug!("tx failed simulation: {}", sim_err); + if reverts.contains(&hash) { + continue; + } else { + bail!("tx {hash} failed simulation but was not marked as allowed to revert") + } + } + } + } + Ok(()) + } + + /// Simulates a transaction by calling it on the host provider at the current height with the current state. + async fn simulate_transaction( + &self, + host_provider: &Provider, + tx_env: TxEnvelope, + ) -> eyre::Result<()> { + let tx = TransactionRequest::from_transaction(tx_env); + host_provider.call(&tx).await?; + Ok(()) + } + async fn filter_transactions(&self, in_progress: &mut InProgressBlock) { // query the rollup node to see which transaction(s) have been included let mut confirmed_transactions = Vec::new(); @@ -203,9 +258,25 @@ impl BlockBuilder { self.secs_to_next_slot() + self.config.target_slot_time } + /// Parses bytes into a transaction envelope that is compatible with Flashbots-style bundles + fn parse_from_bundle(&self, tx: &Bytes) -> Result<(TxEnvelope, FixedBytes<32>), eyre::Error> { + let tx_env = TxEnvelope::decode_2718(&mut tx.chunk())?; + let hash = tx_env.tx_hash().to_owned(); + tracing::debug!(hash = %hash, "decoded bundle tx"); + if tx_env.is_eip4844() { + tracing::error!("eip-4844 disallowed"); + return Err(eyre!("EIP-4844 transactions are not allowed in bundles")); + } + Ok((tx_env, hash)) + } + /// Spawn the block builder task, returning the inbound channel to it, and /// a handle to the running task. - pub fn spawn(mut self, outbound: mpsc::UnboundedSender) -> JoinHandle<()> { + pub fn spawn( + mut self, + outbound: mpsc::UnboundedSender, + host_provider: Provider, + ) -> JoinHandle<()> { tokio::spawn( async move { loop { @@ -216,7 +287,7 @@ impl BlockBuilder { // Build a block let mut in_progress = InProgressBlock::default(); self.get_transactions(&mut in_progress).await; - self.get_bundles(&mut in_progress).await; + self.get_bundles(&host_provider, &mut in_progress).await; // Filter confirmed transactions from the block self.filter_transactions(&mut in_progress).await; From 27f676a1721e28d7dfe4bcf36e249a6e923d1ae8 Mon Sep 17 00:00:00 2001 From: dylan Date: Fri, 10 Jan 2025 16:39:00 -0700 Subject: [PATCH 04/20] puts comments back --- src/tasks/block.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/tasks/block.rs b/src/tasks/block.rs index 80ea3e7..203a639 100644 --- a/src/tasks/block.rs +++ b/src/tasks/block.rs @@ -87,6 +87,8 @@ impl InProgressBlock { if let Ok(txs) = txs { self.unseal(); + // extend the transactions with the decoded transactions. + // As this builder does not provide bundles landing "top of block", its fine to just extend. self.transactions.extend(txs); } else { error!("failed to decode bundle. dropping"); From ba5ba0b033ef0e98ea676ad2787ded57ef3414ef Mon Sep 17 00:00:00 2001 From: dylan Date: Fri, 10 Jan 2025 17:02:22 -0700 Subject: [PATCH 05/20] adds config value for builder helper contract address --- src/config.rs | 4 ++++ src/tasks/block.rs | 4 ++-- src/tasks/oauth.rs | 1 + src/tasks/submit.rs | 2 +- tests/bundle_poller_test.rs | 1 + tests/tx_poller_test.rs | 1 + 6 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/config.rs b/src/config.rs index d538e67..fc672f5 100644 --- a/src/config.rs +++ b/src/config.rs @@ -33,6 +33,7 @@ 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 BUILDER_HELPER_ADDRESS: &str = "0x0000000000000000000000000000000000000000"; /// Configuration for a builder running a specific rollup on a specific host /// chain. @@ -50,6 +51,8 @@ pub struct BuilderConfig { pub tx_broadcast_urls: Vec>, /// address of the Zenith contract on Host. pub zenith_address: Address, + /// address of the Builder Helper contract on Host. + pub builder_helper_address: Address, /// URL for remote Quincey Sequencer server to sign blocks. /// Disregarded if a sequencer_signer is configured. pub quincey_url: Cow<'static, str>, @@ -157,6 +160,7 @@ impl BuilderConfig { .map(Into::into) .collect(), zenith_address: load_address(ZENITH_ADDRESS)?, + builder_helper_address: load_address(BUILDER_HELPER_ADDRESS)?, quincey_url: load_url(QUINCEY_URL)?, builder_port: load_u16(BUILDER_PORT)?, sequencer_key: load_string_option(SEQUENCER_KEY), diff --git a/src/tasks/block.rs b/src/tasks/block.rs index 203a639..b5aa4df 100644 --- a/src/tasks/block.rs +++ b/src/tasks/block.rs @@ -16,7 +16,7 @@ use eyre::{bail, eyre}; use std::time::{SystemTime, UNIX_EPOCH}; use std::{sync::OnceLock, time::Duration}; use tokio::{sync::mpsc, task::JoinHandle}; -use tracing::{debug, error, Instrument}; +use tracing::{error, Instrument}; use zenith_types::{encode_txns, Alloy2718Coder, ZenithEthBundle}; /// Ethereum's slot time in seconds. @@ -75,7 +75,7 @@ impl InProgressBlock { /// Ingest a bundle into the in-progress block. /// Ignores Signed Orders for now. pub fn ingest_bundle(&mut self, bundle: Bundle) { - debug!(bundle = %bundle.id, "ingesting bundle"); + tracing::trace!(bundle = %bundle.id, "ingesting bundle"); let txs = bundle .bundle diff --git a/src/tasks/oauth.rs b/src/tasks/oauth.rs index 0716bfa..3a7c612 100644 --- a/src/tasks/oauth.rs +++ b/src/tasks/oauth.rs @@ -164,6 +164,7 @@ mod tests { oauth_token_url: "http://localhost:9000".into(), tx_broadcast_urls: vec!["http://localhost:9000".into()], oauth_token_refresh_interval: 300, // 5 minutes + builder_helper_address: Address::default(), }; Ok(config) } diff --git a/src/tasks/submit.rs b/src/tasks/submit.rs index 491ef80..8adf084 100644 --- a/src/tasks/submit.rs +++ b/src/tasks/submit.rs @@ -157,7 +157,7 @@ impl SubmitTask { let tx = self .build_blob_tx(fills, header, v, r, s, in_progress)? .with_from(self.host_provider.default_signer_address()) - .with_to(self.config.zenith_address) + .with_to(self.config.builder_helper_address) .with_gas_limit(1_000_000); if let Err(TransportError::ErrorResp(e)) = diff --git a/tests/bundle_poller_test.rs b/tests/bundle_poller_test.rs index f5c5b71..53fa51c 100644 --- a/tests/bundle_poller_test.rs +++ b/tests/bundle_poller_test.rs @@ -41,6 +41,7 @@ mod tests { oauth_token_url: "http://localhost:8080".into(), tx_broadcast_urls: vec!["http://localhost:9000".into()], oauth_token_refresh_interval: 300, // 5 minutes + builder_helper_address: Address::default(), }; Ok(config) } diff --git a/tests/tx_poller_test.rs b/tests/tx_poller_test.rs index e4703c2..a42afa6 100644 --- a/tests/tx_poller_test.rs +++ b/tests/tx_poller_test.rs @@ -87,6 +87,7 @@ mod tests { oauth_authenticate_url: "http://localhost:8080".into(), oauth_token_url: "http://localhost:8080".into(), oauth_token_refresh_interval: 300, // 5 minutes + builder_helper_address: Address::default(), }; Ok(config) } From ae22b439f1123800d73a6add2c862c12569911f4 Mon Sep 17 00:00:00 2001 From: dylan Date: Fri, 10 Jan 2025 17:25:53 -0700 Subject: [PATCH 06/20] cleanup --- src/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config.rs b/src/config.rs index fc672f5..f3c1a26 100644 --- a/src/config.rs +++ b/src/config.rs @@ -33,7 +33,7 @@ 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 BUILDER_HELPER_ADDRESS: &str = "0x0000000000000000000000000000000000000000"; +const BUILDER_HELPER_ADDRESS: &str = "BUILDER_HELPER_ADDRESS"; /// Configuration for a builder running a specific rollup on a specific host /// chain. From 7323d2efe57b32e242778d8ef3fbf665a9e37b39 Mon Sep 17 00:00:00 2001 From: dylan Date: Mon, 13 Jan 2025 15:44:21 -0700 Subject: [PATCH 07/20] adds authentication call before fetching bundles from cache --- src/tasks/block.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/tasks/block.rs b/src/tasks/block.rs index b5aa4df..7d357af 100644 --- a/src/tasks/block.rs +++ b/src/tasks/block.rs @@ -143,6 +143,7 @@ impl BlockBuilder { } } + /// Fetches transactions from the cache and ingests them into the in progress block async fn get_transactions(&mut self, in_progress: &mut InProgressBlock) { tracing::trace!("query transactions from cache"); let txns = self.tx_poller.check_tx_cache().await; @@ -159,7 +160,14 @@ impl BlockBuilder { } } + /// Fetches bundles from the cache and ingests them into the in progress block async fn get_bundles(&mut self, host_provider: &Provider, in_progress: &mut InProgressBlock) { + // Authenticate before fetching to ensure access to a valid token + if let Err(err) = self.bundle_poller.authenticator.authenticate().await { + tracing::error!(err = %err, "bundle fetcher failed to authenticate"); + return; + } + tracing::trace!("query bundles from cache"); let bundles = self.bundle_poller.check_bundle_cache().await; // OPTIMIZE: Sort bundles received from cache From c8f03ce1523e8761ecadfe506e35a08b7e9d98fc Mon Sep 17 00:00:00 2001 From: dylan Date: Tue, 14 Jan 2025 16:02:11 -0700 Subject: [PATCH 08/20] review: review feedback and fixes - pass ru provider not host provider for tx simulation - imports and logging clean up --- bin/builder.rs | 7 +++---- src/tasks/block.rs | 37 ++++++++++++++++++++----------------- 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/bin/builder.rs b/bin/builder.rs index 3070cf0..d317d69 100644 --- a/bin/builder.rs +++ b/bin/builder.rs @@ -27,14 +27,13 @@ async fn main() -> eyre::Result<()> { let sequencer_signer = config.connect_sequencer_signer().await?; let zenith = config.connect_zenith(host_provider.clone()); - let builder = BlockBuilder::new(&config, authenticator.clone(), ru_provider); - 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: host_provider.clone(), + host_provider, zenith, client: reqwest::Client::new(), sequencer_signer, @@ -44,7 +43,7 @@ async fn main() -> eyre::Result<()> { let authenticator_jh = authenticator.spawn(); let (submit_channel, submit_jh) = submit.spawn(); - let build_jh = builder.spawn(submit_channel, host_provider.clone()); + let build_jh = builder.spawn(submit_channel, ru_provider); let port = config.builder_port; let server = serve_builder_with_span(([0, 0, 0, 0], port), span); diff --git a/src/tasks/block.rs b/src/tasks/block.rs index 7d357af..970f87b 100644 --- a/src/tasks/block.rs +++ b/src/tasks/block.rs @@ -1,15 +1,13 @@ use super::bundler::{Bundle, BundlePoller}; use super::oauth::Authenticator; use super::tx_poller::TxPoller; - -use crate::config::{BuilderConfig, Provider, WalletlessProvider}; - -use alloy::primitives::{keccak256, Bytes, FixedBytes, B256}; -use alloy::providers::Provider as _; -use alloy::rpc::types::TransactionRequest; +use crate::config::{BuilderConfig, WalletlessProvider}; use alloy::{ consensus::{SidecarBuilder, SidecarCoder, TxEnvelope}, eips::eip2718::Decodable2718, + primitives::{keccak256, Bytes, FixedBytes, B256}, + providers::Provider as _, + rpc::types::TransactionRequest, }; use alloy_rlp::Buf; use eyre::{bail, eyre}; @@ -161,7 +159,11 @@ impl BlockBuilder { } /// Fetches bundles from the cache and ingests them into the in progress block - async fn get_bundles(&mut self, host_provider: &Provider, in_progress: &mut InProgressBlock) { + async fn get_bundles( + &mut self, + ru_provider: &WalletlessProvider, + in_progress: &mut InProgressBlock, + ) { // Authenticate before fetching to ensure access to a valid token if let Err(err) = self.bundle_poller.authenticator.authenticate().await { tracing::error!(err = %err, "bundle fetcher failed to authenticate"); @@ -174,7 +176,7 @@ impl BlockBuilder { match bundles { Ok(bundles) => { for bundle in bundles { - let result = self.simulate_bundle(&bundle.bundle, host_provider).await; + let result = self.simulate_bundle(&bundle.bundle, ru_provider).await; if result.is_ok() { in_progress.ingest_bundle(bundle.clone()); } @@ -187,13 +189,13 @@ impl BlockBuilder { self.bundle_poller.evict(); } - /// Simulates a Flashbots-style ZenithEthBundle, simualating each transaction in it's bundle + /// Simulates a Flashbots-style `ZenithEthBundle`, simualating each transaction in its bundle /// by calling it against the host provider at the current height against default storage (no state overrides) /// and failing the whole bundle if any transaction not listed in the reverts list fails that call. async fn simulate_bundle( &mut self, bundle: &ZenithEthBundle, - host_provider: &Provider, + ru_provider: &WalletlessProvider, ) -> eyre::Result<()> { tracing::info!("simulating bundle"); @@ -202,9 +204,10 @@ impl BlockBuilder { for tx in &bundle.bundle.txs { let (tx_env, hash) = self.parse_from_bundle(tx)?; + tracing::debug!(?hash, "tx_envelope parsed from bundle"); // Simulate and check for reversion allowance - match self.simulate_transaction(host_provider, tx_env).await { + match self.simulate_transaction(ru_provider, tx_env).await { Ok(_) => { // Passed, log trace and continue tracing::debug!(tx = %hash, "tx passed simulation"); @@ -212,7 +215,7 @@ impl BlockBuilder { } Err(sim_err) => { // Failed, only continfue if tx is marked in revert list - tracing::debug!("tx failed simulation: {}", sim_err); + tracing::debug!(?sim_err, "tx failed simulation"); if reverts.contains(&hash) { continue; } else { @@ -224,14 +227,14 @@ impl BlockBuilder { Ok(()) } - /// Simulates a transaction by calling it on the host provider at the current height with the current state. + /// Simulates a rollup transaction by calling it on the ru provider at the current height with the current state. async fn simulate_transaction( &self, - host_provider: &Provider, + ru_provider: &WalletlessProvider, tx_env: TxEnvelope, ) -> eyre::Result<()> { let tx = TransactionRequest::from_transaction(tx_env); - host_provider.call(&tx).await?; + ru_provider.call(&tx).await?; Ok(()) } @@ -285,7 +288,7 @@ impl BlockBuilder { pub fn spawn( mut self, outbound: mpsc::UnboundedSender, - host_provider: Provider, + ru_provider: WalletlessProvider, ) -> JoinHandle<()> { tokio::spawn( async move { @@ -297,7 +300,7 @@ impl BlockBuilder { // Build a block let mut in_progress = InProgressBlock::default(); self.get_transactions(&mut in_progress).await; - self.get_bundles(&host_provider, &mut in_progress).await; + self.get_bundles(&ru_provider, &mut in_progress).await; // Filter confirmed transactions from the block self.filter_transactions(&mut in_progress).await; From 8af3d79f42dfa75c99aa6ecac8f905a536d1fc20 Mon Sep 17 00:00:00 2001 From: dylan Date: Tue, 14 Jan 2025 16:14:33 -0700 Subject: [PATCH 09/20] reorder imports --- src/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/config.rs b/src/config.rs index f3c1a26..484e59c 100644 --- a/src/config.rs +++ b/src/config.rs @@ -17,6 +17,7 @@ const HOST_RPC_URL: &str = "HOST_RPC_URL"; const ROLLUP_RPC_URL: &str = "ROLLUP_RPC_URL"; const TX_BROADCAST_URLS: &str = "TX_BROADCAST_URLS"; const ZENITH_ADDRESS: &str = "ZENITH_ADDRESS"; +const BUILDER_HELPER_ADDRESS: &str = "BUILDER_HELPER_ADDRESS"; const QUINCEY_URL: &str = "QUINCEY_URL"; const BUILDER_PORT: &str = "BUILDER_PORT"; const SEQUENCER_KEY: &str = "SEQUENCER_KEY"; // empty (to use Quincey) OR AWS key ID (to use AWS signer) OR raw private key (to use local signer) @@ -33,7 +34,6 @@ 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 BUILDER_HELPER_ADDRESS: &str = "BUILDER_HELPER_ADDRESS"; /// Configuration for a builder running a specific rollup on a specific host /// chain. From 48e41925ccc04f1e60f5ea3f300c596c9042e70c Mon Sep 17 00:00:00 2001 From: dylan Date: Wed, 15 Jan 2025 16:27:31 -0700 Subject: [PATCH 10/20] cleanup tracing crate imports to only reference the macros --- src/tasks/block.rs | 58 +++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/src/tasks/block.rs b/src/tasks/block.rs index 970f87b..11de3d2 100644 --- a/src/tasks/block.rs +++ b/src/tasks/block.rs @@ -7,14 +7,13 @@ use alloy::{ eips::eip2718::Decodable2718, primitives::{keccak256, Bytes, FixedBytes, B256}, providers::Provider as _, - rpc::types::TransactionRequest, }; use alloy_rlp::Buf; use eyre::{bail, eyre}; use std::time::{SystemTime, UNIX_EPOCH}; use std::{sync::OnceLock, time::Duration}; use tokio::{sync::mpsc, task::JoinHandle}; -use tracing::{error, Instrument}; +use tracing::{error, debug, info, trace, Instrument}; use zenith_types::{encode_txns, Alloy2718Coder, ZenithEthBundle}; /// Ethereum's slot time in seconds. @@ -58,14 +57,14 @@ impl InProgressBlock { /// Ingest a transaction into the in-progress block. Fails pub fn ingest_tx(&mut self, tx: &TxEnvelope) { - tracing::trace!(hash = %tx.tx_hash(), "ingesting tx"); + trace!(hash = %tx.tx_hash(), "ingesting tx"); self.unseal(); self.transactions.push(tx.clone()); } /// Remove a transaction from the in-progress block. pub fn remove_tx(&mut self, tx: &TxEnvelope) { - tracing::trace!(hash = %tx.tx_hash(), "removing tx"); + trace!(hash = %tx.tx_hash(), "removing tx"); self.unseal(); self.transactions.retain(|t| t.tx_hash() != tx.tx_hash()); } @@ -73,7 +72,7 @@ impl InProgressBlock { /// Ingest a bundle into the in-progress block. /// Ignores Signed Orders for now. pub fn ingest_bundle(&mut self, bundle: Bundle) { - tracing::trace!(bundle = %bundle.id, "ingesting bundle"); + trace!(bundle = %bundle.id, "ingesting bundle"); let txs = bundle .bundle @@ -143,17 +142,17 @@ impl BlockBuilder { /// Fetches transactions from the cache and ingests them into the in progress block async fn get_transactions(&mut self, in_progress: &mut InProgressBlock) { - tracing::trace!("query transactions from cache"); + trace!("query transactions from cache"); let txns = self.tx_poller.check_tx_cache().await; match txns { Ok(txns) => { - tracing::trace!("got transactions response"); + trace!("got transactions response"); for txn in txns.into_iter() { in_progress.ingest_tx(&txn); } } Err(e) => { - tracing::error!(error = %e, "error polling transactions"); + error!(error = %e, "error polling transactions"); } } } @@ -166,13 +165,13 @@ impl BlockBuilder { ) { // Authenticate before fetching to ensure access to a valid token if let Err(err) = self.bundle_poller.authenticator.authenticate().await { - tracing::error!(err = %err, "bundle fetcher failed to authenticate"); + error!(err = %err, "bundle fetcher failed to authenticate"); return; } - tracing::trace!("query bundles from cache"); + trace!("query bundles from cache"); let bundles = self.bundle_poller.check_bundle_cache().await; - // OPTIMIZE: Sort bundles received from cache + // TODO: Sort bundles received from cache match bundles { Ok(bundles) => { for bundle in bundles { @@ -183,13 +182,13 @@ impl BlockBuilder { } } Err(e) => { - tracing::error!(error = %e, "error polling bundles"); + error!(error = %e, "error polling bundles"); } } self.bundle_poller.evict(); } - /// Simulates a Flashbots-style `ZenithEthBundle`, simualating each transaction in its bundle + /// Simulates a Flashbots-style `ZenithEthBundle`, simulating each transaction in its bundle /// by calling it against the host provider at the current height against default storage (no state overrides) /// and failing the whole bundle if any transaction not listed in the reverts list fails that call. async fn simulate_bundle( @@ -197,26 +196,27 @@ impl BlockBuilder { bundle: &ZenithEthBundle, ru_provider: &WalletlessProvider, ) -> eyre::Result<()> { - tracing::info!("simulating bundle"); + // TODO: Simulate bundles with the Simulation Engine + debug!(hash = ?bundle.bundle.bundle_hash(), block_number = ?bundle.block_number(), "beginning bundle simulation"); let reverts = &bundle.bundle.reverting_tx_hashes; - tracing::debug!(reverts = ?reverts, "processing bundle with reverts"); + debug!(reverts = ?reverts, "processing bundle with reverts"); for tx in &bundle.bundle.txs { let (tx_env, hash) = self.parse_from_bundle(tx)?; - tracing::debug!(?hash, "tx_envelope parsed from bundle"); + debug!(?hash, "tx_envelope parsed from bundle"); // Simulate and check for reversion allowance match self.simulate_transaction(ru_provider, tx_env).await { Ok(_) => { // Passed, log trace and continue - tracing::debug!(tx = %hash, "tx passed simulation"); + debug!(tx = %hash, "tx passed simulation"); continue; } Err(sim_err) => { // Failed, only continfue if tx is marked in revert list - tracing::debug!(?sim_err, "tx failed simulation"); if reverts.contains(&hash) { + debug!(?sim_err, "tx failed simulation but is in revert list; skipping."); continue; } else { bail!("tx {hash} failed simulation but was not marked as allowed to revert") @@ -230,11 +230,11 @@ impl BlockBuilder { /// Simulates a rollup transaction by calling it on the ru provider at the current height with the current state. async fn simulate_transaction( &self, - ru_provider: &WalletlessProvider, - tx_env: TxEnvelope, + _ru_provider: &WalletlessProvider, + _tx_env: TxEnvelope, ) -> eyre::Result<()> { - let tx = TransactionRequest::from_transaction(tx_env); - ru_provider.call(&tx).await?; + // let tx = TransactionRequest::from_transaction(tx_env); + // ru_provider.call(&tx).await?; Ok(()) } @@ -251,7 +251,7 @@ impl BlockBuilder { confirmed_transactions.push(transaction.clone()); } } - tracing::trace!(confirmed = confirmed_transactions.len(), "found confirmed transactions"); + trace!(confirmed = confirmed_transactions.len(), "found confirmed transactions"); // remove already-confirmed transactions for transaction in confirmed_transactions { @@ -275,9 +275,9 @@ impl BlockBuilder { fn parse_from_bundle(&self, tx: &Bytes) -> Result<(TxEnvelope, FixedBytes<32>), eyre::Error> { let tx_env = TxEnvelope::decode_2718(&mut tx.chunk())?; let hash = tx_env.tx_hash().to_owned(); - tracing::debug!(hash = %hash, "decoded bundle tx"); + debug!(hash = %hash, "decoded bundle tx"); if tx_env.is_eip4844() { - tracing::error!("eip-4844 disallowed"); + error!("eip-4844 disallowed"); return Err(eyre!("EIP-4844 transactions are not allowed in bundles")); } Ok((tx_env, hash)) @@ -295,7 +295,7 @@ impl BlockBuilder { loop { // sleep the buffer time tokio::time::sleep(Duration::from_secs(self.secs_to_next_target())).await; - tracing::info!("beginning block build cycle"); + info!("beginning block build cycle"); // Build a block let mut in_progress = InProgressBlock::default(); @@ -307,14 +307,14 @@ impl BlockBuilder { // submit the block if it has transactions if !in_progress.is_empty() { - tracing::debug!(txns = in_progress.len(), "sending block to submit task"); + debug!(txns = in_progress.len(), "sending block to submit task"); let in_progress_block = std::mem::take(&mut in_progress); if outbound.send(in_progress_block).is_err() { - tracing::error!("downstream task gone"); + error!("downstream task gone"); break; } } else { - tracing::debug!("no transactions, skipping block submission"); + debug!("no transactions, skipping block submission"); } } } From 69d5bcc5cc097b2af643950fa0234690ac2ab06a Mon Sep 17 00:00:00 2001 From: dylan lott Date: Wed, 15 Jan 2025 16:46:02 -0700 Subject: [PATCH 11/20] uncomment --- src/tasks/block.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tasks/block.rs b/src/tasks/block.rs index 11de3d2..f27167f 100644 --- a/src/tasks/block.rs +++ b/src/tasks/block.rs @@ -230,11 +230,11 @@ impl BlockBuilder { /// Simulates a rollup transaction by calling it on the ru provider at the current height with the current state. async fn simulate_transaction( &self, - _ru_provider: &WalletlessProvider, - _tx_env: TxEnvelope, + ru_provider: &WalletlessProvider, + tx_env: TxEnvelope, ) -> eyre::Result<()> { - // let tx = TransactionRequest::from_transaction(tx_env); - // ru_provider.call(&tx).await?; + let tx = TransactionRequest::from_transaction(tx_env); + ru_provider.call(&tx).await?; Ok(()) } From fabde6ebe7c3df0d2364b22f4455d022695e51a2 Mon Sep 17 00:00:00 2001 From: dylan lott Date: Wed, 15 Jan 2025 16:50:03 -0700 Subject: [PATCH 12/20] import fix --- src/tasks/block.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/tasks/block.rs b/src/tasks/block.rs index f27167f..2277b96 100644 --- a/src/tasks/block.rs +++ b/src/tasks/block.rs @@ -2,6 +2,7 @@ use super::bundler::{Bundle, BundlePoller}; use super::oauth::Authenticator; use super::tx_poller::TxPoller; use crate::config::{BuilderConfig, WalletlessProvider}; +use alloy::rpc::types::TransactionRequest; use alloy::{ consensus::{SidecarBuilder, SidecarCoder, TxEnvelope}, eips::eip2718::Decodable2718, From e7eab8a985edaa9ffe2432e2341b5d704617006f Mon Sep 17 00:00:00 2001 From: dylan lott Date: Wed, 15 Jan 2025 16:50:32 -0700 Subject: [PATCH 13/20] fmt --- src/tasks/block.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tasks/block.rs b/src/tasks/block.rs index 2277b96..29bc621 100644 --- a/src/tasks/block.rs +++ b/src/tasks/block.rs @@ -14,7 +14,7 @@ use eyre::{bail, eyre}; use std::time::{SystemTime, UNIX_EPOCH}; use std::{sync::OnceLock, time::Duration}; use tokio::{sync::mpsc, task::JoinHandle}; -use tracing::{error, debug, info, trace, Instrument}; +use tracing::{debug, error, info, trace, Instrument}; use zenith_types::{encode_txns, Alloy2718Coder, ZenithEthBundle}; /// Ethereum's slot time in seconds. From df38cee0d49084707a806039a1e287d9ea1ec03e Mon Sep 17 00:00:00 2001 From: dylan lott Date: Thu, 16 Jan 2025 09:53:59 -0700 Subject: [PATCH 14/20] remove bundle simulation and add todo comment --- src/tasks/block.rs | 62 ++++------------------------------------------ 1 file changed, 5 insertions(+), 57 deletions(-) diff --git a/src/tasks/block.rs b/src/tasks/block.rs index 29bc621..9a78987 100644 --- a/src/tasks/block.rs +++ b/src/tasks/block.rs @@ -2,15 +2,13 @@ use super::bundler::{Bundle, BundlePoller}; use super::oauth::Authenticator; use super::tx_poller::TxPoller; use crate::config::{BuilderConfig, WalletlessProvider}; -use alloy::rpc::types::TransactionRequest; use alloy::{ consensus::{SidecarBuilder, SidecarCoder, TxEnvelope}, eips::eip2718::Decodable2718, - primitives::{keccak256, Bytes, FixedBytes, B256}, + primitives::{keccak256, Bytes, B256}, providers::Provider as _, }; use alloy_rlp::Buf; -use eyre::{bail, eyre}; use std::time::{SystemTime, UNIX_EPOCH}; use std::{sync::OnceLock, time::Duration}; use tokio::{sync::mpsc, task::JoinHandle}; @@ -189,53 +187,15 @@ impl BlockBuilder { self.bundle_poller.evict(); } - /// Simulates a Flashbots-style `ZenithEthBundle`, simulating each transaction in its bundle - /// by calling it against the host provider at the current height against default storage (no state overrides) - /// and failing the whole bundle if any transaction not listed in the reverts list fails that call. + /// Simulates a Zenith bundle against the rollup state async fn simulate_bundle( &mut self, bundle: &ZenithEthBundle, - ru_provider: &WalletlessProvider, + _ru_provider: &WalletlessProvider, ) -> eyre::Result<()> { - // TODO: Simulate bundles with the Simulation Engine debug!(hash = ?bundle.bundle.bundle_hash(), block_number = ?bundle.block_number(), "beginning bundle simulation"); - - let reverts = &bundle.bundle.reverting_tx_hashes; - debug!(reverts = ?reverts, "processing bundle with reverts"); - - for tx in &bundle.bundle.txs { - let (tx_env, hash) = self.parse_from_bundle(tx)?; - debug!(?hash, "tx_envelope parsed from bundle"); - - // Simulate and check for reversion allowance - match self.simulate_transaction(ru_provider, tx_env).await { - Ok(_) => { - // Passed, log trace and continue - debug!(tx = %hash, "tx passed simulation"); - continue; - } - Err(sim_err) => { - // Failed, only continfue if tx is marked in revert list - if reverts.contains(&hash) { - debug!(?sim_err, "tx failed simulation but is in revert list; skipping."); - continue; - } else { - bail!("tx {hash} failed simulation but was not marked as allowed to revert") - } - } - } - } - Ok(()) - } - - /// Simulates a rollup transaction by calling it on the ru provider at the current height with the current state. - async fn simulate_transaction( - &self, - ru_provider: &WalletlessProvider, - tx_env: TxEnvelope, - ) -> eyre::Result<()> { - let tx = TransactionRequest::from_transaction(tx_env); - ru_provider.call(&tx).await?; + // TODO: Simulate bundles with the Simulation Engine + // [ENG-672](https://linear.app/initiates/issue/ENG-672/add-support-for-bundles) Ok(()) } @@ -272,18 +232,6 @@ impl BlockBuilder { self.secs_to_next_slot() + self.config.target_slot_time } - /// Parses bytes into a transaction envelope that is compatible with Flashbots-style bundles - fn parse_from_bundle(&self, tx: &Bytes) -> Result<(TxEnvelope, FixedBytes<32>), eyre::Error> { - let tx_env = TxEnvelope::decode_2718(&mut tx.chunk())?; - let hash = tx_env.tx_hash().to_owned(); - debug!(hash = %hash, "decoded bundle tx"); - if tx_env.is_eip4844() { - error!("eip-4844 disallowed"); - return Err(eyre!("EIP-4844 transactions are not allowed in bundles")); - } - Ok((tx_env, hash)) - } - /// Spawn the block builder task, returning the inbound channel to it, and /// a handle to the running task. pub fn spawn( From 6a19325675f656b72d705bf1fba2eb3bae5c7c08 Mon Sep 17 00:00:00 2001 From: dylan lott Date: Thu, 16 Jan 2025 10:39:46 -0700 Subject: [PATCH 15/20] removes unnecessary authenticate call --- src/tasks/block.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/tasks/block.rs b/src/tasks/block.rs index 9a78987..96c7142 100644 --- a/src/tasks/block.rs +++ b/src/tasks/block.rs @@ -162,12 +162,6 @@ impl BlockBuilder { ru_provider: &WalletlessProvider, in_progress: &mut InProgressBlock, ) { - // Authenticate before fetching to ensure access to a valid token - if let Err(err) = self.bundle_poller.authenticator.authenticate().await { - error!(err = %err, "bundle fetcher failed to authenticate"); - return; - } - trace!("query bundles from cache"); let bundles = self.bundle_poller.check_bundle_cache().await; // TODO: Sort bundles received from cache From 99cd16f7cde31b82a4afbdd154edb9c615f3c3d4 Mon Sep 17 00:00:00 2001 From: dylan lott Date: Thu, 16 Jan 2025 12:06:25 -0700 Subject: [PATCH 16/20] use alloy rlp feature instead of alloy-rlp crate --- Cargo.toml | 2 +- src/tasks/block.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index dcfe6b9..2d90696 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ path = "bin/submit_transaction.rs" [dependencies] zenith-types = "0.13" -alloy = { version = "0.7.3", features = ["full", "json-rpc", "signer-aws", "rpc-types-mev"] } +alloy = { version = "0.7.3", features = ["full", "json-rpc", "signer-aws", "rpc-types-mev", "rlp"] } alloy-rlp = { version = "0.3.4" } aws-config = "1.1.7" diff --git a/src/tasks/block.rs b/src/tasks/block.rs index 96c7142..ae6cd36 100644 --- a/src/tasks/block.rs +++ b/src/tasks/block.rs @@ -7,8 +7,8 @@ use alloy::{ eips::eip2718::Decodable2718, primitives::{keccak256, Bytes, B256}, providers::Provider as _, + rlp::Buf, }; -use alloy_rlp::Buf; use std::time::{SystemTime, UNIX_EPOCH}; use std::{sync::OnceLock, time::Duration}; use tokio::{sync::mpsc, task::JoinHandle}; From 29bf45406c0eea593e102ccd4abfd2241618748a Mon Sep 17 00:00:00 2001 From: dylan lott Date: Fri, 17 Jan 2025 11:05:22 -0700 Subject: [PATCH 17/20] unify alloy import --- src/config.rs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/config.rs b/src/config.rs index 484e59c..e7a5ba6 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,12 +1,16 @@ use crate::signer::{LocalOrAws, SignerError}; -use alloy::network::{Ethereum, EthereumWallet}; -use alloy::primitives::Address; -use alloy::providers::fillers::BlobGasFiller; -use alloy::providers::{ - fillers::{ChainIdFiller, FillProvider, GasFiller, JoinFill, NonceFiller, WalletFiller}, - Identity, ProviderBuilder, RootProvider, +use alloy::{ + network::{Ethereum, EthereumWallet}, + primitives::Address, + providers::{ + fillers::{ + BlobGasFiller, ChainIdFiller, FillProvider, GasFiller, JoinFill, NonceFiller, + WalletFiller, + }, + Identity, ProviderBuilder, RootProvider, + }, + transports::BoxTransport, }; -use alloy::transports::BoxTransport; use std::{borrow::Cow, env, num, str::FromStr}; use zenith_types::Zenith; From cc3bdbd8e48f27e906da3f43197ec48caa882c45 Mon Sep 17 00:00:00 2001 From: dylan lott Date: Fri, 17 Jan 2025 16:38:35 -0700 Subject: [PATCH 18/20] remove unused httpmock dep --- Cargo.toml | 3 --- 1 file changed, 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2d90696..b1c9cb9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,6 +51,3 @@ async-trait = "0.1.80" oauth2 = "4.4.2" metrics = "0.24.1" metrics-exporter-prometheus = "0.16.0" - -[dev-dependencies] -httpmock = "0.7.0" \ No newline at end of file From 850e399b37c8c8c17ac508d30b932263357d1f8f Mon Sep 17 00:00:00 2001 From: dylan lott Date: Fri, 17 Jan 2025 16:48:10 -0700 Subject: [PATCH 19/20] add error log and clean up debug statement --- src/tasks/block.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/tasks/block.rs b/src/tasks/block.rs index ae6cd36..832e67c 100644 --- a/src/tasks/block.rs +++ b/src/tasks/block.rs @@ -12,7 +12,7 @@ use alloy::{ use std::time::{SystemTime, UNIX_EPOCH}; use std::{sync::OnceLock, time::Duration}; use tokio::{sync::mpsc, task::JoinHandle}; -use tracing::{debug, error, info, trace, Instrument}; +use tracing::{debug, error, info, trace, warn, Instrument}; use zenith_types::{encode_txns, Alloy2718Coder, ZenithEthBundle}; /// Ethereum's slot time in seconds. @@ -169,8 +169,10 @@ impl BlockBuilder { Ok(bundles) => { for bundle in bundles { let result = self.simulate_bundle(&bundle.bundle, ru_provider).await; - if result.is_ok() { + if let Ok(()) = result { in_progress.ingest_bundle(bundle.clone()); + } else { + warn!(id = ?bundle.id, "bundle failed simulation") } } } @@ -187,9 +189,9 @@ impl BlockBuilder { bundle: &ZenithEthBundle, _ru_provider: &WalletlessProvider, ) -> eyre::Result<()> { - debug!(hash = ?bundle.bundle.bundle_hash(), block_number = ?bundle.block_number(), "beginning bundle simulation"); // TODO: Simulate bundles with the Simulation Engine // [ENG-672](https://linear.app/initiates/issue/ENG-672/add-support-for-bundles) + debug!(hash = ?bundle.bundle.bundle_hash(), block_number = ?bundle.block_number(), "bundle simulations is not implemented yet - skipping simulation"); Ok(()) } From 277840aeb87262dcd78322dc35b0af74e229d35a Mon Sep 17 00:00:00 2001 From: dylan lott Date: Fri, 17 Jan 2025 16:57:03 -0700 Subject: [PATCH 20/20] removes ru provider wire up - let simulation engine dictate that how it needs instead --- bin/builder.rs | 2 +- src/tasks/block.rs | 31 ++++++++----------------------- 2 files changed, 9 insertions(+), 24 deletions(-) diff --git a/bin/builder.rs b/bin/builder.rs index d317d69..b5c5ae2 100644 --- a/bin/builder.rs +++ b/bin/builder.rs @@ -43,7 +43,7 @@ async fn main() -> eyre::Result<()> { let authenticator_jh = authenticator.spawn(); let (submit_channel, submit_jh) = submit.spawn(); - let build_jh = builder.spawn(submit_channel, ru_provider); + let build_jh = builder.spawn(submit_channel); let port = config.builder_port; let server = serve_builder_with_span(([0, 0, 0, 0], port), span); diff --git a/src/tasks/block.rs b/src/tasks/block.rs index 832e67c..24d32ed 100644 --- a/src/tasks/block.rs +++ b/src/tasks/block.rs @@ -12,7 +12,7 @@ use alloy::{ use std::time::{SystemTime, UNIX_EPOCH}; use std::{sync::OnceLock, time::Duration}; use tokio::{sync::mpsc, task::JoinHandle}; -use tracing::{debug, error, info, trace, warn, Instrument}; +use tracing::{debug, error, info, trace, Instrument}; use zenith_types::{encode_txns, Alloy2718Coder, ZenithEthBundle}; /// Ethereum's slot time in seconds. @@ -157,22 +157,15 @@ impl BlockBuilder { } /// Fetches bundles from the cache and ingests them into the in progress block - async fn get_bundles( - &mut self, - ru_provider: &WalletlessProvider, - in_progress: &mut InProgressBlock, - ) { + async fn get_bundles(&mut self, in_progress: &mut InProgressBlock) { trace!("query bundles from cache"); let bundles = self.bundle_poller.check_bundle_cache().await; - // TODO: Sort bundles received from cache match bundles { Ok(bundles) => { for bundle in bundles { - let result = self.simulate_bundle(&bundle.bundle, ru_provider).await; - if let Ok(()) = result { - in_progress.ingest_bundle(bundle.clone()); - } else { - warn!(id = ?bundle.id, "bundle failed simulation") + match self.simulate_bundle(&bundle.bundle).await { + Ok(()) => in_progress.ingest_bundle(bundle.clone()), + Err(e) => error!(error = %e, id = ?bundle.id, "bundle simulation failed"), } } } @@ -184,11 +177,7 @@ impl BlockBuilder { } /// Simulates a Zenith bundle against the rollup state - async fn simulate_bundle( - &mut self, - bundle: &ZenithEthBundle, - _ru_provider: &WalletlessProvider, - ) -> eyre::Result<()> { + async fn simulate_bundle(&mut self, bundle: &ZenithEthBundle) -> eyre::Result<()> { // TODO: Simulate bundles with the Simulation Engine // [ENG-672](https://linear.app/initiates/issue/ENG-672/add-support-for-bundles) debug!(hash = ?bundle.bundle.bundle_hash(), block_number = ?bundle.block_number(), "bundle simulations is not implemented yet - skipping simulation"); @@ -230,11 +219,7 @@ impl BlockBuilder { /// Spawn the block builder task, returning the inbound channel to it, and /// a handle to the running task. - pub fn spawn( - mut self, - outbound: mpsc::UnboundedSender, - ru_provider: WalletlessProvider, - ) -> JoinHandle<()> { + pub fn spawn(mut self, outbound: mpsc::UnboundedSender) -> JoinHandle<()> { tokio::spawn( async move { loop { @@ -245,7 +230,7 @@ impl BlockBuilder { // Build a block let mut in_progress = InProgressBlock::default(); self.get_transactions(&mut in_progress).await; - self.get_bundles(&ru_provider, &mut in_progress).await; + self.get_bundles(&mut in_progress).await; // Filter confirmed transactions from the block self.filter_transactions(&mut in_progress).await;