-
Notifications
You must be signed in to change notification settings - Fork 644
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* feat: add evm script add a script which can run arbitrary binaries * fix lint * move evm runner script to `revme` subcommand * cargo fmt * cli byecode,input,path, state options added, output result
- Loading branch information
1 parent
ef64e4d
commit a89daef
Showing
4 changed files
with
117 additions
and
0 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
use revm::{ | ||
db::BenchmarkDB, | ||
primitives::{Address, Bytecode, TransactTo}, | ||
Evm, | ||
}; | ||
use std::io::Error as IoError; | ||
use std::path::PathBuf; | ||
use std::time::Duration; | ||
use std::{borrow::Cow, fs}; | ||
use structopt::StructOpt; | ||
|
||
extern crate alloc; | ||
|
||
#[derive(Debug, thiserror::Error)] | ||
pub enum Errors { | ||
#[error("The specified path does not exist")] | ||
PathNotExists, | ||
#[error("Invalid bytecode")] | ||
InvalidBytecode, | ||
#[error("Invalid input")] | ||
InvalidInput, | ||
#[error("EVM Error")] | ||
EVMError, | ||
#[error(transparent)] | ||
Io(IoError), | ||
} | ||
|
||
impl From<IoError> for Errors { | ||
fn from(e: IoError) -> Self { | ||
Errors::Io(e) | ||
} | ||
} | ||
|
||
/// Evm runner command allows running arbitrary evm bytecode. | ||
/// Bytecode can be provided from cli or from file with --path option. | ||
#[derive(StructOpt, Debug)] | ||
pub struct Cmd { | ||
/// Bytecode to be executed. | ||
#[structopt(default_value = "")] | ||
bytecode: String, | ||
/// Path to file containing the evm bytecode. | ||
/// Overrides the bytecode option. | ||
#[structopt(long)] | ||
path: Option<PathBuf>, | ||
/// Run in benchmarking mode. | ||
#[structopt(long)] | ||
bench: bool, | ||
/// Input bytes. | ||
#[structopt(long, default_value = "")] | ||
input: String, | ||
/// Print the state. | ||
#[structopt(long)] | ||
state: bool, | ||
} | ||
|
||
impl Cmd { | ||
/// Run statetest command. | ||
pub fn run(&self) -> Result<(), Errors> { | ||
let bytecode_str: Cow<'_, str> = if let Some(path) = &self.path { | ||
// check if path exists. | ||
if !path.exists() { | ||
return Err(Errors::PathNotExists); | ||
} | ||
fs::read_to_string(path)?.to_owned().into() | ||
} else { | ||
self.bytecode.as_str().into() | ||
}; | ||
|
||
let bytecode = hex::decode(bytecode_str.trim()).map_err(|_| Errors::InvalidBytecode)?; | ||
let input = hex::decode(self.input.trim()) | ||
.map_err(|_| Errors::InvalidInput)? | ||
.into(); | ||
// BenchmarkDB is dummy state that implements Database trait. | ||
// the bytecode is deployed at zero address. | ||
let mut evm = Evm::builder() | ||
.with_db(BenchmarkDB::new_bytecode(Bytecode::new_raw( | ||
bytecode.into(), | ||
))) | ||
.modify_tx_env(|tx| { | ||
// execution globals block hash/gas_limit/coinbase/timestamp.. | ||
tx.caller = "0x0000000000000000000000000000000000000001" | ||
.parse() | ||
.unwrap(); | ||
tx.transact_to = TransactTo::Call(Address::ZERO); | ||
tx.data = input; | ||
}) | ||
.build(); | ||
|
||
if self.bench { | ||
// Microbenchmark | ||
let bench_options = microbench::Options::default().time(Duration::from_secs(3)); | ||
|
||
microbench::bench(&bench_options, "Run bytecode", || { | ||
let _ = evm.transact().unwrap(); | ||
}); | ||
} else { | ||
let out = evm.transact().map_err(|_| Errors::EVMError)?; | ||
println!("Result: {:#?}", out.result); | ||
if self.state { | ||
println!("State: {:#?}", out.state); | ||
} | ||
} | ||
Ok(()) | ||
} | ||
} |