reth_bench/bench/
send_payload.rs1use super::helpers::{load_jwt_secret, read_input};
2use alloy_consensus::TxEnvelope;
3use alloy_provider::network::AnyRpcBlock;
4use alloy_rpc_types_engine::ExecutionPayload;
5use clap::Parser;
6use eyre::{OptionExt, Result};
7use reth_cli_runner::CliContext;
8use std::io::Write;
9
10#[derive(Debug, Parser)]
13pub struct Command {
14 #[arg(short, long)]
16 path: Option<String>,
17
18 #[arg(
20 short,
21 long,
22 required_if_eq_any([("mode", "execute"), ("mode", "cast")]),
24 required_unless_present("mode")
26 )]
27 rpc_url: Option<String>,
28
29 #[arg(short, long)]
32 jwt_secret: Option<String>,
33
34 #[arg(long, default_value_t = 3)]
35 new_payload_version: u8,
36
37 #[arg(long, value_enum, default_value = "execute")]
39 mode: Mode,
40}
41
42#[derive(Debug, Clone, clap::ValueEnum)]
43enum Mode {
44 Execute,
47 Cast,
50 Json,
52}
53
54impl Command {
55 pub async fn execute(self, _ctx: CliContext) -> Result<()> {
57 let block_json = read_input(self.path.as_deref())?;
59
60 let jwt_secret = load_jwt_secret(self.jwt_secret.as_deref())?;
62
63 let block = serde_json::from_str::<AnyRpcBlock>(&block_json)?
65 .into_inner()
66 .map_header(|header| header.map(|h| h.into_header_with_defaults()))
67 .try_map_transactions(|tx| -> eyre::Result<TxEnvelope> {
68 tx.try_into().map_err(|_| eyre::eyre!("unsupported tx type"))
69 })?
70 .into_consensus();
71
72 let parent_beacon_block_root = block.header.parent_beacon_block_root;
74
75 let blob_versioned_hashes =
77 block.body.blob_versioned_hashes_iter().copied().collect::<Vec<_>>();
78
79 let execution_payload = ExecutionPayload::from_block_slow(&block).0;
81
82 let use_v4 = block.header.requests_hash.is_some();
83
84 let json_request = if use_v4 {
86 serde_json::to_string(&(
87 execution_payload,
88 blob_versioned_hashes,
89 parent_beacon_block_root,
90 block.header.requests_hash.unwrap_or_default(),
91 ))?
92 } else {
93 serde_json::to_string(&(
94 execution_payload,
95 blob_versioned_hashes,
96 parent_beacon_block_root,
97 ))?
98 };
99
100 match self.mode {
102 Mode::Execute => {
103 let mut command = std::process::Command::new("cast");
105 let method = if use_v4 { "engine_newPayloadV4" } else { "engine_newPayloadV3" };
106 command.arg("rpc").arg(method).arg("--raw");
107 if let Some(rpc_url) = self.rpc_url {
108 command.arg("--rpc-url").arg(rpc_url);
109 }
110 if let Some(secret) = &jwt_secret {
111 command.arg("--jwt-secret").arg(secret);
112 }
113
114 let mut process = command.stdin(std::process::Stdio::piped()).spawn()?;
116
117 process
119 .stdin
120 .take()
121 .ok_or_eyre("stdin not available")?
122 .write_all(json_request.as_bytes())?;
123
124 process.wait()?;
126 }
127 Mode::Cast => {
128 let mut cmd = format!(
129 "cast rpc engine_newPayloadV{} --raw '{}'",
130 self.new_payload_version, json_request
131 );
132
133 if let Some(rpc_url) = self.rpc_url {
134 cmd += &format!(" --rpc-url {rpc_url}");
135 }
136 if let Some(secret) = &jwt_secret {
137 cmd += &format!(" --jwt-secret {secret}");
138 }
139
140 println!("{cmd}");
141 }
142 Mode::Json => {
143 println!("{json_request}");
144 }
145 }
146
147 Ok(())
148 }
149}