Skip to main content

cast/cmd/
b2e_payload.rs

1//! Command Line handler to convert Beacon block's execution payload to Execution format.
2
3use alloy_rpc_types_beacon::payload::BeaconBlockData;
4use clap::Parser;
5use eyre::{Result, eyre};
6use foundry_common::{fs, sh_print};
7
8/// CLI arguments for `cast b2e-payload`, convert Beacon block's execution payload to Execution
9/// format.
10#[derive(Parser)]
11pub struct B2EPayloadArgs {
12    /// Input data, it can be either a file path to JSON file or raw JSON string containing the
13    /// beacon block
14    #[arg(
15        value_name = "INPUT",
16        help = "File path to JSON file or raw JSON string containing the beacon block"
17    )]
18    pub input: String,
19}
20
21impl B2EPayloadArgs {
22    pub async fn run(self) -> Result<()> {
23        let json = read_input(self.input)?;
24        let beacon_block_data: BeaconBlockData = serde_json::from_str(&json)
25            .map_err(|e| eyre!("Failed to parse beacon block JSON: {}", e))?;
26        let output = serde_json::to_string(&beacon_block_data.execution_payload())
27            .map_err(|e| eyre!("Failed to serialize execution payload: {}", e))?;
28        sh_print!("{}", output)?;
29        Ok(())
30    }
31}
32
33/// Returns `input` if it is raw JSON, otherwise reads it as a file path.
34fn read_input(input: String) -> Result<String> {
35    if serde_json::from_str::<serde_json::Value>(&input).is_ok() {
36        return Ok(input);
37    }
38    fs::read_to_string(&input).map_err(|e| eyre!("Failed to read JSON file '{input}': {e}"))
39}
40
41#[cfg(test)]
42mod tests {
43    use super::*;
44
45    #[test]
46    fn read_input_prefers_raw_json_over_paths() {
47        let json = r#"{"execution_payload": {"block_hash": "0x123"}}"#;
48        assert_eq!(read_input(json.to_string()).unwrap(), json);
49        let json = r#"[{"block": "data"}]"#;
50        assert_eq!(read_input(json.to_string()).unwrap(), json);
51
52        let file = tempfile::NamedTempFile::new().unwrap();
53        std::fs::write(file.path(), json).unwrap();
54        assert_eq!(read_input(file.path().to_string_lossy().into_owned()).unwrap(), json);
55
56        let err = read_input("not-json-{".to_string()).unwrap_err().to_string();
57        assert!(err.starts_with("Failed to read JSON file 'not-json-{'"), "{err}");
58    }
59}