From 69ac5edd1b0ca7e0e38b6c2720dabb795526dbad Mon Sep 17 00:00:00 2001 From: Alex Ostrovski Date: Mon, 9 Sep 2024 16:39:28 +0300 Subject: [PATCH] feat: Brush up repo for publishing (#58) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit # What ❔ Starts brushing up the repo for publishing: - Better structures the repo directories. - Renames crates in a uniform way + uses workspace dependencies. - Structures imports using well-defined configuration. - Reduces visibility of some items. - Adds more crate metadata, e.g. licenses and readmes. ## Why ❔ Part of preparations for publishing the library crates. --- .github/workflows/ci.yml | 31 +++-- Cargo.lock | 69 +++++------ Cargo.toml | 66 +++++------ README.md | 26 ++++- afl-fuzz/Cargo.toml | 25 ---- crates/vm2-interface/Cargo.toml | 15 +++ crates/vm2-interface/LICENSE-APACHE | 1 + crates/vm2-interface/LICENSE-MIT | 1 + crates/vm2-interface/README.md | 12 ++ .../vm2-interface}/src/lib.rs | 13 ++- .../vm2-interface}/src/state_interface.rs | 0 .../vm2-interface}/src/tracer_interface.rs | 7 +- crates/vm2/Cargo.toml | 36 ++++++ crates/vm2/LICENSE-APACHE | 1 + crates/vm2/LICENSE-MIT | 1 + crates/vm2/README.md | 12 ++ .../vm2/benches}/nested_near_call.rs | 14 +-- .../vm2/proptest-regressions}/world_diff.txt | 0 {src => crates/vm2/src}/addressing_modes.rs | 7 +- {src => crates/vm2/src}/bitset.rs | 3 +- {src => crates/vm2/src}/callframe.rs | 9 +- {src => crates/vm2/src}/decode.rs | 74 ++++++------ {src => crates/vm2/src}/decommit.rs | 9 +- {src => crates/vm2/src}/fat_pointer.rs | 5 +- {src => crates/vm2/src}/heap.rs | 107 +++++++++--------- {src => crates/vm2/src}/instruction.rs | 7 +- .../vm2/src}/instruction_handlers/binop.rs | 11 +- .../vm2/src}/instruction_handlers/common.rs | 3 +- .../vm2/src}/instruction_handlers/context.rs | 13 ++- .../vm2/src}/instruction_handlers/decommit.rs | 7 +- .../vm2/src}/instruction_handlers/event.rs | 7 +- .../vm2/src}/instruction_handlers/far_call.rs | 19 ++-- .../src}/instruction_handlers/heap_access.rs | 84 ++++++++++---- .../vm2/src}/instruction_handlers/jump.rs | 3 +- .../vm2/src}/instruction_handlers/mod.rs | 9 +- .../instruction_handlers/monomorphization.rs | 9 +- .../src}/instruction_handlers/near_call.rs | 3 +- .../vm2/src}/instruction_handlers/nop.rs | 3 +- .../vm2/src}/instruction_handlers/pointer.rs | 11 +- .../src}/instruction_handlers/precompiles.rs | 17 +-- .../vm2/src}/instruction_handlers/ret.rs | 16 ++- .../vm2/src}/instruction_handlers/storage.rs | 3 +- {src => crates/vm2/src}/lib.rs | 58 +++++----- {src => crates/vm2/src}/mode_requirements.rs | 0 {src => crates/vm2/src}/predication.rs | 0 {src => crates/vm2/src}/program.rs | 13 ++- {src => crates/vm2/src}/rollback.rs | 11 +- .../src}/single_instruction_test/callframe.rs | 9 +- .../vm2/src}/single_instruction_test/heap.rs | 19 ++-- .../single_instruction_test/into_zk_evm.rs | 13 +-- .../single_instruction_test/mock_array.rs | 4 +- .../vm2/src}/single_instruction_test/mod.rs | 10 +- .../print_mock_info.rs | 0 .../src}/single_instruction_test/program.rs | 9 +- .../vm2/src}/single_instruction_test/stack.rs | 3 +- .../state_to_zk_evm.rs | 8 +- .../universal_state.rs | 2 +- .../single_instruction_test/validation.rs | 3 +- .../vm2/src}/single_instruction_test/vm.rs | 21 ++-- .../vm2/src}/single_instruction_test/world.rs | 7 +- {src => crates/vm2/src}/stack.rs | 8 +- {src => crates/vm2/src}/state.rs | 16 +-- {src => crates/vm2/src}/testworld.rs | 14 ++- {src => crates/vm2/src}/tracing.rs | 51 ++++----- {src => crates/vm2/src}/vm.rs | 21 ++-- {src => crates/vm2/src}/world_diff.rs | 16 +-- .../vm2/tests}/bytecode_behaviour.rs | 12 +- .../vm2/tests}/bytecodes/call_far | Bin .../vm2/tests}/far_call_decommitment.rs | 28 ++--- .../vm2/tests}/panic.proptest-regressions | 0 {tests => crates/vm2/tests}/panic.rs | 8 +- {tests => crates/vm2/tests}/stipend.rs | 13 +-- eravm-stable-interface/Cargo.toml | 9 -- {afl-fuzz => tests/afl-fuzz}/.gitignore | 0 tests/afl-fuzz/Cargo.toml | 27 +++++ {afl-fuzz => tests/afl-fuzz}/README.md | 4 +- {afl-fuzz => tests/afl-fuzz}/fuzz.sh | 0 ..._to_msg_value_far_call_forward_fat_pointer | Bin .../afl-fuzz}/in/return_calldata | Bin {afl-fuzz => tests/afl-fuzz}/show_crash.sh | 0 .../afl-fuzz}/src/check_input_size.rs | 2 +- {afl-fuzz => tests/afl-fuzz}/src/lib.rs | 4 +- {afl-fuzz => tests/afl-fuzz}/src/main.rs | 6 +- .../afl-fuzz}/src/show_testcase.rs | 15 ++- 84 files changed, 701 insertions(+), 512 deletions(-) delete mode 100644 afl-fuzz/Cargo.toml create mode 100644 crates/vm2-interface/Cargo.toml create mode 120000 crates/vm2-interface/LICENSE-APACHE create mode 120000 crates/vm2-interface/LICENSE-MIT create mode 100644 crates/vm2-interface/README.md rename {eravm-stable-interface => crates/vm2-interface}/src/lib.rs (89%) rename {eravm-stable-interface => crates/vm2-interface}/src/state_interface.rs (100%) rename {eravm-stable-interface => crates/vm2-interface}/src/tracer_interface.rs (98%) create mode 100644 crates/vm2/Cargo.toml create mode 120000 crates/vm2/LICENSE-APACHE create mode 120000 crates/vm2/LICENSE-MIT create mode 100644 crates/vm2/README.md rename {benches => crates/vm2/benches}/nested_near_call.rs (93%) rename {proptest-regressions => crates/vm2/proptest-regressions}/world_diff.txt (100%) rename {src => crates/vm2/src}/addressing_modes.rs (99%) rename {src => crates/vm2/src}/bitset.rs (82%) rename {src => crates/vm2/src}/callframe.rs (98%) rename {src => crates/vm2/src}/decode.rs (89%) rename {src => crates/vm2/src}/decommit.rs (96%) rename {src => crates/vm2/src}/fat_pointer.rs (88%) rename {src => crates/vm2/src}/heap.rs (98%) rename {src => crates/vm2/src}/instruction.rs (87%) rename {src => crates/vm2/src}/instruction_handlers/binop.rs (99%) rename {src => crates/vm2/src}/instruction_handlers/common.rs (97%) rename {src => crates/vm2/src}/instruction_handlers/context.rs (98%) rename {src => crates/vm2/src}/instruction_handlers/decommit.rs (96%) rename {src => crates/vm2/src}/instruction_handlers/event.rs (97%) rename {src => crates/vm2/src}/instruction_handlers/far_call.rs (99%) rename {src => crates/vm2/src}/instruction_handlers/heap_access.rs (84%) rename {src => crates/vm2/src}/instruction_handlers/jump.rs (96%) rename {src => crates/vm2/src}/instruction_handlers/mod.rs (69%) rename {src => crates/vm2/src}/instruction_handlers/monomorphization.rs (93%) rename {src => crates/vm2/src}/instruction_handlers/near_call.rs (97%) rename {src => crates/vm2/src}/instruction_handlers/nop.rs (95%) rename {src => crates/vm2/src}/instruction_handlers/pointer.rs (98%) rename {src => crates/vm2/src}/instruction_handlers/precompiles.rs (97%) rename {src => crates/vm2/src}/instruction_handlers/ret.rs (97%) rename {src => crates/vm2/src}/instruction_handlers/storage.rs (98%) rename {src => crates/vm2/src}/lib.rs (71%) rename {src => crates/vm2/src}/mode_requirements.rs (100%) rename {src => crates/vm2/src}/predication.rs (100%) rename {src => crates/vm2/src}/program.rs (89%) rename {src => crates/vm2/src}/rollback.rs (94%) rename {src => crates/vm2/src}/single_instruction_test/callframe.rs (98%) rename {src => crates/vm2/src}/single_instruction_test/heap.rs (89%) rename {src => crates/vm2/src}/single_instruction_test/into_zk_evm.rs (98%) rename {src => crates/vm2/src}/single_instruction_test/mock_array.rs (96%) rename {src => crates/vm2/src}/single_instruction_test/mod.rs (79%) rename {src => crates/vm2/src}/single_instruction_test/print_mock_info.rs (100%) rename {src => crates/vm2/src}/single_instruction_test/program.rs (97%) rename {src => crates/vm2/src}/single_instruction_test/stack.rs (99%) rename {src => crates/vm2/src}/single_instruction_test/state_to_zk_evm.rs (98%) rename {src => crates/vm2/src}/single_instruction_test/universal_state.rs (99%) rename {src => crates/vm2/src}/single_instruction_test/validation.rs (96%) rename {src => crates/vm2/src}/single_instruction_test/vm.rs (93%) rename {src => crates/vm2/src}/single_instruction_test/world.rs (91%) rename {src => crates/vm2/src}/stack.rs (98%) rename {src => crates/vm2/src}/state.rs (96%) rename {src => crates/vm2/src}/testworld.rs (90%) rename {src => crates/vm2/src}/tracing.rs (90%) rename {src => crates/vm2/src}/vm.rs (94%) rename {src => crates/vm2/src}/world_diff.rs (99%) rename {tests => crates/vm2/tests}/bytecode_behaviour.rs (91%) rename {tests => crates/vm2/tests}/bytecodes/call_far (100%) rename {tests => crates/vm2/tests}/far_call_decommitment.rs (92%) rename {tests => crates/vm2/tests}/panic.proptest-regressions (100%) rename {tests => crates/vm2/tests}/panic.rs (96%) rename {tests => crates/vm2/tests}/stipend.rs (97%) delete mode 100644 eravm-stable-interface/Cargo.toml rename {afl-fuzz => tests/afl-fuzz}/.gitignore (100%) create mode 100644 tests/afl-fuzz/Cargo.toml rename {afl-fuzz => tests/afl-fuzz}/README.md (81%) rename {afl-fuzz => tests/afl-fuzz}/fuzz.sh (100%) rename {afl-fuzz => tests/afl-fuzz}/in/kernel_to_msg_value_far_call_forward_fat_pointer (100%) rename {afl-fuzz => tests/afl-fuzz}/in/return_calldata (100%) rename {afl-fuzz => tests/afl-fuzz}/show_crash.sh (100%) rename {afl-fuzz => tests/afl-fuzz}/src/check_input_size.rs (89%) rename {afl-fuzz => tests/afl-fuzz}/src/lib.rs (60%) rename {afl-fuzz => tests/afl-fuzz}/src/main.rs (89%) rename {afl-fuzz => tests/afl-fuzz}/src/show_testcase.rs (78%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8c8f6d2b..128a53b9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,31 +22,46 @@ jobs: steps: - uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4 - - name: Install stable toolchain - uses: actions-rs/toolchain@v1 + - name: Install Rust + uses: dtolnay/rust-toolchain@master with: toolchain: stable - override: true + components: rustfmt, clippy, rust-src - name: Rust Cache uses: Swatinem/rust-cache@v2 + - name: Install cargo-afl + run: cargo install cargo-afl --version=^0.15 --force + - name: Build project run: | - cargo build + # AFL fuzzing requires a separate command + cargo build --workspace --all-targets --exclude zksync_vm2_afl_fuzz + + - name: Build fuzzer + run: cargo afl build -p zksync_vm2_afl_fuzz # Two runs are needed. One for normal VM, another for the mocked version - name: Run clippy run: | # Check the main library with non-test features (needs to be tested in isolation since the fuzzing crate enables test features) - cargo clippy -p vm2 --all-targets -- -D warnings + cargo clippy -p zksync_vm2 --all-targets -- -D warnings # The benches in `vm2` don't compile with fuzzing enabled cargo clippy --workspace --all-features --lib --bins --tests -- -D warnings - name: Check formatting run: | - cargo fmt --check + cargo fmt --check -- --config imports_granularity=Crate --config group_imports=StdExternalCrate + + - name: Run tests + run: | + cargo test -p zksync_vm2_interface -p zksync_vm2 --all-targets + + - name: Run doc tests + run: cargo test --workspace --doc - - name: Run Tests + - name: Run fuzzer for a bit run: | - cargo test -p vm2 --all-targets + AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 \ + cargo afl fuzz -i tests/afl-fuzz/in -o tests/afl-fuzz/out -V 60 target/debug/zksync_vm2_afl_fuzz diff --git a/Cargo.lock b/Cargo.lock index 3ca30e20..56b75e81 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -237,17 +237,6 @@ version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" -[[package]] -name = "differential_fuzzing" -version = "0.1.0" -dependencies = [ - "afl", - "arbitrary", - "eravm-stable-interface", - "pretty_assertions", - "vm2", -] - [[package]] name = "digest" version = "0.10.7" @@ -337,13 +326,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" -[[package]] -name = "eravm-stable-interface" -version = "0.1.0" -dependencies = [ - "primitive-types", -] - [[package]] name = "errno" version = "0.3.9" @@ -1207,22 +1189,6 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" -[[package]] -name = "vm2" -version = "0.1.0" -dependencies = [ - "anyhow", - "arbitrary", - "divan", - "enum_dispatch", - "eravm-stable-interface", - "primitive-types", - "proptest", - "zk_evm", - "zk_evm_abstractions", - "zkevm_opcode_defs", -] - [[package]] name = "wait-timeout" version = "0.2.0" @@ -1477,3 +1443,38 @@ dependencies = [ "sha2", "sha3", ] + +[[package]] +name = "zksync_vm2" +version = "0.1.0" +dependencies = [ + "anyhow", + "arbitrary", + "divan", + "enum_dispatch", + "primitive-types", + "proptest", + "zk_evm", + "zk_evm_abstractions", + "zkevm_opcode_defs", + "zksync_vm2_interface", +] + +[[package]] +name = "zksync_vm2_afl_fuzz" +version = "0.1.0" +dependencies = [ + "afl", + "arbitrary", + "pretty_assertions", + "zkevm_opcode_defs", + "zksync_vm2", + "zksync_vm2_interface", +] + +[[package]] +name = "zksync_vm2_interface" +version = "0.1.0" +dependencies = [ + "primitive-types", +] diff --git a/Cargo.toml b/Cargo.toml index 1590bdf3..70428c3a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,40 +1,40 @@ -[package] -name = "vm2" +[workspace] +members = [ + # Main published library crates + "crates/vm2-interface", + "crates/vm2", + # Testing crates + "tests/afl-fuzz" +] +resolver = "2" + +[workspace.package] version = "0.1.0" -edition.workspace = true +edition = "2021" +authors = ["The Matter Labs Team "] homepage = "https://zksync.io/" -license.workspace = true -authors.workspace = true - -[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" } -enum_dispatch = "0.3" - -# Optional dependencies (used for fuzzing) -arbitrary = { version = "1", features = ["derive"], optional = true } -# The commit incorporates a fix necessary for fuzzing to work correctly. -zk_evm = { git = "https://github.com/matter-labs/era-zk_evm.git", rev = "b7caa02acc2119b2994730d92c8cb6b861f56484", optional = true } -anyhow = { version = "1", optional = true } +repository = "https://github.com/matter-labs/vm2" +license = "MIT OR Apache-2.0" +keywords = ["blockchain", "zksync"] +categories = ["cryptography"] -[dev-dependencies] +[workspace.dependencies] +# "External" dependencies +afl = "0.15" +anyhow = "1" +arbitrary = "1" divan = "0.1" +enum_dispatch = "0.3" +pretty_assertions = "1.4.0" +primitive-types = "0.12.1" proptest = "1.4" -[[bench]] -name = "nested_near_call" -harness = false - -[features] -default = [] -single_instruction_test = ["arbitrary", "u256/arbitrary", "zk_evm", "anyhow"] - -[workspace] -members = [".", "afl-fuzz", "eravm-stable-interface"] +# "Internal" dependencies +zkevm_opcode_defs = "0.150.0" +zk_evm_abstractions = "0.150.0" +# The commit incorporates a fix necessary for fuzzing to work correctly. +zk_evm = { git = "https://github.com/matter-labs/era-zk_evm.git", rev = "b7caa02acc2119b2994730d92c8cb6b861f56484" } -[workspace.package] -edition = "2021" -license = "MIT OR Apache-2.0" -authors = ["The Matter Labs Team "] \ No newline at end of file +# Dependencies within the workspace +zksync_vm2_interface = { version = "0.1.0", path = "crates/vm2-interface" } +zksync_vm2 = { version = "0.1.0", path = "crates/vm2" } diff --git a/README.md b/README.md index 79a369b7..2778e405 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,25 @@ -# zksync-era-vm2 +# High-Performance ZKsync Era VM -A high-performance rewrite of the zksync-era VM. +A high-performance rewrite of the out-of-circuit VM for ZKsync Era. + +## Overview + +This repository contains the following crates: + +- [`zksync_vm2_interface`](crates/vm2-interface): stable VM interface for tracers +- [`zksync_vm2`](crates/vm2): VM implementation itself +- [`zksync_vm2_afl_fuzz`](tests/afl-fuzz): [AFL](https://crates.io/crates/afl)-based fuzzing for the VM. + +## Policies + +- [Security policy](SECURITY.md) +- [Contribution policy](CONTRIBUTING.md) + +## License + +ZKsync Era VM is distributed under the terms of either + +- Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or ) +- MIT license ([LICENSE-MIT](LICENSE-MIT) or ) + +at your option. diff --git a/afl-fuzz/Cargo.toml b/afl-fuzz/Cargo.toml deleted file mode 100644 index b658bee1..00000000 --- a/afl-fuzz/Cargo.toml +++ /dev/null @@ -1,25 +0,0 @@ -[package] -name = "differential_fuzzing" -version = "0.1.0" -edition.workspace = true -publish = false - -[dependencies] -afl = "0.15" -arbitrary = "1" -pretty_assertions = "1.4.0" - -[dependencies.vm2] -path = ".." -features = ["single_instruction_test"] - -[dependencies.eravm-stable-interface] -path = "../eravm-stable-interface" - -[[bin]] -name = "show_testcase" -path = "src/show_testcase.rs" - -[[bin]] -name = "check_input_size" -path = "src/check_input_size.rs" diff --git a/crates/vm2-interface/Cargo.toml b/crates/vm2-interface/Cargo.toml new file mode 100644 index 00000000..38a5bece --- /dev/null +++ b/crates/vm2-interface/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "zksync_vm2_interface" +description = "Stable interface for ZKsync VM tracers" +readme = "README.md" +version.workspace = true +edition.workspace = true +authors.workspace = true +homepage.workspace = true +repository.workspace = true +license.workspace = true +keywords.workspace = true +categories.workspace = true + +[dependencies] +primitive-types.workspace = true diff --git a/crates/vm2-interface/LICENSE-APACHE b/crates/vm2-interface/LICENSE-APACHE new file mode 120000 index 00000000..1cd601d0 --- /dev/null +++ b/crates/vm2-interface/LICENSE-APACHE @@ -0,0 +1 @@ +../../LICENSE-APACHE \ No newline at end of file diff --git a/crates/vm2-interface/LICENSE-MIT b/crates/vm2-interface/LICENSE-MIT new file mode 120000 index 00000000..b2cfbdc7 --- /dev/null +++ b/crates/vm2-interface/LICENSE-MIT @@ -0,0 +1 @@ +../../LICENSE-MIT \ No newline at end of file diff --git a/crates/vm2-interface/README.md b/crates/vm2-interface/README.md new file mode 100644 index 00000000..7eda45c3 --- /dev/null +++ b/crates/vm2-interface/README.md @@ -0,0 +1,12 @@ +# Stable Interface for ZKsync Era VM + +This library provides a stable interface for the EraVM. It defines an interface for tracers that will never change but may be extended. + +## License + +ZKsync Era VM is distributed under the terms of either + +- Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or ) +- MIT license ([LICENSE-MIT](LICENSE-MIT) or ) + +at your option. diff --git a/eravm-stable-interface/src/lib.rs b/crates/vm2-interface/src/lib.rs similarity index 89% rename from eravm-stable-interface/src/lib.rs rename to crates/vm2-interface/src/lib.rs index 17b3d0d7..1a83f2f6 100644 --- a/eravm-stable-interface/src/lib.rs +++ b/crates/vm2-interface/src/lib.rs @@ -6,7 +6,7 @@ //! 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] +//! 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? @@ -23,9 +23,12 @@ //! 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}; +//! # use zksync_vm2_interface as zksync_vm2_interface_v1; +//! use zksync_vm2_interface_v1::{ +//! StateInterface as StateInterfaceV1, Tracer as TracerV1, opcodes::NearCall, +//! }; //! //! trait StateInterface: StateInterfaceV1 { //! fn get_some_new_field(&self) -> u32; @@ -82,7 +85,7 @@ //! } //! ``` +pub use self::{state_interface::*, tracer_interface::*}; + mod state_interface; mod tracer_interface; -pub use state_interface::*; -pub use tracer_interface::*; diff --git a/eravm-stable-interface/src/state_interface.rs b/crates/vm2-interface/src/state_interface.rs similarity index 100% rename from eravm-stable-interface/src/state_interface.rs rename to crates/vm2-interface/src/state_interface.rs diff --git a/eravm-stable-interface/src/tracer_interface.rs b/crates/vm2-interface/src/tracer_interface.rs similarity index 98% rename from eravm-stable-interface/src/tracer_interface.rs rename to crates/vm2-interface/src/tracer_interface.rs index d497d0f5..3aa75306 100644 --- a/eravm-stable-interface/src/tracer_interface.rs +++ b/crates/vm2-interface/src/tracer_interface.rs @@ -53,9 +53,10 @@ macro_rules! pub_struct { } pub mod opcodes { - use super::{CallingMode, ReturnType}; use std::marker::PhantomData; + use super::{CallingMode, ReturnType}; + forall_simple_opcodes!(pub_struct); pub struct FarCall(PhantomData); pub struct Ret(PhantomData); @@ -192,10 +193,12 @@ impl OpcodeType for opcodes::Ret { /// counter has advanced. /// /// # Examples +/// /// Here `FarCallCounter` counts the number of far calls. /// ``` -/// use eravm_stable_interface::{Tracer, StateInterface, OpcodeType, Opcode}; +/// # use zksync_vm2_interface::{Tracer, StateInterface, OpcodeType, Opcode}; /// struct FarCallCounter(usize); +/// /// impl Tracer for FarCallCounter { /// fn before_instruction(&mut self, state: &mut S) { /// match OP::VALUE { diff --git a/crates/vm2/Cargo.toml b/crates/vm2/Cargo.toml new file mode 100644 index 00000000..4134bb30 --- /dev/null +++ b/crates/vm2/Cargo.toml @@ -0,0 +1,36 @@ +[package] +name = "zksync_vm2" +description = "High-performance rewrite of the out-of-circuit VM for ZKsync Era" +readme = "README.md" +version.workspace = true +edition.workspace = true +authors.workspace = true +homepage.workspace = true +repository.workspace = true +license.workspace = true +keywords.workspace = true +categories.workspace = true + +[dependencies] +zksync_vm2_interface.workspace = true +zkevm_opcode_defs.workspace = true +zk_evm_abstractions.workspace = true +primitive-types.workspace = true +enum_dispatch.workspace = true + +# Optional dependencies (used for fuzzing) +arbitrary = { workspace = true, features = ["derive"], optional = true } +zk_evm = { workspace = true, optional = true } +anyhow = { workspace = true, optional = true } + +[dev-dependencies] +divan.workspace = true +proptest.workspace = true + +[[bench]] +name = "nested_near_call" +harness = false + +[features] +default = [] +single_instruction_test = ["arbitrary", "primitive-types/arbitrary", "zk_evm", "anyhow"] diff --git a/crates/vm2/LICENSE-APACHE b/crates/vm2/LICENSE-APACHE new file mode 120000 index 00000000..1cd601d0 --- /dev/null +++ b/crates/vm2/LICENSE-APACHE @@ -0,0 +1 @@ +../../LICENSE-APACHE \ No newline at end of file diff --git a/crates/vm2/LICENSE-MIT b/crates/vm2/LICENSE-MIT new file mode 120000 index 00000000..b2cfbdc7 --- /dev/null +++ b/crates/vm2/LICENSE-MIT @@ -0,0 +1 @@ +../../LICENSE-MIT \ No newline at end of file diff --git a/crates/vm2/README.md b/crates/vm2/README.md new file mode 100644 index 00000000..1c693c4f --- /dev/null +++ b/crates/vm2/README.md @@ -0,0 +1,12 @@ +# High-Performance ZKsync Era VM + +A high-performance rewrite of the out-of-circuit VM for ZKsync Era. + +## License + +ZKsync Era VM is distributed under the terms of either + +- Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or ) +- MIT license ([LICENSE-MIT](LICENSE-MIT) or ) + +at your option. diff --git a/benches/nested_near_call.rs b/crates/vm2/benches/nested_near_call.rs similarity index 93% rename from benches/nested_near_call.rs rename to crates/vm2/benches/nested_near_call.rs index 5f5fbb24..8119108a 100644 --- a/benches/nested_near_call.rs +++ b/crates/vm2/benches/nested_near_call.rs @@ -1,13 +1,13 @@ use divan::{black_box, Bencher}; -use vm2::{ +use zkevm_opcode_defs::ethereum_types::Address; +use zksync_vm2::{ addressing_modes::{Arguments, Immediate1, Immediate2, Register, Register1, Register2}, initial_decommit, testworld::TestWorld, Instruction, ModeRequirements, Predicate::Always, - Program, + Program, Settings, VirtualMachine, }; -use zkevm_opcode_defs::ethereum_types::Address; #[divan::bench] fn nested_near_call(bencher: Bencher) { @@ -27,13 +27,13 @@ fn nested_near_call(bencher: Bencher) { bencher.bench(|| { let mut world = TestWorld::new(&[(address, program.clone())]); let program = initial_decommit(&mut world, address); - let mut vm = vm2::VirtualMachine::new( + let mut vm = VirtualMachine::new( address, program, Address::zero(), vec![], 10_000_000, - vm2::Settings { + Settings { default_aa_code_hash: [0; 32], evm_interpreter_code_hash: [0; 32], hook_address: 0, @@ -74,13 +74,13 @@ fn nested_near_call_with_storage_write(bencher: Bencher) { bencher.bench(|| { let mut world = TestWorld::new(&[(address, program.clone())]); let program = initial_decommit(&mut world, address); - let mut vm = vm2::VirtualMachine::new( + let mut vm = VirtualMachine::new( address, program, Address::zero(), vec![], 80_000_000, - vm2::Settings { + Settings { default_aa_code_hash: [0; 32], evm_interpreter_code_hash: [0; 32], hook_address: 0, diff --git a/proptest-regressions/world_diff.txt b/crates/vm2/proptest-regressions/world_diff.txt similarity index 100% rename from proptest-regressions/world_diff.txt rename to crates/vm2/proptest-regressions/world_diff.txt diff --git a/src/addressing_modes.rs b/crates/vm2/src/addressing_modes.rs similarity index 99% rename from src/addressing_modes.rs rename to crates/vm2/src/addressing_modes.rs index 94d5c2a5..954b74e7 100644 --- a/src/addressing_modes.rs +++ b/crates/vm2/src/addressing_modes.rs @@ -1,10 +1,11 @@ -use crate::{mode_requirements::ModeRequirements, predication::Predicate}; #[cfg(feature = "arbitrary")] use arbitrary::{Arbitrary, Unstructured}; use enum_dispatch::enum_dispatch; -use u256::U256; +use primitive_types::U256; use zkevm_opcode_defs::erase_fat_pointer_metadata; +use crate::{mode_requirements::ModeRequirements, predication::Predicate}; + pub(crate) trait Source { /// Get a word's value for non-pointer operations. (Pointers are erased.) fn get(args: &Arguments, state: &mut impl Addressable) -> U256 { @@ -323,7 +324,7 @@ fn source_stack_address(args: &Arguments, state: &mut impl Addressable) -> u16 { compute_stack_address(state, args.source_registers.register1(), args.immediate1) } -pub fn destination_stack_address(args: &Arguments, state: &mut impl Addressable) -> u16 { +pub(crate) fn destination_stack_address(args: &Arguments, state: &mut impl Addressable) -> u16 { compute_stack_address( state, args.destination_registers.register1(), diff --git a/src/bitset.rs b/crates/vm2/src/bitset.rs similarity index 82% rename from src/bitset.rs rename to crates/vm2/src/bitset.rs index 5c78f316..ad1b4f8d 100644 --- a/src/bitset.rs +++ b/crates/vm2/src/bitset.rs @@ -1,5 +1,6 @@ +/// Bitset with `1 << 16` elements. Used to store pointer flags for VM [`Stack`](crate::stack::Stack). #[derive(Clone, PartialEq, Debug, Hash)] -pub struct Bitset([u64; 1 << 10]); +pub(crate) struct Bitset([u64; 1 << 10]); impl Bitset { #[inline(always)] diff --git a/src/callframe.rs b/crates/vm2/src/callframe.rs similarity index 98% rename from src/callframe.rs rename to crates/vm2/src/callframe.rs index f06483cc..b6b690e6 100644 --- a/src/callframe.rs +++ b/crates/vm2/src/callframe.rs @@ -1,3 +1,7 @@ +use primitive_types::H160; +use zkevm_opcode_defs::system_params::{NEW_FRAME_MEMORY_STIPEND, NEW_KERNEL_FRAME_MEMORY_STIPEND}; +use zksync_vm2_interface::HeapId; + use crate::{ decommit::is_kernel, instruction_handlers::invalid_instruction, @@ -6,9 +10,6 @@ use crate::{ world_diff::Snapshot, Instruction, }; -use eravm_stable_interface::HeapId; -use u256::H160; -use zkevm_opcode_defs::system_params::{NEW_FRAME_MEMORY_STIPEND, NEW_KERNEL_FRAME_MEMORY_STIPEND}; #[derive(Debug)] pub struct Callframe { @@ -21,7 +22,7 @@ pub struct Callframe { pub is_static: bool, pub is_kernel: bool, - pub stack: Box, + pub(crate) stack: Box, pub sp: u16, pub gas: u32, diff --git a/src/decode.rs b/crates/vm2/src/decode.rs similarity index 89% rename from src/decode.rs rename to crates/vm2/src/decode.rs index 6b971fca..99c0ec4c 100644 --- a/src/decode.rs +++ b/crates/vm2/src/decode.rs @@ -1,27 +1,27 @@ +use zkevm_opcode_defs::{ + decoding::{EncodingModeProduction, VmEncodingMode}, + ImmMemHandlerFlags, Opcode, + Operand::*, + RegOrImmFlags, FAR_CALL_SHARD_FLAG_IDX, FAR_CALL_STATIC_FLAG_IDX, FIRST_MESSAGE_FLAG_IDX, + RET_TO_LABEL_BIT_IDX, SET_FLAGS_FLAG_IDX, SWAP_OPERANDS_FLAG_IDX_FOR_ARITH_OPCODES, + SWAP_OPERANDS_FLAG_IDX_FOR_PTR_OPCODE, UMA_INCREMENT_FLAG_IDX, +}; +use zksync_vm2_interface::{opcodes, Tracer}; + use crate::{ addressing_modes::{ AbsoluteStack, AdvanceStackPointer, AnyDestination, AnySource, Arguments, CodePage, Immediate1, Immediate2, Register, Register1, Register2, RegisterAndImmediate, RelativeStack, Source, SourceWriter, }, - instruction::{ExecutionEnd, ExecutionStatus}, + instruction::{jump_to_beginning, ExecutionEnd, ExecutionStatus}, instruction_handlers::{ - Add, And, AuxHeap, Div, Heap, Mul, Or, PointerAdd, PointerPack, PointerShrink, PointerSub, - RotateLeft, RotateRight, ShiftLeft, ShiftRight, Sub, Xor, + Add, And, Div, Mul, Or, PointerAdd, PointerPack, PointerShrink, PointerSub, RotateLeft, + RotateRight, ShiftLeft, ShiftRight, Sub, Xor, }, - jump_to_beginning, mode_requirements::ModeRequirements, Instruction, Predicate, VirtualMachine, World, }; -use eravm_stable_interface::{opcodes, Tracer}; -use zkevm_opcode_defs::{ - decoding::{EncodingModeProduction, VmEncodingMode}, - ImmMemHandlerFlags, Opcode, - Operand::*, - RegOrImmFlags, FAR_CALL_SHARD_FLAG_IDX, FAR_CALL_STATIC_FLAG_IDX, FIRST_MESSAGE_FLAG_IDX, - RET_TO_LABEL_BIT_IDX, SET_FLAGS_FLAG_IDX, SWAP_OPERANDS_FLAG_IDX_FOR_ARITH_OPCODES, - SWAP_OPERANDS_FLAG_IDX_FOR_PTR_OPCODE, UMA_INCREMENT_FLAG_IDX, -}; pub fn decode_program>( raw: &[u64], @@ -47,6 +47,7 @@ fn unimplemented_instruction(variant: Opcode) -> Instruction { arguments, } } + fn unimplemented_handler( vm: &mut VirtualMachine, _: &mut W, @@ -148,25 +149,23 @@ pub(crate) fn decode>(raw: u64, is_bootloader: bool) -> I } match parsed.variant.opcode { - zkevm_opcode_defs::Opcode::Add(_) => binop!(Add, ()), - zkevm_opcode_defs::Opcode::Sub(_) => binop!(Sub, ()), - zkevm_opcode_defs::Opcode::Mul(_) => binop!(Mul, out2), - zkevm_opcode_defs::Opcode::Div(_) => binop!(Div, out2), - zkevm_opcode_defs::Opcode::Binop(x) => match x { + Opcode::Add(_) => binop!(Add, ()), + Opcode::Sub(_) => binop!(Sub, ()), + Opcode::Mul(_) => binop!(Mul, out2), + Opcode::Div(_) => binop!(Div, out2), + Opcode::Binop(x) => match x { zkevm_opcode_defs::BinopOpcode::Xor => binop!(Xor, ()), zkevm_opcode_defs::BinopOpcode::And => binop!(And, ()), zkevm_opcode_defs::BinopOpcode::Or => binop!(Or, ()), }, - zkevm_opcode_defs::Opcode::Shift(x) => match x { + Opcode::Shift(x) => match x { zkevm_opcode_defs::ShiftOpcode::Shl => binop!(ShiftLeft, ()), zkevm_opcode_defs::ShiftOpcode::Shr => binop!(ShiftRight, ()), zkevm_opcode_defs::ShiftOpcode::Rol => binop!(RotateLeft, ()), zkevm_opcode_defs::ShiftOpcode::Ror => binop!(RotateRight, ()), }, - zkevm_opcode_defs::Opcode::Jump(_) => { - Instruction::from_jump(src1, out.try_into().unwrap(), arguments) - } - zkevm_opcode_defs::Opcode::Context(x) => match x { + Opcode::Jump(_) => Instruction::from_jump(src1, out.try_into().unwrap(), arguments), + Opcode::Context(x) => match x { zkevm_opcode_defs::ContextOpcode::This => { Instruction::from_this(out.try_into().unwrap(), arguments) } @@ -198,19 +197,19 @@ pub(crate) fn decode>(raw: u64, is_bootloader: bool) -> I Instruction::from_aux_mutating(arguments) } }, - zkevm_opcode_defs::Opcode::Ptr(x) => match x { + Opcode::Ptr(x) => match x { zkevm_opcode_defs::PtrOpcode::Add => ptr!(PointerAdd), zkevm_opcode_defs::PtrOpcode::Sub => ptr!(PointerSub), zkevm_opcode_defs::PtrOpcode::Pack => ptr!(PointerPack), zkevm_opcode_defs::PtrOpcode::Shrink => ptr!(PointerShrink), }, - zkevm_opcode_defs::Opcode::NearCall(_) => Instruction::from_near_call( + Opcode::NearCall(_) => Instruction::from_near_call( Register1(Register::new(parsed.src0_reg_idx)), Immediate1(parsed.imm_0), Immediate2(parsed.imm_1), arguments, ), - zkevm_opcode_defs::Opcode::FarCall(kind) => { + Opcode::FarCall(kind) => { let constructor = match kind { zkevm_opcode_defs::FarCallOpcode::Normal => { Instruction::from_far_call:: @@ -231,7 +230,7 @@ pub(crate) fn decode>(raw: u64, is_bootloader: bool) -> I arguments, ) } - zkevm_opcode_defs::Opcode::Ret(kind) => { + Opcode::Ret(kind) => { let to_label = parsed.variant.flags[RET_TO_LABEL_BIT_IDX]; let label = if to_label { Some(Immediate1(parsed.imm_0)) @@ -248,7 +247,7 @@ pub(crate) fn decode>(raw: u64, is_bootloader: bool) -> I zkevm_opcode_defs::RetOpcode::Panic => Instruction::from_panic(label, arguments), } } - zkevm_opcode_defs::Opcode::Log(x) => match x { + Opcode::Log(x) => match x { zkevm_opcode_defs::LogOpcode::StorageRead => Instruction::from_sload( src1.try_into().unwrap(), out.try_into().unwrap(), @@ -295,34 +294,33 @@ pub(crate) fn decode>(raw: u64, is_bootloader: bool) -> I arguments, ), }, - zkevm_opcode_defs::Opcode::UMA(x) => { + Opcode::UMA(x) => { let increment = parsed.variant.flags[UMA_INCREMENT_FLAG_IDX]; match x { - zkevm_opcode_defs::UMAOpcode::HeapRead => Instruction::from_load::( + zkevm_opcode_defs::UMAOpcode::HeapRead => Instruction::from_heap_load( src1.try_into().unwrap(), out.try_into().unwrap(), increment.then_some(out2), arguments, ), - zkevm_opcode_defs::UMAOpcode::HeapWrite => Instruction::from_store::( + zkevm_opcode_defs::UMAOpcode::HeapWrite => Instruction::from_heap_store( src1.try_into().unwrap(), src2, increment.then_some(out.try_into().unwrap()), arguments, is_bootloader, ), - zkevm_opcode_defs::UMAOpcode::AuxHeapRead => Instruction::from_load::( + zkevm_opcode_defs::UMAOpcode::AuxHeapRead => Instruction::from_aux_heap_load( src1.try_into().unwrap(), out.try_into().unwrap(), increment.then_some(out2), arguments, ), - zkevm_opcode_defs::UMAOpcode::AuxHeapWrite => Instruction::from_store::( + zkevm_opcode_defs::UMAOpcode::AuxHeapWrite => Instruction::from_aux_heap_store( src1.try_into().unwrap(), src2, increment.then_some(out.try_into().unwrap()), arguments, - false, ), zkevm_opcode_defs::UMAOpcode::FatPointerRead => Instruction::from_load_pointer( src1.try_into().unwrap(), @@ -331,15 +329,15 @@ pub(crate) fn decode>(raw: u64, is_bootloader: bool) -> I arguments, ), zkevm_opcode_defs::UMAOpcode::StaticMemoryRead => unimplemented_instruction( - zkevm_opcode_defs::Opcode::UMA(zkevm_opcode_defs::UMAOpcode::StaticMemoryRead), + Opcode::UMA(zkevm_opcode_defs::UMAOpcode::StaticMemoryRead), ), zkevm_opcode_defs::UMAOpcode::StaticMemoryWrite => unimplemented_instruction( - zkevm_opcode_defs::Opcode::UMA(zkevm_opcode_defs::UMAOpcode::StaticMemoryWrite), + Opcode::UMA(zkevm_opcode_defs::UMAOpcode::StaticMemoryWrite), ), } } - zkevm_opcode_defs::Opcode::Invalid(_) => Instruction::from_invalid(), - zkevm_opcode_defs::Opcode::Nop(_) => { + Opcode::Invalid(_) => Instruction::from_invalid(), + Opcode::Nop(_) => { let no_sp_movement = AdvanceStackPointer(RegisterAndImmediate { immediate: 0, register: Register::new(0), diff --git a/src/decommit.rs b/crates/vm2/src/decommit.rs similarity index 96% rename from src/decommit.rs rename to crates/vm2/src/decommit.rs index 34b6553e..b7aa3796 100644 --- a/src/decommit.rs +++ b/crates/vm2/src/decommit.rs @@ -1,9 +1,10 @@ -use crate::{program::Program, world_diff::WorldDiff, World}; -use eravm_stable_interface::{CycleStats, Tracer}; -use u256::{H160, U256}; +use primitive_types::{H160, U256}; use zkevm_opcode_defs::{ ethereum_types::Address, system_params::DEPLOYER_SYSTEM_CONTRACT_ADDRESS_LOW, }; +use zksync_vm2_interface::{CycleStats, Tracer}; + +use crate::{program::Program, world_diff::WorldDiff, World}; impl WorldDiff { pub(crate) fn decommit( @@ -140,6 +141,7 @@ pub(crate) struct UnpaidDecommit { /// May be used to load code when the VM first starts up. /// Doesn't check for any errors. /// Doesn't cost anything but also doesn't make the code free in future decommits. +#[doc(hidden)] // should be used only in low-level testing / benches pub fn initial_decommit>(world: &mut W, address: H160) -> Program { let deployer_system_contract_address = Address::from_low_u64_be(DEPLOYER_SYSTEM_CONTRACT_ADDRESS_LOW as u64); @@ -156,6 +158,7 @@ pub fn initial_decommit>(world: &mut W, address: H160) -> Program world.decommit(code_key) } +#[doc(hidden)] // should be used only in low-level testing / benches pub fn address_into_u256(address: H160) -> U256 { let mut buffer = [0; 32]; buffer[12..].copy_from_slice(address.as_bytes()); diff --git a/src/fat_pointer.rs b/crates/vm2/src/fat_pointer.rs similarity index 88% rename from src/fat_pointer.rs rename to crates/vm2/src/fat_pointer.rs index c0012aaa..8e7b9075 100644 --- a/src/fat_pointer.rs +++ b/crates/vm2/src/fat_pointer.rs @@ -1,6 +1,7 @@ -use eravm_stable_interface::HeapId; -use u256::U256; +use primitive_types::U256; +use zksync_vm2_interface::HeapId; +/// Fat pointer to a heap location. #[derive(Debug)] #[repr(C)] pub struct FatPointer { diff --git a/src/heap.rs b/crates/vm2/src/heap.rs similarity index 98% rename from src/heap.rs rename to crates/vm2/src/heap.rs index 3e8711a4..e2cf9688 100644 --- a/src/heap.rs +++ b/crates/vm2/src/heap.rs @@ -1,10 +1,10 @@ -use crate::instruction_handlers::HeapInterface; -use eravm_stable_interface::HeapId; use std::{ fmt, mem, ops::{Index, Range}, }; -use u256::U256; + +use primitive_types::U256; +use zksync_vm2_interface::HeapId; /// Heap page size in bytes. const HEAP_PAGE_SIZE: usize = 1 << 12; @@ -69,55 +69,8 @@ impl Heap { Self { pages } } - /// Needed only by tracers - pub(crate) fn read_byte(&self, address: u32) -> u8 { - let (page, offset) = address_to_page_offset(address); - self.page(page).map(|page| page.0[offset]).unwrap_or(0) - } - - fn page(&self, idx: usize) -> Option<&HeapPage> { - self.pages.get(idx)?.as_ref() - } - - fn get_or_insert_page(&mut self, idx: usize, pagepool: &mut PagePool) -> &mut HeapPage { - if self.pages.len() <= idx { - self.pages.resize(idx + 1, None); - } - self.pages[idx].get_or_insert_with(|| pagepool.allocate_page()) - } - - fn write_u256(&mut self, start_address: u32, value: U256, pagepool: &mut PagePool) { - let (page_idx, offset_in_page) = address_to_page_offset(start_address); - let bytes_in_page = HEAP_PAGE_SIZE - offset_in_page; - let page = self.get_or_insert_page(page_idx, pagepool); - - if bytes_in_page >= 32 { - value.to_big_endian(&mut page.0[offset_in_page..offset_in_page + 32]); - } else { - let mut bytes = [0; 32]; - value.to_big_endian(&mut bytes); - let mut bytes_iter = bytes.into_iter(); - - for (dst, src) in page.0[offset_in_page..].iter_mut().zip(bytes_iter.by_ref()) { - *dst = src; - } - - let page = self.get_or_insert_page(page_idx + 1, pagepool); - for (dst, src) in page.0.iter_mut().zip(bytes_iter) { - *dst = src; - } - } - } -} - -#[inline(always)] -fn address_to_page_offset(address: u32) -> (usize, usize) { - let offset = address as usize; - (offset >> 12, offset & (HEAP_PAGE_SIZE - 1)) -} - -impl HeapInterface for Heap { - fn read_u256(&self, start_address: u32) -> U256 { + // TODO: reduce visibility once `multivm` uses `StateInterface` APIs + pub fn read_u256(&self, start_address: u32) -> U256 { let (page_idx, offset_in_page) = address_to_page_offset(start_address); let bytes_in_page = HEAP_PAGE_SIZE - offset_in_page; @@ -143,7 +96,7 @@ impl HeapInterface for Heap { } } - fn read_u256_partially(&self, range: Range) -> U256 { + pub(crate) fn read_u256_partially(&self, range: Range) -> U256 { let (page_idx, offset_in_page) = address_to_page_offset(range.start); let length = range.len(); let bytes_in_page = length.min(HEAP_PAGE_SIZE - offset_in_page); @@ -165,7 +118,7 @@ impl HeapInterface for Heap { U256::from_big_endian(&result) } - fn read_range_big_endian(&self, range: Range) -> Vec { + pub fn read_range_big_endian(&self, range: Range) -> Vec { let length = range.len(); let (mut page_idx, mut offset_in_page) = address_to_page_offset(range.start); @@ -182,6 +135,52 @@ impl HeapInterface for Heap { } result } + + /// Needed only by tracers + pub(crate) fn read_byte(&self, address: u32) -> u8 { + let (page, offset) = address_to_page_offset(address); + self.page(page).map(|page| page.0[offset]).unwrap_or(0) + } + + fn page(&self, idx: usize) -> Option<&HeapPage> { + self.pages.get(idx)?.as_ref() + } + + fn get_or_insert_page(&mut self, idx: usize, pagepool: &mut PagePool) -> &mut HeapPage { + if self.pages.len() <= idx { + self.pages.resize(idx + 1, None); + } + self.pages[idx].get_or_insert_with(|| pagepool.allocate_page()) + } + + fn write_u256(&mut self, start_address: u32, value: U256, pagepool: &mut PagePool) { + let (page_idx, offset_in_page) = address_to_page_offset(start_address); + let bytes_in_page = HEAP_PAGE_SIZE - offset_in_page; + let page = self.get_or_insert_page(page_idx, pagepool); + + if bytes_in_page >= 32 { + value.to_big_endian(&mut page.0[offset_in_page..offset_in_page + 32]); + } else { + let mut bytes = [0; 32]; + value.to_big_endian(&mut bytes); + let mut bytes_iter = bytes.into_iter(); + + for (dst, src) in page.0[offset_in_page..].iter_mut().zip(bytes_iter.by_ref()) { + *dst = src; + } + + let page = self.get_or_insert_page(page_idx + 1, pagepool); + for (dst, src) in page.0.iter_mut().zip(bytes_iter) { + *dst = src; + } + } + } +} + +#[inline(always)] +fn address_to_page_offset(address: u32) -> (usize, usize) { + let offset = address as usize; + (offset >> 12, offset & (HEAP_PAGE_SIZE - 1)) } #[derive(Debug, Clone)] diff --git a/src/instruction.rs b/crates/vm2/src/instruction.rs similarity index 87% rename from src/instruction.rs rename to crates/vm2/src/instruction.rs index 2625f59d..261b5e05 100644 --- a/src/instruction.rs +++ b/crates/vm2/src/instruction.rs @@ -4,6 +4,7 @@ use crate::{ addressing_modes::Arguments, mode_requirements::ModeRequirements, vm::VirtualMachine, Predicate, }; +#[doc(hidden)] // should only be used for low-level testing / benchmarking pub struct Instruction { pub(crate) handler: Handler, pub(crate) arguments: Arguments, @@ -19,7 +20,9 @@ impl fmt::Debug for Instruction { } pub(crate) type Handler = fn(&mut VirtualMachine, &mut W, &mut T) -> ExecutionStatus; -pub enum ExecutionStatus { + +#[derive(Debug)] +pub(crate) enum ExecutionStatus { Running, Stopped(ExecutionEnd), } @@ -34,7 +37,7 @@ pub enum ExecutionEnd { SuspendedOnHook(u32), } -pub fn jump_to_beginning() -> Instruction { +pub(crate) fn jump_to_beginning() -> Instruction { Instruction { handler: jump_to_beginning_handler, arguments: Arguments::new(Predicate::Always, 0, ModeRequirements::none()), diff --git a/src/instruction_handlers/binop.rs b/crates/vm2/src/instruction_handlers/binop.rs similarity index 99% rename from src/instruction_handlers/binop.rs rename to crates/vm2/src/instruction_handlers/binop.rs index 54253a27..336ca4ac 100644 --- a/src/instruction_handlers/binop.rs +++ b/crates/vm2/src/instruction_handlers/binop.rs @@ -1,3 +1,9 @@ +use primitive_types::U256; +use zksync_vm2_interface::{ + opcodes::{Add, And, Div, Mul, Or, RotateLeft, RotateRight, ShiftLeft, ShiftRight, Sub, Xor}, + OpcodeType, Tracer, +}; + use super::common::boilerplate; use crate::{ addressing_modes::{ @@ -9,11 +15,6 @@ use crate::{ predication::Flags, VirtualMachine, }; -use eravm_stable_interface::{ - opcodes::{Add, And, Div, Mul, Or, RotateLeft, RotateRight, ShiftLeft, ShiftRight, Sub, Xor}, - OpcodeType, Tracer, -}; -use u256::U256; fn binop< T: Tracer, diff --git a/src/instruction_handlers/common.rs b/crates/vm2/src/instruction_handlers/common.rs similarity index 97% rename from src/instruction_handlers/common.rs rename to crates/vm2/src/instruction_handlers/common.rs index d274e740..4f865113 100644 --- a/src/instruction_handlers/common.rs +++ b/crates/vm2/src/instruction_handlers/common.rs @@ -1,6 +1,7 @@ +use zksync_vm2_interface::{opcodes, OpcodeType, Tracer}; + use super::ret::free_panic; use crate::{addressing_modes::Arguments, instruction::ExecutionStatus, VirtualMachine}; -use eravm_stable_interface::{opcodes, OpcodeType, Tracer}; #[inline(always)] pub(crate) fn boilerplate( diff --git a/src/instruction_handlers/context.rs b/crates/vm2/src/instruction_handlers/context.rs similarity index 98% rename from src/instruction_handlers/context.rs rename to crates/vm2/src/instruction_handlers/context.rs index 74c02650..679ef97e 100644 --- a/src/instruction_handlers/context.rs +++ b/crates/vm2/src/instruction_handlers/context.rs @@ -1,3 +1,10 @@ +use primitive_types::U256; +use zkevm_opcode_defs::VmMetaParameters; +use zksync_vm2_interface::{ + opcodes::{self, Caller, CodeAddress, ContextU128, ErgsLeft, This, SP}, + OpcodeType, Tracer, +}; + use super::common::boilerplate; use crate::{ addressing_modes::{Arguments, Destination, Register1, Source}, @@ -6,12 +13,6 @@ use crate::{ state::State, Instruction, VirtualMachine, }; -use eravm_stable_interface::{ - opcodes::{self, Caller, CodeAddress, ContextU128, ErgsLeft, This, SP}, - OpcodeType, Tracer, -}; -use u256::U256; -use zkevm_opcode_defs::VmMetaParameters; fn context( vm: &mut VirtualMachine, diff --git a/src/instruction_handlers/decommit.rs b/crates/vm2/src/instruction_handlers/decommit.rs similarity index 96% rename from src/instruction_handlers/decommit.rs rename to crates/vm2/src/instruction_handlers/decommit.rs index dc2e0d9c..13b0ed1b 100644 --- a/src/instruction_handlers/decommit.rs +++ b/crates/vm2/src/instruction_handlers/decommit.rs @@ -1,3 +1,7 @@ +use primitive_types::U256; +use zkevm_opcode_defs::{BlobSha256Format, ContractCodeSha256Format, VersionedHashLen32}; +use zksync_vm2_interface::{opcodes, Tracer}; + use super::common::boilerplate_ext; use crate::{ addressing_modes::{Arguments, Destination, Register1, Register2, Source}, @@ -5,9 +9,6 @@ use crate::{ instruction::ExecutionStatus, Instruction, VirtualMachine, World, }; -use eravm_stable_interface::{opcodes, Tracer}; -use u256::U256; -use zkevm_opcode_defs::{BlobSha256Format, ContractCodeSha256Format, VersionedHashLen32}; fn decommit>( vm: &mut VirtualMachine, diff --git a/src/instruction_handlers/event.rs b/crates/vm2/src/instruction_handlers/event.rs similarity index 97% rename from src/instruction_handlers/event.rs rename to crates/vm2/src/instruction_handlers/event.rs index 62895734..71bc44a3 100644 --- a/src/instruction_handlers/event.rs +++ b/crates/vm2/src/instruction_handlers/event.rs @@ -1,3 +1,7 @@ +use primitive_types::H160; +use zkevm_opcode_defs::ADDRESS_EVENT_WRITER; +use zksync_vm2_interface::{opcodes, Tracer}; + use super::common::boilerplate_ext; use crate::{ addressing_modes::{Arguments, Immediate1, Register1, Register2, Source}, @@ -5,9 +9,6 @@ use crate::{ world_diff::{Event, L2ToL1Log}, Instruction, VirtualMachine, }; -use eravm_stable_interface::{opcodes, Tracer}; -use u256::H160; -use zkevm_opcode_defs::ADDRESS_EVENT_WRITER; fn event( vm: &mut VirtualMachine, diff --git a/src/instruction_handlers/far_call.rs b/crates/vm2/src/instruction_handlers/far_call.rs similarity index 99% rename from src/instruction_handlers/far_call.rs rename to crates/vm2/src/instruction_handlers/far_call.rs index 9437ee57..556c728d 100644 --- a/src/instruction_handlers/far_call.rs +++ b/crates/vm2/src/instruction_handlers/far_call.rs @@ -1,3 +1,13 @@ +use primitive_types::U256; +use zkevm_opcode_defs::{ + system_params::{EVM_SIMULATOR_STIPEND, MSG_VALUE_SIMULATOR_ADDITIVE_COST}, + ADDRESS_MSG_VALUE, +}; +use zksync_vm2_interface::{ + opcodes::{FarCall, TypeLevelCallingMode}, + Tracer, +}; + use super::{ common::boilerplate_ext, heap_access::grow_heap, @@ -12,15 +22,6 @@ use crate::{ predication::Flags, Instruction, VirtualMachine, World, }; -use eravm_stable_interface::{ - opcodes::{FarCall, TypeLevelCallingMode}, - Tracer, -}; -use u256::U256; -use zkevm_opcode_defs::{ - system_params::{EVM_SIMULATOR_STIPEND, MSG_VALUE_SIMULATOR_ADDITIVE_COST}, - ADDRESS_MSG_VALUE, -}; /// A call to another contract. /// diff --git a/src/instruction_handlers/heap_access.rs b/crates/vm2/src/instruction_handlers/heap_access.rs similarity index 84% rename from src/instruction_handlers/heap_access.rs rename to crates/vm2/src/instruction_handlers/heap_access.rs index 74ff1ce5..70aba1ea 100644 --- a/src/instruction_handlers/heap_access.rs +++ b/crates/vm2/src/instruction_handlers/heap_access.rs @@ -1,3 +1,6 @@ +use primitive_types::U256; +use zksync_vm2_interface::{opcodes, OpcodeType, Tracer}; + use super::common::{boilerplate, full_boilerplate}; use crate::{ addressing_modes::{ @@ -9,45 +12,43 @@ use crate::{ state::State, ExecutionEnd, HeapId, Instruction, VirtualMachine, }; -use eravm_stable_interface::{opcodes, OpcodeType, Tracer}; -use std::ops::Range; -use u256::U256; - -pub trait HeapInterface { - fn read_u256(&self, start_address: u32) -> U256; - fn read_u256_partially(&self, range: Range) -> U256; - fn read_range_big_endian(&self, range: Range) -> Vec; -} -pub trait HeapFromState { - fn get_heap(state: &State) -> HeapId; - fn get_heap_size(state: &mut State) -> &mut u32; +pub(crate) trait HeapFromState { type Read: OpcodeType; type Write: OpcodeType; + + fn get_heap(state: &State) -> HeapId; + fn get_heap_size(state: &mut State) -> &mut u32; } -pub struct Heap; +pub(crate) struct Heap; + impl HeapFromState for Heap { + type Read = opcodes::HeapRead; + type Write = opcodes::HeapWrite; + fn get_heap(state: &State) -> HeapId { state.current_frame.heap } + fn get_heap_size(state: &mut State) -> &mut u32 { &mut state.current_frame.heap_size } - type Read = opcodes::HeapRead; - type Write = opcodes::HeapWrite; } -pub struct AuxHeap; +pub(crate) struct AuxHeap; + impl HeapFromState for AuxHeap { + type Read = opcodes::AuxHeapRead; + type Write = opcodes::AuxHeapWrite; + fn get_heap(state: &State) -> HeapId { state.current_frame.aux_heap } + fn get_heap_size(state: &mut State) -> &mut u32 { &mut state.current_frame.aux_heap_size } - type Read = opcodes::AuxHeapRead; - type Write = opcodes::AuxHeapWrite; } /// The last address to which 32 can be added without overflow. @@ -146,7 +147,7 @@ fn store< /// Pays for more heap space. Doesn't acually grow the heap. /// That distinction is necessary because the bootloader gets u32::MAX heap for free. -pub fn grow_heap( +pub(crate) fn grow_heap( state: &mut State, new_bound: u32, ) -> Result<(), ()> { @@ -198,7 +199,27 @@ use super::monomorphization::*; impl Instruction { #[inline(always)] - pub fn from_load( + pub fn from_heap_load( + src: RegisterOrImmediate, + out: Register1, + incremented_out: Option, + arguments: Arguments, + ) -> Self { + Self::from_load::(src, out, incremented_out, arguments) + } + + #[inline(always)] + pub fn from_aux_heap_load( + src: RegisterOrImmediate, + out: Register1, + incremented_out: Option, + arguments: Arguments, + ) -> Self { + Self::from_load::(src, out, incremented_out, arguments) + } + + #[inline(always)] + fn from_load( src: RegisterOrImmediate, out: Register1, incremented_out: Option, @@ -218,7 +239,28 @@ impl Instruction { } #[inline(always)] - pub fn from_store( + pub fn from_heap_store( + src1: RegisterOrImmediate, + src2: Register2, + incremented_out: Option, + arguments: Arguments, + should_hook: bool, + ) -> Self { + Self::from_store::(src1, src2, incremented_out, arguments, should_hook) + } + + #[inline(always)] + pub fn from_aux_heap_store( + src1: RegisterOrImmediate, + src2: Register2, + incremented_out: Option, + arguments: Arguments, + ) -> Self { + Self::from_store::(src1, src2, incremented_out, arguments, false) + } + + #[inline(always)] + fn from_store( src1: RegisterOrImmediate, src2: Register2, incremented_out: Option, diff --git a/src/instruction_handlers/jump.rs b/crates/vm2/src/instruction_handlers/jump.rs similarity index 96% rename from src/instruction_handlers/jump.rs rename to crates/vm2/src/instruction_handlers/jump.rs index 28ccc4db..3ca7a557 100644 --- a/src/instruction_handlers/jump.rs +++ b/crates/vm2/src/instruction_handlers/jump.rs @@ -1,3 +1,5 @@ +use zksync_vm2_interface::{opcodes, Tracer}; + use super::common::boilerplate; use crate::{ addressing_modes::{ @@ -7,7 +9,6 @@ use crate::{ instruction::{ExecutionStatus, Instruction}, VirtualMachine, }; -use eravm_stable_interface::{opcodes, Tracer}; fn jump( vm: &mut VirtualMachine, diff --git a/src/instruction_handlers/mod.rs b/crates/vm2/src/instruction_handlers/mod.rs similarity index 69% rename from src/instruction_handlers/mod.rs rename to crates/vm2/src/instruction_handlers/mod.rs index 1f7e32fc..9b62fabe 100644 --- a/src/instruction_handlers/mod.rs +++ b/crates/vm2/src/instruction_handlers/mod.rs @@ -1,9 +1,12 @@ -pub use eravm_stable_interface::opcodes::{ +pub use zksync_vm2_interface::opcodes::{ Add, And, Div, Mul, Or, PointerAdd, PointerPack, PointerShrink, PointerSub, RotateLeft, RotateRight, ShiftLeft, ShiftRight, Sub, Xor, }; -pub use heap_access::{AuxHeap, Heap, HeapInterface}; -pub(crate) use ret::{invalid_instruction, RETURN_COST}; + +pub(crate) use self::{ + heap_access::{AuxHeap, Heap}, + ret::{invalid_instruction, RETURN_COST}, +}; mod binop; mod common; diff --git a/src/instruction_handlers/monomorphization.rs b/crates/vm2/src/instruction_handlers/monomorphization.rs similarity index 93% rename from src/instruction_handlers/monomorphization.rs rename to crates/vm2/src/instruction_handlers/monomorphization.rs index 87108329..660f15ac 100644 --- a/src/instruction_handlers/monomorphization.rs +++ b/crates/vm2/src/instruction_handlers/monomorphization.rs @@ -59,6 +59,9 @@ macro_rules! parameterize { }; } -pub(crate) use { - match_boolean, match_destination, match_reg_imm, match_source, monomorphize, parameterize, -}; +pub(crate) use match_boolean; +pub(crate) use match_destination; +pub(crate) use match_reg_imm; +pub(crate) use match_source; +pub(crate) use monomorphize; +pub(crate) use parameterize; diff --git a/src/instruction_handlers/near_call.rs b/crates/vm2/src/instruction_handlers/near_call.rs similarity index 97% rename from src/instruction_handlers/near_call.rs rename to crates/vm2/src/instruction_handlers/near_call.rs index 3f3b74b1..16c3a19d 100644 --- a/src/instruction_handlers/near_call.rs +++ b/crates/vm2/src/instruction_handlers/near_call.rs @@ -1,3 +1,5 @@ +use zksync_vm2_interface::{opcodes, Tracer}; + use super::common::boilerplate; use crate::{ addressing_modes::{Arguments, Immediate1, Immediate2, Register1, Source}, @@ -5,7 +7,6 @@ use crate::{ predication::Flags, Instruction, VirtualMachine, }; -use eravm_stable_interface::{opcodes, Tracer}; fn near_call( vm: &mut VirtualMachine, diff --git a/src/instruction_handlers/nop.rs b/crates/vm2/src/instruction_handlers/nop.rs similarity index 95% rename from src/instruction_handlers/nop.rs rename to crates/vm2/src/instruction_handlers/nop.rs index b9a00168..7349ae20 100644 --- a/src/instruction_handlers/nop.rs +++ b/crates/vm2/src/instruction_handlers/nop.rs @@ -1,10 +1,11 @@ +use zksync_vm2_interface::{opcodes, Tracer}; + use super::common::boilerplate; use crate::{ addressing_modes::{destination_stack_address, AdvanceStackPointer, Arguments, Source}, instruction::ExecutionStatus, Instruction, VirtualMachine, }; -use eravm_stable_interface::{opcodes, Tracer}; fn nop( vm: &mut VirtualMachine, diff --git a/src/instruction_handlers/pointer.rs b/crates/vm2/src/instruction_handlers/pointer.rs similarity index 98% rename from src/instruction_handlers/pointer.rs rename to crates/vm2/src/instruction_handlers/pointer.rs index f450ad74..c78a92d7 100644 --- a/src/instruction_handlers/pointer.rs +++ b/crates/vm2/src/instruction_handlers/pointer.rs @@ -1,3 +1,9 @@ +use primitive_types::U256; +use zksync_vm2_interface::{ + opcodes::{PointerAdd, PointerPack, PointerShrink, PointerSub}, + OpcodeType, Tracer, +}; + use super::common::boilerplate; use crate::{ addressing_modes::{ @@ -8,11 +14,6 @@ use crate::{ instruction::ExecutionStatus, Instruction, VirtualMachine, }; -use eravm_stable_interface::{ - opcodes::{PointerAdd, PointerPack, PointerShrink, PointerSub}, - OpcodeType, Tracer, -}; -use u256::U256; fn ptr( vm: &mut VirtualMachine, diff --git a/src/instruction_handlers/precompiles.rs b/crates/vm2/src/instruction_handlers/precompiles.rs similarity index 97% rename from src/instruction_handlers/precompiles.rs rename to crates/vm2/src/instruction_handlers/precompiles.rs index a337a11c..4d4d549d 100644 --- a/src/instruction_handlers/precompiles.rs +++ b/crates/vm2/src/instruction_handlers/precompiles.rs @@ -1,11 +1,3 @@ -use super::{common::boilerplate_ext, HeapInterface}; -use crate::{ - addressing_modes::{Arguments, Destination, Register1, Register2, Source}, - heap::Heaps, - instruction::ExecutionStatus, - Instruction, VirtualMachine, -}; -use eravm_stable_interface::{opcodes, CycleStats, HeapId, Tracer}; use zk_evm_abstractions::{ aux::Timestamp, precompiles::{ @@ -22,6 +14,15 @@ use zkevm_opcode_defs::{ }, PrecompileAuxData, PrecompileCallABI, }; +use zksync_vm2_interface::{opcodes, CycleStats, HeapId, Tracer}; + +use super::common::boilerplate_ext; +use crate::{ + addressing_modes::{Arguments, Destination, Register1, Register2, Source}, + heap::Heaps, + instruction::ExecutionStatus, + Instruction, VirtualMachine, +}; fn precompile_call( vm: &mut VirtualMachine, diff --git a/src/instruction_handlers/ret.rs b/crates/vm2/src/instruction_handlers/ret.rs similarity index 97% rename from src/instruction_handlers/ret.rs rename to crates/vm2/src/instruction_handlers/ret.rs index 30ad2394..f423bf8f 100644 --- a/src/instruction_handlers/ret.rs +++ b/crates/vm2/src/instruction_handlers/ret.rs @@ -1,4 +1,10 @@ -use super::{common::full_boilerplate, far_call::get_far_call_calldata, HeapInterface}; +use primitive_types::U256; +use zksync_vm2_interface::{ + opcodes::{self, Normal, Panic, Revert, TypeLevelReturnType}, + ReturnType, Tracer, +}; + +use super::{common::full_boilerplate, far_call::get_far_call_calldata, monomorphization::*}; use crate::{ addressing_modes::{Arguments, Immediate1, Register1, Source, INVALID_INSTRUCTION_COST}, callframe::FrameRemnant, @@ -7,11 +13,6 @@ use crate::{ predication::Flags, Instruction, Predicate, VirtualMachine, }; -use eravm_stable_interface::{ - opcodes::{self, TypeLevelReturnType}, - ReturnType, Tracer, -}; -use u256::U256; fn naked_ret( vm: &mut VirtualMachine, @@ -181,9 +182,6 @@ pub fn invalid_instruction<'a, T, W>() -> &'a Instruction { pub(crate) const RETURN_COST: u32 = 5; -use super::monomorphization::*; -use eravm_stable_interface::opcodes::{Normal, Panic, Revert}; - impl Instruction { pub fn from_ret(src1: Register1, label: Option, arguments: Arguments) -> Self { let to_label = label.is_some(); diff --git a/src/instruction_handlers/storage.rs b/crates/vm2/src/instruction_handlers/storage.rs similarity index 98% rename from src/instruction_handlers/storage.rs rename to crates/vm2/src/instruction_handlers/storage.rs index 7f6b857c..ff8fd208 100644 --- a/src/instruction_handlers/storage.rs +++ b/crates/vm2/src/instruction_handlers/storage.rs @@ -1,3 +1,5 @@ +use zksync_vm2_interface::{opcodes, Tracer}; + use super::common::{boilerplate, boilerplate_ext}; use crate::{ addressing_modes::{ @@ -6,7 +8,6 @@ use crate::{ instruction::ExecutionStatus, Instruction, VirtualMachine, World, }; -use eravm_stable_interface::{opcodes, Tracer}; fn sstore>( vm: &mut VirtualMachine, diff --git a/src/lib.rs b/crates/vm2/src/lib.rs similarity index 71% rename from src/lib.rs rename to crates/vm2/src/lib.rs index d52150b7..f0733960 100644 --- a/src/lib.rs +++ b/crates/vm2/src/lib.rs @@ -1,19 +1,45 @@ +use std::hash::{DefaultHasher, Hash, Hasher}; + +use primitive_types::{H160, U256}; +pub use zksync_vm2_interface::{ + CallframeInterface, CycleStats, HeapId, Opcode, OpcodeType, ReturnType, StateInterface, Tracer, +}; + +// Re-export missing modules if single instruction testing is enabled +#[cfg(feature = "single_instruction_test")] +pub(crate) use self::single_instruction_test::{heap, program, stack}; +pub use self::{ + decommit::{address_into_u256, initial_decommit}, + fat_pointer::FatPointer, + heap::FIRST_HEAP, + instruction::{ExecutionEnd, Instruction}, + mode_requirements::ModeRequirements, + predication::Predicate, + program::Program, + state::State, + vm::{Settings, VirtualMachine, VmSnapshot as Snapshot}, + world_diff::{Event, L2ToL1Log, WorldDiff}, +}; + +// FIXME: revise visibility pub mod addressing_modes; #[cfg(not(feature = "single_instruction_test"))] mod bitset; mod callframe; pub mod decode; mod decommit; -pub mod fat_pointer; +mod fat_pointer; #[cfg(not(feature = "single_instruction_test"))] mod heap; mod instruction; -pub mod instruction_handlers; +mod instruction_handlers; mod mode_requirements; mod predication; #[cfg(not(feature = "single_instruction_test"))] mod program; mod rollback; +#[cfg(feature = "single_instruction_test")] +pub mod single_instruction_test; #[cfg(not(feature = "single_instruction_test"))] mod stack; mod state; @@ -22,34 +48,6 @@ mod tracing; mod vm; mod world_diff; -use std::hash::{DefaultHasher, Hash, Hasher}; -use u256::{H160, U256}; - -pub use decommit::address_into_u256; -pub use decommit::initial_decommit; -pub use eravm_stable_interface::{ - CallframeInterface, CycleStats, HeapId, Opcode, OpcodeType, ReturnType, StateInterface, Tracer, -}; -pub use heap::FIRST_HEAP; -pub use instruction::{jump_to_beginning, ExecutionEnd, Instruction}; -pub use mode_requirements::ModeRequirements; -pub use predication::Predicate; -pub use program::Program; -pub use state::State; -pub use vm::{Settings, VirtualMachine, VmSnapshot as Snapshot}; -pub use world_diff::{Event, L2ToL1Log, WorldDiff}; - -#[cfg(feature = "single_instruction_test")] -pub mod single_instruction_test; -#[cfg(feature = "single_instruction_test")] -use single_instruction_test::heap; -#[cfg(feature = "single_instruction_test")] -use single_instruction_test::program; -#[cfg(feature = "single_instruction_test")] -use single_instruction_test::stack; -#[cfg(feature = "single_instruction_test")] -pub use zkevm_opcode_defs; - pub trait World: StorageInterface + Sized { /// This will be called *every* time a contract is called. Caching and decoding is /// the world implementor's job. diff --git a/src/mode_requirements.rs b/crates/vm2/src/mode_requirements.rs similarity index 100% rename from src/mode_requirements.rs rename to crates/vm2/src/mode_requirements.rs diff --git a/src/predication.rs b/crates/vm2/src/predication.rs similarity index 100% rename from src/predication.rs rename to crates/vm2/src/predication.rs diff --git a/src/program.rs b/crates/vm2/src/program.rs similarity index 89% rename from src/program.rs rename to crates/vm2/src/program.rs index 401892b1..d33a9589 100644 --- a/src/program.rs +++ b/crates/vm2/src/program.rs @@ -1,13 +1,16 @@ -use crate::{hash_for_debugging, Instruction}; use std::{fmt, sync::Arc}; -use u256::U256; -// An internal representation that doesn't need two Arcs would be better -// but it would also require a lot of unsafe, so I made this wrapper to -// enable changing the internals later. +use primitive_types::U256; + +use crate::{hash_for_debugging, Instruction}; +/// Compiled ZKsync Era VM bytecode. +/// /// Cloning this is cheap. It is a handle to memory similar to [`Arc`]. pub struct Program { + // An internal representation that doesn't need two Arcs would be better + // but it would also require a lot of unsafe, so I made this wrapper to + // enable changing the internals later. code_page: Arc<[U256]>, instructions: Arc<[Instruction]>, } diff --git a/src/rollback.rs b/crates/vm2/src/rollback.rs similarity index 94% rename from src/rollback.rs rename to crates/vm2/src/rollback.rs index 2b1c9f6d..a04b2c30 100644 --- a/src/rollback.rs +++ b/crates/vm2/src/rollback.rs @@ -9,7 +9,7 @@ pub(crate) trait Rollback { } #[derive(Default)] -pub struct RollbackableMap { +pub(crate) struct RollbackableMap { map: BTreeMap, old_entries: Vec<(K, Option)>, } @@ -64,8 +64,8 @@ impl AsRef> for RollbackableMap { } } -#[derive(Default)] -pub struct RollbackableSet { +#[derive(Debug, Default)] +pub(crate) struct RollbackableSet { map: BTreeMap, old_entries: Vec, } @@ -105,7 +105,8 @@ impl AsRef> for RollbackableSet { } } -pub struct RollbackableLog { +#[derive(Debug)] +pub(crate) struct RollbackableLog { entries: Vec, } @@ -149,7 +150,7 @@ impl AsRef<[T]> for RollbackableLog { /// Rollbackable Plain Old Data simply stores copies of itself in snapshots. #[derive(Default, Copy, Clone)] -pub struct RollbackablePod(pub T); +pub(crate) struct RollbackablePod(pub T); impl Rollback for RollbackablePod { type Snapshot = T; diff --git a/src/single_instruction_test/callframe.rs b/crates/vm2/src/single_instruction_test/callframe.rs similarity index 98% rename from src/single_instruction_test/callframe.rs rename to crates/vm2/src/single_instruction_test/callframe.rs index f2ac3839..d389ca49 100644 --- a/src/single_instruction_test/callframe.rs +++ b/crates/vm2/src/single_instruction_test/callframe.rs @@ -1,3 +1,8 @@ +use arbitrary::Arbitrary; +use primitive_types::H160; +use zkevm_opcode_defs::EVM_SIMULATOR_STIPEND; +use zksync_vm2_interface::Tracer; + use super::{ heap::FIRST_AUX_HEAP, stack::{Stack, StackPool}, @@ -6,10 +11,6 @@ use crate::{ callframe::Callframe, decommit::is_kernel, predication::Flags, HeapId, Program, World, WorldDiff, }; -use arbitrary::Arbitrary; -use eravm_stable_interface::Tracer; -use u256::H160; -use zkevm_opcode_defs::EVM_SIMULATOR_STIPEND; impl<'a> Arbitrary<'a> for Flags { fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { diff --git a/src/single_instruction_test/heap.rs b/crates/vm2/src/single_instruction_test/heap.rs similarity index 89% rename from src/single_instruction_test/heap.rs rename to crates/vm2/src/single_instruction_test/heap.rs index 20bfea89..a8ed5ca1 100644 --- a/src/single_instruction_test/heap.rs +++ b/crates/vm2/src/single_instruction_test/heap.rs @@ -1,9 +1,10 @@ -use super::mock_array::MockRead; -use crate::instruction_handlers::HeapInterface; -use arbitrary::Arbitrary; -use eravm_stable_interface::HeapId; use std::ops::Index; -use u256::U256; + +use arbitrary::Arbitrary; +use primitive_types::U256; +use zksync_vm2_interface::HeapId; + +use super::mock_array::MockRead; #[derive(Debug, Clone)] pub struct Heap { @@ -20,15 +21,13 @@ impl Heap { pub(crate) fn read_byte(&self, _: u32) -> u8 { unimplemented!() } -} -impl HeapInterface for Heap { - fn read_u256(&self, start_address: u32) -> U256 { + pub(crate) fn read_u256(&self, start_address: u32) -> U256 { assert!(self.write.is_none()); U256::from_little_endian(self.read.get(start_address)) } - fn read_u256_partially(&self, range: std::ops::Range) -> U256 { + pub(crate) fn read_u256_partially(&self, range: std::ops::Range) -> U256 { assert!(self.write.is_none()); let mut result = *self.read.get(range.start); for byte in &mut result[0..32 - range.len()] { @@ -37,7 +36,7 @@ impl HeapInterface for Heap { U256::from_little_endian(&result) } - fn read_range_big_endian(&self, _: std::ops::Range) -> Vec { + pub(crate) fn read_range_big_endian(&self, _: std::ops::Range) -> Vec { // This is wrong, but this method is only used to get the final return value. vec![] } diff --git a/src/single_instruction_test/into_zk_evm.rs b/crates/vm2/src/single_instruction_test/into_zk_evm.rs similarity index 98% rename from src/single_instruction_test/into_zk_evm.rs rename to crates/vm2/src/single_instruction_test/into_zk_evm.rs index 13470752..e7e4c8cc 100644 --- a/src/single_instruction_test/into_zk_evm.rs +++ b/crates/vm2/src/single_instruction_test/into_zk_evm.rs @@ -1,11 +1,6 @@ use std::sync::Arc; -use super::{stack::Stack, state_to_zk_evm::vm2_state_to_zk_evm_state, MockWorld}; -use crate::{ - zkevm_opcode_defs::decoding::EncodingModeProduction, StorageInterface, VirtualMachine, -}; -use eravm_stable_interface::Tracer; -use u256::U256; +use primitive_types::U256; use zk_evm::{ abstractions::{DecommittmentProcessor, Memory, MemoryType, PrecompilesProcessor, Storage}, aux_structures::PubdataCost, @@ -16,7 +11,11 @@ use zk_evm::{ witness_trace::VmWitnessTracer, }; use zk_evm_abstractions::vm::EventSink; -use zkevm_opcode_defs::TRANSIENT_STORAGE_AUX_BYTE; +use zkevm_opcode_defs::{decoding::EncodingModeProduction, TRANSIENT_STORAGE_AUX_BYTE}; +use zksync_vm2_interface::Tracer; + +use super::{stack::Stack, state_to_zk_evm::vm2_state_to_zk_evm_state, MockWorld}; +use crate::{StorageInterface, VirtualMachine}; type ZkEvmState = VmState< MockWorldWrapper, diff --git a/src/single_instruction_test/mock_array.rs b/crates/vm2/src/single_instruction_test/mock_array.rs similarity index 96% rename from src/single_instruction_test/mock_array.rs rename to crates/vm2/src/single_instruction_test/mock_array.rs index c18c237b..4b9eff18 100644 --- a/src/single_instruction_test/mock_array.rs +++ b/crates/vm2/src/single_instruction_test/mock_array.rs @@ -1,6 +1,6 @@ +use std::{cell::Cell, fmt::Debug}; + use arbitrary::Arbitrary; -use std::cell::Cell; -use std::fmt::Debug; #[derive(Clone, Debug)] pub struct MockRead { diff --git a/src/single_instruction_test/mod.rs b/crates/vm2/src/single_instruction_test/mod.rs similarity index 79% rename from src/single_instruction_test/mod.rs rename to crates/vm2/src/single_instruction_test/mod.rs index abd31636..4db72b28 100644 --- a/src/single_instruction_test/mod.rs +++ b/crates/vm2/src/single_instruction_test/mod.rs @@ -5,6 +5,12 @@ //! //! The same kind of mocking in applied to stack memory, the program, the world and callstack. +pub use self::{ + into_zk_evm::{add_heap_to_zk_evm, vm2_to_zk_evm, NoTracer}, + universal_state::UniversalVmState, + world::MockWorld, +}; + mod callframe; pub mod heap; mod into_zk_evm; @@ -17,7 +23,3 @@ mod universal_state; mod validation; mod vm; mod world; - -pub use into_zk_evm::{add_heap_to_zk_evm, vm2_to_zk_evm, NoTracer}; -pub use universal_state::UniversalVmState; -pub use world::MockWorld; diff --git a/src/single_instruction_test/print_mock_info.rs b/crates/vm2/src/single_instruction_test/print_mock_info.rs similarity index 100% rename from src/single_instruction_test/print_mock_info.rs rename to crates/vm2/src/single_instruction_test/print_mock_info.rs diff --git a/src/single_instruction_test/program.rs b/crates/vm2/src/single_instruction_test/program.rs similarity index 97% rename from src/single_instruction_test/program.rs rename to crates/vm2/src/single_instruction_test/program.rs index 50ba1bb4..d7679cb0 100644 --- a/src/single_instruction_test/program.rs +++ b/crates/vm2/src/single_instruction_test/program.rs @@ -1,10 +1,11 @@ -use crate::{decode::decode, Instruction, World}; -use arbitrary::Arbitrary; -use eravm_stable_interface::Tracer; use std::{rc::Rc, sync::Arc}; -use u256::U256; + +use arbitrary::Arbitrary; +use primitive_types::U256; +use zksync_vm2_interface::Tracer; use super::mock_array::MockRead; +use crate::{decode::decode, Instruction, World}; #[derive(Debug)] pub struct Program { diff --git a/src/single_instruction_test/stack.rs b/crates/vm2/src/single_instruction_test/stack.rs similarity index 99% rename from src/single_instruction_test/stack.rs rename to crates/vm2/src/single_instruction_test/stack.rs index d6cc12e4..6618bd39 100644 --- a/src/single_instruction_test/stack.rs +++ b/crates/vm2/src/single_instruction_test/stack.rs @@ -1,8 +1,9 @@ +use primitive_types::U256; + use super::{ mock_array::MockRead, validation::is_valid_tagged_value, vm::arbitrary_register_value, }; use crate::HeapId; -use u256::U256; #[derive(PartialEq, Debug, Clone)] pub struct Stack { diff --git a/src/single_instruction_test/state_to_zk_evm.rs b/crates/vm2/src/single_instruction_test/state_to_zk_evm.rs similarity index 98% rename from src/single_instruction_test/state_to_zk_evm.rs rename to crates/vm2/src/single_instruction_test/state_to_zk_evm.rs index 907b944b..b6127f82 100644 --- a/src/single_instruction_test/state_to_zk_evm.rs +++ b/crates/vm2/src/single_instruction_test/state_to_zk_evm.rs @@ -1,12 +1,14 @@ -use crate::callframe::{Callframe, NearCallFrame}; -use eravm_stable_interface::Tracer; use std::iter; -use u256::U256; + +use primitive_types::U256; use zk_evm::{ aux_structures::{MemoryPage, PubdataCost}, vm_state::{execution_stack::CallStackEntry, Callstack, PrimitiveValue, VmLocalState}, }; use zkevm_opcode_defs::decoding::EncodingModeProduction; +use zksync_vm2_interface::Tracer; + +use crate::callframe::{Callframe, NearCallFrame}; pub(crate) fn vm2_state_to_zk_evm_state( state: &crate::State, diff --git a/src/single_instruction_test/universal_state.rs b/crates/vm2/src/single_instruction_test/universal_state.rs similarity index 99% rename from src/single_instruction_test/universal_state.rs rename to crates/vm2/src/single_instruction_test/universal_state.rs index fa108b54..4cd5e898 100644 --- a/src/single_instruction_test/universal_state.rs +++ b/crates/vm2/src/single_instruction_test/universal_state.rs @@ -1,4 +1,4 @@ -use u256::{H160, U256}; +use primitive_types::{H160, U256}; use zk_evm::{ reference_impls::event_sink::InMemoryEventSink, vm_state::{CallStackEntry, VmLocalState, VmState}, diff --git a/src/single_instruction_test/validation.rs b/crates/vm2/src/single_instruction_test/validation.rs similarity index 96% rename from src/single_instruction_test/validation.rs rename to crates/vm2/src/single_instruction_test/validation.rs index df4eed4d..4b54f23f 100644 --- a/src/single_instruction_test/validation.rs +++ b/crates/vm2/src/single_instruction_test/validation.rs @@ -1,5 +1,6 @@ +use primitive_types::U256; + use crate::{callframe::Callframe, fat_pointer::FatPointer, State}; -use u256::U256; pub(crate) fn is_valid_tagged_value((value, is_pointer): (U256, bool)) -> bool { if is_pointer { diff --git a/src/single_instruction_test/vm.rs b/crates/vm2/src/single_instruction_test/vm.rs similarity index 93% rename from src/single_instruction_test/vm.rs rename to crates/vm2/src/single_instruction_test/vm.rs index 62b8ca14..5585a23a 100644 --- a/src/single_instruction_test/vm.rs +++ b/crates/vm2/src/single_instruction_test/vm.rs @@ -1,17 +1,20 @@ +use std::fmt::Debug; + +use arbitrary::Arbitrary; +use primitive_types::U256; +use zksync_vm2_interface::Tracer; + use super::{heap::Heaps, stack::StackPool}; use crate::{ - addressing_modes::Arguments, callframe::Callframe, fat_pointer::FatPointer, - instruction::ExecutionStatus, HeapId, Instruction, ModeRequirements, Predicate, Settings, - State, VirtualMachine, World, + addressing_modes::Arguments, callframe::Callframe, fat_pointer::FatPointer, HeapId, + Instruction, ModeRequirements, Predicate, Settings, State, VirtualMachine, World, }; -use arbitrary::Arbitrary; -use eravm_stable_interface::Tracer; -use std::fmt::Debug; -use u256::U256; impl VirtualMachine { - pub fn run_single_instruction(&mut self, world: &mut W, tracer: &mut T) -> ExecutionStatus { - unsafe { ((*self.state.current_frame.pc).handler)(self, world, tracer) } + pub fn run_single_instruction(&mut self, world: &mut W, tracer: &mut T) { + unsafe { + ((*self.state.current_frame.pc).handler)(self, world, tracer); + } } pub fn is_in_valid_state(&self) -> bool { diff --git a/src/single_instruction_test/world.rs b/crates/vm2/src/single_instruction_test/world.rs similarity index 91% rename from src/single_instruction_test/world.rs rename to crates/vm2/src/single_instruction_test/world.rs index 1dc7d6c9..500757c1 100644 --- a/src/single_instruction_test/world.rs +++ b/crates/vm2/src/single_instruction_test/world.rs @@ -1,8 +1,9 @@ +use arbitrary::Arbitrary; +use primitive_types::{H160, U256}; +use zksync_vm2_interface::Tracer; + use super::mock_array::MockRead; use crate::{Program, StorageInterface, World}; -use arbitrary::Arbitrary; -use eravm_stable_interface::Tracer; -use u256::{H160, U256}; #[derive(Debug, Arbitrary, Clone)] pub struct MockWorld { diff --git a/src/stack.rs b/crates/vm2/src/stack.rs similarity index 98% rename from src/stack.rs rename to crates/vm2/src/stack.rs index 9774e954..6236b47e 100644 --- a/src/stack.rs +++ b/crates/vm2/src/stack.rs @@ -1,12 +1,14 @@ -use crate::{bitset::Bitset, fat_pointer::FatPointer, hash_for_debugging}; use std::{ alloc::{alloc, alloc_zeroed, Layout}, fmt, }; -use u256::U256; + +use primitive_types::U256; + +use crate::{bitset::Bitset, fat_pointer::FatPointer, hash_for_debugging}; #[derive(PartialEq)] -pub struct Stack { +pub(crate) struct Stack { /// set of slots that may be interpreted as [`FatPointer`]. pointer_flags: Bitset, dirty_areas: u64, diff --git a/src/state.rs b/crates/vm2/src/state.rs similarity index 96% rename from src/state.rs rename to crates/vm2/src/state.rs index ec7fcd0d..c3cb86c6 100644 --- a/src/state.rs +++ b/crates/vm2/src/state.rs @@ -1,3 +1,5 @@ +use primitive_types::{H160, U256}; + use crate::{ addressing_modes::Addressable, callframe::{Callframe, CallframeSnapshot}, @@ -8,25 +10,19 @@ use crate::{ stack::Stack, world_diff::Snapshot, }; -use u256::{H160, U256}; +// TODO: reduce visibility once `multivm` uses `StateInterface` APIs #[derive(Debug)] pub struct State { - pub registers: [U256; 16], + pub(crate) registers: [U256; 16], pub(crate) register_pointer_flags: u16, - - pub flags: Flags, - + pub(crate) flags: Flags, pub current_frame: Callframe, - /// Contains indices to the far call instructions currently being executed. /// They are needed to continue execution from the correct spot upon return. pub previous_frames: Vec>, - pub heaps: Heaps, - - pub transaction_number: u16, - + pub(crate) transaction_number: u16, pub(crate) context_u128: u128, } diff --git a/src/testworld.rs b/crates/vm2/src/testworld.rs similarity index 90% rename from src/testworld.rs rename to crates/vm2/src/testworld.rs index 4e957fd6..0bb0e3c4 100644 --- a/src/testworld.rs +++ b/crates/vm2/src/testworld.rs @@ -1,13 +1,15 @@ -use crate::{address_into_u256, Program, StorageInterface, World}; -use eravm_stable_interface::Tracer; use std::{ collections::{hash_map::DefaultHasher, BTreeMap}, hash::{Hash, Hasher}, }; -use u256::U256; + +use primitive_types::{H160, U256}; use zkevm_opcode_defs::{ ethereum_types::Address, system_params::DEPLOYER_SYSTEM_CONTRACT_ADDRESS_LOW, }; +use zksync_vm2_interface::Tracer; + +use crate::{address_into_u256, Program, StorageInterface, World}; #[derive(Debug)] pub struct TestWorld { @@ -42,7 +44,7 @@ impl TestWorld { } impl World for TestWorld { - fn decommit(&mut self, hash: u256::U256) -> Program { + fn decommit(&mut self, hash: U256) -> Program { if let Some(program) = self.hash_to_contract.get(&hash) { program.clone() } else { @@ -64,7 +66,7 @@ impl World for TestWorld { } impl StorageInterface for TestWorld { - fn read_storage(&mut self, contract: u256::H160, key: u256::U256) -> Option { + fn read_storage(&mut self, contract: H160, key: U256) -> Option { let deployer_system_contract_address = Address::from_low_u64_be(DEPLOYER_SYSTEM_CONTRACT_ADDRESS_LOW as u64); @@ -84,7 +86,7 @@ impl StorageInterface for TestWorld { 50 } - fn is_free_storage_slot(&self, _contract: &u256::H160, _key: &U256) -> bool { + fn is_free_storage_slot(&self, _contract: &H160, _key: &U256) -> bool { false } } diff --git a/src/tracing.rs b/crates/vm2/src/tracing.rs similarity index 90% rename from src/tracing.rs rename to crates/vm2/src/tracing.rs index 5e266614..4c196abb 100644 --- a/src/tracing.rs +++ b/crates/vm2/src/tracing.rs @@ -1,21 +1,24 @@ +use std::cmp::Ordering; + +use primitive_types::{H160, U256}; +use zksync_vm2_interface::*; + use crate::{ callframe::{Callframe, NearCallFrame}, decommit::is_kernel, predication::{self, Predicate}, VirtualMachine, }; -use eravm_stable_interface::*; -use std::cmp::Ordering; impl StateInterface for VirtualMachine { - fn read_register(&self, register: u8) -> (u256::U256, bool) { + fn read_register(&self, register: u8) -> (U256, bool) { ( self.state.registers[register as usize], self.state.register_pointer_flags & (1 << register) != 0, ) } - fn set_register(&mut self, register: u8, value: u256::U256, is_pointer: bool) { + fn set_register(&mut self, register: u8, value: U256, is_pointer: bool) { self.state.registers[register as usize] = value; self.state.register_pointer_flags &= !(1 << register); @@ -99,23 +102,21 @@ impl StateInterface for VirtualMachine { self.state.context_u128 = value; } - fn get_storage_state(&self) -> impl Iterator { + fn get_storage_state(&self) -> impl Iterator { self.world_diff .get_storage_state() .iter() .map(|(key, value)| (*key, *value)) } - fn get_transient_storage_state( - &self, - ) -> impl Iterator { + fn get_transient_storage_state(&self) -> impl Iterator { self.world_diff .get_transient_storage_state() .iter() .map(|(key, value)| (*key, *value)) } - fn get_transient_storage(&self, address: u256::H160, slot: u256::U256) -> u256::U256 { + fn get_transient_storage(&self, address: H160, slot: U256) -> U256 { self.world_diff .get_transient_storage_state() .get(&(address, slot)) @@ -123,12 +124,7 @@ impl StateInterface for VirtualMachine { .unwrap_or_default() } - fn write_transient_storage( - &mut self, - address: u256::H160, - slot: u256::U256, - value: u256::U256, - ) { + fn write_transient_storage(&mut self, address: H160, slot: U256, value: U256) { self.world_diff .write_transient_storage(address, slot, value) } @@ -169,28 +165,28 @@ struct CallframeWrapper<'a, T, W> { } impl CallframeInterface for CallframeWrapper<'_, T, W> { - fn address(&self) -> u256::H160 { + fn address(&self) -> H160 { self.frame.address } - fn set_address(&mut self, address: u256::H160) { + fn set_address(&mut self, address: H160) { self.frame.address = address; self.frame.is_kernel = is_kernel(address); } - fn code_address(&self) -> u256::H160 { + fn code_address(&self) -> H160 { self.frame.code_address } - fn set_code_address(&mut self, address: u256::H160) { + fn set_code_address(&mut self, address: H160) { self.frame.code_address = address; } - fn caller(&self) -> u256::H160 { + fn caller(&self) -> H160 { self.frame.caller } - fn set_caller(&mut self, address: u256::H160) { + fn set_caller(&mut self, address: H160) { self.frame.caller = address; } @@ -214,14 +210,14 @@ impl CallframeInterface for CallframeWrapper<'_, T, W> { self.frame.context_u128 = value; } - fn read_stack(&self, index: u16) -> (u256::U256, bool) { + fn read_stack(&self, index: u16) -> (U256, bool) { ( self.frame.stack.get(index), self.frame.stack.get_pointer_flag(index), ) } - fn write_stack(&mut self, index: u16, value: u256::U256, is_pointer: bool) { + fn write_stack(&mut self, index: u16, value: U256, is_pointer: bool) { self.frame.stack.set(index, value); if is_pointer { self.frame.stack.set_pointer_flag(index); @@ -254,7 +250,7 @@ impl CallframeInterface for CallframeWrapper<'_, T, W> { self.frame.aux_heap_size = value; } - fn read_code_page(&self, slot: u16) -> u256::U256 { + fn read_code_page(&self, slot: u16) -> U256 { self.frame.program.code_page()[slot as usize] } @@ -359,11 +355,12 @@ impl CallframeWrapper<'_, T, W> { #[cfg(all(test, not(feature = "single_instruction_test")))] mod test { + use primitive_types::H160; + use zkevm_opcode_defs::ethereum_types::Address; + use zksync_vm2_interface::HeapId; + use super::*; use crate::{initial_decommit, testworld::TestWorld, Instruction, Program, VirtualMachine}; - use eravm_stable_interface::HeapId; - use u256::H160; - use zkevm_opcode_defs::ethereum_types::Address; #[test] fn callframe_picking() { diff --git a/src/vm.rs b/crates/vm2/src/vm.rs similarity index 94% rename from src/vm.rs rename to crates/vm2/src/vm.rs index ebd90203..7024ba81 100644 --- a/src/vm.rs +++ b/crates/vm2/src/vm.rs @@ -1,20 +1,17 @@ -use crate::addressing_modes::Arguments; -use crate::instruction::ExecutionStatus; -use crate::instruction_handlers::RETURN_COST; -use crate::state::StateSnapshot; -use crate::world_diff::ExternalSnapshot; +use primitive_types::H160; +use zksync_vm2_interface::{opcodes::TypeLevelCallingMode, CallingMode, HeapId, Tracer}; + use crate::{ + addressing_modes::Arguments, callframe::{Callframe, FrameRemnant}, decommit::u256_into_address, + instruction::ExecutionStatus, + instruction_handlers::RETURN_COST, stack::StackPool, - state::State, - world_diff::{Snapshot, WorldDiff}, - ExecutionEnd, Program, + state::{State, StateSnapshot}, + world_diff::{ExternalSnapshot, Snapshot, WorldDiff}, + ExecutionEnd, Instruction, ModeRequirements, Predicate, Program, }; -use crate::{Instruction, ModeRequirements, Predicate}; -use eravm_stable_interface::opcodes::TypeLevelCallingMode; -use eravm_stable_interface::{CallingMode, HeapId, Tracer}; -use u256::H160; #[derive(Debug)] pub struct Settings { diff --git a/src/world_diff.rs b/crates/vm2/src/world_diff.rs similarity index 99% rename from src/world_diff.rs rename to crates/vm2/src/world_diff.rs index 4fca03bb..5d747698 100644 --- a/src/world_diff.rs +++ b/crates/vm2/src/world_diff.rs @@ -1,15 +1,16 @@ use std::collections::BTreeMap; -use crate::{ - rollback::{Rollback, RollbackableLog, RollbackableMap, RollbackablePod, RollbackableSet}, - StorageInterface, -}; -use eravm_stable_interface::{CycleStats, Tracer}; -use u256::{H160, U256}; +use primitive_types::{H160, U256}; use zkevm_opcode_defs::system_params::{ STORAGE_ACCESS_COLD_READ_COST, STORAGE_ACCESS_COLD_WRITE_COST, STORAGE_ACCESS_WARM_READ_COST, STORAGE_ACCESS_WARM_WRITE_COST, }; +use zksync_vm2_interface::{CycleStats, Tracer}; + +use crate::{ + rollback::{Rollback, RollbackableLog, RollbackableMap, RollbackablePod, RollbackableSet}, + StorageInterface, +}; /// Pending modifications to the global state that are executed at the end of a block. /// In other words, side effects. @@ -375,9 +376,10 @@ const COLD_WRITE_AFTER_WARM_READ_REFUND: u32 = STORAGE_ACCESS_COLD_READ_COST; #[cfg(test)] mod tests { - use super::*; use proptest::prelude::*; + use super::*; + proptest! { #[test] fn test_storage_changes( diff --git a/tests/bytecode_behaviour.rs b/crates/vm2/tests/bytecode_behaviour.rs similarity index 91% rename from tests/bytecode_behaviour.rs rename to crates/vm2/tests/bytecode_behaviour.rs index 436ee6f0..af0023e4 100644 --- a/tests/bytecode_behaviour.rs +++ b/crates/vm2/tests/bytecode_behaviour.rs @@ -1,12 +1,12 @@ #![cfg(not(feature = "single_instruction_test"))] -use eravm_stable_interface::Tracer; -use u256::U256; -use vm2::{ +use primitive_types::U256; +use zkevm_opcode_defs::ethereum_types::Address; +use zksync_vm2::{ decode::decode_program, initial_decommit, testworld::TestWorld, ExecutionEnd, Program, - VirtualMachine, World, + Settings, VirtualMachine, World, }; -use zkevm_opcode_defs::ethereum_types::Address; +use zksync_vm2_interface::Tracer; fn program_from_file>(filename: &str) -> Program { let blob = std::fs::read(filename).unwrap(); @@ -40,7 +40,7 @@ fn call_to_invalid_address() { Address::zero(), vec![], 10000, - vm2::Settings { + Settings { default_aa_code_hash: [0; 32], evm_interpreter_code_hash: [0; 32], hook_address: 0, diff --git a/tests/bytecodes/call_far b/crates/vm2/tests/bytecodes/call_far similarity index 100% rename from tests/bytecodes/call_far rename to crates/vm2/tests/bytecodes/call_far diff --git a/tests/far_call_decommitment.rs b/crates/vm2/tests/far_call_decommitment.rs similarity index 92% rename from tests/far_call_decommitment.rs rename to crates/vm2/tests/far_call_decommitment.rs index f9238d72..3452934e 100644 --- a/tests/far_call_decommitment.rs +++ b/crates/vm2/tests/far_call_decommitment.rs @@ -1,18 +1,18 @@ #![cfg(not(feature = "single_instruction_test"))] -use eravm_stable_interface::opcodes; use std::collections::HashSet; -use u256::{H160, U256}; -use vm2::addressing_modes::{ - Arguments, CodePage, Immediate1, Register, Register1, Register2, RegisterAndImmediate, -}; -use vm2::instruction_handlers::Heap; -use vm2::testworld::TestWorld; -use vm2::{ - initial_decommit, ExecutionEnd, Instruction, ModeRequirements, Predicate, Program, - VirtualMachine, -}; + +use primitive_types::{H160, U256}; use zkevm_opcode_defs::ethereum_types::Address; +use zksync_vm2::{ + addressing_modes::{ + Arguments, CodePage, Immediate1, Register, Register1, Register2, RegisterAndImmediate, + }, + initial_decommit, + testworld::TestWorld, + ExecutionEnd, Instruction, ModeRequirements, Predicate, Program, Settings, VirtualMachine, +}; +use zksync_vm2_interface::opcodes; const GAS_TO_PASS: u32 = 10_000; const LARGE_BYTECODE_LEN: usize = 10_000; @@ -67,7 +67,7 @@ fn create_test_world() -> TestWorld<()> { Arguments::new(Predicate::Always, 200, ModeRequirements::none()), ), // 3: Hook (0) - Instruction::from_store::( + Instruction::from_heap_store( Register1(r0).into(), Register2(r0), None, @@ -127,7 +127,7 @@ fn test() { Address::zero(), vec![], initial_gas, - vm2::Settings { + Settings { default_aa_code_hash: [0; 32], evm_interpreter_code_hash: [0; 32], hook_address: 0, @@ -163,7 +163,7 @@ fn test_with_initial_out_of_gas_error() { Address::zero(), vec![], 10_000, - vm2::Settings { + Settings { default_aa_code_hash: [0; 32], evm_interpreter_code_hash: [0; 32], hook_address: 0, diff --git a/tests/panic.proptest-regressions b/crates/vm2/tests/panic.proptest-regressions similarity index 100% rename from tests/panic.proptest-regressions rename to crates/vm2/tests/panic.proptest-regressions diff --git a/tests/panic.rs b/crates/vm2/tests/panic.rs similarity index 96% rename from tests/panic.rs rename to crates/vm2/tests/panic.rs index c6721c83..272ac366 100644 --- a/tests/panic.rs +++ b/crates/vm2/tests/panic.rs @@ -1,13 +1,13 @@ #![cfg(not(feature = "single_instruction_test"))] use proptest::prelude::*; -use vm2::{ +use zkevm_opcode_defs::ethereum_types::Address; +use zksync_vm2::{ addressing_modes::{Arguments, Immediate1, Immediate2, Register, Register1}, initial_decommit, testworld::TestWorld, - ExecutionEnd, Instruction, ModeRequirements, Predicate, Program, VirtualMachine, + ExecutionEnd, Instruction, ModeRequirements, Predicate, Program, Settings, VirtualMachine, }; -use zkevm_opcode_defs::ethereum_types::Address; proptest! { #[test] @@ -41,7 +41,7 @@ proptest! { Address::zero(), vec![], 1000, - vm2::Settings { + Settings { default_aa_code_hash: [0; 32], evm_interpreter_code_hash: [0; 32], hook_address: 0, diff --git a/tests/stipend.rs b/crates/vm2/tests/stipend.rs similarity index 97% rename from tests/stipend.rs rename to crates/vm2/tests/stipend.rs index d1832d1d..65470b51 100644 --- a/tests/stipend.rs +++ b/crates/vm2/tests/stipend.rs @@ -1,18 +1,17 @@ #![cfg(not(feature = "single_instruction_test"))] -use eravm_stable_interface::opcodes; -use u256::U256; -use vm2::{ +use primitive_types::U256; +use zkevm_opcode_defs::ethereum_types::Address; +use zksync_vm2::{ address_into_u256, addressing_modes::{ Arguments, CodePage, Immediate1, Register, Register1, Register2, RegisterAndImmediate, }, initial_decommit, - instruction_handlers::Add, testworld::TestWorld, - ExecutionEnd, Instruction, ModeRequirements, Predicate, Program, VirtualMachine, + ExecutionEnd, Instruction, ModeRequirements, Predicate, Program, Settings, VirtualMachine, }; -use zkevm_opcode_defs::ethereum_types::Address; +use zksync_vm2_interface::opcodes::{self, Add}; const INITIAL_GAS: u32 = 1000; @@ -113,7 +112,7 @@ fn test_scenario(gas_to_pass: u32) -> (ExecutionEnd, u32) { Address::zero(), vec![], INITIAL_GAS, - vm2::Settings { + Settings { default_aa_code_hash: [0; 32], evm_interpreter_code_hash: interpreter_hash, hook_address: 0, diff --git a/eravm-stable-interface/Cargo.toml b/eravm-stable-interface/Cargo.toml deleted file mode 100644 index 9d0757b2..00000000 --- a/eravm-stable-interface/Cargo.toml +++ /dev/null @@ -1,9 +0,0 @@ -[package] -name = "eravm-stable-interface" -version = "0.1.0" -edition.workspace = true -license.workspace = true -authors.workspace = true - -[dependencies] -primitive-types = "0.12.1" diff --git a/afl-fuzz/.gitignore b/tests/afl-fuzz/.gitignore similarity index 100% rename from afl-fuzz/.gitignore rename to tests/afl-fuzz/.gitignore diff --git a/tests/afl-fuzz/Cargo.toml b/tests/afl-fuzz/Cargo.toml new file mode 100644 index 00000000..6a0dbdff --- /dev/null +++ b/tests/afl-fuzz/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "zksync_vm2_afl_fuzz" +version.workspace = true +edition.workspace = true +authors.workspace = true +homepage.workspace = true +repository.workspace = true +license.workspace = true +keywords.workspace = true +categories.workspace = true +publish = false + +[dependencies] +afl.workspace = true +arbitrary.workspace = true +pretty_assertions.workspace = true +zkevm_opcode_defs.workspace = true +zksync_vm2_interface.workspace = true +zksync_vm2 = { workspace = true, features = ["single_instruction_test"] } + +[[bin]] +name = "show_testcase" +path = "src/show_testcase.rs" + +[[bin]] +name = "check_input_size" +path = "src/check_input_size.rs" diff --git a/afl-fuzz/README.md b/tests/afl-fuzz/README.md similarity index 81% rename from afl-fuzz/README.md rename to tests/afl-fuzz/README.md index 1439d00d..a68e0929 100644 --- a/afl-fuzz/README.md +++ b/tests/afl-fuzz/README.md @@ -5,9 +5,9 @@ Finds divergences and instructions that put vm2 in an invalid state. Setup: `cargo install cargo-afl` -Use `sh fuzz.sh` (or customize the command to your liking) to start fuzzing. +Use `sh fuzz.sh` (or customize the command to your liking) to start fuzzing. `show_crash.sh` can be used to quickly run one of the found crashes and display all the necessary information for fixing it. The size of the search space is relatively small due to tricks explained in the single_instruction_test module. -`cargo run --bin check_input_size` prints out an estimate of the amount of information in the state in bytes. \ No newline at end of file +`cargo run --bin check_input_size` prints out an estimate of the amount of information in the state in bytes. diff --git a/afl-fuzz/fuzz.sh b/tests/afl-fuzz/fuzz.sh similarity index 100% rename from afl-fuzz/fuzz.sh rename to tests/afl-fuzz/fuzz.sh diff --git a/afl-fuzz/in/kernel_to_msg_value_far_call_forward_fat_pointer b/tests/afl-fuzz/in/kernel_to_msg_value_far_call_forward_fat_pointer similarity index 100% rename from afl-fuzz/in/kernel_to_msg_value_far_call_forward_fat_pointer rename to tests/afl-fuzz/in/kernel_to_msg_value_far_call_forward_fat_pointer diff --git a/afl-fuzz/in/return_calldata b/tests/afl-fuzz/in/return_calldata similarity index 100% rename from afl-fuzz/in/return_calldata rename to tests/afl-fuzz/in/return_calldata diff --git a/afl-fuzz/show_crash.sh b/tests/afl-fuzz/show_crash.sh similarity index 100% rename from afl-fuzz/show_crash.sh rename to tests/afl-fuzz/show_crash.sh diff --git a/afl-fuzz/src/check_input_size.rs b/tests/afl-fuzz/src/check_input_size.rs similarity index 89% rename from afl-fuzz/src/check_input_size.rs rename to tests/afl-fuzz/src/check_input_size.rs index 72bcedca..9deed3df 100644 --- a/afl-fuzz/src/check_input_size.rs +++ b/tests/afl-fuzz/src/check_input_size.rs @@ -1,6 +1,6 @@ //! Finds out how many bytes of data have to be provided to build the mock state. -use differential_fuzzing::VmAndWorld; +use zksync_vm2_afl_fuzz::VmAndWorld; fn main() { const BYTES_GIVEN: usize = 10000; diff --git a/afl-fuzz/src/lib.rs b/tests/afl-fuzz/src/lib.rs similarity index 60% rename from afl-fuzz/src/lib.rs rename to tests/afl-fuzz/src/lib.rs index 52f33d27..839c5cde 100644 --- a/afl-fuzz/src/lib.rs +++ b/tests/afl-fuzz/src/lib.rs @@ -1,6 +1,6 @@ use arbitrary::Arbitrary; -use eravm_stable_interface::Tracer; -use vm2::{single_instruction_test::MockWorld, VirtualMachine}; +use zksync_vm2::{single_instruction_test::MockWorld, VirtualMachine}; +use zksync_vm2_interface::Tracer; #[derive(Arbitrary, Debug)] pub struct VmAndWorld { diff --git a/afl-fuzz/src/main.rs b/tests/afl-fuzz/src/main.rs similarity index 89% rename from afl-fuzz/src/main.rs rename to tests/afl-fuzz/src/main.rs index a48730a8..e8f3fd25 100644 --- a/afl-fuzz/src/main.rs +++ b/tests/afl-fuzz/src/main.rs @@ -1,5 +1,7 @@ -use differential_fuzzing::VmAndWorld; -use vm2::single_instruction_test::{add_heap_to_zk_evm, vm2_to_zk_evm, NoTracer, UniversalVmState}; +use zksync_vm2::single_instruction_test::{ + add_heap_to_zk_evm, vm2_to_zk_evm, NoTracer, UniversalVmState, +}; +use zksync_vm2_afl_fuzz::VmAndWorld; fn main() { afl::fuzz!(|data: &[u8]| { diff --git a/afl-fuzz/src/show_testcase.rs b/tests/afl-fuzz/src/show_testcase.rs similarity index 78% rename from afl-fuzz/src/show_testcase.rs rename to tests/afl-fuzz/src/show_testcase.rs index 04f2e521..087bddf8 100644 --- a/afl-fuzz/src/show_testcase.rs +++ b/tests/afl-fuzz/src/show_testcase.rs @@ -1,12 +1,11 @@ -use differential_fuzzing::VmAndWorld; +use std::{env, fs}; + use pretty_assertions::assert_eq; -use std::env; -use std::fs; -use vm2::single_instruction_test::add_heap_to_zk_evm; -use vm2::single_instruction_test::vm2_to_zk_evm; -use vm2::single_instruction_test::NoTracer; -use vm2::single_instruction_test::UniversalVmState; -use vm2::zkevm_opcode_defs::decoding::{EncodingModeProduction, VmEncodingMode}; +use zkevm_opcode_defs::decoding::{EncodingModeProduction, VmEncodingMode}; +use zksync_vm2::single_instruction_test::{ + add_heap_to_zk_evm, vm2_to_zk_evm, NoTracer, UniversalVmState, +}; +use zksync_vm2_afl_fuzz::VmAndWorld; fn main() { let filename = env::args()