diff --git a/Cargo.lock b/Cargo.lock index efada755..ce5f6ccf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -92,7 +92,7 @@ dependencies = [ "alloy-signer 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=bfd0fda)", "alloy-signer-wallet", "alloy-transport-http 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=bfd0fda)", - "reqwest 0.12.3", + "reqwest 0.12.4", ] [[package]] @@ -323,7 +323,7 @@ dependencies = [ "dashmap", "futures", "lru", - "reqwest 0.12.3", + "reqwest 0.12.4", "serde_json", "tokio", "tracing", @@ -349,7 +349,7 @@ dependencies = [ "dashmap", "futures", "lru", - "reqwest 0.12.3", + "reqwest 0.12.4", "serde_json", "tokio", "tracing", @@ -388,7 +388,7 @@ dependencies = [ "alloy-transport-http 0.1.0 (git+https://github.com/brechtpd/alloy?branch=175)", "futures", "pin-project", - "reqwest 0.12.3", + "reqwest 0.12.4", "serde", "serde_json", "tokio", @@ -408,7 +408,7 @@ dependencies = [ "alloy-transport-http 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=bfd0fda)", "futures", "pin-project", - "reqwest 0.12.3", + "reqwest 0.12.4", "serde", "serde_json", "tokio", @@ -640,7 +640,7 @@ source = "git+https://github.com/brechtpd/alloy?branch=175#55a8fb3b1cee4a867851e dependencies = [ "alloy-json-rpc 0.1.0 (git+https://github.com/brechtpd/alloy?branch=175)", "alloy-transport 0.1.0 (git+https://github.com/brechtpd/alloy?branch=175)", - "reqwest 0.12.3", + "reqwest 0.12.4", "serde_json", "tower", "url", @@ -653,7 +653,7 @@ source = "git+https://github.com/alloy-rs/alloy?rev=bfd0fda#bfd0fda492e560c3463d dependencies = [ "alloy-json-rpc 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=bfd0fda)", "alloy-transport 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=bfd0fda)", - "reqwest 0.12.3", + "reqwest 0.12.4", "serde_json", "tower", "url", @@ -4610,6 +4610,7 @@ dependencies = [ "raiko-lib", "raiko-primitives", "reqwest 0.11.27", + "reqwest 0.12.4", "revm", "risc0-prover", "rlp", @@ -4881,14 +4882,16 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.3" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e6cc1e89e689536eb5aeede61520e874df5a4707df811cd5da4aa5fbb2aae19" +checksum = "566cafdd92868e0939d3fb961bd0dc25fcfaaed179291093b3d43e6b3150ea10" dependencies = [ "base64 0.22.0", "bytes", + "encoding_rs", "futures-core", "futures-util", + "h2 0.4.4", "http 1.1.0", "http-body 1.0.0", "http-body-util", @@ -4908,6 +4911,7 @@ dependencies = [ "serde_json", "serde_urlencoded", "sync_wrapper", + "system-configuration", "tokio", "tokio-native-tls", "tower-service", diff --git a/Cargo.toml b/Cargo.toml index 59da3f68..95a86714 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -100,6 +100,7 @@ lazy_static = "1.4.0" once_cell = "1.8.0" thiserror = "1.0" reqwest = { version = "0.11.22", features = ["json"] } +reqwest_alloy = { package = "reqwest", version = "0.12.4", features = ["json"] } sha2 = "0.10.8" proptest = "1.4.0" rlp = "0.5.2" diff --git a/host/Cargo.toml b/host/Cargo.toml index 0b998396..6a12bf46 100644 --- a/host/Cargo.toml +++ b/host/Cargo.toml @@ -52,6 +52,7 @@ lazy_static = { workspace = true } once_cell = { workspace = true } thiserror = { workspace = true } reqwest = { workspace = true } +reqwest_alloy = { workspace = true } sha2 = { workspace = true } proptest = { workspace = true } c-kzg = { workspace = true } diff --git a/host/src/preflight.rs b/host/src/preflight.rs index 9f058f8c..75fafeb6 100644 --- a/host/src/preflight.rs +++ b/host/src/preflight.rs @@ -6,12 +6,10 @@ use alloy_consensus::{ pub use alloy_primitives::*; use alloy_provider::{Provider, ProviderBuilder, ReqwestProvider, RootProvider}; pub use alloy_rlp as rlp; -use alloy_rpc_client::RpcClient; use alloy_rpc_types::{ Block as AlloyBlock, BlockTransactions, Filter, Transaction as AlloyRpcTransaction, }; use alloy_sol_types::{SolCall, SolEvent}; -use alloy_transport_http::Http; use anyhow::{anyhow, bail, Result}; use c_kzg::{Blob, KzgCommitment}; use hashbrown::HashSet; @@ -30,7 +28,6 @@ use raiko_primitives::{ mpt::proofs_to_tries, }; use serde::{Deserialize, Serialize}; -use url::Url; use crate::provider_db::{MeasuredProviderDb, ProviderDb}; @@ -42,8 +39,9 @@ pub fn preflight( l1_rpc_url: Option, beacon_rpc_url: Option, ) -> Result { - let http = Http::new(Url::parse(&rpc_url.clone().unwrap()).expect("invalid rpc url")); - let provider = ProviderBuilder::new().provider(RootProvider::new(RpcClient::new(http, true))); + let provider = ProviderBuilder::new().provider(RootProvider::new_http( + reqwest::Url::parse(&rpc_url.clone().unwrap()).expect("invalid rpc url"), + )); let measurement = Measurement::start("Fetching block data...", true); @@ -56,9 +54,9 @@ pub fn preflight( println!("block transactions: {:?}", block.transactions.len()); let taiko_guest_input = if network.is_taiko() { - let http_l1 = Http::new(Url::parse(&l1_rpc_url.clone().unwrap()).expect("invalid rpc url")); - let provider_l1 = - ProviderBuilder::new().provider(RootProvider::new(RpcClient::new(http_l1, true))); + let provider_l1 = ProviderBuilder::new().provider(RootProvider::new_http( + reqwest::Url::parse(&l1_rpc_url.clone().unwrap()).expect("invalid rpc url"), + )); // Decode the anchor tx to find out which L1 blocks we need to fetch let anchor_tx = match &block.transactions { diff --git a/host/src/provider_db.rs b/host/src/provider_db.rs index 6b8f053e..0c7ce1c6 100644 --- a/host/src/provider_db.rs +++ b/host/src/provider_db.rs @@ -17,10 +17,14 @@ use std::{ }; use alloy_consensus::Header as AlloyConsensusHeader; +use alloy_primitives::{Bytes, Uint}; use alloy_provider::{Provider, ReqwestProvider}; +use alloy_rpc_client::{ClientBuilder, RpcClient}; use alloy_rpc_types::{Block, BlockId, EIP1186AccountProofResponse}; +use alloy_transport_http::Http; use raiko_lib::{clear_line, inplace_print, mem_db::MemDb, print_duration, taiko_utils::to_header}; -use raiko_primitives::{mpt::KECCAK_EMPTY, Address, B256, U256}; +use raiko_primitives::{Address, B256, U256}; +use reqwest_alloy::Client; use revm::{ primitives::{Account, AccountInfo, Bytecode, HashMap}, Database, DatabaseCommit, @@ -31,6 +35,7 @@ use crate::preflight::get_block; pub struct ProviderDb { pub provider: ReqwestProvider, + pub client: RpcClient>, pub block_number: u64, pub initial_db: MemDb, pub initial_headers: HashMap, @@ -54,8 +59,12 @@ impl ProviderDb { initial_headers.insert(block_number, to_header(&block.header)); } } + // The client used for batch requests + let client = ClientBuilder::default() + .reqwest_http(reqwest::Url::parse(&provider.client().transport().url()).unwrap()); ProviderDb { provider, + client, block_number, initial_db, initial_headers, @@ -81,19 +90,37 @@ impl ProviderDb { ) -> Result, anyhow::Error> { let mut storage_proofs = HashMap::new(); let mut idx = offset; - for (address, keys) in storage_keys { + + // Create a batch for all storage proofs + let mut batch = self.client.new_batch(); + + // Collect all requests + let mut requests = Vec::new(); + for (address, keys) in storage_keys.clone() { + requests.push(( + Box::pin( + batch + .add_call::<_, EIP1186AccountProofResponse>( + "eth_getProof", + &(address, keys.clone(), BlockId::from(block_number)), + ) + .unwrap(), + ), + keys.len(), + )); + } + + // Send the batch + self.async_executor.block_on(async { batch.send().await })?; + + // Collect the data from the batch + for (request, num_keys) in requests.into_iter() { inplace_print(&format!( "fetching storage proof {idx}/{num_storage_proofs}..." )); - - let indices = keys.iter().map(|x| x.to_be_bytes().into()).collect(); - let proof = self.async_executor.block_on(async { - self.provider - .get_proof(address, indices, Some(BlockId::from(block_number))) - .await - })?; - storage_proofs.insert(address, proof); - idx += keys.len(); + let proof = self.async_executor.block_on(async { request.await })?; + storage_proofs.insert(proof.address, proof); + idx += num_keys; } clear_line(); @@ -186,57 +213,46 @@ impl Database for ProviderDb { return Ok(db_result); } - let use_get_proof = true; - let account_info = if use_get_proof { - let proof = self.async_executor.block_on(async { - self.provider - .get_proof(address, Vec::new(), Some(BlockId::from(self.block_number))) - .await - })?; - - // Only fetch the code if we know it's not empty - let code = if proof.code_hash.0 != KECCAK_EMPTY.0 { - let code = self.async_executor.block_on(async { - self.provider - .get_code_at(address, BlockId::from(self.block_number)) - .await - })?; - Bytecode::new_raw(code) - } else { - Bytecode::new() - }; - - AccountInfo::new( - proof.balance, - proof.nonce.try_into().unwrap(), - proof.code_hash, - code, + // Create a batch request for all account values + let mut batch = self.client.new_batch(); + + let nonce_request = batch + .add_call::<_, Uint<64, 1>>( + "eth_getTransactionCount", + &(address, Some(BlockId::from(self.block_number))), + ) + .unwrap(); + let balance_request = batch + .add_call::<_, Uint<256, 4>>( + "eth_getBalance", + &(address, Some(BlockId::from(self.block_number))), ) - } else { - // Get the nonce, balance, and code to reconstruct the account. - let nonce = self.async_executor.block_on(async { - self.provider - .get_transaction_count(address, Some(BlockId::from(self.block_number))) - .await - })?; - let balance = self.async_executor.block_on(async { - self.provider - .get_balance(address, Some(BlockId::from(self.block_number))) - .await - })?; - let code = self.async_executor.block_on(async { - self.provider - .get_code_at(address, BlockId::from(self.block_number)) - .await - })?; - - AccountInfo::new( - balance, - nonce.try_into().unwrap(), - Bytecode::new_raw(code.clone()).hash_slow(), - Bytecode::new_raw(code), + .unwrap(); + let code_request = batch + .add_call::<_, Bytes>( + "eth_getCode", + &(address, Some(BlockId::from(self.block_number))), ) - }; + .unwrap(); + + // Send the batch + self.async_executor.block_on(async { batch.send().await })?; + + // Collect the data from the batch + let (nonce, balance, code) = self.async_executor.block_on(async { + Ok::<_, Self::Error>(( + nonce_request.await?, + balance_request.await?, + code_request.await?, + )) + })?; + + let account_info = AccountInfo::new( + balance, + nonce.try_into().unwrap(), + Bytecode::new_raw(code.clone()).hash_slow(), + Bytecode::new_raw(code), + ); // Insert the account into the initial database. self.initial_db