//! This contains the [`BenchContext`], which is information that all replay-based benchmarks need. //! The initialization code is also the same, so this can be shared across benchmark commands. use crate::{authenticated_transport::AuthenticatedTransportConnect, bench_mode::BenchMode}; use alloy_eips::BlockNumberOrTag; use alloy_provider::{network::AnyNetwork, Provider, RootProvider}; use alloy_rpc_client::ClientBuilder; use alloy_rpc_types_engine::JwtSecret; use reqwest::Url; use reth_node_core::args::BenchmarkArgs; use tracing::info; /// This is intended to be used by benchmarks that replay blocks from an RPC. /// /// It contains an authenticated provider for engine API queries, a block provider for block /// queries, a [`BenchMode`] to determine whether the benchmark should run for a closed or open /// range of blocks, and the next block to fetch. pub(crate) struct BenchContext { /// The auth provider is used for engine API queries. pub(crate) auth_provider: RootProvider, /// The block provider is used for block queries. pub(crate) block_provider: RootProvider, /// The benchmark mode, which defines whether the benchmark should run for a closed or open /// range of blocks. pub(crate) benchmark_mode: BenchMode, /// The next block to fetch. pub(crate) next_block: u64, } impl BenchContext { /// This is the initialization code for most benchmarks, taking in a [`BenchmarkArgs`] and /// returning the providers needed to run a benchmark. pub(crate) async fn new(bench_args: &BenchmarkArgs, rpc_url: String) -> eyre::Result { info!("Running benchmark using data from RPC URL: {}", rpc_url); // Ensure that output directory is a directory if let Some(output) = &bench_args.output { if output.is_file() { return Err(eyre::eyre!("Output path must be a directory")); } } // set up alloy client for blocks let client = ClientBuilder::default().http(rpc_url.parse()?); let block_provider = RootProvider::::new(client); // If neither `--from` nor `--to` are provided, we will run the benchmark continuously, // starting at the latest block. let mut benchmark_mode = BenchMode::new(bench_args.from, bench_args.to)?; // construct the authenticated provider let auth_jwt = bench_args .auth_jwtsecret .clone() .ok_or_else(|| eyre::eyre!("--jwtsecret must be provided for authenticated RPC"))?; // fetch jwt from file // // the jwt is hex encoded so we will decode it after let jwt = std::fs::read_to_string(auth_jwt)?; let jwt = JwtSecret::from_hex(jwt)?; // get engine url let auth_url = Url::parse(&bench_args.engine_rpc_url)?; // construct the authed transport info!("Connecting to Engine RPC at {} for replay", auth_url); let auth_transport = AuthenticatedTransportConnect::new(auth_url, jwt); let client = ClientBuilder::default().connect_with(auth_transport).await?; let auth_provider = RootProvider::::new(client); let first_block = match benchmark_mode { BenchMode::Continuous => { // fetch Latest block block_provider.get_block_by_number(BlockNumberOrTag::Latest).full().await?.unwrap() } BenchMode::Range(ref mut range) => { match range.next() { Some(block_number) => { // fetch first block in range block_provider .get_block_by_number(block_number.into()) .full() .await? .unwrap() } None => { return Err(eyre::eyre!( "Benchmark mode range is empty, please provide a larger range" )); } } } }; let next_block = first_block.header.number + 1; Ok(Self { auth_provider, block_provider, benchmark_mode, next_block }) } }