Skip to content

Commit

Permalink
✨ EVM Diff tests
Browse files Browse the repository at this point in the history
  • Loading branch information
clabby committed Sep 23, 2023
1 parent bb81005 commit e185126
Show file tree
Hide file tree
Showing 7 changed files with 128 additions and 16 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions crates/mipsevm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,21 @@ version.workspace = true
authors.workspace = true

[dependencies]
preimage-oracle = { path = "../preimage" }
alloy-primitives = "0.3.3"
alloy-sol-types = "0.3.2"
once_cell = "1.18.0"
serde = { version = "1.0.188", features = ["derive"] }
serde_json = "1.0.106"
fnv = "1.0.7"
revm = { version = "3.3.0", features = ["no_gas_measuring"] }
preimage-oracle = { path = "../preimage" }
cfg-if = "1.0.0"

# misc
anyhow = "1.0.75"
tracing = "0.1.37"

[dev-dependencies]
revm = { version = "3.3.0", features = ["no_gas_measuring"] }
rand = "0.8.5"
criterion = { version = "0.5.1", features = ["html_reports"] }

Expand Down
2 changes: 0 additions & 2 deletions crates/mipsevm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,5 @@ pub use types::{Address, Fd, Gindex, Page, PageIndex, StateWitness, VMStatus};
mod mips;
pub use mips::InstrumentedState;

mod evm;

#[cfg(test)]
mod test_utils;
7 changes: 1 addition & 6 deletions crates/mipsevm/src/mips/instrumented.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,14 +107,9 @@ where
mod test {
use crate::test_utils::StaticOracle;

/// Used in tests to write the results to
const BASE_ADDR_END: u32 = 0xBF_FF_FF_F0;

/// Used as the return-address for tests
const END_ADDR: u32 = 0xA7_EF_00_D0;

mod open_mips {
use super::*;
use crate::test_utils::{BASE_ADDR_END, END_ADDR};
use crate::{Address, InstrumentedState, Memory, State};
use std::{
cell::RefCell,
Expand Down
2 changes: 1 addition & 1 deletion crates/mipsevm/src/mips/mips_vm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ where
/// - A [Result] indicating if the operation was successful.
pub(crate) fn track_mem_access(&mut self, effective_address: Address) -> Result<()> {
if self.mem_proof_enabled && self.last_mem_access != effective_address {
if self.last_mem_access != Address::MAX {
if self.last_mem_access as u32 != u32::MAX {
anyhow::bail!("Unexpected diffrent memory access at {:x}, already have access at {:x} buffered", effective_address, self.last_mem_access);
}

Expand Down
118 changes: 114 additions & 4 deletions crates/mipsevm/src/evm.rs → crates/mipsevm/src/test_utils/evm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ pub const MIPS_ADDR: [u8; 20] = hex!("000000000000000000000000000000000000C0DE")
pub const PREIMAGE_ORACLE_ADDR: [u8; 20] = hex!("00000000000000000000000000000000424f4f4b");

/// The creation EVM bytecode of the MIPS contract. Does not include constructor arguments.
pub const MIPS_CREATION_CODE: &str = include_str!("../bindings/mips_creation.bin");
pub const MIPS_CREATION_CODE: &str = include_str!("../../bindings/mips_creation.bin");
/// The deployed EVM bytecode of the PreimageOracle contract.
pub const PREIMAGE_ORACLE_DEPLOYED_CODE: &str =
include_str!("../bindings/preimage_oracle_deployed.bin");
include_str!("../../bindings/preimage_oracle_deployed.bin");

/// A wrapper around a [revm] inspector with an in-memory backend that has the MIPS & PreimageOracle
/// smart contracts deployed at deterministic addresses. This is used for differential testing the
Expand Down Expand Up @@ -104,7 +104,7 @@ impl MipsEVM<CacheDB<EmptyDB>> {
/// ### Returns
/// - A [Result] containing the post-state hash of the MIPS VM or an error returned during
/// execution.
pub fn step(&mut self, witness: StepWitness) -> Result<B256> {
pub fn step(&mut self, witness: StepWitness) -> Result<StateWitness> {
if witness.has_preimage() {
#[cfg(feature = "tracing")]
tracing::info!(
Expand Down Expand Up @@ -172,7 +172,7 @@ impl MipsEVM<CacheDB<EmptyDB>> {
);
}

Ok(output)
Ok(post_state)
} else {
anyhow::bail!("Failed to step MIPS contract");
}
Expand Down Expand Up @@ -222,7 +222,18 @@ impl MipsEVM<CacheDB<EmptyDB>> {
#[cfg(test)]
mod test {
use super::*;
use crate::{
test_utils::{StaticOracle, BASE_ADDR_END, END_ADDR},
Address, InstrumentedState, Memory, State,
};
use revm::primitives::ExecutionResult;
use std::{
cell::RefCell,
fs,
io::{self, BufReader},
path::PathBuf,
rc::Rc,
};

#[test]
fn sanity_evm_execution() {
Expand Down Expand Up @@ -257,4 +268,103 @@ mod test {
))
);
}

#[test]
fn evm() {
// todo
let mut mips_evm = MipsEVM::new();
mips_evm.try_init().unwrap();

let tests_path = PathBuf::from(std::env::current_dir().unwrap())
.join("open_mips_tests")
.join("test")
.join("bin");
let test_files = fs::read_dir(tests_path).unwrap();

for f in test_files.into_iter() {
if let Ok(f) = f {
let file_name = String::from(f.file_name().to_str().unwrap());
println!(" -> Running test: {file_name}");

if file_name.starts_with("oracle") {
println!("skipping oracle test");
continue;
}

// Short circuit early for `exit_group.bin`
let exit_group = file_name == "exit_group.bin";

let program_mem = fs::read(f.path()).unwrap();

let mut state = {
let mut state = State::default();
state.pc = 0;
state.next_pc = 4;
state.memory = Rc::new(RefCell::new(Memory::default()));
state
};
state
.memory
.borrow_mut()
.set_memory_range(0, BufReader::new(program_mem.as_slice()))
.unwrap();

// Set the return address ($ra) to jump into when the test completes.
state.registers[31] = END_ADDR;

let mut instrumented = InstrumentedState::new(
state,
StaticOracle::new(b"hello world".to_vec()),
io::stdout(),
io::stderr(),
);

for _ in 0..1000 {
if instrumented.state.pc == END_ADDR {
break;
}
if exit_group && instrumented.state.exited {
break;
}

let instruction = instrumented
.state
.memory
.borrow_mut()
.get_memory(instrumented.state.pc as Address)
.unwrap();
println!(
"{}",
format!(
"step: {} pc: 0x{:08x} insn: 0x{:08x}",
instrumented.state.step, instrumented.state.pc, instruction
)
);

let step_witness = instrumented.step(true).unwrap().unwrap();

// Verify that the post state matches
let evm_post = mips_evm.step(step_witness).unwrap();
let rust_post = instrumented.state.encode_witness().unwrap();

assert_eq!(evm_post, rust_post);
}

if exit_group {
assert_ne!(END_ADDR, instrumented.state.pc, "must not reach end");
assert!(instrumented.state.exited, "must exit");
assert_eq!(1, instrumented.state.exit_code, "must exit with 1");
} else {
assert_eq!(END_ADDR, instrumented.state.pc, "must reach end");
let mut state = instrumented.state.memory.borrow_mut();
let (done, result) = (
state.get_memory((BASE_ADDR_END + 4) as Address).unwrap(),
state.get_memory((BASE_ADDR_END + 8) as Address).unwrap(),
);
assert_eq!(done, 1, "must set done to 1");
assert_eq!(result, 1, "must have success result {:?}", f.file_name());
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
//! Testing utilities.

use crate::PreimageOracle;
use alloy_primitives::B256;
use preimage_oracle::{Keccak256Key, Key};

use crate::PreimageOracle;
pub mod evm;

/// Used in tests to write the results to
pub const BASE_ADDR_END: u32 = 0xBF_FF_FF_F0;

/// Used as the return-address for tests
pub const END_ADDR: u32 = 0xA7_EF_00_D0;

pub struct StaticOracle {
preimage_data: Vec<u8>,
Expand Down

0 comments on commit e185126

Please sign in to comment.