reth_bench/bench/
context.rs1use crate::{authenticated_transport::AuthenticatedTransportConnect, bench_mode::BenchMode};
5use alloy_eips::BlockNumberOrTag;
6use alloy_provider::{network::AnyNetwork, Provider, RootProvider};
7use alloy_rpc_client::ClientBuilder;
8use alloy_rpc_types_engine::JwtSecret;
9use alloy_transport::layers::{RateLimitRetryPolicy, RetryBackoffLayer};
10use reqwest::Url;
11use reth_node_core::args::{BenchmarkArgs, WaitForPersistence};
12use tracing::info;
13
14pub(crate) struct BenchContext {
20 pub(crate) auth_provider: RootProvider<AnyNetwork>,
22 pub(crate) block_provider: RootProvider<AnyNetwork>,
24 pub(crate) benchmark_mode: BenchMode,
27 pub(crate) next_block: u64,
29 pub(crate) use_reth_namespace: bool,
31 pub(crate) rlp_blocks: bool,
33 pub(crate) wait_for_persistence: WaitForPersistence,
35 pub(crate) no_wait_for_caches: bool,
37}
38
39impl BenchContext {
40 pub(crate) async fn new(bench_args: &BenchmarkArgs, rpc_url: String) -> eyre::Result<Self> {
43 info!(target: "reth-bench", "Running benchmark using data from RPC URL: {}", rpc_url);
44
45 if let Some(output) = &bench_args.output {
47 if output.is_file() {
48 return Err(eyre::eyre!("Output path must be a directory"));
49 }
50 if !output.exists() {
52 std::fs::create_dir_all(output)?;
53 info!(target: "reth-bench", "Created output directory: {:?}", output);
54 }
55 }
56
57 let retry_policy = RateLimitRetryPolicy::default().or(|_| true);
59 let max_retries = bench_args.rpc_block_fetch_retries.as_max_retries();
60 let client = ClientBuilder::default()
61 .layer(RetryBackoffLayer::new_with_policy(max_retries, 800, u64::MAX, retry_policy))
62 .http(rpc_url.parse()?);
63 let block_provider = RootProvider::<AnyNetwork>::new(client);
64
65 let auth_jwt = bench_args
67 .auth_jwtsecret
68 .clone()
69 .ok_or_else(|| eyre::eyre!("--jwt-secret must be provided for authenticated RPC"))?;
70
71 let jwt = std::fs::read_to_string(auth_jwt)?;
75 let jwt = JwtSecret::from_hex(jwt)?;
76
77 let auth_url = Url::parse(&bench_args.engine_rpc_url)?;
79
80 info!(target: "reth-bench", "Connecting to Engine RPC at {} for replay", auth_url);
82 let auth_transport = AuthenticatedTransportConnect::new(auth_url, jwt);
83 let client = ClientBuilder::default().connect_with(auth_transport).await?;
84 let auth_provider = RootProvider::<AnyNetwork>::new(client);
85
86 let (from, to) = if let Some(advance) = bench_args.advance {
95 if advance == 0 {
96 return Err(eyre::eyre!("--advance must be greater than 0"));
97 }
98
99 let head_block = auth_provider
100 .get_block_by_number(BlockNumberOrTag::Latest)
101 .await?
102 .ok_or_else(|| eyre::eyre!("Failed to fetch latest block for --advance"))?;
103 let head_number = head_block.header.number;
104 (Some(head_number), Some(head_number + advance))
105 } else if bench_args.from.is_none() && bench_args.to.is_some() {
106 let head_block = auth_provider
107 .get_block_by_number(BlockNumberOrTag::Latest)
108 .await?
109 .ok_or_else(|| eyre::eyre!("Failed to fetch latest block from engine"))?;
110 let head_number = head_block.header.number;
111 info!(target: "reth-bench", "No --from provided, derived from engine head: {}", head_number);
112 (Some(head_number), bench_args.to)
113 } else {
114 (bench_args.from, bench_args.to)
115 };
116
117 let latest_block = block_provider
120 .get_block_by_number(BlockNumberOrTag::Latest)
121 .full()
122 .await?
123 .ok_or_else(|| eyre::eyre!("Failed to fetch latest block from RPC"))?;
124 let mut benchmark_mode = BenchMode::new(from, to, latest_block.into_inner().number());
125
126 let first_block = match benchmark_mode {
127 BenchMode::Continuous(start) => {
128 block_provider.get_block_by_number(start.into()).full().await?.ok_or_else(|| {
129 eyre::eyre!("Failed to fetch block {} from RPC for continuous mode", start)
130 })?
131 }
132 BenchMode::Range(ref mut range) => {
133 match range.next() {
134 Some(block_number) => {
135 block_provider
137 .get_block_by_number(block_number.into())
138 .full()
139 .await?
140 .ok_or_else(|| {
141 eyre::eyre!("Failed to fetch block {} from RPC", block_number)
142 })?
143 }
144 None => {
145 return Err(eyre::eyre!(
146 "Benchmark mode range is empty, please provide a larger range"
147 ));
148 }
149 }
150 }
151 };
152
153 let next_block = first_block.header.number + 1;
154 let rlp_blocks = bench_args.rlp_blocks;
155 let wait_for_persistence =
156 bench_args.wait_for_persistence.unwrap_or(WaitForPersistence::Never);
157 let use_reth_namespace = bench_args.reth_new_payload || rlp_blocks;
158 let no_wait_for_caches = bench_args.no_wait_for_caches;
159 Ok(Self {
160 auth_provider,
161 block_provider,
162 benchmark_mode,
163 next_block,
164 use_reth_namespace,
165 rlp_blocks,
166 wait_for_persistence,
167 no_wait_for_caches,
168 })
169 }
170}