reth_bench/bench/
context.rs

1//! This contains the [`BenchContext`], which is information that all replay-based benchmarks need.
2//! The initialization code is also the same, so this can be shared across benchmark commands.
3
4use crate::{authenticated_transport::AuthenticatedTransportConnect, bench_mode::BenchMode};
5use alloy_eips::BlockNumberOrTag;
6use alloy_provider::{network::AnyNetwork, Provider, ProviderBuilder, RootProvider};
7use alloy_rpc_client::ClientBuilder;
8use alloy_rpc_types_engine::JwtSecret;
9use alloy_transport::BoxTransport;
10use alloy_transport_http::Http;
11use reqwest::{Client, Url};
12use reth_node_core::args::BenchmarkArgs;
13use tracing::info;
14
15/// This is intended to be used by benchmarks that replay blocks from an RPC.
16///
17/// It contains an authenticated provider for engine API queries, a block provider for block
18/// queries, a [`BenchMode`] to determine whether the benchmark should run for a closed or open
19/// range of blocks, and the next block to fetch.
20pub(crate) struct BenchContext {
21    /// The auth provider used for engine API queries.
22    pub(crate) auth_provider: RootProvider<BoxTransport, AnyNetwork>,
23    /// The block provider used for block queries.
24    pub(crate) block_provider: RootProvider<Http<Client>, AnyNetwork>,
25    /// The benchmark mode, which defines whether the benchmark should run for a closed or open
26    /// range of blocks.
27    pub(crate) benchmark_mode: BenchMode,
28    /// The next block to fetch.
29    pub(crate) next_block: u64,
30}
31
32impl BenchContext {
33    /// This is the initialization code for most benchmarks, taking in a [`BenchmarkArgs`] and
34    /// returning the providers needed to run a benchmark.
35    pub(crate) async fn new(bench_args: &BenchmarkArgs, rpc_url: String) -> eyre::Result<Self> {
36        info!("Running benchmark using data from RPC URL: {}", rpc_url);
37
38        // Ensure that output directory is a directory
39        if let Some(output) = &bench_args.output {
40            if output.is_file() {
41                return Err(eyre::eyre!("Output path must be a directory"));
42            }
43        }
44
45        // set up alloy client for blocks
46        let block_provider =
47            ProviderBuilder::new().network::<AnyNetwork>().on_http(rpc_url.parse()?);
48
49        // If neither `--from` nor `--to` are provided, we will run the benchmark continuously,
50        // starting at the latest block.
51        let mut benchmark_mode = BenchMode::new(bench_args.from, bench_args.to)?;
52
53        // construct the authenticated provider
54        let auth_jwt = bench_args
55            .auth_jwtsecret
56            .clone()
57            .ok_or_else(|| eyre::eyre!("--jwtsecret must be provided for authenticated RPC"))?;
58
59        // fetch jwt from file
60        //
61        // the jwt is hex encoded so we will decode it after
62        let jwt = std::fs::read_to_string(auth_jwt)?;
63        let jwt = JwtSecret::from_hex(jwt)?;
64
65        // get engine url
66        let auth_url = Url::parse(&bench_args.engine_rpc_url)?;
67
68        // construct the authed transport
69        info!("Connecting to Engine RPC at {} for replay", auth_url);
70        let auth_transport = AuthenticatedTransportConnect::new(auth_url, jwt);
71        let client = ClientBuilder::default().connect_boxed(auth_transport).await?;
72        let auth_provider = RootProvider::<_, AnyNetwork>::new(client);
73
74        let first_block = match benchmark_mode {
75            BenchMode::Continuous => {
76                // fetch Latest block
77                block_provider
78                    .get_block_by_number(BlockNumberOrTag::Latest, true.into())
79                    .await?
80                    .unwrap()
81            }
82            BenchMode::Range(ref mut range) => {
83                match range.next() {
84                    Some(block_number) => {
85                        // fetch first block in range
86                        block_provider
87                            .get_block_by_number(block_number.into(), true.into())
88                            .await?
89                            .unwrap()
90                    }
91                    None => {
92                        return Err(eyre::eyre!(
93                            "Benchmark mode range is empty, please provide a larger range"
94                        ));
95                    }
96                }
97            }
98        };
99
100        let next_block = first_block.header.number + 1;
101        Ok(Self { auth_provider, block_provider, benchmark_mode, next_block })
102    }
103}