reth_bench/bench/
send_payload.rs
1use alloy_provider::network::AnyRpcBlock;
2use alloy_rpc_types_engine::ExecutionPayload;
3use clap::Parser;
4use eyre::{OptionExt, Result};
5use op_alloy_consensus::OpTxEnvelope;
6use reth_cli_runner::CliContext;
7use std::io::{BufReader, Read, Write};
8
9#[derive(Debug, Parser)]
12pub struct Command {
13 #[arg(short, long)]
15 path: Option<String>,
16
17 #[arg(
19 short,
20 long,
21 required_if_eq_any([("mode", "execute"), ("mode", "cast")]),
23 required_unless_present("mode")
25 )]
26 rpc_url: Option<String>,
27
28 #[arg(short, long)]
31 jwt_secret: Option<String>,
32
33 #[arg(long, default_value_t = 3)]
34 new_payload_version: u8,
35
36 #[arg(long, value_enum, default_value = "execute")]
38 mode: Mode,
39}
40
41#[derive(Debug, Clone, clap::ValueEnum)]
42enum Mode {
43 Execute,
46 Cast,
49 Json,
51}
52
53impl Command {
54 fn read_input(&self) -> Result<String> {
56 Ok(match &self.path {
57 Some(path) => reth_fs_util::read_to_string(path)?,
58 None => String::from_utf8(
59 BufReader::new(std::io::stdin()).bytes().collect::<Result<Vec<_>, _>>()?,
60 )?,
61 })
62 }
63
64 fn load_jwt_secret(&self) -> Result<Option<String>> {
66 match &self.jwt_secret {
67 Some(secret) => {
68 match std::fs::read_to_string(secret) {
70 Ok(contents) => Ok(Some(contents.trim().to_string())),
71 Err(_) => Ok(Some(secret.clone())),
73 }
74 }
75 None => Ok(None),
76 }
77 }
78
79 pub async fn execute(self, _ctx: CliContext) -> Result<()> {
81 let block_json = self.read_input()?;
83
84 let jwt_secret = self.load_jwt_secret()?;
86
87 let block = serde_json::from_str::<AnyRpcBlock>(&block_json)?
89 .into_inner()
90 .map_header(|header| header.map(|h| h.into_header_with_defaults()))
91 .try_map_transactions(|tx| {
92 tx.try_into_either::<OpTxEnvelope>()
94 })?
95 .into_consensus();
96
97 let parent_beacon_block_root = block.header.parent_beacon_block_root;
99
100 let blob_versioned_hashes =
102 block.body.blob_versioned_hashes_iter().copied().collect::<Vec<_>>();
103
104 let execution_payload = ExecutionPayload::from_block_slow(&block).0;
106
107 let json_request = serde_json::to_string(&(
109 execution_payload,
110 blob_versioned_hashes,
111 parent_beacon_block_root,
112 ))?;
113
114 match self.mode {
116 Mode::Execute => {
117 let mut command = std::process::Command::new("cast");
119 command.arg("rpc").arg("engine_newPayloadV3").arg("--raw");
120 if let Some(rpc_url) = self.rpc_url {
121 command.arg("--rpc-url").arg(rpc_url);
122 }
123 if let Some(secret) = &jwt_secret {
124 command.arg("--jwt-secret").arg(secret);
125 }
126
127 let mut process = command.stdin(std::process::Stdio::piped()).spawn()?;
129
130 process
132 .stdin
133 .take()
134 .ok_or_eyre("stdin not available")?
135 .write_all(json_request.as_bytes())?;
136
137 process.wait()?;
139 }
140 Mode::Cast => {
141 let mut cmd = format!(
142 "cast rpc engine_newPayloadV{} --raw '{}'",
143 self.new_payload_version, json_request
144 );
145
146 if let Some(rpc_url) = self.rpc_url {
147 cmd += &format!(" --rpc-url {}", rpc_url);
148 }
149 if let Some(secret) = &jwt_secret {
150 cmd += &format!(" --jwt-secret {}", secret);
151 }
152
153 println!("{cmd}");
154 }
155 Mode::Json => {
156 println!("{json_request}");
157 }
158 }
159
160 Ok(())
161 }
162}