Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
106 changes: 86 additions & 20 deletions bins/revme/src/cmd/bytecode.rs
Original file line number Diff line number Diff line change
@@ -1,42 +1,108 @@
use revm::{
interpreter::{analysis::validate_eof_inner, opcode::eof_printer::print_eof_code},
primitives::{Bytes, Eof},
interpreter::{
analysis::{validate_eof_inner, CodeType, EofError},
opcode::eof_printer::print_eof_code,
},
primitives::{Bytes, Eof, MAX_INITCODE_SIZE},
};
use std::io;
use structopt::StructOpt;

/// Statetest command
#[derive(StructOpt, Debug)]
pub struct Cmd {
/// Is EOF code in INITCODE mode.
#[structopt(long)]
eof_initcode: bool,
/// Is EOF code in RUNTIME mode.
#[structopt(long)]
eof_runtime: bool,
/// Bytecode in hex format. If bytes start with 0xFE it will be interpreted as a EOF.
/// Otherwise, it will be interpreted as a EOF bytecode.
#[structopt(required = true)]
bytes: String,
/// If not provided, it will operate in interactive EOF validation mode.
#[structopt()]
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 {
/// Run statetest command.
pub fn run(&self) {
let trimmed = self.bytes.trim_start_matches("0x");
let Ok(bytes) = hex::decode(trimmed) else {
eprintln!("Invalid hex string");
return;
let container_kind = if self.eof_initcode {
Some(CodeType::ReturnContract)
} else if self.eof_runtime {
Some(CodeType::ReturnOrStop)
} else {
None
};
let bytes: Bytes = bytes.into();
if bytes.is_empty() {
eprintln!("Empty hex string");

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 {
print_eof_code(&bytes)
}
return;
}
if bytes[0] == 0xEF {

// 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) => {
println!("Decoding: {:#?}", eof);
let res = validate_eof_inner(&eof, None);
println!("Validation: {:#?}", res);
}
Err(e) => eprintln!("Decoding Error: {:#?}", e),
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),
}
} else {
print_eof_code(&bytes)
}
}
}
2 changes: 1 addition & 1 deletion crates/interpreter/src/interpreter/analysis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -377,7 +377,7 @@ impl AccessTracker {

/// Types of code sections. It is a error if container to contain
/// both RETURNCONTRACT and either of RETURN or STOP.
#[derive(Clone, Debug, PartialEq, Eq)]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum CodeType {
/// Return contract code.
ReturnContract,
Expand Down