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