Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Stable tracer interface #46

Merged
merged 63 commits into from
Aug 28, 2024
Merged
Show file tree
Hide file tree
Changes from 38 commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
17a9d33
interface draft
joonazan Jun 25, 2024
6711c48
depend on tracer interface
joonazan Jul 26, 2024
f9c3c45
WIP
joonazan Jul 30, 2024
fab16a5
the easy part of tracers
joonazan Jul 30, 2024
3392160
store program counter inside vm
joonazan Jul 31, 2024
1fddab9
add license
joonazan Jul 31, 2024
048526f
make the previous frame not look like a panic
joonazan Aug 1, 2024
76d0b2b
jump returns next instruction, not the one after that
joonazan Aug 1, 2024
21686b9
fix trace compilation
joonazan Aug 1, 2024
8cbcc22
move comment to right place
joonazan Aug 5, 2024
331253d
unrename u256 to primitive types
joonazan Aug 5, 2024
23a782b
zero-cost tracers
joonazan Aug 5, 2024
a03ac29
fix traces
joonazan Aug 5, 2024
b77f09f
remove clone
joonazan Aug 6, 2024
7bfce11
make all opcodes part of the tracer interface
joonazan Aug 6, 2024
abf0aed
clearer naming for InstructionResult
joonazan Aug 6, 2024
ee2c503
cargo fmt
joonazan Aug 6, 2024
d015137
fix tracers so they actually work; add tests
joonazan Aug 7, 2024
3eea939
document the strategy for extending the interface
joonazan Aug 8, 2024
5adab73
make tracers *actually* work
joonazan Aug 8, 2024
63c708c
fix test compilation
joonazan Aug 9, 2024
b3c834c
simplify Cargo.toml
joonazan Aug 9, 2024
33ffc4a
change todo to unimplemented
joonazan Aug 9, 2024
43fd7dd
remove default is_kernel impl
joonazan Aug 9, 2024
2daea31
add missing method
joonazan Aug 9, 2024
ce4ba4b
separate methods for aux heap
joonazan Aug 14, 2024
f0113e0
NotifyTracer to vm; expose forall_opcodes
joonazan Aug 14, 2024
01d77c5
write test for callframe picking and fix bugs
joonazan Aug 14, 2024
ee09fd2
better name for context_u128
joonazan Aug 15, 2024
481ce54
fix previous
joonazan Aug 15, 2024
5757076
trace Nop when running a disabled instruction
joonazan Aug 15, 2024
16d8603
more ergornomic tracer interface
joonazan Aug 19, 2024
bd17a32
update docs on how to extend the interface
joonazan Aug 19, 2024
717120f
expose farcall and ret variants
joonazan Aug 19, 2024
373be9d
remove static heap; nobody uses it
joonazan Aug 19, 2024
b4b0b72
appease clippy
joonazan Aug 19, 2024
439338e
remove problematic storage access for now
joonazan Aug 19, 2024
58961c6
remove run_arbitrary_code
joonazan Aug 19, 2024
609450b
expose tracer interface via VM for convenience
joonazan Aug 19, 2024
bf5866e
better document Tracer
joonazan Aug 19, 2024
139f486
replace const u8 with meaningful trait
joonazan Aug 19, 2024
32fee21
fix tests
joonazan Aug 20, 2024
58e6352
hide pc
joonazan Aug 20, 2024
0026891
add derives to Opcode
joonazan Aug 20, 2024
18e3671
prevent resuming after execution ends
joonazan Aug 20, 2024
63b40ce
save pc in snapshots
joonazan Aug 20, 2024
36b6690
statically dispatch World
joonazan Aug 21, 2024
af08176
clippy
joonazan Aug 21, 2024
0e30b0d
don't care about type complexity of tests
joonazan Aug 21, 2024
ea4659d
take metadata from workspace
joonazan Aug 22, 2024
2529495
properly inherit from workspace
joonazan Aug 22, 2024
fa11e78
inline Stack::set
joonazan Aug 22, 2024
6811a52
inline more
joonazan Aug 22, 2024
c339dde
inline bitset
joonazan Aug 22, 2024
ecda98d
resolve conflict with segmented heap
joonazan Aug 23, 2024
37e86e0
fix clippy
joonazan Aug 23, 2024
2cc5587
trace panic when farcall fails
joonazan Aug 26, 2024
c640a06
improved comment
joonazan Aug 26, 2024
e448ac7
move code from dispatch to boilerplate
joonazan Aug 26, 2024
37e0cff
Merge branch 'master' into stable-tracer-interface
joonazan Aug 27, 2024
3126fb0
clean up
joonazan Aug 27, 2024
f4bf057
derive Hash for Opcode
joonazan Aug 28, 2024
55a1829
fix bug: calling before_instruction instead of after
joonazan Aug 28, 2024
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
9 changes: 9 additions & 0 deletions Cargo.lock

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

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ license = "MIT OR Apache-2.0"
authors = ["The Matter Labs Team <[email protected]>"]

[dependencies]
eravm-stable-interface = { path = "./eravm-stable-interface" }
zkevm_opcode_defs = "0.150.0"
zk_evm_abstractions = "0.150.0"
u256 = { package = "primitive-types", version = "0.12.1" }
Expand All @@ -32,4 +33,4 @@ trace = []
single_instruction_test = ["arbitrary", "u256/arbitrary", "zk_evm", "anyhow"]

[workspace]
members = [".", "afl-fuzz"]
members = [".", "afl-fuzz", "eravm-stable-interface"]
3 changes: 3 additions & 0 deletions afl-fuzz/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ pretty_assertions = "1.4.0"
path = ".."
features = ["single_instruction_test"]

[dependencies.eravm-stable-interface]
path = "../eravm-stable-interface"

[[bin]]
name = "show_testcase"
path = "src/show_testcase.rs"
Expand Down
2 changes: 1 addition & 1 deletion afl-fuzz/src/check_input_size.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ fn main() {
const BYTES_GIVEN: usize = 10000;
let data = [0xFF; BYTES_GIVEN];
let mut u = arbitrary::Unstructured::new(&data);
let _: VmAndWorld = u.arbitrary().unwrap();
let _: VmAndWorld<()> = u.arbitrary().unwrap();
println!("{:?}", BYTES_GIVEN - u.len());
}
5 changes: 3 additions & 2 deletions afl-fuzz/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
use arbitrary::Arbitrary;
use eravm_stable_interface::Tracer;
use vm2::{single_instruction_test::MockWorld, VirtualMachine};

#[derive(Arbitrary, Debug)]
pub struct VmAndWorld {
pub vm: VirtualMachine,
pub struct VmAndWorld<T: Tracer> {
pub vm: VirtualMachine<T>,
pub world: MockWorld,
}
10 changes: 3 additions & 7 deletions afl-fuzz/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,9 @@ fn main() {
// Tests that running one instruction and converting to zk_evm produces the same result as
// first converting to zk_evm and then running one instruction.

let mut zk_evm = vm2_to_zk_evm(
&vm,
world.clone(),
vm.state.current_frame.pc_from_u16(0).unwrap(),
);
let mut zk_evm = vm2_to_zk_evm(&vm, world.clone());

let pc = vm.run_single_instruction(&mut world).unwrap();
vm.run_single_instruction(&mut world, &mut ());
assert!(vm.is_in_valid_state());

add_heap_to_zk_evm(&mut zk_evm, &vm);
Expand All @@ -29,7 +25,7 @@ fn main() {

assert_eq!(
UniversalVmState::from(zk_evm),
vm2_to_zk_evm(&vm, world.clone(), pc).into()
vm2_to_zk_evm(&vm, world.clone()).into()
);
}
}
Expand Down
10 changes: 3 additions & 7 deletions afl-fuzz/src/show_testcase.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,13 @@ fn main() {
println!("{:?}", vm.state);
assert!(vm.is_in_valid_state());

let mut zk_evm = vm2_to_zk_evm(
&vm,
world.clone(),
vm.state.current_frame.pc_from_u16(0).unwrap(),
);
let mut zk_evm = vm2_to_zk_evm(&vm, world.clone());

let (parsed, _) = EncodingModeProduction::parse_preliminary_variant_and_absolute_number(
vm.state.current_frame.raw_first_instruction(),
);
println!("{}", parsed);
let pc = vm.run_single_instruction(&mut world).unwrap();
vm.run_single_instruction(&mut world, &mut ());

println!("Mocks that have been touched:");
vm.print_mock_info();
Expand All @@ -49,6 +45,6 @@ fn main() {

assert_eq!(
UniversalVmState::from(zk_evm),
vm2_to_zk_evm(&vm, world.clone(), pc).into()
vm2_to_zk_evm(&vm, world.clone()).into()
);
}
4 changes: 2 additions & 2 deletions benches/nested_near_call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ fn nested_near_call(bencher: Bencher) {
},
);

vm.run(black_box(&mut world));
vm.run(black_box(&mut world), &mut ());
});
}

Expand Down Expand Up @@ -87,7 +87,7 @@ fn nested_near_call_with_storage_write(bencher: Bencher) {
},
);

vm.run(black_box(&mut world));
vm.run(black_box(&mut world), &mut ());
});
}

Expand Down
9 changes: 9 additions & 0 deletions eravm-stable-interface/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
name = "eravm-stable-interface"
version = "0.1.0"
edition = "2021"
license = "MIT OR Apache-2.0"
authors = ["The Matter Labs Team <[email protected]>"]
joonazan marked this conversation as resolved.
Show resolved Hide resolved

[dependencies]
primitive-types = "0.12.1"
88 changes: 88 additions & 0 deletions eravm-stable-interface/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
//! # EraVM Stable Interface
//!
//! This crate defines an interface for tracers that will never change but may be extended.
//! To be precise, a tracer using this interface will work in any VM written against that
//! version or a newer one. Updating the tracer to depend on a newer interface version is
//! not necessary. In fact, tracers should depend on the oldest version that has the required
//! features.
//!
//! A struct implementing [Tracer] may read and mutate the VM's state via [StateInterface]
//! when particular opcodes are executed.
//!
//! ## Why is extreme backwards compatibility required here?
//!
//! Suppose VM1 uses stable interface version 1 and VM2 uses stable interface version 2.
//! With any sane design it would be trivial to take a tracer written for version 1 and
//! update it to work with version 2. However, then it can no longer be used with VM1.
//!
//! This exact thing caused us a lot of trouble when we put many versions of zk_evm in multivm.
//!
//! ## How do I add a new feature to the interface?
joonazan marked this conversation as resolved.
Show resolved Hide resolved
//!
//! Do not change the existing traits. In fact, you should delete existing code in the new
//! version that you publish and import it from the previous version instead.
//!
//! This is how you would add a new method to StateInterface and a new opcode.
//! ```
//! # use eravm_stable_interface as eravm_stable_interface_v1;
//! use eravm_stable_interface_v1::{StateInterface as StateInterfaceV1, Tracer as TracerV1, opcodes::NearCall};
//!
//! trait StateInterface: StateInterfaceV1 {
//! fn get_some_new_field(&self) -> u32;
//! }
//!
//! pub struct NewOpcode;
//!
//! #[derive(PartialEq, Eq)]
//! enum Opcode {
//! NewOpcode,
//! NearCall,
//! // ...
//! }
//!
//! trait OpcodeType {
//! const VALUE: Opcode;
//! }
//!
//! impl OpcodeType for NewOpcode {
//! const VALUE: Opcode = Opcode::NewOpcode;
//! }
//!
//! // Do this for every old opcode
//! impl OpcodeType for NearCall {
//! const VALUE: Opcode = Opcode::NearCall;
//! }
//!
//! trait Tracer {
//! fn before_instruction<OP: OpcodeType, S: StateInterface>(&mut self, _state: &mut S) {}
//! fn after_instruction<OP: OpcodeType, S: StateInterface>(&mut self, _state: &mut S) {}
//! }
//!
//! impl<T: TracerV1> Tracer for T {
//! fn before_instruction<OP: OpcodeType, S: StateInterface>(&mut self, state: &mut S) {
//! match OP::VALUE {
//! Opcode::NewOpcode => {}
//! // Do this for every old opcode
//! Opcode::NearCall => {
//! <Self as TracerV1>::before_instruction::<NearCall, _>(self, state)
//! }
//! }
//! }
//! fn after_instruction<OP: OpcodeType, S: StateInterface>(&mut self, _state: &mut S) {}
//! }
//!
//! // Now you can use the new features by implementing TracerV2
//! struct MyTracer;
//! impl Tracer for MyTracer {
//! fn before_instruction<OP: OpcodeType, S: StateInterface>(&mut self, state: &mut S) {
//! if OP::VALUE == Opcode::NewOpcode {
//! state.get_some_new_field();
//! }
//! }
//! }
//! ```

mod state_interface;
mod tracer_interface;
pub use state_interface::*;
pub use tracer_interface::*;
Loading
Loading