revme/cmd/
bytecode.rs

1use bytecode::{validate_eof_inner, Eof};
2use clap::Parser;
3use revm::{
4    bytecode::eof::{self, validate_raw_eof_inner, CodeType, EofError},
5    primitives::{hex, Bytes},
6};
7use std::io;
8
9/// `bytecode` subcommand.
10#[derive(Parser, Debug)]
11pub struct Cmd {
12    /// Is EOF code in INITCODE mode.
13    #[arg(long)]
14    eof_initcode: bool,
15    /// Is EOF code in RUNTIME mode.
16    #[arg(long)]
17    eof_runtime: bool,
18    /// Bytecode in hex format string.
19    ///
20    /// - If bytes start with 0xFE it will be interpreted as a EOF.
21    /// - Otherwise, it will be interpreted as a EOF bytecode.
22    /// - If not provided, it will operate in interactive EOF validation mode.
23    #[arg()]
24    bytes: Option<String>,
25}
26
27#[inline]
28fn trim_decode(input: &str) -> Option<Bytes> {
29    let trimmed = input.trim().trim_start_matches("0x");
30    let decoded = hex::decode(trimmed).ok().map(Into::into);
31    if decoded.is_none() {
32        eprintln!("Invalid hex string");
33        return None;
34    }
35    decoded
36}
37
38impl Cmd {
39    /// Runs statetest command.
40    pub fn run(&self) {
41        let container_kind = if self.eof_initcode {
42            Some(CodeType::Initcode)
43        } else if self.eof_runtime {
44            Some(CodeType::Runtime)
45        } else {
46            None
47        };
48
49        if let Some(input_bytes) = &self.bytes {
50            let Some(bytes) = trim_decode(input_bytes) else {
51                return;
52            };
53
54            if bytes[0] == 0xEF {
55                match Eof::decode(bytes) {
56                    Ok(eof) => {
57                        println!("Decoding: {:#?}", eof);
58                        match validate_eof_inner(&eof, container_kind) {
59                            Ok(_) => {
60                                println!("Validation: OK");
61                            }
62                            Err(eof_error) => {
63                                eprintln!("Validation error: {}", eof_error);
64                            }
65                        }
66                        println!("Validation: OK");
67                    }
68                    Err(eof_error) => {
69                        eprintln!("Decoding error: {}", eof_error);
70                    }
71                }
72            } else {
73                eof::printer::print(&bytes)
74            }
75            return;
76        }
77
78        // Else run command in loop.
79        loop {
80            let mut input = String::new();
81            io::stdin().read_line(&mut input).expect("Input Error");
82            if input.len() == 1 {
83                // Just a newline, so exit
84                return;
85            }
86            let Some(bytes) = trim_decode(&input) else {
87                return;
88            };
89            match validate_raw_eof_inner(bytes, container_kind) {
90                Ok(eof) => {
91                    println!(
92                        "OK {}/{}/{}",
93                        eof.body.code_section.len(),
94                        eof.body.container_section.len(),
95                        eof.body.data_section.len()
96                    );
97                }
98                Err(eof_error) => {
99                    if matches!(
100                        eof_error,
101                        EofError::Decode(eof::EofDecodeError::InvalidEOFSize)
102                    ) {
103                        continue;
104                    }
105                    println!("err: {}", eof_error);
106                }
107            }
108        }
109    }
110}