reth_bench/bench/
send_payload.rs1use super::helpers::{load_jwt_secret, read_input};
2use alloy_provider::network::AnyRpcBlock;
3use alloy_rpc_types_engine::ExecutionPayload;
4use clap::Parser;
5use eyre::{OptionExt, Result};
6use op_alloy_consensus::OpTxEnvelope;
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| {
68 tx.try_into_either::<OpTxEnvelope>()
70 })?
71 .into_consensus();
72
73 let parent_beacon_block_root = block.header.parent_beacon_block_root;
75
76 let blob_versioned_hashes =
78 block.body.blob_versioned_hashes_iter().copied().collect::<Vec<_>>();
79
80 let execution_payload = ExecutionPayload::from_block_slow(&block).0;
82
83 let use_v4 = block.header.requests_hash.is_some();
84
85 let json_request = if use_v4 {
87 serde_json::to_string(&(
88 execution_payload,
89 blob_versioned_hashes,
90 parent_beacon_block_root,
91 block.header.requests_hash.unwrap_or_default(),
92 ))?
93 } else {
94 serde_json::to_string(&(
95 execution_payload,
96 blob_versioned_hashes,
97 parent_beacon_block_root,
98 ))?
99 };
100
101 match self.mode {
103 Mode::Execute => {
104 let mut command = std::process::Command::new("cast");
106 let method = if use_v4 { "engine_newPayloadV4" } else { "engine_newPayloadV3" };
107 command.arg("rpc").arg(method).arg("--raw");
108 if let Some(rpc_url) = self.rpc_url {
109 command.arg("--rpc-url").arg(rpc_url);
110 }
111 if let Some(secret) = &jwt_secret {
112 command.arg("--jwt-secret").arg(secret);
113 }
114
115 let mut process = command.stdin(std::process::Stdio::piped()).spawn()?;
117
118 process
120 .stdin
121 .take()
122 .ok_or_eyre("stdin not available")?
123 .write_all(json_request.as_bytes())?;
124
125 process.wait()?;
127 }
128 Mode::Cast => {
129 let mut cmd = format!(
130 "cast rpc engine_newPayloadV{} --raw '{}'",
131 self.new_payload_version, json_request
132 );
133
134 if let Some(rpc_url) = self.rpc_url {
135 cmd += &format!(" --rpc-url {rpc_url}");
136 }
137 if let Some(secret) = &jwt_secret {
138 cmd += &format!(" --jwt-secret {secret}");
139 }
140
141 println!("{cmd}");
142 }
143 Mode::Json => {
144 println!("{json_request}");
145 }
146 }
147
148 Ok(())
149 }
150}