diff --git a/.github/workflows/bench.yml b/.github/workflows/bench.yml index 00cebb3590..ddf45554aa 100644 --- a/.github/workflows/bench.yml +++ b/.github/workflows/bench.yml @@ -14,7 +14,7 @@ jobs: codspeed: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: submodules: true - uses: dtolnay/rust-toolchain@stable diff --git a/.github/workflows/book.yml b/.github/workflows/book.yml index 8733a73aba..919f41802f 100644 --- a/.github/workflows/book.yml +++ b/.github/workflows/book.yml @@ -17,7 +17,7 @@ jobs: name: test steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Install mdbook run: | @@ -42,7 +42,7 @@ jobs: name: lint steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Install mdbook-linkcheck run: | @@ -58,7 +58,7 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 with: fetch-depth: 0 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e3df5c7262..9eb02638d6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -20,10 +20,10 @@ jobs: strategy: fail-fast: false matrix: - rust: ["stable", "beta", "nightly"] + rust: ["1.88", "stable", "nightly"] flags: ["--no-default-features", "", "--all-features"] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: dtolnay/rust-toolchain@master with: toolchain: ${{ matrix.rust }} @@ -39,7 +39,7 @@ jobs: matrix: features: ["", "kzg-rs"] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: dtolnay/rust-toolchain@stable with: targets: riscv32imac-unknown-none-elf @@ -55,9 +55,9 @@ jobs: strategy: fail-fast: false matrix: - features: ["", "serde", "std"] + features: ["", "serde", "std", "std,map-foldhash"] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: dtolnay/rust-toolchain@stable - run: cargo check --no-default-features -p revm --features=${{ matrix.features }} @@ -66,7 +66,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 30 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: dtolnay/rust-toolchain@stable - uses: taiki-e/install-action@cargo-hack - uses: Swatinem/rust-cache@v2 @@ -80,7 +80,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 30 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: dtolnay/rust-toolchain@stable - run: cargo clippy --workspace --all-targets --all-features env: @@ -91,7 +91,7 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 30 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: dtolnay/rust-toolchain@stable with: components: rust-docs @@ -104,31 +104,26 @@ jobs: runs-on: ubuntu-latest timeout-minutes: 30 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - uses: dtolnay/rust-toolchain@stable with: components: rustfmt - run: cargo fmt --all --check - # Check crates correctly propagate features feature-propagation: runs-on: ubuntu-latest timeout-minutes: 20 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: run zepter run: | cargo install zepter -f --locked zepter --version time zepter run check - typos-check: - name: TyposCheck - timeout-minutes: 5 + typos: runs-on: ubuntu-latest + timeout-minutes: 30 steps: - - uses: actions/checkout@v4 - - uses: crate-ci/typos@v1.22.7 - with: - config: ./typos.toml - isolated: true + - uses: actions/checkout@v5 + - uses: crate-ci/typos@v1 diff --git a/.github/workflows/ethereum-tests.yml b/.github/workflows/ethereum-tests.yml index 8bd366d24b..c8d6f99f27 100644 --- a/.github/workflows/ethereum-tests.yml +++ b/.github/workflows/ethereum-tests.yml @@ -20,7 +20,7 @@ jobs: target: [i686-unknown-linux-gnu, x86_64-unknown-linux-gnu] steps: - name: Checkout sources - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Install toolchain uses: dtolnay/rust-toolchain@stable diff --git a/.github/workflows/release-plz.yml b/.github/workflows/release-plz.yml index d5b034760d..8390d785d2 100644 --- a/.github/workflows/release-plz.yml +++ b/.github/workflows/release-plz.yml @@ -16,7 +16,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 with: fetch-depth: 0 - name: Install Rust toolchain diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ef1d8d6c3..83f3a8d3b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,26 +1,90 @@ Because this is workspace with multi libraries, tags will be simplified, and with this document you can match version of project with git tag. +# v86 +date: 24.08.2025 + +Maintainance release. PrecompileId added + +* `revm-bytecode`: 6.2.1 -> 6.2.2 (✓ API compatible changes) +* `revm-database-interface`: 7.0.4 -> 7.0.5 (✓ API compatible changes) +* `revm-context-interface`: 10.0.1 -> 10.1.0 (✓ API compatible changes) +* `revm-context`: 9.0.1 -> 9.0.2 (✓ API compatible changes) +* `revm-database`: 7.0.4 -> 7.0.5 (✓ API compatible changes) +* `revm-interpreter`: 25.0.1 -> 25.0.2 (✓ API compatible changes) +* `revm-precompile`: 26.0.1 -> 27.0.0 (⚠ API breaking changes) +* `revm-handler`: 9.0.1 -> 10.0.0 (✓ API compatible changes) +* `op-revm`: 9.0.1 -> 10.0.0 (✓ API compatible changes) +* `revm-state`: 7.0.4 -> 7.0.5 +* `revm-inspector`: 9.1.0 -> 10.0.0 +* `revm`: 28.0.1 -> 29.0.0 +* `revm-statetest-types`: 9.0.1 -> 9.0.2 +* `revme`: 7.2.1 -> 7.2.2 + +# v85 +date: 12.08.2025 + +Reverting: "feat: removed padding in case last opcode is terminal (#2816)" (#2883) + +* `revm-primitives`: 20.2.0 -> 20.2.1 (✓ API compatible changes) +* `revm-bytecode`: 6.2.0 -> 6.2.1 (✓ API compatible changes) +* `revm-state`: 7.0.3 -> 7.0.4 (✓ API compatible changes) +* `revm-context-interface`: 10.0.0 -> 10.0.1 (✓ API compatible changes) +* `revm-database`: 7.0.3 -> 7.0.4 (✓ API compatible changes) +* `revm-precompile`: 26.0.0 -> 26.0.1 (✓ API compatible changes) +* `revm-inspector`: 9.0.0 -> 9.1.0 (✓ API compatible changes) +* `revme`: 7.2.0 -> 7.2.1 (✓ API compatible changes) +* `revm-ee-tests`: 0.1.0 +* `revm-database-interface`: 7.0.3 -> 7.0.4 +* `revm-context`: 9.0.0 -> 9.0.1 +* `revm-interpreter`: 25.0.0 -> 25.0.1 +* `revm-handler`: 9.0.0 -> 9.0.1 +* `revm`: 28.0.0 -> 28.0.1 +* `revm-statetest-types`: 9.0.0 -> 9.0.1 +* `op-revm`: 9.0.0 -> 9.0.1 + +# v84 +date: 07.08.2025 + +Small perf and maintainance release. + +revm-inspector@9.0.0 revm@28.0.0 revm-statetest-types@9.0.0 + +* `revm-primitives`: 20.1.0 -> 20.2.0 (✓ API compatible changes) +* `revm-bytecode`: 6.1.0 -> 6.2.0 (✓ API compatible changes) +* `revm-state`: 7.0.2 -> 7.0.3 (✓ API compatible changes) +* `revm-database-interface`: 7.0.2 -> 7.0.3 (✓ API compatible changes) +* `revm-context-interface`: 9.0.0 -> 10.0.0 (⚠ API breaking changes) +* `revm-context`: 8.0.4 -> 9.0.0 (⚠ API breaking changes) +* `revm-database`: 7.0.2 -> 7.0.3 (✓ API compatible changes) +* `revm-interpreter`: 24.0.0 -> 25.0.0 (⚠ API breaking changes) +* `revm-precompile`: 25.0.0 -> 26.0.0 (⚠ API breaking changes) +* `revm-handler`: 8.1.0 -> 9.0.0 (⚠ API breaking changes) +* `revm-inspector`: 8.1.0 -> 9.0.0 (✓ API compatible changes) +* `revm`: 27.1.0 -> 28.0.0 (✓ API compatible changes) +* `revm-statetest-types`: 8.0.5 -> 9.0.0 (✓ API compatible changes) +* `revme`: 7.1.0 -> 7.2.0 (✓ API compatible changes) +* `op-revm`: 8.1.0 -> 9.0.0 (⚠ API breaking changes) # v83 date: 23.07.2025 Fusaka devnet-3 support. Performance regresion fixes. -`revm-primitives`: 20.0.0 -> 20.1.0 (✓ API compatible changes) -`revm-bytecode`: 6.0.1 -> 6.1.0 (✓ API compatible changes) -`revm-database-interface`: 7.0.1 -> 7.0.2 (✓ API compatible changes) -`revm-context-interface`: 8.0.1 -> 9.0.0 (⚠ API breaking changes) -`revm-context`: 8.0.3 -> 8.0.4 (✓ API compatible changes) -`revm-interpreter`: 23.0.2 -> 24.0.0 (⚠ API breaking changes) -`revm-precompile`: 24.0.1 -> 25.0.0 (⚠ API breaking changes) -`revm-handler`: 8.0.3 -> 8.1.0 (✓ API compatible changes) -`revm-inspector`: 8.0.3 -> 8.1.0 (✓ API compatible changes) -`revm`: 27.0.3 -> 27.1.0 (✓ API compatible changes) -`revme`: 7.0.4 -> 7.1.0 (✓ API compatible changes) -`op-revm`: 8.0.3 -> 8.1.0 (✓ API compatible changes) -`revm-state`: 7.0.1 -> 7.0.2 -`revm-database`: 7.0.1 -> 7.0.2 -`revm-statetest-types`: 8.0.4 -> 8.0.5 +* `revm-primitives`: 20.0.0 -> 20.1.0 (✓ API compatible changes) +* `revm-bytecode`: 6.0.1 -> 6.1.0 (✓ API compatible changes) +* `revm-database-interface`: 7.0.1 -> 7.0.2 (✓ API compatible changes) +* `revm-context-interface`: 8.0.1 -> 9.0.0 (⚠ API breaking changes) +* `revm-context`: 8.0.3 -> 8.0.4 (✓ API compatible changes) +* `revm-interpreter`: 23.0.2 -> 24.0.0 (⚠ API breaking changes) +* `revm-precompile`: 24.0.1 -> 25.0.0 (⚠ API breaking changes) +* `revm-handler`: 8.0.3 -> 8.1.0 (✓ API compatible changes) +* `revm-inspector`: 8.0.3 -> 8.1.0 (✓ API compatible changes) +* `revm`: 27.0.3 -> 27.1.0 (✓ API compatible changes) +* `revme`: 7.0.4 -> 7.1.0 (✓ API compatible changes) +* `op-revm`: 8.0.3 -> 8.1.0 (✓ API compatible changes) +* `revm-state`: 7.0.1 -> 7.0.2 +* `revm-database`: 7.0.1 -> 7.0.2 +* `revm-statetest-types`: 8.0.4 -> 8.0.5 # v82 date 14.07.2025 diff --git a/Cargo.lock b/Cargo.lock index 09958e91f3..dfba341dae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1375,7 +1375,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" dependencies = [ "lazy_static", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -1560,14 +1560,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "custom_precompile_journal" -version = "0.1.0" -dependencies = [ - "anyhow", - "revm", -] - [[package]] name = "darling" version = "0.20.11" @@ -1830,7 +1822,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cea14ef9355e3beab063703aa9dab15afd25f0667c341310c1e5274bb1d0da18" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -1869,6 +1861,14 @@ dependencies = [ "revm", ] +[[package]] +name = "example-custom-precompile-journal" +version = "0.1.0" +dependencies = [ + "anyhow", + "revm", +] + [[package]] name = "example-database-components" version = "0.0.0" @@ -2598,7 +2598,7 @@ checksum = "e04d7f318608d35d4b61ddd75cbdaee86b023ebe2bd5a66ee0915f0bf93095a9" dependencies = [ "hermit-abi", "libc", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -3034,12 +3034,11 @@ checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e" [[package]] name = "op-revm" -version = "8.1.0" +version = "10.0.0" dependencies = [ "alloy-primitives", "alloy-sol-types", "auto_impl", - "once_cell", "revm", "rstest", "serde", @@ -3773,7 +3772,7 @@ dependencies = [ [[package]] name = "revm" -version = "27.1.0" +version = "29.0.0" dependencies = [ "revm-bytecode", "revm-context", @@ -3792,10 +3791,9 @@ dependencies = [ [[package]] name = "revm-bytecode" -version = "6.1.0" +version = "6.2.2" dependencies = [ "bitvec", - "once_cell", "paste", "phf", "revm-primitives", @@ -3804,8 +3802,9 @@ dependencies = [ [[package]] name = "revm-context" -version = "8.0.4" +version = "9.0.2" dependencies = [ + "bitvec", "cfg-if", "derive-where", "revm-bytecode", @@ -3819,7 +3818,7 @@ dependencies = [ [[package]] name = "revm-context-interface" -version = "9.0.0" +version = "10.1.0" dependencies = [ "alloy-eip2930", "alloy-eip7702", @@ -3833,17 +3832,15 @@ dependencies = [ [[package]] name = "revm-database" -version = "7.0.2" +version = "7.0.5" dependencies = [ "alloy-eips", "alloy-provider", "alloy-transport", - "anyhow", "revm-bytecode", "revm-database-interface", "revm-primitives", "revm-state", - "rstest", "serde", "serde_json", "tokio", @@ -3851,21 +3848,33 @@ dependencies = [ [[package]] name = "revm-database-interface" -version = "7.0.2" +version = "7.0.5" dependencies = [ - "anyhow", "auto_impl", "either", "revm-primitives", "revm-state", - "rstest", "serde", "tokio", ] +[[package]] +name = "revm-ee-tests" +version = "0.1.0" +dependencies = [ + "alloy-primitives", + "alloy-sol-types", + "op-revm", + "revm", + "rstest", + "serde", + "serde_json", + "sha2 0.10.9", +] + [[package]] name = "revm-handler" -version = "8.1.0" +version = "10.0.0" dependencies = [ "alloy-eip7702", "alloy-provider", @@ -3887,7 +3896,7 @@ dependencies = [ [[package]] name = "revm-inspector" -version = "8.1.0" +version = "10.0.0" dependencies = [ "auto_impl", "either", @@ -3904,7 +3913,7 @@ dependencies = [ [[package]] name = "revm-interpreter" -version = "24.0.0" +version = "25.0.2" dependencies = [ "bincode 2.0.1", "revm-bytecode", @@ -3915,7 +3924,7 @@ dependencies = [ [[package]] name = "revm-precompile" -version = "25.0.0" +version = "27.0.0" dependencies = [ "ark-bls12-381", "ark-bn254", @@ -3932,7 +3941,6 @@ dependencies = [ "k256", "kzg-rs", "libsecp256k1", - "once_cell", "p256", "rand 0.9.1", "revm-primitives", @@ -3946,16 +3954,17 @@ dependencies = [ [[package]] name = "revm-primitives" -version = "20.1.0" +version = "20.2.1" dependencies = [ "alloy-primitives", "num_enum", + "once_cell", "serde", ] [[package]] name = "revm-state" -version = "7.0.2" +version = "7.0.5" dependencies = [ "bitflags", "revm-bytecode", @@ -3965,7 +3974,7 @@ dependencies = [ [[package]] name = "revm-statetest-types" -version = "8.0.5" +version = "9.0.2" dependencies = [ "k256", "revm", @@ -3976,7 +3985,7 @@ dependencies = [ [[package]] name = "revme" -version = "7.1.0" +version = "7.2.2" dependencies = [ "alloy-rlp", "alloy-sol-types", @@ -4077,9 +4086,9 @@ dependencies = [ [[package]] name = "ruint" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11256b5fe8c68f56ac6f39ef0720e592f33d2367a4782740d9c9142e889c7fb4" +checksum = "9ecb38f82477f20c5c3d62ef52d7c4e536e38ea9b73fb570a20c5cae0e14bcf6" dependencies = [ "alloy-rlp", "arbitrary", @@ -4158,7 +4167,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -4720,7 +4729,7 @@ dependencies = [ "getrandom 0.3.3", "once_cell", "rustix", - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] @@ -5271,7 +5280,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.52.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index b096e420d4..dd4f8aaf67 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,6 +22,7 @@ members = [ # utility "crates/statetest-types", + "crates/ee-tests", # examples "examples/block_traces", @@ -40,20 +41,21 @@ default-members = ["crates/revm"] [workspace.dependencies] # revm -revm = { path = "crates/revm", version = "27.1.0", default-features = false } -primitives = { path = "crates/primitives", package = "revm-primitives", version = "20.1.0", default-features = false } -bytecode = { path = "crates/bytecode", package = "revm-bytecode", version = "6.1.0", default-features = false } -database = { path = "crates/database", package = "revm-database", version = "7.0.2", default-features = false } -database-interface = { path = "crates/database/interface", package = "revm-database-interface", version = "7.0.2", default-features = false } -state = { path = "crates/state", package = "revm-state", version = "7.0.2", default-features = false } -interpreter = { path = "crates/interpreter", package = "revm-interpreter", version = "24.0.0", default-features = false } -inspector = { path = "crates/inspector", package = "revm-inspector", version = "8.1.0", default-features = false } -precompile = { path = "crates/precompile", package = "revm-precompile", version = "25.0.0", default-features = false } -statetest-types = { path = "crates/statetest-types", package = "revm-statetest-types", version = "8.0.5", default-features = false } -context = { path = "crates/context", package = "revm-context", version = "8.0.4", default-features = false } -context-interface = { path = "crates/context/interface", package = "revm-context-interface", version = "9.0.0", default-features = false } -handler = { path = "crates/handler", package = "revm-handler", version = "8.1.0", default-features = false } -op-revm = { path = "crates/op-revm", package = "op-revm", version = "8.1.0", default-features = false } +revm = { path = "crates/revm", version = "29.0.0", default-features = false } +primitives = { path = "crates/primitives", package = "revm-primitives", version = "20.2.1", default-features = false } +bytecode = { path = "crates/bytecode", package = "revm-bytecode", version = "6.2.2", default-features = false } +database = { path = "crates/database", package = "revm-database", version = "7.0.5", default-features = false } +database-interface = { path = "crates/database/interface", package = "revm-database-interface", version = "7.0.5", default-features = false } +state = { path = "crates/state", package = "revm-state", version = "7.0.5", default-features = false } +interpreter = { path = "crates/interpreter", package = "revm-interpreter", version = "25.0.2", default-features = false } +inspector = { path = "crates/inspector", package = "revm-inspector", version = "10.0.0", default-features = false } +precompile = { path = "crates/precompile", package = "revm-precompile", version = "27.0.0", default-features = false } +statetest-types = { path = "crates/statetest-types", package = "revm-statetest-types", version = "9.0.2", default-features = false } +context = { path = "crates/context", package = "revm-context", version = "9.0.2", default-features = false } +context-interface = { path = "crates/context/interface", package = "revm-context-interface", version = "10.1.0", default-features = false } +handler = { path = "crates/handler", package = "revm-handler", version = "10.0.0", default-features = false } +op-revm = { path = "crates/op-revm", package = "op-revm", version = "10.0.0", default-features = false } +ee-tests = { path = "crates/ee-tests", package = "revm-ee-tests", version = "0.1.0", default-features = false } # alloy alloy-eip2930 = { version = "0.2.1", default-features = false } @@ -108,7 +110,6 @@ auto_impl = "1.3.0" bitflags = { version = "2.9.1", default-features = false } cfg-if = { version = "1.0", default-features = false } derive-where = { version = "1.5.0", default-features = false } -once_cell = { version = "1.21", default-features = false } rand = "0.9" tokio = "1.45" either = { version = "1.15.0", default-features = false } @@ -133,8 +134,9 @@ categories = ["no-std", "compilers", "cryptography::cryptocurrencies"] keywords = ["revm", "evm", "ethereum", "blockchain", "no_std"] repository = "https://github.com/bluealloy/revm" documentation = "https://bluealloy.github.io/revm/" -homepage = "" +homepage = "https://github.com/bluealloy/revm" edition = "2021" +rust-version = "1.88.0" [workspace.lints] rust.missing_debug_implementations = "warn" @@ -165,7 +167,9 @@ strip = false # Make sure debug symbols are in the bench profile [profile.bench] -inherits = "profiling" +debug = 2 +inherits = "release" +strip = false [profile.ethtests] inherits = "test" diff --git a/MIGRATION_GUIDE.md b/MIGRATION_GUIDE.md index d1bb31cd23..9b638a86ba 100644 --- a/MIGRATION_GUIDE.md +++ b/MIGRATION_GUIDE.md @@ -1,4 +1,26 @@ -# v82 tag (revm v27.1.0) from v81 tag (revm v27.0.3) +# v86 tag (revm v29.0.0) + +* `PrecompileWithAddress` is renamed to `Precompile` and it became a struct. + * `Precompile` contains`PrecompileId`, `Address` and function. + * The reason is adding `PrecompileId` as it is needed for fusaka hardfork + +# v85 tag (revm v28.0.1) from v84 tag (revm v28.0.0) + +Forward compatible version. + +# v84 tag (revm v28.0.0) from v83 tag (revm v27.1.0) + +* `SystemCallEvm` functions got renamed and old ones are deprecated. Renaming is done to align it with other API calls. + * `transact_system_call_finalize` is now `system_call`. + * `transact_system_call` is now `system_call_one`. +* `ExtBytecode::regenerate_hash` got deprecated in support for `get_or_calculate_hash` or `calculate_hash`. +* Precompiles: + * Bn128 renamed to Bn254. https://github.com/ethereum/EIPs/pull/10029#issue-3240867404 +* `InstructionResult` now starts from 1 (previous 0) for perf purposes. +* In `JournalInner` previous `precompiles`, `warm_coinbase_address` and `warm_preloaded_addresses` pub fields are now moved to `warm_addresses` to encapsulate addresses that are warm by default. All access list account are all loaded from database. + + +# v83 tag (revm v27.1.0) from v82 tag (revm v27.0.3) * `ContextTr` gained `Host` supertrait. * Previously Host was implemented for any T that has ContextTr, this restricts specializations. diff --git a/README.md b/README.md index 57a72e32a1..e9e6d1d697 100644 --- a/README.md +++ b/README.md @@ -51,17 +51,23 @@ The [book](https://bluealloy.github.io/revm/) and [`Architecture and API`](https Some quick links can be found here. Some point to code documentation or the book. code docs are there to explain usage of a particular part of the code where the book is to get more of an overview of the architecture or how components/projects fit together. -* How to build and use revm can be found here. [book](https://bluealloy.github.io/revm/dev.html) -* Architecture overview can be seen here. [book](https://bluealloy.github.io/revm/architecture.html) -* Structure of the project (list of crates and their versions) can be seen here. [book](https://github.com/bluealloy/revm/tree/main/crates) -* How to use Revm Framework can be found in MyEvm example. [book](https://github.com/bluealloy/revm/tree/main/examples/my_evm) -* Release procedure and changelogs explanation. [book](https://bluealloy.github.io/revm/release_procedure.html) -* How to use revme (Revm binary with few commands) can be found here. [code](https://github.com/bluealloy/revm/tree/main/bins/revme) -* How to run Ethereum test can be found here: [book](https://bluealloy.github.io/revm/revme.html#running-eth-tests) +* [How to build and use revm](https://bluealloy.github.io/revm/dev.html) +* [Architecture overview](https://bluealloy.github.io/revm/architecture.html) +* [Structure of the project](https://github.com/bluealloy/revm/tree/main/crates) (list of crates and their versions) +* [How to use Revm Framework](https://github.com/bluealloy/revm/tree/main/examples/my_evm) (MyEvm example) +* [Release procedure and changelogs explanation](https://bluealloy.github.io/revm/release_procedure.html) +* [How to use revme](https://github.com/bluealloy/revm/tree/main/bins/revme) (Revm binary with few commands) +* [How to run Ethereum tests](https://bluealloy.github.io/revm/revme.html#running-eth-tests) * If there is more need for explanations please open a PR request. +## Supported Rust Versions (MSRV) + +Revm always aims to stay up-to-date with the latest stable Rust release. + +The Minimum Supported Rust Version (MSRV) may be updated at any time, so we can take advantage of new features and improvements in Rust. + ### Community: -For questions please open a github issue or join the public telegram group: [https://t.me/+Ig4WDWOzikA3MzA0](https://t.me/+Ig4WDWOzikA3MzA0) +For questions please open a github issue or join the public [telegram group](https://t.me/+Ig4WDWOzikA3MzA0) ### Licence Revm is licensed under MIT Licence. diff --git a/bins/revme/CHANGELOG.md b/bins/revme/CHANGELOG.md index 3932b96718..907105d190 100644 --- a/bins/revme/CHANGELOG.md +++ b/bins/revme/CHANGELOG.md @@ -1,4 +1,38 @@ # Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [7.2.2](https://github.com/bluealloy/revm/compare/revme-v7.2.1...revme-v7.2.2) - 2025-08-23 + +### Other + +- updated the following local packages: revm-bytecode, revm-database-interface, revm-context-interface, revm-context, revm-database, revm-state, revm-inspector, revm, revm-statetest-types + +## [7.2.1](https://github.com/bluealloy/revm/compare/revme-v7.2.0...revme-v7.2.1) - 2025-08-12 + +### Other + +- codspeed sstore sload opcodes ([#2881](https://github.com/bluealloy/revm/pull/2881)) + +## [7.2.0](https://github.com/bluealloy/revm/compare/revme-v7.1.0...revme-v7.2.0) - 2025-08-06 + +### Added + +- Reuse bls12-381 codepaths to implement kzg point evaluation precompile ([#2809](https://github.com/bluealloy/revm/pull/2809)) + +### Other + +- *(benches)* rename anaysis-inspector to snailtracer-inspect ([#2834](https://github.com/bluealloy/revm/pull/2834)) +- *(benches)* clean up criterion callsites ([#2833](https://github.com/bluealloy/revm/pull/2833)) +- add rust-version and note about MSRV ([#2789](https://github.com/bluealloy/revm/pull/2789)) +- fix clippy ([#2785](https://github.com/bluealloy/revm/pull/2785)) +- add gas_limit to revme evm ([#2779](https://github.com/bluealloy/revm/pull/2779)) +# Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), diff --git a/bins/revme/Cargo.toml b/bins/revme/Cargo.toml index 20c416ed6e..1e4b918970 100644 --- a/bins/revme/Cargo.toml +++ b/bins/revme/Cargo.toml @@ -1,16 +1,17 @@ [package] name = "revme" description = "Rust Ethereum Virtual Machine Executable" -version = "7.1.0" +version = "7.2.2" authors.workspace = true edition.workspace = true keywords.workspace = true license.workspace = true repository.workspace = true +rust-version.workspace = true [dependencies] # revm -revm = { workspace = true, features = ["std", "c-kzg", "blst", "hashbrown"] } +revm = { workspace = true, features = ["std", "hashbrown", "c-kzg", "blst"] } primitives.workspace = true database.workspace = true database-interface.workspace = true diff --git a/bins/revme/src/cmd/bench/analysis.rs b/bins/revme/src/cmd/bench/analysis.rs index e8fdb3704f..e12bc97e96 100644 --- a/bins/revme/src/cmd/bench/analysis.rs +++ b/bins/revme/src/cmd/bench/analysis.rs @@ -24,13 +24,8 @@ pub fn run(criterion: &mut Criterion) { let mut evm = context.build_mainnet(); criterion.bench_function("analysis", |b| { b.iter_batched( - || { - // create a transaction input - tx.clone() - }, - |input| { - let _ = evm.transact_one(input); - }, + || tx.clone(), + |input| evm.transact_one(input).unwrap(), criterion::BatchSize::SmallInput, ); }); diff --git a/bins/revme/src/cmd/bench/burntpix.rs b/bins/revme/src/cmd/bench/burntpix.rs index 1e65627fe4..ba7a14f85f 100644 --- a/bins/revme/src/cmd/bench/burntpix.rs +++ b/bins/revme/src/cmd/bench/burntpix.rs @@ -51,13 +51,8 @@ pub fn run(criterion: &mut Criterion) { criterion.bench_function("burntpix", |b| { b.iter_batched( - || { - // create a transaction input - tx.clone() - }, - |input| { - evm.transact_one(input).unwrap(); - }, + || tx.clone(), + |input| evm.transact_one(input).unwrap(), criterion::BatchSize::SmallInput, ); }); diff --git a/bins/revme/src/cmd/bench/evm_build.rs b/bins/revme/src/cmd/bench/evm_build.rs index a7e2ea7b51..e54b473c82 100644 --- a/bins/revme/src/cmd/bench/evm_build.rs +++ b/bins/revme/src/cmd/bench/evm_build.rs @@ -3,8 +3,6 @@ use revm::{Context, MainBuilder, MainContext}; pub fn run(criterion: &mut Criterion) { criterion.bench_function("evm-build", |b| { - b.iter(|| { - let _ = Context::mainnet().build_mainnet(); - }); + b.iter(|| Context::mainnet().build_mainnet()); }); } diff --git a/bins/revme/src/cmd/bench/gas_cost_estimator.rs b/bins/revme/src/cmd/bench/gas_cost_estimator.rs index d596ac1dab..06db3292a5 100644 --- a/bins/revme/src/cmd/bench/gas_cost_estimator.rs +++ b/bins/revme/src/cmd/bench/gas_cost_estimator.rs @@ -35,13 +35,8 @@ pub fn run(criterion: &mut Criterion) { criterion.bench_function(name, |b| { b.iter_batched( - || { - // create a transaction input - tx.clone() - }, - |input| { - let _ = evm.transact_one(input).unwrap(); - }, + || tx.clone(), + |input| evm.transact_one(input).unwrap(), criterion::BatchSize::SmallInput, ); }); diff --git a/bins/revme/src/cmd/bench/gas_cost_estimator_sample.csv b/bins/revme/src/cmd/bench/gas_cost_estimator_sample.csv index 29eb985378..d6a0d9cdf3 100644 --- a/bins/revme/src/cmd/bench/gas_cost_estimator_sample.csv +++ b/bins/revme/src/cmd/bench/gas_cost_estimator_sample.csv @@ -136,4 +136,6 @@ SWAP13_50,SWAP13,50,600360036003600360036003600360036003600360036003600360036003 SWAP14_50,SWAP14,50,6003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360039d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d9d SWAP15_50,SWAP15,50,6003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360039e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e9e SWAP16_50,SWAP16,50,60036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360039f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f9f -CLZ_50,CLZ,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360031e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e5050505050505050505050 \ No newline at end of file +CLZ_50,CLZ,50,6000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360031e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e501e505050505050505050505000 +SSTORE_50, SSTORE,50,600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555555500 +SLOAD_50, SLOAD,50,600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600060006000600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003600360036003545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545454545400 \ No newline at end of file diff --git a/bins/revme/src/cmd/bench/snailtracer.rs b/bins/revme/src/cmd/bench/snailtracer.rs index 0228b3df4c..5445d2fee9 100644 --- a/bins/revme/src/cmd/bench/snailtracer.rs +++ b/bins/revme/src/cmd/bench/snailtracer.rs @@ -27,26 +27,16 @@ pub fn run(criterion: &mut Criterion) { criterion.bench_function("snailtracer", |b| { b.iter_batched( - || { - // create a transaction input - tx.clone() - }, - |input| { - let _ = evm.transact_one(input).unwrap(); - }, + || tx.clone(), + |input| evm.transact_one(input).unwrap(), criterion::BatchSize::SmallInput, ); }); - criterion.bench_function("analysis-inspector", |b| { + criterion.bench_function("snailtracer-inspect", |b| { b.iter_batched( - || { - // create a transaction input - tx.clone() - }, - |input| { - let _ = evm.inspect_one_tx(input); - }, + || tx.clone(), + |input| evm.inspect_one_tx(input), criterion::BatchSize::SmallInput, ); }); diff --git a/bins/revme/src/cmd/bench/transfer.rs b/bins/revme/src/cmd/bench/transfer.rs index 0914eff60d..ac196dfe97 100644 --- a/bins/revme/src/cmd/bench/transfer.rs +++ b/bins/revme/src/cmd/bench/transfer.rs @@ -28,13 +28,10 @@ pub fn run(criterion: &mut Criterion) { let mut i = 0; criterion.bench_function("transfer", |b| { b.iter_batched( - || { - // create a transfer input - tx.clone() - }, + || tx.clone(), |input| { i += 1; - evm.transact_one(input).unwrap(); + evm.transact_one(input).unwrap() }, criterion::BatchSize::SmallInput, ); @@ -57,9 +54,5 @@ pub fn run(criterion: &mut Criterion) { evm.modify_cfg(|cfg| cfg.disable_nonce_check = false); - criterion.bench_function("transfer_finalize", |b| { - b.iter(|| { - let _ = evm.replay().unwrap(); - }) - }); + criterion.bench_function("transfer_finalize", |b| b.iter(|| evm.replay().unwrap())); } diff --git a/bins/revme/src/cmd/bench/transfer_multi.rs b/bins/revme/src/cmd/bench/transfer_multi.rs index 9c3e85eefb..d22c467677 100644 --- a/bins/revme/src/cmd/bench/transfer_multi.rs +++ b/bins/revme/src/cmd/bench/transfer_multi.rs @@ -51,10 +51,7 @@ pub fn run(criterion: &mut Criterion) { criterion.bench_function("transact_commit_1000txs", |b| { b.iter_batched( - || { - // create transaction inputs - txs.clone() - }, + || txs.clone(), |inputs| { for tx in inputs { let _ = evm.transact_commit(tx).unwrap(); @@ -66,14 +63,11 @@ pub fn run(criterion: &mut Criterion) { criterion.bench_function("transact_1000tx_commit_inner_every_40", |b| { b.iter_batched( - || { - // create transaction inputs - txs.clone() - }, + || txs.clone(), |inputs| { for (i, tx) in inputs.into_iter().enumerate() { let _ = evm.transact_one(tx).unwrap(); - if i % 40 == 0 { + if i.is_multiple_of(40) { evm.commit_inner(); } } diff --git a/bins/revme/src/cmd/evmrunner.rs b/bins/revme/src/cmd/evmrunner.rs index 8fda0fac16..4e54833cb9 100644 --- a/bins/revme/src/cmd/evmrunner.rs +++ b/bins/revme/src/cmd/evmrunner.rs @@ -40,12 +40,18 @@ pub struct Cmd { /// Overrides the positional `bytecode` argument. #[arg(long)] path: Option, + /// Whether to run in benchmarking mode #[arg(long)] bench: bool, + /// Hex-encoded input/calldata bytes #[arg(long, default_value = "")] input: String, + /// Gas limit + #[arg(long, default_value = "1000000000")] + gas_limit: u64, + /// Whether to print the state #[arg(long)] state: bool, @@ -92,6 +98,7 @@ impl Cmd { .kind(TxKind::Call(BENCH_TARGET)) .data(input) .nonce(nonce) + .gas_limit(self.gas_limit) .build() .unwrap(); @@ -102,9 +109,11 @@ impl Cmd { .without_plots(); let mut criterion_group = criterion.benchmark_group("revme"); criterion_group.bench_function("evm", |b| { - b.iter(|| { - let _ = evm.transact(tx.clone()).unwrap(); - }) + b.iter_batched( + || tx.clone(), + |input| evm.transact(input).unwrap(), + criterion::BatchSize::SmallInput, + ); }); criterion_group.finish(); @@ -112,19 +121,17 @@ impl Cmd { } let time = Instant::now(); - let state = if self.trace { - evm.inspect_tx(tx.clone()) - .map_err(|_| Errors::EVMError)? - .state + let r = if self.trace { + evm.inspect_tx(tx) } else { - let out = evm.transact(tx.clone()).map_err(|_| Errors::EVMError)?; - println!("Result: {:#?}", out.result); - out.state - }; + evm.transact(tx) + } + .map_err(|_| Errors::EVMError)?; let time = time.elapsed(); + println!("Result: {:#?}", r.result); if self.state { - println!("State: {state:#?}"); + println!("State: {:#?}", r.state); } println!("Elapsed: {time:?}"); diff --git a/bins/revme/src/main.rs b/bins/revme/src/main.rs index a509243c22..d53929cb21 100644 --- a/bins/revme/src/main.rs +++ b/bins/revme/src/main.rs @@ -1,22 +1,17 @@ use clap::Parser; -use revme::cmd::{Error, MainCmd}; +use revme::cmd::MainCmd; +use std::process::ExitCode; -fn main() -> Result<(), Error> { - set_thread_panic_hook(); - MainCmd::parse().run().inspect_err(|e| println!("{e:?}")) -} +fn main() -> ExitCode { + if std::env::var_os("RUST_BACKTRACE").is_none() { + unsafe { std::env::set_var("RUST_BACKTRACE", "1") }; + } -/// Sets thread panic hook, useful for having tests that panic. -fn set_thread_panic_hook() { - use std::{ - backtrace::Backtrace, - panic::{set_hook, take_hook}, - process::exit, - }; - let orig_hook = take_hook(); - set_hook(Box::new(move |panic_info| { - println!("Custom backtrace: {}", Backtrace::capture()); - orig_hook(panic_info); - exit(1); - })); + match MainCmd::parse().run() { + Ok(()) => ExitCode::SUCCESS, + Err(e) => { + eprintln!("error:\n- {e}\n- {e:#?}"); + ExitCode::FAILURE + } + } } diff --git a/book/src/awesome.md b/book/src/awesome.md index ad61479a3f..51f759a196 100644 --- a/book/src/awesome.md +++ b/book/src/awesome.md @@ -26,7 +26,7 @@ A curated list of excellent Revm-related resources. Feel free to contribute to t #### Tools - [**Foundry:**](https://github.com/foundry-rs/foundry) A portable and modular toolkit for rapid Ethereum application development in Rust. - [**Hardhat:**](https://github.com/NomicFoundation/hardhat) A comprehensive development environment for compiling, deploying, testing, and debugging Ethereum software. -- [**Arbiter:**](https://github.com/primitivefinance/arbiter) smart-contract simulation. +- [**Arbiter:**](https://github.com/harnesslabs/arbiter) smart-contract simulation. #### Frameworks and Libraries - [**revm-inspectors:**](https://github.com/paradigmxyz/revm-inspectors) Hooks for EVM execution. @@ -40,6 +40,6 @@ A curated list of excellent Revm-related resources. Feel free to contribute to t #### Tutorials - [**MyEvm**](https://github.com/bluealloy/revm/tree/main/examples/my_evm): Custom EVM Implementation Example - [**Revm is All You Need:**](https://medium.com/@solidquant/revm-is-all-you-need-e01b5b0421e4): Guide on building simulated blockchain environments. -- [**Uniswap Swap Example:**](https://github.com/bluealloy/revm/tree/main/examples/uniswap_get_reserves) Demonstrates a USDC swap on Uniswap V2.evm is available in the [awesome-revm](./awesome.md) section o -- [**revm-by-example:**](https://github.com/Cionn3/revm-by-example) Practical examples using the Rust Ethereum Virtual Machine. +- [**Uniswap Swap Example:**](https://github.com/bluealloy/revm/tree/main/examples/uniswap_get_reserves) Demonstrates a USDC swap on Uniswap V2. +- [**revm-by-example:**](https://github.com/greekfetacheese/revm-by-example) Practical examples using the Rust Ethereum Virtual Machine. - [**How to Discover long-tail MEV Strategies using Revm**](https://pawelurbanek.com/long-tail-mev-revm) diff --git a/book/src/external_state_transitions.md b/book/src/external_state_transitions.md index 131b1b012f..d7dee89c27 100644 --- a/book/src/external_state_transitions.md +++ b/book/src/external_state_transitions.md @@ -1,6 +1,6 @@ # External State Transitions (EIP-4788 & EIP-2935) -Some Ethereum Improvement Proposals (EIPs) require state transitions that are not triggered by regular user transactions, but are instead performed by the client using special system calls (such as `transact_system_call`). These transitions are part of the EVM state changes, but are initiated by the client at specific block boundaries (pre- or post-block hooks), as required by the EIP. +Some Ethereum Improvement Proposals (EIPs) require state transitions that are not triggered by regular user transactions, but are instead performed by the client using special system calls (such as `system_call`). These transitions are part of the EVM state changes, but are initiated by the client at specific block boundaries (pre- or post-block hooks), as required by the EIP. - [EIP-4788: Beacon block root in the EVM](https://eips.ethereum.org/EIPS/eip-4788) - [EIP-2935: Add `blockHash` and `blockNumber` to the EVM](https://eips.ethereum.org/EIPS/eip-2935) @@ -28,7 +28,7 @@ EIP-2935 introduces a system contract that stores recent block hashes, allowing ## How does this affect REVM users? -- To perform these block state transitions, the client or test harness should use the system call mechanism (`transact_system_call`) provided by REVM. +- To perform these block state transitions, the client or test harness should use the system call mechanism (`system_call`) provided by REVM. - REVM itself does not automatically perform these transitions; it expects the client to initiate them at the appropriate block boundaries, as specified by the EIPs. - If you are building a full Ethereum client or a test harness, you are responsible for performing these system calls at the appropriate block boundaries, as specified in the EIPs. - If you are only using REVM for transaction execution, you may need to ensure that the state of these system contracts is kept up to date externally. diff --git a/book/src/revme.md b/book/src/revme.md index 90cb09f2f0..bc0818d58b 100644 --- a/book/src/revme.md +++ b/book/src/revme.md @@ -22,12 +22,12 @@ Options: Eth tests are a suite of tests from the Ethereum Foundation that are used to test EVM implementations. Part of these tests are included in the revm repository in the `tests` folder. -Test suites for the latest hardforks can be found in EEST releases https://github.com/ethereum/execution-spec-tests/releases, and there are additional tests that cover older hardforks in https://github.com/ethereum/legacytests +Test suites for the latest hardforks can be found in [EEST releases](https://github.com/ethereum/execution-spec-tests/releases), and there are additional tests that cover older hardforks in [legacytests](https://github.com/ethereum/legacytests) Revm can run statetest type of tests with `revme` using the following command: `cargo run --release -p revme -- statetest folder_path` For running EEST tests, we can use the `./scripts/run-tests.sh.` -For legacy tests, we need to first to download the repo `git clone https://github.com/ethereum/legacytests` and then run it with `cargo run --release -p revme -- statetest legacytests/Cancun/GeneralStateTests ` +For legacy tests, we need to first download the repo `git clone https://github.com/ethereum/legacytests` and then run it with `cargo run --release -p revme -- statetest legacytests/Cancun/GeneralStateTests` All statetest that can be run by revme can be found in the `GeneralStateTests` folder. diff --git a/crates/bytecode/CHANGELOG.md b/crates/bytecode/CHANGELOG.md index 9c484b890e..5aabf75f0e 100644 --- a/crates/bytecode/CHANGELOG.md +++ b/crates/bytecode/CHANGELOG.md @@ -7,6 +7,39 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [6.2.2](https://github.com/bluealloy/revm/compare/revm-bytecode-v6.2.1...revm-bytecode-v6.2.2) - 2025-08-23 + +### Other + +- use core::fmt and remove unused Debug import ([#2887](https://github.com/bluealloy/revm/pull/2887)) + +## [6.2.1](https://github.com/bluealloy/revm/compare/revm-bytecode-v6.2.0...revm-bytecode-v6.2.1) - 2025-08-12 + +### Other + +- Revert "feat: removed padding in case last opcode is terminal ([#2816](https://github.com/bluealloy/revm/pull/2816))" ([#2883](https://github.com/bluealloy/revm/pull/2883)) +- *(bytecode)* remove unused Debug import ([#2879](https://github.com/bluealloy/revm/pull/2879)) +- update outdated opcode memory reference link ([#2859](https://github.com/bluealloy/revm/pull/2859)) + +## [6.2.0](https://github.com/bluealloy/revm/compare/revm-bytecode-v6.1.0...revm-bytecode-v6.2.0) - 2025-08-06 + +### Added + +- removed padding in case last opcode is terminating or unknown ([#2816](https://github.com/bluealloy/revm/pull/2816)) + +### Fixed + +- correct various typos in documentation and comments ([#2855](https://github.com/bluealloy/revm/pull/2855)) + +### Other + +- *(OpCode)* add is_valid ([#2847](https://github.com/bluealloy/revm/pull/2847)) +- update README.md ([#2842](https://github.com/bluealloy/revm/pull/2842)) +- *(benches)* clean up criterion callsites ([#2833](https://github.com/bluealloy/revm/pull/2833)) +- improve ExtBytecode hash handling ([#2826](https://github.com/bluealloy/revm/pull/2826)) +- add rust-version and note about MSRV ([#2789](https://github.com/bluealloy/revm/pull/2789)) +- add OnceLock re-export with no_std support ([#2787](https://github.com/bluealloy/revm/pull/2787)) + ## [6.1.0](https://github.com/bluealloy/revm/compare/revm-bytecode-v6.0.1...revm-bytecode-v6.1.0) - 2025-07-23 ### Added diff --git a/crates/bytecode/Cargo.toml b/crates/bytecode/Cargo.toml index 78114d50f8..b35526c1c0 100644 --- a/crates/bytecode/Cargo.toml +++ b/crates/bytecode/Cargo.toml @@ -1,13 +1,14 @@ [package] name = "revm-bytecode" description = "EVM Bytecodes" -version = "6.1.0" +version = "6.2.2" authors.workspace = true edition.workspace = true keywords.workspace = true license.workspace = true repository.workspace = true readme.workspace = true +rust-version.workspace = true [package.metadata.docs.rs] all-features = true @@ -22,7 +23,6 @@ primitives.workspace = true # Jumpmap bitvec = { workspace = true, features = ["alloc"] } -once_cell = { workspace = true, features = ["alloc"] } # Optional serde = { workspace = true, features = ["derive", "rc"], optional = true } @@ -37,7 +37,6 @@ std = [ "serde?/std", "primitives/std", "bitvec/std", - "once_cell/std", "phf?/std", ] hashbrown = ["primitives/hashbrown"] diff --git a/crates/bytecode/src/bytecode.rs b/crates/bytecode/src/bytecode.rs index b9e8a697c2..a6f09b7aa5 100644 --- a/crates/bytecode/src/bytecode.rs +++ b/crates/bytecode/src/bytecode.rs @@ -8,7 +8,6 @@ use crate::{ eip7702::{Eip7702Bytecode, EIP7702_MAGIC_BYTES}, BytecodeDecodeError, JumpTable, LegacyAnalyzedBytecode, LegacyRawBytecode, }; -use core::fmt::Debug; use primitives::{keccak256, Address, Bytes, B256, KECCAK_EMPTY}; /// Main bytecode structure with all variants. @@ -45,6 +44,7 @@ impl Bytecode { } /// Calculates hash of the bytecode. + #[inline] pub fn hash_slow(&self) -> B256 { if self.is_empty() { KECCAK_EMPTY @@ -54,6 +54,7 @@ impl Bytecode { } /// Returns `true` if bytecode is EIP-7702. + #[inline] pub const fn is_eip7702(&self) -> bool { matches!(self, Self::Eip7702(_)) } @@ -100,6 +101,7 @@ impl Bytecode { /// # Panics /// /// For possible panics see [`LegacyAnalyzedBytecode::new`]. + #[inline] pub fn new_analyzed(bytecode: Bytes, original_len: usize, jump_table: JumpTable) -> Self { Self::LegacyAnalyzed(LegacyAnalyzedBytecode::new( bytecode, @@ -118,6 +120,7 @@ impl Bytecode { } /// Pointer to the executable bytecode. + #[inline] pub fn bytecode_ptr(&self) -> *const u8 { self.bytecode().as_ptr() } diff --git a/crates/bytecode/src/decode_errors.rs b/crates/bytecode/src/decode_errors.rs index f281e4f355..4f92a6a930 100644 --- a/crates/bytecode/src/decode_errors.rs +++ b/crates/bytecode/src/decode_errors.rs @@ -1,6 +1,5 @@ use crate::eip7702::Eip7702DecodeError; -use core::fmt::Debug; -use std::fmt; +use core::fmt; /// Bytecode decode errors #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] diff --git a/crates/bytecode/src/iter.rs b/crates/bytecode/src/iter.rs index 30aff63c83..7abc25cc0f 100644 --- a/crates/bytecode/src/iter.rs +++ b/crates/bytecode/src/iter.rs @@ -6,10 +6,10 @@ use crate::{opcode, Bytecode, OpCode}; /// without dealing with the immediate values that follow instructions. #[derive(Debug, Clone)] pub struct BytecodeIterator<'a> { - /// Start pointer of the bytecode. Only used to calculate [`position`](Self::position). - start: *const u8, /// Iterator over the bytecode bytes. bytes: core::slice::Iter<'a, u8>, + /// Start pointer of the bytecode. Only used to calculate [`position`](Self::position). + start: *const u8, } impl<'a> BytecodeIterator<'a> { @@ -21,8 +21,8 @@ impl<'a> BytecodeIterator<'a> { Bytecode::Eip7702(_) => &[], }; Self { - start: bytes.as_ptr(), bytes: bytes.iter(), + start: bytes.as_ptr(), } } @@ -40,15 +40,13 @@ impl<'a> BytecodeIterator<'a> { /// Returns the current position in the bytecode. #[inline] pub fn position(&self) -> usize { - (self.bytes.as_slice().as_ptr() as usize) - (self.start as usize) - // TODO: Use the following on 1.87 // SAFETY: `start` always points to the start of the bytecode. - // unsafe { - // self.bytes - // .as_slice() - // .as_ptr() - // .offset_from_unsigned(self.start) - // } + unsafe { + self.bytes + .as_slice() + .as_ptr() + .offset_from_unsigned(self.start) + } } #[inline] diff --git a/crates/bytecode/src/legacy/analyzed.rs b/crates/bytecode/src/legacy/analyzed.rs index 295ec20baf..72b0a43069 100644 --- a/crates/bytecode/src/legacy/analyzed.rs +++ b/crates/bytecode/src/legacy/analyzed.rs @@ -1,5 +1,4 @@ use super::JumpTable; -use crate::opcode; use primitives::Bytes; /// Legacy analyzed bytecode represents the original bytecode format used in Ethereum. @@ -66,7 +65,7 @@ impl LegacyAnalyzedBytecode { /// /// * If `original_len` is greater than `bytecode.len()` /// * If jump table length is less than `original_len`. - /// * If last bytecode byte is not `0x00` or if bytecode is empty. + /// * If bytecode is empty. pub fn new(bytecode: Bytes, original_len: usize, jump_table: JumpTable) -> Self { assert!( original_len <= bytecode.len(), @@ -77,10 +76,6 @@ impl LegacyAnalyzedBytecode { "jump table length is less than original length" ); assert!(!bytecode.is_empty(), "bytecode cannot be empty"); - assert!( - bytecode.last() == Some(&opcode::STOP), - "last bytecode byte should be STOP (0x00)" - ); Self { bytecode, original_len, @@ -150,14 +145,6 @@ mod tests { let _ = LegacyAnalyzedBytecode::new(bytecode.bytecode, bytecode.original_len, jump_table); } - #[test] - #[should_panic(expected = "last bytecode byte should be STOP (0x00)")] - fn test_panic_on_non_stop_bytecode() { - let bytecode = Bytes::from_static(&[opcode::PUSH1, 0x01]); - let jump_table = JumpTable::new(bitvec![u8, Lsb0; 0; 2]); - let _ = LegacyAnalyzedBytecode::new(bytecode, 2, jump_table); - } - #[test] #[should_panic(expected = "bytecode cannot be empty")] fn test_panic_on_empty_bytecode() { diff --git a/crates/bytecode/src/legacy/jump_map.rs b/crates/bytecode/src/legacy/jump_map.rs index d66dceab28..b4a99ebd7f 100644 --- a/crates/bytecode/src/legacy/jump_map.rs +++ b/crates/bytecode/src/legacy/jump_map.rs @@ -3,8 +3,7 @@ use core::{ cmp::Ordering, hash::{Hash, Hasher}, }; -use once_cell::race::OnceBox; -use primitives::hex; +use primitives::{hex, OnceLock}; use std::{fmt::Debug, sync::Arc}; /// A table of valid `jump` destinations. @@ -80,10 +79,8 @@ impl Debug for JumpTable { impl Default for JumpTable { #[inline] fn default() -> Self { - static DEFAULT: OnceBox = OnceBox::new(); - DEFAULT - .get_or_init(|| Self::new(BitVec::default()).into()) - .clone() + static DEFAULT: OnceLock = OnceLock::new(); + DEFAULT.get_or_init(|| Self::new(BitVec::default())).clone() } } diff --git a/crates/bytecode/src/opcode.rs b/crates/bytecode/src/opcode.rs index 774ddb37d7..20a0aaad55 100644 --- a/crates/bytecode/src/opcode.rs +++ b/crates/bytecode/src/opcode.rs @@ -160,7 +160,7 @@ impl OpCode { /// Returns the number of both input and output stack elements. /// - /// Can be slightly faster that calling `inputs` and `outputs` separately. + /// Can be slightly faster than calling `inputs` and `outputs` separately. pub const fn input_output(&self) -> (u8, u8) { let info = self.info(); (info.inputs, info.outputs) @@ -174,7 +174,7 @@ impl OpCode { /// Returns true if the opcode modifies memory. /// - /// + /// /// /// #[inline] @@ -195,6 +195,12 @@ impl OpCode { | OpCode::STATICCALL ) } + + /// Returns true if the opcode is valid + #[inline] + pub const fn is_valid(&self) -> bool { + OPCODE_INFO[self.0 as usize].is_some() + } } impl PartialEq for OpCode { @@ -217,9 +223,6 @@ pub struct OpCodeInfo { /// Stack outputs outputs: u8, /// Number of intermediate bytes - /// - /// RJUMPV is a special case where the bytes len depends on bytecode value, - /// for RJUMV size will be set to one byte as it is the minimum immediate size. immediate_size: u8, /// If the opcode stops execution. aka STOP, RETURN, .. terminating: bool, @@ -297,16 +300,13 @@ impl OpCodeInfo { } /// Used for [`OPCODE_INFO`] to set the immediate bytes number in the [`OpCodeInfo`]. -/// -/// RJUMPV is special case where the bytes len is depending on bytecode value, -/// for RJUMPV size will be set to one byte while minimum is two. #[inline] pub const fn immediate_size(mut op: OpCodeInfo, n: u8) -> OpCodeInfo { op.immediate_size = n; op } -/// Use for [`OPCODE_INFO`] to set the terminating flag to true in the [`OpCodeInfo`]. +/// Used for [`OPCODE_INFO`] to set the terminating flag to true in the [`OpCodeInfo`]. #[inline] pub const fn terminating(mut op: OpCodeInfo) -> OpCodeInfo { op.terminating = true; @@ -748,4 +748,29 @@ mod tests { } } } + + #[test] + #[should_panic(expected = "opcode not found")] + fn test_new_unchecked_invalid() { + let op = unsafe { OpCode::new_unchecked(0x0C) }; + op.info(); + } + + #[test] + fn test_op_code_valid() { + let op1 = OpCode::new(ADD).unwrap(); + let op2 = OpCode::new(MUL).unwrap(); + assert!(op1.is_valid()); + assert!(op2.is_valid()); + + let op3 = unsafe { OpCode::new_unchecked(0x0C) }; + assert!(!op3.is_valid()); + } + + #[test] + fn test_modifies_memory() { + assert!(OpCode::new(MLOAD).unwrap().modifies_memory()); + assert!(OpCode::new(MSTORE).unwrap().modifies_memory()); + assert!(!OpCode::new(ADD).unwrap().modifies_memory()); + } } diff --git a/crates/context/CHANGELOG.md b/crates/context/CHANGELOG.md index 70646c5757..377e80b0c9 100644 --- a/crates/context/CHANGELOG.md +++ b/crates/context/CHANGELOG.md @@ -7,6 +7,38 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [9.0.2](https://github.com/bluealloy/revm/compare/revm-context-v9.0.1...revm-context-v9.0.2) - 2025-08-23 + +### Fixed + +- EIP-7702 target check to return correct error ([#2896](https://github.com/bluealloy/revm/pull/2896)) + +### Other + +- skip drain if checkpoing is inconsistent ([#2911](https://github.com/bluealloy/revm/pull/2911)) + +## [9.0.1](https://github.com/bluealloy/revm/compare/revm-context-v9.0.0...revm-context-v9.0.1) - 2025-08-12 + +### Other + +- updated the following local packages: revm-primitives, revm-bytecode, revm-state, revm-context-interface, revm-database, revm-database-interface + +## [9.0.0](https://github.com/bluealloy/revm/compare/revm-context-v8.0.4...revm-context-v9.0.0) - 2025-08-06 + +### Added + +- short address for journal cold/warm check ([#2849](https://github.com/bluealloy/revm/pull/2849)) + +### Fixed + +- correct various typos in documentation and comments ([#2855](https://github.com/bluealloy/revm/pull/2855)) + +### Other + +- rm redundant lifetime constraints ([#2850](https://github.com/bluealloy/revm/pull/2850)) +- update README.md ([#2842](https://github.com/bluealloy/revm/pull/2842)) +- add rust-version and note about MSRV ([#2789](https://github.com/bluealloy/revm/pull/2789)) + ## [8.0.4](https://github.com/bluealloy/revm/compare/revm-context-v8.0.3...revm-context-v8.0.4) - 2025-07-23 ### Fixed diff --git a/crates/context/Cargo.toml b/crates/context/Cargo.toml index b9c01d9305..fd2065ff02 100644 --- a/crates/context/Cargo.toml +++ b/crates/context/Cargo.toml @@ -1,13 +1,14 @@ [package] name = "revm-context" description = "Revm context crates" -version = "8.0.4" +version = "9.0.2" authors.workspace = true edition.workspace = true keywords.workspace = true license.workspace = true repository.workspace = true readme.workspace = true +rust-version.workspace = true [package.metadata.docs.rs] all-features = true @@ -27,6 +28,7 @@ bytecode.workspace = true # misc derive-where.workspace = true cfg-if.workspace = true +bitvec.workspace = true # Optional serde = { workspace = true, features = ["derive", "rc"], optional = true } @@ -44,6 +46,7 @@ std = [ "database-interface/std", "primitives/std", "state/std", + "bitvec/std", ] serde = [ "dep:serde", @@ -54,6 +57,7 @@ serde = [ "database/serde", "database-interface/serde", "derive-where/serde", + "bitvec/serde", ] dev = [ "memory_limit", diff --git a/crates/context/interface/CHANGELOG.md b/crates/context/interface/CHANGELOG.md index 0cf77dcb7e..0c2ec479a3 100644 --- a/crates/context/interface/CHANGELOG.md +++ b/crates/context/interface/CHANGELOG.md @@ -7,6 +7,36 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [10.1.0](https://github.com/bluealloy/revm/compare/revm-context-interface-v10.0.1...revm-context-interface-v10.1.0) - 2025-08-23 + +### Added + +- add generic state to ResultAndState ([#2897](https://github.com/bluealloy/revm/pull/2897)) + +## [10.0.1](https://github.com/bluealloy/revm/compare/revm-context-interface-v10.0.0...revm-context-interface-v10.0.1) - 2025-08-12 + +### Other + +- Aggregate changes from PRs #2866, #2867, and #2874 ([#2876](https://github.com/bluealloy/revm/pull/2876)) +- make ci happy ([#2863](https://github.com/bluealloy/revm/pull/2863)) + +## [10.0.0](https://github.com/bluealloy/revm/compare/revm-context-interface-v9.0.0...revm-context-interface-v10.0.0) - 2025-08-06 + +### Added + +- short address for journal cold/warm check ([#2849](https://github.com/bluealloy/revm/pull/2849)) + +### Fixed + +- correct various typos in documentation and comments ([#2855](https://github.com/bluealloy/revm/pull/2855)) +- swapped comments for db and db_mut methods in JournalTr trait ([#2774](https://github.com/bluealloy/revm/pull/2774)) + +### Other + +- rm redundant lifetime constraints ([#2850](https://github.com/bluealloy/revm/pull/2850)) +- update README.md ([#2842](https://github.com/bluealloy/revm/pull/2842)) +- add rust-version and note about MSRV ([#2789](https://github.com/bluealloy/revm/pull/2789)) + ## [9.0.0](https://github.com/bluealloy/revm/compare/revm-context-interface-v8.0.1...revm-context-interface-v9.0.0) - 2025-07-23 ### Fixed diff --git a/crates/context/interface/Cargo.toml b/crates/context/interface/Cargo.toml index de26f16d8d..82a8e8a5f8 100644 --- a/crates/context/interface/Cargo.toml +++ b/crates/context/interface/Cargo.toml @@ -1,13 +1,14 @@ [package] name = "revm-context-interface" description = "Revm context interface crates" -version = "9.0.0" +version = "10.1.0" authors.workspace = true edition.workspace = true keywords.workspace = true license.workspace = true repository.workspace = true readme.workspace = true +rust-version.workspace = true [package.metadata.docs.rs] all-features = true diff --git a/crates/context/interface/src/block.rs b/crates/context/interface/src/block.rs index dcc4c53af2..544c0994bc 100644 --- a/crates/context/interface/src/block.rs +++ b/crates/context/interface/src/block.rs @@ -16,7 +16,7 @@ pub trait Block { /// The number of ancestor blocks of this block (block height). fn number(&self) -> U256; - /// Beneficiary (Coinbase, miner) is a address that have signed the block. + /// Beneficiary (Coinbase, miner) is an address that has signed the block. /// /// This is the receiver address of priority gas rewards. fn beneficiary(&self) -> Address; diff --git a/crates/context/interface/src/block/blob.rs b/crates/context/interface/src/block/blob.rs index fab7bc10e3..bb8e661ef3 100644 --- a/crates/context/interface/src/block/blob.rs +++ b/crates/context/interface/src/block/blob.rs @@ -43,7 +43,7 @@ impl BlobExcessGasAndPrice { /// Calculate this block excess gas and price from the parent excess gas and gas used /// and the target blob gas per block. /// - /// This fields will be used to calculate `excess_blob_gas` with [`calc_excess_blob_gas`] func. + /// These fields will be used to calculate `excess_blob_gas` with [`calc_excess_blob_gas`] func. #[deprecated( note = "Use `calc_excess_blob_gas` and `BlobExcessGasAndPrice::new` instead. Only works for forks before Osaka." )] @@ -65,7 +65,7 @@ impl BlobExcessGasAndPrice { } /// Calculates the `excess_blob_gas` from the parent header's `blob_gas_used` and `excess_blob_gas`. -/// uses [`calc_excess_blob_gas`] internally. +/// Uses [`calc_excess_blob_gas_osaka`] internally. #[inline] pub fn calc_excess_blob_gas( parent_excess_blob_gas: u64, diff --git a/crates/context/interface/src/cfg.rs b/crates/context/interface/src/cfg.rs index 79958a2241..9e2d6f9a2f 100644 --- a/crates/context/interface/src/cfg.rs +++ b/crates/context/interface/src/cfg.rs @@ -7,7 +7,7 @@ use primitives::{hardfork::SpecId, Address, TxKind, U256}; /// Configuration for the EVM. #[auto_impl(&, &mut, Box, Arc)] pub trait Cfg { - /// Specification id type, in requires to be convertible to `SpecId` so it can be used + /// Specification id type, it requires to be convertible to `SpecId` so it can be used /// by default in mainnet. type Spec: Into + Clone; diff --git a/crates/context/interface/src/context.rs b/crates/context/interface/src/context.rs index bbf1311a18..0be6f53439 100644 --- a/crates/context/interface/src/context.rs +++ b/crates/context/interface/src/context.rs @@ -13,7 +13,7 @@ use std::string::String; /// It is used to access the transaction, block, configuration, database, journal, and chain. /// It is also used to set the error of the EVM. /// -/// All function has a `*_mut` variant except the function for [`ContextTr::tx`] and [`ContextTr::block`]. +/// All functions have a `*_mut` variant except the function for [`ContextTr::tx`] and [`ContextTr::block`]. #[auto_impl(&mut, Box)] pub trait ContextTr: Host { /// Block type @@ -79,7 +79,7 @@ pub trait ContextTr: Host { fn tx_local_mut(&mut self) -> (&Self::Tx, &mut Self::Local); } -/// Inner Context error used for Interpreter to set error without returning it frm instruction +/// Inner Context error used for Interpreter to set error without returning it from instruction #[derive(Clone, Debug, PartialEq, Eq, Hash, Ord, PartialOrd)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum ContextError { diff --git a/crates/context/interface/src/journaled_state.rs b/crates/context/interface/src/journaled_state.rs index 3f816c6775..7c981a6605 100644 --- a/crates/context/interface/src/journaled_state.rs +++ b/crates/context/interface/src/journaled_state.rs @@ -20,10 +20,10 @@ pub trait JournalTr { /// Dont forget to set spec_id. fn new(database: Self::Database) -> Self; - /// Returns the database. + /// Returns a mutable reference to the database. fn db_mut(&mut self) -> &mut Self::Database; - /// Returns the mutable database. + /// Returns an immutable reference to the database. fn db(&self) -> &Self::Database; /// Returns the storage value from Journal state. @@ -66,8 +66,13 @@ pub trait JournalTr { storage_keys: impl IntoIterator, ) -> Result<(), ::Error>; - /// Warms the account. - fn warm_account(&mut self, address: Address); + /// Warms the account. Internally calls [`JournalTr::warm_account_and_storage`] with empty storage keys. + fn warm_account( + &mut self, + address: Address, + ) -> Result<(), ::Error> { + self.warm_account_and_storage(address, []) + } /// Warms the coinbase account. fn warm_coinbase_account(&mut self, address: Address); diff --git a/crates/context/interface/src/result.rs b/crates/context/interface/src/result.rs index e9dd33769b..340da3a72b 100644 --- a/crates/context/interface/src/result.rs +++ b/crates/context/interface/src/result.rs @@ -30,7 +30,7 @@ pub struct ExecResultAndState { } /// Type alias for backwards compatibility. -pub type ResultAndState = ExecResultAndState>; +pub type ResultAndState = ExecResultAndState, S>; /// Tuple containing multiple execution results and state. pub type ResultVecAndState = ExecResultAndState, S>; diff --git a/crates/context/interface/src/transaction.rs b/crates/context/interface/src/transaction.rs index 091512df3e..474d3e6ff7 100644 --- a/crates/context/interface/src/transaction.rs +++ b/crates/context/interface/src/transaction.rs @@ -55,7 +55,7 @@ pub trait Transaction { /// Note : Common field for all transactions. fn gas_limit(&self) -> u64; - /// The value sent to the receiver of [`TxKind::Call`][primitives::TxKind::Call]. + /// The value sent to the receiver of [`TxKind::Call`]. /// /// Note : Common field for all transactions. fn value(&self) -> U256; diff --git a/crates/context/interface/src/transaction/eip7702.rs b/crates/context/interface/src/transaction/eip7702.rs index b92ba7d47b..6262c79a8c 100644 --- a/crates/context/interface/src/transaction/eip7702.rs +++ b/crates/context/interface/src/transaction/eip7702.rs @@ -16,7 +16,7 @@ pub trait AuthorizationTr { /// signature s-value should be less than SECP256K1N_HALF. fn authority(&self) -> Option
; - /// Returns authorization the chain id. + /// Returns the chain id from the authorization. fn chain_id(&self) -> U256; /// Returns the nonce. diff --git a/crates/context/interface/src/transaction/either.rs b/crates/context/interface/src/transaction/either.rs index 46eb43cebe..c4d6413de7 100644 --- a/crates/context/interface/src/transaction/either.rs +++ b/crates/context/interface/src/transaction/either.rs @@ -10,15 +10,9 @@ where Authorization<'a> = L::Authorization<'a>, > + 'static, { - type AccessListItem<'a> - = L::AccessListItem<'a> - where - Self: 'a; - - type Authorization<'a> - = L::Authorization<'a> - where - Self: 'a; + type AccessListItem<'a> = L::AccessListItem<'a>; + + type Authorization<'a> = L::Authorization<'a>; fn tx_type(&self) -> u8 { match self { diff --git a/crates/context/interface/src/transaction/transaction_type.rs b/crates/context/interface/src/transaction/transaction_type.rs index 1946c6647f..3d011eca2f 100644 --- a/crates/context/interface/src/transaction/transaction_type.rs +++ b/crates/context/interface/src/transaction/transaction_type.rs @@ -1,6 +1,6 @@ //! Transaction type enum. -/// Transaction types of all Ethereum transaction +/// Transaction types of all Ethereum transactions #[repr(u8)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] diff --git a/crates/context/src/journal.rs b/crates/context/src/journal.rs index 722f3cfc6e..e6f63accfd 100644 --- a/crates/context/src/journal.rs +++ b/crates/context/src/journal.rs @@ -4,6 +4,7 @@ //! and inner submodule contains [`JournalInner`] struct that contains state. pub mod entry; pub mod inner; +pub mod warm_addresses; pub use entry::{JournalEntry, JournalEntryTr}; pub use inner::JournalInner; @@ -140,24 +141,19 @@ impl JournalTr for Journal { self.inner.selfdestruct(&mut self.database, address, target) } - fn warm_account(&mut self, address: Address) { - self.inner.warm_preloaded_addresses.insert(address); - } - fn warm_coinbase_account(&mut self, address: Address) { - self.inner.warm_coinbase_address = Some(address); + self.inner.warm_addresses.set_coinbase(address); } fn warm_precompiles(&mut self, precompiles: HashSet
) { - self.inner.precompiles = precompiles; self.inner - .warm_preloaded_addresses - .clone_from(&self.inner.precompiles); + .warm_addresses + .set_precompile_addresses(precompiles); } #[inline] fn precompile_addresses(&self) -> &HashSet
{ - &self.inner.precompiles + self.inner.warm_addresses.precompiles() } /// Returns call depth. diff --git a/crates/context/src/journal/inner.rs b/crates/context/src/journal/inner.rs index 0b805e8047..3230216692 100644 --- a/crates/context/src/journal/inner.rs +++ b/crates/context/src/journal/inner.rs @@ -1,5 +1,5 @@ //! Module containing the [`JournalInner`] that is part of [`crate::Journal`]. -use crate::entry::SelfdestructionRevertStatus; +use crate::{entry::SelfdestructionRevertStatus, warm_addresses::WarmAddresses}; use super::JournalEntryTr; use bytecode::Bytecode; @@ -12,7 +12,7 @@ use database_interface::Database; use primitives::{ hardfork::SpecId::{self, *}, hash_map::Entry, - Address, HashMap, HashSet, Log, StorageKey, StorageValue, B256, KECCAK_EMPTY, U256, + Address, HashMap, Log, StorageKey, StorageValue, B256, KECCAK_EMPTY, U256, }; use state::{Account, EvmState, EvmStorageSlot, TransientStorage}; use std::vec::Vec; @@ -53,17 +53,8 @@ pub struct JournalInner { /// [EIP-161]: https://eips.ethereum.org/EIPS/eip-161 /// [EIP-6780]: https://eips.ethereum.org/EIPS/eip-6780 pub spec: SpecId, - /// Warm loaded addresses are used to check if loaded address - /// should be considered cold or warm loaded when the account - /// is first accessed. - /// - /// Note that this not include newly loaded accounts, account and storage - /// is considered warm if it is found in the `State`. - pub warm_preloaded_addresses: HashSet
, - /// Warm coinbase address, stored separately to avoid cloning preloaded addresses. - pub warm_coinbase_address: Option
, - /// Precompile addresses - pub precompiles: HashSet
, + /// Warm addresses containing both coinbase and current precompiles. + pub warm_addresses: WarmAddresses, } impl Default for JournalInner { @@ -86,9 +77,7 @@ impl JournalInner { transaction_id: 0, depth: 0, spec: SpecId::default(), - warm_preloaded_addresses: HashSet::default(), - precompiles: HashSet::default(), - warm_coinbase_address: None, + warm_addresses: WarmAddresses::new(), } } @@ -116,13 +105,10 @@ impl JournalInner { journal, transaction_id, spec, - warm_preloaded_addresses, - precompiles, - warm_coinbase_address, + warm_addresses, } = self; // Spec precompiles and state are not changed. It is always set again execution. let _ = spec; - let _ = precompiles; let _ = state; transient_storage.clear(); *depth = 0; @@ -131,11 +117,7 @@ impl JournalInner { journal.clear(); // Clear coinbase address warming for next tx - *warm_coinbase_address = None; - // Load precompiles into warm_preloaded_addresses. - // TODO for precompiles we can use max transaction_id so they are always touched warm loaded. - // at least after state clear EIP. - reset_preloaded_addresses(warm_preloaded_addresses, precompiles); + warm_addresses.clear_coinbase(); // increment transaction id. *transaction_id += 1; logs.clear(); @@ -152,11 +134,8 @@ impl JournalInner { journal, transaction_id, spec, - warm_preloaded_addresses, - warm_coinbase_address, - precompiles, + warm_addresses, } = self; - let is_spurious_dragon_enabled = spec.is_enabled_in(SPURIOUS_DRAGON); // iterate over all journals entries and revert our global state journal.drain(..).rev().for_each(|entry| { @@ -166,9 +145,9 @@ impl JournalInner { *depth = 0; logs.clear(); *transaction_id += 1; + // Clear coinbase address warming for next tx - *warm_coinbase_address = None; - reset_preloaded_addresses(warm_preloaded_addresses, precompiles); + warm_addresses.clear_coinbase(); } /// Take the [`EvmState`] and clears the journal by resetting it to initial state. @@ -187,16 +166,12 @@ impl JournalInner { journal, transaction_id, spec, - warm_preloaded_addresses, - warm_coinbase_address, - precompiles, + warm_addresses, } = self; // Spec is not changed. And it is always set again in execution. let _ = spec; // Clear coinbase address warming for next tx - *warm_coinbase_address = None; - // Load precompiles into warm_preloaded_addresses. - reset_preloaded_addresses(warm_preloaded_addresses, precompiles); + warm_addresses.clear_coinbase(); let state = mem::take(state); logs.clear(); @@ -491,12 +466,14 @@ impl JournalInner { self.logs.truncate(checkpoint.log_i); // iterate over last N journals sets and revert our global state - self.journal - .drain(checkpoint.journal_i..) - .rev() - .for_each(|entry| { - entry.revert(state, Some(transient_storage), is_spurious_dragon_enabled); - }); + if checkpoint.journal_i < self.journal.len() { + self.journal + .drain(checkpoint.journal_i..) + .rev() + .for_each(|entry| { + entry.revert(state, Some(transient_storage), is_spurious_dragon_enabled); + }); + } } /// Performs selfdestruct action. @@ -680,8 +657,7 @@ impl JournalInner { }; // Precompiles among some other account(coinbase included) are warm loaded so we need to take that into account - let is_cold = !self.warm_preloaded_addresses.contains(&address) - && self.warm_coinbase_address.as_ref() != Some(&address); + let is_cold = self.warm_addresses.is_cold(&address); StateLoad { data: vac.insert(account), @@ -882,16 +858,3 @@ pub fn sload_with_account( Ok(StateLoad::new(value, is_cold)) } - -fn reset_preloaded_addresses( - warm_preloaded_addresses: &mut HashSet
, - precompiles: &HashSet
, -) { - // `warm_preloaded_addresses` is append-only, and is initialized with `precompiles`. - // Avoid unnecessarily cloning if it hasn't changed. - if warm_preloaded_addresses.len() == precompiles.len() { - debug_assert_eq!(warm_preloaded_addresses, precompiles); - return; - } - warm_preloaded_addresses.clone_from(precompiles); -} diff --git a/crates/context/src/journal/warm_addresses.rs b/crates/context/src/journal/warm_addresses.rs new file mode 100644 index 0000000000..6e72b725f7 --- /dev/null +++ b/crates/context/src/journal/warm_addresses.rs @@ -0,0 +1,266 @@ +//! This module contains [`WarmAddresses`] struct that stores addresses that are warm loaded. +//! +//! It is used to optimize access to precompile addresses. + +use bitvec::{bitvec, order::Lsb0, vec::BitVec}; +use primitives::{short_address, Address, HashSet, SHORT_ADDRESS_CAP}; + +/// Stores addresses that are warm loaded. Contains precompiles and coinbase address. +#[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub struct WarmAddresses { + /// Set of warm loaded precompile addresses. + precompile_set: HashSet
, + /// Bit vector of precompile short addresses. If address is shorter than [`SHORT_ADDRESS_CAP`] it + /// will be stored in this bit vector for faster access. + precompile_short_addresses: BitVec, + /// `true` if all precompiles are short addresses. + all_short_addresses: bool, + /// Coinbase address. + coinbase: Option
, +} + +impl Default for WarmAddresses { + fn default() -> Self { + Self::new() + } +} + +impl WarmAddresses { + /// Create a new warm addresses instance. + #[inline] + pub fn new() -> Self { + Self { + precompile_set: HashSet::default(), + precompile_short_addresses: BitVec::new(), + all_short_addresses: true, + coinbase: None, + } + } + + /// Returns the precompile addresses. + #[inline] + pub fn precompiles(&self) -> &HashSet
{ + &self.precompile_set + } + + /// Returns the coinbase address. + #[inline] + pub fn coinbase(&self) -> Option
{ + self.coinbase + } + + /// Set the precompile addresses and short addresses. + #[inline] + pub fn set_precompile_addresses(&mut self, addresses: HashSet
) { + // short address is always smaller than SHORT_ADDRESS_CAP + self.precompile_short_addresses = bitvec![usize, Lsb0; 0; SHORT_ADDRESS_CAP]; + + let mut all_short_addresses = true; + for address in addresses.iter() { + if let Some(short_address) = short_address(address) { + self.precompile_short_addresses.set(short_address, true); + } else { + all_short_addresses = false; + } + } + + self.all_short_addresses = all_short_addresses; + self.precompile_set = addresses; + } + + /// Set the coinbase address. + #[inline] + pub fn set_coinbase(&mut self, address: Address) { + self.coinbase = Some(address); + } + + /// Clear the coinbase address. + #[inline] + pub fn clear_coinbase(&mut self) { + self.coinbase = None; + } + + /// Returns true if the address is warm loaded. + #[inline] + pub fn is_warm(&self, address: &Address) -> bool { + // check if it is coinbase + if Some(*address) == self.coinbase { + return true; + } + + // if there are no precompiles, it is cold loaded and bitvec is not set. + if self.precompile_set.is_empty() { + return false; + } + + // check if it is short precompile address + if let Some(short_address) = short_address(address) { + return self.precompile_short_addresses[short_address]; + } + + // if all precompiles are short addresses, it is cold loaded. + if self.all_short_addresses { + return false; + } + + // in the end check if it is inside precompile set + self.precompile_set.contains(address) + } + + /// Returns true if the address is cold loaded. + #[inline] + pub fn is_cold(&self, address: &Address) -> bool { + !self.is_warm(address) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use primitives::{address, Address}; + + #[test] + fn test_initialization() { + let warm_addresses = WarmAddresses::new(); + assert!(warm_addresses.precompile_set.is_empty()); + assert!(warm_addresses.precompile_short_addresses.is_empty()); + assert!(warm_addresses.coinbase.is_none()); + + // Test Default trait + let default_addresses = WarmAddresses::default(); + assert_eq!(warm_addresses, default_addresses); + } + + #[test] + fn test_coinbase_management() { + let mut warm_addresses = WarmAddresses::new(); + let coinbase_addr = address!("1234567890123456789012345678901234567890"); + + // Test setting coinbase + warm_addresses.set_coinbase(coinbase_addr); + assert_eq!(warm_addresses.coinbase, Some(coinbase_addr)); + assert!(warm_addresses.is_warm(&coinbase_addr)); + + // Test clearing coinbase + warm_addresses.clear_coinbase(); + assert!(warm_addresses.coinbase.is_none()); + assert!(!warm_addresses.is_warm(&coinbase_addr)); + } + + #[test] + fn test_short_address_precompiles() { + let mut warm_addresses = WarmAddresses::new(); + + // Create short addresses (18 leading zeros, last 2 bytes < 300) + let mut bytes1 = [0u8; 20]; + bytes1[19] = 1u8; + let short_addr1 = Address::from(bytes1); + + let mut bytes2 = [0u8; 20]; + bytes2[19] = 5u8; + let short_addr2 = Address::from(bytes2); + + let mut precompiles = HashSet::default(); + precompiles.insert(short_addr1); + precompiles.insert(short_addr2); + + warm_addresses.set_precompile_addresses(precompiles.clone()); + + // Verify storage + assert_eq!(warm_addresses.precompile_set, precompiles); + assert_eq!( + warm_addresses.precompile_short_addresses.len(), + SHORT_ADDRESS_CAP + ); + + // Verify bitvec optimization + assert!(warm_addresses.precompile_short_addresses[1]); + assert!(warm_addresses.precompile_short_addresses[5]); + assert!(!warm_addresses.precompile_short_addresses[0]); + + // Verify warmth detection + assert!(warm_addresses.is_warm(&short_addr1)); + assert!(warm_addresses.is_warm(&short_addr2)); + + // Test non-existent short address + let mut other_bytes = [0u8; 20]; + other_bytes[19] = 20u8; + let other_short_addr = Address::from(other_bytes); + assert!(!warm_addresses.is_warm(&other_short_addr)); + } + + #[test] + fn test_regular_address_precompiles() { + let mut warm_addresses = WarmAddresses::new(); + + // Create non-short addresses + let regular_addr = address!("1234567890123456789012345678901234567890"); + let mut bytes = [0u8; 20]; + bytes[18] = 1u8; + bytes[19] = 44u8; // 300 + let boundary_addr = Address::from(bytes); + + let mut precompiles = HashSet::default(); + precompiles.insert(regular_addr); + precompiles.insert(boundary_addr); + + warm_addresses.set_precompile_addresses(precompiles.clone()); + + // Verify storage + assert_eq!(warm_addresses.precompile_set, precompiles); + assert!(!warm_addresses.precompile_short_addresses.any()); + + // Verify warmth detection + assert!(warm_addresses.is_warm(®ular_addr)); + assert!(warm_addresses.is_warm(&boundary_addr)); + + // Test non-existent regular address + let other_addr = address!("0987654321098765432109876543210987654321"); + assert!(!warm_addresses.is_warm(&other_addr)); + } + + #[test] + fn test_mixed_address_types() { + let mut warm_addresses = WarmAddresses::new(); + + let mut short_bytes = [0u8; 20]; + short_bytes[19] = 7u8; + let short_addr = Address::from(short_bytes); + let regular_addr = address!("1234567890123456789012345678901234567890"); + + let mut precompiles = HashSet::default(); + precompiles.insert(short_addr); + precompiles.insert(regular_addr); + + warm_addresses.set_precompile_addresses(precompiles); + + // Both types should be warm + assert!(warm_addresses.is_warm(&short_addr)); + assert!(warm_addresses.is_warm(®ular_addr)); + + // Verify short address optimization is used + assert!(warm_addresses.precompile_short_addresses[7]); + assert!(!warm_addresses.precompile_short_addresses[8]); + } + + #[test] + fn test_short_address_boundary() { + let mut warm_addresses = WarmAddresses::new(); + + // Address at boundary (SHORT_ADDRESS_CAP - 1) + let mut boundary_bytes = [0u8; 20]; + let boundary_val = (SHORT_ADDRESS_CAP - 1) as u16; + boundary_bytes[18] = (boundary_val >> 8) as u8; + boundary_bytes[19] = boundary_val as u8; + let boundary_addr = Address::from(boundary_bytes); + + let mut precompiles = HashSet::default(); + precompiles.insert(boundary_addr); + + warm_addresses.set_precompile_addresses(precompiles); + + assert!(warm_addresses.is_warm(&boundary_addr)); + assert!(warm_addresses.precompile_short_addresses[SHORT_ADDRESS_CAP - 1]); + } +} diff --git a/crates/context/src/tx.rs b/crates/context/src/tx.rs index b7752a3aea..d3510e5c6c 100644 --- a/crates/context/src/tx.rs +++ b/crates/context/src/tx.rs @@ -541,7 +541,7 @@ impl TxEnvBuilder { // target is required if !self.kind.is_call() { - return Err(DeriveTxTypeError::MissingTargetForEip4844.into()); + return Err(DeriveTxTypeError::MissingTargetForEip7702.into()); } } TransactionType::Custom => { diff --git a/crates/database/CHANGELOG.md b/crates/database/CHANGELOG.md index 1cfa90d7b8..a5dcf17337 100644 --- a/crates/database/CHANGELOG.md +++ b/crates/database/CHANGELOG.md @@ -7,6 +7,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [7.0.5](https://github.com/bluealloy/revm/compare/revm-database-v7.0.4...revm-database-v7.0.5) - 2025-08-23 + +### Other + +- *(database)* remove unused dependencies ([#2885](https://github.com/bluealloy/revm/pull/2885)) +- add AccountStatus unit test ([#2869](https://github.com/bluealloy/revm/pull/2869)) + +## [7.0.4](https://github.com/bluealloy/revm/compare/revm-database-v7.0.3...revm-database-v7.0.4) - 2025-08-12 + +### Other + +- use mem::take ([#2870](https://github.com/bluealloy/revm/pull/2870)) +- small performance and safety improvements ([#2868](https://github.com/bluealloy/revm/pull/2868)) +- use HashMap::or_insert_with lazily compute ([#2864](https://github.com/bluealloy/revm/pull/2864)) + +## [7.0.3](https://github.com/bluealloy/revm/compare/revm-database-v7.0.2...revm-database-v7.0.3) - 2025-08-06 + +### Other + +- update README.md ([#2842](https://github.com/bluealloy/revm/pull/2842)) +- add rust-version and note about MSRV ([#2789](https://github.com/bluealloy/revm/pull/2789)) + ## [7.0.2](https://github.com/bluealloy/revm/compare/revm-database-v7.0.1...revm-database-v7.0.2) - 2025-07-23 ### Other diff --git a/crates/database/Cargo.toml b/crates/database/Cargo.toml index 97e27554c2..099e5c6caf 100644 --- a/crates/database/Cargo.toml +++ b/crates/database/Cargo.toml @@ -1,13 +1,14 @@ [package] name = "revm-database" description = "Revm Database implementations" -version = "7.0.2" +version = "7.0.5" authors.workspace = true edition.workspace = true keywords.workspace = true license.workspace = true repository.workspace = true readme.workspace = true +rust-version.workspace = true [package.metadata.docs.rs] all-features = true @@ -27,8 +28,8 @@ serde = { workspace = true, features = ["derive", "rc"], optional = true } # alloydb tokio = { workspace = true, features = [ - "rt-multi-thread", - "macros", + "rt-multi-thread", + "macros", ], optional = true } alloy-provider = { workspace = true, optional = true } alloy-eips = { workspace = true, optional = true } @@ -36,8 +37,6 @@ alloy-transport = { workspace = true, optional = true } [dev-dependencies] serde_json = { workspace = true, features = ["alloc"] } -anyhow.workspace = true -rstest.workspace = true [features] default = ["std"] @@ -48,7 +47,7 @@ std = [ "database-interface/std", "primitives/std", "state/std", - "serde_json/std" + "serde_json/std", ] serde = [ "dep:serde", @@ -56,13 +55,13 @@ serde = [ "bytecode/serde", "database-interface/serde", "primitives/serde", - "state/serde" + "state/serde", ] alloydb = [ - "std", - "database-interface/asyncdb", - "dep:tokio", - "dep:alloy-provider", - "dep:alloy-eips", - "dep:alloy-transport", + "std", + "database-interface/asyncdb", + "dep:tokio", + "dep:alloy-provider", + "dep:alloy-eips", + "dep:alloy-transport", ] diff --git a/crates/database/interface/CHANGELOG.md b/crates/database/interface/CHANGELOG.md index 1e2d3eb839..e308ef5bf3 100644 --- a/crates/database/interface/CHANGELOG.md +++ b/crates/database/interface/CHANGELOG.md @@ -7,6 +7,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [7.0.5](https://github.com/bluealloy/revm/compare/revm-database-interface-v7.0.4...revm-database-interface-v7.0.5) - 2025-08-23 + +### Other + +- *(database)* remove unused dependencies ([#2885](https://github.com/bluealloy/revm/pull/2885)) + +## [7.0.4](https://github.com/bluealloy/revm/compare/revm-database-interface-v7.0.3...revm-database-interface-v7.0.4) - 2025-08-12 + +### Other + +- updated the following local packages: revm-primitives, revm-state + +## [7.0.3](https://github.com/bluealloy/revm/compare/revm-database-interface-v7.0.2...revm-database-interface-v7.0.3) - 2025-08-06 + +### Other + +- update README.md ([#2842](https://github.com/bluealloy/revm/pull/2842)) +- add rust-version and note about MSRV ([#2789](https://github.com/bluealloy/revm/pull/2789)) + ## [7.0.2](https://github.com/bluealloy/revm/compare/revm-database-interface-v7.0.1...revm-database-interface-v7.0.2) - 2025-07-23 ### Other diff --git a/crates/database/interface/Cargo.toml b/crates/database/interface/Cargo.toml index 49ef0ba52c..b6e19704e0 100644 --- a/crates/database/interface/Cargo.toml +++ b/crates/database/interface/Cargo.toml @@ -1,13 +1,14 @@ [package] name = "revm-database-interface" description = "Revm Database interface" -version = "7.0.2" +version = "7.0.5" authors.workspace = true edition.workspace = true keywords.workspace = true license.workspace = true repository.workspace = true readme.workspace = true +rust-version.workspace = true [package.metadata.docs.rs] all-features = true @@ -32,21 +33,9 @@ serde = { workspace = true, features = ["derive", "rc"], optional = true } tokio = { workspace = true, optional = true } [dev-dependencies] -anyhow.workspace = true -rstest.workspace = true [features] default = ["std"] -std = [ - "serde?/std", - "primitives/std", - "state/std", - "either/std" -] -serde = [ - "dep:serde", - "primitives/serde", - "state/serde", - "either/serde" -] +std = ["serde?/std", "primitives/std", "state/std", "either/std"] +serde = ["dep:serde", "primitives/serde", "state/serde", "either/serde"] asyncdb = ["dep:tokio", "tokio/rt-multi-thread"] diff --git a/crates/database/src/states/account_status.rs b/crates/database/src/states/account_status.rs index ac443fb280..8b3bfcebf7 100644 --- a/crates/database/src/states/account_status.rs +++ b/crates/database/src/states/account_status.rs @@ -41,9 +41,7 @@ impl AccountStatus { pub fn is_not_modified(&self) -> bool { matches!( self, - AccountStatus::LoadedNotExisting - | AccountStatus::Loaded - | AccountStatus::LoadedEmptyEIP161 + Self::LoadedNotExisting | Self::Loaded | Self::LoadedEmptyEIP161 ) } @@ -52,9 +50,7 @@ impl AccountStatus { pub fn was_destroyed(&self) -> bool { matches!( self, - AccountStatus::Destroyed - | AccountStatus::DestroyedChanged - | AccountStatus::DestroyedAgain + Self::Destroyed | Self::DestroyedChanged | Self::DestroyedAgain ) } @@ -62,11 +58,11 @@ impl AccountStatus { pub fn is_storage_known(&self) -> bool { matches!( self, - AccountStatus::LoadedNotExisting - | AccountStatus::InMemoryChange - | AccountStatus::Destroyed - | AccountStatus::DestroyedChanged - | AccountStatus::DestroyedAgain + Self::LoadedNotExisting + | Self::InMemoryChange + | Self::Destroyed + | Self::DestroyedChanged + | Self::DestroyedAgain ) } @@ -74,27 +70,27 @@ impl AccountStatus { /// This means that some storage values can be found in both /// memory and database. pub fn is_modified_and_not_destroyed(&self) -> bool { - matches!(self, AccountStatus::Changed | AccountStatus::InMemoryChange) + matches!(self, Self::Changed | Self::InMemoryChange) } /// Returns the next account status on creation. - pub fn on_created(&self) -> AccountStatus { + pub fn on_created(&self) -> Self { match self { // If account was destroyed previously just copy new info to it. - AccountStatus::DestroyedAgain - | AccountStatus::Destroyed - | AccountStatus::DestroyedChanged => AccountStatus::DestroyedChanged, + Self::DestroyedAgain + | Self::Destroyed + | Self::DestroyedChanged => Self::DestroyedChanged, // If account is loaded from db. - AccountStatus::LoadedNotExisting + Self::LoadedNotExisting // Loaded empty eip161 to creates is not possible as CREATE2 was added after EIP-161 - | AccountStatus::LoadedEmptyEIP161 - | AccountStatus::Loaded - | AccountStatus::Changed - | AccountStatus::InMemoryChange => { + | Self::LoadedEmptyEIP161 + | Self::Loaded + | Self::Changed + | Self::InMemoryChange => { // If account is loaded and not empty this means that account has some balance. // This means that account cannot be created. // We are assuming that EVM did necessary checks before allowing account to be created. - AccountStatus::InMemoryChange + Self::InMemoryChange } } } @@ -104,20 +100,16 @@ impl AccountStatus { /// # Panics /// /// If current status is [AccountStatus::Loaded] or [AccountStatus::Changed]. - pub fn on_touched_empty_post_eip161(&self) -> AccountStatus { + pub fn on_touched_empty_post_eip161(&self) -> Self { match self { // Account can be touched but not existing. The status should remain the same. - AccountStatus::LoadedNotExisting => AccountStatus::LoadedNotExisting, + Self::LoadedNotExisting => Self::LoadedNotExisting, // Account can be created empty and only then touched. - AccountStatus::InMemoryChange - | AccountStatus::Destroyed - | AccountStatus::LoadedEmptyEIP161 => AccountStatus::Destroyed, + Self::InMemoryChange | Self::Destroyed | Self::LoadedEmptyEIP161 => Self::Destroyed, // Transition to destroy the account. - AccountStatus::DestroyedAgain | AccountStatus::DestroyedChanged => { - AccountStatus::DestroyedAgain - } + Self::DestroyedAgain | Self::DestroyedChanged => Self::DestroyedAgain, // Account statuses considered unreachable. - AccountStatus::Loaded | AccountStatus::Changed => { + Self::Loaded | Self::Changed => { unreachable!("Wrong state transition, touch empty is not possible from {self:?}"); } } @@ -129,77 +121,69 @@ impl AccountStatus { /// # Panics /// /// If current status is [AccountStatus::Loaded] or [AccountStatus::Changed]. - pub fn on_touched_created_pre_eip161(&self, had_no_info: bool) -> Option { + pub fn on_touched_created_pre_eip161(&self, had_no_info: bool) -> Option { match self { - AccountStatus::LoadedEmptyEIP161 => None, - AccountStatus::DestroyedChanged => { + Self::LoadedEmptyEIP161 => None, + Self::DestroyedChanged => { if had_no_info { None } else { - Some(AccountStatus::DestroyedChanged) + Some(Self::DestroyedChanged) } } - AccountStatus::Destroyed | AccountStatus::DestroyedAgain => { - Some(AccountStatus::DestroyedChanged) - } - AccountStatus::InMemoryChange | AccountStatus::LoadedNotExisting => { - Some(AccountStatus::InMemoryChange) - } - AccountStatus::Loaded | AccountStatus::Changed => { + Self::Destroyed | Self::DestroyedAgain => Some(Self::DestroyedChanged), + Self::InMemoryChange | Self::LoadedNotExisting => Some(Self::InMemoryChange), + Self::Loaded | Self::Changed => { unreachable!("Wrong state transition, touch crate is not possible from {self:?}") } } } /// Returns the next account status on change. - pub fn on_changed(&self, had_no_nonce_and_code: bool) -> AccountStatus { + pub fn on_changed(&self, had_no_nonce_and_code: bool) -> Self { match self { // If the account was loaded as not existing, promote it to changed. // This account was likely created by a balance transfer. - AccountStatus::LoadedNotExisting => AccountStatus::InMemoryChange, + Self::LoadedNotExisting => Self::InMemoryChange, // Change on empty account, should transfer storage if there is any. // There is possibility that there are storage entries inside db. // That storage is used in merkle tree calculation before state clear EIP. - AccountStatus::LoadedEmptyEIP161 => AccountStatus::InMemoryChange, + Self::LoadedEmptyEIP161 => Self::InMemoryChange, // The account was loaded as existing. - AccountStatus::Loaded => { + Self::Loaded => { if had_no_nonce_and_code { // Account is fully in memory - AccountStatus::InMemoryChange + Self::InMemoryChange } else { // Can be contract and some of storage slots can be present inside db. - AccountStatus::Changed + Self::Changed } } // On change, the "changed" type account statuses are preserved. // Any checks for empty accounts are done outside of this fn. - AccountStatus::Changed => AccountStatus::Changed, - AccountStatus::InMemoryChange => AccountStatus::InMemoryChange, - AccountStatus::DestroyedChanged => AccountStatus::DestroyedChanged, + Self::Changed => Self::Changed, + Self::InMemoryChange => Self::InMemoryChange, + Self::DestroyedChanged => Self::DestroyedChanged, // If account is destroyed and then changed this means this is // balance transfer. - AccountStatus::Destroyed | AccountStatus::DestroyedAgain => { - AccountStatus::DestroyedChanged - } + Self::Destroyed | Self::DestroyedAgain => Self::DestroyedChanged, } } /// Returns the next account status on selfdestruct. - pub fn on_selfdestructed(&self) -> AccountStatus { + pub fn on_selfdestructed(&self) -> Self { match self { // Non existing account can't be destroyed. - AccountStatus::LoadedNotExisting => AccountStatus::LoadedNotExisting, + Self::LoadedNotExisting => Self::LoadedNotExisting, // If account is created and selfdestructed in the same block, mark it as destroyed again. // Note: There is no big difference between Destroyed and DestroyedAgain in this case, // but was added for clarity. - AccountStatus::DestroyedChanged - | AccountStatus::DestroyedAgain - | AccountStatus::Destroyed => AccountStatus::DestroyedAgain, + Self::DestroyedChanged | Self::DestroyedAgain | Self::Destroyed => Self::DestroyedAgain, // Transition to destroyed status. - _ => AccountStatus::Destroyed, + _ => Self::Destroyed, } } @@ -271,4 +255,290 @@ mod test { assert!(!AccountStatus::DestroyedChanged.is_modified_and_not_destroyed()); assert!(!AccountStatus::DestroyedAgain.is_modified_and_not_destroyed()); } + + #[test] + fn test_on_created() { + assert_eq!( + AccountStatus::Destroyed.on_created(), + AccountStatus::DestroyedChanged + ); + assert_eq!( + AccountStatus::DestroyedAgain.on_created(), + AccountStatus::DestroyedChanged + ); + assert_eq!( + AccountStatus::DestroyedChanged.on_created(), + AccountStatus::DestroyedChanged + ); + + assert_eq!( + AccountStatus::LoadedNotExisting.on_created(), + AccountStatus::InMemoryChange + ); + assert_eq!( + AccountStatus::Loaded.on_created(), + AccountStatus::InMemoryChange + ); + assert_eq!( + AccountStatus::LoadedEmptyEIP161.on_created(), + AccountStatus::InMemoryChange + ); + assert_eq!( + AccountStatus::Changed.on_created(), + AccountStatus::InMemoryChange + ); + assert_eq!( + AccountStatus::InMemoryChange.on_created(), + AccountStatus::InMemoryChange + ); + } + + #[test] + fn test_on_touched_empty_post_eip161() { + assert_eq!( + AccountStatus::LoadedNotExisting.on_touched_empty_post_eip161(), + AccountStatus::LoadedNotExisting + ); + assert_eq!( + AccountStatus::InMemoryChange.on_touched_empty_post_eip161(), + AccountStatus::Destroyed + ); + assert_eq!( + AccountStatus::Destroyed.on_touched_empty_post_eip161(), + AccountStatus::Destroyed + ); + assert_eq!( + AccountStatus::LoadedEmptyEIP161.on_touched_empty_post_eip161(), + AccountStatus::Destroyed + ); + assert_eq!( + AccountStatus::DestroyedAgain.on_touched_empty_post_eip161(), + AccountStatus::DestroyedAgain + ); + assert_eq!( + AccountStatus::DestroyedChanged.on_touched_empty_post_eip161(), + AccountStatus::DestroyedAgain + ); + } + + #[test] + fn test_on_touched_created_pre_eip161() { + assert_eq!( + AccountStatus::LoadedEmptyEIP161.on_touched_created_pre_eip161(true), + None + ); + assert_eq!( + AccountStatus::LoadedEmptyEIP161.on_touched_created_pre_eip161(false), + None + ); + + assert_eq!( + AccountStatus::DestroyedChanged.on_touched_created_pre_eip161(true), + None + ); + assert_eq!( + AccountStatus::DestroyedChanged.on_touched_created_pre_eip161(false), + Some(AccountStatus::DestroyedChanged) + ); + + assert_eq!( + AccountStatus::Destroyed.on_touched_created_pre_eip161(true), + Some(AccountStatus::DestroyedChanged) + ); + assert_eq!( + AccountStatus::Destroyed.on_touched_created_pre_eip161(false), + Some(AccountStatus::DestroyedChanged) + ); + + assert_eq!( + AccountStatus::DestroyedAgain.on_touched_created_pre_eip161(true), + Some(AccountStatus::DestroyedChanged) + ); + assert_eq!( + AccountStatus::DestroyedAgain.on_touched_created_pre_eip161(false), + Some(AccountStatus::DestroyedChanged) + ); + + assert_eq!( + AccountStatus::InMemoryChange.on_touched_created_pre_eip161(true), + Some(AccountStatus::InMemoryChange) + ); + assert_eq!( + AccountStatus::InMemoryChange.on_touched_created_pre_eip161(false), + Some(AccountStatus::InMemoryChange) + ); + + assert_eq!( + AccountStatus::LoadedNotExisting.on_touched_created_pre_eip161(true), + Some(AccountStatus::InMemoryChange) + ); + assert_eq!( + AccountStatus::LoadedNotExisting.on_touched_created_pre_eip161(false), + Some(AccountStatus::InMemoryChange) + ); + } + + #[test] + fn test_on_changed() { + assert_eq!( + AccountStatus::LoadedNotExisting.on_changed(true), + AccountStatus::InMemoryChange + ); + assert_eq!( + AccountStatus::LoadedNotExisting.on_changed(false), + AccountStatus::InMemoryChange + ); + + assert_eq!( + AccountStatus::LoadedEmptyEIP161.on_changed(true), + AccountStatus::InMemoryChange + ); + assert_eq!( + AccountStatus::LoadedEmptyEIP161.on_changed(false), + AccountStatus::InMemoryChange + ); + + assert_eq!( + AccountStatus::Loaded.on_changed(true), + AccountStatus::InMemoryChange + ); + assert_eq!( + AccountStatus::Loaded.on_changed(false), + AccountStatus::Changed + ); + + assert_eq!( + AccountStatus::Changed.on_changed(true), + AccountStatus::Changed + ); + assert_eq!( + AccountStatus::Changed.on_changed(false), + AccountStatus::Changed + ); + + assert_eq!( + AccountStatus::InMemoryChange.on_changed(true), + AccountStatus::InMemoryChange + ); + assert_eq!( + AccountStatus::InMemoryChange.on_changed(false), + AccountStatus::InMemoryChange + ); + + assert_eq!( + AccountStatus::DestroyedChanged.on_changed(true), + AccountStatus::DestroyedChanged + ); + assert_eq!( + AccountStatus::DestroyedChanged.on_changed(false), + AccountStatus::DestroyedChanged + ); + + assert_eq!( + AccountStatus::Destroyed.on_changed(true), + AccountStatus::DestroyedChanged + ); + assert_eq!( + AccountStatus::Destroyed.on_changed(false), + AccountStatus::DestroyedChanged + ); + + assert_eq!( + AccountStatus::DestroyedAgain.on_changed(true), + AccountStatus::DestroyedChanged + ); + assert_eq!( + AccountStatus::DestroyedAgain.on_changed(false), + AccountStatus::DestroyedChanged + ); + } + + #[test] + fn test_on_selfdestructed() { + assert_eq!( + AccountStatus::LoadedNotExisting.on_selfdestructed(), + AccountStatus::LoadedNotExisting + ); + + assert_eq!( + AccountStatus::DestroyedChanged.on_selfdestructed(), + AccountStatus::DestroyedAgain + ); + assert_eq!( + AccountStatus::DestroyedAgain.on_selfdestructed(), + AccountStatus::DestroyedAgain + ); + assert_eq!( + AccountStatus::Destroyed.on_selfdestructed(), + AccountStatus::DestroyedAgain + ); + + assert_eq!( + AccountStatus::Loaded.on_selfdestructed(), + AccountStatus::Destroyed + ); + assert_eq!( + AccountStatus::LoadedEmptyEIP161.on_selfdestructed(), + AccountStatus::Destroyed + ); + assert_eq!( + AccountStatus::InMemoryChange.on_selfdestructed(), + AccountStatus::Destroyed + ); + assert_eq!( + AccountStatus::Changed.on_selfdestructed(), + AccountStatus::Destroyed + ); + } + + #[test] + fn test_transition() { + let mut status = AccountStatus::Destroyed; + status.transition(AccountStatus::Loaded); + assert_eq!(status, AccountStatus::DestroyedChanged); + + let mut status = AccountStatus::DestroyedChanged; + status.transition(AccountStatus::InMemoryChange); + assert_eq!(status, AccountStatus::DestroyedChanged); + + let mut status = AccountStatus::DestroyedAgain; + status.transition(AccountStatus::Changed); + assert_eq!(status, AccountStatus::DestroyedChanged); + + let mut status = AccountStatus::InMemoryChange; + status.transition(AccountStatus::Loaded); + assert_eq!(status, AccountStatus::InMemoryChange); + + let mut status = AccountStatus::InMemoryChange; + status.transition(AccountStatus::Changed); + assert_eq!(status, AccountStatus::InMemoryChange); + + let mut status = AccountStatus::Loaded; + status.transition(AccountStatus::Changed); + assert_eq!(status, AccountStatus::Changed); + + let mut status = AccountStatus::LoadedNotExisting; + status.transition(AccountStatus::InMemoryChange); + assert_eq!(status, AccountStatus::InMemoryChange); + + let mut status = AccountStatus::LoadedEmptyEIP161; + status.transition(AccountStatus::Loaded); + assert_eq!(status, AccountStatus::Loaded); + + let mut status = AccountStatus::Destroyed; + status.transition(AccountStatus::DestroyedChanged); + assert_eq!(status, AccountStatus::DestroyedChanged); + + let mut status = AccountStatus::DestroyedAgain; + status.transition(AccountStatus::Destroyed); + assert_eq!(status, AccountStatus::Destroyed); + + let mut status = AccountStatus::Loaded; + status.transition(AccountStatus::Destroyed); + assert_eq!(status, AccountStatus::Destroyed); + + let mut status = AccountStatus::Changed; + status.transition(AccountStatus::DestroyedAgain); + assert_eq!(status, AccountStatus::DestroyedAgain); + } } diff --git a/crates/database/src/states/bundle_account.rs b/crates/database/src/states/bundle_account.rs index ffa4b20b4f..54bd85ff10 100644 --- a/crates/database/src/states/bundle_account.rs +++ b/crates/database/src/states/bundle_account.rs @@ -118,7 +118,7 @@ impl BundleAccount { // if storage is not present set original value as current value. self.storage .entry(key) - .or_insert(StorageSlot::new(value)) + .or_insert_with(|| StorageSlot::new(value)) .present_value = value; } RevertToSlot::Destroyed => { @@ -232,7 +232,7 @@ impl BundleAccount { } AccountStatus::Destroyed => { // Clear this storage and move it to the Revert. - let this_storage = self.storage.drain().collect(); + let this_storage = core::mem::take(&mut self.storage); let ret = match self.status { AccountStatus::InMemoryChange | AccountStatus::Changed | AccountStatus::Loaded | AccountStatus::LoadedEmptyEIP161 => { Some(AccountRevert::new_selfdestructed(self.status, info_revert, this_storage)) @@ -356,7 +356,7 @@ impl BundleAccount { // Destroyed again will set empty account. AccountStatus::DestroyedChanged, AccountInfoRevert::RevertTo(self.info.clone().unwrap_or_default()), - self.storage.drain().collect(), + core::mem::take(&mut self.storage), HashMap::default(), )) } diff --git a/crates/database/src/states/bundle_state.rs b/crates/database/src/states/bundle_state.rs index 7b24298e04..f4b0a6cceb 100644 --- a/crates/database/src/states/bundle_state.rs +++ b/crates/database/src/states/bundle_state.rs @@ -307,7 +307,7 @@ impl BundleBuilder { reverts_size += account_revert.size_hint(); reverts_map .entry(block_number) - .or_insert(Vec::new()) + .or_insert_with(Vec::new) .push((address, account_revert)); } }); @@ -618,7 +618,7 @@ impl BundleState { // database so we can check if plain state was wiped or not. let mut account_storage_changed = Vec::with_capacity(account.storage.len()); - for (key, slot) in account.storage.iter().map(|(k, v)| (*k, *v)) { + for (&key, &slot) in account.storage.iter() { // If storage was destroyed that means that storage was wiped. // In that case we need to check if present storage value is different then ZERO. let destroyed_and_not_zero = was_destroyed && !slot.present_value.is_zero(); diff --git a/crates/database/src/states/state.rs b/crates/database/src/states/state.rs index 76ba828a6f..22f8263343 100644 --- a/crates/database/src/states/state.rs +++ b/crates/database/src/states/state.rs @@ -93,7 +93,8 @@ impl State { balances: impl IntoIterator, ) -> Result<(), DB::Error> { // Make transition and update cache state - let mut transitions = Vec::new(); + let balances = balances.into_iter(); + let mut transitions = Vec::with_capacity(balances.size_hint().0); for (address, balance) in balances { if balance == 0 { continue; diff --git a/crates/ee-tests/CHANGELOG.md b/crates/ee-tests/CHANGELOG.md new file mode 100644 index 0000000000..f6c03b2070 --- /dev/null +++ b/crates/ee-tests/CHANGELOG.md @@ -0,0 +1,20 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [0.1.0](https://github.com/bluealloy/revm/releases/tag/revm-ee-tests-v0.1.0) - 2025-08-06 + +### Added + +- gastable, record static gas in Interpreter loop ([#2822](https://github.com/bluealloy/revm/pull/2822)) +- fix renamed functions for system_call ([#2824](https://github.com/bluealloy/revm/pull/2824)) +- refactor test utils ([#2813](https://github.com/bluealloy/revm/pull/2813)) + +### Other + +- *(op-revm)* Adds caller nonce assertion to op-revm intergation tests ([#2815](https://github.com/bluealloy/revm/pull/2815)) diff --git a/crates/ee-tests/Cargo.toml b/crates/ee-tests/Cargo.toml new file mode 100644 index 0000000000..fee90fdd51 --- /dev/null +++ b/crates/ee-tests/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "revm-ee-tests" +description = "Common test utilities for REVM crates" +version = "0.1.0" +authors.workspace = true +edition.workspace = true +keywords.workspace = true +license.workspace = true +repository.workspace = true +readme.workspace = true +rust-version.workspace = true + +[lints] +workspace = true + +[dependencies] +serde = { version = "1.0", features = ["derive"] } +serde_json = { version = "1.0", features = ["preserve_order"] } +revm = { workspace = true, features = ["serde"] } +op-revm = { workspace = true, features = ["serde"] } + +[dev-dependencies] +rstest = { workspace = true } +alloy-sol-types = { workspace = true } +sha2 = { workspace = true } +alloy-primitives = { workspace = true } + +[features] +default = [] +optional_balance_check = [ + "revm/optional_balance_check", + "op-revm/optional_balance_check", +] diff --git a/crates/ee-tests/src/lib.rs b/crates/ee-tests/src/lib.rs new file mode 100644 index 0000000000..e07453abcf --- /dev/null +++ b/crates/ee-tests/src/lib.rs @@ -0,0 +1,134 @@ +//! Common test utilities for REVM crates. +//! +//! This crate provides shared test utilities that are used across different REVM crates. + +use std::path::PathBuf; + +use serde_json::Value; + +/// Configuration for the test data comparison utility. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct TestdataConfig { + /// The directory where test data files are stored. + pub testdata_dir: PathBuf, +} + +impl Default for TestdataConfig { + fn default() -> Self { + Self { + testdata_dir: PathBuf::from("tests/testdata"), + } + } +} + +/// Compares or saves the execution output to a testdata file. +/// +/// This utility helps maintain consistent test behavior by comparing +/// execution results against known-good outputs stored in JSON files. +/// +/// # Arguments +/// +/// * `filename` - The name of the testdata file, relative to tests/testdata/ +/// * `output` - The execution output to compare or save +/// +/// # Panics +/// +/// This function panics if: +/// - The output doesn't match the expected testdata (when testdata file exists) +/// - There's an error reading/writing files +/// - JSON serialization/deserialization fails +/// +/// # Note +/// +/// Tests using this function require the `serde` feature to be enabled: +/// ```bash +/// cargo test --features serde +/// ``` +pub fn compare_or_save_testdata(filename: &str, output: &T) +where + T: serde::Serialize + for<'a> serde::Deserialize<'a> + PartialEq + std::fmt::Debug, +{ + compare_or_save_testdata_with_config(filename, output, TestdataConfig::default()); +} + +/// Compares or saves the execution output to a testdata file with custom configuration. +/// +/// This is a more flexible version of [`compare_or_save_testdata`] that allows +/// specifying a custom testdata directory. +/// +/// # Arguments +/// +/// * `filename` - The name of the testdata file, relative to the testdata directory +/// * `output` - The execution output to compare or save +/// * `config` - Configuration for the test data comparison +pub fn compare_or_save_testdata_with_config(filename: &str, output: &T, config: TestdataConfig) +where + T: serde::Serialize + for<'a> serde::Deserialize<'a> + PartialEq + std::fmt::Debug, +{ + use std::fs; + + let testdata_file = config.testdata_dir.join(filename); + + // Create directory if it doesn't exist + if !config.testdata_dir.exists() { + fs::create_dir_all(&config.testdata_dir).unwrap(); + } + + // Serialize the output to serde Value. + let output_json = serde_json::to_string(&output).unwrap(); + + // convert to Value and sort all objects. + let mut temp: Value = serde_json::from_str(&output_json).unwrap(); + temp.sort_all_objects(); + + // serialize to pretty string + let output_json = serde_json::to_string_pretty(&temp).unwrap(); + + // If the testdata file doesn't exist, save the output + if !testdata_file.exists() { + fs::write(&testdata_file, &output_json).unwrap(); + println!("Saved testdata to {}", testdata_file.display()); + return; + } + + // Read the expected output from the testdata file + let expected_json = fs::read_to_string(&testdata_file).unwrap(); + + // Deserialize to actual object for proper comparison + let expected: T = serde_json::from_str(&expected_json).unwrap(); + + // Compare the output objects directly + if *output != expected { + panic!( + "Value does not match testdata.\nExpected:\n{expected_json}\n\nActual:\n{output_json}" + ); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[derive(Debug, PartialEq, serde::Serialize, serde::Deserialize)] + struct TestData { + value: u32, + message: String, + } + + #[test] + fn test_compare_or_save_testdata() { + let test_data = TestData { + value: 42, + message: "test message".to_string(), + }; + + // This will save the test data on first run, then compare on subsequent runs + compare_or_save_testdata("test_data.json", &test_data); + } +} + +#[cfg(test)] +mod op_revm_tests; + +#[cfg(test)] +mod revm_tests; diff --git a/crates/op-revm/tests/integration.rs b/crates/ee-tests/src/op_revm_tests.rs similarity index 90% rename from crates/op-revm/tests/integration.rs rename to crates/ee-tests/src/op_revm_tests.rs index a41840ff36..c98e3d57b1 100644 --- a/crates/op-revm/tests/integration.rs +++ b/crates/ee-tests/src/op_revm_tests.rs @@ -1,9 +1,8 @@ //! Integration tests for the `op-revm` crate. -mod common; -use common::compare_or_save_testdata; +use crate::TestdataConfig; use op_revm::{ - precompiles::bn128_pair::GRANITE_MAX_INPUT_SIZE, DefaultOp, L1BlockInfo, OpBuilder, + precompiles::bn254_pair::GRANITE_MAX_INPUT_SIZE, DefaultOp, L1BlockInfo, OpBuilder, OpHaltReason, OpSpecId, OpTransaction, }; use revm::{ @@ -14,17 +13,35 @@ use revm::{ }, context_interface::result::HaltReason, database::{BenchmarkDB, EmptyDB, BENCH_CALLER, BENCH_CALLER_BALANCE, BENCH_TARGET}, + handler::system_call::SYSTEM_ADDRESS, interpreter::{ gas::{calculate_initial_tx_gas, InitialAndFloorGas}, Interpreter, InterpreterTypes, }, - precompile::{bls12_381_const, bls12_381_utils, bn128, secp256r1, u64_to_address}, - primitives::{eip7825, Address, Bytes, Log, TxKind, U256}, + precompile::{bls12_381_const, bls12_381_utils, bn254, secp256r1, u64_to_address}, + primitives::{bytes, eip7825, Address, Bytes, Log, TxKind, U256}, state::Bytecode, - Context, ExecuteEvm, InspectEvm, Inspector, Journal, + Context, ExecuteEvm, InspectEvm, Inspector, Journal, SystemCallEvm, }; +use std::path::PathBuf; use std::vec::Vec; +// Re-export the constant for testdata directory path +const TESTS_TESTDATA: &str = "tests/op_revm_testdata"; + +fn op_revm_testdata_config() -> TestdataConfig { + TestdataConfig { + testdata_dir: PathBuf::from(TESTS_TESTDATA), + } +} + +fn compare_or_save_op_testdata(filename: &str, output: &T) +where + T: serde::Serialize + for<'a> serde::Deserialize<'a> + PartialEq + std::fmt::Debug, +{ + crate::compare_or_save_testdata_with_config(filename, output, op_revm_testdata_config()); +} + #[test] fn test_deposit_tx() { let ctx = Context::op() @@ -49,7 +66,7 @@ fn test_deposit_tx() { .map(|a| a.info.balance), Some(U256::from(100)) ); - compare_or_save_testdata("test_deposit_tx.json", &output); + compare_or_save_op_testdata("test_deposit_tx.json", &output); } #[test] @@ -90,7 +107,7 @@ fn test_halted_deposit_tx() { Some(U256::from(100) + BENCH_CALLER_BALANCE) ); - compare_or_save_testdata("test_halted_deposit_tx.json", &output); + compare_or_save_op_testdata("test_halted_deposit_tx.json", &output); } fn p256verify_test_tx( @@ -134,7 +151,7 @@ fn test_tx_call_p256verify() { // assert successful call to P256VERIFY assert!(output.result.is_success()); - compare_or_save_testdata("test_tx_call_p256verify.json", &output); + compare_or_save_op_testdata("test_tx_call_p256verify.json", &output); } #[test] @@ -179,10 +196,10 @@ fn test_halted_tx_call_p256verify() { } )); - compare_or_save_testdata("test_halted_tx_call_p256verify.json", &output); + compare_or_save_op_testdata("test_halted_tx_call_p256verify.json", &output); } -fn bn128_pair_test_tx( +fn bn254_pair_test_tx( spec: OpSpecId, ) -> Context, CfgEnv, EmptyDB, Journal, L1BlockInfo> { @@ -205,7 +222,7 @@ fn bn128_pair_test_tx( OpTransaction::builder() .base( TxEnv::builder() - .kind(TxKind::Call(bn128::pair::ADDRESS)) + .kind(TxKind::Call(bn254::pair::ADDRESS)) .data(input) .gas_limit(initial_gas), ) @@ -215,8 +232,8 @@ fn bn128_pair_test_tx( } #[test] -fn test_halted_tx_call_bn128_pair_fjord() { - let ctx = bn128_pair_test_tx(OpSpecId::FJORD); +fn test_halted_tx_call_bn254_pair_fjord() { + let ctx = bn254_pair_test_tx(OpSpecId::FJORD); let mut evm = ctx.build_op(); let output = evm.replay().unwrap(); @@ -230,12 +247,12 @@ fn test_halted_tx_call_bn128_pair_fjord() { } )); - compare_or_save_testdata("test_halted_tx_call_bn128_pair_fjord.json", &output); + compare_or_save_op_testdata("test_halted_tx_call_bn254_pair_fjord.json", &output); } #[test] -fn test_halted_tx_call_bn128_pair_granite() { - let ctx = bn128_pair_test_tx(OpSpecId::GRANITE); +fn test_halted_tx_call_bn254_pair_granite() { + let ctx = bn254_pair_test_tx(OpSpecId::GRANITE); let mut evm = ctx.build_op(); let output = evm.replay().unwrap(); @@ -249,7 +266,7 @@ fn test_halted_tx_call_bn128_pair_granite() { } )); - compare_or_save_testdata("test_halted_tx_call_bn128_pair_granite.json", &output); + compare_or_save_op_testdata("test_halted_tx_call_bn254_pair_granite.json", &output); } #[test] @@ -283,7 +300,7 @@ fn test_halted_tx_call_bls12_381_g1_add_out_of_gas() { } )); - compare_or_save_testdata( + compare_or_save_op_testdata( "test_halted_tx_call_bls12_381_g1_add_out_of_gas.json", &output, ); @@ -319,7 +336,7 @@ fn test_halted_tx_call_bls12_381_g1_add_input_wrong_size() { } )); - compare_or_save_testdata( + compare_or_save_op_testdata( "test_halted_tx_call_bls12_381_g1_add_input_wrong_size.json", &output, ); @@ -419,7 +436,7 @@ fn test_halted_tx_call_bls12_381_g1_msm_input_wrong_size() { } )); - compare_or_save_testdata( + compare_or_save_op_testdata( "test_halted_tx_call_bls12_381_g1_msm_input_wrong_size.json", &output, ); @@ -477,7 +494,7 @@ fn test_halted_tx_call_bls12_381_g1_msm_out_of_gas() { } )); - compare_or_save_testdata( + compare_or_save_op_testdata( "test_halted_tx_call_bls12_381_g1_msm_out_of_gas.json", &output, ); @@ -499,7 +516,7 @@ fn test_halted_tx_call_bls12_381_g1_msm_wrong_input_layout() { } )); - compare_or_save_testdata( + compare_or_save_op_testdata( "test_halted_tx_call_bls12_381_g1_msm_wrong_input_layout.json", &output, ); @@ -536,7 +553,7 @@ fn test_halted_tx_call_bls12_381_g2_add_out_of_gas() { } )); - compare_or_save_testdata( + compare_or_save_op_testdata( "test_halted_tx_call_bls12_381_g2_add_out_of_gas.json", &output, ); @@ -573,7 +590,7 @@ fn test_halted_tx_call_bls12_381_g2_add_input_wrong_size() { } )); - compare_or_save_testdata( + compare_or_save_op_testdata( "test_halted_tx_call_bls12_381_g2_add_input_wrong_size.json", &output, ); @@ -673,7 +690,7 @@ fn test_halted_tx_call_bls12_381_g2_msm_input_wrong_size() { } )); - compare_or_save_testdata( + compare_or_save_op_testdata( "test_halted_tx_call_bls12_381_g2_msm_input_wrong_size.json", &output, ); @@ -731,7 +748,7 @@ fn test_halted_tx_call_bls12_381_g2_msm_out_of_gas() { } )); - compare_or_save_testdata( + compare_or_save_op_testdata( "test_halted_tx_call_bls12_381_g2_msm_out_of_gas.json", &output, ); @@ -753,7 +770,7 @@ fn test_halted_tx_call_bls12_381_g2_msm_wrong_input_layout() { } )); - compare_or_save_testdata( + compare_or_save_op_testdata( "test_halted_tx_call_bls12_381_g2_msm_wrong_input_layout.json", &output, ); @@ -848,7 +865,7 @@ fn test_halted_tx_call_bls12_381_pairing_input_wrong_size() { } )); - compare_or_save_testdata( + compare_or_save_op_testdata( "test_halted_tx_call_bls12_381_pairing_input_wrong_size.json", &output, ); @@ -903,7 +920,7 @@ fn test_halted_tx_call_bls12_381_pairing_out_of_gas() { } )); - compare_or_save_testdata( + compare_or_save_op_testdata( "test_halted_tx_call_bls12_381_pairing_out_of_gas.json", &output, ); @@ -925,7 +942,7 @@ fn test_tx_call_bls12_381_pairing_wrong_input_layout() { } )); - compare_or_save_testdata( + compare_or_save_op_testdata( "test_halted_tx_call_bls12_381_pairing_wrong_input_layout.json", &output, ); @@ -978,7 +995,7 @@ fn test_halted_tx_call_bls12_381_map_fp_to_g1_out_of_gas() { } )); - compare_or_save_testdata( + compare_or_save_op_testdata( "test_halted_tx_call_bls12_381_map_fp_to_g1_out_of_gas.json", &output, ); @@ -1031,7 +1048,7 @@ fn test_halted_tx_call_bls12_381_map_fp_to_g1_input_wrong_size() { } )); - compare_or_save_testdata( + compare_or_save_op_testdata( "test_halted_tx_call_bls12_381_map_fp_to_g1_input_wrong_size.json", &output, ); @@ -1084,7 +1101,7 @@ fn test_halted_tx_call_bls12_381_map_fp2_to_g2_out_of_gas() { } )); - compare_or_save_testdata( + compare_or_save_op_testdata( "test_halted_tx_call_bls12_381_map_fp2_to_g2_out_of_gas.json", &output, ); @@ -1137,7 +1154,7 @@ fn test_halted_tx_call_bls12_381_map_fp2_to_g2_input_wrong_size() { } )); - compare_or_save_testdata( + compare_or_save_op_testdata( "test_halted_tx_call_bls12_381_map_fp2_to_g2_input_wrong_size.json", &output, ); @@ -1241,5 +1258,56 @@ fn test_log_inspector() { let inspector = &evm.0.inspector; assert!(!inspector.logs.is_empty()); - compare_or_save_testdata("test_log_inspector.json", &output); + compare_or_save_op_testdata("test_log_inspector.json", &output); +} + +#[test] +fn test_system_call_inspection() { + use revm::InspectSystemCallEvm; + + let ctx = Context::op(); + + let mut evm = ctx.build_op_with_inspector(LogInspector::default()); + + // Test system call inspection + let result = evm + .inspect_one_system_call(BENCH_TARGET, Bytes::default()) + .unwrap(); + + // Should succeed + assert!(result.is_success()); + + // Test system call inspection with caller + let custom_caller = Address::from([0x12; 20]); + let result = evm + .inspect_one_system_call_with_caller(custom_caller, BENCH_TARGET, Bytes::default()) + .unwrap(); + + // Should also succeed + assert!(result.is_success()); + + // Test system call inspection with inspector + let result = evm + .inspect_one_system_call_with_inspector( + BENCH_TARGET, + Bytes::default(), + LogInspector::default(), + ) + .unwrap(); + + // Should succeed + assert!(result.is_success()); +} + +#[test] +fn test_system_call() { + let ctx = Context::op(); + + let mut evm = ctx.build_op(); + + let _ = evm.system_call_one(BENCH_TARGET, bytes!("0x0001")); + let state = evm.finalize(); + + assert!(state.get(&SYSTEM_ADDRESS).is_none()); + assert!(state.get(&BENCH_TARGET).unwrap().is_touched()); } diff --git a/crates/revm/tests/integration.rs b/crates/ee-tests/src/revm_tests.rs similarity index 85% rename from crates/revm/tests/integration.rs rename to crates/ee-tests/src/revm_tests.rs index 4aa41ce0c2..b89459ebfc 100644 --- a/crates/revm/tests/integration.rs +++ b/crates/ee-tests/src/revm_tests.rs @@ -1,19 +1,31 @@ -//! Integration tests for the `op-revm` crate. -mod common; +//! Integration tests for the `revm` crate. -use common::compare_or_save_testdata; -use context::ContextTr; -use database::BENCH_CALLER; -use primitives::{address, b256, hardfork::SpecId, Bytes, TxKind, KECCAK_EMPTY}; +use crate::TestdataConfig; use revm::{ bytecode::opcode, - context::TxEnv, - database::{BenchmarkDB, BENCH_TARGET}, - primitives::U256, - state::Bytecode, + context::{ContextTr, TxEnv}, + database::{BenchmarkDB, BENCH_CALLER, BENCH_TARGET}, + primitives::{address, b256, hardfork::SpecId, Bytes, TxKind, KECCAK_EMPTY, U256}, + state::{AccountStatus, Bytecode}, Context, ExecuteEvm, MainBuilder, MainContext, }; -use state::AccountStatus; +use std::path::PathBuf; + +// Re-export the constant for testdata directory path +const TESTS_TESTDATA: &str = "tests/revm_testdata"; + +fn revm_testdata_config() -> TestdataConfig { + TestdataConfig { + testdata_dir: PathBuf::from(TESTS_TESTDATA), + } +} + +fn compare_or_save_revm_testdata(filename: &str, output: &T) +where + T: serde::Serialize + for<'a> serde::Deserialize<'a> + PartialEq + std::fmt::Debug, +{ + crate::compare_or_save_testdata_with_config(filename, output, revm_testdata_config()); +} const SELFDESTRUCT_BYTECODE: &[u8] = &[ opcode::PUSH2, @@ -60,9 +72,9 @@ fn test_selfdestruct_multi_tx() { let output = evm.finalize(); - compare_or_save_testdata( + compare_or_save_revm_testdata( "test_selfdestruct_multi_tx.json", - (result1, result2, output), + &(result1, result2, output), ); } @@ -70,7 +82,7 @@ fn test_selfdestruct_multi_tx() { /// Verifies that created contracts persist correctly across transactions /// and that their state is properly maintained. #[test] -pub fn test_multi_tx_create() { +fn test_multi_tx_create() { let mut evm = Context::mainnet() .modify_cfg_chained(|cfg| { cfg.spec = SpecId::BERLIN; @@ -171,15 +183,15 @@ pub fn test_multi_tx_create() { ); let output = evm.finalize(); - compare_or_save_testdata( + compare_or_save_revm_testdata( "test_multi_tx_create.json", - (result1, result2, result3, output), + &(result1, result2, result3, output), ); } /// Creates deployment bytecode for a contract. /// Prepends the initialization code that will deploy the provided runtime bytecode. -pub fn deployment_contract(bytes: &[u8]) -> Bytes { +fn deployment_contract(bytes: &[u8]) -> Bytes { assert!(bytes.len() < 256); let len = bytes.len(); let ret = &[ @@ -221,14 +233,13 @@ fn test_frame_stack_index() { .unwrap(); assert_eq!(evm.frame_stack.index(), None); - compare_or_save_testdata("test_frame_stack_index.json", result1); + compare_or_save_revm_testdata("test_frame_stack_index.json", &result1); } #[test] #[cfg(feature = "optional_balance_check")] fn test_disable_balance_check() { - use database::BENCH_CALLER_BALANCE; - + use revm::database::BENCH_CALLER_BALANCE; const RETURN_CALLER_BALANCE_BYTECODE: &[u8] = &[ opcode::CALLER, opcode::BALANCE, diff --git a/crates/op-revm/tests/testdata/test_deposit_tx.json b/crates/ee-tests/tests/op_revm_testdata/test_deposit_tx.json similarity index 65% rename from crates/op-revm/tests/testdata/test_deposit_tx.json rename to crates/ee-tests/tests/op_revm_testdata/test_deposit_tx.json index c187d50833..ce989e10db 100644 --- a/crates/op-revm/tests/testdata/test_deposit_tx.json +++ b/crates/ee-tests/tests/op_revm_testdata/test_deposit_tx.json @@ -1,40 +1,40 @@ { "result": { "Success": { - "reason": "Stop", - "gas_used": 21000, "gas_refunded": 0, + "gas_used": 21000, "logs": [], "output": { "Call": "0x" - } + }, + "reason": "Stop" } }, "state": { "0x0000000000000000000000000000000000000000": { "info": { "balance": "0x64", - "nonce": 1, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 1 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 } } } \ No newline at end of file diff --git a/crates/op-revm/tests/testdata/test_halted_deposit_tx.json b/crates/ee-tests/tests/op_revm_testdata/test_halted_deposit_tx.json similarity index 62% rename from crates/op-revm/tests/testdata/test_halted_deposit_tx.json rename to crates/ee-tests/tests/op_revm_testdata/test_halted_deposit_tx.json index 8aac2ceb88..0769dd9c2f 100644 --- a/crates/op-revm/tests/testdata/test_halted_deposit_tx.json +++ b/crates/ee-tests/tests/op_revm_testdata/test_halted_deposit_tx.json @@ -1,62 +1,62 @@ { "result": { "Halt": { - "reason": "FailedDeposit", - "gas_used": 16777216 + "gas_used": 16777216, + "reason": "FailedDeposit" } }, "state": { "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee": { "info": { "balance": "0x2386f26fc10064", - "nonce": 1, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 1 }, - "transaction_id": 0, + "status": "Touched", "storage": {}, - "status": "Touched" + "transaction_id": 0 }, "0xffffffffffffffffffffffffffffffffffffffff": { "info": { "balance": "0x2386f26fc10000", - "nonce": 1, - "code_hash": "0x7b2ab94bb7d45041581aa3757ae020084674ccad6f75dc3750eb2ea8a92c4e9a", "code": { "LegacyAnalyzed": { "bytecode": "0x5000", - "original_len": 1, "jump_table": { - "order": "bitvec::order::Lsb0", - "head": { - "width": 8, - "index": 0 - }, "bits": 1, "data": [ 0 - ] - } + ], + "head": { + "index": 0, + "width": 8 + }, + "order": "bitvec::order::Lsb0" + }, + "original_len": 1 } - } + }, + "code_hash": "0x7b2ab94bb7d45041581aa3757ae020084674ccad6f75dc3750eb2ea8a92c4e9a", + "nonce": 1 }, - "transaction_id": 0, + "status": "Cold", "storage": {}, - "status": "Cold" + "transaction_id": 0 } } } \ No newline at end of file diff --git a/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g1_add_input_wrong_size.json b/crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_g1_add_input_wrong_size.json similarity index 60% rename from crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g1_add_input_wrong_size.json rename to crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_g1_add_input_wrong_size.json index 5b5fc6861b..91cea8ca54 100644 --- a/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g1_add_input_wrong_size.json +++ b/crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_g1_add_input_wrong_size.json @@ -1,137 +1,137 @@ { "result": { "Halt": { + "gas_used": 21375, "reason": { "Base": "PrecompileError" - }, - "gas_used": 21375 + } } }, "state": { - "0x420000000000000000000000000000000000001a": { + "0x0000000000000000000000000000000000000000": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 1 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x420000000000000000000000000000000000001b": { + "0x000000000000000000000000000000000000000b": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, "0x4200000000000000000000000000000000000019": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x000000000000000000000000000000000000000b": { + "0x420000000000000000000000000000000000001a": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "LoadedAsNotExisting" + "transaction_id": 0 }, - "0x0000000000000000000000000000000000000000": { + "0x420000000000000000000000000000000000001b": { "info": { "balance": "0x0", - "nonce": 1, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 } } } \ No newline at end of file diff --git a/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g1_add_out_of_gas.json b/crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_g1_add_out_of_gas.json similarity index 60% rename from crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g1_add_out_of_gas.json rename to crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_g1_add_out_of_gas.json index 5690b09303..4d1f78ca80 100644 --- a/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g1_add_out_of_gas.json +++ b/crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_g1_add_out_of_gas.json @@ -1,139 +1,139 @@ { "result": { "Halt": { + "gas_used": 21374, "reason": { "Base": { "OutOfGas": "Precompile" } - }, - "gas_used": 21374 + } } }, "state": { "0x0000000000000000000000000000000000000000": { "info": { "balance": "0x0", - "nonce": 1, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 1 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, "0x000000000000000000000000000000000000000b": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "LoadedAsNotExisting", "storage": {}, - "status": "LoadedAsNotExisting" + "transaction_id": 0 }, - "0x420000000000000000000000000000000000001b": { + "0x4200000000000000000000000000000000000019": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, "0x420000000000000000000000000000000000001a": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x4200000000000000000000000000000000000019": { + "0x420000000000000000000000000000000000001b": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 } } } \ No newline at end of file diff --git a/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g1_msm_input_wrong_size.json b/crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_g1_msm_input_wrong_size.json similarity index 60% rename from crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g1_msm_input_wrong_size.json rename to crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_g1_msm_input_wrong_size.json index 109343782b..5fdee80453 100644 --- a/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g1_msm_input_wrong_size.json +++ b/crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_g1_msm_input_wrong_size.json @@ -1,137 +1,137 @@ { "result": { "Halt": { + "gas_used": 35560, "reason": { "Base": "PrecompileError" - }, - "gas_used": 35560 + } } }, "state": { - "0x420000000000000000000000000000000000001a": { + "0x0000000000000000000000000000000000000000": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 1 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, "0x000000000000000000000000000000000000000c": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "LoadedAsNotExisting", "storage": {}, - "status": "LoadedAsNotExisting" + "transaction_id": 0 }, "0x4200000000000000000000000000000000000019": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x420000000000000000000000000000000000001b": { + "0x420000000000000000000000000000000000001a": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x0000000000000000000000000000000000000000": { + "0x420000000000000000000000000000000000001b": { "info": { "balance": "0x0", - "nonce": 1, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 } } } \ No newline at end of file diff --git a/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g1_msm_out_of_gas.json b/crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_g1_msm_out_of_gas.json similarity index 60% rename from crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g1_msm_out_of_gas.json rename to crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_g1_msm_out_of_gas.json index 38d133784c..d2a41cfed6 100644 --- a/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g1_msm_out_of_gas.json +++ b/crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_g1_msm_out_of_gas.json @@ -1,139 +1,139 @@ { "result": { "Halt": { + "gas_used": 35559, "reason": { "Base": { "OutOfGas": "Precompile" } - }, - "gas_used": 35559 + } } }, "state": { - "0x420000000000000000000000000000000000001a": { + "0x0000000000000000000000000000000000000000": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 1 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x420000000000000000000000000000000000001b": { + "0x000000000000000000000000000000000000000c": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, "0x4200000000000000000000000000000000000019": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x000000000000000000000000000000000000000c": { + "0x420000000000000000000000000000000000001a": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "LoadedAsNotExisting" + "transaction_id": 0 }, - "0x0000000000000000000000000000000000000000": { + "0x420000000000000000000000000000000000001b": { "info": { "balance": "0x0", - "nonce": 1, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 } } } \ No newline at end of file diff --git a/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g1_msm_wrong_input_layout.json b/crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_g1_msm_wrong_input_layout.json similarity index 60% rename from crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g1_msm_wrong_input_layout.json rename to crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_g1_msm_wrong_input_layout.json index 83fd20ba23..5fdee80453 100644 --- a/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g1_msm_wrong_input_layout.json +++ b/crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_g1_msm_wrong_input_layout.json @@ -1,137 +1,137 @@ { "result": { "Halt": { + "gas_used": 35560, "reason": { "Base": "PrecompileError" - }, - "gas_used": 35560 + } } }, "state": { - "0x4200000000000000000000000000000000000019": { + "0x0000000000000000000000000000000000000000": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 1 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, "0x000000000000000000000000000000000000000c": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "LoadedAsNotExisting", "storage": {}, - "status": "LoadedAsNotExisting" + "transaction_id": 0 }, - "0x0000000000000000000000000000000000000000": { + "0x4200000000000000000000000000000000000019": { "info": { "balance": "0x0", - "nonce": 1, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x420000000000000000000000000000000000001b": { + "0x420000000000000000000000000000000000001a": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x420000000000000000000000000000000000001a": { + "0x420000000000000000000000000000000000001b": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 } } } \ No newline at end of file diff --git a/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g2_add_input_wrong_size.json b/crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_g2_add_input_wrong_size.json similarity index 60% rename from crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g2_add_input_wrong_size.json rename to crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_g2_add_input_wrong_size.json index 9b58339aba..b2970ea9cb 100644 --- a/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g2_add_input_wrong_size.json +++ b/crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_g2_add_input_wrong_size.json @@ -1,137 +1,137 @@ { "result": { "Halt": { + "gas_used": 21600, "reason": { "Base": "PrecompileError" - }, - "gas_used": 21600 + } } }, "state": { - "0x420000000000000000000000000000000000001b": { + "0x0000000000000000000000000000000000000000": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 1 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, "0x000000000000000000000000000000000000000d": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "LoadedAsNotExisting", "storage": {}, - "status": "LoadedAsNotExisting" + "transaction_id": 0 }, - "0x420000000000000000000000000000000000001a": { + "0x4200000000000000000000000000000000000019": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x0000000000000000000000000000000000000000": { + "0x420000000000000000000000000000000000001a": { "info": { "balance": "0x0", - "nonce": 1, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x4200000000000000000000000000000000000019": { + "0x420000000000000000000000000000000000001b": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 } } } \ No newline at end of file diff --git a/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g2_add_out_of_gas.json b/crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_g2_add_out_of_gas.json similarity index 60% rename from crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g2_add_out_of_gas.json rename to crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_g2_add_out_of_gas.json index 31d7f31de0..c050e75ec1 100644 --- a/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g2_add_out_of_gas.json +++ b/crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_g2_add_out_of_gas.json @@ -1,139 +1,139 @@ { "result": { "Halt": { + "gas_used": 21599, "reason": { "Base": { "OutOfGas": "Precompile" } - }, - "gas_used": 21599 + } } }, "state": { - "0x420000000000000000000000000000000000001a": { + "0x0000000000000000000000000000000000000000": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 1 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x420000000000000000000000000000000000001b": { + "0x000000000000000000000000000000000000000d": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x000000000000000000000000000000000000000d": { + "0x4200000000000000000000000000000000000019": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "LoadedAsNotExisting" + "transaction_id": 0 }, - "0x4200000000000000000000000000000000000019": { + "0x420000000000000000000000000000000000001a": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x0000000000000000000000000000000000000000": { + "0x420000000000000000000000000000000000001b": { "info": { "balance": "0x0", - "nonce": 1, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 } } } \ No newline at end of file diff --git a/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g2_msm_input_wrong_size.json b/crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_g2_msm_input_wrong_size.json similarity index 60% rename from crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g2_msm_input_wrong_size.json rename to crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_g2_msm_input_wrong_size.json index d22cb09181..4ef0718ec2 100644 --- a/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g2_msm_input_wrong_size.json +++ b/crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_g2_msm_input_wrong_size.json @@ -1,137 +1,137 @@ { "result": { "Halt": { + "gas_used": 48108, "reason": { "Base": "PrecompileError" - }, - "gas_used": 48108 + } } }, "state": { "0x0000000000000000000000000000000000000000": { "info": { "balance": "0x0", - "nonce": 1, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 1 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x420000000000000000000000000000000000001b": { + "0x000000000000000000000000000000000000000e": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, "0x4200000000000000000000000000000000000019": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, "0x420000000000000000000000000000000000001a": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x000000000000000000000000000000000000000e": { + "0x420000000000000000000000000000000000001b": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "LoadedAsNotExisting" + "transaction_id": 0 } } } \ No newline at end of file diff --git a/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g2_msm_out_of_gas.json b/crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_g2_msm_out_of_gas.json similarity index 60% rename from crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g2_msm_out_of_gas.json rename to crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_g2_msm_out_of_gas.json index 60ab39f58c..59b81d7b5e 100644 --- a/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g2_msm_out_of_gas.json +++ b/crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_g2_msm_out_of_gas.json @@ -1,139 +1,139 @@ { "result": { "Halt": { + "gas_used": 48107, "reason": { "Base": { "OutOfGas": "Precompile" } - }, - "gas_used": 48107 + } } }, "state": { - "0x4200000000000000000000000000000000000019": { + "0x0000000000000000000000000000000000000000": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 1 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x420000000000000000000000000000000000001b": { + "0x000000000000000000000000000000000000000e": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x420000000000000000000000000000000000001a": { + "0x4200000000000000000000000000000000000019": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x000000000000000000000000000000000000000e": { + "0x420000000000000000000000000000000000001a": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "LoadedAsNotExisting" + "transaction_id": 0 }, - "0x0000000000000000000000000000000000000000": { + "0x420000000000000000000000000000000000001b": { "info": { "balance": "0x0", - "nonce": 1, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 } } } \ No newline at end of file diff --git a/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g2_msm_wrong_input_layout.json b/crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_g2_msm_wrong_input_layout.json similarity index 60% rename from crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g2_msm_wrong_input_layout.json rename to crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_g2_msm_wrong_input_layout.json index 48c1006554..4ef0718ec2 100644 --- a/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_g2_msm_wrong_input_layout.json +++ b/crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_g2_msm_wrong_input_layout.json @@ -1,137 +1,137 @@ { "result": { "Halt": { + "gas_used": 48108, "reason": { "Base": "PrecompileError" - }, - "gas_used": 48108 + } } }, "state": { - "0x000000000000000000000000000000000000000e": { + "0x0000000000000000000000000000000000000000": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 1 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "LoadedAsNotExisting" + "transaction_id": 0 }, - "0x420000000000000000000000000000000000001a": { + "0x000000000000000000000000000000000000000e": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x0000000000000000000000000000000000000000": { + "0x4200000000000000000000000000000000000019": { "info": { "balance": "0x0", - "nonce": 1, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x4200000000000000000000000000000000000019": { + "0x420000000000000000000000000000000000001a": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, "0x420000000000000000000000000000000000001b": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 } } } \ No newline at end of file diff --git a/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_map_fp2_to_g2_input_wrong_size.json b/crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_map_fp2_to_g2_input_wrong_size.json similarity index 60% rename from crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_map_fp2_to_g2_input_wrong_size.json rename to crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_map_fp2_to_g2_input_wrong_size.json index 3e00f925e8..311e0b6a77 100644 --- a/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_map_fp2_to_g2_input_wrong_size.json +++ b/crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_map_fp2_to_g2_input_wrong_size.json @@ -1,137 +1,137 @@ { "result": { "Halt": { + "gas_used": 46848, "reason": { "Base": "PrecompileError" - }, - "gas_used": 46848 + } } }, "state": { "0x0000000000000000000000000000000000000000": { "info": { "balance": "0x0", - "nonce": 1, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 1 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x420000000000000000000000000000000000001b": { + "0x0000000000000000000000000000000000000011": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, "0x4200000000000000000000000000000000000019": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x0000000000000000000000000000000000000011": { + "0x420000000000000000000000000000000000001a": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "LoadedAsNotExisting" + "transaction_id": 0 }, - "0x420000000000000000000000000000000000001a": { + "0x420000000000000000000000000000000000001b": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 } } } \ No newline at end of file diff --git a/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_map_fp2_to_g2_out_of_gas.json b/crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_map_fp2_to_g2_out_of_gas.json similarity index 60% rename from crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_map_fp2_to_g2_out_of_gas.json rename to crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_map_fp2_to_g2_out_of_gas.json index 9152806db6..4e12839026 100644 --- a/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_map_fp2_to_g2_out_of_gas.json +++ b/crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_map_fp2_to_g2_out_of_gas.json @@ -1,139 +1,139 @@ { "result": { "Halt": { + "gas_used": 46847, "reason": { "Base": { "OutOfGas": "Precompile" } - }, - "gas_used": 46847 + } } }, "state": { "0x0000000000000000000000000000000000000000": { "info": { "balance": "0x0", - "nonce": 1, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 1 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x420000000000000000000000000000000000001a": { + "0x0000000000000000000000000000000000000011": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x0000000000000000000000000000000000000011": { + "0x4200000000000000000000000000000000000019": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "LoadedAsNotExisting" + "transaction_id": 0 }, - "0x4200000000000000000000000000000000000019": { + "0x420000000000000000000000000000000000001a": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, "0x420000000000000000000000000000000000001b": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 } } } \ No newline at end of file diff --git a/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_map_fp_to_g1_input_wrong_size.json b/crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_map_fp_to_g1_input_wrong_size.json similarity index 60% rename from crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_map_fp_to_g1_input_wrong_size.json rename to crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_map_fp_to_g1_input_wrong_size.json index db93c13ab6..1b768b6653 100644 --- a/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_map_fp_to_g1_input_wrong_size.json +++ b/crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_map_fp_to_g1_input_wrong_size.json @@ -1,137 +1,137 @@ { "result": { "Halt": { + "gas_used": 27524, "reason": { "Base": "PrecompileError" - }, - "gas_used": 27524 + } } }, "state": { - "0x420000000000000000000000000000000000001b": { + "0x0000000000000000000000000000000000000000": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 1 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x0000000000000000000000000000000000000000": { + "0x0000000000000000000000000000000000000010": { "info": { "balance": "0x0", - "nonce": 1, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x0000000000000000000000000000000000000010": { + "0x4200000000000000000000000000000000000019": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "LoadedAsNotExisting" + "transaction_id": 0 }, "0x420000000000000000000000000000000000001a": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x4200000000000000000000000000000000000019": { + "0x420000000000000000000000000000000000001b": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 } } } \ No newline at end of file diff --git a/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_map_fp_to_g1_out_of_gas.json b/crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_map_fp_to_g1_out_of_gas.json similarity index 60% rename from crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_map_fp_to_g1_out_of_gas.json rename to crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_map_fp_to_g1_out_of_gas.json index 11a64278d3..cc66059ecf 100644 --- a/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_map_fp_to_g1_out_of_gas.json +++ b/crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_map_fp_to_g1_out_of_gas.json @@ -1,139 +1,139 @@ { "result": { "Halt": { + "gas_used": 27523, "reason": { "Base": { "OutOfGas": "Precompile" } - }, - "gas_used": 27523 + } } }, "state": { "0x0000000000000000000000000000000000000000": { "info": { "balance": "0x0", - "nonce": 1, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 1 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x4200000000000000000000000000000000000019": { + "0x0000000000000000000000000000000000000010": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x420000000000000000000000000000000000001b": { + "0x4200000000000000000000000000000000000019": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, "0x420000000000000000000000000000000000001a": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x0000000000000000000000000000000000000010": { + "0x420000000000000000000000000000000000001b": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "LoadedAsNotExisting" + "transaction_id": 0 } } } \ No newline at end of file diff --git a/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_pairing_input_wrong_size.json b/crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_pairing_input_wrong_size.json similarity index 60% rename from crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_pairing_input_wrong_size.json rename to crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_pairing_input_wrong_size.json index 001577b3a3..b650e8b8f1 100644 --- a/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_pairing_input_wrong_size.json +++ b/crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_pairing_input_wrong_size.json @@ -1,137 +1,137 @@ { "result": { "Halt": { + "gas_used": 97444, "reason": { "Base": "PrecompileError" - }, - "gas_used": 97444 + } } }, "state": { "0x0000000000000000000000000000000000000000": { "info": { "balance": "0x0", - "nonce": 1, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 1 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, "0x000000000000000000000000000000000000000f": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "LoadedAsNotExisting", "storage": {}, - "status": "LoadedAsNotExisting" + "transaction_id": 0 }, - "0x420000000000000000000000000000000000001a": { + "0x4200000000000000000000000000000000000019": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x420000000000000000000000000000000000001b": { + "0x420000000000000000000000000000000000001a": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x4200000000000000000000000000000000000019": { + "0x420000000000000000000000000000000000001b": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 } } } \ No newline at end of file diff --git a/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_pairing_out_of_gas.json b/crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_pairing_out_of_gas.json similarity index 60% rename from crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_pairing_out_of_gas.json rename to crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_pairing_out_of_gas.json index 628f248bd2..e3ecc1304f 100644 --- a/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_pairing_out_of_gas.json +++ b/crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_pairing_out_of_gas.json @@ -1,139 +1,139 @@ { "result": { "Halt": { + "gas_used": 97443, "reason": { "Base": { "OutOfGas": "Precompile" } - }, - "gas_used": 97443 + } } }, "state": { - "0x420000000000000000000000000000000000001b": { + "0x0000000000000000000000000000000000000000": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 1 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, "0x000000000000000000000000000000000000000f": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "LoadedAsNotExisting", "storage": {}, - "status": "LoadedAsNotExisting" + "transaction_id": 0 }, "0x4200000000000000000000000000000000000019": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x0000000000000000000000000000000000000000": { + "0x420000000000000000000000000000000000001a": { "info": { "balance": "0x0", - "nonce": 1, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x420000000000000000000000000000000000001a": { + "0x420000000000000000000000000000000000001b": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 } } } \ No newline at end of file diff --git a/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_pairing_wrong_input_layout.json b/crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_pairing_wrong_input_layout.json similarity index 60% rename from crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_pairing_wrong_input_layout.json rename to crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_pairing_wrong_input_layout.json index a7245cc245..b650e8b8f1 100644 --- a/crates/op-revm/tests/testdata/test_halted_tx_call_bls12_381_pairing_wrong_input_layout.json +++ b/crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_pairing_wrong_input_layout.json @@ -1,137 +1,137 @@ { "result": { "Halt": { + "gas_used": 97444, "reason": { "Base": "PrecompileError" - }, - "gas_used": 97444 + } } }, "state": { - "0x4200000000000000000000000000000000000019": { + "0x0000000000000000000000000000000000000000": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 1 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x420000000000000000000000000000000000001a": { + "0x000000000000000000000000000000000000000f": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x420000000000000000000000000000000000001b": { + "0x4200000000000000000000000000000000000019": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x0000000000000000000000000000000000000000": { + "0x420000000000000000000000000000000000001a": { "info": { "balance": "0x0", - "nonce": 1, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x000000000000000000000000000000000000000f": { + "0x420000000000000000000000000000000000001b": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "LoadedAsNotExisting" + "transaction_id": 0 } } } \ No newline at end of file diff --git a/crates/op-revm/tests/testdata/test_halted_tx_call_bn128_pair_fjord.json b/crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bn254_pair_fjord.json similarity index 60% rename from crates/op-revm/tests/testdata/test_halted_tx_call_bn128_pair_fjord.json rename to crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bn254_pair_fjord.json index eae5c631fa..4f98b9d9ad 100644 --- a/crates/op-revm/tests/testdata/test_halted_tx_call_bn128_pair_fjord.json +++ b/crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bn254_pair_fjord.json @@ -1,139 +1,139 @@ { "result": { "Halt": { + "gas_used": 1824024, "reason": { "Base": { "OutOfGas": "Precompile" } - }, - "gas_used": 1824024 + } } }, "state": { - "0x4200000000000000000000000000000000000019": { + "0x0000000000000000000000000000000000000000": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 1 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x420000000000000000000000000000000000001b": { + "0x0000000000000000000000000000000000000008": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x0000000000000000000000000000000000000000": { + "0x4200000000000000000000000000000000000019": { "info": { "balance": "0x0", - "nonce": 1, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x0000000000000000000000000000000000000008": { + "0x420000000000000000000000000000000000001a": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "LoadedAsNotExisting" + "transaction_id": 0 }, - "0x420000000000000000000000000000000000001a": { + "0x420000000000000000000000000000000000001b": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 } } } \ No newline at end of file diff --git a/crates/op-revm/tests/testdata/test_halted_tx_call_bn128_pair_granite.json b/crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bn254_pair_granite.json similarity index 60% rename from crates/op-revm/tests/testdata/test_halted_tx_call_bn128_pair_granite.json rename to crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bn254_pair_granite.json index ce92b11014..85591e9afa 100644 --- a/crates/op-revm/tests/testdata/test_halted_tx_call_bn128_pair_granite.json +++ b/crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bn254_pair_granite.json @@ -1,137 +1,137 @@ { "result": { "Halt": { + "gas_used": 1824024, "reason": { "Base": "PrecompileError" - }, - "gas_used": 1824024 + } } }, "state": { - "0x4200000000000000000000000000000000000019": { + "0x0000000000000000000000000000000000000000": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 1 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x420000000000000000000000000000000000001b": { + "0x0000000000000000000000000000000000000008": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x420000000000000000000000000000000000001a": { + "0x4200000000000000000000000000000000000019": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x0000000000000000000000000000000000000000": { + "0x420000000000000000000000000000000000001a": { "info": { "balance": "0x0", - "nonce": 1, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x0000000000000000000000000000000000000008": { + "0x420000000000000000000000000000000000001b": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "LoadedAsNotExisting" + "transaction_id": 0 } } } \ No newline at end of file diff --git a/crates/op-revm/tests/testdata/test_halted_tx_call_p256verify.json b/crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_p256verify.json similarity index 60% rename from crates/op-revm/tests/testdata/test_halted_tx_call_p256verify.json rename to crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_p256verify.json index 98a205f483..a21e7ce5e3 100644 --- a/crates/op-revm/tests/testdata/test_halted_tx_call_p256verify.json +++ b/crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_p256verify.json @@ -1,139 +1,139 @@ { "result": { "Halt": { + "gas_used": 24449, "reason": { "Base": { "OutOfGas": "Precompile" } - }, - "gas_used": 24449 + } } }, "state": { "0x0000000000000000000000000000000000000000": { "info": { "balance": "0x0", - "nonce": 1, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 1 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, "0x0000000000000000000000000000000000000100": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "LoadedAsNotExisting", "storage": {}, - "status": "LoadedAsNotExisting" + "transaction_id": 0 }, - "0x420000000000000000000000000000000000001b": { + "0x4200000000000000000000000000000000000019": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x4200000000000000000000000000000000000019": { + "0x420000000000000000000000000000000000001a": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x420000000000000000000000000000000000001a": { + "0x420000000000000000000000000000000000001b": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 } } } \ No newline at end of file diff --git a/crates/op-revm/tests/testdata/test_log_inspector.json b/crates/ee-tests/tests/op_revm_testdata/test_log_inspector.json similarity index 62% rename from crates/op-revm/tests/testdata/test_log_inspector.json rename to crates/ee-tests/tests/op_revm_testdata/test_log_inspector.json index 04fbaf3a18..145505a365 100644 --- a/crates/op-revm/tests/testdata/test_log_inspector.json +++ b/crates/ee-tests/tests/op_revm_testdata/test_log_inspector.json @@ -1,173 +1,173 @@ { "result": { "Success": { - "reason": "Stop", - "gas_used": 21381, "gas_refunded": 0, + "gas_used": 21381, "logs": [ { "address": "0xffffffffffffffffffffffffffffffffffffffff", - "topics": [], - "data": "0x" + "data": "0x", + "topics": [] } ], "output": { "Call": "0x" - } + }, + "reason": "Stop" } }, "state": { - "0xffffffffffffffffffffffffffffffffffffffff": { + "0x0000000000000000000000000000000000000000": { "info": { - "balance": "0x2386f26fc10000", - "nonce": 1, - "code_hash": "0x8013c386d5a03c3fa0a6ccbfefcf7d91471dedba2bb94eefef57f916e5929a8d", + "balance": "0x0", "code": { "LegacyAnalyzed": { - "bytecode": "0x600080a000", - "original_len": 5, + "bytecode": "0x00", "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 5, - "data": [ - 0 - ] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched" + "transaction_id": 0 }, - "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee": { + "0x4200000000000000000000000000000000000019": { "info": { - "balance": "0x2386f26fc10000", - "nonce": 1, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "balance": "0x0", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched" + "transaction_id": 0 }, - "0x0000000000000000000000000000000000000000": { + "0x420000000000000000000000000000000000001a": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x420000000000000000000000000000000000001a": { + "0x420000000000000000000000000000000000001b": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x420000000000000000000000000000000000001b": { + "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee": { "info": { - "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "balance": "0x2386f26fc10000", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 1 }, - "transaction_id": 0, + "status": "Touched", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x4200000000000000000000000000000000000019": { + "0xffffffffffffffffffffffffffffffffffffffff": { "info": { - "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "balance": "0x2386f26fc10000", "code": { "LegacyAnalyzed": { - "bytecode": "0x00", - "original_len": 0, + "bytecode": "0x600080a000", "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 5, + "data": [ + 0 + ], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 5 } - } + }, + "code_hash": "0x8013c386d5a03c3fa0a6ccbfefcf7d91471dedba2bb94eefef57f916e5929a8d", + "nonce": 1 }, - "transaction_id": 0, + "status": "Touched", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 } } } \ No newline at end of file diff --git a/crates/ee-tests/tests/op_revm_testdata/test_system_call.json b/crates/ee-tests/tests/op_revm_testdata/test_system_call.json new file mode 100644 index 0000000000..eb8f4e1a10 --- /dev/null +++ b/crates/ee-tests/tests/op_revm_testdata/test_system_call.json @@ -0,0 +1,165 @@ +{ + "result": { + "Success": { + "gas_refunded": 0, + "gas_used": 21020, + "logs": [], + "output": { + "Call": "0x" + }, + "reason": "Stop" + } + }, + "state": { + "0x0000000000000000000000000000000000000000": { + "info": { + "balance": "0x0", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "jump_table": { + "bits": 0, + "data": [], + "head": { + "index": 0, + "width": 8 + }, + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 + } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 + }, + "status": "Touched | LoadedAsNotExisting", + "storage": {}, + "transaction_id": 1 + }, + "0x4200000000000000000000000000000000000019": { + "info": { + "balance": "0x0", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "jump_table": { + "bits": 0, + "data": [], + "head": { + "index": 0, + "width": 8 + }, + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 + } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 + }, + "status": "Touched | LoadedAsNotExisting", + "storage": {}, + "transaction_id": 1 + }, + "0x420000000000000000000000000000000000001a": { + "info": { + "balance": "0x0", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "jump_table": { + "bits": 0, + "data": [], + "head": { + "index": 0, + "width": 8 + }, + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 + } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 + }, + "status": "Touched | LoadedAsNotExisting", + "storage": {}, + "transaction_id": 1 + }, + "0x420000000000000000000000000000000000001b": { + "info": { + "balance": "0x0", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "jump_table": { + "bits": 0, + "data": [], + "head": { + "index": 0, + "width": 8 + }, + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 + } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 + }, + "status": "Touched | LoadedAsNotExisting", + "storage": {}, + "transaction_id": 1 + }, + "0xfffffffffffffffffffffffffffffffffffffffe": { + "info": { + "balance": "0x0", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "jump_table": { + "bits": 0, + "data": [], + "head": { + "index": 0, + "width": 8 + }, + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 + } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 1 + }, + "status": "Touched | LoadedAsNotExisting", + "storage": {}, + "transaction_id": 1 + }, + "0xffffffffffffffffffffffffffffffffffffffff": { + "info": { + "balance": "0x0", + "code": { + "LegacyAnalyzed": { + "bytecode": "0x00", + "jump_table": { + "bits": 0, + "data": [], + "head": { + "index": 0, + "width": 8 + }, + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 + } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 + }, + "status": "Touched | LoadedAsNotExisting", + "storage": {}, + "transaction_id": 1 + } + } +} \ No newline at end of file diff --git a/crates/op-revm/tests/testdata/test_tx_call_p256verify.json b/crates/ee-tests/tests/op_revm_testdata/test_tx_call_p256verify.json similarity index 60% rename from crates/op-revm/tests/testdata/test_tx_call_p256verify.json rename to crates/ee-tests/tests/op_revm_testdata/test_tx_call_p256verify.json index edca703816..87cdf23853 100644 --- a/crates/op-revm/tests/testdata/test_tx_call_p256verify.json +++ b/crates/ee-tests/tests/op_revm_testdata/test_tx_call_p256verify.json @@ -1,140 +1,140 @@ { "result": { "Success": { - "reason": "Return", - "gas_used": 24450, "gas_refunded": 0, + "gas_used": 24450, "logs": [], "output": { "Call": "0x" - } + }, + "reason": "Return" } }, "state": { - "0x420000000000000000000000000000000000001b": { + "0x0000000000000000000000000000000000000000": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 1 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x4200000000000000000000000000000000000019": { + "0x0000000000000000000000000000000000000100": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x420000000000000000000000000000000000001a": { + "0x4200000000000000000000000000000000000019": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x0000000000000000000000000000000000000000": { + "0x420000000000000000000000000000000000001a": { "info": { "balance": "0x0", - "nonce": 1, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 }, - "0x0000000000000000000000000000000000000100": { + "0x420000000000000000000000000000000000001b": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 0 } } } \ No newline at end of file diff --git a/crates/revm/tests/testdata/test_frame_stack_index.json b/crates/ee-tests/tests/revm_testdata/test_frame_stack_index.json similarity index 80% rename from crates/revm/tests/testdata/test_frame_stack_index.json rename to crates/ee-tests/tests/revm_testdata/test_frame_stack_index.json index c5981e4b93..5d69c4ffbb 100644 --- a/crates/revm/tests/testdata/test_frame_stack_index.json +++ b/crates/ee-tests/tests/revm_testdata/test_frame_stack_index.json @@ -1,11 +1,11 @@ { "Success": { - "reason": "Stop", - "gas_used": 21000, "gas_refunded": 0, + "gas_used": 21000, "logs": [], "output": { "Call": "0x" - } + }, + "reason": "Stop" } } \ No newline at end of file diff --git a/crates/revm/tests/testdata/test_multi_tx_create.json b/crates/ee-tests/tests/revm_testdata/test_multi_tx_create.json similarity index 67% rename from crates/revm/tests/testdata/test_multi_tx_create.json rename to crates/ee-tests/tests/revm_testdata/test_multi_tx_create.json index 10d184d7de..60cff1e58f 100644 --- a/crates/revm/tests/testdata/test_multi_tx_create.json +++ b/crates/ee-tests/tests/revm_testdata/test_multi_tx_create.json @@ -1,145 +1,145 @@ [ { "Success": { - "reason": "Return", - "gas_used": 54260, "gas_refunded": 0, + "gas_used": 54260, "logs": [], "output": { "Create": [ "0x61ffffff00", "0x84bcbaa99ae6d1f7f70b37d5f6c27c9631eeb2f2" ] - } + }, + "reason": "Return" } }, { "Success": { - "reason": "SelfDestruct", - "gas_used": 14302, "gas_refunded": 14301, + "gas_used": 14302, "logs": [], "output": { "Call": "0x" - } + }, + "reason": "SelfDestruct" } }, { "Success": { - "reason": "Return", - "gas_used": 54260, "gas_refunded": 0, + "gas_used": 54260, "logs": [], "output": { "Create": [ "0x61ffffff00", "0x84bcbaa99ae6d1f7f70b37d5f6c27c9631eeb2f2" ] - } + }, + "reason": "Return" } }, { "0x0000000000000000000000000000000000000000": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 2, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 2 }, - "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee": { + "0x000000000000000000000000000000000000ffff": { "info": { - "balance": "0x2386f26fc10000", - "nonce": 1, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "balance": "0x0", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 2, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched" + "transaction_id": 1 }, - "0x000000000000000000000000000000000000ffff": { + "0x84bcbaa99ae6d1f7f70b37d5f6c27c9631eeb2f2": { "info": { "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", "code": { "LegacyAnalyzed": { - "bytecode": "0x00", - "original_len": 0, + "bytecode": "0x61ffffff00", "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 5, + "data": [ + 0 + ], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 5 } - } + }, + "code_hash": "0x9125466aa9ef15459d85e7318f6d3bdc5f6978c0565bee37a8e768d7c202a67a", + "nonce": 1 }, - "transaction_id": 1, + "status": "Created | CreatedLocal | SelfDestructed | Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 2 }, - "0x84bcbaa99ae6d1f7f70b37d5f6c27c9631eeb2f2": { + "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee": { "info": { - "balance": "0x0", - "nonce": 1, - "code_hash": "0x9125466aa9ef15459d85e7318f6d3bdc5f6978c0565bee37a8e768d7c202a67a", + "balance": "0x2386f26fc10000", "code": { "LegacyAnalyzed": { - "bytecode": "0x61ffffff00", - "original_len": 5, + "bytecode": "0x00", "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 5, - "data": [ - 0 - ] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 1 }, - "transaction_id": 2, + "status": "Touched", "storage": {}, - "status": "Created | CreatedLocal | SelfDestructed | Touched | LoadedAsNotExisting" + "transaction_id": 2 } } ] \ No newline at end of file diff --git a/crates/revm/tests/testdata/test_selfdestruct_multi_tx.json b/crates/ee-tests/tests/revm_testdata/test_selfdestruct_multi_tx.json similarity index 62% rename from crates/revm/tests/testdata/test_selfdestruct_multi_tx.json rename to crates/ee-tests/tests/revm_testdata/test_selfdestruct_multi_tx.json index 3db1e8eec5..ccc0fe6dd4 100644 --- a/crates/revm/tests/testdata/test_selfdestruct_multi_tx.json +++ b/crates/ee-tests/tests/revm_testdata/test_selfdestruct_multi_tx.json @@ -1,126 +1,126 @@ [ { "Success": { - "reason": "SelfDestruct", - "gas_used": 29603, "gas_refunded": 24000, + "gas_used": 29603, "logs": [], "output": { "Call": "0x" - } + }, + "reason": "SelfDestruct" } }, { "Success": { - "reason": "Stop", - "gas_used": 21000, "gas_refunded": 0, + "gas_used": 21000, "logs": [], "output": { "Call": "0x" - } + }, + "reason": "Stop" } }, { - "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee": { + "0x0000000000000000000000000000000000000000": { "info": { - "balance": "0x2386f26fc10000", - "nonce": 2, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "balance": "0x0", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 1, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "Touched" + "transaction_id": 1 }, - "0xffffffffffffffffffffffffffffffffffffffff": { + "0x000000000000000000000000000000000000ffff": { "info": { - "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "balance": "0x2386f26fc10000", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 1, + "status": "Touched | LoadedAsNotExisting", "storage": {}, - "status": "SelfDestructed | Touched" + "transaction_id": 0 }, - "0x0000000000000000000000000000000000000000": { + "0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee": { "info": { - "balance": "0x0", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "balance": "0x2386f26fc10000", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 2 }, - "transaction_id": 1, + "status": "Touched", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 1 }, - "0x000000000000000000000000000000000000ffff": { + "0xffffffffffffffffffffffffffffffffffffffff": { "info": { - "balance": "0x2386f26fc10000", - "nonce": 0, - "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "balance": "0x0", "code": { "LegacyAnalyzed": { "bytecode": "0x00", - "original_len": 0, "jump_table": { - "order": "bitvec::order::Lsb0", + "bits": 0, + "data": [], "head": { - "width": 8, - "index": 0 + "index": 0, + "width": 8 }, - "bits": 0, - "data": [] - } + "order": "bitvec::order::Lsb0" + }, + "original_len": 0 } - } + }, + "code_hash": "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470", + "nonce": 0 }, - "transaction_id": 0, + "status": "SelfDestructed | Touched", "storage": {}, - "status": "Touched | LoadedAsNotExisting" + "transaction_id": 1 } } ] \ No newline at end of file diff --git a/crates/ee-tests/tests/testdata/test_data.json b/crates/ee-tests/tests/testdata/test_data.json new file mode 100644 index 0000000000..7798031b53 --- /dev/null +++ b/crates/ee-tests/tests/testdata/test_data.json @@ -0,0 +1,4 @@ +{ + "message": "test message", + "value": 42 +} \ No newline at end of file diff --git a/crates/handler/CHANGELOG.md b/crates/handler/CHANGELOG.md index 19ce478016..8cb93f8356 100644 --- a/crates/handler/CHANGELOG.md +++ b/crates/handler/CHANGELOG.md @@ -5,6 +5,50 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] + +## [10.0.0](https://github.com/bluealloy/revm/compare/revm-handler-v9.0.1...revm-handler-v10.0.0) - 2025-08-23 + +### Added + +- *(fusaka)* Add PrecompileId ([#2904](https://github.com/bluealloy/revm/pull/2904)) + +## [9.0.1](https://github.com/bluealloy/revm/compare/revm-handler-v9.0.0...revm-handler-v9.0.1) - 2025-08-12 + +### Other + +- updated the following local packages: revm-primitives, revm-bytecode, revm-state, revm-context-interface, revm-database, revm-precompile, revm-database-interface, revm-context, revm-interpreter + +## [9.0.0](https://github.com/bluealloy/revm/compare/revm-handler-v8.1.0...revm-handler-v9.0.0) - 2025-08-06 + +### Added + +- short address for journal cold/warm check ([#2849](https://github.com/bluealloy/revm/pull/2849)) +- gastable, record static gas in Interpreter loop ([#2822](https://github.com/bluealloy/revm/pull/2822)) +- fix renamed functions for system_call ([#2824](https://github.com/bluealloy/revm/pull/2824)) +- Align naming of SystemCallEvm function to ExecuteEvm ([#2814](https://github.com/bluealloy/revm/pull/2814)) + +### Fixed + +- nonce changed is not reverted in journal if fail due to insufficient balance ([#2805](https://github.com/bluealloy/revm/pull/2805)) + +### Other + +- update README.md ([#2842](https://github.com/bluealloy/revm/pull/2842)) +- rm commented code ([#2839](https://github.com/bluealloy/revm/pull/2839)) +- *(benches)* clean up criterion callsites ([#2833](https://github.com/bluealloy/revm/pull/2833)) +- improve ExtBytecode hash handling ([#2826](https://github.com/bluealloy/revm/pull/2826)) +- fix run-tests.sh ([#2801](https://github.com/bluealloy/revm/pull/2801)) +- reuse global crypto provide idea ([#2786](https://github.com/bluealloy/revm/pull/2786)) +- add rust-version and note about MSRV ([#2789](https://github.com/bluealloy/revm/pull/2789)) +- Add dyn Crypto trait to PrecompileFn ([#2772](https://github.com/bluealloy/revm/pull/2772)) +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + ## [8.1.0](https://github.com/bluealloy/revm/compare/revm-handler-v8.0.3...revm-handler-v8.1.0) - 2025-07-23 diff --git a/crates/handler/Cargo.toml b/crates/handler/Cargo.toml index eb5a2a201f..6cae72e6f1 100644 --- a/crates/handler/Cargo.toml +++ b/crates/handler/Cargo.toml @@ -1,13 +1,14 @@ [package] name = "revm-handler" description = "Revm handler crates" -version = "8.1.0" +version = "10.0.0" authors.workspace = true edition.workspace = true keywords.workspace = true license.workspace = true repository.workspace = true readme.workspace = true +rust-version.workspace = true [package.metadata.docs.rs] all-features = true diff --git a/crates/handler/src/frame.rs b/crates/handler/src/frame.rs index 6fdb853851..8b413365fb 100644 --- a/crates/handler/src/frame.rs +++ b/crates/handler/src/frame.rs @@ -25,7 +25,7 @@ use primitives::{ constants::CALL_STACK_LIMIT, hardfork::SpecId::{self, HOMESTEAD, LONDON, SPURIOUS_DRAGON}, }; -use primitives::{keccak256, Address, Bytes, B256, U256}; +use primitives::{keccak256, Address, Bytes, U256}; use state::Bytecode; use std::borrow::ToOwned; use std::boxed::Box; @@ -309,11 +309,11 @@ impl EthFrame { .nonce_bump_journal_entry(inputs.caller); // Create address - let mut init_code_hash = B256::ZERO; + let mut init_code_hash = None; let created_address = match inputs.scheme { CreateScheme::Create => inputs.caller.create(old_nonce), CreateScheme::Create2 { salt } => { - init_code_hash = keccak256(&inputs.init_code); + let init_code_hash = *init_code_hash.insert(keccak256(&inputs.init_code)); inputs.caller.create2(salt.to_be_bytes(), init_code_hash) } CreateScheme::Custom { address } => address, @@ -333,7 +333,7 @@ impl EthFrame { Err(e) => return return_error(e.into()), }; - let bytecode = ExtBytecode::new_with_hash( + let bytecode = ExtBytecode::new_with_optional_hash( Bytecode::new_legacy(inputs.init_code.clone()), init_code_hash, ); @@ -362,126 +362,6 @@ impl EthFrame { Ok(ItemOrResult::Item(this.consume())) } - /* - /// Make create frame. - #[inline] - pub fn make_eofcreate_frame( - mut this: OutFrame<'_, Self>, - evm: &mut EVM, - depth: usize, - memory: SharedMemory, - inputs: Box, - ) -> Result, ERROR> { - let context = evm.ctx(); - let spec = context.cfg().spec().into(); - let return_error = |e| { - Ok(ItemOrResult::Result(FrameResult::EOFCreate( - CreateOutcome { - result: InterpreterResult { - result: e, - gas: Gas::new(inputs.gas_limit), - output: Bytes::new(), - }, - address: None, - }, - ))) - }; - - let (input, initcode, created_address) = match &inputs.kind { - EOFCreateKind::Opcode { - initcode, - input, - created_address, - } => (input.clone(), initcode.clone(), Some(*created_address)), - EOFCreateKind::Tx { .. } => { - // Decode eof and init code. - // TODO : Handle inc_nonce handling more gracefully. - // let Ok((eof, input)) = Eof::decode_dangling(initdata.clone()) else { - // context.journal_mut().inc_account_nonce(inputs.caller)?; - // return return_error(InstructionResult::InvalidEOFInitCode); - // }; - - // if eof.validate().is_err() { - // // TODO : (EOF) New error type. - // context.journal_mut().inc_account_nonce(inputs.caller)?; - // return return_error(InstructionResult::InvalidEOFInitCode); - // } - - // // Use nonce from tx to calculate address. - // let tx = context.tx(); - // let create_address = tx.caller().create(tx.nonce()); - unreachable!("EOF is disabled"); - //(CallInput::Bytes(input), eof, Some(create_address)) - } - }; - - // Check depth - if depth > CALL_STACK_LIMIT as usize { - return return_error(InstructionResult::CallTooDeep); - } - - // Fetch balance of caller. - let caller = context.journal_mut().load_account(inputs.caller)?.data; - - // Check if caller has enough balance to send to the created contract. - if caller.info.balance < inputs.value { - return return_error(InstructionResult::OutOfFunds); - } - - // Increase nonce of caller and check if it overflows - let Some(new_nonce) = caller.info.nonce.checked_add(1) else { - // Can't happen on mainnet. - return return_error(InstructionResult::Return); - }; - caller.info.nonce = new_nonce; - context - .journal_mut() - .nonce_bump_journal_entry(inputs.caller); - - let old_nonce = new_nonce - 1; - - let created_address = created_address.unwrap_or_else(|| inputs.caller.create(old_nonce)); - - // Load account so it needs to be marked as warm for access list. - context.journal_mut().load_account(created_address)?; - - // Create account, transfer funds and make the journal checkpoint. - let checkpoint = match context.journal_mut().create_account_checkpoint( - inputs.caller, - created_address, - inputs.value, - spec, - ) { - Ok(checkpoint) => checkpoint, - Err(e) => return return_error(e.into()), - }; - - let interpreter_input = InputsImpl { - target_address: created_address, - caller_address: inputs.caller, - bytecode_address: None, - input, - call_value: inputs.value, - }; - - let gas_limit = inputs.gas_limit; - this.get(EthFrame::invalid).clear( - FrameData::EOFCreate(EOFCreateFrame { created_address }), - FrameInput::EOFCreate(inputs), - depth, - memory, - ExtBytecode::new(Bytecode::Eof(initcode)), - interpreter_input, - false, - true, - spec, - gas_limit, - checkpoint, - ); - Ok(ItemOrResult::Item(this.consume())) - } - */ - /// Initializes a frame with the given context and precompiles. pub fn init_with_context< CTX: ContextTr, @@ -728,47 +608,3 @@ pub fn return_create( interpreter_result.result = InstructionResult::Return; } - -/* -pub fn return_eofcreate( - journal: &mut JOURNAL, - checkpoint: JournalCheckpoint, - interpreter_result: &mut InterpreterResult, - address: Address, - max_code_size: usize, -) { - // Note we still execute RETURN opcode and return the bytes. - // In EOF those opcodes should abort execution. - // - // In RETURN gas is still protecting us from ddos and in oog, - // behaviour will be same as if it failed on return. - // - // Bytes of RETURN will drained in `insert_eofcreate_outcome`. - if interpreter_result.result != InstructionResult::ReturnContract { - journal.checkpoint_revert(checkpoint); - return; - } - - if interpreter_result.output.len() > max_code_size { - journal.checkpoint_revert(checkpoint); - interpreter_result.result = InstructionResult::CreateContractSizeLimit; - return; - } - - // Deduct gas for code deployment. - let gas_for_code = interpreter_result.output.len() as u64 * gas::CODEDEPOSIT; - if !interpreter_result.gas.record_cost(gas_for_code) { - journal.checkpoint_revert(checkpoint); - interpreter_result.result = InstructionResult::OutOfGas; - return; - } - - journal.checkpoint_commit(); - - // Decode bytecode has a performance hit, but it has reasonable restrains. - let bytecode = Eof::decode(interpreter_result.output.clone()).expect("Eof is already verified"); - - // Eof bytecode is going to be hashed. - journal.set_code(address, Bytecode::Eof(Arc::new(bytecode))); -} - */ diff --git a/crates/handler/src/instructions.rs b/crates/handler/src/instructions.rs index a7006be15f..b45582f0d4 100644 --- a/crates/handler/src/instructions.rs +++ b/crates/handler/src/instructions.rs @@ -19,12 +19,12 @@ pub trait InstructionProvider { /// Ethereum instruction contains list of mainnet instructions that is used for Interpreter execution. #[derive(Debug)] -pub struct EthInstructions { +pub struct EthInstructions { /// Table containing instruction implementations indexed by opcode. pub instruction_table: Box>, } -impl Clone for EthInstructions +impl Clone for EthInstructions where WIRE: InterpreterTypes, { @@ -45,14 +45,16 @@ where Self::new(instruction_table::()) } - /// Rerurns new `EthInstructions` with custom instruction table. + /// Returns a new instance of `EthInstructions` with custom instruction table. + #[inline] pub fn new(base_table: InstructionTable) -> Self { Self { instruction_table: Box::new(base_table), } } - /// Inserts a new instruction into the instruction table.s + /// Inserts a new instruction into the instruction table. + #[inline] pub fn insert_instruction(&mut self, opcode: u8, instruction: Instruction) { self.instruction_table[opcode as usize] = instruction; } diff --git a/crates/handler/src/pre_execution.rs b/crates/handler/src/pre_execution.rs index c1a9aa3816..0c9bf87b9e 100644 --- a/crates/handler/src/pre_execution.rs +++ b/crates/handler/src/pre_execution.rs @@ -55,16 +55,10 @@ pub fn load_accounts< if tx.tx_type() != TransactionType::Legacy { if let Some(access_list) = tx.access_list() { for item in access_list { - let address = item.address(); - let mut storage = item.storage_slots().peekable(); - if storage.peek().is_none() { - journal.warm_account(*address); - } else { - journal.warm_account_and_storage( - *address, - storage.map(|i| StorageKey::from_be_bytes(i.0)), - )?; - } + journal.warm_account_and_storage( + *item.address(), + item.storage_slots().map(|i| StorageKey::from_be_bytes(i.0)), + )?; } } } @@ -138,12 +132,6 @@ pub fn validate_against_state_and_deduct_caller< is_nonce_check_disabled, )?; - // Bump the nonce for calls. Nonce for CREATE will be bumped in `make_create_frame`. - if tx.kind().is_call() { - // Nonce is already checked - caller_account.info.nonce = caller_account.info.nonce.saturating_add(1); - } - let max_balance_spending = tx.max_balance_spending()?; // Check if account has enough balance for `gas_limit * max_fee`` and value transfer. @@ -178,6 +166,12 @@ pub fn validate_against_state_and_deduct_caller< caller_account.mark_touch(); caller_account.info.balance = new_balance; + // Bump the nonce for calls. Nonce for CREATE will be bumped in `make_create_frame`. + if tx.kind().is_call() { + // Nonce is already checked + caller_account.info.nonce = caller_account.info.nonce.saturating_add(1); + } + journal.caller_accounting_journal_entry(tx.caller(), old_balance, tx.kind().is_call()); Ok(()) } diff --git a/crates/handler/src/precompile_provider.rs b/crates/handler/src/precompile_provider.rs index bf960a1e51..eb75bf6135 100644 --- a/crates/handler/src/precompile_provider.rs +++ b/crates/handler/src/precompile_provider.rs @@ -101,6 +101,7 @@ impl PrecompileProvider for EthPrecompiles { let Some(precompile) = self.precompiles.get(address) else { return Ok(None); }; + let mut result = InterpreterResult { result: InstructionResult::Return, gas: Gas::new(gas_limit), @@ -120,7 +121,7 @@ impl PrecompileProvider for EthPrecompiles { CallInput::Bytes(bytes) => bytes.0.iter().as_slice(), }; - match (*precompile)(input_bytes, gas_limit) { + match precompile.execute(input_bytes, gas_limit) { Ok(output) => { let underflow = result.gas.record_cost(output.gas_used); assert!(underflow, "Gas underflow is not possible"); diff --git a/crates/handler/src/system_call.rs b/crates/handler/src/system_call.rs index 5f27a9fb85..d4ce748ee5 100644 --- a/crates/handler/src/system_call.rs +++ b/crates/handler/src/system_call.rs @@ -2,20 +2,20 @@ //! //! These EIPs require the client to perform special system calls to update state (such as block hashes or beacon roots) at block boundaries, outside of normal EVM transaction execution. REVM provides the system call mechanism, but the actual state transitions must be performed by the client or test harness, not by the EVM itself. //! -//! # Example: Using `transact_system_call` for pre/post block hooks +//! # Example: Using `system_call` for pre/post block hooks //! -//! The client should use [`SystemCallEvm::transact_system_call`] method to perform required state updates before or after block execution, as specified by the EIP: +//! The client should use [`SystemCallEvm::system_call`] method to perform required state updates before or after block execution, as specified by the EIP: //! //! ```rust,ignore //! // Example: update beacon root (EIP-4788) at the start of a block //! let beacon_root: Bytes = ...; // obtained from consensus layer //! let beacon_contract: Address = "0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02".parse().unwrap(); -//! evm.transact_system_call(beacon_contract, beacon_root)?; +//! evm.system_call(beacon_contract, beacon_root)?; //! //! // Example: update block hash (EIP-2935) at the end of a block //! let block_hash: Bytes = ...; // new block hash //! let history_contract: Address = "0x0000F90827F1C53a10cb7A02335B175320002935".parse().unwrap(); -//! evm.transact_system_call(history_contract, block_hash)?; +//! evm.system_call(history_contract, block_hash)?; //! ``` //! //! See the book section on [External State Transitions](../../book/src/external_state_transitions.md) for more details. @@ -72,6 +72,11 @@ impl SystemCallTx for TxEnv { /// beneficiary. They are used before and after block execution to insert or obtain blockchain state. /// /// It act similar to `transact` function and sets default Tx with data and system contract as a target. +/// +/// # Note +/// +/// Only one function needs implementation [`SystemCallEvm::system_call_one_with_caller`], other functions +/// are derived from it. pub trait SystemCallEvm: ExecuteEvm { /// System call is a special transaction call that is used to call a system contract. /// @@ -79,69 +84,137 @@ pub trait SystemCallEvm: ExecuteEvm { /// given values. /// /// Block values are taken into account and will determent how system call will be executed. - fn transact_system_call_with_caller( + fn system_call_one_with_caller( &mut self, caller: Address, system_contract_address: Address, data: Bytes, ) -> Result; - /// Calls [`SystemCallEvm::transact_system_call_with_caller`] with [`SYSTEM_ADDRESS`] as a caller. + /// System call is a special transaction call that is used to call a system contract. + /// + /// Transaction fields are reset and set in [`SystemCallTx`] and data and target are set to + /// given values. + /// + /// Block values are taken into account and will determent how system call will be executed. + fn system_call_one( + &mut self, + system_contract_address: Address, + data: Bytes, + ) -> Result { + self.system_call_one_with_caller(SYSTEM_ADDRESS, system_contract_address, data) + } + + /// Internally calls [`SystemCallEvm::system_call_with_caller`]. + fn system_call( + &mut self, + system_contract_address: Address, + data: Bytes, + ) -> Result, Self::Error> { + self.system_call_with_caller(SYSTEM_ADDRESS, system_contract_address, data) + } + + /// Internally calls [`SystemCallEvm::system_call_one`] and [`ExecuteEvm::finalize`] functions to obtain the changed state. + fn system_call_with_caller( + &mut self, + caller: Address, + system_contract_address: Address, + data: Bytes, + ) -> Result, Self::Error> { + let result = self.system_call_one_with_caller(caller, system_contract_address, data)?; + let state = self.finalize(); + Ok(ExecResultAndState::new(result, state)) + } + + /// System call is a special transaction call that is used to call a system contract. + /// + /// Transaction fields are reset and set in [`SystemCallTx`] and data and target are set to + /// given values. + /// + /// Block values are taken into account and will determent how system call will be executed. + #[deprecated(since = "0.1.0", note = "Use `system_call_one_with_caller` instead")] + fn transact_system_call_with_caller( + &mut self, + caller: Address, + system_contract_address: Address, + data: Bytes, + ) -> Result { + self.system_call_one_with_caller(caller, system_contract_address, data) + } + + /// Calls [`SystemCallEvm::system_call_one`] with [`SYSTEM_ADDRESS`] as a caller. + #[deprecated(since = "0.1.0", note = "Use `system_call_one` instead")] fn transact_system_call( &mut self, system_contract_address: Address, data: Bytes, ) -> Result { - self.transact_system_call_with_caller(SYSTEM_ADDRESS, system_contract_address, data) + self.system_call_one(system_contract_address, data) } /// Transact the system call and finalize. /// /// Internally calls combo of `transact_system_call` and `finalize` functions. + #[deprecated(since = "0.1.0", note = "Use `system_call` instead")] fn transact_system_call_finalize( &mut self, system_contract_address: Address, data: Bytes, ) -> Result, Self::Error> { - self.transact_system_call_with_caller_finalize( - SYSTEM_ADDRESS, - system_contract_address, - data, - ) + self.system_call(system_contract_address, data) } - /// Calls [`SystemCallEvm::transact_system_call_with_caller`] and `finalize` functions. + /// Calls [`SystemCallEvm::system_call_one`] and `finalize` functions. + #[deprecated(since = "0.1.0", note = "Use `system_call_with_caller` instead")] fn transact_system_call_with_caller_finalize( &mut self, caller: Address, system_contract_address: Address, data: Bytes, ) -> Result, Self::Error> { - let result = - self.transact_system_call_with_caller(caller, system_contract_address, data)?; - let state = self.finalize(); - Ok(ExecResultAndState::new(result, state)) + self.system_call_with_caller(caller, system_contract_address, data) } } /// Extension of the [`SystemCallEvm`] trait that adds a method that commits the state after execution. pub trait SystemCallCommitEvm: SystemCallEvm + ExecuteCommitEvm { /// Transact the system call and commit to the state. + fn system_call_commit( + &mut self, + system_contract_address: Address, + data: Bytes, + ) -> Result { + self.system_call_with_caller_commit(SYSTEM_ADDRESS, system_contract_address, data) + } + + /// Transact the system call and commit to the state. + #[deprecated(since = "0.1.0", note = "Use `system_call_commit` instead")] fn transact_system_call_commit( &mut self, system_contract_address: Address, data: Bytes, ) -> Result { - self.transact_system_call_with_caller_commit(SYSTEM_ADDRESS, system_contract_address, data) + self.system_call_commit(system_contract_address, data) } - /// Calls [`SystemCallCommitEvm::transact_system_call_commit`] with [`SYSTEM_ADDRESS`] as a caller. - fn transact_system_call_with_caller_commit( + /// Calls [`SystemCallCommitEvm::system_call_commit`] with a custom caller. + fn system_call_with_caller_commit( &mut self, caller: Address, system_contract_address: Address, data: Bytes, ) -> Result; + + /// Calls [`SystemCallCommitEvm::system_call_commit`] with a custom caller. + #[deprecated(since = "0.1.0", note = "Use `system_call_with_caller_commit` instead")] + fn transact_system_call_with_caller_commit( + &mut self, + caller: Address, + system_contract_address: Address, + data: Bytes, + ) -> Result { + self.system_call_with_caller_commit(caller, system_contract_address, data) + } } impl SystemCallEvm @@ -151,7 +224,7 @@ where INST: InstructionProvider, PRECOMPILES: PrecompileProvider, { - fn transact_system_call_with_caller( + fn system_call_one_with_caller( &mut self, caller: Address, system_contract_address: Address, @@ -176,13 +249,13 @@ where INST: InstructionProvider, PRECOMPILES: PrecompileProvider, { - fn transact_system_call_with_caller_commit( + fn system_call_with_caller_commit( &mut self, caller: Address, system_contract_address: Address, data: Bytes, ) -> Result { - self.transact_system_call_with_caller_finalize(caller, system_contract_address, data) + self.system_call_with_caller(caller, system_contract_address, data) .map(|output| { self.db_mut().commit(output.state); output.result @@ -223,7 +296,7 @@ mod tests { .modify_block_chained(|b| b.number = U256::ONE) .build_mainnet(); let output = evm - .transact_system_call_finalize(HISTORY_STORAGE_ADDRESS, block_hash.0.into()) + .system_call(HISTORY_STORAGE_ADDRESS, block_hash.0.into()) .unwrap(); // system call gas limit is 30M diff --git a/crates/handler/src/validation.rs b/crates/handler/src/validation.rs index 6c956cbc66..5962f03716 100644 --- a/crates/handler/src/validation.rs +++ b/crates/handler/src/validation.rs @@ -195,32 +195,6 @@ pub fn validate_tx_env( return Err(InvalidTransaction::EmptyAuthorizationList); } } - /* // TODO(EOF) EOF removed from spec. - TransactionType::Eip7873 => { - // Check if EIP-7873 transaction is enabled. - if !spec_id.is_enabled_in(SpecId::OSAKA) { - return Err(InvalidTransaction::Eip7873NotSupported); - } - // validate chain id - if Some(context.cfg().chain_id()) != tx.chain_id() { - return Err(InvalidTransaction::InvalidChainId); - } - - // validate initcodes. - validate_eip7873_initcodes(tx.initcodes())?; - - // InitcodeTransaction is invalid if the to is nil. - if tx.kind().is_create() { - return Err(InvalidTransaction::Eip7873MissingTarget); - } - - validate_priority_fee_tx( - tx.max_fee_per_gas(), - tx.max_priority_fee_per_gas().unwrap_or_default(), - base_fee, - )?; - } - */ TransactionType::Custom => { // Custom transaction type check is not done here. } @@ -243,44 +217,6 @@ pub fn validate_tx_env( Ok(()) } -/* TODO(EOF) -/// Validate Initcode Transaction initcode list, return error if any of the following conditions are met: -/// * there are zero entries in initcodes, or if there are more than MAX_INITCODE_COUNT entries. -/// * any entry in initcodes is zero length, or if any entry exceeds MAX_INITCODE_SIZE. -/// * the to is nil. -pub fn validate_eip7873_initcodes(initcodes: &[Bytes]) -> Result<(), InvalidTransaction> { - let mut i = 0; - for initcode in initcodes { - // InitcodeTransaction is invalid if any entry in initcodes is zero length - if initcode.is_empty() { - return Err(InvalidTransaction::Eip7873EmptyInitcode { i }); - } - - // or if any entry exceeds MAX_INITCODE_SIZE. - if initcode.len() > MAX_INITCODE_SIZE { - return Err(InvalidTransaction::Eip7873InitcodeTooLarge { - i, - size: initcode.len(), - }); - } - - i += 1; - } - - // InitcodeTransaction is invalid if there are zero entries in initcodes, - if i == 0 { - return Err(InvalidTransaction::Eip7873EmptyInitcodeList); - } - - // or if there are more than MAX_INITCODE_COUNT entries. - if i > MAX_INITCODE_COUNT { - return Err(InvalidTransaction::Eip7873TooManyInitcodes { size: i }); - } - - Ok(()) -} -*/ - /// Validate initial transaction gas. pub fn validate_initial_tx_gas( tx: impl Transaction, @@ -393,13 +329,16 @@ mod tests { ]; let bytecode: Bytes = init_code.into(); let result = deploy_contract(bytecode, Some(SpecId::OSAKA)); - assert!(matches!( - result, - Ok(ExecutionResult::Halt { - reason: HaltReason::CreateContractSizeLimit, - .. - },) - )); + assert!( + matches!( + result, + Ok(ExecutionResult::Halt { + reason: HaltReason::CreateContractSizeLimit, + .. + },) + ), + "{result:?}" + ); } #[test] @@ -415,13 +354,16 @@ mod tests { ]; let bytecode: Bytes = init_code.into(); let result = deploy_contract(bytecode, Some(SpecId::PRAGUE)); - assert!(matches!( - result, - Ok(ExecutionResult::Halt { - reason: HaltReason::CreateContractSizeLimit, - .. - },) - )); + assert!( + matches!( + result, + Ok(ExecutionResult::Halt { + reason: HaltReason::CreateContractSizeLimit, + .. + },) + ), + "{result:?}" + ); } #[test] diff --git a/crates/inspector/CHANGELOG.md b/crates/inspector/CHANGELOG.md index 2c6729f593..a05acf056d 100644 --- a/crates/inspector/CHANGELOG.md +++ b/crates/inspector/CHANGELOG.md @@ -7,6 +7,37 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [10.0.0](https://github.com/bluealloy/revm/compare/revm-inspector-v9.1.0...revm-inspector-v10.0.0) - 2025-08-23 + +### Other + +- updated the following local packages: revm-database-interface, revm-context, revm-database, revm-interpreter, revm-handler, revm-state + +## [9.1.0](https://github.com/bluealloy/revm/compare/revm-inspector-v9.0.0...revm-inspector-v9.1.0) - 2025-08-12 + +### Added + +- impl inspector for tuple ([#2871](https://github.com/bluealloy/revm/pull/2871)) + +### Other + +- Aggregate changes from PRs #2866, #2867, and #2874 ([#2876](https://github.com/bluealloy/revm/pull/2876)) +- small performance and safety improvements ([#2868](https://github.com/bluealloy/revm/pull/2868)) + +## [9.0.0](https://github.com/bluealloy/revm/compare/revm-inspector-v8.1.0...revm-inspector-v9.0.0) - 2025-08-06 + +### Added + +- fix renamed functions for system_call ([#2824](https://github.com/bluealloy/revm/pull/2824)) +- add system transaction inspection support ([#2808](https://github.com/bluealloy/revm/pull/2808)) + +### Other + +- update README.md ([#2842](https://github.com/bluealloy/revm/pull/2842)) +- fix inspector, cleanup loop ([#2797](https://github.com/bluealloy/revm/pull/2797)) +- improve inspector loop ([#2776](https://github.com/bluealloy/revm/pull/2776)) +- add rust-version and note about MSRV ([#2789](https://github.com/bluealloy/revm/pull/2789)) + ## [8.1.0](https://github.com/bluealloy/revm/compare/revm-inspector-v8.0.3...revm-inspector-v8.1.0) - 2025-07-23 ### Added diff --git a/crates/inspector/Cargo.toml b/crates/inspector/Cargo.toml index 1777ade610..519b30dcc9 100644 --- a/crates/inspector/Cargo.toml +++ b/crates/inspector/Cargo.toml @@ -1,13 +1,14 @@ [package] name = "revm-inspector" description = "Revm inspector interface" -version = "8.1.0" +version = "10.0.0" authors.workspace = true edition.workspace = true keywords.workspace = true license.workspace = true repository.workspace = true readme.workspace = true +rust-version.workspace = true [package.metadata.docs.rs] all-features = true diff --git a/crates/inspector/src/count_inspector.rs b/crates/inspector/src/count_inspector.rs index dd29efe15f..a80d09af62 100644 --- a/crates/inspector/src/count_inspector.rs +++ b/crates/inspector/src/count_inspector.rs @@ -47,7 +47,7 @@ impl CountInspector { /// Get the count for a specific opcode. pub fn get_count(&self, opcode: u8) -> u64 { - self.opcode_counts.get(&opcode).copied().unwrap_or(0) + self.opcode_counts.get(&opcode).copied().unwrap_or_default() } /// Get a reference to all opcode counts. diff --git a/crates/inspector/src/handler.rs b/crates/inspector/src/handler.rs index ba2b8570d5..aad34460cc 100644 --- a/crates/inspector/src/handler.rs +++ b/crates/inspector/src/handler.rs @@ -4,14 +4,17 @@ use handler::{evm::FrameTr, EvmTr, FrameResult, Handler, ItemOrResult}; use interpreter::{ instructions::InstructionTable, interpreter_types::{Jumps, LoopControl}, - FrameInput, Host, InitialAndFloorGas, InstructionContext, InstructionResult, Interpreter, - InterpreterAction, InterpreterTypes, + FrameInput, Host, InitialAndFloorGas, InstructionResult, Interpreter, InterpreterAction, + InterpreterTypes, }; +use state::bytecode::opcode; /// Trait that extends [`Handler`] with inspection functionality. /// /// Similar how [`Handler::run`] method serves as the entry point, /// [`InspectorHandler::inspect_run`] method serves as the entry point for inspection. +/// For system calls, [`InspectorHandler::inspect_run_system_call`] provides inspection +/// support similar to [`Handler::run_system_call`]. /// /// Notice that when inspection is run it skips few functions from handler, this can be /// a problem if custom EVM is implemented and some of skipped functions have changed logic. @@ -23,6 +26,7 @@ use interpreter::{ /// * [`Handler::execution`] replaced with [`InspectorHandler::inspect_execution`] /// * [`Handler::run_exec_loop`] replaced with [`InspectorHandler::inspect_run_exec_loop`] /// * `run_exec_loop` calls `inspect_frame_init` and `inspect_frame_run` that call inspector inside. +/// * [`Handler::run_system_call`] replaced with [`InspectorHandler::inspect_run_system_call`] pub trait InspectorHandler: Handler where Self::Evm: @@ -120,6 +124,27 @@ where } } } + + /// Run system call with inspection support. + /// + /// This method acts as [`Handler::run_system_call`] method for inspection. + /// Similar to [`InspectorHandler::inspect_run`] but skips validation and pre-execution phases, + /// going directly to execution with inspection support. + fn inspect_run_system_call( + &mut self, + evm: &mut Self::Evm, + ) -> Result, Self::Error> { + // dummy values that are not used. + let init_and_floor_gas = InitialAndFloorGas::new(0, 0); + // call execution with inspection and then output. + match self + .inspect_execution(evm, &init_and_floor_gas) + .and_then(|exec_result| self.execution_result(evm, exec_result)) + { + out @ Ok(_) => out, + Err(e) => self.catch_error(evm, e), + } + } } /// Handles the start of a frame by calling the appropriate inspector method. @@ -182,75 +207,84 @@ where CTX: ContextTr + Host, IT: InterpreterTypes, { - let mut log_num = context.journal_mut().logs().len(); - // Main loop - while interpreter.bytecode.is_not_end() { - // Get current opcode. - let opcode = interpreter.bytecode.opcode(); - - // Call Inspector step. + loop { inspector.step(interpreter, context); if interpreter.bytecode.is_end() { break; } - // SAFETY: In analysis we are doing padding of bytecode so that we are sure that last - // byte instruction is STOP so we are safe to just increment program_counter bcs on last instruction - // it will do noop and just stop execution of this contract - interpreter.bytecode.relative_jump(1); - - // Execute instruction. - let instruction_context = InstructionContext { - interpreter, - host: context, - }; - instructions[opcode as usize](instruction_context); + let opcode = interpreter.bytecode.opcode(); + interpreter.step(instructions, context); - // check if new log is added - let new_log = context.journal_mut().logs().len(); - if log_num < new_log { - // as there is a change in log number this means new log is added - let log = context.journal_mut().logs().last().unwrap().clone(); - inspector.log(interpreter, context, log); - log_num = new_log; + if (opcode::LOG0..=opcode::LOG4).contains(&opcode) { + inspect_log(interpreter, context, &mut inspector); } - // if loops is ending, break the loop so we can revert to the previous pointer and then call step_end. + inspector.step_end(interpreter, context); + if interpreter.bytecode.is_end() { break; } - - // Call step_end. - inspector.step_end(interpreter, context); } - interpreter.bytecode.revert_to_previous_pointer(); - // call step_end again to handle the last instruction - inspector.step_end(interpreter, context); - let next_action = interpreter.take_next_action(); - // handle selfdestruct + // Handle selfdestruct. if let InterpreterAction::Return(result) = &next_action { if result.result == InstructionResult::SelfDestruct { - match context.journal_mut().journal().last() { - Some(JournalEntry::AccountDestroyed { - address, - target, - had_balance, - .. - }) => { - inspector.selfdestruct(*address, *target, *had_balance); - } - Some(JournalEntry::BalanceTransfer { - from, to, balance, .. - }) => { - inspector.selfdestruct(*from, *to, *balance); - } - _ => {} - } + inspect_selfdestruct(context, &mut inspector); } } next_action } + +#[inline(never)] +#[cold] +fn inspect_log( + interpreter: &mut Interpreter, + context: &mut CTX, + inspector: &mut impl Inspector, +) where + CTX: ContextTr + Host, + IT: InterpreterTypes, +{ + // `LOG*` instruction reverted. + if interpreter + .bytecode + .action() + .as_ref() + .is_some_and(|x| x.is_return()) + { + return; + } + + let log = context.journal_mut().logs().last().unwrap().clone(); + inspector.log(interpreter, context, log); +} + +#[inline(never)] +#[cold] +fn inspect_selfdestruct(context: &mut CTX, inspector: &mut impl Inspector) +where + CTX: ContextTr + Host, + IT: InterpreterTypes, +{ + if let Some( + JournalEntry::AccountDestroyed { + address: contract, + target: to, + had_balance: balance, + .. + } + | JournalEntry::BalanceTransfer { + from: contract, + to, + balance, + .. + }, + ) = context.journal_mut().journal().last() + { + inspector.selfdestruct(*contract, *to, *balance); + } +} diff --git a/crates/inspector/src/inspect.rs b/crates/inspector/src/inspect.rs index 5ac1ada4a6..2036108b9c 100644 --- a/crates/inspector/src/inspect.rs +++ b/crates/inspector/src/inspect.rs @@ -1,5 +1,6 @@ use context::result::ExecResultAndState; -use handler::{ExecuteCommitEvm, ExecuteEvm}; +use handler::{system_call::SYSTEM_ADDRESS, ExecuteCommitEvm, ExecuteEvm, SystemCallEvm}; +use primitives::{Address, Bytes}; /// InspectEvm is a API that allows inspecting the EVM. /// @@ -76,3 +77,122 @@ pub trait InspectCommitEvm: InspectEvm + ExecuteCommitEvm { Ok(output) } } + +/// InspectSystemCallEvm is an API that allows inspecting system calls in the EVM. +/// +/// It extends [`InspectEvm`] and [`SystemCallEvm`] traits to provide inspection +/// capabilities for system transactions, enabling tracing and debugging of +/// system calls similar to regular transactions. +pub trait InspectSystemCallEvm: InspectEvm + SystemCallEvm { + /// Inspect a system call with the current inspector. + /// + /// Similar to [`InspectEvm::inspect_one_tx`] but for system calls. + /// Uses [`SYSTEM_ADDRESS`] as the caller. + fn inspect_one_system_call( + &mut self, + system_contract_address: Address, + data: Bytes, + ) -> Result { + self.inspect_one_system_call_with_caller(SYSTEM_ADDRESS, system_contract_address, data) + } + + /// Inspect a system call with the current inspector and a custom caller. + /// + /// Similar to [`InspectEvm::inspect_one_tx`] but for system calls with a custom caller. + fn inspect_one_system_call_with_caller( + &mut self, + caller: Address, + system_contract_address: Address, + data: Bytes, + ) -> Result; + + /// Inspect a system call and finalize the state. + /// + /// Similar to [`InspectEvm::inspect_tx`] but for system calls. + fn inspect_system_call( + &mut self, + system_contract_address: Address, + data: Bytes, + ) -> Result, Self::Error> { + let output = self.inspect_one_system_call(system_contract_address, data)?; + let state = self.finalize(); + Ok(ExecResultAndState::new(output, state)) + } + + /// Inspect a system call with a custom caller and finalize the state. + /// + /// Similar to [`InspectEvm::inspect_tx`] but for system calls with a custom caller. + fn inspect_system_call_with_caller( + &mut self, + caller: Address, + system_contract_address: Address, + data: Bytes, + ) -> Result, Self::Error> { + let output = + self.inspect_one_system_call_with_caller(caller, system_contract_address, data)?; + let state = self.finalize(); + Ok(ExecResultAndState::new(output, state)) + } + + /// Inspect a system call with a given inspector. + /// + /// Similar to [`InspectEvm::inspect_one`] but for system calls. + fn inspect_one_system_call_with_inspector( + &mut self, + system_contract_address: Address, + data: Bytes, + inspector: Self::Inspector, + ) -> Result { + self.set_inspector(inspector); + self.inspect_one_system_call(system_contract_address, data) + } + + /// Inspect a system call with a given inspector and finalize the state. + /// + /// Similar to [`InspectEvm::inspect`] but for system calls. + fn inspect_system_call_with_inspector( + &mut self, + system_contract_address: Address, + data: Bytes, + inspector: Self::Inspector, + ) -> Result, Self::Error> { + let output = + self.inspect_one_system_call_with_inspector(system_contract_address, data, inspector)?; + let state = self.finalize(); + Ok(ExecResultAndState::new(output, state)) + } + + /// Inspect a system call with a given inspector and caller. + /// + /// Similar to [`InspectEvm::inspect_one`] but for system calls. + fn inspect_one_system_call_with_inspector_and_caller( + &mut self, + caller: Address, + system_contract_address: Address, + data: Bytes, + inspector: Self::Inspector, + ) -> Result { + self.set_inspector(inspector); + self.inspect_one_system_call_with_caller(caller, system_contract_address, data) + } + + /// Inspect a system call with a given inspector and finalize the state. + /// + /// Similar to [`InspectEvm::inspect`] but for system calls. + fn inspect_system_call_with_inspector_and_caller( + &mut self, + caller: Address, + system_contract_address: Address, + data: Bytes, + inspector: Self::Inspector, + ) -> Result, Self::Error> { + let output = self.inspect_one_system_call_with_inspector_and_caller( + caller, + system_contract_address, + data, + inspector, + )?; + let state = self.finalize(); + Ok(ExecResultAndState::new(output, state)) + } +} diff --git a/crates/inspector/src/inspector.rs b/crates/inspector/src/inspector.rs index 7a2101c377..0df83be214 100644 --- a/crates/inspector/src/inspector.rs +++ b/crates/inspector/src/inspector.rs @@ -113,6 +113,64 @@ pub trait Inspector { } } +impl Inspector for (L, R) +where + L: Inspector, + R: Inspector, +{ + fn initialize_interp(&mut self, interp: &mut Interpreter, context: &mut CTX) { + self.0.initialize_interp(interp, context); + self.1.initialize_interp(interp, context); + } + + fn step(&mut self, interp: &mut Interpreter, context: &mut CTX) { + self.0.step(interp, context); + self.1.step(interp, context); + } + + fn step_end(&mut self, interp: &mut Interpreter, context: &mut CTX) { + self.0.step_end(interp, context); + self.1.step_end(interp, context); + } + + fn log(&mut self, interp: &mut Interpreter, context: &mut CTX, log: Log) { + self.0.log(interp, context, log.clone()); + self.1.log(interp, context, log); + } + + fn call(&mut self, context: &mut CTX, inputs: &mut CallInputs) -> Option { + self.0 + .call(context, inputs) + .or_else(|| self.1.call(context, inputs)) + } + + fn call_end(&mut self, context: &mut CTX, inputs: &CallInputs, outcome: &mut CallOutcome) { + self.0.call_end(context, inputs, outcome); + self.1.call_end(context, inputs, outcome); + } + + fn create(&mut self, context: &mut CTX, inputs: &mut CreateInputs) -> Option { + self.0 + .create(context, inputs) + .or_else(|| self.1.create(context, inputs)) + } + + fn create_end( + &mut self, + context: &mut CTX, + inputs: &CreateInputs, + outcome: &mut CreateOutcome, + ) { + self.0.create_end(context, inputs, outcome); + self.1.create_end(context, inputs, outcome); + } + + fn selfdestruct(&mut self, contract: Address, target: Address, value: U256) { + self.0.selfdestruct(contract, target, value); + self.1.selfdestruct(contract, target, value); + } +} + /// Extends the journal with additional methods that are used by the inspector. #[auto_impl(&mut, Box)] pub trait JournalExt { diff --git a/crates/inspector/src/inspector_tests.rs b/crates/inspector/src/inspector_tests.rs index 29cfa54c94..5916a75c86 100644 --- a/crates/inspector/src/inspector_tests.rs +++ b/crates/inspector/src/inspector_tests.rs @@ -1,6 +1,6 @@ #[cfg(test)] mod tests { - use crate::{InspectEvm, Inspector}; + use crate::{InspectEvm, InspectSystemCallEvm, Inspector}; use context::{Context, TxEnv}; use database::{BenchmarkDB, BENCH_CALLER, BENCH_TARGET}; use handler::{MainBuilder, MainContext}; @@ -731,4 +731,73 @@ mod tests { "Should have jumped to JUMPDEST" ); } + + #[test] + fn test_system_call_inspection_basic() { + // PUSH1 0x42, SSTORE, STOP + let code = Bytes::from(vec![ + opcode::PUSH1, + 0x42, + opcode::PUSH1, + 0x00, + opcode::SSTORE, + opcode::STOP, + ]); + + let bytecode = Bytecode::new_raw(code); + let ctx = Context::mainnet().with_db(BenchmarkDB::new_bytecode(bytecode)); + let mut evm = ctx.build_mainnet_with_inspector(TestInspector::new()); + + let result = evm + .inspect_system_call(BENCH_TARGET, Bytes::default()) + .unwrap(); + + assert!(result.result.is_success()); + assert!(evm.inspector.get_step_count() > 0); + assert!(!result.state.is_empty()); + } + + #[test] + fn test_system_call_inspection_api_variants() { + let code = vec![ + opcode::CALLER, + opcode::PUSH1, + 0x00, + opcode::MSTORE, + opcode::PUSH1, + 0x20, + opcode::PUSH1, + 0x00, + opcode::RETURN, + ]; + + let bytecode = Bytecode::new_raw(Bytes::from(code)); + let ctx = Context::mainnet().with_db(BenchmarkDB::new_bytecode(bytecode)); + let mut evm = ctx.build_mainnet_with_inspector(TestInspector::new()); + + // Test inspect_one_system_call + let result = evm + .inspect_one_system_call(BENCH_TARGET, Bytes::default()) + .unwrap(); + assert!(result.is_success()); + + // Test inspect_one_system_call_with_caller + let custom_caller = address!("0x1234567890123456789012345678901234567890"); + let result = evm + .inspect_one_system_call_with_caller(custom_caller, BENCH_TARGET, Bytes::default()) + .unwrap(); + assert!(result.is_success()); + + // Test inspect_one_system_call_with_inspector + let result = evm + .inspect_one_system_call_with_inspector( + BENCH_TARGET, + Bytes::default(), + TestInspector::new(), + ) + .unwrap(); + assert!(result.is_success()); + + assert!(evm.inspector.get_step_count() > 0); + } } diff --git a/crates/inspector/src/lib.rs b/crates/inspector/src/lib.rs index 3c7f331b2b..35338857bb 100644 --- a/crates/inspector/src/lib.rs +++ b/crates/inspector/src/lib.rs @@ -30,7 +30,53 @@ pub mod inspectors { pub use count_inspector::CountInspector; pub use handler::{inspect_instructions, InspectorHandler}; -pub use inspect::{InspectCommitEvm, InspectEvm}; +pub use inspect::{InspectCommitEvm, InspectEvm, InspectSystemCallEvm}; pub use inspector::*; pub use noop::NoOpInspector; pub use traits::*; + +#[cfg(test)] +mod tests { + use super::*; + use ::handler::{MainBuilder, MainContext}; + use context::{BlockEnv, CfgEnv, Context, Journal, TxEnv}; + use database::{BenchmarkDB, BENCH_CALLER, BENCH_TARGET}; + use interpreter::{interpreter::EthInterpreter, InstructionResult, InterpreterTypes}; + use primitives::TxKind; + use state::{bytecode::opcode, Bytecode}; + + struct HaltInspector; + impl Inspector for HaltInspector { + fn step(&mut self, interp: &mut interpreter::Interpreter, _context: &mut CTX) { + interp.halt(InstructionResult::Stop); + } + } + + #[test] + fn test_step_halt() { + let bytecode = [opcode::INVALID]; + let r = run(&bytecode, HaltInspector); + assert!(r.is_success()); + } + + fn run( + bytecode: &[u8], + inspector: impl Inspector< + Context, ()>, + EthInterpreter, + >, + ) -> context::result::ExecutionResult { + let bytecode = Bytecode::new_raw(bytecode.to_vec().into()); + let ctx = Context::mainnet().with_db(BenchmarkDB::new_bytecode(bytecode)); + let mut evm = ctx.build_mainnet_with_inspector(inspector); + evm.inspect_one_tx( + TxEnv::builder() + .caller(BENCH_CALLER) + .kind(TxKind::Call(BENCH_TARGET)) + .gas_limit(21100) + .build() + .unwrap(), + ) + .unwrap() + } +} diff --git a/crates/inspector/src/mainnet_inspect.rs b/crates/inspector/src/mainnet_inspect.rs index 33afea5512..6b78bf7440 100644 --- a/crates/inspector/src/mainnet_inspect.rs +++ b/crates/inspector/src/mainnet_inspect.rs @@ -1,14 +1,15 @@ use crate::{ - inspect::{InspectCommitEvm, InspectEvm}, + inspect::{InspectCommitEvm, InspectEvm, InspectSystemCallEvm}, Inspector, InspectorEvmTr, InspectorHandler, JournalExt, }; use context::{ContextSetters, ContextTr, Evm, JournalTr}; use database_interface::DatabaseCommit; use handler::{ - instructions::InstructionProvider, EthFrame, EvmTr, EvmTrError, Handler, MainnetHandler, - PrecompileProvider, + instructions::InstructionProvider, system_call::SystemCallTx, EthFrame, EvmTr, EvmTrError, + Handler, MainnetHandler, PrecompileProvider, }; use interpreter::{interpreter::EthInterpreter, InterpreterResult}; +use primitives::{Address, Bytes}; use state::EvmState; // Implementing InspectorHandler for MainnetHandler. @@ -57,6 +58,33 @@ where { } +// Implementing InspectSystemCallEvm for Evm +impl InspectSystemCallEvm + for Evm> +where + CTX: ContextSetters + + ContextTr + JournalExt, Tx: SystemCallTx>, + INSP: Inspector, + INST: InstructionProvider, + PRECOMPILES: PrecompileProvider, +{ + fn inspect_one_system_call_with_caller( + &mut self, + caller: Address, + system_contract_address: Address, + data: Bytes, + ) -> Result { + // Set system call transaction fields similar to transact_system_call_with_caller + self.set_tx(CTX::Tx::new_system_tx_with_caller( + caller, + system_contract_address, + data, + )); + // Use inspect_run_system_call instead of run_system_call for inspection + MainnetHandler::default().inspect_run_system_call(self) + } +} + // Implementing InspectorEvmTr for Evm impl InspectorEvmTr for Evm> where diff --git a/crates/interpreter/CHANGELOG.md b/crates/interpreter/CHANGELOG.md index 473ea6dea4..0d6561a73a 100644 --- a/crates/interpreter/CHANGELOG.md +++ b/crates/interpreter/CHANGELOG.md @@ -1,4 +1,49 @@ # Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [25.0.2](https://github.com/bluealloy/revm/compare/revm-interpreter-v25.0.1...revm-interpreter-v25.0.2) - 2025-08-23 + +### Fixed + +- *(interpreter)* correct CreateContractStartingWithEF halt mapping ([#2890](https://github.com/bluealloy/revm/pull/2890)) + +## [25.0.1](https://github.com/bluealloy/revm/compare/revm-interpreter-v25.0.0...revm-interpreter-v25.0.1) - 2025-08-12 + +### Other + +- updated the following local packages: revm-primitives, revm-bytecode, revm-context-interface + +## [25.0.0](https://github.com/bluealloy/revm/compare/revm-interpreter-v24.0.0...revm-interpreter-v25.0.0) - 2025-08-06 + +### Added + +- short address for journal cold/warm check ([#2849](https://github.com/bluealloy/revm/pull/2849)) +- gastable, record static gas in Interpreter loop ([#2822](https://github.com/bluealloy/revm/pull/2822)) + +### Fixed + +- map new once and for all (+ci) ([#2852](https://github.com/bluealloy/revm/pull/2852)) + +### Other + +- *(deps)* bump ruint ([#2811](https://github.com/bluealloy/revm/pull/2811)) +- specialize halt, making instruction code very slightly smaller ([#2840](https://github.com/bluealloy/revm/pull/2840)) +- update README.md ([#2842](https://github.com/bluealloy/revm/pull/2842)) +- add debug assertions to set_action ([#2832](https://github.com/bluealloy/revm/pull/2832)) +- improve ExtBytecode hash handling ([#2826](https://github.com/bluealloy/revm/pull/2826)) +- fix inspector, cleanup loop ([#2797](https://github.com/bluealloy/revm/pull/2797)) +- start InstructionResult at 1 ([#2802](https://github.com/bluealloy/revm/pull/2802)) +- fix typos ([#2800](https://github.com/bluealloy/revm/pull/2800)) +- improve inspector loop ([#2776](https://github.com/bluealloy/revm/pull/2776)) +- add rust-version and note about MSRV ([#2789](https://github.com/bluealloy/revm/pull/2789)) +- collapse debug info for interpreter macros ([#2780](https://github.com/bluealloy/revm/pull/2780)) +# Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), diff --git a/crates/interpreter/Cargo.toml b/crates/interpreter/Cargo.toml index a03818785f..4e3ccca73d 100644 --- a/crates/interpreter/Cargo.toml +++ b/crates/interpreter/Cargo.toml @@ -1,13 +1,14 @@ [package] name = "revm-interpreter" description = "Revm Interpreter that executes bytecode." -version = "24.0.0" +version = "25.0.2" authors.workspace = true edition.workspace = true keywords.workspace = true license.workspace = true repository.workspace = true readme.workspace = true +rust-version.workspace = true [package.metadata.docs.rs] all-features = true @@ -30,12 +31,7 @@ bincode.workspace = true [features] default = ["std"] -std = [ - "serde?/std", - "primitives/std", - "context-interface/std", - "bytecode/std" -] +std = ["serde?/std", "primitives/std", "context-interface/std", "bytecode/std"] hashbrown = ["primitives/hashbrown"] serde = [ "dep:serde", diff --git a/crates/interpreter/src/gas.rs b/crates/interpreter/src/gas.rs index e270224069..37a0421835 100644 --- a/crates/interpreter/src/gas.rs +++ b/crates/interpreter/src/gas.rs @@ -153,19 +153,15 @@ impl Gas { false } - /// Record memory expansion - #[inline] - #[must_use = "internally uses record_cost that flags out of gas error"] - pub fn record_memory_expansion(&mut self, new_len: usize) -> MemoryExtensionResult { - let Some(additional_cost) = self.memory.record_new_len(new_len) else { - return MemoryExtensionResult::Same; - }; - - if !self.record_cost(additional_cost) { - return MemoryExtensionResult::OutOfGas; - } - - MemoryExtensionResult::Extended + /// Records an explicit cost. In case of underflow the gas will wrap around cost. + /// + /// Returns `true` if the gas limit is exceeded. + #[inline(always)] + #[must_use = "In case of not enough gas, the interpreter should halt with an out-of-gas error"] + pub fn record_cost_unsafe(&mut self, cost: u64) -> bool { + let oog = self.remaining < cost; + self.remaining = self.remaining.wrapping_sub(cost); + oog } } diff --git a/crates/interpreter/src/instruction_context.rs b/crates/interpreter/src/instruction_context.rs index d8aa146829..37e48a6565 100644 --- a/crates/interpreter/src/instruction_context.rs +++ b/crates/interpreter/src/instruction_context.rs @@ -1,6 +1,4 @@ -use crate::{interpreter_types::Jumps, Interpreter, InterpreterTypes}; - -use super::Instruction; +use crate::{Interpreter, InterpreterTypes}; /// Context passed to instruction implementations containing the host and interpreter. /// This struct provides access to both the host interface for external state operations @@ -20,22 +18,3 @@ impl std::fmt::Debug for InstructionContext<'_ .finish() } } - -impl InstructionContext<'_, H, ITy> { - /// Executes the instruction at the current instruction pointer. - /// - /// Internally it will increment instruction pointer by one. - #[inline] - pub(crate) fn step(self, instruction_table: &[Instruction; 256]) { - // Get current opcode. - let opcode = self.interpreter.bytecode.opcode(); - - // SAFETY: In analysis we are doing padding of bytecode so that we are sure that last - // byte instruction is STOP so we are safe to just increment program_counter bcs on last instruction - // it will do noop and just stop execution of this contract - self.interpreter.bytecode.relative_jump(1); - - // Execute instruction. - instruction_table[opcode as usize](self) - } -} diff --git a/crates/interpreter/src/instruction_result.rs b/crates/interpreter/src/instruction_result.rs index a5c7485c55..c6d8f3cada 100644 --- a/crates/interpreter/src/instruction_result.rs +++ b/crates/interpreter/src/instruction_result.rs @@ -4,16 +4,17 @@ use context_interface::{ }; use core::fmt::Debug; -#[repr(u8)] -#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] /// Result of executing an EVM instruction. +/// /// This enum represents all possible outcomes when executing an instruction, /// including successful execution, reverts, and various error conditions. +#[repr(u8)] +#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum InstructionResult { /// Encountered a `STOP` opcode #[default] - Stop, + Stop = 1, // Start at 1 so that `Result<(), _>::Ok(())` is 0. /// Return from the current call. Return, /// Self-destruct the current contract. @@ -35,7 +36,7 @@ pub enum InstructionResult { // Error Codes /// Out of gas error. - OutOfGas = 0x50, + OutOfGas = 0x20, /// Out of gas error encountered during memory expansion. MemoryOOG, /// The memory limit of the EVM has been exceeded. @@ -195,19 +196,19 @@ impl InstructionResult { /// Returns whether the result is a success. #[inline] pub const fn is_ok(self) -> bool { - matches!(self, crate::return_ok!()) + matches!(self, return_ok!()) } #[inline] /// Returns whether the result is a success or revert (not an error). pub const fn is_ok_or_revert(self) -> bool { - matches!(self, crate::return_ok!() | crate::return_revert!()) + matches!(self, return_ok!() | return_revert!()) } /// Returns whether the result is a revert. #[inline] pub const fn is_revert(self) -> bool { - matches!(self, crate::return_revert!()) + matches!(self, return_revert!()) } /// Returns whether the result is an error. @@ -331,10 +332,12 @@ impl> From for SuccessOrHalt Self::Halt(HaltReason::OverflowPayment.into()), // Check for first call is done separately. InstructionResult::PrecompileError => Self::Halt(HaltReason::PrecompileError.into()), InstructionResult::NonceOverflow => Self::Halt(HaltReason::NonceOverflow.into()), - InstructionResult::CreateContractSizeLimit - | InstructionResult::CreateContractStartingWithEF => { + InstructionResult::CreateContractSizeLimit => { Self::Halt(HaltReason::CreateContractSizeLimit.into()) } + InstructionResult::CreateContractStartingWithEF => { + Self::Halt(HaltReason::CreateContractStartingWithEF.into()) + } InstructionResult::CreateInitCodeSizeLimit => { Self::Halt(HaltReason::CreateInitCodeSizeLimit.into()) } @@ -353,7 +356,7 @@ mod tests { use crate::InstructionResult; #[test] - fn all_results_are_covered() { + fn exhaustiveness() { match InstructionResult::Stop { return_error!() => {} return_revert!() => {} @@ -363,31 +366,29 @@ mod tests { #[test] fn test_results() { - let ok_results = vec![ + let ok_results = [ InstructionResult::Stop, InstructionResult::Return, InstructionResult::SelfDestruct, ]; - for result in ok_results { assert!(result.is_ok()); assert!(!result.is_revert()); assert!(!result.is_error()); } - let revert_results = vec![ + let revert_results = [ InstructionResult::Revert, InstructionResult::CallTooDeep, InstructionResult::OutOfFunds, ]; - for result in revert_results { assert!(!result.is_ok()); assert!(result.is_revert()); assert!(!result.is_error()); } - let error_results = vec![ + let error_results = [ InstructionResult::OutOfGas, InstructionResult::MemoryOOG, InstructionResult::MemoryLimitOOG, @@ -411,7 +412,6 @@ mod tests { InstructionResult::CreateInitCodeSizeLimit, InstructionResult::FatalExternalError, ]; - for result in error_results { assert!(!result.is_ok()); assert!(!result.is_revert()); diff --git a/crates/interpreter/src/instructions.rs b/crates/interpreter/src/instructions.rs index 63ff98f6b6..185b11b6e1 100644 --- a/crates/interpreter/src/instructions.rs +++ b/crates/interpreter/src/instructions.rs @@ -30,184 +30,222 @@ pub mod utility; use crate::{interpreter_types::InterpreterTypes, Host, InstructionContext}; /// EVM opcode function signature. -pub type Instruction = fn(InstructionContext<'_, H, W>); +#[derive(Debug)] +pub struct Instruction { + fn_: fn(InstructionContext<'_, H, W>), + static_gas: u64, +} + +impl Instruction { + /// Creates a new instruction with the given function and static gas cost. + #[inline] + pub const fn new(fn_: fn(InstructionContext<'_, H, W>), static_gas: u64) -> Self { + Self { fn_, static_gas } + } + + /// Creates an unknown/invalid instruction. + #[inline] + pub const fn unknown() -> Self { + Self { + fn_: control::unknown, + static_gas: 0, + } + } + + /// Executes the instruction with the given context. + #[inline(always)] + pub fn execute(self, ctx: InstructionContext<'_, H, W>) { + (self.fn_)(ctx) + } + + /// Returns the static gas cost of this instruction. + #[inline(always)] + pub const fn static_gas(&self) -> u64 { + self.static_gas + } +} + +impl Copy for Instruction {} +impl Clone for Instruction { + fn clone(&self) -> Self { + *self + } +} /// Instruction table is list of instruction function pointers mapped to 256 EVM opcodes. pub type InstructionTable = [Instruction; 256]; /// Returns the default instruction table for the given interpreter types and host. #[inline] -pub const fn instruction_table( -) -> [Instruction; 256] { +pub const fn instruction_table() -> [Instruction; 256] { const { instruction_table_impl::() } } -const fn instruction_table_impl( -) -> [Instruction; 256] { +const fn instruction_table_impl() -> [Instruction; 256] { use bytecode::opcode::*; - let mut table = [control::unknown as Instruction; 256]; - - table[STOP as usize] = control::stop; - table[ADD as usize] = arithmetic::add; - table[MUL as usize] = arithmetic::mul; - table[SUB as usize] = arithmetic::sub; - table[DIV as usize] = arithmetic::div; - table[SDIV as usize] = arithmetic::sdiv; - table[MOD as usize] = arithmetic::rem; - table[SMOD as usize] = arithmetic::smod; - table[ADDMOD as usize] = arithmetic::addmod; - table[MULMOD as usize] = arithmetic::mulmod; - table[EXP as usize] = arithmetic::exp; - table[SIGNEXTEND as usize] = arithmetic::signextend; - - table[LT as usize] = bitwise::lt; - table[GT as usize] = bitwise::gt; - table[SLT as usize] = bitwise::slt; - table[SGT as usize] = bitwise::sgt; - table[EQ as usize] = bitwise::eq; - table[ISZERO as usize] = bitwise::iszero; - table[AND as usize] = bitwise::bitand; - table[OR as usize] = bitwise::bitor; - table[XOR as usize] = bitwise::bitxor; - table[NOT as usize] = bitwise::not; - table[BYTE as usize] = bitwise::byte; - table[SHL as usize] = bitwise::shl; - table[SHR as usize] = bitwise::shr; - table[SAR as usize] = bitwise::sar; - table[CLZ as usize] = bitwise::clz; - - table[KECCAK256 as usize] = system::keccak256; - - table[ADDRESS as usize] = system::address; - table[BALANCE as usize] = host::balance; - table[ORIGIN as usize] = tx_info::origin; - table[CALLER as usize] = system::caller; - table[CALLVALUE as usize] = system::callvalue; - table[CALLDATALOAD as usize] = system::calldataload; - table[CALLDATASIZE as usize] = system::calldatasize; - table[CALLDATACOPY as usize] = system::calldatacopy; - table[CODESIZE as usize] = system::codesize; - table[CODECOPY as usize] = system::codecopy; - - table[GASPRICE as usize] = tx_info::gasprice; - table[EXTCODESIZE as usize] = host::extcodesize; - table[EXTCODECOPY as usize] = host::extcodecopy; - table[RETURNDATASIZE as usize] = system::returndatasize; - table[RETURNDATACOPY as usize] = system::returndatacopy; - table[EXTCODEHASH as usize] = host::extcodehash; - table[BLOCKHASH as usize] = host::blockhash; - table[COINBASE as usize] = block_info::coinbase; - table[TIMESTAMP as usize] = block_info::timestamp; - table[NUMBER as usize] = block_info::block_number; - table[DIFFICULTY as usize] = block_info::difficulty; - table[GASLIMIT as usize] = block_info::gaslimit; - table[CHAINID as usize] = block_info::chainid; - table[SELFBALANCE as usize] = host::selfbalance; - table[BASEFEE as usize] = block_info::basefee; - table[BLOBHASH as usize] = tx_info::blob_hash; - table[BLOBBASEFEE as usize] = block_info::blob_basefee; - - table[POP as usize] = stack::pop; - table[MLOAD as usize] = memory::mload; - table[MSTORE as usize] = memory::mstore; - table[MSTORE8 as usize] = memory::mstore8; - table[SLOAD as usize] = host::sload; - table[SSTORE as usize] = host::sstore; - table[JUMP as usize] = control::jump; - table[JUMPI as usize] = control::jumpi; - table[PC as usize] = control::pc; - table[MSIZE as usize] = memory::msize; - table[GAS as usize] = system::gas; - table[JUMPDEST as usize] = control::jumpdest; - table[TLOAD as usize] = host::tload; - table[TSTORE as usize] = host::tstore; - table[MCOPY as usize] = memory::mcopy; - - table[PUSH0 as usize] = stack::push0; - table[PUSH1 as usize] = stack::push::<1, _, _>; - table[PUSH2 as usize] = stack::push::<2, _, _>; - table[PUSH3 as usize] = stack::push::<3, _, _>; - table[PUSH4 as usize] = stack::push::<4, _, _>; - table[PUSH5 as usize] = stack::push::<5, _, _>; - table[PUSH6 as usize] = stack::push::<6, _, _>; - table[PUSH7 as usize] = stack::push::<7, _, _>; - table[PUSH8 as usize] = stack::push::<8, _, _>; - table[PUSH9 as usize] = stack::push::<9, _, _>; - table[PUSH10 as usize] = stack::push::<10, _, _>; - table[PUSH11 as usize] = stack::push::<11, _, _>; - table[PUSH12 as usize] = stack::push::<12, _, _>; - table[PUSH13 as usize] = stack::push::<13, _, _>; - table[PUSH14 as usize] = stack::push::<14, _, _>; - table[PUSH15 as usize] = stack::push::<15, _, _>; - table[PUSH16 as usize] = stack::push::<16, _, _>; - table[PUSH17 as usize] = stack::push::<17, _, _>; - table[PUSH18 as usize] = stack::push::<18, _, _>; - table[PUSH19 as usize] = stack::push::<19, _, _>; - table[PUSH20 as usize] = stack::push::<20, _, _>; - table[PUSH21 as usize] = stack::push::<21, _, _>; - table[PUSH22 as usize] = stack::push::<22, _, _>; - table[PUSH23 as usize] = stack::push::<23, _, _>; - table[PUSH24 as usize] = stack::push::<24, _, _>; - table[PUSH25 as usize] = stack::push::<25, _, _>; - table[PUSH26 as usize] = stack::push::<26, _, _>; - table[PUSH27 as usize] = stack::push::<27, _, _>; - table[PUSH28 as usize] = stack::push::<28, _, _>; - table[PUSH29 as usize] = stack::push::<29, _, _>; - table[PUSH30 as usize] = stack::push::<30, _, _>; - table[PUSH31 as usize] = stack::push::<31, _, _>; - table[PUSH32 as usize] = stack::push::<32, _, _>; - - table[DUP1 as usize] = stack::dup::<1, _, _>; - table[DUP2 as usize] = stack::dup::<2, _, _>; - table[DUP3 as usize] = stack::dup::<3, _, _>; - table[DUP4 as usize] = stack::dup::<4, _, _>; - table[DUP5 as usize] = stack::dup::<5, _, _>; - table[DUP6 as usize] = stack::dup::<6, _, _>; - table[DUP7 as usize] = stack::dup::<7, _, _>; - table[DUP8 as usize] = stack::dup::<8, _, _>; - table[DUP9 as usize] = stack::dup::<9, _, _>; - table[DUP10 as usize] = stack::dup::<10, _, _>; - table[DUP11 as usize] = stack::dup::<11, _, _>; - table[DUP12 as usize] = stack::dup::<12, _, _>; - table[DUP13 as usize] = stack::dup::<13, _, _>; - table[DUP14 as usize] = stack::dup::<14, _, _>; - table[DUP15 as usize] = stack::dup::<15, _, _>; - table[DUP16 as usize] = stack::dup::<16, _, _>; - - table[SWAP1 as usize] = stack::swap::<1, _, _>; - table[SWAP2 as usize] = stack::swap::<2, _, _>; - table[SWAP3 as usize] = stack::swap::<3, _, _>; - table[SWAP4 as usize] = stack::swap::<4, _, _>; - table[SWAP5 as usize] = stack::swap::<5, _, _>; - table[SWAP6 as usize] = stack::swap::<6, _, _>; - table[SWAP7 as usize] = stack::swap::<7, _, _>; - table[SWAP8 as usize] = stack::swap::<8, _, _>; - table[SWAP9 as usize] = stack::swap::<9, _, _>; - table[SWAP10 as usize] = stack::swap::<10, _, _>; - table[SWAP11 as usize] = stack::swap::<11, _, _>; - table[SWAP12 as usize] = stack::swap::<12, _, _>; - table[SWAP13 as usize] = stack::swap::<13, _, _>; - table[SWAP14 as usize] = stack::swap::<14, _, _>; - table[SWAP15 as usize] = stack::swap::<15, _, _>; - table[SWAP16 as usize] = stack::swap::<16, _, _>; - - table[LOG0 as usize] = host::log::<0, _>; - table[LOG1 as usize] = host::log::<1, _>; - table[LOG2 as usize] = host::log::<2, _>; - table[LOG3 as usize] = host::log::<3, _>; - table[LOG4 as usize] = host::log::<4, _>; - - table[CREATE as usize] = contract::create::<_, false, _>; - table[CALL as usize] = contract::call; - table[CALLCODE as usize] = contract::call_code; - table[RETURN as usize] = control::ret; - table[DELEGATECALL as usize] = contract::delegate_call; - table[CREATE2 as usize] = contract::create::<_, true, _>; - - table[STATICCALL as usize] = contract::static_call; - table[REVERT as usize] = control::revert; - table[INVALID as usize] = control::invalid; - table[SELFDESTRUCT as usize] = host::selfdestruct; + let mut table = [Instruction::unknown(); 256]; + + table[STOP as usize] = Instruction::new(control::stop, 0); + table[ADD as usize] = Instruction::new(arithmetic::add, 3); + table[MUL as usize] = Instruction::new(arithmetic::mul, 5); + table[SUB as usize] = Instruction::new(arithmetic::sub, 3); + table[DIV as usize] = Instruction::new(arithmetic::div, 5); + table[SDIV as usize] = Instruction::new(arithmetic::sdiv, 5); + table[MOD as usize] = Instruction::new(arithmetic::rem, 5); + table[SMOD as usize] = Instruction::new(arithmetic::smod, 5); + table[ADDMOD as usize] = Instruction::new(arithmetic::addmod, 8); + table[MULMOD as usize] = Instruction::new(arithmetic::mulmod, 8); + table[EXP as usize] = Instruction::new(arithmetic::exp, 0); // dynamic + table[SIGNEXTEND as usize] = Instruction::new(arithmetic::signextend, 5); + + table[LT as usize] = Instruction::new(bitwise::lt, 3); + table[GT as usize] = Instruction::new(bitwise::gt, 3); + table[SLT as usize] = Instruction::new(bitwise::slt, 3); + table[SGT as usize] = Instruction::new(bitwise::sgt, 3); + table[EQ as usize] = Instruction::new(bitwise::eq, 3); + table[ISZERO as usize] = Instruction::new(bitwise::iszero, 3); + table[AND as usize] = Instruction::new(bitwise::bitand, 3); + table[OR as usize] = Instruction::new(bitwise::bitor, 3); + table[XOR as usize] = Instruction::new(bitwise::bitxor, 3); + table[NOT as usize] = Instruction::new(bitwise::not, 3); + table[BYTE as usize] = Instruction::new(bitwise::byte, 3); + table[SHL as usize] = Instruction::new(bitwise::shl, 3); + table[SHR as usize] = Instruction::new(bitwise::shr, 3); + table[SAR as usize] = Instruction::new(bitwise::sar, 3); + table[CLZ as usize] = Instruction::new(bitwise::clz, 5); + + table[KECCAK256 as usize] = Instruction::new(system::keccak256, 0); // dynamic + + table[ADDRESS as usize] = Instruction::new(system::address, 2); + table[BALANCE as usize] = Instruction::new(host::balance, 0); // dynamic + table[ORIGIN as usize] = Instruction::new(tx_info::origin, 2); + table[CALLER as usize] = Instruction::new(system::caller, 2); + table[CALLVALUE as usize] = Instruction::new(system::callvalue, 2); + table[CALLDATALOAD as usize] = Instruction::new(system::calldataload, 3); + table[CALLDATASIZE as usize] = Instruction::new(system::calldatasize, 2); + table[CALLDATACOPY as usize] = Instruction::new(system::calldatacopy, 0); // static 2, mostly dynamic + table[CODESIZE as usize] = Instruction::new(system::codesize, 2); + table[CODECOPY as usize] = Instruction::new(system::codecopy, 0); // static 2, mostly dynamic + + table[GASPRICE as usize] = Instruction::new(tx_info::gasprice, 2); + table[EXTCODESIZE as usize] = Instruction::new(host::extcodesize, 0); // dynamic + table[EXTCODECOPY as usize] = Instruction::new(host::extcodecopy, 0); // dynamic + table[RETURNDATASIZE as usize] = Instruction::new(system::returndatasize, 2); + table[RETURNDATACOPY as usize] = Instruction::new(system::returndatacopy, 0); // static 2, mostly dynamic + table[EXTCODEHASH as usize] = Instruction::new(host::extcodehash, 0); // dynamic + table[BLOCKHASH as usize] = Instruction::new(host::blockhash, 20); + table[COINBASE as usize] = Instruction::new(block_info::coinbase, 2); + table[TIMESTAMP as usize] = Instruction::new(block_info::timestamp, 2); + table[NUMBER as usize] = Instruction::new(block_info::block_number, 2); + table[DIFFICULTY as usize] = Instruction::new(block_info::difficulty, 2); + table[GASLIMIT as usize] = Instruction::new(block_info::gaslimit, 2); + table[CHAINID as usize] = Instruction::new(block_info::chainid, 2); + table[SELFBALANCE as usize] = Instruction::new(host::selfbalance, 5); + table[BASEFEE as usize] = Instruction::new(block_info::basefee, 2); + table[BLOBHASH as usize] = Instruction::new(tx_info::blob_hash, 3); + table[BLOBBASEFEE as usize] = Instruction::new(block_info::blob_basefee, 2); + + table[POP as usize] = Instruction::new(stack::pop, 2); + table[MLOAD as usize] = Instruction::new(memory::mload, 3); + table[MSTORE as usize] = Instruction::new(memory::mstore, 3); + table[MSTORE8 as usize] = Instruction::new(memory::mstore8, 3); + table[SLOAD as usize] = Instruction::new(host::sload, 0); // dynamic + table[SSTORE as usize] = Instruction::new(host::sstore, 0); // dynamic + table[JUMP as usize] = Instruction::new(control::jump, 8); + table[JUMPI as usize] = Instruction::new(control::jumpi, 10); + table[PC as usize] = Instruction::new(control::pc, 2); + table[MSIZE as usize] = Instruction::new(memory::msize, 2); + table[GAS as usize] = Instruction::new(system::gas, 2); + table[JUMPDEST as usize] = Instruction::new(control::jumpdest, 1); + table[TLOAD as usize] = Instruction::new(host::tload, 100); + table[TSTORE as usize] = Instruction::new(host::tstore, 100); + table[MCOPY as usize] = Instruction::new(memory::mcopy, 0); // static 2, mostly dynamic + + table[PUSH0 as usize] = Instruction::new(stack::push0, 2); + table[PUSH1 as usize] = Instruction::new(stack::push::<1, _, _>, 3); + table[PUSH2 as usize] = Instruction::new(stack::push::<2, _, _>, 3); + table[PUSH3 as usize] = Instruction::new(stack::push::<3, _, _>, 3); + table[PUSH4 as usize] = Instruction::new(stack::push::<4, _, _>, 3); + table[PUSH5 as usize] = Instruction::new(stack::push::<5, _, _>, 3); + table[PUSH6 as usize] = Instruction::new(stack::push::<6, _, _>, 3); + table[PUSH7 as usize] = Instruction::new(stack::push::<7, _, _>, 3); + table[PUSH8 as usize] = Instruction::new(stack::push::<8, _, _>, 3); + table[PUSH9 as usize] = Instruction::new(stack::push::<9, _, _>, 3); + table[PUSH10 as usize] = Instruction::new(stack::push::<10, _, _>, 3); + table[PUSH11 as usize] = Instruction::new(stack::push::<11, _, _>, 3); + table[PUSH12 as usize] = Instruction::new(stack::push::<12, _, _>, 3); + table[PUSH13 as usize] = Instruction::new(stack::push::<13, _, _>, 3); + table[PUSH14 as usize] = Instruction::new(stack::push::<14, _, _>, 3); + table[PUSH15 as usize] = Instruction::new(stack::push::<15, _, _>, 3); + table[PUSH16 as usize] = Instruction::new(stack::push::<16, _, _>, 3); + table[PUSH17 as usize] = Instruction::new(stack::push::<17, _, _>, 3); + table[PUSH18 as usize] = Instruction::new(stack::push::<18, _, _>, 3); + table[PUSH19 as usize] = Instruction::new(stack::push::<19, _, _>, 3); + table[PUSH20 as usize] = Instruction::new(stack::push::<20, _, _>, 3); + table[PUSH21 as usize] = Instruction::new(stack::push::<21, _, _>, 3); + table[PUSH22 as usize] = Instruction::new(stack::push::<22, _, _>, 3); + table[PUSH23 as usize] = Instruction::new(stack::push::<23, _, _>, 3); + table[PUSH24 as usize] = Instruction::new(stack::push::<24, _, _>, 3); + table[PUSH25 as usize] = Instruction::new(stack::push::<25, _, _>, 3); + table[PUSH26 as usize] = Instruction::new(stack::push::<26, _, _>, 3); + table[PUSH27 as usize] = Instruction::new(stack::push::<27, _, _>, 3); + table[PUSH28 as usize] = Instruction::new(stack::push::<28, _, _>, 3); + table[PUSH29 as usize] = Instruction::new(stack::push::<29, _, _>, 3); + table[PUSH30 as usize] = Instruction::new(stack::push::<30, _, _>, 3); + table[PUSH31 as usize] = Instruction::new(stack::push::<31, _, _>, 3); + table[PUSH32 as usize] = Instruction::new(stack::push::<32, _, _>, 3); + + table[DUP1 as usize] = Instruction::new(stack::dup::<1, _, _>, 3); + table[DUP2 as usize] = Instruction::new(stack::dup::<2, _, _>, 3); + table[DUP3 as usize] = Instruction::new(stack::dup::<3, _, _>, 3); + table[DUP4 as usize] = Instruction::new(stack::dup::<4, _, _>, 3); + table[DUP5 as usize] = Instruction::new(stack::dup::<5, _, _>, 3); + table[DUP6 as usize] = Instruction::new(stack::dup::<6, _, _>, 3); + table[DUP7 as usize] = Instruction::new(stack::dup::<7, _, _>, 3); + table[DUP8 as usize] = Instruction::new(stack::dup::<8, _, _>, 3); + table[DUP9 as usize] = Instruction::new(stack::dup::<9, _, _>, 3); + table[DUP10 as usize] = Instruction::new(stack::dup::<10, _, _>, 3); + table[DUP11 as usize] = Instruction::new(stack::dup::<11, _, _>, 3); + table[DUP12 as usize] = Instruction::new(stack::dup::<12, _, _>, 3); + table[DUP13 as usize] = Instruction::new(stack::dup::<13, _, _>, 3); + table[DUP14 as usize] = Instruction::new(stack::dup::<14, _, _>, 3); + table[DUP15 as usize] = Instruction::new(stack::dup::<15, _, _>, 3); + table[DUP16 as usize] = Instruction::new(stack::dup::<16, _, _>, 3); + + table[SWAP1 as usize] = Instruction::new(stack::swap::<1, _, _>, 3); + table[SWAP2 as usize] = Instruction::new(stack::swap::<2, _, _>, 3); + table[SWAP3 as usize] = Instruction::new(stack::swap::<3, _, _>, 3); + table[SWAP4 as usize] = Instruction::new(stack::swap::<4, _, _>, 3); + table[SWAP5 as usize] = Instruction::new(stack::swap::<5, _, _>, 3); + table[SWAP6 as usize] = Instruction::new(stack::swap::<6, _, _>, 3); + table[SWAP7 as usize] = Instruction::new(stack::swap::<7, _, _>, 3); + table[SWAP8 as usize] = Instruction::new(stack::swap::<8, _, _>, 3); + table[SWAP9 as usize] = Instruction::new(stack::swap::<9, _, _>, 3); + table[SWAP10 as usize] = Instruction::new(stack::swap::<10, _, _>, 3); + table[SWAP11 as usize] = Instruction::new(stack::swap::<11, _, _>, 3); + table[SWAP12 as usize] = Instruction::new(stack::swap::<12, _, _>, 3); + table[SWAP13 as usize] = Instruction::new(stack::swap::<13, _, _>, 3); + table[SWAP14 as usize] = Instruction::new(stack::swap::<14, _, _>, 3); + table[SWAP15 as usize] = Instruction::new(stack::swap::<15, _, _>, 3); + table[SWAP16 as usize] = Instruction::new(stack::swap::<16, _, _>, 3); + + table[LOG0 as usize] = Instruction::new(host::log::<0, _>, 0); // dynamic + table[LOG1 as usize] = Instruction::new(host::log::<1, _>, 0); // dynamic + table[LOG2 as usize] = Instruction::new(host::log::<2, _>, 0); // dynamic + table[LOG3 as usize] = Instruction::new(host::log::<3, _>, 0); // dynamic + table[LOG4 as usize] = Instruction::new(host::log::<4, _>, 0); // dynamic + + table[CREATE as usize] = Instruction::new(contract::create::<_, false, _>, 0); // dynamic + table[CALL as usize] = Instruction::new(contract::call, 0); // dynamic + table[CALLCODE as usize] = Instruction::new(contract::call_code, 0); // dynamic + table[RETURN as usize] = Instruction::new(control::ret, 0); + table[DELEGATECALL as usize] = Instruction::new(contract::delegate_call, 0); // dynamic + table[CREATE2 as usize] = Instruction::new(contract::create::<_, true, _>, 0); // dynamic + + table[STATICCALL as usize] = Instruction::new(contract::static_call, 0); // dynamic + table[REVERT as usize] = Instruction::new(control::revert, 0); + table[INVALID as usize] = Instruction::new(control::invalid, 0); + table[SELFDESTRUCT as usize] = Instruction::new(host::selfdestruct, 0); // dynamic table } @@ -227,7 +265,7 @@ mod tests { for (i, instr) in instr_table.iter().enumerate() { let is_opcode_unknown = OpCode::new(i as u8).is_none(); // - let is_instr_unknown = std::ptr::fn_addr_eq(*instr, unknown_istr); + let is_instr_unknown = std::ptr::fn_addr_eq(instr.fn_, unknown_istr.fn_); assert_eq!( is_instr_unknown, is_opcode_unknown, "Opcode 0x{i:X?} is not handled", diff --git a/crates/interpreter/src/instructions/arithmetic.rs b/crates/interpreter/src/instructions/arithmetic.rs index 7575cd167d..68333c9385 100644 --- a/crates/interpreter/src/instructions/arithmetic.rs +++ b/crates/interpreter/src/instructions/arithmetic.rs @@ -8,28 +8,28 @@ use primitives::U256; /// Implements the ADD instruction - adds two values from stack. pub fn add(context: InstructionContext<'_, H, WIRE>) { - gas!(context.interpreter, gas::VERYLOW); + //gas!(context.interpreter, gas::VERYLOW); popn_top!([op1], op2, context.interpreter); *op2 = op1.wrapping_add(*op2); } /// Implements the MUL instruction - multiplies two values from stack. pub fn mul(context: InstructionContext<'_, H, WIRE>) { - gas!(context.interpreter, gas::LOW); + //gas!(context.interpreter, gas::LOW); popn_top!([op1], op2, context.interpreter); *op2 = op1.wrapping_mul(*op2); } /// Implements the SUB instruction - subtracts two values from stack. pub fn sub(context: InstructionContext<'_, H, WIRE>) { - gas!(context.interpreter, gas::VERYLOW); + //gas!(context.interpreter, gas::VERYLOW); popn_top!([op1], op2, context.interpreter); *op2 = op1.wrapping_sub(*op2); } /// Implements the DIV instruction - divides two values from stack. pub fn div(context: InstructionContext<'_, H, WIRE>) { - gas!(context.interpreter, gas::LOW); + //gas!(context.interpreter, gas::LOW); popn_top!([op1], op2, context.interpreter); if !op2.is_zero() { *op2 = op1.wrapping_div(*op2); @@ -40,7 +40,7 @@ pub fn div(context: InstructionContext<'_, H, /// /// Performs signed division of two values from stack. pub fn sdiv(context: InstructionContext<'_, H, WIRE>) { - gas!(context.interpreter, gas::LOW); + //gas!(context.interpreter, gas::LOW); popn_top!([op1], op2, context.interpreter); *op2 = i256_div(op1, *op2); } @@ -49,7 +49,7 @@ pub fn sdiv(context: InstructionContext<'_, H /// /// Pops two values from stack and pushes the remainder of their division. pub fn rem(context: InstructionContext<'_, H, WIRE>) { - gas!(context.interpreter, gas::LOW); + //gas!(context.interpreter, gas::LOW); popn_top!([op1], op2, context.interpreter); if !op2.is_zero() { *op2 = op1.wrapping_rem(*op2); @@ -60,7 +60,7 @@ pub fn rem(context: InstructionContext<'_, H, /// /// Performs signed modulo of two values from stack. pub fn smod(context: InstructionContext<'_, H, WIRE>) { - gas!(context.interpreter, gas::LOW); + //gas!(context.interpreter, gas::LOW); popn_top!([op1], op2, context.interpreter); *op2 = i256_mod(op1, *op2) } @@ -69,7 +69,7 @@ pub fn smod(context: InstructionContext<'_, H /// /// Pops three values from stack and pushes (a + b) % n. pub fn addmod(context: InstructionContext<'_, H, WIRE>) { - gas!(context.interpreter, gas::MID); + //gas!(context.interpreter, gas::MID); popn_top!([op1, op2], op3, context.interpreter); *op3 = op1.add_mod(op2, *op3) } @@ -78,7 +78,7 @@ pub fn addmod(context: InstructionContext<'_, /// /// Pops three values from stack and pushes (a * b) % n. pub fn mulmod(context: InstructionContext<'_, H, WIRE>) { - gas!(context.interpreter, gas::MID); + //gas!(context.interpreter, gas::MID); popn_top!([op1, op2], op3, context.interpreter); *op3 = op1.mul_mod(op2, *op3) } @@ -121,7 +121,7 @@ pub fn exp(context: InstructionContext<'_, H, /// Similarly, if `b == 0` then the yellow paper says the output should start with all zeros, /// then end with bits from `b`; this is equal to `y & mask` where `&` is bitwise `AND`. pub fn signextend(context: InstructionContext<'_, H, WIRE>) { - gas!(context.interpreter, gas::LOW); + //gas!(context.interpreter, gas::LOW); popn_top!([ext], x, context.interpreter); // For 31 we also don't need to do anything. if ext < U256::from(31) { diff --git a/crates/interpreter/src/instructions/bitwise.rs b/crates/interpreter/src/instructions/bitwise.rs index 18696e7871..d07f7638e1 100644 --- a/crates/interpreter/src/instructions/bitwise.rs +++ b/crates/interpreter/src/instructions/bitwise.rs @@ -1,6 +1,5 @@ use super::i256::i256_cmp; use crate::{ - gas, interpreter_types::{InterpreterTypes, RuntimeFlag, StackTr}, InstructionContext, }; @@ -9,14 +8,14 @@ use primitives::U256; /// Implements the LT instruction - less than comparison. pub fn lt(context: InstructionContext<'_, H, WIRE>) { - gas!(context.interpreter, gas::VERYLOW); + //gas!(context.interpreter, gas::VERYLOW); popn_top!([op1], op2, context.interpreter); *op2 = U256::from(op1 < *op2); } /// Implements the GT instruction - greater than comparison. pub fn gt(context: InstructionContext<'_, H, WIRE>) { - gas!(context.interpreter, gas::VERYLOW); + //gas!(context.interpreter, gas::VERYLOW); popn_top!([op1], op2, context.interpreter); *op2 = U256::from(op1 > *op2); @@ -25,7 +24,7 @@ pub fn gt(context: InstructionContext<'_, H, /// Implements the CLZ instruction - count leading zeros. pub fn clz(context: InstructionContext<'_, H, WIRE>) { check!(context.interpreter, OSAKA); - gas!(context.interpreter, gas::LOW); + //gas!(context.interpreter, gas::LOW); popn_top!([], op1, context.interpreter); let leading_zeros = op1.leading_zeros(); @@ -36,7 +35,7 @@ pub fn clz(context: InstructionContext<'_, H, /// /// Signed less than comparison of two values from stack. pub fn slt(context: InstructionContext<'_, H, WIRE>) { - gas!(context.interpreter, gas::VERYLOW); + //gas!(context.interpreter, gas::VERYLOW); popn_top!([op1], op2, context.interpreter); *op2 = U256::from(i256_cmp(&op1, op2) == Ordering::Less); @@ -46,7 +45,7 @@ pub fn slt(context: InstructionContext<'_, H, /// /// Signed greater than comparison of two values from stack. pub fn sgt(context: InstructionContext<'_, H, WIRE>) { - gas!(context.interpreter, gas::VERYLOW); + //gas!(context.interpreter, gas::VERYLOW); popn_top!([op1], op2, context.interpreter); *op2 = U256::from(i256_cmp(&op1, op2) == Ordering::Greater); @@ -56,7 +55,7 @@ pub fn sgt(context: InstructionContext<'_, H, /// /// Equality comparison of two values from stack. pub fn eq(context: InstructionContext<'_, H, WIRE>) { - gas!(context.interpreter, gas::VERYLOW); + //gas!(context.interpreter, gas::VERYLOW); popn_top!([op1], op2, context.interpreter); *op2 = U256::from(op1 == *op2); @@ -66,7 +65,7 @@ pub fn eq(context: InstructionContext<'_, H, /// /// Checks if the top stack value is zero. pub fn iszero(context: InstructionContext<'_, H, WIRE>) { - gas!(context.interpreter, gas::VERYLOW); + //gas!(context.interpreter, gas::VERYLOW); popn_top!([], op1, context.interpreter); *op1 = U256::from(op1.is_zero()); } @@ -75,7 +74,7 @@ pub fn iszero(context: InstructionContext<'_, /// /// Bitwise AND of two values from stack. pub fn bitand(context: InstructionContext<'_, H, WIRE>) { - gas!(context.interpreter, gas::VERYLOW); + //gas!(context.interpreter, gas::VERYLOW); popn_top!([op1], op2, context.interpreter); *op2 = op1 & *op2; } @@ -84,7 +83,7 @@ pub fn bitand(context: InstructionContext<'_, /// /// Bitwise OR of two values from stack. pub fn bitor(context: InstructionContext<'_, H, WIRE>) { - gas!(context.interpreter, gas::VERYLOW); + //gas!(context.interpreter, gas::VERYLOW); popn_top!([op1], op2, context.interpreter); *op2 = op1 | *op2; @@ -94,7 +93,7 @@ pub fn bitor(context: InstructionContext<'_, /// /// Bitwise XOR of two values from stack. pub fn bitxor(context: InstructionContext<'_, H, WIRE>) { - gas!(context.interpreter, gas::VERYLOW); + //gas!(context.interpreter, gas::VERYLOW); popn_top!([op1], op2, context.interpreter); *op2 = op1 ^ *op2; @@ -104,7 +103,7 @@ pub fn bitxor(context: InstructionContext<'_, /// /// Bitwise NOT (negation) of the top stack value. pub fn not(context: InstructionContext<'_, H, WIRE>) { - gas!(context.interpreter, gas::VERYLOW); + //gas!(context.interpreter, gas::VERYLOW); popn_top!([], op1, context.interpreter); *op1 = !*op1; @@ -114,7 +113,7 @@ pub fn not(context: InstructionContext<'_, H, /// /// Extracts a single byte from a word at a given index. pub fn byte(context: InstructionContext<'_, H, WIRE>) { - gas!(context.interpreter, gas::VERYLOW); + //gas!(context.interpreter, gas::VERYLOW); popn_top!([op1], op2, context.interpreter); let o1 = as_usize_saturated!(op1); @@ -129,7 +128,7 @@ pub fn byte(context: InstructionContext<'_, H /// EIP-145: Bitwise shifting instructions in EVM pub fn shl(context: InstructionContext<'_, H, WIRE>) { check!(context.interpreter, CONSTANTINOPLE); - gas!(context.interpreter, gas::VERYLOW); + //gas!(context.interpreter, gas::VERYLOW); popn_top!([op1], op2, context.interpreter); let shift = as_usize_saturated!(op1); @@ -143,7 +142,7 @@ pub fn shl(context: InstructionContext<'_, H, /// EIP-145: Bitwise shifting instructions in EVM pub fn shr(context: InstructionContext<'_, H, WIRE>) { check!(context.interpreter, CONSTANTINOPLE); - gas!(context.interpreter, gas::VERYLOW); + //gas!(context.interpreter, gas::VERYLOW); popn_top!([op1], op2, context.interpreter); let shift = as_usize_saturated!(op1); @@ -157,7 +156,7 @@ pub fn shr(context: InstructionContext<'_, H, /// EIP-145: Bitwise shifting instructions in EVM pub fn sar(context: InstructionContext<'_, H, WIRE>) { check!(context.interpreter, CONSTANTINOPLE); - gas!(context.interpreter, gas::VERYLOW); + //gas!(context.interpreter, gas::VERYLOW); popn_top!([op1], op2, context.interpreter); let shift = as_usize_saturated!(op1); diff --git a/crates/interpreter/src/instructions/block_info.rs b/crates/interpreter/src/instructions/block_info.rs index 2e7b251c4b..0dff4a6ad1 100644 --- a/crates/interpreter/src/instructions/block_info.rs +++ b/crates/interpreter/src/instructions/block_info.rs @@ -1,5 +1,4 @@ use crate::{ - gas, interpreter_types::{InterpreterTypes, RuntimeFlag, StackTr}, Host, }; @@ -10,7 +9,7 @@ use crate::InstructionContext; /// EIP-1344: ChainID opcode pub fn chainid(context: InstructionContext<'_, H, WIRE>) { check!(context.interpreter, ISTANBUL); - gas!(context.interpreter, gas::BASE); + //gas!(context.interpreter, gas::BASE); push!(context.interpreter, context.host.chain_id()); } @@ -20,7 +19,7 @@ pub fn chainid(context: InstructionCon pub fn coinbase( context: InstructionContext<'_, H, WIRE>, ) { - gas!(context.interpreter, gas::BASE); + //gas!(context.interpreter, gas::BASE); push!( context.interpreter, context.host.beneficiary().into_word().into() @@ -33,7 +32,7 @@ pub fn coinbase( pub fn timestamp( context: InstructionContext<'_, H, WIRE>, ) { - gas!(context.interpreter, gas::BASE); + //gas!(context.interpreter, gas::BASE); push!(context.interpreter, context.host.timestamp()); } @@ -43,7 +42,7 @@ pub fn timestamp( pub fn block_number( context: InstructionContext<'_, H, WIRE>, ) { - gas!(context.interpreter, gas::BASE); + //gas!(context.interpreter, gas::BASE); push!(context.interpreter, U256::from(context.host.block_number())); } @@ -53,7 +52,7 @@ pub fn block_number( pub fn difficulty( context: InstructionContext<'_, H, WIRE>, ) { - gas!(context.interpreter, gas::BASE); + //gas!(context.interpreter, gas::BASE); if context .interpreter .runtime_flag @@ -73,14 +72,14 @@ pub fn difficulty( pub fn gaslimit( context: InstructionContext<'_, H, WIRE>, ) { - gas!(context.interpreter, gas::BASE); + //gas!(context.interpreter, gas::BASE); push!(context.interpreter, context.host.gas_limit()); } /// EIP-3198: BASEFEE opcode pub fn basefee(context: InstructionContext<'_, H, WIRE>) { check!(context.interpreter, LONDON); - gas!(context.interpreter, gas::BASE); + //gas!(context.interpreter, gas::BASE); push!(context.interpreter, context.host.basefee()); } @@ -89,6 +88,6 @@ pub fn blob_basefee( context: InstructionContext<'_, H, WIRE>, ) { check!(context.interpreter, CANCUN); - gas!(context.interpreter, gas::BASE); + //gas!(context.interpreter, gas::BASE); push!(context.interpreter, context.host.blob_gasprice()); } diff --git a/crates/interpreter/src/instructions/control.rs b/crates/interpreter/src/instructions/control.rs index 58502560ca..66224360c4 100644 --- a/crates/interpreter/src/instructions/control.rs +++ b/crates/interpreter/src/instructions/control.rs @@ -1,5 +1,4 @@ use crate::{ - gas, interpreter::Interpreter, interpreter_types::{InterpreterTypes, Jumps, LoopControl, MemoryTr, RuntimeFlag, StackTr}, InstructionResult, InterpreterAction, @@ -12,7 +11,7 @@ use crate::InstructionContext; /// /// Unconditional jump to a valid destination. pub fn jump(context: InstructionContext<'_, H, ITy>) { - gas!(context.interpreter, gas::MID); + //gas!(context.interpreter, gas::MID); popn!([target], context.interpreter); jump_inner(context.interpreter, target); } @@ -21,7 +20,7 @@ pub fn jump(context: InstructionContext<'_, H, /// /// Conditional jump to a valid destination if condition is true. pub fn jumpi(context: InstructionContext<'_, H, WIRE>) { - gas!(context.interpreter, gas::HIGH); + //gas!(context.interpreter, gas::HIGH); popn!([target, cond], context.interpreter); if !cond.is_zero() { @@ -46,15 +45,15 @@ fn jump_inner(interpreter: &mut Interpreter, targe /// Implements the JUMPDEST instruction. /// /// Marks a valid destination for jump operations. -pub fn jumpdest(context: InstructionContext<'_, H, WIRE>) { - gas!(context.interpreter, gas::JUMPDEST); +pub fn jumpdest(_context: InstructionContext<'_, H, WIRE>) { + //gas!(context.interpreter, gas::JUMPDEST); } /// Implements the PC instruction. /// /// Pushes the current program counter onto the stack. pub fn pc(context: InstructionContext<'_, H, WIRE>) { - gas!(context.interpreter, gas::BASE); + //gas!(context.interpreter, gas::BASE); // - 1 because we have already advanced the instruction pointer in `Interpreter::step` push!( context.interpreter, @@ -71,7 +70,7 @@ fn return_inner( instruction_result: InstructionResult, ) { // Zero gas cost - // gas!(interpreter, gas::ZERO) + // //gas!(interpreter, gas::ZERO) popn!([offset, len], interpreter); let len = as_usize_or_fail!(interpreter, len); // Important: Offset must be ignored if len is zeros diff --git a/crates/interpreter/src/instructions/host.rs b/crates/interpreter/src/instructions/host.rs index 70245220e8..4fb362e7a9 100644 --- a/crates/interpreter/src/instructions/host.rs +++ b/crates/interpreter/src/instructions/host.rs @@ -43,7 +43,7 @@ pub fn selfbalance( context: InstructionContext<'_, H, WIRE>, ) { check!(context.interpreter, ISTANBUL); - gas!(context.interpreter, gas::LOW); + //gas!(context.interpreter, gas::LOW); let Some(balance) = context .host @@ -154,7 +154,7 @@ pub fn extcodecopy( pub fn blockhash( context: InstructionContext<'_, H, WIRE>, ) { - gas!(context.interpreter, gas::BLOCKHASH); + //gas!(context.interpreter, gas::BLOCKHASH); popn_top!([], number, context.interpreter); let requested_number = *number; @@ -261,7 +261,7 @@ pub fn sstore(context: InstructionCont pub fn tstore(context: InstructionContext<'_, H, WIRE>) { check!(context.interpreter, CANCUN); require_non_staticcall!(context.interpreter); - gas!(context.interpreter, gas::WARM_STORAGE_READ_COST); + //gas!(context.interpreter, gas::WARM_STORAGE_READ_COST); popn!([index, value], context.interpreter); @@ -274,7 +274,7 @@ pub fn tstore(context: InstructionCont /// Load value from transient storage pub fn tload(context: InstructionContext<'_, H, WIRE>) { check!(context.interpreter, CANCUN); - gas!(context.interpreter, gas::WARM_STORAGE_READ_COST); + //gas!(context.interpreter, gas::WARM_STORAGE_READ_COST); popn_top!([], index, context.interpreter); diff --git a/crates/interpreter/src/instructions/macros.rs b/crates/interpreter/src/instructions/macros.rs index b361c0369a..8904830211 100644 --- a/crates/interpreter/src/instructions/macros.rs +++ b/crates/interpreter/src/instructions/macros.rs @@ -2,6 +2,7 @@ /// `const` Option `?`. #[macro_export] +#[collapse_debuginfo(yes)] macro_rules! tri { ($e:expr) => { match $e { @@ -13,6 +14,7 @@ macro_rules! tri { /// Fails the instruction if the current call is static. #[macro_export] +#[collapse_debuginfo(yes)] macro_rules! require_non_staticcall { ($interpreter:expr) => { if $interpreter.runtime_flag.is_static() { @@ -25,6 +27,7 @@ macro_rules! require_non_staticcall { /// Macro for optional try - returns early if the expression evaluates to None. /// Similar to the `?` operator but for use in instruction implementations. #[macro_export] +#[collapse_debuginfo(yes)] macro_rules! otry { ($expression: expr) => {{ let Some(value) = $expression else { @@ -34,19 +37,9 @@ macro_rules! otry { }}; } -/// Error if the current call is executing EOF. -#[macro_export] -macro_rules! require_eof { - ($interpreter:expr) => { - if !$interpreter.runtime_flag.is_eof() { - $interpreter.halt($crate::InstructionResult::EOFOpcodeDisabledInLegacy); - return; - } - }; -} - /// Check if the `SPEC` is enabled, and fail the instruction if it is not. #[macro_export] +#[collapse_debuginfo(yes)] macro_rules! check { ($interpreter:expr, $min:ident) => { if !$interpreter @@ -54,7 +47,7 @@ macro_rules! check { .spec_id() .is_enabled_in(primitives::hardfork::SpecId::$min) { - $interpreter.halt($crate::InstructionResult::NotActivated); + $interpreter.halt_not_activated(); return; } }; @@ -62,13 +55,14 @@ macro_rules! check { /// Records a `gas` cost and fails the instruction if it would exceed the available gas. #[macro_export] +#[collapse_debuginfo(yes)] macro_rules! gas { ($interpreter:expr, $gas:expr) => { $crate::gas!($interpreter, $gas, ()) }; ($interpreter:expr, $gas:expr, $ret:expr) => { if !$interpreter.gas.record_cost($gas) { - $interpreter.halt($crate::InstructionResult::OutOfGas); + $interpreter.halt_oog(); return $ret; } }; @@ -76,6 +70,7 @@ macro_rules! gas { /// Same as [`gas!`], but with `gas` as an option. #[macro_export] +#[collapse_debuginfo(yes)] macro_rules! gas_or_fail { ($interpreter:expr, $gas:expr) => { $crate::gas_or_fail!($interpreter, $gas, ()) @@ -84,16 +79,17 @@ macro_rules! gas_or_fail { match $gas { Some(gas_used) => $crate::gas!($interpreter, gas_used, $ret), None => { - $interpreter.halt($crate::InstructionResult::OutOfGas); + $interpreter.halt_oog(); return $ret; } } }; } -/// Resizes the interpreterreter memory if necessary. Fails the instruction if the memory or gas limit +/// Resizes the interpreter memory if necessary. Fails the instruction if the memory or gas limit /// is exceeded. #[macro_export] +#[collapse_debuginfo(yes)] macro_rules! resize_memory { ($interpreter:expr, $offset:expr, $len:expr) => { $crate::resize_memory!($interpreter, $offset, $len, ()) @@ -105,7 +101,7 @@ macro_rules! resize_memory { $offset, $len, ) { - $interpreter.halt($crate::InstructionResult::MemoryOOG); + $interpreter.halt_memory_oog(); return $ret; } }; @@ -113,10 +109,11 @@ macro_rules! resize_memory { /// Pops n values from the stack. Fails the instruction if n values can't be popped. #[macro_export] +#[collapse_debuginfo(yes)] macro_rules! popn { - ([ $($x:ident),* ],$interpreterreter:expr $(,$ret:expr)? ) => { - let Some([$( $x ),*]) = $interpreterreter.stack.popn() else { - $interpreterreter.halt($crate::InstructionResult::StackUnderflow); + ([ $($x:ident),* ],$interpreter:expr $(,$ret:expr)? ) => { + let Some([$( $x ),*]) = $interpreter.stack.popn() else { + $interpreter.halt_underflow(); return $($ret)?; }; }; @@ -124,6 +121,7 @@ macro_rules! popn { #[doc(hidden)] #[macro_export] +#[collapse_debuginfo(yes)] macro_rules! _count { (@count) => { 0 }; (@count $head:tt $($tail:tt)*) => { 1 + _count!(@count $($tail)*) }; @@ -132,6 +130,7 @@ macro_rules! _count { /// Pops n values from the stack and returns the top value. Fails the instruction if n values can't be popped. #[macro_export] +#[collapse_debuginfo(yes)] macro_rules! popn_top { ([ $($x:ident),* ], $top:ident, $interpreter:expr $(,$ret:expr)? ) => { /* @@ -143,7 +142,7 @@ macro_rules! popn_top { // Workaround for https://github.com/rust-lang/rust/issues/144329. if $interpreter.stack.len() < (1 + $crate::_count!($($x)*)) { - $interpreter.halt($crate::InstructionResult::StackUnderflow); + $interpreter.halt_underflow(); return $($ret)?; } let ([$( $x ),*], $top) = unsafe { $interpreter.stack.popn_top().unwrap_unchecked() }; @@ -152,10 +151,11 @@ macro_rules! popn_top { /// Pushes a `B256` value onto the stack. Fails the instruction if the stack is full. #[macro_export] +#[collapse_debuginfo(yes)] macro_rules! push { ($interpreter:expr, $x:expr $(,$ret:item)?) => ( if !($interpreter.stack.push($x)) { - $interpreter.halt($crate::InstructionResult::StackOverflow); + $interpreter.halt_overflow(); return $($ret)?; } ) @@ -163,6 +163,7 @@ macro_rules! push { /// Converts a `U256` value to a `u64`, saturating to `MAX` if the value is too large. #[macro_export] +#[collapse_debuginfo(yes)] macro_rules! as_u64_saturated { ($v:expr) => { match $v.as_limbs() { @@ -179,6 +180,7 @@ macro_rules! as_u64_saturated { /// Converts a `U256` value to a `usize`, saturating to `MAX` if the value is too large. #[macro_export] +#[collapse_debuginfo(yes)] macro_rules! as_usize_saturated { ($v:expr) => { usize::try_from($crate::as_u64_saturated!($v)).unwrap_or(usize::MAX) @@ -187,6 +189,7 @@ macro_rules! as_usize_saturated { /// Converts a `U256` value to a `isize`, saturating to `isize::MAX` if the value is too large. #[macro_export] +#[collapse_debuginfo(yes)] macro_rules! as_isize_saturated { ($v:expr) => { // `isize_try_from(u64::MAX)`` will fail and return isize::MAX @@ -197,6 +200,7 @@ macro_rules! as_isize_saturated { /// Converts a `U256` value to a `usize`, failing the instruction if the value is too large. #[macro_export] +#[collapse_debuginfo(yes)] macro_rules! as_usize_or_fail { ($interpreter:expr, $v:expr) => { $crate::as_usize_or_fail_ret!($interpreter, $v, ()) @@ -209,6 +213,7 @@ macro_rules! as_usize_or_fail { /// Converts a `U256` value to a `usize` and returns `ret`, /// failing the instruction if the value is too large. #[macro_export] +#[collapse_debuginfo(yes)] macro_rules! as_usize_or_fail_ret { ($interpreter:expr, $v:expr, $ret:expr) => { $crate::as_usize_or_fail_ret!( diff --git a/crates/interpreter/src/instructions/memory.rs b/crates/interpreter/src/instructions/memory.rs index dff34d12c1..9a48d88f3d 100644 --- a/crates/interpreter/src/instructions/memory.rs +++ b/crates/interpreter/src/instructions/memory.rs @@ -11,7 +11,7 @@ use crate::InstructionContext; /// /// Loads a 32-byte word from memory. pub fn mload(context: InstructionContext<'_, H, WIRE>) { - gas!(context.interpreter, gas::VERYLOW); + //gas!(context.interpreter, gas::VERYLOW); popn_top!([], top, context.interpreter); let offset = as_usize_or_fail!(context.interpreter, top); resize_memory!(context.interpreter, offset, 32); @@ -23,7 +23,7 @@ pub fn mload(context: InstructionContext<'_, /// /// Stores a 32-byte word to memory. pub fn mstore(context: InstructionContext<'_, H, WIRE>) { - gas!(context.interpreter, gas::VERYLOW); + //gas!(context.interpreter, gas::VERYLOW); popn!([offset, value], context.interpreter); let offset = as_usize_or_fail!(context.interpreter, offset); resize_memory!(context.interpreter, offset, 32); @@ -37,7 +37,7 @@ pub fn mstore(context: InstructionContext<'_, /// /// Stores a single byte to memory. pub fn mstore8(context: InstructionContext<'_, H, WIRE>) { - gas!(context.interpreter, gas::VERYLOW); + //gas!(context.interpreter, gas::VERYLOW); popn!([offset, value], context.interpreter); let offset = as_usize_or_fail!(context.interpreter, offset); resize_memory!(context.interpreter, offset, 1); @@ -48,7 +48,7 @@ pub fn mstore8(context: InstructionContext<'_ /// /// Gets the size of active memory in bytes. pub fn msize(context: InstructionContext<'_, H, WIRE>) { - gas!(context.interpreter, gas::BASE); + //gas!(context.interpreter, gas::BASE); push!( context.interpreter, U256::from(context.interpreter.memory.size()) diff --git a/crates/interpreter/src/instructions/stack.rs b/crates/interpreter/src/instructions/stack.rs index cdfdceccd0..822e6240d7 100644 --- a/crates/interpreter/src/instructions/stack.rs +++ b/crates/interpreter/src/instructions/stack.rs @@ -1,5 +1,4 @@ use crate::{ - gas, interpreter_types::{Immediates, InterpreterTypes, Jumps, RuntimeFlag, StackTr}, InstructionResult, }; @@ -11,7 +10,7 @@ use crate::InstructionContext; /// /// Removes the top item from the stack. pub fn pop(context: InstructionContext<'_, H, WIRE>) { - gas!(context.interpreter, gas::BASE); + //gas!(context.interpreter, gas::BASE); // Can ignore return. as relative N jump is safe operation. popn!([_i], context.interpreter); } @@ -21,7 +20,7 @@ pub fn pop(context: InstructionContext<'_, H, /// Introduce a new instruction which pushes the constant value 0 onto the stack. pub fn push0(context: InstructionContext<'_, H, WIRE>) { check!(context.interpreter, SHANGHAI); - gas!(context.interpreter, gas::BASE); + //gas!(context.interpreter, gas::BASE); push!(context.interpreter, U256::ZERO); } @@ -31,7 +30,7 @@ pub fn push0(context: InstructionContext<'_, pub fn push( context: InstructionContext<'_, H, WIRE>, ) { - gas!(context.interpreter, gas::VERYLOW); + //gas!(context.interpreter, gas::VERYLOW); let slice = context.interpreter.bytecode.read_slice(N); if !context.interpreter.stack.push_slice(slice) { @@ -49,7 +48,7 @@ pub fn push( pub fn dup( context: InstructionContext<'_, H, WIRE>, ) { - gas!(context.interpreter, gas::VERYLOW); + //gas!(context.interpreter, gas::VERYLOW); if !context.interpreter.stack.dup(N) { context.interpreter.halt(InstructionResult::StackOverflow); } @@ -61,7 +60,7 @@ pub fn dup( pub fn swap( context: InstructionContext<'_, H, WIRE>, ) { - gas!(context.interpreter, gas::VERYLOW); + //gas!(context.interpreter, gas::VERYLOW); assert!(N != 0); if !context.interpreter.stack.exchange(0, N) { context.interpreter.halt(InstructionResult::StackOverflow); diff --git a/crates/interpreter/src/instructions/system.rs b/crates/interpreter/src/instructions/system.rs index 6d3ba86570..0bea684e7f 100644 --- a/crates/interpreter/src/instructions/system.rs +++ b/crates/interpreter/src/instructions/system.rs @@ -32,7 +32,7 @@ pub fn keccak256(context: InstructionContext< /// /// Pushes the current contract's address onto the stack. pub fn address(context: InstructionContext<'_, H, WIRE>) { - gas!(context.interpreter, gas::BASE); + //gas!(context.interpreter, gas::BASE); push!( context.interpreter, context @@ -48,7 +48,7 @@ pub fn address(context: InstructionContext<'_ /// /// Pushes the caller's address onto the stack. pub fn caller(context: InstructionContext<'_, H, WIRE>) { - gas!(context.interpreter, gas::BASE); + //gas!(context.interpreter, gas::BASE); push!( context.interpreter, context @@ -64,7 +64,7 @@ pub fn caller(context: InstructionContext<'_, /// /// Pushes the size of running contract's bytecode onto the stack. pub fn codesize(context: InstructionContext<'_, H, WIRE>) { - gas!(context.interpreter, gas::BASE); + //gas!(context.interpreter, gas::BASE); push!( context.interpreter, U256::from(context.interpreter.bytecode.bytecode_len()) @@ -95,7 +95,7 @@ pub fn codecopy(context: InstructionContext<' /// /// Loads 32 bytes of input data from the specified offset. pub fn calldataload(context: InstructionContext<'_, H, WIRE>) { - gas!(context.interpreter, gas::VERYLOW); + //gas!(context.interpreter, gas::VERYLOW); popn_top!([], offset_ptr, context.interpreter); let mut word = B256::ZERO; let offset = as_usize_saturated!(offset_ptr); @@ -133,7 +133,7 @@ pub fn calldataload(context: InstructionConte /// /// Pushes the size of input data onto the stack. pub fn calldatasize(context: InstructionContext<'_, H, WIRE>) { - gas!(context.interpreter, gas::BASE); + //gas!(context.interpreter, gas::BASE); push!( context.interpreter, U256::from(context.interpreter.input.input().len()) @@ -144,7 +144,7 @@ pub fn calldatasize(context: InstructionConte /// /// Pushes the value sent with the current call onto the stack. pub fn callvalue(context: InstructionContext<'_, H, WIRE>) { - gas!(context.interpreter, gas::BASE); + //gas!(context.interpreter, gas::BASE); push!(context.interpreter, context.interpreter.input.call_value()); } @@ -180,7 +180,7 @@ pub fn calldatacopy(context: InstructionConte /// EIP-211: New opcodes: RETURNDATASIZE and RETURNDATACOPY pub fn returndatasize(context: InstructionContext<'_, H, WIRE>) { check!(context.interpreter, BYZANTIUM); - gas!(context.interpreter, gas::BASE); + //gas!(context.interpreter, gas::BASE); push!( context.interpreter, U256::from(context.interpreter.return_data.buffer().len()) @@ -219,7 +219,7 @@ pub fn returndatacopy(context: InstructionCon /// /// Pushes the amount of remaining gas onto the stack. pub fn gas(context: InstructionContext<'_, H, WIRE>) { - gas!(context.interpreter, gas::BASE); + //gas!(context.interpreter, gas::BASE); push!( context.interpreter, U256::from(context.interpreter.gas.remaining()) diff --git a/crates/interpreter/src/instructions/tx_info.rs b/crates/interpreter/src/instructions/tx_info.rs index 745c99a6be..9f0e9f38cb 100644 --- a/crates/interpreter/src/instructions/tx_info.rs +++ b/crates/interpreter/src/instructions/tx_info.rs @@ -1,5 +1,4 @@ use crate::{ - gas, interpreter_types::{InterpreterTypes, RuntimeFlag, StackTr}, Host, }; @@ -13,7 +12,7 @@ use crate::InstructionContext; pub fn gasprice( context: InstructionContext<'_, H, WIRE>, ) { - gas!(context.interpreter, gas::BASE); + //gas!(context.interpreter, gas::BASE); push!( context.interpreter, U256::from(context.host.effective_gas_price()) @@ -24,7 +23,7 @@ pub fn gasprice( /// /// Gets the execution origination address. pub fn origin(context: InstructionContext<'_, H, WIRE>) { - gas!(context.interpreter, gas::BASE); + //gas!(context.interpreter, gas::BASE); push!( context.interpreter, context.host.caller().into_word().into() @@ -38,7 +37,7 @@ pub fn blob_hash( context: InstructionContext<'_, H, WIRE>, ) { check!(context.interpreter, CANCUN); - gas!(context.interpreter, gas::VERYLOW); + //gas!(context.interpreter, gas::VERYLOW); popn_top!([], index, context.interpreter); let i = as_usize_saturated!(index); *index = context.host.blob_hash(i).unwrap_or_default(); diff --git a/crates/interpreter/src/interpreter.rs b/crates/interpreter/src/interpreter.rs index db0ae972f2..aa77301911 100644 --- a/crates/interpreter/src/interpreter.rs +++ b/crates/interpreter/src/interpreter.rs @@ -193,8 +193,10 @@ impl Interpreter { /// Takes the next action from the control and returns it. #[inline] pub fn take_next_action(&mut self) -> InterpreterAction { + self.bytecode.reset_action(); // Return next action if it is some. - core::mem::take(self.bytecode.action()).expect("Interpreter to set action") + let action = core::mem::take(self.bytecode.action()).expect("Interpreter to set action"); + action } /// Halt the interpreter with the given result. @@ -207,6 +209,42 @@ impl Interpreter { .set_action(InterpreterAction::new_halt(result, self.gas)); } + /// Halt the interpreter with an out-of-gas error. + #[cold] + #[inline(never)] + pub fn halt_oog(&mut self) { + self.gas.spend_all(); + self.halt(InstructionResult::OutOfGas); + } + + /// Halt the interpreter with an out-of-gas error. + #[cold] + #[inline(never)] + pub fn halt_memory_oog(&mut self) { + self.halt(InstructionResult::MemoryLimitOOG); + } + + /// Halt the interpreter with and overflow error. + #[cold] + #[inline(never)] + pub fn halt_overflow(&mut self) { + self.halt(InstructionResult::StackOverflow); + } + + /// Halt the interpreter with and underflow error. + #[cold] + #[inline(never)] + pub fn halt_underflow(&mut self) { + self.halt(InstructionResult::StackUnderflow); + } + + /// Halt the interpreter with and not activated error. + #[cold] + #[inline(never)] + pub fn halt_not_activated(&mut self) { + self.halt(InstructionResult::NotActivated); + } + /// Return with the given output. /// /// This will set the action to [`InterpreterAction::Return`] and set the gas to the current gas. @@ -222,12 +260,29 @@ impl Interpreter { /// /// Internally it will increment instruction pointer by one. #[inline] - pub fn step(&mut self, instruction_table: &InstructionTable, host: &mut H) { + pub fn step( + &mut self, + instruction_table: &InstructionTable, + host: &mut H, + ) { + // Get current opcode. + let opcode = self.bytecode.opcode(); + + // SAFETY: In analysis we are doing padding of bytecode so that we are sure that last + // byte instruction is STOP so we are safe to just increment program_counter bcs on last instruction + // it will do noop and just stop execution of this contract + self.bytecode.relative_jump(1); + + let instruction = unsafe { instruction_table.get_unchecked(opcode as usize) }; + + if self.gas.record_cost_unsafe(instruction.static_gas()) { + return self.halt_oog(); + } let context = InstructionContext { interpreter: self, host, }; - context.step(instruction_table); + instruction.execute(context); } /// Executes the instruction at the current instruction pointer. @@ -237,41 +292,41 @@ impl Interpreter { /// This uses dummy Host. #[inline] pub fn step_dummy(&mut self, instruction_table: &InstructionTable) { - let context = InstructionContext { - interpreter: self, - host: &mut DummyHost, - }; - context.step(instruction_table); + self.step(instruction_table, &mut DummyHost); } /// Executes the interpreter until it returns or stops. #[inline] - pub fn run_plain( + pub fn run_plain( &mut self, instruction_table: &InstructionTable, host: &mut H, ) -> InterpreterAction { while self.bytecode.is_not_end() { - // Get current opcode. - let opcode = self.bytecode.opcode(); - - // SAFETY: In analysis we are doing padding of bytecode so that we are sure that last - // byte instruction is STOP so we are safe to just increment program_counter bcs on last instruction - // it will do noop and just stop execution of this contract - self.bytecode.relative_jump(1); - let context = InstructionContext { - interpreter: self, - host, - }; - // Execute instruction. - instruction_table[opcode as usize](context); + self.step(instruction_table, host); } - self.bytecode.revert_to_previous_pointer(); - self.take_next_action() } } +/* used for cargo asm +pub fn asm_step( + interpreter: &mut Interpreter, + instruction_table: &InstructionTable, + host: &mut DummyHost, +) { + interpreter.step(instruction_table, host); +} + +pub fn asm_run( + interpreter: &mut Interpreter, + instruction_table: &InstructionTable, + host: &mut DummyHost, +) { + interpreter.run_plain(instruction_table, host); +} +*/ + /// The result of an interpreter operation. #[derive(Clone, Debug, PartialEq, Eq)] #[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))] diff --git a/crates/interpreter/src/interpreter/ext_bytecode.rs b/crates/interpreter/src/interpreter/ext_bytecode.rs index ede6bfcb02..bbfc7030bf 100644 --- a/crates/interpreter/src/interpreter/ext_bytecode.rs +++ b/crates/interpreter/src/interpreter/ext_bytecode.rs @@ -1,7 +1,7 @@ use super::{Immediates, Jumps, LegacyBytecode}; use crate::{interpreter_types::LoopControl, InterpreterAction}; use bytecode::{utils::read_u16, Bytecode}; -use core::{ops::Deref, ptr}; +use core::ops::Deref; use primitives::B256; #[cfg(feature = "serde")] @@ -10,16 +10,19 @@ mod serde; /// Extended bytecode structure that wraps base bytecode with additional execution metadata. #[derive(Debug)] pub struct ExtBytecode { + /// The current instruction pointer. + instruction_pointer: *const u8, + /// Whether the execution should continue. + continue_execution: bool, + /// Bytecode Keccak-256 hash. + /// This is `None` if it hasn't been calculated yet. + /// Since it's not necessary for execution, it's not calculated by default. bytecode_hash: Option, /// Actions that the EVM should do. It contains return value of the Interpreter or inputs for `CALL` or `CREATE` instructions. /// For `RETURN` or `REVERT` instructions it contains the result of the instruction. pub action: Option, /// The base bytecode. base: Bytecode, - /// The previous instruction pointer. - previous_pointer: Option<*const u8>, - /// The current instruction pointer. - instruction_pointer: *const u8, } impl Deref for ExtBytecode { @@ -39,63 +42,91 @@ impl Default for ExtBytecode { impl ExtBytecode { /// Create new extended bytecode and set the instruction pointer to the start of the bytecode. + /// + /// The bytecode hash will not be calculated. #[inline] pub fn new(base: Bytecode) -> Self { - let instruction_pointer = base.bytecode_ptr(); - Self { - base, - instruction_pointer, - bytecode_hash: None, - action: None, - previous_pointer: None, - } + Self::new_with_optional_hash(base, None) } /// Creates new `ExtBytecode` with the given hash. + #[inline] pub fn new_with_hash(base: Bytecode, hash: B256) -> Self { + Self::new_with_optional_hash(base, Some(hash)) + } + + /// Creates new `ExtBytecode` with the given hash. + #[inline] + pub fn new_with_optional_hash(base: Bytecode, hash: Option) -> Self { let instruction_pointer = base.bytecode_ptr(); Self { base, instruction_pointer, - bytecode_hash: Some(hash), + bytecode_hash: hash, action: None, - previous_pointer: None, + continue_execution: true, } } /// Regenerates the bytecode hash. + #[inline] + #[deprecated(note = "use `get_or_calculate_hash` or `calculate_hash` instead")] + #[doc(hidden)] pub fn regenerate_hash(&mut self) -> B256 { + self.calculate_hash() + } + + /// Re-calculates the bytecode hash. + /// + /// Prefer [`get_or_calculate_hash`](Self::get_or_calculate_hash) if you just need to get the hash. + #[inline] + pub fn calculate_hash(&mut self) -> B256 { let hash = self.base.hash_slow(); self.bytecode_hash = Some(hash); hash } /// Returns the bytecode hash. + #[inline] pub fn hash(&mut self) -> Option { self.bytecode_hash } + + /// Returns the bytecode hash or calculates it if it is not set. + #[inline] + pub fn get_or_calculate_hash(&mut self) -> B256 { + *self.bytecode_hash.get_or_insert_with( + #[cold] + || self.base.hash_slow(), + ) + } } impl LoopControl for ExtBytecode { #[inline] - fn is_end(&self) -> bool { - self.instruction_pointer.is_null() + fn is_not_end(&self) -> bool { + self.continue_execution } #[inline] - fn revert_to_previous_pointer(&mut self) { - if let Some(previous_pointer) = self.previous_pointer { - self.instruction_pointer = previous_pointer; - } + fn reset_action(&mut self) { + self.continue_execution = true; } #[inline] fn set_action(&mut self, action: InterpreterAction) { + debug_assert_eq!( + !self.continue_execution, + self.action.is_some(), + "has_set_action out of sync" + ); + debug_assert!( + self.continue_execution, + "action already set;\nold: {:#?}\nnew: {:#?}", + self.action, action, + ); + self.continue_execution = false; self.action = Some(action); - self.previous_pointer = Some(core::mem::replace( - &mut self.instruction_pointer, - ptr::null(), - )); } #[inline] diff --git a/crates/interpreter/src/interpreter/ext_bytecode/serde.rs b/crates/interpreter/src/interpreter/ext_bytecode/serde.rs index c627200912..8c5457e361 100644 --- a/crates/interpreter/src/interpreter/ext_bytecode/serde.rs +++ b/crates/interpreter/src/interpreter/ext_bytecode/serde.rs @@ -2,10 +2,12 @@ use super::ExtBytecode; use crate::interpreter::Jumps; use primitives::B256; use serde::{Deserialize, Deserializer, Serialize, Serializer}; +use std::borrow::Cow; +use std::format; #[derive(Serialize, Deserialize)] -struct ExtBytecodeSerde { - base: bytecode::Bytecode, +struct ExtBytecodeSerde<'a> { + base: Cow<'a, bytecode::Bytecode>, program_counter: usize, bytecode_hash: Option, } @@ -16,7 +18,7 @@ impl Serialize for ExtBytecode { S: Serializer, { ExtBytecodeSerde { - base: self.base.clone(), + base: Cow::Borrowed(&self.base), program_counter: self.pc(), bytecode_hash: self.bytecode_hash, } @@ -34,15 +36,12 @@ impl<'de> Deserialize<'de> for ExtBytecode { program_counter, bytecode_hash, } = ExtBytecodeSerde::deserialize(deserializer)?; - - let mut bytecode = if let Some(hash) = bytecode_hash { - Self::new_with_hash(base, hash) - } else { - Self::new(base) - }; - - if program_counter >= bytecode.base.bytecode().len() { - panic!("serde pc: {program_counter} is greater than or equal to bytecode len"); + let mut bytecode = Self::new_with_optional_hash(base.into_owned(), bytecode_hash); + let len = bytecode.base.bytecode().len(); + if program_counter >= len { + return Err(serde::de::Error::custom(format!( + "program counter ({program_counter}) exceeds bytecode length ({len})" + ))); } bytecode.absolute_jump(program_counter); Ok(bytecode) diff --git a/crates/interpreter/src/interpreter/stack.rs b/crates/interpreter/src/interpreter/stack.rs index c835a0202a..ae675fea20 100644 --- a/crates/interpreter/src/interpreter/stack.rs +++ b/crates/interpreter/src/interpreter/stack.rs @@ -422,7 +422,7 @@ mod tests { // No-op run(|stack| { stack.push_slice(b"").unwrap(); - assert_eq!(stack.data, []); + assert!(stack.data.is_empty()); }); // One word diff --git a/crates/interpreter/src/interpreter/subroutine_stack.rs b/crates/interpreter/src/interpreter/subroutine_stack.rs deleted file mode 100644 index 9c39d5b4ee..0000000000 --- a/crates/interpreter/src/interpreter/subroutine_stack.rs +++ /dev/null @@ -1,101 +0,0 @@ -use std::vec::Vec; - -use crate::interpreter_types::SubRoutineStack; - -/// Function(Sub Routine) return frame in eof -/// -/// Needed information for returning from a function. -#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct SubRoutineReturnFrame { - /// The index of the code container that this frame is executing. - pub idx: usize, - /// The program counter where frame execution should continue. - pub pc: usize, -} - -impl SubRoutineReturnFrame { - /// Return new function frame. - pub fn new(idx: usize, pc: usize) -> Self { - Self { idx, pc } - } -} - -/// Function Stack -#[derive(Clone, Debug, Default, PartialEq, Eq)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct SubRoutineImpl { - /// Stack of return frames for managing nested subroutine calls - pub return_stack: Vec, - /// Index of the currently executing code section - pub current_code_idx: usize, -} - -impl SubRoutineImpl { - /// Returns new function stack. - pub fn new() -> Self { - Self { - return_stack: Vec::new(), - current_code_idx: 0, - } - } - - /// Clears the function stack. - pub fn clear(&mut self) { - self.return_stack.clear(); - self.current_code_idx = 0; - } - - /// Returns the number of subroutine frames on the stack. - pub fn len(&self) -> usize { - self.return_stack.len() - } - - /// Returns true if the subroutine stack is empty. - pub fn is_empty(&self) -> bool { - self.return_stack.is_empty() - } - - /// Return stack length - pub fn return_stack_len(&self) -> usize { - self.return_stack.len() - } - - /// Sets current_code_idx, this is needed for JUMPF opcode. - pub fn set_current_code_idx(&mut self, idx: usize) { - self.current_code_idx = idx; - } -} - -impl SubRoutineStack for SubRoutineImpl { - fn len(&self) -> usize { - self.return_stack.len() - } - - fn routine_idx(&self) -> usize { - self.current_code_idx - } - - fn push(&mut self, program_counter: usize, new_idx: usize) -> bool { - if self.return_stack.len() >= 1024 { - return false; - } - self.return_stack.push(SubRoutineReturnFrame { - idx: self.current_code_idx, - pc: program_counter, - }); - self.current_code_idx = new_idx; - true - } - - fn pop(&mut self) -> Option { - self.return_stack.pop().map(|i| { - self.current_code_idx = i.idx; - i.pc - }) - } - - fn set_routine_idx(&mut self, idx: usize) { - self.current_code_idx = idx; - } -} diff --git a/crates/interpreter/src/interpreter_action.rs b/crates/interpreter/src/interpreter_action.rs index 08743e8885..83cf29741f 100644 --- a/crates/interpreter/src/interpreter_action.rs +++ b/crates/interpreter/src/interpreter_action.rs @@ -54,23 +54,36 @@ pub enum InterpreterAction { impl InterpreterAction { /// Returns `true` if action is call. + #[inline] pub fn is_call(&self) -> bool { matches!(self, InterpreterAction::NewFrame(FrameInput::Call(..))) } /// Returns `true` if action is create. + #[inline] pub fn is_create(&self) -> bool { matches!(self, InterpreterAction::NewFrame(FrameInput::Create(..))) } /// Returns `true` if action is return. + #[inline] pub fn is_return(&self) -> bool { matches!(self, InterpreterAction::Return { .. }) } + /// Returns [`Gas`] if action is return. + #[inline] + pub fn gas_mut(&mut self) -> Option<&mut Gas> { + match self { + InterpreterAction::Return(result) => Some(&mut result.gas), + _ => None, + } + } + /// Returns [`InterpreterResult`] if action is return. /// /// Else it returns [None]. + #[inline] pub fn into_result_return(self) -> Option { match self { InterpreterAction::Return(result) => Some(result), @@ -81,6 +94,7 @@ impl InterpreterAction { /// Returns [`InstructionResult`] if action is return. /// /// Else it returns [None]. + #[inline] pub fn instruction_result(&self) -> Option { match self { InterpreterAction::Return(result) => Some(result.result), @@ -89,21 +103,25 @@ impl InterpreterAction { } /// Create new frame action with the given frame input. + #[inline] pub fn new_frame(frame_input: FrameInput) -> Self { Self::NewFrame(frame_input) } /// Create new halt action with the given result and gas. + #[inline] pub fn new_halt(result: InstructionResult, gas: Gas) -> Self { Self::Return(InterpreterResult::new(result, Bytes::new(), gas)) } /// Create new return action with the given result, output and gas. + #[inline] pub fn new_return(result: InstructionResult, output: Bytes, gas: Gas) -> Self { Self::Return(InterpreterResult::new(result, output, gas)) } /// Create new stop action. + #[inline] pub fn new_stop() -> Self { Self::Return(InterpreterResult::new( InstructionResult::Stop, diff --git a/crates/interpreter/src/interpreter_types.rs b/crates/interpreter/src/interpreter_types.rs index 810d1eec62..4c152336a3 100644 --- a/crates/interpreter/src/interpreter_types.rs +++ b/crates/interpreter/src/interpreter_types.rs @@ -248,21 +248,17 @@ pub trait ReturnData { /// Trait controls execution of the loop. pub trait LoopControl { /// Returns `true` if the loop should continue. + fn is_not_end(&self) -> bool; + /// Is end of the loop. #[inline] - fn is_not_end(&self) -> bool { - !self.is_end() + fn is_end(&self) -> bool { + !self.is_not_end() } - /// Is end of the loop. - fn is_end(&self) -> bool; - /// Reverts to previous instruction pointer. - /// - /// After the loop is finished, the instruction pointer is set to the previous one. - fn revert_to_previous_pointer(&mut self); - /// Set return action and set instruction pointer to null. Preserve previous pointer - /// - /// Previous pointer can be restored by calling [`LoopControl::revert_to_previous_pointer`]. + /// Sets the `end` flag internally. Action should be taken after. + fn reset_action(&mut self); + /// Set return action. fn set_action(&mut self, action: InterpreterAction); - /// Takes next action. + /// Returns the current action. fn action(&mut self) -> &mut Option; /// Returns instruction result #[inline] diff --git a/crates/interpreter/src/lib.rs b/crates/interpreter/src/lib.rs index e860126833..8c0a6b87b1 100644 --- a/crates/interpreter/src/lib.rs +++ b/crates/interpreter/src/lib.rs @@ -43,4 +43,3 @@ pub use interpreter_action::{ FrameInput, InterpreterAction, }; pub use interpreter_types::InterpreterTypes; -pub use primitives::{eip7907::MAX_CODE_SIZE, eip7907::MAX_INITCODE_SIZE}; diff --git a/crates/interpreter/src/macros.rs b/crates/interpreter/src/macros.rs index 7b28fdefd6..004d940122 100644 --- a/crates/interpreter/src/macros.rs +++ b/crates/interpreter/src/macros.rs @@ -1,6 +1,7 @@ /// Macro that triggers `unreachable!` in debug builds but uses unchecked unreachable in release builds. /// This provides better error messages during development while optimizing for performance in release. #[macro_export] +#[collapse_debuginfo(yes)] macro_rules! debug_unreachable { ($($t:tt)*) => { if cfg!(debug_assertions) { @@ -15,6 +16,7 @@ macro_rules! debug_unreachable { /// In debug builds, this will trigger unreachable code if the assumption is false. /// In release builds, this serves as an optimization hint. #[macro_export] +#[collapse_debuginfo(yes)] macro_rules! assume { ($e:expr $(,)?) => { if !$e { diff --git a/crates/op-revm/CHANGELOG.md b/crates/op-revm/CHANGELOG.md index bc9d37965e..3486bf1404 100644 --- a/crates/op-revm/CHANGELOG.md +++ b/crates/op-revm/CHANGELOG.md @@ -7,6 +7,48 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [10.0.0](https://github.com/bluealloy/revm/compare/op-revm-v9.0.1...op-revm-v10.0.0) - 2025-08-23 + +### Added + +- *(fusaka)* Add PrecompileId ([#2904](https://github.com/bluealloy/revm/pull/2904)) + +### Fixed + +- *(handler)* correct transaction ID decrement logic ([#2892](https://github.com/bluealloy/revm/pull/2892)) + +## [9.0.1](https://github.com/bluealloy/revm/compare/op-revm-v9.0.0...op-revm-v9.0.1) - 2025-08-12 + +### Other + +- updated the following local packages: revm + +## [9.0.0](https://github.com/bluealloy/revm/compare/op-revm-v8.1.0...op-revm-v9.0.0) - 2025-08-06 + +### Added + +- fix renamed functions for system_call ([#2824](https://github.com/bluealloy/revm/pull/2824)) +- refactor test utils ([#2813](https://github.com/bluealloy/revm/pull/2813)) +- add system transaction inspection support ([#2808](https://github.com/bluealloy/revm/pull/2808)) +- Align naming of SystemCallEvm function to ExecuteEvm ([#2814](https://github.com/bluealloy/revm/pull/2814)) +- rename bn128 to bn254 for Ethereum standard consistency ([#2810](https://github.com/bluealloy/revm/pull/2810)) + +### Fixed + +- *(op-revm)* system tx not enveloped ([#2807](https://github.com/bluealloy/revm/pull/2807)) +- nonce changed is not reverted in journal if fail due to insufficient balance ([#2805](https://github.com/bluealloy/revm/pull/2805)) + +### Other + +- update README.md ([#2842](https://github.com/bluealloy/revm/pull/2842)) +- *(op-revm)* Adds caller nonce assertion to op-revm intergation tests ([#2815](https://github.com/bluealloy/revm/pull/2815)) +- *(op-revm)* Full test coverage `OpTransactionError` ([#2818](https://github.com/bluealloy/revm/pull/2818)) +- Update test data for renamed tests ([#2817](https://github.com/bluealloy/revm/pull/2817)) +- reuse global crypto provide idea ([#2786](https://github.com/bluealloy/revm/pull/2786)) +- add rust-version and note about MSRV ([#2789](https://github.com/bluealloy/revm/pull/2789)) +- add OnceLock re-export with no_std support ([#2787](https://github.com/bluealloy/revm/pull/2787)) +- Add dyn Crypto trait to PrecompileFn ([#2772](https://github.com/bluealloy/revm/pull/2772)) + ## [8.1.0](https://github.com/bluealloy/revm/compare/op-revm-v8.0.3...op-revm-v8.1.0) - 2025-07-23 ### Added diff --git a/crates/op-revm/Cargo.toml b/crates/op-revm/Cargo.toml index 5b8f39ae75..9565a3beca 100644 --- a/crates/op-revm/Cargo.toml +++ b/crates/op-revm/Cargo.toml @@ -1,13 +1,14 @@ [package] name = "op-revm" description = "Optimism variant of Revm" -version = "8.1.0" +version = "10.0.0" authors.workspace = true edition.workspace = true keywords.workspace = true license.workspace = true repository.workspace = true readme.workspace = true +rust-version.workspace = true [package.metadata.docs.rs] all-features = true @@ -21,9 +22,6 @@ workspace = true revm.workspace = true auto_impl.workspace = true -# static precompile sets. -once_cell = { workspace = true, features = ["alloc"] } - # Optional serde = { workspace = true, features = ["derive", "rc"], optional = true } @@ -32,8 +30,8 @@ rstest.workspace = true alloy-sol-types.workspace = true sha2.workspace = true serde_json = { workspace = true, features = ["alloc", "preserve_order"] } -alloy-primitives.workspace = true serde = { workspace = true, features = ["derive"] } +alloy-primitives.workspace = true [features] default = ["std", "c-kzg", "secp256k1", "portable", "blst"] @@ -41,7 +39,6 @@ std = [ "serde?/std", "revm/std", "alloy-sol-types/std", - "once_cell/std", "sha2/std", "serde_json/std", "alloy-primitives/std", diff --git a/crates/op-revm/src/api/exec.rs b/crates/op-revm/src/api/exec.rs index a5ddec95b6..9c460bdcac 100644 --- a/crates/op-revm/src/api/exec.rs +++ b/crates/op-revm/src/api/exec.rs @@ -13,7 +13,9 @@ use revm::{ instructions::EthInstructions, system_call::SystemCallEvm, EthFrame, Handler, PrecompileProvider, SystemCallTx, }, - inspector::{InspectCommitEvm, InspectEvm, Inspector, InspectorHandler, JournalExt}, + inspector::{ + InspectCommitEvm, InspectEvm, InspectSystemCallEvm, Inspector, InspectorHandler, JournalExt, + }, interpreter::{interpreter::EthInterpreter, InterpreterResult}, primitives::{Address, Bytes}, state::EvmState, @@ -127,7 +129,7 @@ where CTX: OpContextTr + ContextSetters, PRECOMPILE: PrecompileProvider, { - fn transact_system_call_with_caller( + fn system_call_one_with_caller( &mut self, caller: Address, system_contract_address: Address, @@ -142,3 +144,26 @@ where h.run_system_call(self) } } + +impl InspectSystemCallEvm + for OpEvm, PRECOMPILE> +where + CTX: OpContextTr + ContextSetters, + INSP: Inspector, + PRECOMPILE: PrecompileProvider, +{ + fn inspect_one_system_call_with_caller( + &mut self, + caller: Address, + system_contract_address: Address, + data: Bytes, + ) -> Result { + self.0.ctx.set_tx(CTX::Tx::new_system_tx_with_caller( + caller, + system_contract_address, + data, + )); + let mut h = OpHandler::<_, _, EthFrame>::new(); + h.inspect_run_system_call(self) + } +} diff --git a/crates/op-revm/src/handler.rs b/crates/op-revm/src/handler.rs index e696aba055..f70421fc72 100644 --- a/crates/op-revm/src/handler.rs +++ b/crates/op-revm/src/handler.rs @@ -157,11 +157,6 @@ where )?; } - // Bump the nonce for calls. Nonce for CREATE will be bumped in `handle_create`. - if tx.kind().is_call() { - caller_account.info.nonce = caller_account.info.nonce.saturating_add(1); - } - let max_balance_spending = tx.max_balance_spending()?.saturating_add(additional_cost); // old balance is journaled before mint is incremented. @@ -210,6 +205,11 @@ where caller_account.mark_touch(); caller_account.info.balance = new_balance; + // Bump the nonce for calls. Nonce for CREATE will be bumped in `handle_create`. + if tx.kind().is_call() { + caller_account.info.nonce = caller_account.info.nonce.saturating_add(1); + } + // NOTE: all changes to the caller account should journaled so in case of error // we can revert the changes. journal.caller_accounting_journal_entry(tx.caller(), old_balance, tx.kind().is_call()); @@ -436,7 +436,7 @@ where let old_balance = acc.info.balance; // decrement transaction id as it was incremented when we discarded the tx. - acc.transaction_id -= acc.transaction_id; + acc.transaction_id -= 1; acc.info.nonce = acc.info.nonce.saturating_add(1); acc.info.balance = acc .info @@ -1109,4 +1109,37 @@ mod tests { let account = evm.ctx().journal_mut().load_account(SENDER).unwrap(); assert_eq!(account.info.balance, expected_refund); } + + #[test] + fn test_tx_low_balance_nonce_unchanged() { + let ctx = Context::op().with_tx( + OpTransaction::builder() + .base(TxEnv::builder().value(U256::from(1000))) + .build_fill(), + ); + + let mut evm = ctx.build_op(); + + let handler = + OpHandler::<_, EVMError<_, OpTransactionError>, EthFrame>::new(); + + let result = handler.validate_against_state_and_deduct_caller(&mut evm); + + assert!(matches!( + result.err().unwrap(), + EVMError::Transaction(OpTransactionError::Base( + InvalidTransaction::LackOfFundForMaxFee { .. } + )) + )); + assert_eq!( + evm.0 + .ctx + .journal_mut() + .load_account(Address::ZERO) + .unwrap() + .info + .nonce, + 0 + ); + } } diff --git a/crates/op-revm/src/precompiles.rs b/crates/op-revm/src/precompiles.rs index d29e566765..579ceb30c8 100644 --- a/crates/op-revm/src/precompiles.rs +++ b/crates/op-revm/src/precompiles.rs @@ -1,16 +1,15 @@ //! Contains Optimism specific precompiles. use crate::OpSpecId; -use once_cell::race::OnceBox; use revm::{ context::Cfg, context_interface::ContextTr, handler::{EthPrecompiles, PrecompileProvider}, interpreter::{InputsImpl, InterpreterResult}, precompile::{ - self, bn128, secp256r1, PrecompileError, PrecompileResult, PrecompileWithAddress, + self, bn254, secp256r1, Precompile, PrecompileError, PrecompileId, PrecompileResult, Precompiles, }, - primitives::{hardfork::SpecId, Address}, + primitives::{hardfork::SpecId, Address, OnceLock}, }; use std::boxed::Box; use std::string::String; @@ -56,29 +55,29 @@ impl OpPrecompiles { /// Returns precompiles for Fjord spec. pub fn fjord() -> &'static Precompiles { - static INSTANCE: OnceBox = OnceBox::new(); + static INSTANCE: OnceLock = OnceLock::new(); INSTANCE.get_or_init(|| { let mut precompiles = Precompiles::cancun().clone(); // RIP-7212: secp256r1 P256verify precompiles.extend([secp256r1::P256VERIFY]); - Box::new(precompiles) + precompiles }) } /// Returns precompiles for Granite spec. pub fn granite() -> &'static Precompiles { - static INSTANCE: OnceBox = OnceBox::new(); + static INSTANCE: OnceLock = OnceLock::new(); INSTANCE.get_or_init(|| { let mut precompiles = fjord().clone(); - // Restrict bn256Pairing input size - precompiles.extend([bn128_pair::GRANITE]); - Box::new(precompiles) + // Restrict bn254Pairing input size + precompiles.extend([bn254_pair::GRANITE]); + precompiles }) } /// Returns precompiles for isthumus spec. pub fn isthmus() -> &'static Precompiles { - static INSTANCE: OnceBox = OnceBox::new(); + static INSTANCE: OnceLock = OnceLock::new(); INSTANCE.get_or_init(|| { let mut precompiles = granite().clone(); // Prague bls12 precompiles @@ -89,7 +88,7 @@ pub fn isthmus() -> &'static Precompiles { bls12_381::ISTHMUS_G2_MSM, bls12_381::ISTHMUS_PAIRING, ]); - Box::new(precompiles) + precompiles }) } @@ -138,27 +137,25 @@ impl Default for OpPrecompiles { } } -/// Bn128 pair precompile. -pub mod bn128_pair { +/// Bn254 pair precompile. +pub mod bn254_pair { use super::*; - /// Max input size for the bn128 pair precompile. + /// Max input size for the bn254 pair precompile. pub const GRANITE_MAX_INPUT_SIZE: usize = 112687; - /// Bn128 pair precompile. - pub const GRANITE: PrecompileWithAddress = - PrecompileWithAddress(bn128::pair::ADDRESS, |input, gas_limit| { - run_pair(input, gas_limit) - }); + /// Bn254 pair precompile. + pub const GRANITE: Precompile = + Precompile::new(PrecompileId::Bn254Pairing, bn254::pair::ADDRESS, run_pair); - /// Run the bn128 pair precompile with Optimism input limit. + /// Run the bn254 pair precompile with Optimism input limit. pub fn run_pair(input: &[u8], gas_limit: u64) -> PrecompileResult { if input.len() > GRANITE_MAX_INPUT_SIZE { - return Err(PrecompileError::Bn128PairLength); + return Err(PrecompileError::Bn254PairLength); } - bn128::run_pair( + bn254::run_pair( input, - bn128::pair::ISTANBUL_PAIR_PER_POINT, - bn128::pair::ISTANBUL_PAIR_BASE, + bn254::pair::ISTANBUL_PAIR_PER_POINT, + bn254::pair::ISTANBUL_PAIR_BASE, gas_limit, ) } @@ -180,14 +177,14 @@ pub mod bls12_381 { pub const ISTHMUS_PAIRING_MAX_INPUT_SIZE: usize = 235008; /// G1 msm precompile. - pub const ISTHMUS_G1_MSM: PrecompileWithAddress = - PrecompileWithAddress(G1_MSM_ADDRESS, run_g1_msm); + pub const ISTHMUS_G1_MSM: Precompile = + Precompile::new(PrecompileId::Bls12G1Msm, G1_MSM_ADDRESS, run_g1_msm); /// G2 msm precompile. - pub const ISTHMUS_G2_MSM: PrecompileWithAddress = - PrecompileWithAddress(G2_MSM_ADDRESS, run_g2_msm); + pub const ISTHMUS_G2_MSM: Precompile = + Precompile::new(PrecompileId::Bls12G2Msm, G2_MSM_ADDRESS, run_g2_msm); /// Pairing precompile. - pub const ISTHMUS_PAIRING: PrecompileWithAddress = - PrecompileWithAddress(PAIRING_ADDRESS, run_pair); + pub const ISTHMUS_PAIRING: Precompile = + Precompile::new(PrecompileId::Bls12Pairing, PAIRING_ADDRESS, run_pair); /// Run the g1 msm precompile with Optimism input limit. pub fn run_g1_msm(input: &[u8], gas_limit: u64) -> PrecompileResult { @@ -235,7 +232,7 @@ mod tests { use std::vec; #[test] - fn test_bn128_pair() { + fn test_bn254_pair() { let input = hex::decode( "\ 1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f59\ @@ -255,7 +252,7 @@ mod tests { let expected = hex::decode("0000000000000000000000000000000000000000000000000000000000000001") .unwrap(); - let outcome = bn128_pair::run_pair(&input, 260_000).unwrap(); + let outcome = bn254_pair::run_pair(&input, 260_000).unwrap(); assert_eq!(outcome.bytes, expected); // Invalid input length @@ -268,18 +265,18 @@ mod tests { ) .unwrap(); - let res = bn128_pair::run_pair(&input, 260_000); - assert!(matches!(res, Err(PrecompileError::Bn128PairLength))); + let res = bn254_pair::run_pair(&input, 260_000); + assert!(matches!(res, Err(PrecompileError::Bn254PairLength))); // Valid input length shorter than 112687 - let input = vec![1u8; 586 * bn128::PAIR_ELEMENT_LEN]; - let res = bn128_pair::run_pair(&input, 260_000); + let input = vec![1u8; 586 * bn254::PAIR_ELEMENT_LEN]; + let res = bn254_pair::run_pair(&input, 260_000); assert!(matches!(res, Err(PrecompileError::OutOfGas))); // Input length longer than 112687 - let input = vec![1u8; 587 * bn128::PAIR_ELEMENT_LEN]; - let res = bn128_pair::run_pair(&input, 260_000); - assert!(matches!(res, Err(PrecompileError::Bn128PairLength))); + let input = vec![1u8; 587 * bn254::PAIR_ELEMENT_LEN]; + let res = bn254_pair::run_pair(&input, 260_000); + assert!(matches!(res, Err(PrecompileError::Bn254PairLength))); } #[test] @@ -291,7 +288,7 @@ mod tests { #[test] fn test_cancun_precompiles_in_granite() { // granite has p256verify (fjord) - // granite has modification of cancun's bn128 pair (doesn't count as new precompile) + // granite has modification of cancun's bn254 pair (doesn't count as new precompile) assert_eq!(granite().difference(Precompiles::cancun()).len(), 1) } diff --git a/crates/op-revm/src/transaction/abstraction.rs b/crates/op-revm/src/transaction/abstraction.rs index 65b50e3ddd..2043f1ca0a 100644 --- a/crates/op-revm/src/transaction/abstraction.rs +++ b/crates/op-revm/src/transaction/abstraction.rs @@ -89,11 +89,15 @@ impl SystemCallTx for OpTransaction { system_contract_address: Address, data: Bytes, ) -> Self { - OpTransaction::new(TX::new_system_tx_with_caller( + let mut tx = OpTransaction::new(TX::new_system_tx_with_caller( caller, system_contract_address, data, - )) + )); + + tx.enveloped_tx = Some(Bytes::default()); + + tx } } diff --git a/crates/op-revm/src/transaction/error.rs b/crates/op-revm/src/transaction/error.rs index 76169a3dd8..ba13cab90e 100644 --- a/crates/op-revm/src/transaction/error.rs +++ b/crates/op-revm/src/transaction/error.rs @@ -18,7 +18,7 @@ pub enum OpTransactionError { /// was deprecated in the Regolith hardfork, and this error is thrown if a `Deposit` transaction /// is found with this field set to `true` after the hardfork activation. /// - /// In addition, this error is internal, and bubbles up into a [OpHaltReason::FailedDeposit][crate::OpHaltReason::FailedDeposit] error + /// In addition, this error is internal, and bubbles up into an [OpHaltReason::FailedDeposit][crate::OpHaltReason::FailedDeposit] error /// in the `revm` handler for the consumer to easily handle. This is due to a state transition /// rule on OP Stack chains where, if for any reason a deposit transaction fails, the transaction /// must still be included in the block, the sender nonce is bumped, the `mint` value persists, and @@ -26,14 +26,14 @@ pub enum OpTransactionError { /// are cause for non-inclusion, so a special [OpHaltReason][crate::OpHaltReason] variant was introduced to handle this /// case for failed deposit transactions. DepositSystemTxPostRegolith, - /// Deposit transaction haults bubble up to the global main return handler, wiping state and + /// Deposit transaction halts bubble up to the global main return handler, wiping state and /// only increasing the nonce + persisting the mint value. /// - /// This is a catch-all error for any deposit transaction that is results in a [OpHaltReason][crate::OpHaltReason] error + /// This is a catch-all error for any deposit transaction that results in an [OpHaltReason][crate::OpHaltReason] error /// post-regolith hardfork. This allows for a consumer to easily handle special cases where /// a deposit transaction fails during validation, but must still be included in the block. /// - /// In addition, this error is internal, and bubbles up into a [OpHaltReason::FailedDeposit][crate::OpHaltReason::FailedDeposit] error + /// In addition, this error is internal, and bubbles up into an [OpHaltReason::FailedDeposit][crate::OpHaltReason::FailedDeposit] error /// in the `revm` handler for the consumer to easily handle. This is due to a state transition /// rule on OP Stack chains where, if for any reason a deposit transaction fails, the transaction /// must still be included in the block, the sender nonce is bumped, the `mint` value persists, and @@ -86,6 +86,11 @@ mod test { #[test] fn test_display_op_errors() { + assert_eq!( + OpTransactionError::Base(InvalidTransaction::NonceTooHigh { tx: 2, state: 1 }) + .to_string(), + "nonce 2 too high, expected 1" + ); assert_eq!( OpTransactionError::DepositSystemTxPostRegolith.to_string(), "deposit system transactions post regolith hardfork are not supported" diff --git a/crates/op-revm/tests/common.rs b/crates/op-revm/tests/common.rs deleted file mode 100644 index bca6e97ec5..0000000000 --- a/crates/op-revm/tests/common.rs +++ /dev/null @@ -1,111 +0,0 @@ -//! Common test utilities used to compare execution results against testdata. -#![allow(dead_code)] - -use revm::{ - context::result::ResultAndState, - context_interface::result::{ExecutionResult, HaltReason, Output, SuccessReason}, - primitives::Bytes, - state::EvmState, -}; - -// Constant for testdata directory path -pub(crate) const TESTS_TESTDATA: &str = "tests/testdata"; - -#[cfg(not(feature = "serde"))] -pub(crate) fn compare_or_save_testdata( - _filename: &str, - _output: &ResultAndState, -) { - // serde needs to be enabled to use this function -} - -/// Compares or saves the execution output to a testdata file. -/// -/// This utility helps maintain consistent test behavior by comparing -/// execution results against known-good outputs stored in JSON files. -/// -/// # Arguments -/// -/// * `filename` - The name of the testdata file, relative to tests/testdata/ -/// * `output` - The execution output to compare or save -/// -/// # Returns -/// -/// `Ok(())` if the comparison or save was successful -/// `Err(anyhow::Error)` if there was an error -/// -/// # Note -/// -/// Tests using this function require the `serde` feature to be enabled: -/// ```bash -/// cargo test --features serde -/// ``` -#[cfg(feature = "serde")] -pub(crate) fn compare_or_save_testdata( - filename: &str, - output: &ResultAndState, -) where - HaltReasonTy: serde::Serialize + for<'a> serde::Deserialize<'a> + PartialEq, -{ - use std::{fs, path::PathBuf}; - - let tests_dir = PathBuf::from(TESTS_TESTDATA); - let testdata_file = tests_dir.join(filename); - - // Create directory if it doesn't exist - if !tests_dir.exists() { - fs::create_dir_all(&tests_dir).unwrap(); - } - - // Serialize the output to JSON for saving - let output_json = serde_json::to_string_pretty(output).unwrap(); - - // If the testdata file doesn't exist, save the output - if !testdata_file.exists() { - fs::write(&testdata_file, &output_json).unwrap(); - println!("Saved testdata to {}", testdata_file.display()); - return; - } - - // Read the expected output from the testdata file - let expected_json = fs::read_to_string(&testdata_file).unwrap(); - - // Deserialize to actual ResultAndState object for proper comparison - let expected = serde_json::from_str(&expected_json).unwrap(); - - // Compare the output objects directly - if output != &expected { - // If they don't match, generate a nicer error by pretty-printing both as JSON - // This helps with debugging by showing the exact differences - let expected_pretty = serde_json::to_string_pretty(&expected).unwrap(); - - panic!( - "Value does not match testdata.\nExpected:\n{expected_pretty}\n\nActual:\n{output_json}", - ); - } -} - -/// Example showing how to migrate an existing test to use the testdata comparison. -/// -/// This example consists of: -/// 1. The "original" test with standard assertions -/// 2. The migration approach - running assertions and saving testdata -/// 3. The final migrated test that only uses testdata comparison -#[test] -fn template_test() { - // Create a minimal result and state - let result = ResultAndState::new( - ExecutionResult::Success { - reason: SuccessReason::Stop, - gas_used: 1000, - gas_refunded: 0, - logs: vec![], - output: Output::Call(Bytes::from(vec![4, 5, 6])), - }, - EvmState::default(), - ); - - // Simply use the testdata comparison utility - // No assertions needed - full validation is done by comparing with testdata - compare_or_save_testdata::("template_test.json", &result); -} diff --git a/crates/op-revm/tests/testdata/template_test.json b/crates/op-revm/tests/testdata/template_test.json deleted file mode 100644 index 5c35711ddd..0000000000 --- a/crates/op-revm/tests/testdata/template_test.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "result": { - "Success": { - "reason": "Stop", - "gas_used": 1000, - "gas_refunded": 0, - "logs": [], - "output": { - "Call": "0x040506" - } - } - }, - "state": {} -} \ No newline at end of file diff --git a/crates/precompile/CHANGELOG.md b/crates/precompile/CHANGELOG.md index c36189fd5c..e58f0a4933 100644 --- a/crates/precompile/CHANGELOG.md +++ b/crates/precompile/CHANGELOG.md @@ -1,4 +1,51 @@ # Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [27.0.0](https://github.com/bluealloy/revm/compare/revm-precompile-v26.0.1...revm-precompile-v27.0.0) - 2025-08-23 + +### Added + +- *(fusaka)* Add PrecompileId ([#2904](https://github.com/bluealloy/revm/pull/2904)) + +## [26.0.1](https://github.com/bluealloy/revm/compare/revm-precompile-v26.0.0...revm-precompile-v26.0.1) - 2025-08-12 + +### Fixed + +- *(osaka)* do base/mod zero check after gas calc ([#2872](https://github.com/bluealloy/revm/pull/2872)) + +### Other + +- Aggregate changes from PRs #2866, #2867, and #2874 ([#2876](https://github.com/bluealloy/revm/pull/2876)) + +## [26.0.0](https://github.com/bluealloy/revm/compare/revm-precompile-v25.0.0...revm-precompile-v26.0.0) - 2025-08-06 + +### Added + +- short address for journal cold/warm check ([#2849](https://github.com/bluealloy/revm/pull/2849)) +- optimize access to precompile short addresses ([#2846](https://github.com/bluealloy/revm/pull/2846)) +- Reuse bls12-381 codepaths to implement kzg point evaluation precompile ([#2809](https://github.com/bluealloy/revm/pull/2809)) +- rename bn128 to bn254 for Ethereum standard consistency ([#2810](https://github.com/bluealloy/revm/pull/2810)) + +### Fixed + +- map new once and for all (+ci) ([#2852](https://github.com/bluealloy/revm/pull/2852)) + +### Other + +- update README.md ([#2842](https://github.com/bluealloy/revm/pull/2842)) +- simplify the ecrecover test ([#2836](https://github.com/bluealloy/revm/pull/2836)) +- reuse global crypto provide idea ([#2786](https://github.com/bluealloy/revm/pull/2786)) +- add rust-version and note about MSRV ([#2789](https://github.com/bluealloy/revm/pull/2789)) +- add OnceLock re-export with no_std support ([#2787](https://github.com/bluealloy/revm/pull/2787)) +- fix clippy ([#2785](https://github.com/bluealloy/revm/pull/2785)) +- Add dyn Crypto trait to PrecompileFn ([#2772](https://github.com/bluealloy/revm/pull/2772)) +# Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), diff --git a/crates/precompile/Cargo.toml b/crates/precompile/Cargo.toml index 450736a400..e5a9ff5a86 100644 --- a/crates/precompile/Cargo.toml +++ b/crates/precompile/Cargo.toml @@ -1,13 +1,14 @@ [package] name = "revm-precompile" description = "Revm Precompiles - Ethereum compatible precompiled contracts" -version = "25.0.0" +version = "27.0.0" authors.workspace = true edition.workspace = true keywords.workspace = true license.workspace = true repository.workspace = true readme.workspace = true +rust-version.workspace = true [package.metadata.docs.rs] all-features = true @@ -25,9 +26,6 @@ aurora-engine-modexp.workspace = true # gmp wrapper rug = { workspace = true, features = ["integer"], optional = true } -# static precompile sets. -once_cell = { workspace = true, features = ["alloc"] } - # ecRecover k256 = { workspace = true, features = ["ecdsa"] } secp256k1 = { workspace = true, features = [ @@ -81,11 +79,10 @@ ark-std = { workspace = true } rstest.workspace = true [features] -default = ["std", "c-kzg", "secp256k1", "portable", "blst"] +default = ["std", "secp256k1", "blst", "c-kzg", "portable"] std = [ "primitives/std", "k256/std", - "once_cell/std", "ripemd/std", "sha2/std", "c-kzg?/std", @@ -105,9 +102,8 @@ hashbrown = ["primitives/hashbrown"] asm-keccak = ["primitives/asm-keccak"] asm-sha2 = ["sha2/asm"] -# These libraries may not work on all no_std platforms as they depend on C. -# Enables the KZG point evaluation precompile. +# Enables the c-kzg point evaluation precompile. Enabled by default as most stable/used implementation. c-kzg = ["dep:c-kzg"] # `kzg-rs` is not audited but useful for `no_std` environment, use it with causing and default to `c-kzg` if possible. kzg-rs = ["dep:kzg-rs"] diff --git a/crates/precompile/bench/ecrecover.rs b/crates/precompile/bench/ecrecover.rs index dd2ff2fa5c..d5b62ffc83 100644 --- a/crates/precompile/bench/ecrecover.rs +++ b/crates/precompile/bench/ecrecover.rs @@ -1,6 +1,6 @@ //! Benchmarks for the ecrecover precompile use criterion::{measurement::Measurement, BenchmarkGroup}; -use primitives::{hex, keccak256, Bytes, U256}; +use primitives::{hex, keccak256, Bytes}; use revm_precompile::secp256k1::ec_recover_run; use secp256k1::{Message, SecretKey, SECP256K1}; @@ -20,8 +20,7 @@ pub fn add_benches(group: &mut BenchmarkGroup<'_, M>) { message_and_signature[0..32].copy_from_slice(&hash[..]); // Fit signature into format the precompile expects - let rec_id = U256::from(rec_id as u64); - message_and_signature[32..64].copy_from_slice(&rec_id.to_be_bytes::<32>()); + message_and_signature[63] = rec_id; message_and_signature[64..128].copy_from_slice(&data); let message_and_signature = Bytes::from(message_and_signature); diff --git a/crates/precompile/bench/eip1962.rs b/crates/precompile/bench/eip1962.rs index 92b547da95..afcc0b77f4 100644 --- a/crates/precompile/bench/eip1962.rs +++ b/crates/precompile/bench/eip1962.rs @@ -1,16 +1,16 @@ -//! Benchmarks for the BN128 precompiles +//! Benchmarks for the BN254 precompiles use criterion::{measurement::Measurement, BenchmarkGroup}; use primitives::hex; use primitives::Bytes; -use revm_precompile::bn128::{ +use revm_precompile::bn254::{ add::ISTANBUL_ADD_GAS_COST, mul::ISTANBUL_MUL_GAS_COST, pair::{ISTANBUL_PAIR_BASE, ISTANBUL_PAIR_PER_POINT}, run_add, run_mul, run_pair, }; -/// Add benches for the BN128 add precompile -pub fn add_bn128_add_benches(group: &mut BenchmarkGroup<'_, M>) { +/// Add benches for the BN254 add precompile +pub fn add_bn254_add_benches(group: &mut BenchmarkGroup<'_, M>) { let ecadd_input = hex::decode( "\ 18b18acfb4c2c30276db5411368e7185b311dd124691610c5d3b74034e093dc9\ @@ -21,13 +21,13 @@ pub fn add_bn128_add_benches(group: &mut BenchmarkGroup<'_, M>) .unwrap(); let input = Bytes::from(ecadd_input); - group.bench_function("bn128 add precompile", |b| { + group.bench_function("bn254 add precompile", |b| { b.iter(|| run_add(&input, ISTANBUL_ADD_GAS_COST, 150).unwrap()) }); } -/// Add benches for the BN128 mul precompile -pub fn add_bn128_mul_benches(group: &mut BenchmarkGroup<'_, M>) { +/// Add benches for the BN254 mul precompile +pub fn add_bn254_mul_benches(group: &mut BenchmarkGroup<'_, M>) { let ecmul_input = hex::decode( "\ 18b18acfb4c2c30276db5411368e7185b311dd124691610c5d3b74034e093dc9\ @@ -37,13 +37,13 @@ pub fn add_bn128_mul_benches(group: &mut BenchmarkGroup<'_, M>) .unwrap(); let input = Bytes::from(ecmul_input); - group.bench_function("bn128 mul precompile", |b| { + group.bench_function("bn254 mul precompile", |b| { b.iter(|| run_mul(&input, ISTANBUL_MUL_GAS_COST, 6000).unwrap()) }); } -/// Add benches for the BN128 pair precompile -pub fn add_bn128_pair_benches(group: &mut BenchmarkGroup<'_, M>) { +/// Add benches for the BN254 pair precompile +pub fn add_bn254_pair_benches(group: &mut BenchmarkGroup<'_, M>) { let ecpair_input = hex::decode( "\ 1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f59\ diff --git a/crates/precompile/bench/main.rs b/crates/precompile/bench/main.rs index 153dc40ad1..dcb1bc6675 100644 --- a/crates/precompile/bench/main.rs +++ b/crates/precompile/bench/main.rs @@ -22,10 +22,10 @@ pub fn benchmark_crypto_precompiles(c: &mut Criterion) { eip2537::add_map_fp_to_g1_benches(&mut group); eip2537::add_map_fp2_to_g2_benches(&mut group); - // Run BN128 benchmarks - eip1962::add_bn128_add_benches(&mut group); - eip1962::add_bn128_mul_benches(&mut group); - eip1962::add_bn128_pair_benches(&mut group); + // Run BN254 benchmarks + eip1962::add_bn254_add_benches(&mut group); + eip1962::add_bn254_mul_benches(&mut group); + eip1962::add_bn254_pair_benches(&mut group); // Run secp256k1 benchmarks ecrecover::add_benches(&mut group); diff --git a/crates/precompile/src/blake2.rs b/crates/precompile/src/blake2.rs index 6c446152a9..91b12fcd25 100644 --- a/crates/precompile/src/blake2.rs +++ b/crates/precompile/src/blake2.rs @@ -1,12 +1,14 @@ //! Blake2 precompile. More details in [`run`] -use crate::{PrecompileError, PrecompileOutput, PrecompileResult, PrecompileWithAddress}; +use crate::{ + crypto, Precompile, PrecompileError, PrecompileId, PrecompileOutput, PrecompileResult, +}; const F_ROUND: u64 = 1; const INPUT_LENGTH: usize = 213; /// Blake2 precompile -pub const FUN: PrecompileWithAddress = PrecompileWithAddress(crate::u64_to_address(9), run); +pub const FUN: Precompile = Precompile::new(PrecompileId::Blake2F, crate::u64_to_address(9), run); /// reference: /// input format: @@ -17,7 +19,7 @@ pub fn run(input: &[u8], gas_limit: u64) -> PrecompileResult { } // Parse number of rounds (4 bytes) - let rounds = u32::from_be_bytes(input[..4].try_into().unwrap()) as usize; + let rounds = u32::from_be_bytes(input[..4].try_into().unwrap()); let gas_used = rounds as u64 * F_ROUND; if gas_used > gas_limit { return Err(PrecompileError::OutOfGas); @@ -52,7 +54,7 @@ pub fn run(input: &[u8], gas_limit: u64) -> PrecompileResult { let t_0 = u64::from_le_bytes(input[196..204].try_into().unwrap()); let t_1 = u64::from_le_bytes(input[204..212].try_into().unwrap()); - algo::compress(rounds, &mut h, m, [t_0, t_1], f); + crypto().blake2_compress(rounds, &mut h, m, [t_0, t_1], f); let mut out = [0u8; 64]; for (i, h) in (0..64).step_by(8).zip(h.iter()) { @@ -190,6 +192,7 @@ macro_rules! _MM_SHUFFLE { /// Code adapted from https://github.com/oconnor663/blake2_simd/blob/82b3e2aee4d2384aabbeb146058301ff0dbd453f/blake2b/src/avx2.rs #[cfg(all(target_feature = "avx2", feature = "std"))] +#[allow(clippy::ptr_offset_with_cast)] // From array_refs mod avx2 { #[cfg(target_arch = "x86")] use core::arch::x86::*; @@ -510,7 +513,7 @@ mod avx2 { #[inline(always)] pub(crate) fn count_high(count: Count) -> Word { - (count >> 8 * size_of::()) as Word + (count >> Word::BITS as usize) as Word } #[inline(always)] diff --git a/crates/precompile/src/bls12_381.rs b/crates/precompile/src/bls12_381.rs index 879dcd60bc..0c6ff83b9e 100644 --- a/crates/precompile/src/bls12_381.rs +++ b/crates/precompile/src/bls12_381.rs @@ -1,26 +1,34 @@ //! BLS12-381 precompiles added in [`EIP-2537`](https://eips.ethereum.org/EIPS/eip-2537) //! For more details check modules for each precompile. -use crate::PrecompileWithAddress; +use crate::Precompile; + +#[allow(dead_code)] +pub(crate) mod arkworks; cfg_if::cfg_if! { if #[cfg(feature = "blst")]{ - mod blst; - use blst as crypto_backend; + pub(crate) mod blst; + pub(crate) use blst as crypto_backend; } else { - mod arkworks; - use arkworks as crypto_backend; + pub(crate) use arkworks as crypto_backend; } } // Re-export type aliases for use in submodules -use crate::bls12_381_const::FP_LENGTH; -type G1Point = ([u8; FP_LENGTH], [u8; FP_LENGTH]); -type G2Point = ( +use crate::bls12_381_const::{FP_LENGTH, SCALAR_LENGTH}; +/// G1 point represented as two field elements (x, y coordinates) +pub type G1Point = ([u8; FP_LENGTH], [u8; FP_LENGTH]); +/// G2 point represented as four field elements (x0, x1, y0, y1 coordinates) +pub type G2Point = ( [u8; FP_LENGTH], [u8; FP_LENGTH], [u8; FP_LENGTH], [u8; FP_LENGTH], ); +/// G1 point and scalar pair for MSM operations +pub type G1PointScalar = (G1Point, [u8; SCALAR_LENGTH]); +/// G2 point and scalar pair for MSM operations +pub type G2PointScalar = (G2Point, [u8; SCALAR_LENGTH]); type PairingPair = (G1Point, G2Point); pub mod g1_add; @@ -33,7 +41,7 @@ pub mod pairing; mod utils; /// Returns the BLS12-381 precompiles with their addresses. -pub fn precompiles() -> impl Iterator { +pub fn precompiles() -> impl Iterator { [ g1_add::PRECOMPILE, g1_msm::PRECOMPILE, diff --git a/crates/precompile/src/bls12_381/arkworks.rs b/crates/precompile/src/bls12_381/arkworks.rs index b8eb0a437a..4ca5573cbd 100644 --- a/crates/precompile/src/bls12_381/arkworks.rs +++ b/crates/precompile/src/bls12_381/arkworks.rs @@ -1,3 +1,4 @@ +//! BLS12-381 precompile using Arkworks BLS12-381 implementation. use super::{G1Point, G2Point, PairingPair}; use crate::{ bls12_381_const::{FP_LENGTH, G1_LENGTH, G2_LENGTH, SCALAR_LENGTH}, @@ -347,7 +348,7 @@ fn map_fp2_to_g2(fp2: &Fq2) -> G2Affine { /// pairing_check performs a pairing check on a list of G1 and G2 point pairs and /// returns true if the result is equal to the identity element. #[inline] -fn pairing_check(pairs: &[(G1Affine, G2Affine)]) -> bool { +pub(crate) fn pairing_check(pairs: &[(G1Affine, G2Affine)]) -> bool { if pairs.is_empty() { return true; } @@ -360,7 +361,7 @@ fn pairing_check(pairs: &[(G1Affine, G2Affine)]) -> bool { /// pairing_check_bytes performs a pairing check on a list of G1 and G2 point pairs taking byte inputs. #[inline] -pub(super) fn pairing_check_bytes(pairs: &[PairingPair]) -> Result { +pub(crate) fn pairing_check_bytes(pairs: &[PairingPair]) -> Result { if pairs.is_empty() { return Ok(true); } @@ -405,7 +406,7 @@ pub(super) fn pairing_check_bytes(pairs: &[PairingPair]) -> Result Result<[u8; G1_LENGTH], PrecompileError> { @@ -426,7 +427,7 @@ pub(super) fn p1_add_affine_bytes( /// Performs point addition on two G2 points taking byte coordinates. #[inline] -pub(super) fn p2_add_affine_bytes( +pub(crate) fn p2_add_affine_bytes( a: G2Point, b: G2Point, ) -> Result<[u8; G2_LENGTH], PrecompileError> { @@ -447,7 +448,7 @@ pub(super) fn p2_add_affine_bytes( /// Maps a field element to a G1 point from bytes #[inline] -pub(super) fn map_fp_to_g1_bytes( +pub(crate) fn map_fp_to_g1_bytes( fp_bytes: &[u8; FP_LENGTH], ) -> Result<[u8; G1_LENGTH], PrecompileError> { let fp = read_fp(fp_bytes)?; @@ -457,7 +458,7 @@ pub(super) fn map_fp_to_g1_bytes( /// Maps field elements to a G2 point from bytes #[inline] -pub(super) fn map_fp2_to_g2_bytes( +pub(crate) fn map_fp2_to_g2_bytes( fp2_x: &[u8; FP_LENGTH], fp2_y: &[u8; FP_LENGTH], ) -> Result<[u8; G2_LENGTH], PrecompileError> { @@ -468,7 +469,7 @@ pub(super) fn map_fp2_to_g2_bytes( /// Performs multi-scalar multiplication (MSM) for G1 points taking byte inputs. #[inline] -pub(super) fn p1_msm_bytes( +pub(crate) fn p1_msm_bytes( point_scalar_pairs: impl Iterator>, ) -> Result<[u8; G1_LENGTH], PrecompileError> { let mut g1_points = Vec::new(); @@ -505,7 +506,7 @@ pub(super) fn p1_msm_bytes( /// Performs multi-scalar multiplication (MSM) for G2 points taking byte inputs. #[inline] -pub(super) fn p2_msm_bytes( +pub(crate) fn p2_msm_bytes( point_scalar_pairs: impl Iterator>, ) -> Result<[u8; G2_LENGTH], PrecompileError> { let mut g2_points = Vec::new(); diff --git a/crates/precompile/src/bls12_381/blst.rs b/crates/precompile/src/bls12_381/blst.rs index 822eed35ba..747c695f4a 100644 --- a/crates/precompile/src/bls12_381/blst.rs +++ b/crates/precompile/src/bls12_381/blst.rs @@ -2,6 +2,7 @@ use super::{G1Point, G2Point, PairingPair}; use crate::{ + bls12_381::{G1PointScalar, G2PointScalar}, bls12_381_const::{FP_LENGTH, G1_LENGTH, G2_LENGTH, SCALAR_LENGTH, SCALAR_LENGTH_BITS}, PrecompileError, }; @@ -24,7 +25,7 @@ const MODULUS_REPR: [u8; 48] = [ ]; #[inline] -fn p1_to_affine(p: &blst_p1) -> blst_p1_affine { +pub(crate) fn p1_to_affine(p: &blst_p1) -> blst_p1_affine { let mut p_affine = blst_p1_affine::default(); // SAFETY: both inputs are valid blst types unsafe { blst_p1_to_affine(&mut p_affine, p) }; @@ -32,7 +33,7 @@ fn p1_to_affine(p: &blst_p1) -> blst_p1_affine { } #[inline] -fn p1_from_affine(p_affine: &blst_p1_affine) -> blst_p1 { +pub(crate) fn p1_from_affine(p_affine: &blst_p1_affine) -> blst_p1 { let mut p = blst_p1::default(); // SAFETY: both inputs are valid blst types unsafe { blst_p1_from_affine(&mut p, p_affine) }; @@ -40,7 +41,7 @@ fn p1_from_affine(p_affine: &blst_p1_affine) -> blst_p1 { } #[inline] -fn p1_add_or_double(p: &blst_p1, p_affine: &blst_p1_affine) -> blst_p1 { +pub(crate) fn p1_add_or_double(p: &blst_p1, p_affine: &blst_p1_affine) -> blst_p1 { let mut result = blst_p1::default(); // SAFETY: all inputs are valid blst types unsafe { blst_p1_add_or_double_affine(&mut result, p, p_affine) }; @@ -48,7 +49,7 @@ fn p1_add_or_double(p: &blst_p1, p_affine: &blst_p1_affine) -> blst_p1 { } #[inline] -fn p2_to_affine(p: &blst_p2) -> blst_p2_affine { +pub(crate) fn p2_to_affine(p: &blst_p2) -> blst_p2_affine { let mut p_affine = blst_p2_affine::default(); // SAFETY: both inputs are valid blst types unsafe { blst_p2_to_affine(&mut p_affine, p) }; @@ -56,7 +57,7 @@ fn p2_to_affine(p: &blst_p2) -> blst_p2_affine { } #[inline] -fn p2_from_affine(p_affine: &blst_p2_affine) -> blst_p2 { +pub(crate) fn p2_from_affine(p_affine: &blst_p2_affine) -> blst_p2 { let mut p = blst_p2::default(); // SAFETY: both inputs are valid blst types unsafe { blst_p2_from_affine(&mut p, p_affine) }; @@ -64,7 +65,7 @@ fn p2_from_affine(p_affine: &blst_p2_affine) -> blst_p2 { } #[inline] -fn p2_add_or_double(p: &blst_p2, p_affine: &blst_p2_affine) -> blst_p2 { +pub(crate) fn p2_add_or_double(p: &blst_p2, p_affine: &blst_p2_affine) -> blst_p2 { let mut result = blst_p2::default(); // SAFETY: all inputs are valid blst types unsafe { blst_p2_add_or_double_affine(&mut result, p, p_affine) }; @@ -107,7 +108,7 @@ fn p2_add_affine(a: &blst_p2_affine, b: &blst_p2_affine) -> blst_p2_affine { /// /// Note: The scalar is expected to be in Big Endian format. #[inline] -fn p1_scalar_mul(p: &blst_p1_affine, scalar: &blst_scalar) -> blst_p1_affine { +pub(crate) fn p1_scalar_mul(p: &blst_p1_affine, scalar: &blst_scalar) -> blst_p1_affine { // Convert point to Jacobian coordinates let p_jacobian = p1_from_affine(p); @@ -134,7 +135,7 @@ fn p1_scalar_mul(p: &blst_p1_affine, scalar: &blst_scalar) -> blst_p1_affine { /// /// Note: The scalar is expected to be in Big Endian format. #[inline] -fn p2_scalar_mul(p: &blst_p2_affine, scalar: &blst_scalar) -> blst_p2_affine { +pub(crate) fn p2_scalar_mul(p: &blst_p2_affine, scalar: &blst_scalar) -> blst_p2_affine { // Convert point to Jacobian coordinates let p_jacobian = p2_from_affine(p); @@ -307,7 +308,7 @@ fn is_fp12_one(f: &blst_fp12) -> bool { /// pairing_check performs a pairing check on a list of G1 and G2 point pairs and /// returns true if the result is equal to the identity element. #[inline] -fn pairing_check(pairs: &[(blst_p1_affine, blst_p2_affine)]) -> bool { +pub(crate) fn pairing_check(pairs: &[(blst_p1_affine, blst_p2_affine)]) -> bool { // When no inputs are given, we return true // This case can only trigger, if the initial pairing components // all had, either the G1 element as the point at infinity @@ -622,7 +623,7 @@ fn is_valid_be(input: &[u8; 48]) -> bool { /// Performs point addition on two G1 points taking byte coordinates. #[inline] -pub(super) fn p1_add_affine_bytes( +pub(crate) fn p1_add_affine_bytes( a: G1Point, b: G1Point, ) -> Result<[u8; G1_LENGTH], crate::PrecompileError> { @@ -643,7 +644,7 @@ pub(super) fn p1_add_affine_bytes( /// Performs point addition on two G2 points taking byte coordinates. #[inline] -pub(super) fn p2_add_affine_bytes( +pub(crate) fn p2_add_affine_bytes( a: G2Point, b: G2Point, ) -> Result<[u8; G2_LENGTH], crate::PrecompileError> { @@ -664,7 +665,7 @@ pub(super) fn p2_add_affine_bytes( /// Maps a field element to a G1 point from bytes #[inline] -pub(super) fn map_fp_to_g1_bytes( +pub(crate) fn map_fp_to_g1_bytes( fp_bytes: &[u8; FP_LENGTH], ) -> Result<[u8; G1_LENGTH], crate::PrecompileError> { let fp = read_fp(fp_bytes)?; @@ -674,7 +675,7 @@ pub(super) fn map_fp_to_g1_bytes( /// Maps field elements to a G2 point from bytes #[inline] -pub(super) fn map_fp2_to_g2_bytes( +pub(crate) fn map_fp2_to_g2_bytes( fp2_x: &[u8; FP_LENGTH], fp2_y: &[u8; FP_LENGTH], ) -> Result<[u8; G2_LENGTH], crate::PrecompileError> { @@ -685,10 +686,8 @@ pub(super) fn map_fp2_to_g2_bytes( /// Performs multi-scalar multiplication (MSM) for G1 points taking byte inputs. #[inline] -pub(super) fn p1_msm_bytes( - point_scalar_pairs: impl Iterator< - Item = Result<(G1Point, [u8; SCALAR_LENGTH]), crate::PrecompileError>, - >, +pub(crate) fn p1_msm_bytes( + point_scalar_pairs: impl Iterator>, ) -> Result<[u8; G1_LENGTH], crate::PrecompileError> { let mut g1_points = Vec::new(); let mut scalars = Vec::new(); @@ -724,10 +723,8 @@ pub(super) fn p1_msm_bytes( /// Performs multi-scalar multiplication (MSM) for G2 points taking byte inputs. #[inline] -pub(super) fn p2_msm_bytes( - point_scalar_pairs: impl Iterator< - Item = Result<(G2Point, [u8; SCALAR_LENGTH]), crate::PrecompileError>, - >, +pub(crate) fn p2_msm_bytes( + point_scalar_pairs: impl Iterator>, ) -> Result<[u8; G2_LENGTH], crate::PrecompileError> { let mut g2_points = Vec::new(); let mut scalars = Vec::new(); @@ -763,7 +760,7 @@ pub(super) fn p2_msm_bytes( /// pairing_check_bytes performs a pairing check on a list of G1 and G2 point pairs taking byte inputs. #[inline] -pub(super) fn pairing_check_bytes(pairs: &[PairingPair]) -> Result { +pub(crate) fn pairing_check_bytes(pairs: &[PairingPair]) -> Result { if pairs.is_empty() { return Ok(true); } diff --git a/crates/precompile/src/bls12_381/g1_add.rs b/crates/precompile/src/bls12_381/g1_add.rs index c8aa2f80f0..3b2dd2e59d 100644 --- a/crates/precompile/src/bls12_381/g1_add.rs +++ b/crates/precompile/src/bls12_381/g1_add.rs @@ -1,13 +1,15 @@ //! BLS12-381 G1 add precompile. More details in [`g1_add`] -use super::crypto_backend::p1_add_affine_bytes; use super::utils::{pad_g1_point, remove_g1_padding}; use crate::bls12_381_const::{ G1_ADD_ADDRESS, G1_ADD_BASE_GAS_FEE, G1_ADD_INPUT_LENGTH, PADDED_G1_LENGTH, }; -use crate::{PrecompileError, PrecompileOutput, PrecompileResult, PrecompileWithAddress}; +use crate::{ + crypto, Precompile, PrecompileError, PrecompileId, PrecompileOutput, PrecompileResult, +}; /// [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537#specification) BLS12_G1ADD precompile. -pub const PRECOMPILE: PrecompileWithAddress = PrecompileWithAddress(G1_ADD_ADDRESS, g1_add); +pub const PRECOMPILE: Precompile = + Precompile::new(PrecompileId::Bls12G1Add, G1_ADD_ADDRESS, g1_add); /// G1 addition call expects `256` bytes as an input that is interpreted as byte /// concatenation of two G1 points (`128` bytes each). @@ -33,8 +35,7 @@ pub fn g1_add(input: &[u8], gas_limit: u64) -> PrecompileResult { let a = (*a_x, *a_y); let b = (*b_x, *b_y); - // Get unpadded result from crypto backend - let unpadded_result = p1_add_affine_bytes(a, b)?; + let unpadded_result = crypto().bls12_381_g1_add(a, b)?; // Pad the result for EVM compatibility let padded_result = pad_g1_point(&unpadded_result); diff --git a/crates/precompile/src/bls12_381/g1_msm.rs b/crates/precompile/src/bls12_381/g1_msm.rs index f47802ef4b..c4840cfe1c 100644 --- a/crates/precompile/src/bls12_381/g1_msm.rs +++ b/crates/precompile/src/bls12_381/g1_msm.rs @@ -1,16 +1,18 @@ //! BLS12-381 G1 msm precompile. More details in [`g1_msm`] -use super::crypto_backend::p1_msm_bytes; -use super::G1Point; use crate::bls12_381::utils::{pad_g1_point, remove_g1_padding}; +use crate::bls12_381::G1Point; use crate::bls12_381_const::{ DISCOUNT_TABLE_G1_MSM, G1_MSM_ADDRESS, G1_MSM_BASE_GAS_FEE, G1_MSM_INPUT_LENGTH, PADDED_G1_LENGTH, SCALAR_LENGTH, }; use crate::bls12_381_utils::msm_required_gas; -use crate::{PrecompileError, PrecompileOutput, PrecompileResult, PrecompileWithAddress}; +use crate::{ + crypto, Precompile, PrecompileError, PrecompileId, PrecompileOutput, PrecompileResult, +}; /// [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537#specification) BLS12_G1MSM precompile. -pub const PRECOMPILE: PrecompileWithAddress = PrecompileWithAddress(G1_MSM_ADDRESS, g1_msm); +pub const PRECOMPILE: Precompile = + Precompile::new(PrecompileId::Bls12G1Msm, G1_MSM_ADDRESS, g1_msm); /// Implements EIP-2537 G1MSM precompile. /// G1 multi-scalar-multiplication call expects `160*k` bytes as an input that is interpreted @@ -22,7 +24,7 @@ pub const PRECOMPILE: PrecompileWithAddress = PrecompileWithAddress(G1_MSM_ADDRE /// See also: pub fn g1_msm(input: &[u8], gas_limit: u64) -> PrecompileResult { let input_len = input.len(); - if input_len == 0 || input_len % G1_MSM_INPUT_LENGTH != 0 { + if input_len == 0 || !input_len.is_multiple_of(G1_MSM_INPUT_LENGTH) { return Err(PrecompileError::Other(format!( "G1MSM input length should be multiple of {G1_MSM_INPUT_LENGTH}, was {input_len}", ))); @@ -34,7 +36,7 @@ pub fn g1_msm(input: &[u8], gas_limit: u64) -> PrecompileResult { return Err(PrecompileError::OutOfGas); } - let valid_pairs_iter = (0..k).map(|i| { + let mut valid_pairs_iter = (0..k).map(|i| { let start = i * G1_MSM_INPUT_LENGTH; let padded_g1 = &input[start..start + PADDED_G1_LENGTH]; let scalar_bytes = &input[start + PADDED_G1_LENGTH..start + G1_MSM_INPUT_LENGTH]; @@ -47,7 +49,7 @@ pub fn g1_msm(input: &[u8], gas_limit: u64) -> PrecompileResult { Ok((point, scalar_array)) }); - let unpadded_result = p1_msm_bytes(valid_pairs_iter)?; + let unpadded_result = crypto().bls12_381_g1_msm(&mut valid_pairs_iter)?; // Pad the result for EVM compatibility let padded_result = pad_g1_point(&unpadded_result); diff --git a/crates/precompile/src/bls12_381/g2_add.rs b/crates/precompile/src/bls12_381/g2_add.rs index bcd4f7984e..d3af54f4c3 100644 --- a/crates/precompile/src/bls12_381/g2_add.rs +++ b/crates/precompile/src/bls12_381/g2_add.rs @@ -1,13 +1,15 @@ //! BLS12-381 G2 add precompile. More details in [`g2_add`] -use super::crypto_backend::p2_add_affine_bytes; use super::utils::{pad_g2_point, remove_g2_padding}; use crate::bls12_381_const::{ G2_ADD_ADDRESS, G2_ADD_BASE_GAS_FEE, G2_ADD_INPUT_LENGTH, PADDED_G2_LENGTH, }; -use crate::{PrecompileError, PrecompileOutput, PrecompileResult, PrecompileWithAddress}; +use crate::{ + crypto, Precompile, PrecompileError, PrecompileId, PrecompileOutput, PrecompileResult, +}; /// [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537#specification) BLS12_G2ADD precompile. -pub const PRECOMPILE: PrecompileWithAddress = PrecompileWithAddress(G2_ADD_ADDRESS, g2_add); +pub const PRECOMPILE: Precompile = + Precompile::new(PrecompileId::Bls12G2Add, G2_ADD_ADDRESS, g2_add); /// G2 addition call expects `512` bytes as an input that is interpreted as byte /// concatenation of two G2 points (`256` bytes each). @@ -34,8 +36,7 @@ pub fn g2_add(input: &[u8], gas_limit: u64) -> PrecompileResult { let a = (*a_x_0, *a_x_1, *a_y_0, *a_y_1); let b = (*b_x_0, *b_x_1, *b_y_0, *b_y_1); - // Get unpadded result from crypto backend - let unpadded_result = p2_add_affine_bytes(a, b)?; + let unpadded_result = crypto().bls12_381_g2_add(a, b)?; // Pad the result for EVM compatibility let padded_result = pad_g2_point(&unpadded_result); diff --git a/crates/precompile/src/bls12_381/g2_msm.rs b/crates/precompile/src/bls12_381/g2_msm.rs index 98dfa71768..eaa2c4f4f7 100644 --- a/crates/precompile/src/bls12_381/g2_msm.rs +++ b/crates/precompile/src/bls12_381/g2_msm.rs @@ -1,16 +1,17 @@ //! BLS12-381 G2 msm precompile. More details in [`g2_msm`] -use super::crypto_backend::p2_msm_bytes; use super::utils::{pad_g2_point, remove_g2_padding}; -use super::G2Point; use crate::bls12_381_const::{ DISCOUNT_TABLE_G2_MSM, G2_MSM_ADDRESS, G2_MSM_BASE_GAS_FEE, G2_MSM_INPUT_LENGTH, PADDED_G2_LENGTH, SCALAR_LENGTH, }; use crate::bls12_381_utils::msm_required_gas; -use crate::{PrecompileError, PrecompileOutput, PrecompileResult, PrecompileWithAddress}; +use crate::{ + crypto, Precompile, PrecompileError, PrecompileId, PrecompileOutput, PrecompileResult, +}; /// [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537#specification) BLS12_G2MSM precompile. -pub const PRECOMPILE: PrecompileWithAddress = PrecompileWithAddress(G2_MSM_ADDRESS, g2_msm); +pub const PRECOMPILE: Precompile = + Precompile::new(PrecompileId::Bls12G2Msm, G2_MSM_ADDRESS, g2_msm); /// Implements EIP-2537 G2MSM precompile. /// G2 multi-scalar-multiplication call expects `288*k` bytes as an input that is interpreted @@ -22,7 +23,7 @@ pub const PRECOMPILE: PrecompileWithAddress = PrecompileWithAddress(G2_MSM_ADDRE /// See also: pub fn g2_msm(input: &[u8], gas_limit: u64) -> PrecompileResult { let input_len = input.len(); - if input_len == 0 || input_len % G2_MSM_INPUT_LENGTH != 0 { + if input_len == 0 || !input_len.is_multiple_of(G2_MSM_INPUT_LENGTH) { return Err(PrecompileError::Other(format!( "G2MSM input length should be multiple of {G2_MSM_INPUT_LENGTH}, was {input_len}", ))); @@ -34,7 +35,7 @@ pub fn g2_msm(input: &[u8], gas_limit: u64) -> PrecompileResult { return Err(PrecompileError::OutOfGas); } - let valid_pairs_iter = (0..k).map(|i| { + let mut valid_pairs_iter = (0..k).map(|i| { let start = i * G2_MSM_INPUT_LENGTH; let padded_g2 = &input[start..start + PADDED_G2_LENGTH]; let scalar_bytes = &input[start + PADDED_G2_LENGTH..start + G2_MSM_INPUT_LENGTH]; @@ -43,11 +44,10 @@ pub fn g2_msm(input: &[u8], gas_limit: u64) -> PrecompileResult { let [x_0, x_1, y_0, y_1] = remove_g2_padding(padded_g2)?; let scalar_array: [u8; SCALAR_LENGTH] = scalar_bytes.try_into().unwrap(); - let point: G2Point = (*x_0, *x_1, *y_0, *y_1); - Ok((point, scalar_array)) + Ok(((*x_0, *x_1, *y_0, *y_1), scalar_array)) }); - let unpadded_result = p2_msm_bytes(valid_pairs_iter)?; + let unpadded_result = crypto().bls12_381_g2_msm(&mut valid_pairs_iter)?; // Pad the result for EVM compatibility let padded_result = pad_g2_point(&unpadded_result); diff --git a/crates/precompile/src/bls12_381/map_fp2_to_g2.rs b/crates/precompile/src/bls12_381/map_fp2_to_g2.rs index 50f67a32cb..847f9638d6 100644 --- a/crates/precompile/src/bls12_381/map_fp2_to_g2.rs +++ b/crates/precompile/src/bls12_381/map_fp2_to_g2.rs @@ -1,17 +1,18 @@ //! BLS12-381 map fp2 to g2 precompile. More details in [`map_fp2_to_g2`] -use super::{ - crypto_backend::map_fp2_to_g2_bytes, - utils::{pad_g2_point, remove_fp_padding}, -}; +use super::utils::{pad_g2_point, remove_fp_padding}; use crate::bls12_381_const::{ MAP_FP2_TO_G2_ADDRESS, MAP_FP2_TO_G2_BASE_GAS_FEE, PADDED_FP2_LENGTH, PADDED_FP_LENGTH, }; -use crate::PrecompileWithAddress; -use crate::{PrecompileError, PrecompileOutput, PrecompileResult}; +use crate::{ + crypto, Precompile, PrecompileError, PrecompileId, PrecompileOutput, PrecompileResult, +}; /// [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537#specification) BLS12_MAP_FP2_TO_G2 precompile. -pub const PRECOMPILE: PrecompileWithAddress = - PrecompileWithAddress(MAP_FP2_TO_G2_ADDRESS, map_fp2_to_g2); +pub const PRECOMPILE: Precompile = Precompile::new( + PrecompileId::Bls12MapFp2ToGp2, + MAP_FP2_TO_G2_ADDRESS, + map_fp2_to_g2, +); /// Field-to-curve call expects 128 bytes as an input that is interpreted as /// an element of Fp2. Output of this call is 256 bytes and is an encoded G2 @@ -32,8 +33,7 @@ pub fn map_fp2_to_g2(input: &[u8], gas_limit: u64) -> PrecompileResult { let input_p0_x = remove_fp_padding(&input[..PADDED_FP_LENGTH])?; let input_p0_y = remove_fp_padding(&input[PADDED_FP_LENGTH..PADDED_FP2_LENGTH])?; - // Get unpadded result from crypto backend - let unpadded_result = map_fp2_to_g2_bytes(input_p0_x, input_p0_y)?; + let unpadded_result = crypto().bls12_381_fp2_to_g2((*input_p0_x, *input_p0_y))?; // Pad the result for EVM compatibility let padded_result = pad_g2_point(&unpadded_result); diff --git a/crates/precompile/src/bls12_381/map_fp_to_g1.rs b/crates/precompile/src/bls12_381/map_fp_to_g1.rs index de4ee4503e..64a8f11393 100644 --- a/crates/precompile/src/bls12_381/map_fp_to_g1.rs +++ b/crates/precompile/src/bls12_381/map_fp_to_g1.rs @@ -1,14 +1,16 @@ //! BLS12-381 map fp to g1 precompile. More details in [`map_fp_to_g1`] -use super::{ - crypto_backend::map_fp_to_g1_bytes, - utils::{pad_g1_point, remove_fp_padding}, -}; +use super::utils::{pad_g1_point, remove_fp_padding}; use crate::bls12_381_const::{MAP_FP_TO_G1_ADDRESS, MAP_FP_TO_G1_BASE_GAS_FEE, PADDED_FP_LENGTH}; -use crate::{PrecompileError, PrecompileOutput, PrecompileResult, PrecompileWithAddress}; +use crate::{ + crypto, Precompile, PrecompileError, PrecompileId, PrecompileOutput, PrecompileResult, +}; /// [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537#specification) BLS12_MAP_FP_TO_G1 precompile. -pub const PRECOMPILE: PrecompileWithAddress = - PrecompileWithAddress(MAP_FP_TO_G1_ADDRESS, map_fp_to_g1); +pub const PRECOMPILE: Precompile = Precompile::new( + PrecompileId::Bls12MapFpToGp1, + MAP_FP_TO_G1_ADDRESS, + map_fp_to_g1, +); /// Field-to-curve call expects 64 bytes as an input that is interpreted as an /// element of Fp. Output of this call is 128 bytes and is an encoded G1 point. @@ -27,8 +29,7 @@ pub fn map_fp_to_g1(input: &[u8], gas_limit: u64) -> PrecompileResult { let input_p0 = remove_fp_padding(input)?; - // Get unpadded result from crypto backend - let unpadded_result = map_fp_to_g1_bytes(input_p0)?; + let unpadded_result = crypto().bls12_381_fp_to_g1(input_p0)?; // Pad the result for EVM compatibility let padded_result = pad_g1_point(&unpadded_result); diff --git a/crates/precompile/src/bls12_381/pairing.rs b/crates/precompile/src/bls12_381/pairing.rs index 6f9a59bcbd..4cf4c3f5b5 100644 --- a/crates/precompile/src/bls12_381/pairing.rs +++ b/crates/precompile/src/bls12_381/pairing.rs @@ -1,17 +1,19 @@ //! BLS12-381 pairing precompile. More details in [`pairing`] -use super::crypto_backend::pairing_check_bytes; use super::utils::{remove_g1_padding, remove_g2_padding}; use super::PairingPair; use crate::bls12_381_const::{ PADDED_G1_LENGTH, PADDED_G2_LENGTH, PAIRING_ADDRESS, PAIRING_INPUT_LENGTH, PAIRING_MULTIPLIER_BASE, PAIRING_OFFSET_BASE, }; -use crate::{PrecompileError, PrecompileOutput, PrecompileResult, PrecompileWithAddress}; +use crate::{ + crypto, Precompile, PrecompileError, PrecompileId, PrecompileOutput, PrecompileResult, +}; use primitives::B256; use std::vec::Vec; /// [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537#specification) BLS12_PAIRING precompile. -pub const PRECOMPILE: PrecompileWithAddress = PrecompileWithAddress(PAIRING_ADDRESS, pairing); +pub const PRECOMPILE: Precompile = + Precompile::new(PrecompileId::Bls12Pairing, PAIRING_ADDRESS, pairing); /// Pairing call expects 384*k (k being a positive integer) bytes as an inputs /// that is interpreted as byte concatenation of k slices. Each slice has the @@ -27,7 +29,7 @@ pub const PRECOMPILE: PrecompileWithAddress = PrecompileWithAddress(PAIRING_ADDR /// See also: pub fn pairing(input: &[u8], gas_limit: u64) -> PrecompileResult { let input_len = input.len(); - if input_len == 0 || input_len % PAIRING_INPUT_LENGTH != 0 { + if input_len == 0 || !input_len.is_multiple_of(PAIRING_INPUT_LENGTH) { return Err(PrecompileError::Other(format!( "Pairing input length should be multiple of {PAIRING_INPUT_LENGTH}, was {input_len}" ))); @@ -53,7 +55,7 @@ pub fn pairing(input: &[u8], gas_limit: u64) -> PrecompileResult { pairs.push(((*a_x, *a_y), (*b_x_0, *b_x_1, *b_y_0, *b_y_1))); } - let result = pairing_check_bytes(&pairs)?; + let result = crypto().bls12_381_pairing_check(&pairs)?; let result = if result { 1 } else { 0 }; Ok(PrecompileOutput::new( diff --git a/crates/precompile/src/bls12_381_const.rs b/crates/precompile/src/bls12_381_const.rs index 9898aac258..8fc92bcb1a 100644 --- a/crates/precompile/src/bls12_381_const.rs +++ b/crates/precompile/src/bls12_381_const.rs @@ -1,7 +1,7 @@ //! Constants specifying the precompile addresses for each precompile in EIP-2537 use crate::u64_to_address; -use primitives::Address; +use primitives::{hex, Address}; /// G1 add precompile address pub const G1_ADD_ADDRESS: Address = u64_to_address(0x0b); @@ -182,6 +182,12 @@ pub const PAIRING_INPUT_LENGTH: usize = PADDED_G1_LENGTH + PADDED_G2_LENGTH; /// Note: This should be equal to PADDED_FP_LENGTH - FP_LENGTH. pub const FP_PAD_BY: usize = 16; +/// The trusted setup G2 point `[τ]₂` from the Ethereum KZG ceremony (compressed format) +/// Taken from: +pub const TRUSTED_SETUP_TAU_G2_BYTES: [u8; 96] = hex!( + "b5bfd7dd8cdeb128843bc287230af38926187075cbfbefa81009a2ce615ac53d2914e5870cb452d2afaaab24f3499f72185cbfee53492714734429b7b38608e23926c911cceceac9a36851477ba4c60b087041de621000edc98edada20c1def2" + ); + #[test] fn check_discount_table_invariant_holds() { // Currently EIP-2537 specifies the cost for a G1/G2 scalar multiplication in two places diff --git a/crates/precompile/src/bn128.rs b/crates/precompile/src/bn254.rs similarity index 86% rename from crates/precompile/src/bn128.rs rename to crates/precompile/src/bn254.rs index 3cad806801..b254b29526 100644 --- a/crates/precompile/src/bn128.rs +++ b/crates/precompile/src/bn254.rs @@ -1,88 +1,91 @@ -//! BN128 precompiles added in [`EIP-1962`](https://eips.ethereum.org/EIPS/eip-1962) +//! BN254 precompiles added in [`EIP-1962`](https://eips.ethereum.org/EIPS/eip-1962) use crate::{ + crypto, utilities::{bool_to_bytes32, right_pad}, - Address, PrecompileError, PrecompileOutput, PrecompileResult, PrecompileWithAddress, + Address, Precompile, PrecompileError, PrecompileId, PrecompileOutput, PrecompileResult, }; use std::vec::Vec; +#[allow(dead_code)] +pub mod arkworks; + cfg_if::cfg_if! { if #[cfg(feature = "bn")]{ - mod substrate; - use substrate::{g1_point_add, g1_point_mul, pairing_check}; + pub(crate) mod substrate; + pub(crate) use substrate as crypto_backend; } else { - mod arkworks; - use arkworks::{g1_point_add, g1_point_mul, pairing_check}; + pub(crate) use arkworks as crypto_backend; } } -/// Bn128 add precompile +/// Bn254 add precompile pub mod add { use super::*; - /// Bn128 add precompile address + /// Bn254 add precompile address pub const ADDRESS: Address = crate::u64_to_address(6); - /// Bn128 add precompile with ISTANBUL gas rules + /// Bn254 add precompile with ISTANBUL gas rules pub const ISTANBUL_ADD_GAS_COST: u64 = 150; - /// Bn128 add precompile with ISTANBUL gas rules - pub const ISTANBUL: PrecompileWithAddress = - PrecompileWithAddress(ADDRESS, |input, gas_limit| { + /// Bn254 add precompile with ISTANBUL gas rules + pub const ISTANBUL: Precompile = + Precompile::new(PrecompileId::Bn254Add, ADDRESS, |input, gas_limit| { run_add(input, ISTANBUL_ADD_GAS_COST, gas_limit) }); - /// Bn128 add precompile with BYZANTIUM gas rules + /// Bn254 add precompile with BYZANTIUM gas rules pub const BYZANTIUM_ADD_GAS_COST: u64 = 500; - /// Bn128 add precompile with BYZANTIUM gas rules - pub const BYZANTIUM: PrecompileWithAddress = - PrecompileWithAddress(ADDRESS, |input, gas_limit| { + /// Bn254 add precompile with BYZANTIUM gas rules + pub const BYZANTIUM: Precompile = + Precompile::new(PrecompileId::Bn254Add, ADDRESS, |input, gas_limit| { run_add(input, BYZANTIUM_ADD_GAS_COST, gas_limit) }); } -/// Bn128 mul precompile +/// Bn254 mul precompile pub mod mul { use super::*; - /// Bn128 mul precompile address + /// Bn254 mul precompile address pub const ADDRESS: Address = crate::u64_to_address(7); - /// Bn128 mul precompile with ISTANBUL gas rules + /// Bn254 mul precompile with ISTANBUL gas rules pub const ISTANBUL_MUL_GAS_COST: u64 = 6_000; - /// Bn128 mul precompile with ISTANBUL gas rules - pub const ISTANBUL: PrecompileWithAddress = - PrecompileWithAddress(ADDRESS, |input, gas_limit| { + /// Bn254 mul precompile with ISTANBUL gas rules + pub const ISTANBUL: Precompile = + Precompile::new(PrecompileId::Bn254Mul, ADDRESS, |input, gas_limit| { run_mul(input, ISTANBUL_MUL_GAS_COST, gas_limit) }); - /// Bn128 mul precompile with BYZANTIUM gas rules + /// Bn254 mul precompile with BYZANTIUM gas rules pub const BYZANTIUM_MUL_GAS_COST: u64 = 40_000; - /// Bn128 mul precompile with BYZANTIUM gas rules - pub const BYZANTIUM: PrecompileWithAddress = - PrecompileWithAddress(ADDRESS, |input, gas_limit| { + /// Bn254 mul precompile with BYZANTIUM gas rules + pub const BYZANTIUM: Precompile = + Precompile::new(PrecompileId::Bn254Mul, ADDRESS, |input, gas_limit| { run_mul(input, BYZANTIUM_MUL_GAS_COST, gas_limit) }); } -/// Bn128 pair precompile +/// Bn254 pair precompile pub mod pair { use super::*; - /// Bn128 pair precompile address + /// Bn254 pair precompile address pub const ADDRESS: Address = crate::u64_to_address(8); - /// Bn128 pair precompile with ISTANBUL gas rules + /// Bn254 pair precompile with ISTANBUL gas rules pub const ISTANBUL_PAIR_PER_POINT: u64 = 34_000; - /// Bn128 pair precompile with ISTANBUL gas rules + /// Bn254 pair precompile with ISTANBUL gas rules pub const ISTANBUL_PAIR_BASE: u64 = 45_000; - /// Bn128 pair precompile with ISTANBUL gas rules - pub const ISTANBUL: PrecompileWithAddress = - PrecompileWithAddress(ADDRESS, |input, gas_limit| { + /// Bn254 pair precompile with ISTANBUL gas rules + pub const ISTANBUL: Precompile = + Precompile::new(PrecompileId::Bn254Pairing, ADDRESS, |input, gas_limit| { run_pair( input, ISTANBUL_PAIR_PER_POINT, @@ -91,15 +94,15 @@ pub mod pair { ) }); - /// Bn128 pair precompile with BYZANTIUM gas rules + /// Bn254 pair precompile with BYZANTIUM gas rules pub const BYZANTIUM_PAIR_PER_POINT: u64 = 80_000; - /// Bn128 pair precompile with BYZANTIUM gas rules + /// Bn254 pair precompile with BYZANTIUM gas rules pub const BYZANTIUM_PAIR_BASE: u64 = 100_000; - /// Bn128 pair precompile with BYZANTIUM gas rules - pub const BYZANTIUM: PrecompileWithAddress = - PrecompileWithAddress(ADDRESS, |input, gas_limit| { + /// Bn254 pair precompile with BYZANTIUM gas rules + pub const BYZANTIUM: Precompile = + Precompile::new(PrecompileId::Bn254Pairing, ADDRESS, |input, gas_limit| { run_pair( input, BYZANTIUM_PAIR_PER_POINT, @@ -148,7 +151,7 @@ pub const MUL_INPUT_LEN: usize = G1_LEN + SCALAR_LEN; /// (128 bytes). pub const PAIR_ELEMENT_LEN: usize = G1_LEN + G2_LEN; -/// Run the Bn128 add precompile +/// Run the Bn254 add precompile pub fn run_add(input: &[u8], gas_cost: u64, gas_limit: u64) -> PrecompileResult { if gas_cost > gas_limit { return Err(PrecompileError::OutOfGas); @@ -158,12 +161,12 @@ pub fn run_add(input: &[u8], gas_cost: u64, gas_limit: u64) -> PrecompileResult let p1_bytes = &input[..G1_LEN]; let p2_bytes = &input[G1_LEN..]; - let output = g1_point_add(p1_bytes, p2_bytes)?; + let output = crypto().bn254_g1_add(p1_bytes, p2_bytes)?; Ok(PrecompileOutput::new(gas_cost, output.into())) } -/// Run the Bn128 mul precompile +/// Run the Bn254 mul precompile pub fn run_mul(input: &[u8], gas_cost: u64, gas_limit: u64) -> PrecompileResult { if gas_cost > gas_limit { return Err(PrecompileError::OutOfGas); @@ -173,12 +176,12 @@ pub fn run_mul(input: &[u8], gas_cost: u64, gas_limit: u64) -> PrecompileResult let point_bytes = &input[..G1_LEN]; let scalar_bytes = &input[G1_LEN..G1_LEN + SCALAR_LEN]; - let output = g1_point_mul(point_bytes, scalar_bytes)?; + let output = crypto().bn254_g1_mul(point_bytes, scalar_bytes)?; Ok(PrecompileOutput::new(gas_cost, output.into())) } -/// Run the Bn128 pair precompile +/// Run the Bn254 pair precompile pub fn run_pair( input: &[u8], pair_per_point_cost: u64, @@ -190,8 +193,8 @@ pub fn run_pair( return Err(PrecompileError::OutOfGas); } - if input.len() % PAIR_ELEMENT_LEN != 0 { - return Err(PrecompileError::Bn128PairLength); + if !input.len().is_multiple_of(PAIR_ELEMENT_LEN) { + return Err(PrecompileError::Bn254PairLength); } let elements = input.len() / PAIR_ELEMENT_LEN; @@ -212,7 +215,7 @@ pub fn run_pair( points.push((encoded_g1_element, encoded_g2_element)); } - let pairing_result = pairing_check(&points)?; + let pairing_result = crypto().bn254_pairing_check(&points)?; Ok(PrecompileOutput::new( gas_used, bool_to_bytes32(pairing_result), @@ -222,7 +225,7 @@ pub fn run_pair( #[cfg(test)] mod tests { use crate::{ - bn128::{ + bn254::{ add::BYZANTIUM_ADD_GAS_COST, mul::BYZANTIUM_MUL_GAS_COST, pair::{BYZANTIUM_PAIR_BASE, BYZANTIUM_PAIR_PER_POINT}, @@ -234,7 +237,7 @@ mod tests { use super::*; #[test] - fn test_alt_bn128_add() { + fn test_bn254_add() { let input = hex::decode( "\ 18b18acfb4c2c30276db5411368e7185b311dd124691610c5d3b74034e093dc9\ @@ -311,12 +314,12 @@ mod tests { let res = run_add(&input, BYZANTIUM_ADD_GAS_COST, 500); assert!(matches!( res, - Err(PrecompileError::Bn128AffineGFailedToCreate) + Err(PrecompileError::Bn254AffineGFailedToCreate) )); } #[test] - fn test_alt_bn128_mul() { + fn test_bn254_mul() { let input = hex::decode( "\ 2bd3e6d0f3b142924f5ca7b49ce5b9d54c4703d7ae5648e61d02268b1a0a9fb7\ @@ -388,12 +391,12 @@ mod tests { let res = run_mul(&input, BYZANTIUM_MUL_GAS_COST, 40_000); assert!(matches!( res, - Err(PrecompileError::Bn128AffineGFailedToCreate) + Err(PrecompileError::Bn254AffineGFailedToCreate) )); } #[test] - fn test_alt_bn128_pair() { + fn test_bn254_pair() { let input = hex::decode( "\ 1c76476f4def4bb94541d57ebba1193381ffa7aa76ada664dd31c16024c43f59\ @@ -484,7 +487,7 @@ mod tests { ); assert!(matches!( res, - Err(PrecompileError::Bn128AffineGFailedToCreate) + Err(PrecompileError::Bn254AffineGFailedToCreate) )); // Invalid input length @@ -503,7 +506,7 @@ mod tests { BYZANTIUM_PAIR_BASE, 260_000, ); - assert!(matches!(res, Err(PrecompileError::Bn128PairLength))); + assert!(matches!(res, Err(PrecompileError::Bn254PairLength))); // Test with point at infinity - should return true (identity element) // G1 point at infinity (0,0) followed by a valid G2 point diff --git a/crates/precompile/src/bn128/arkworks.rs b/crates/precompile/src/bn254/arkworks.rs similarity index 93% rename from crates/precompile/src/bn128/arkworks.rs rename to crates/precompile/src/bn254/arkworks.rs index 63a14a9946..676968d6af 100644 --- a/crates/precompile/src/bn128/arkworks.rs +++ b/crates/precompile/src/bn254/arkworks.rs @@ -1,3 +1,4 @@ +//! BN128 precompile using Arkworks BLS12-381 implementation. use super::{FQ2_LEN, FQ_LEN, G1_LEN, SCALAR_LEN}; use crate::PrecompileError; use std::vec::Vec; @@ -27,7 +28,7 @@ fn read_fq(input_be: &[u8]) -> Result { input_le.reverse(); Fq::deserialize_uncompressed(&input_le[..]) - .map_err(|_| PrecompileError::Bn128FieldPointNotAMember) + .map_err(|_| PrecompileError::Bn254FieldPointNotAMember) } /// Reads a Fq2 (quadratic extension field element) from the input slice. /// @@ -64,7 +65,7 @@ fn new_g1_point(px: Fq, py: Fq) -> Result { // We cannot use `G1Affine::new` because that triggers an assert if the point is not on the curve. let point = G1Affine::new_unchecked(px, py); if !point.is_on_curve() || !point.is_in_correct_subgroup_assuming_on_curve() { - return Err(PrecompileError::Bn128AffineGFailedToCreate); + return Err(PrecompileError::Bn254AffineGFailedToCreate); } Ok(point) } @@ -72,7 +73,7 @@ fn new_g1_point(px: Fq, py: Fq) -> Result { /// Creates a new `G2` point from the given Fq2 coordinates. /// -/// G2 points in BN128 are defined over a quadratic extension field Fq2. +/// G2 points in BN254 are defined over a quadratic extension field Fq2. /// This function takes two Fq2 elements representing the x and y coordinates /// and creates a G2 point. /// @@ -89,7 +90,7 @@ fn new_g2_point(x: Fq2, y: Fq2) -> Result { // We cannot use `G1Affine::new` because that triggers an assert if the point is not on the curve. let point = G2Affine::new_unchecked(x, y); if !point.is_on_curve() || !point.is_in_correct_subgroup_assuming_on_curve() { - return Err(PrecompileError::Bn128AffineGFailedToCreate); + return Err(PrecompileError::Bn254AffineGFailedToCreate); } point }; @@ -180,7 +181,7 @@ pub(super) fn read_scalar(input: &[u8]) -> Fr { /// Performs point addition on two G1 points. #[inline] -pub(super) fn g1_point_add(p1_bytes: &[u8], p2_bytes: &[u8]) -> Result<[u8; 64], PrecompileError> { +pub(crate) fn g1_point_add(p1_bytes: &[u8], p2_bytes: &[u8]) -> Result<[u8; 64], PrecompileError> { let p1 = read_g1_point(p1_bytes)?; let p2 = read_g1_point(p2_bytes)?; @@ -194,7 +195,7 @@ pub(super) fn g1_point_add(p1_bytes: &[u8], p2_bytes: &[u8]) -> Result<[u8; 64], /// Performs a G1 scalar multiplication. #[inline] -pub(super) fn g1_point_mul( +pub(crate) fn g1_point_mul( point_bytes: &[u8], fr_bytes: &[u8], ) -> Result<[u8; 64], PrecompileError> { @@ -215,7 +216,7 @@ pub(super) fn g1_point_mul( /// Note: If the input is empty, this function returns true. /// This is different to EIP2537 which disallows the empty input. #[inline] -pub(super) fn pairing_check(pairs: &[(&[u8], &[u8])]) -> Result { +pub(crate) fn pairing_check(pairs: &[(&[u8], &[u8])]) -> Result { let mut g1_points = Vec::with_capacity(pairs.len()); let mut g2_points = Vec::with_capacity(pairs.len()); diff --git a/crates/precompile/src/bn128/substrate.rs b/crates/precompile/src/bn254/substrate.rs similarity index 94% rename from crates/precompile/src/bn128/substrate.rs rename to crates/precompile/src/bn254/substrate.rs index ee3b5c162b..d4e18cec4b 100644 --- a/crates/precompile/src/bn128/substrate.rs +++ b/crates/precompile/src/bn254/substrate.rs @@ -14,7 +14,7 @@ use std::vec::Vec; /// Panics if the input is not at least 32 bytes long. #[inline] fn read_fq(input: &[u8]) -> Result { - Fq::from_slice(&input[..FQ_LEN]).map_err(|_| PrecompileError::Bn128FieldPointNotAMember) + Fq::from_slice(&input[..FQ_LEN]).map_err(|_| PrecompileError::Bn254FieldPointNotAMember) } /// Reads a Fq2 (quadratic extension field element) from the input slice. /// @@ -49,13 +49,13 @@ fn new_g1_point(px: Fq, py: Fq) -> Result { } else { AffineG1::new(px, py) .map(Into::into) - .map_err(|_| PrecompileError::Bn128AffineGFailedToCreate) + .map_err(|_| PrecompileError::Bn254AffineGFailedToCreate) } } /// Creates a new `G2` point from the given Fq2 coordinates. /// -/// G2 points in BN128 are defined over a quadratic extension field Fq2. +/// G2 points in BN254 are defined over a quadratic extension field Fq2. /// This function takes two Fq2 elements representing the x and y coordinates /// and creates a G2 point. /// @@ -69,7 +69,7 @@ fn new_g2_point(x: Fq2, y: Fq2) -> Result { let point = if x.is_zero() && y.is_zero() { G2::zero() } else { - G2::from(AffineG2::new(x, y).map_err(|_| PrecompileError::Bn128AffineGFailedToCreate)?) + G2::from(AffineG2::new(x, y).map_err(|_| PrecompileError::Bn254AffineGFailedToCreate)?) }; Ok(point) @@ -151,7 +151,7 @@ pub(super) fn read_scalar(input: &[u8]) -> bn::Fr { /// Performs point addition on two G1 points. #[inline] -pub(super) fn g1_point_add(p1_bytes: &[u8], p2_bytes: &[u8]) -> Result<[u8; 64], PrecompileError> { +pub(crate) fn g1_point_add(p1_bytes: &[u8], p2_bytes: &[u8]) -> Result<[u8; 64], PrecompileError> { let p1 = read_g1_point(p1_bytes)?; let p2 = read_g1_point(p2_bytes)?; let result = p1 + p2; @@ -160,7 +160,7 @@ pub(super) fn g1_point_add(p1_bytes: &[u8], p2_bytes: &[u8]) -> Result<[u8; 64], /// Performs a G1 scalar multiplication. #[inline] -pub(super) fn g1_point_mul( +pub(crate) fn g1_point_mul( point_bytes: &[u8], fr_bytes: &[u8], ) -> Result<[u8; 64], PrecompileError> { @@ -176,7 +176,7 @@ pub(super) fn g1_point_mul( /// Note: If the input is empty, this function returns true. /// This is different to EIP2537 which disallows the empty input. #[inline] -pub(super) fn pairing_check(pairs: &[(&[u8], &[u8])]) -> Result { +pub(crate) fn pairing_check(pairs: &[(&[u8], &[u8])]) -> Result { let mut parsed_pairs = Vec::with_capacity(pairs.len()); for (g1_bytes, g2_bytes) in pairs { diff --git a/crates/precompile/src/hash.rs b/crates/precompile/src/hash.rs index 58286d6485..3ac8988f36 100644 --- a/crates/precompile/src/hash.rs +++ b/crates/precompile/src/hash.rs @@ -1,16 +1,20 @@ //! Hash precompiles, it contains SHA-256 and RIPEMD-160 hash precompiles //! More details in [`sha256_run`] and [`ripemd160_run`] use super::calc_linear_cost_u32; -use crate::{PrecompileError, PrecompileOutput, PrecompileResult, PrecompileWithAddress}; -use sha2::Digest; +use crate::{ + crypto, Precompile, PrecompileError, PrecompileId, PrecompileOutput, PrecompileResult, +}; /// SHA-256 precompile -pub const SHA256: PrecompileWithAddress = - PrecompileWithAddress(crate::u64_to_address(2), sha256_run); +pub const SHA256: Precompile = + Precompile::new(PrecompileId::Sha256, crate::u64_to_address(2), sha256_run); /// RIPEMD-160 precompile -pub const RIPEMD160: PrecompileWithAddress = - PrecompileWithAddress(crate::u64_to_address(3), ripemd160_run); +pub const RIPEMD160: Precompile = Precompile::new( + PrecompileId::Ripemd160, + crate::u64_to_address(3), + ripemd160_run, +); /// Computes the SHA-256 hash of the input data /// @@ -23,7 +27,7 @@ pub fn sha256_run(input: &[u8], gas_limit: u64) -> PrecompileResult { if cost > gas_limit { Err(PrecompileError::OutOfGas) } else { - let output = sha2::Sha256::digest(input); + let output = crypto().sha256(input); Ok(PrecompileOutput::new(cost, output.to_vec().into())) } } @@ -39,11 +43,7 @@ pub fn ripemd160_run(input: &[u8], gas_limit: u64) -> PrecompileResult { if gas_used > gas_limit { Err(PrecompileError::OutOfGas) } else { - let mut hasher = ripemd::Ripemd160::new(); - hasher.update(input); - - let mut output = [0u8; 32]; - hasher.finalize_into((&mut output[12..]).into()); + let output = crypto().ripemd160(input); Ok(PrecompileOutput::new(gas_used, output.to_vec().into())) } } diff --git a/crates/precompile/src/id.rs b/crates/precompile/src/id.rs new file mode 100644 index 0000000000..49c8259fff --- /dev/null +++ b/crates/precompile/src/id.rs @@ -0,0 +1,181 @@ +use std::borrow::Cow; + +use primitives::{address, Address}; + +use crate::{Precompile, PrecompileSpecId}; + +/// Precompile with address and function. +/// Unique precompile identifier. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub enum PrecompileId { + /// Elliptic curve digital signature algorithm (ECDSA) public key recovery function. + EcRec, + /// SHA2-256 hash function. + Sha256, + /// RIPEMD-160 hash function. + Ripemd160, + /// Identity precompile. + Identity, + /// Arbitrary-precision exponentiation under modulo. + ModExp, + /// Point addition (ADD) on the elliptic curve 'alt_bn128'. + Bn254Add, + /// Scalar multiplication (MUL) on the elliptic curve 'alt_bn128'. + Bn254Mul, + /// Bilinear function on groups on the elliptic curve 'alt_bn128'. + Bn254Pairing, + /// Compression function F used in the BLAKE2 cryptographic hashing algorithm. + Blake2F, + /// Verify p(z) = y given commitment that corresponds to the polynomial p(x) and a KZG proof. Also verify that the provided commitment matches the provided versioned_hash. + KzgPointEvaluation, + /// Point addition in G1 (curve over base prime field). + Bls12G1Add, + /// Multi-scalar-multiplication (MSM) in G1 (curve over base prime field). + Bls12G1Msm, + /// Point addition in G2 (curve over quadratic extension of the base prime field). + Bls12G2Add, + /// Multi-scalar-multiplication (MSM) in G2 (curve over quadratic extension of the base prime field). + Bls12G2Msm, + /// Pairing operations between a set of pairs of (G1, G2) points. + Bls12Pairing, + /// Base field element mapping into the G1 point. + Bls12MapFpToGp1, + /// Extension field element mapping into the G2 point. + Bls12MapFp2ToGp2, + /// ECDSA signature verification over the secp256r1 elliptic curve (also known as P-256 or prime256v1). + P256Verify, + /// Custom precompile identifier. + Custom(Cow<'static, str>), +} + +impl PrecompileId { + /// Create new custom precompile ID. + pub fn custom(id: I) -> Self + where + I: Into>, + { + Self::Custom(id.into()) + } + + /// Returns the mainnet address for the precompile. + pub fn mainnet_address(&self) -> Option
{ + let address = match self { + Self::EcRec => address!("0x0000000000000000000000000000000000000001"), + Self::Sha256 => address!("0x0000000000000000000000000000000000000002"), + Self::Ripemd160 => address!("0x0000000000000000000000000000000000000003"), + Self::Identity => address!("0x0000000000000000000000000000000000000004"), + Self::ModExp => address!("0x0000000000000000000000000000000000000005"), + Self::Bn254Add => address!("0x0000000000000000000000000000000000000006"), + Self::Bn254Mul => address!("0x0000000000000000000000000000000000000007"), + Self::Bn254Pairing => address!("0x0000000000000000000000000000000000000008"), + Self::Blake2F => address!("0x0000000000000000000000000000000000000009"), + Self::KzgPointEvaluation => address!("0x000000000000000000000000000000000000000A"), + Self::Bls12G1Add => address!("0x000000000000000000000000000000000000000B"), + Self::Bls12G1Msm => address!("0x000000000000000000000000000000000000000C"), + Self::Bls12G2Add => address!("0x000000000000000000000000000000000000000D"), + Self::Bls12G2Msm => address!("0x000000000000000000000000000000000000000E"), + Self::Bls12Pairing => address!("0x000000000000000000000000000000000000000F"), + Self::Bls12MapFpToGp1 => address!("0x0000000000000000000000000000000000000010"), + Self::Bls12MapFp2ToGp2 => address!("0x0000000000000000000000000000000000000011"), + Self::P256Verify => address!("0x0000000000000000000000000000000000000012"), + Self::Custom(_) => return None, + }; + Some(address) + } + + /// Returns the name of the precompile as defined in EIP-7910. + pub fn name(&self) -> &str { + match self { + Self::EcRec => "ECREC", + Self::Sha256 => "SHA256", + Self::Ripemd160 => "RIPEMD160", + Self::Identity => "ID", + Self::ModExp => "MODEXP", + Self::Bn254Add => "BN254_ADD", + Self::Bn254Mul => "BN254_MUL", + Self::Bn254Pairing => "BN254_PAIRING", + Self::Blake2F => "BLAKE2F", + Self::KzgPointEvaluation => "KZG_POINT_EVALUATION", + Self::Bls12G1Add => "BLS12_G1ADD", + Self::Bls12G1Msm => "BLS12_G1MSM", + Self::Bls12G2Add => "BLS12_G2ADD", + Self::Bls12G2Msm => "BLS12_G2MSM", + Self::Bls12Pairing => "BLS12_PAIRING_CHECK", + Self::Bls12MapFpToGp1 => "BLS12_MAP_FP_TO_G1", + Self::Bls12MapFp2ToGp2 => "BLS12_MAP_FP2_TO_G2", + Self::P256Verify => "P256VERIFY", + Self::Custom(a) => a.as_ref(), + } + } + + /// Returns the precompile function for the given spec. + /// + /// If case of [`PrecompileId::Custom`] it will return [`None`]. + /// + /// For case where precompile was still not introduced in the spec, + /// it will return [`Some`] with fork closest to activation. + pub fn precompile(&self, spec: PrecompileSpecId) -> Option { + use PrecompileSpecId::*; + + let precompile = match self { + Self::EcRec => crate::secp256k1::ECRECOVER, + Self::Sha256 => crate::hash::SHA256, + Self::Ripemd160 => crate::hash::RIPEMD160, + Self::Identity => crate::identity::FUN, + Self::ModExp => { + // ModExp changes gas calculation based on spec + if spec < BERLIN { + crate::modexp::BYZANTIUM + } else if spec < OSAKA { + crate::modexp::BERLIN + } else { + crate::modexp::OSAKA + } + } + Self::Bn254Add => { + // BN254 add - gas cost changes in Istanbul + if spec < ISTANBUL { + crate::bn254::add::BYZANTIUM + } else { + crate::bn254::add::ISTANBUL + } + } + Self::Bn254Mul => { + // BN254 mul - gas cost changes in Istanbul + if spec < ISTANBUL { + crate::bn254::mul::BYZANTIUM + } else { + crate::bn254::mul::ISTANBUL + } + } + Self::Bn254Pairing => { + // BN254 pairing - gas cost changes in Istanbul + if spec < ISTANBUL { + crate::bn254::pair::BYZANTIUM + } else { + crate::bn254::pair::ISTANBUL + } + } + Self::Blake2F => crate::blake2::FUN, + Self::KzgPointEvaluation => crate::kzg_point_evaluation::POINT_EVALUATION, + Self::Bls12G1Add => crate::bls12_381::g1_add::PRECOMPILE, + Self::Bls12G1Msm => crate::bls12_381::g1_msm::PRECOMPILE, + Self::Bls12G2Add => crate::bls12_381::g2_add::PRECOMPILE, + Self::Bls12G2Msm => crate::bls12_381::g2_msm::PRECOMPILE, + Self::Bls12Pairing => crate::bls12_381::pairing::PRECOMPILE, + Self::Bls12MapFpToGp1 => crate::bls12_381::map_fp_to_g1::PRECOMPILE, + Self::Bls12MapFp2ToGp2 => crate::bls12_381::map_fp2_to_g2::PRECOMPILE, + Self::P256Verify => { + // P256 verify - gas cost changes in Osaka + if spec < OSAKA { + crate::secp256r1::P256VERIFY + } else { + crate::secp256r1::P256VERIFY_OSAKA + } + } + Self::Custom(_) => return None, + }; + + Some(precompile) + } +} diff --git a/crates/precompile/src/identity.rs b/crates/precompile/src/identity.rs index 9377bf440c..69129b138a 100644 --- a/crates/precompile/src/identity.rs +++ b/crates/precompile/src/identity.rs @@ -1,11 +1,14 @@ //! Identity precompile returns use super::calc_linear_cost_u32; -use crate::{PrecompileError, PrecompileOutput, PrecompileResult, PrecompileWithAddress}; +use crate::{Precompile, PrecompileError, PrecompileId, PrecompileOutput, PrecompileResult}; use primitives::Bytes; /// Address of the identity precompile. -pub const FUN: PrecompileWithAddress = - PrecompileWithAddress(crate::u64_to_address(4), identity_run); +pub const FUN: Precompile = Precompile::new( + PrecompileId::Identity, + crate::u64_to_address(4), + identity_run, +); /// The base cost of the operation pub const IDENTITY_BASE: u64 = 15; diff --git a/crates/precompile/src/interface.rs b/crates/precompile/src/interface.rs index 1c9c683458..cac543fffd 100644 --- a/crates/precompile/src/interface.rs +++ b/crates/precompile/src/interface.rs @@ -1,8 +1,28 @@ //! Interface for the precompiles. It contains the precompile result type, //! the precompile output type, and the precompile error type. -use core::fmt; -use primitives::Bytes; -use std::string::String; +use core::fmt::{self, Debug}; +use primitives::{Bytes, OnceLock}; +use std::{boxed::Box, string::String, vec::Vec}; + +use crate::bls12_381::{G1Point, G1PointScalar, G2Point, G2PointScalar}; + +/// Global crypto provider instance +static CRYPTO: OnceLock> = OnceLock::new(); + +/// Install a custom crypto provider globally. +pub fn install_crypto(crypto: C) -> bool { + if CRYPTO.get().is_some() { + return false; + } + + CRYPTO.get_or_init(|| Box::new(crypto)); + true +} + +/// Get the installed crypto provider, or the default if none is installed. +pub fn crypto() -> &'static dyn Crypto { + CRYPTO.get_or_init(|| Box::new(DefaultCrypto)).as_ref() +} /// A precompile operation result type /// @@ -46,7 +66,138 @@ impl PrecompileOutput { } } -/// Precompile function type. Takes input and gas limit and returns precompile result. +/// Crypto operations trait for precompiles. +pub trait Crypto: Send + Sync + Debug { + /// Compute SHA-256 hash + #[inline] + fn sha256(&self, input: &[u8]) -> [u8; 32] { + use sha2::Digest; + let output = sha2::Sha256::digest(input); + output.into() + } + + /// Compute RIPEMD-160 hash + #[inline] + fn ripemd160(&self, input: &[u8]) -> [u8; 32] { + use ripemd::Digest; + let mut hasher = ripemd::Ripemd160::new(); + hasher.update(input); + + let mut output = [0u8; 32]; + hasher.finalize_into((&mut output[12..]).into()); + output + } + + /// BN254 elliptic curve addition. + #[inline] + fn bn254_g1_add(&self, p1: &[u8], p2: &[u8]) -> Result<[u8; 64], PrecompileError> { + crate::bn254::crypto_backend::g1_point_add(p1, p2) + } + + /// BN254 elliptic curve scalar multiplication. + #[inline] + fn bn254_g1_mul(&self, point: &[u8], scalar: &[u8]) -> Result<[u8; 64], PrecompileError> { + crate::bn254::crypto_backend::g1_point_mul(point, scalar) + } + + /// BN254 pairing check. + #[inline] + fn bn254_pairing_check(&self, pairs: &[(&[u8], &[u8])]) -> Result { + crate::bn254::crypto_backend::pairing_check(pairs) + } + + /// secp256k1 ECDSA signature recovery. + #[inline] + fn secp256k1_ecrecover( + &self, + sig: &[u8; 64], + recid: u8, + msg: &[u8; 32], + ) -> Result<[u8; 32], PrecompileError> { + crate::secp256k1::ecrecover_bytes(*sig, recid, *msg) + .ok_or_else(|| PrecompileError::other("ecrecover failed")) + } + + /// Modular exponentiation. + #[inline] + fn modexp(&self, base: &[u8], exp: &[u8], modulus: &[u8]) -> Result, PrecompileError> { + Ok(crate::modexp::modexp(base, exp, modulus)) + } + + /// Blake2 compression function. + #[inline] + fn blake2_compress(&self, rounds: u32, h: &mut [u64; 8], m: [u64; 16], t: [u64; 2], f: bool) { + crate::blake2::algo::compress(rounds as usize, h, m, t, f); + } + + /// secp256r1 (P-256) signature verification. + #[inline] + fn secp256r1_verify_signature(&self, msg: &[u8; 32], sig: &[u8; 64], pk: &[u8; 64]) -> bool { + crate::secp256r1::verify_signature(*msg, *sig, *pk).is_some() + } + + /// KZG point evaluation. + #[inline] + fn verify_kzg_proof( + &self, + z: &[u8; 32], + y: &[u8; 32], + commitment: &[u8; 48], + proof: &[u8; 48], + ) -> Result<(), PrecompileError> { + if !crate::kzg_point_evaluation::verify_kzg_proof(commitment, z, y, proof) { + return Err(PrecompileError::BlobVerifyKzgProofFailed); + } + + Ok(()) + } + + /// BLS12-381 G1 addition (returns 96-byte unpadded G1 point) + fn bls12_381_g1_add(&self, a: G1Point, b: G1Point) -> Result<[u8; 96], PrecompileError> { + crate::bls12_381::crypto_backend::p1_add_affine_bytes(a, b) + } + + /// BLS12-381 G1 multi-scalar multiplication (returns 96-byte unpadded G1 point) + fn bls12_381_g1_msm( + &self, + pairs: &mut dyn Iterator>, + ) -> Result<[u8; 96], PrecompileError> { + crate::bls12_381::crypto_backend::p1_msm_bytes(pairs) + } + + /// BLS12-381 G2 addition (returns 192-byte unpadded G2 point) + fn bls12_381_g2_add(&self, a: G2Point, b: G2Point) -> Result<[u8; 192], PrecompileError> { + crate::bls12_381::crypto_backend::p2_add_affine_bytes(a, b) + } + + /// BLS12-381 G2 multi-scalar multiplication (returns 192-byte unpadded G2 point) + fn bls12_381_g2_msm( + &self, + pairs: &mut dyn Iterator>, + ) -> Result<[u8; 192], PrecompileError> { + crate::bls12_381::crypto_backend::p2_msm_bytes(pairs) + } + + /// BLS12-381 pairing check. + fn bls12_381_pairing_check( + &self, + pairs: &[(G1Point, G2Point)], + ) -> Result { + crate::bls12_381::crypto_backend::pairing_check_bytes(pairs) + } + + /// BLS12-381 map field element to G1. + fn bls12_381_fp_to_g1(&self, fp: &[u8; 48]) -> Result<[u8; 96], PrecompileError> { + crate::bls12_381::crypto_backend::map_fp_to_g1_bytes(fp) + } + + /// BLS12-381 map field element to G2. + fn bls12_381_fp2_to_g2(&self, fp2: ([u8; 48], [u8; 48])) -> Result<[u8; 192], PrecompileError> { + crate::bls12_381::crypto_backend::map_fp2_to_g2_bytes(&fp2.0, &fp2.1) + } +} + +/// Precompile function type. Takes input, gas limit, and crypto implementation and returns precompile result. pub type PrecompileFn = fn(&[u8], u64) -> PrecompileResult; /// Precompile error type. @@ -66,12 +217,12 @@ pub enum PrecompileError { ModexpModOverflow, /// Modexp limit all input sizes. ModexpEip7823LimitSize, - /// Bn128 errors - Bn128FieldPointNotAMember, - /// Bn128 affine g failed to create - Bn128AffineGFailedToCreate, - /// Bn128 pair length - Bn128PairLength, + /// Bn254 errors + Bn254FieldPointNotAMember, + /// Bn254 affine g failed to create + Bn254AffineGFailedToCreate, + /// Bn254 pair length + Bn254PairLength, // Blob errors /// The input length is not exactly 192 bytes BlobInvalidInputLength, @@ -109,9 +260,9 @@ impl fmt::Display for PrecompileError { Self::ModexpBaseOverflow => "modexp base overflow", Self::ModexpModOverflow => "modexp mod overflow", Self::ModexpEip7823LimitSize => "Modexp limit all input sizes.", - Self::Bn128FieldPointNotAMember => "field point not a member of bn128 curve", - Self::Bn128AffineGFailedToCreate => "failed to create affine g point for bn128 curve", - Self::Bn128PairLength => "bn128 invalid pair length", + Self::Bn254FieldPointNotAMember => "field point not a member of bn254 curve", + Self::Bn254AffineGFailedToCreate => "failed to create affine g point for bn254 curve", + Self::Bn254PairLength => "bn254 invalid pair length", Self::BlobInvalidInputLength => "invalid blob input length", Self::BlobMismatchedVersion => "mismatched blob version", Self::BlobVerifyKzgProofFailed => "verifying blob kzg proof failed", @@ -121,3 +272,9 @@ impl fmt::Display for PrecompileError { f.write_str(s) } } + +/// Default implementation of the Crypto trait using the existing crypto libraries. +#[derive(Clone, Debug)] +pub struct DefaultCrypto; + +impl Crypto for DefaultCrypto {} diff --git a/crates/precompile/src/kzg_point_evaluation.rs b/crates/precompile/src/kzg_point_evaluation.rs index 9fb761cd7b..9bec2c322c 100644 --- a/crates/precompile/src/kzg_point_evaluation.rs +++ b/crates/precompile/src/kzg_point_evaluation.rs @@ -1,18 +1,18 @@ //! KZG point evaluation precompile added in [`EIP-4844`](https://eips.ethereum.org/EIPS/eip-4844) //! For more details check [`run`] function. -use crate::{Address, PrecompileError, PrecompileOutput, PrecompileResult, PrecompileWithAddress}; -cfg_if::cfg_if! { - if #[cfg(feature = "c-kzg")] { - use c_kzg::{Bytes32, Bytes48}; - } else if #[cfg(feature = "kzg-rs")] { - use kzg_rs::{Bytes32, Bytes48, KzgProof}; - } -} +use crate::{ + crypto, Address, Precompile, PrecompileError, PrecompileId, PrecompileOutput, PrecompileResult, +}; +pub mod arkworks; + +#[cfg(feature = "blst")] +pub mod blst; + use primitives::hex_literal::hex; -use sha2::{Digest, Sha256}; /// KZG point evaluation precompile, containing address and function to run. -pub const POINT_EVALUATION: PrecompileWithAddress = PrecompileWithAddress(ADDRESS, run); +pub const POINT_EVALUATION: Precompile = + Precompile::new(PrecompileId::KzgPointEvaluation, ADDRESS, run); /// Address of the KZG point evaluation precompile. pub const ADDRESS: Address = crate::u64_to_address(0x0A); @@ -59,9 +59,7 @@ pub fn run(input: &[u8], gas_limit: u64) -> PrecompileResult { let z = input[32..64].try_into().unwrap(); let y = input[64..96].try_into().unwrap(); let proof = input[144..192].try_into().unwrap(); - if !verify_kzg_proof(commitment, z, y, proof) { - return Err(PrecompileError::BlobVerifyKzgProofFailed); - } + crypto().verify_kzg_proof(z, y, commitment, proof)?; // Return FIELD_ELEMENTS_PER_BLOB and BLS_MODULUS as padded 32 byte big endian values Ok(PrecompileOutput::new(GAS_COST, RETURN_VALUE.into())) @@ -70,7 +68,7 @@ pub fn run(input: &[u8], gas_limit: u64) -> PrecompileResult { /// `VERSIONED_HASH_VERSION_KZG ++ sha256(commitment)[1..]` #[inline] pub fn kzg_to_versioned_hash(commitment: &[u8]) -> [u8; 32] { - let mut hash: [u8; 32] = Sha256::digest(commitment).into(); + let mut hash = crypto().sha256(commitment); hash[0] = VERSIONED_HASH_VERSION_KZG; hash } @@ -85,39 +83,28 @@ pub fn verify_kzg_proof( ) -> bool { cfg_if::cfg_if! { if #[cfg(feature = "c-kzg")] { + use c_kzg::{Bytes48, Bytes32}; + + let as_bytes48 = |bytes: &[u8; 48]| -> &Bytes48 { unsafe { &*bytes.as_ptr().cast() } }; + let as_bytes32 = |bytes: &[u8; 32]| -> &Bytes32 { unsafe { &*bytes.as_ptr().cast() } }; + let kzg_settings = c_kzg::ethereum_kzg_settings(8); kzg_settings.verify_kzg_proof(as_bytes48(commitment), as_bytes32(z), as_bytes32(y), as_bytes48(proof)).unwrap_or(false) } else if #[cfg(feature = "kzg-rs")] { + use kzg_rs::{Bytes48, Bytes32, KzgProof}; let env = kzg_rs::EnvKzgSettings::default(); + let as_bytes48 = |bytes: &[u8; 48]| -> &Bytes48 { unsafe { &*bytes.as_ptr().cast() } }; + let as_bytes32 = |bytes: &[u8; 32]| -> &Bytes32 { unsafe { &*bytes.as_ptr().cast() } }; + let kzg_settings = env.get(); KzgProof::verify_kzg_proof(as_bytes48(commitment), as_bytes32(z), as_bytes32(y), as_bytes48(proof), kzg_settings).unwrap_or(false) + } else if #[cfg(feature = "blst")] { + blst::verify_kzg_proof(commitment, z, y, proof) + } else { + arkworks::verify_kzg_proof(commitment, z, y, proof) } } } - -/// Convert a slice to an array of a specific size. -#[inline] -#[track_caller] -fn as_array(bytes: &[u8]) -> &[u8; N] { - bytes.try_into().expect("slice with incorrect length") -} - -/// Convert a slice to a 32 byte big endian array. -#[inline] -#[track_caller] -fn as_bytes32(bytes: &[u8]) -> &Bytes32 { - // SAFETY: `#[repr(C)] Bytes32([u8; 32])` - unsafe { &*as_array::<32>(bytes).as_ptr().cast() } -} - -/// Convert a slice to a 48 byte big endian array. -#[inline] -#[track_caller] -fn as_bytes48(bytes: &[u8]) -> &Bytes48 { - // SAFETY: `#[repr(C)] Bytes48([u8; 48])` - unsafe { &*as_array::<48>(bytes).as_ptr().cast() } -} - #[cfg(test)] mod tests { use super::*; @@ -127,7 +114,8 @@ mod tests { // Test data from: https://github.com/ethereum/c-kzg-4844/blob/main/tests/verify_kzg_proof/kzg-mainnet/verify_kzg_proof_case_correct_proof_4_4/data.yaml let commitment = hex!("8f59a8d2a1a625a17f3fea0fe5eb8c896db3764f3185481bc22f91b4aaffcca25f26936857bc3a7c2539ea8ec3a952b7").to_vec(); - let mut versioned_hash = Sha256::digest(&commitment).to_vec(); + let crypto = &crate::DefaultCrypto; + let mut versioned_hash = crate::Crypto::sha256(crypto, &commitment).to_vec(); versioned_hash[0] = VERSIONED_HASH_VERSION_KZG; let z = hex!("73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000000").to_vec(); let y = hex!("1522a4a7f34e1ea350ae07c29c96c7e79655aa926122e95fe69fcbd932ca49e9").to_vec(); @@ -141,4 +129,26 @@ mod tests { assert_eq!(output.gas_used, gas); assert_eq!(output.bytes[..], expected_output); } + + #[test] + fn test_invalid_input() { + let commitment = hex!("c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); + let z = hex!("0000000000000000000000000000000000000000000000000000000000000000"); + let y = hex!("73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000001"); + let proof = hex!("c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); + + let t = verify_kzg_proof(&commitment, &z, &y, &proof); + assert!(!t); + } + + #[test] + fn test_valid_input() { + let commitment = hex!("c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); + let z = hex!("73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000000"); + let y = hex!("0000000000000000000000000000000000000000000000000000000000000000"); + let proof = hex!("c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); + + let t = verify_kzg_proof(&commitment, &z, &y, &proof); + assert!(t); + } } diff --git a/crates/precompile/src/kzg_point_evaluation/arkworks.rs b/crates/precompile/src/kzg_point_evaluation/arkworks.rs new file mode 100644 index 0000000000..2f23d2481e --- /dev/null +++ b/crates/precompile/src/kzg_point_evaluation/arkworks.rs @@ -0,0 +1,135 @@ +//! KZG point evaluation precompile using Arkworks BLS12-381 implementation. +use crate::bls12_381::arkworks::pairing_check; +use crate::bls12_381_const::TRUSTED_SETUP_TAU_G2_BYTES; +use crate::PrecompileError; +use ark_bls12_381::{Fr, G1Affine, G2Affine}; +use ark_ec::{AffineRepr, CurveGroup}; +use ark_ff::{BigInteger, PrimeField}; +use ark_serialize::CanonicalDeserialize; +use core::ops::Neg; +use std::string::ToString; + +/// Verify KZG proof using BLS12-381 implementation. +/// +/// +/// +#[inline] +pub fn verify_kzg_proof( + commitment: &[u8; 48], + z: &[u8; 32], + y: &[u8; 32], + proof: &[u8; 48], +) -> bool { + // Parse the commitment (G1 point) + let Ok(commitment_point) = parse_g1_compressed(commitment) else { + return false; + }; + + // Parse the proof (G1 point) + let Ok(proof_point) = parse_g1_compressed(proof) else { + return false; + }; + + // Parse z and y as field elements (Fr, scalar field) + // We expect 32-byte big-endian scalars that must be canonical + let Ok(z_fr) = read_scalar_canonical(z) else { + return false; + }; + let Ok(y_fr) = read_scalar_canonical(y) else { + return false; + }; + + // Get the trusted setup G2 point [τ]₂ + let tau_g2 = get_trusted_setup_g2(); + + // Get generators + let g1 = get_g1_generator(); + let g2 = get_g2_generator(); + + // Compute P_minus_y = commitment - [y]G₁ + let y_g1 = p1_scalar_mul(&g1, &y_fr); + let p_minus_y = p1_sub_affine(&commitment_point, &y_g1); + + // Compute X_minus_z = [τ]G₂ - [z]G₂ + let z_g2 = p2_scalar_mul(&g2, &z_fr); + let x_minus_z = p2_sub_affine(&tau_g2, &z_g2); + + // Verify: P - y = Q * (X - z) + // Using pairing check: e(P - y, -G₂) * e(proof, X - z) == 1 + let neg_g2 = p2_neg(&g2); + + pairing_check(&[(p_minus_y, neg_g2), (proof_point, x_minus_z)]) +} + +/// Get the trusted setup G2 point `[τ]₂` from the Ethereum KZG ceremony. +/// This is g2_monomial_1 from trusted_setup_4096.json +fn get_trusted_setup_g2() -> G2Affine { + // Parse the compressed G2 point using unchecked deserialization since we trust this point + // This should never fail since we're using a known valid point from the trusted setup + G2Affine::deserialize_compressed_unchecked(&TRUSTED_SETUP_TAU_G2_BYTES[..]) + .expect("Failed to parse trusted setup G2 point") +} + +/// Parse a G1 point from compressed format (48 bytes) +fn parse_g1_compressed(bytes: &[u8; 48]) -> Result { + G1Affine::deserialize_compressed(&bytes[..]) + .map_err(|_| PrecompileError::Other("Invalid compressed G1 point".to_string())) +} + +/// Read a scalar field element from bytes and verify it's canonical +fn read_scalar_canonical(bytes: &[u8; 32]) -> Result { + let fr = Fr::from_be_bytes_mod_order(bytes); + + // Check if the field element is canonical by serializing back and comparing + let bytes_roundtrip = fr.into_bigint().to_bytes_be(); + + if bytes_roundtrip.as_slice() != bytes { + return Err(PrecompileError::Other( + "Non-canonical scalar field element".to_string(), + )); + } + + Ok(fr) +} + +/// Get G1 generator point +#[inline] +fn get_g1_generator() -> G1Affine { + G1Affine::generator() +} + +/// Get G2 generator point +#[inline] +fn get_g2_generator() -> G2Affine { + G2Affine::generator() +} + +/// Scalar multiplication for G1 points +#[inline] +fn p1_scalar_mul(point: &G1Affine, scalar: &Fr) -> G1Affine { + point.mul_bigint(scalar.into_bigint()).into_affine() +} + +/// Scalar multiplication for G2 points +#[inline] +fn p2_scalar_mul(point: &G2Affine, scalar: &Fr) -> G2Affine { + point.mul_bigint(scalar.into_bigint()).into_affine() +} + +/// Subtract two G1 points in affine form +#[inline] +fn p1_sub_affine(a: &G1Affine, b: &G1Affine) -> G1Affine { + (a.into_group() - b.into_group()).into_affine() +} + +/// Subtract two G2 points in affine form +#[inline] +fn p2_sub_affine(a: &G2Affine, b: &G2Affine) -> G2Affine { + (a.into_group() - b.into_group()).into_affine() +} + +/// Negate a G2 point +#[inline] +fn p2_neg(p: &G2Affine) -> G2Affine { + p.neg() +} diff --git a/crates/precompile/src/kzg_point_evaluation/blst.rs b/crates/precompile/src/kzg_point_evaluation/blst.rs new file mode 100644 index 0000000000..fc13973e3d --- /dev/null +++ b/crates/precompile/src/kzg_point_evaluation/blst.rs @@ -0,0 +1,181 @@ +//! KZG point evaluation precompile using BLST BLS12-381 implementation. +use crate::bls12_381::blst::{ + p1_add_or_double, p1_from_affine, p1_scalar_mul, p1_to_affine, p2_add_or_double, + p2_from_affine, p2_scalar_mul, p2_to_affine, pairing_check, +}; +use crate::bls12_381_const::TRUSTED_SETUP_TAU_G2_BYTES; +use crate::PrecompileError; +use ::blst::{ + blst_p1_affine, blst_p1_affine_in_g1, blst_p1_affine_on_curve, blst_p2_affine, blst_scalar, + blst_scalar_fr_check, blst_scalar_from_bendian, +}; +use std::string::ToString; + +/// Verify KZG proof using BLST BLS12-381 implementation. +/// +/// +/// +#[inline] +pub fn verify_kzg_proof( + commitment: &[u8; 48], + z: &[u8; 32], + y: &[u8; 32], + proof: &[u8; 48], +) -> bool { + // Parse the commitment (G1 point) + let Ok(commitment_point) = parse_g1_compressed(commitment) else { + return false; + }; + + // Parse the proof (G1 point) + let Ok(proof_point) = parse_g1_compressed(proof) else { + return false; + }; + + // Parse z and y as field elements (Fr, scalar field) + let Ok(z_scalar) = read_scalar_canonical(z) else { + return false; + }; + let Ok(y_scalar) = read_scalar_canonical(y) else { + return false; + }; + + // Get the trusted setup G2 point [τ]₂ + let tau_g2 = get_trusted_setup_g2(); + + // Get generators + let g1 = get_g1_generator(); + let g2 = get_g2_generator(); + + // Compute P_minus_y = commitment - [y]G₁ + let y_g1 = p1_scalar_mul(&g1, &y_scalar); + let p_minus_y = p1_sub_affine(&commitment_point, &y_g1); + + // Compute X_minus_z = [τ]G₂ - [z]G₂ + let z_g2 = p2_scalar_mul(&g2, &z_scalar); + let x_minus_z = p2_sub_affine(&tau_g2, &z_g2); + + // Verify: P - y = Q * (X - z) + // Using pairing check: e(P - y, -G₂) * e(proof, X - z) == 1 + let neg_g2 = p2_neg(&g2); + + pairing_check(&[(p_minus_y, neg_g2), (proof_point, x_minus_z)]) +} + +/// Get the trusted setup G2 point `[τ]₂` from the Ethereum KZG ceremony. +/// This is g2_monomial_1 from trusted_setup_4096.json +fn get_trusted_setup_g2() -> blst_p2_affine { + // For compressed G2, we need to decompress + let mut g2_affine = blst_p2_affine::default(); + unsafe { + // The compressed format has x coordinate and a flag bit for y + // We use deserialize_compressed which handles this automatically + let result = blst::blst_p2_deserialize(&mut g2_affine, TRUSTED_SETUP_TAU_G2_BYTES.as_ptr()); + if result != blst::BLST_ERROR::BLST_SUCCESS { + panic!("Failed to deserialize trusted setup G2 point"); + } + } + g2_affine +} + +/// Get G1 generator point +fn get_g1_generator() -> blst_p1_affine { + unsafe { ::blst::BLS12_381_G1 } +} + +/// Get G2 generator point +fn get_g2_generator() -> blst_p2_affine { + unsafe { ::blst::BLS12_381_G2 } +} + +/// Parse a G1 point from compressed format (48 bytes) +fn parse_g1_compressed(bytes: &[u8; 48]) -> Result { + let mut point = blst_p1_affine::default(); + unsafe { + let result = blst::blst_p1_deserialize(&mut point, bytes.as_ptr()); + if result != blst::BLST_ERROR::BLST_SUCCESS { + return Err(PrecompileError::Other( + "Invalid compressed G1 point".to_string(), + )); + } + + // Verify the point is on curve + if !blst_p1_affine_on_curve(&point) { + return Err(PrecompileError::Other("G1 point not on curve".to_string())); + } + + // Verify the point is in the correct subgroup + if !blst_p1_affine_in_g1(&point) { + return Err(PrecompileError::Other( + "G1 point not in correct subgroup".to_string(), + )); + } + } + Ok(point) +} + +/// Read a scalar field element from bytes and verify it's canonical +fn read_scalar_canonical(bytes: &[u8; 32]) -> Result { + let mut scalar = blst_scalar::default(); + + // Read scalar from big endian bytes + unsafe { + blst_scalar_from_bendian(&mut scalar, bytes.as_ptr()); + } + + if unsafe { !blst_scalar_fr_check(&scalar) } { + return Err(PrecompileError::Other( + "Non-canonical scalar field element".to_string(), + )); + } + + Ok(scalar) +} + +/// Subtract two G1 points in affine form +fn p1_sub_affine(a: &blst_p1_affine, b: &blst_p1_affine) -> blst_p1_affine { + // Convert first point to Jacobian + let a_jacobian = p1_from_affine(a); + + // Negate second point + let neg_b = p1_neg(b); + + // Add a + (-b) + let result = p1_add_or_double(&a_jacobian, &neg_b); + + p1_to_affine(&result) +} + +/// Subtract two G2 points in affine form +fn p2_sub_affine(a: &blst_p2_affine, b: &blst_p2_affine) -> blst_p2_affine { + // Convert first point to Jacobian + let a_jacobian = p2_from_affine(a); + + // Negate second point + let neg_b = p2_neg(b); + + // Add a + (-b) + let result = p2_add_or_double(&a_jacobian, &neg_b); + + p2_to_affine(&result) +} + +/// Negate a G1 point +fn p1_neg(p: &blst_p1_affine) -> blst_p1_affine { + // Convert to Jacobian, negate, convert back + let mut p_jacobian = p1_from_affine(p); + unsafe { + ::blst::blst_p1_cneg(&mut p_jacobian, true); + } + p1_to_affine(&p_jacobian) +} + +/// Negate a G2 point +fn p2_neg(p: &blst_p2_affine) -> blst_p2_affine { + // Convert to Jacobian, negate, convert back + let mut p_jacobian = p2_from_affine(p); + unsafe { + ::blst::blst_p2_cneg(&mut p_jacobian, true); + } + p2_to_affine(&p_jacobian) +} diff --git a/crates/precompile/src/lib.rs b/crates/precompile/src/lib.rs index 4cbb7eeee6..92c420054f 100644 --- a/crates/precompile/src/lib.rs +++ b/crates/precompile/src/lib.rs @@ -12,17 +12,18 @@ pub mod blake2; pub mod bls12_381; pub mod bls12_381_const; pub mod bls12_381_utils; -pub mod bn128; +pub mod bn254; pub mod hash; +mod id; pub mod identity; pub mod interface; -#[cfg(any(feature = "c-kzg", feature = "kzg-rs"))] pub mod kzg_point_evaluation; pub mod modexp; pub mod secp256k1; pub mod secp256r1; pub mod utilities; +pub use id::PrecompileId; pub use interface::*; // silence arkworks lint as bn impl will be used as default if both are enabled. @@ -55,11 +56,11 @@ cfg_if::cfg_if! { #[cfg(feature = "gmp")] use aurora_engine_modexp as _; -use cfg_if::cfg_if; use core::hash::Hash; -use once_cell::race::OnceBox; -use primitives::{hardfork::SpecId, Address, HashMap, HashSet}; -use std::{boxed::Box, vec::Vec}; +use primitives::{ + hardfork::SpecId, short_address, Address, HashMap, HashSet, OnceLock, SHORT_ADDRESS_CAP, +}; +use std::vec::Vec; /// Calculate the linear cost of a precompile. pub fn calc_linear_cost_u32(len: usize, base: u64, word: u64) -> u64 { @@ -67,12 +68,27 @@ pub fn calc_linear_cost_u32(len: usize, base: u64, word: u64) -> u64 { } /// Precompiles contain map of precompile addresses to functions and HashSet of precompile addresses. -#[derive(Clone, Default, Debug)] +#[derive(Clone, Debug)] pub struct Precompiles { /// Precompiles - inner: HashMap, - /// Addresses of precompile + inner: HashMap, + /// Addresses of precompiles. addresses: HashSet
, + /// Optimized addresses filter. + optimized_access: Vec>, + /// `true` if all precompiles are short addresses. + all_short_addresses: bool, +} + +impl Default for Precompiles { + fn default() -> Self { + Self { + inner: HashMap::default(), + addresses: HashSet::default(), + optimized_access: vec![None; SHORT_ADDRESS_CAP], + all_short_addresses: true, + } + } } impl Precompiles { @@ -91,7 +107,7 @@ impl Precompiles { /// Returns precompiles for Homestead spec. pub fn homestead() -> &'static Self { - static INSTANCE: OnceBox = OnceBox::new(); + static INSTANCE: OnceLock = OnceLock::new(); INSTANCE.get_or_init(|| { let mut precompiles = Precompiles::default(); precompiles.extend([ @@ -100,18 +116,18 @@ impl Precompiles { hash::RIPEMD160, identity::FUN, ]); - Box::new(precompiles) + precompiles }) } /// Returns inner HashMap of precompiles. - pub fn inner(&self) -> &HashMap { + pub fn inner(&self) -> &HashMap { &self.inner } /// Returns precompiles for Byzantium spec. pub fn byzantium() -> &'static Self { - static INSTANCE: OnceBox = OnceBox::new(); + static INSTANCE: OnceLock = OnceLock::new(); INSTANCE.get_or_init(|| { let mut precompiles = Self::homestead().clone(); precompiles.extend([ @@ -119,41 +135,41 @@ impl Precompiles { modexp::BYZANTIUM, // EIP-196: Precompiled contracts for addition and scalar multiplication on the elliptic curve alt_bn128. // EIP-197: Precompiled contracts for optimal ate pairing check on the elliptic curve alt_bn128. - bn128::add::BYZANTIUM, - bn128::mul::BYZANTIUM, - bn128::pair::BYZANTIUM, + bn254::add::BYZANTIUM, + bn254::mul::BYZANTIUM, + bn254::pair::BYZANTIUM, ]); - Box::new(precompiles) + precompiles }) } /// Returns precompiles for Istanbul spec. pub fn istanbul() -> &'static Self { - static INSTANCE: OnceBox = OnceBox::new(); + static INSTANCE: OnceLock = OnceLock::new(); INSTANCE.get_or_init(|| { let mut precompiles = Self::byzantium().clone(); precompiles.extend([ // EIP-1108: Reduce alt_bn128 precompile gas costs. - bn128::add::ISTANBUL, - bn128::mul::ISTANBUL, - bn128::pair::ISTANBUL, + bn254::add::ISTANBUL, + bn254::mul::ISTANBUL, + bn254::pair::ISTANBUL, // EIP-152: Add BLAKE2 compression function `F` precompile. blake2::FUN, ]); - Box::new(precompiles) + precompiles }) } /// Returns precompiles for Berlin spec. pub fn berlin() -> &'static Self { - static INSTANCE: OnceBox = OnceBox::new(); + static INSTANCE: OnceLock = OnceLock::new(); INSTANCE.get_or_init(|| { let mut precompiles = Self::istanbul().clone(); precompiles.extend([ // EIP-2565: ModExp Gas Cost. modexp::BERLIN, ]); - Box::new(precompiles) + precompiles }) } @@ -162,45 +178,34 @@ impl Precompiles { /// If the `c-kzg` feature is not enabled KZG Point Evaluation precompile will not be included, /// effectively making this the same as Berlin. pub fn cancun() -> &'static Self { - static INSTANCE: OnceBox = OnceBox::new(); + static INSTANCE: OnceLock = OnceLock::new(); INSTANCE.get_or_init(|| { let mut precompiles = Self::berlin().clone(); - - // EIP-4844: Shard Blob Transactions - cfg_if! { - if #[cfg(any(feature = "c-kzg", feature = "kzg-rs"))] { - let precompile = kzg_point_evaluation::POINT_EVALUATION.clone(); - } else { - let precompile = PrecompileWithAddress(u64_to_address(0x0A), |_,_| Err(PrecompileError::Fatal("c-kzg feature is not enabled".into()))); - } - } - - precompiles.extend([ - precompile, + // EIP-4844: Shard Blob Transactions + kzg_point_evaluation::POINT_EVALUATION, ]); - - Box::new(precompiles) + precompiles }) } /// Returns precompiles for Prague spec. pub fn prague() -> &'static Self { - static INSTANCE: OnceBox = OnceBox::new(); + static INSTANCE: OnceLock = OnceLock::new(); INSTANCE.get_or_init(|| { let mut precompiles = Self::cancun().clone(); precompiles.extend(bls12_381::precompiles()); - Box::new(precompiles) + precompiles }) } /// Returns precompiles for Osaka spec. pub fn osaka() -> &'static Self { - static INSTANCE: OnceBox = OnceBox::new(); + static INSTANCE: OnceLock = OnceLock::new(); INSTANCE.get_or_init(|| { let mut precompiles = Self::prague().clone(); precompiles.extend([modexp::OSAKA, secp256r1::P256VERIFY_OSAKA]); - Box::new(precompiles) + precompiles }) } @@ -229,19 +234,22 @@ impl Precompiles { /// Returns the precompile for the given address. #[inline] - pub fn get(&self, address: &Address) -> Option<&PrecompileFn> { + pub fn get(&self, address: &Address) -> Option<&Precompile> { + if let Some(short_address) = short_address(address) { + return self.optimized_access[short_address].as_ref(); + } self.inner.get(address) } /// Returns the precompile for the given address. #[inline] - pub fn get_mut(&mut self, address: &Address) -> Option<&mut PrecompileFn> { + pub fn get_mut(&mut self, address: &Address) -> Option<&mut Precompile> { self.inner.get_mut(address) } /// Is the precompiles list empty. pub fn is_empty(&self) -> bool { - self.inner.len() == 0 + self.inner.is_empty() } /// Returns the number of precompiles. @@ -258,10 +266,19 @@ impl Precompiles { /// /// Other precompiles with overwrite existing precompiles. #[inline] - pub fn extend(&mut self, other: impl IntoIterator) { - let items: Vec = other.into_iter().collect::>(); + pub fn extend(&mut self, other: impl IntoIterator) { + let items: Vec = other.into_iter().collect::>(); + for item in items.iter() { + if let Some(short_address) = short_address(item.address()) { + self.optimized_access[short_address] = Some(item.clone()); + } else { + self.all_short_addresses = false; + } + } + self.addresses.extend(items.iter().map(|p| *p.address())); - self.inner.extend(items.into_iter().map(|p| (p.0, p.1))); + self.inner + .extend(items.into_iter().map(|p| (*p.address(), p.clone()))); } /// Returns complement of `other` in `self`. @@ -273,12 +290,12 @@ impl Precompiles { let inner = inner .iter() .filter(|(a, _)| !other.inner.contains_key(*a)) - .map(|(a, p)| (*a, *p)) + .map(|(a, p)| (*a, p.clone())) .collect::>(); - let addresses = inner.keys().cloned().collect::>(); - - Self { inner, addresses } + let mut precompiles = Self::default(); + precompiles.extend(inner.into_iter().map(|p| p.1)); + precompiles } /// Returns intersection of `self` and `other`. @@ -290,42 +307,66 @@ impl Precompiles { let inner = inner .iter() .filter(|(a, _)| other.inner.contains_key(*a)) - .map(|(a, p)| (*a, *p)) + .map(|(a, p)| (*a, p.clone())) .collect::>(); - let addresses = inner.keys().cloned().collect::>(); - - Self { inner, addresses } + let mut precompiles = Self::default(); + precompiles.extend(inner.into_iter().map(|p| p.1)); + precompiles } } -/// Precompile with address and function. +/// Precompile. #[derive(Clone, Debug)] -pub struct PrecompileWithAddress(pub Address, pub PrecompileFn); +pub struct Precompile { + /// Unique identifier. + id: PrecompileId, + /// Precompile address. + address: Address, + /// Precompile implementation. + fn_: PrecompileFn, +} -impl From<(Address, PrecompileFn)> for PrecompileWithAddress { - fn from(value: (Address, PrecompileFn)) -> Self { - PrecompileWithAddress(value.0, value.1) +impl From<(PrecompileId, Address, PrecompileFn)> for Precompile { + fn from((id, address, fn_): (PrecompileId, Address, PrecompileFn)) -> Self { + Precompile { id, address, fn_ } } } -impl From for (Address, PrecompileFn) { - fn from(value: PrecompileWithAddress) -> Self { - (value.0, value.1) +impl From for (PrecompileId, Address, PrecompileFn) { + fn from(value: Precompile) -> Self { + (value.id, value.address, value.fn_) } } -impl PrecompileWithAddress { - /// Returns reference of address. +impl Precompile { + /// Create new precompile. + pub const fn new(id: PrecompileId, address: Address, fn_: PrecompileFn) -> Self { + Self { id, address, fn_ } + } + + /// Returns reference to precompile identifier. + #[inline] + pub fn id(&self) -> &PrecompileId { + &self.id + } + + /// Returns reference to address. #[inline] pub fn address(&self) -> &Address { - &self.0 + &self.address } - /// Returns reference of precompile. + /// Returns reference to precompile implementation. #[inline] pub fn precompile(&self) -> &PrecompileFn { - &self.1 + &self.fn_ + } + + /// Executes the precompile. + #[inline] + pub fn execute(&self, input: &[u8], gas_limit: u64) -> PrecompileResult { + (self.fn_)(input, gas_limit) } } @@ -404,7 +445,45 @@ pub const fn u64_to_address(x: u64) -> Address { #[cfg(test)] mod test { - use crate::Precompiles; + use super::*; + + fn temp_precompile(_input: &[u8], _gas_limit: u64) -> PrecompileResult { + PrecompileResult::Err(PrecompileError::OutOfGas) + } + + #[test] + fn test_optimized_access() { + let mut precompiles = Precompiles::istanbul().clone(); + assert!(precompiles.optimized_access[9].is_some()); + assert!(precompiles.optimized_access[10].is_none()); + + precompiles.extend([Precompile::new( + PrecompileId::Custom("test".into()), + u64_to_address(100), + temp_precompile, + )]); + precompiles.extend([Precompile::new( + PrecompileId::Custom("test".into()), + u64_to_address(101), + temp_precompile, + )]); + + assert_eq!( + precompiles.optimized_access[100] + .as_ref() + .unwrap() + .execute(&[], u64::MAX), + PrecompileResult::Err(PrecompileError::OutOfGas) + ); + + assert_eq!( + precompiles + .get(&Address::left_padding_from(&[101])) + .unwrap() + .execute(&[], u64::MAX), + PrecompileResult::Err(PrecompileError::OutOfGas) + ); + } #[test] fn test_difference_precompile_sets() { diff --git a/crates/precompile/src/modexp.rs b/crates/precompile/src/modexp.rs index 08300abe3c..3107837228 100644 --- a/crates/precompile/src/modexp.rs +++ b/crates/precompile/src/modexp.rs @@ -1,27 +1,32 @@ //! Modexp precompile added in [`EIP-198`](https://eips.ethereum.org/EIPS/eip-198) //! and reprices in berlin hardfork with [`EIP-2565`](https://eips.ethereum.org/EIPS/eip-2565). use crate::{ + crypto, utilities::{left_pad, left_pad_vec, right_pad_vec, right_pad_with_offset}, - PrecompileError, PrecompileOutput, PrecompileResult, PrecompileWithAddress, + Precompile, PrecompileError, PrecompileId, PrecompileOutput, PrecompileResult, }; use core::cmp::{max, min}; use primitives::{eip7823, Bytes, U256}; use std::vec::Vec; /// `modexp` precompile with BYZANTIUM gas rules. -pub const BYZANTIUM: PrecompileWithAddress = - PrecompileWithAddress(crate::u64_to_address(5), byzantium_run); +pub const BYZANTIUM: Precompile = Precompile::new( + PrecompileId::ModExp, + crate::u64_to_address(5), + byzantium_run, +); /// `modexp` precompile with BERLIN gas rules. -pub const BERLIN: PrecompileWithAddress = - PrecompileWithAddress(crate::u64_to_address(5), berlin_run); +pub const BERLIN: Precompile = + Precompile::new(PrecompileId::ModExp, crate::u64_to_address(5), berlin_run); /// `modexp` precompile with OSAKA gas rules. -pub const OSAKA: PrecompileWithAddress = PrecompileWithAddress(crate::u64_to_address(5), osaka_run); +pub const OSAKA: Precompile = + Precompile::new(PrecompileId::ModExp, crate::u64_to_address(5), osaka_run); #[cfg(feature = "gmp")] /// GMP-based modular exponentiation implementation -fn modexp(base: &[u8], exponent: &[u8], modulus: &[u8]) -> Vec { +pub(crate) fn modexp(base: &[u8], exponent: &[u8], modulus: &[u8]) -> Vec { use rug::{integer::Order::Msf, Integer}; // Convert byte slices to GMP integers let base_int = Integer::from_digits(base, Msf); @@ -39,7 +44,7 @@ fn modexp(base: &[u8], exponent: &[u8], modulus: &[u8]) -> Vec { } #[cfg(not(feature = "gmp"))] -fn modexp(base: &[u8], exponent: &[u8], modulus: &[u8]) -> Vec { +pub(crate) fn modexp(base: &[u8], exponent: &[u8], modulus: &[u8]) -> Vec { aurora_engine_modexp::modexp(base, exponent, modulus) } @@ -125,11 +130,6 @@ where return Err(PrecompileError::ModexpEip7823LimitSize); } - // special case for both base and mod length being 0. - if base_len == 0 && mod_len == 0 { - return Ok(PrecompileOutput::new(min_gas, Bytes::new())); - } - // Used to extract ADJUSTED_EXPONENT_LENGTH. let exp_highp_len = min(exp_len, 32); @@ -150,6 +150,10 @@ where return Err(PrecompileError::OutOfGas); } + if base_len == 0 && mod_len == 0 { + return Ok(PrecompileOutput::new(gas_cost, Bytes::new())); + } + // Padding is needed if the input does not contain all 3 values. let input_len = base_len.saturating_add(exp_len).saturating_add(mod_len); let input = right_pad_vec(input, input_len); @@ -158,7 +162,7 @@ where debug_assert_eq!(modulus.len(), mod_len); // Call the modexp. - let output = modexp(base, exponent, modulus); + let output = crypto().modexp(base, exponent, modulus)?; // Left pad the result to modulus length. bytes will always by less or equal to modulus length. Ok(PrecompileOutput::new( diff --git a/crates/precompile/src/secp256k1.rs b/crates/precompile/src/secp256k1.rs index 2ac987af13..314ae2bd19 100644 --- a/crates/precompile/src/secp256k1.rs +++ b/crates/precompile/src/secp256k1.rs @@ -20,14 +20,17 @@ pub mod k256; pub mod parity_libsecp256k1; use crate::{ - utilities::right_pad, PrecompileError, PrecompileOutput, PrecompileResult, - PrecompileWithAddress, + crypto, utilities::right_pad, Precompile, PrecompileError, PrecompileId, PrecompileOutput, + PrecompileResult, }; use primitives::{alloy_primitives::B512, Bytes, B256}; /// `ecrecover` precompile, containing address and function to run. -pub const ECRECOVER: PrecompileWithAddress = - PrecompileWithAddress(crate::u64_to_address(1), ec_recover_run); +pub const ECRECOVER: Precompile = Precompile::new( + PrecompileId::EcRec, + crate::u64_to_address(1), + ec_recover_run, +); /// `ecrecover` precompile function. Read more about input and output format in [this module docs](self). pub fn ec_recover_run(input: &[u8], gas_limit: u64) -> PrecompileResult { @@ -48,12 +51,12 @@ pub fn ec_recover_run(input: &[u8], gas_limit: u64) -> PrecompileResult { let recid = input[63] - 27; let sig = <&B512>::try_from(&input[64..128]).unwrap(); - let res = ecrecover_bytes(sig.0, recid, msg.0); + let res = crypto().secp256k1_ecrecover(&sig.0, recid, &msg.0).ok(); let out = res.map(|o| o.to_vec().into()).unwrap_or_default(); Ok(PrecompileOutput::new(ECRECOVER_BASE, out)) } -fn ecrecover_bytes(sig: [u8; 64], recid: u8, msg: [u8; 32]) -> Option<[u8; 32]> { +pub(crate) fn ecrecover_bytes(sig: [u8; 64], recid: u8, msg: [u8; 32]) -> Option<[u8; 32]> { let sig = B512::from_slice(&sig); let msg = B256::from_slice(&msg); diff --git a/crates/precompile/src/secp256r1.rs b/crates/precompile/src/secp256r1.rs index 323f803f69..262a2d0889 100644 --- a/crates/precompile/src/secp256r1.rs +++ b/crates/precompile/src/secp256r1.rs @@ -7,7 +7,8 @@ //! P256 elliptic curve. The [`P256VERIFY`] const represents the implementation of this precompile, //! with the address that it is currently deployed at. use crate::{ - u64_to_address, PrecompileError, PrecompileOutput, PrecompileResult, PrecompileWithAddress, + crypto, u64_to_address, Precompile, PrecompileError, PrecompileId, PrecompileOutput, + PrecompileResult, }; use p256::{ ecdsa::{signature::hazmat::PrehashVerifier, Signature, VerifyingKey}, @@ -25,17 +26,23 @@ pub const P256VERIFY_BASE_GAS_FEE: u64 = 3450; pub const P256VERIFY_BASE_GAS_FEE_OSAKA: u64 = 6900; /// Returns the secp256r1 precompile with its address. -pub fn precompiles() -> impl Iterator { +pub fn precompiles() -> impl Iterator { [P256VERIFY].into_iter() } /// [RIP-7212](https://github.com/ethereum/RIPs/blob/master/RIPS/rip-7212.md#specification) secp256r1 precompile. -pub const P256VERIFY: PrecompileWithAddress = - PrecompileWithAddress(u64_to_address(P256VERIFY_ADDRESS), p256_verify); +pub const P256VERIFY: Precompile = Precompile::new( + PrecompileId::P256Verify, + u64_to_address(P256VERIFY_ADDRESS), + p256_verify, +); /// [RIP-7212](https://github.com/ethereum/RIPs/blob/master/RIPS/rip-7212.md#specification) secp256r1 precompile. -pub const P256VERIFY_OSAKA: PrecompileWithAddress = - PrecompileWithAddress(u64_to_address(P256VERIFY_ADDRESS), p256_verify_osaka); +pub const P256VERIFY_OSAKA: Precompile = Precompile::new( + PrecompileId::P256Verify, + u64_to_address(P256VERIFY_ADDRESS), + p256_verify_osaka, +); /// secp256r1 precompile logic. It takes the input bytes sent to the precompile /// and the gas limit. The output represents the result of verifying the @@ -67,7 +74,7 @@ fn p256_verify_inner(input: &[u8], gas_limit: u64, gas_cost: u64) -> PrecompileR if gas_cost > gas_limit { return Err(PrecompileError::OutOfGas); } - let result = if verify_impl(input).is_some() { + let result = if verify_impl(input) { B256::with_last_byte(1).into() } else { Bytes::new() @@ -77,9 +84,9 @@ fn p256_verify_inner(input: &[u8], gas_limit: u64, gas_cost: u64) -> PrecompileR /// Returns `Some(())` if the signature included in the input byte slice is /// valid, `None` otherwise. -pub fn verify_impl(input: &[u8]) -> Option<()> { +pub fn verify_impl(input: &[u8]) -> bool { if input.len() != 160 { - return None; + return false; } // msg signed (msg is already the hash of the original message) @@ -89,10 +96,10 @@ pub fn verify_impl(input: &[u8]) -> Option<()> { // x, y: public key let pk = <&B512>::try_from(&input[96..160]).unwrap(); - verify_signature(msg.0, sig.0, pk.0) + crypto().secp256r1_verify_signature(&msg.0, &sig.0, &pk.0) } -fn verify_signature(msg: [u8; 32], sig: [u8; 64], pk: [u8; 64]) -> Option<()> { +pub(crate) fn verify_signature(msg: [u8; 32], sig: [u8; 64], pk: [u8; 64]) -> Option<()> { // Can fail only if the input is not exact length. let signature = Signature::from_slice(&sig).ok()?; // Decode the public key bytes (x,y coordinates) using EncodedPoint @@ -157,6 +164,6 @@ mod test { let input = Bytes::from_hex(input).unwrap(); let result = verify_impl(&input); - assert_eq!(result.is_some(), expect_success); + assert_eq!(result, expect_success); } } diff --git a/crates/primitives/CHANGELOG.md b/crates/primitives/CHANGELOG.md index cb1711f1b7..9b8105eae8 100644 --- a/crates/primitives/CHANGELOG.md +++ b/crates/primitives/CHANGELOG.md @@ -1,4 +1,32 @@ # Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [20.2.1](https://github.com/bluealloy/revm/compare/revm-primitives-v20.2.0...revm-primitives-v20.2.1) - 2025-08-12 + +### Other + +- small performance and safety improvements ([#2868](https://github.com/bluealloy/revm/pull/2868)) + +## [20.2.0](https://github.com/bluealloy/revm/compare/revm-primitives-v20.1.0...revm-primitives-v20.2.0) - 2025-08-06 + +### Added + +- short address for journal cold/warm check ([#2849](https://github.com/bluealloy/revm/pull/2849)) + +### Other + +- update README.md ([#2842](https://github.com/bluealloy/revm/pull/2842)) +- improve primitives crate documentation and consistency ([#2829](https://github.com/bluealloy/revm/pull/2829)) +- reuse global crypto provide idea ([#2786](https://github.com/bluealloy/revm/pull/2786)) +- add rust-version and note about MSRV ([#2789](https://github.com/bluealloy/revm/pull/2789)) +- add OnceLock re-export with no_std support ([#2787](https://github.com/bluealloy/revm/pull/2787)) +# Changelog All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), diff --git a/crates/primitives/Cargo.toml b/crates/primitives/Cargo.toml index dc6f7a321e..e6de97202f 100644 --- a/crates/primitives/Cargo.toml +++ b/crates/primitives/Cargo.toml @@ -1,13 +1,14 @@ [package] name = "revm-primitives" description = "Revm primitives types" -version = "20.1.0" +version = "20.2.1" authors.workspace = true edition.workspace = true keywords.workspace = true license.workspace = true repository.workspace = true readme.workspace = true +rust-version.workspace = true [package.metadata.docs.rs] all-features = true @@ -22,13 +23,17 @@ alloy-primitives = { workspace = true, features = ["rlp", "map"] } # mics num_enum = { version = "0.7.3", default-features = false } +once_cell = { version = "1.21", default-features = false, features = [ + "alloc", + "race", +] } # Optional serde = { workspace = true, features = ["derive", "rc"], optional = true } [features] default = ["std"] -std = ["alloy-primitives/std", "serde?/std", "num_enum/std"] +std = ["alloy-primitives/std", "serde?/std", "num_enum/std", "once_cell/std"] serde = ["dep:serde", "alloy-primitives/serde"] map-foldhash = ["alloy-primitives/map-foldhash"] diff --git a/crates/primitives/src/eip170.rs b/crates/primitives/src/eip170.rs index 486150ec09..7022626e11 100644 --- a/crates/primitives/src/eip170.rs +++ b/crates/primitives/src/eip170.rs @@ -1,4 +1,6 @@ -//! EIP-170: Contract code size limit +//! EIP-170: Contract Code Size Limit +//! +//! Introduces a maximum limit on smart contract code size. /// EIP-170: Contract code size limit /// diff --git a/crates/primitives/src/eip3860.rs b/crates/primitives/src/eip3860.rs index 95b3ad8112..160c4bd09d 100644 --- a/crates/primitives/src/eip3860.rs +++ b/crates/primitives/src/eip3860.rs @@ -1,4 +1,6 @@ -//! EIP-3860: Limit and meter initcode +//! EIP-3860: Limit and Meter Initcode +//! +//! Introduces limits and gas metering for contract creation code. use crate::eip170; diff --git a/crates/primitives/src/eip4844.rs b/crates/primitives/src/eip4844.rs index 61db2aa15c..8a67e8224a 100644 --- a/crates/primitives/src/eip4844.rs +++ b/crates/primitives/src/eip4844.rs @@ -1,5 +1,6 @@ -//! EIP-4844 constants +//! EIP-4844: Shard Blob Transactions //! +//! Constants for blob transaction support in Cancun and Prague hard forks. /// First version of the blob pub const VERSIONED_HASH_VERSION_KZG: u8 = 0x01; diff --git a/crates/primitives/src/eip7702.rs b/crates/primitives/src/eip7702.rs index 248513fb3a..0a958fb905 100644 --- a/crates/primitives/src/eip7702.rs +++ b/crates/primitives/src/eip7702.rs @@ -1,4 +1,6 @@ -//! EIP-7702 constants +//! EIP-7702: Set EOA Account Code +//! +//! Constants for account authorization and delegation functionality. /// Base cost of updating authorized account. pub const PER_AUTH_BASE_COST: u64 = 12500; diff --git a/crates/primitives/src/eip7823.rs b/crates/primitives/src/eip7823.rs index 2a8e5d2a9b..5fa40e6f59 100644 --- a/crates/primitives/src/eip7823.rs +++ b/crates/primitives/src/eip7823.rs @@ -1,8 +1,7 @@ -//! EIP-7823 Set upper bounds for MODEXP +//! EIP-7823: Set Upper Bounds for MODEXP //! -//! Introduce an upper bound on the inputs of the MODEXP precompile. -//! This can reduce the number of potential bugs, because the testing surface is not infinite anymore, -//! and makes it easier to be replaced using EVMMAX. +//! Introduces an upper bound on the inputs of the MODEXP precompile. +//! This reduces the number of potential bugs and makes it easier to replace using EVMMAX. /// Each of the modexp length inputs (length_of_BASE, length_of_EXPONENT and length_of_MODULUS) /// MUST be less than or equal to 8192 bits (1024 bytes). diff --git a/crates/primitives/src/eip7825.rs b/crates/primitives/src/eip7825.rs index b8248f5882..bfde4cfb10 100644 --- a/crates/primitives/src/eip7825.rs +++ b/crates/primitives/src/eip7825.rs @@ -1,5 +1,6 @@ -//! EIP-7825: Transaction Gas Limit Cap -//! Introduce a protocol-level cap on the maximum gas used by a transaction to 16 777 216. +//! EIP-7825: Transaction Gas Limit Cap +//! +//! Introduces a protocol-level cap on the maximum gas used by a transaction. /// Transaction gas limit cap. /// diff --git a/crates/primitives/src/eip7907.rs b/crates/primitives/src/eip7907.rs index ac955e2724..fd9e03f479 100644 --- a/crates/primitives/src/eip7907.rs +++ b/crates/primitives/src/eip7907.rs @@ -1,4 +1,6 @@ -//! TODO dont have specific EIP. It is part of: EIP-7907: Meter Contract Code Size And Increase Limit +//! EIP-7907: Meter Contract Code Size And Increase Limit (Prague) +//! +//! This EIP introduces updated code size limits that apply starting from the Prague hard fork. /// By default the limit is `0xC000` (49_152 bytes). pub const MAX_CODE_SIZE: usize = 0xC000; diff --git a/crates/primitives/src/eip7918.rs b/crates/primitives/src/eip7918.rs index f40e4a0eef..a84d99c902 100644 --- a/crates/primitives/src/eip7918.rs +++ b/crates/primitives/src/eip7918.rs @@ -1,5 +1,6 @@ -//! Constants for EIP-7918: Blob base fee bounded by execution cost +//! EIP-7918: Blob Base Fee Bounded by Execution Cost //! +//! Constants for blob base fee calculation with execution cost bounds. /// Minimum base fee for blobs, if price of the blob is less than this value, this value will be used. pub const BLOB_BASE_COST: u64 = 2_u64.pow(14); diff --git a/crates/primitives/src/lib.rs b/crates/primitives/src/lib.rs index 7c60172a0f..8fb8bceeb2 100644 --- a/crates/primitives/src/lib.rs +++ b/crates/primitives/src/lib.rs @@ -1,6 +1,14 @@ //! # revm-primitives //! -//! EVM primitive types. +//! Core primitive types and constants for the Ethereum Virtual Machine (EVM) implementation. +//! +//! This crate provides: +//! - EVM constants and limits (gas, stack, code size) +//! - Ethereum hard fork management and version control +//! - EIP-specific constants and configuration values +//! - Cross-platform synchronization primitives +//! - Type aliases for common EVM concepts (storage keys/values) +//! - Re-exports of alloy primitive types for convenience #![cfg_attr(not(test), warn(unused_crate_dependencies))] #![cfg_attr(not(feature = "std"), no_std)] @@ -17,8 +25,10 @@ pub mod eip7825; pub mod eip7907; pub mod eip7918; pub mod hardfork; +mod once_lock; pub use constants::*; +pub use once_lock::OnceLock; // Reexport alloy primitives. @@ -28,7 +38,28 @@ pub use alloy_primitives::{ Bytes, FixedBytes, Log, LogData, TxKind, B256, I128, I256, U128, U256, }; -/// type alias for storage keys +/// Type alias for EVM storage keys (256-bit unsigned integers). +/// Used to identify storage slots within smart contract storage. pub type StorageKey = U256; -/// type alias for storage values + +/// Type alias for EVM storage values (256-bit unsigned integers). +/// Used to store data values in smart contract storage slots. pub type StorageValue = U256; + +/// Optimize short address access. +pub const SHORT_ADDRESS_CAP: usize = 300; + +/// Returns the short address from Address. +/// +/// Short address is considered address that has 18 leading zeros +/// and last two bytes are less than [`SHORT_ADDRESS_CAP`]. +#[inline] +pub fn short_address(address: &Address) -> Option { + if address.0[..18].iter().all(|b| *b == 0) { + let short_address = u16::from_be_bytes([address.0[18], address.0[19]]) as usize; + if short_address < SHORT_ADDRESS_CAP { + return Some(short_address); + } + } + None +} diff --git a/crates/primitives/src/once_lock.rs b/crates/primitives/src/once_lock.rs new file mode 100644 index 0000000000..90d129ea6a --- /dev/null +++ b/crates/primitives/src/once_lock.rs @@ -0,0 +1,53 @@ +//! `OnceLock` abstraction that uses [`std::sync::OnceLock`] when available, once_cell otherwise. + +#[cfg(not(feature = "std"))] +mod no_std_impl { + use once_cell::race::OnceBox; + use std::boxed::Box; + + /// A thread-safe cell which can be written to only once. + #[derive(Debug)] + pub struct OnceLock { + inner: OnceBox, + } + + impl Default for OnceLock { + fn default() -> Self { + Self::new() + } + } + + impl OnceLock { + /// Creates a new empty OnceLock. + #[inline] + pub const fn new() -> Self { + Self { + inner: OnceBox::new(), + } + } + + /// Gets the contents of the OnceLock, initializing it if necessary. + #[inline] + pub fn get_or_init(&self, f: F) -> &T + where + F: FnOnce() -> T, + T: Into>, + { + self.inner.get_or_init(|| f().into()) + } + + /// Gets the contents of the OnceLock, returning None if it is not initialized. + #[inline] + pub fn get(&self) -> Option<&T> { + self.inner.get() + } + } +} + +#[cfg(feature = "std")] +use once_cell as _; +#[cfg(feature = "std")] +pub use std::sync::OnceLock; + +#[cfg(not(feature = "std"))] +pub use no_std_impl::OnceLock; diff --git a/crates/revm/CHANGELOG.md b/crates/revm/CHANGELOG.md index f380d29a73..cd72a23e7c 100644 --- a/crates/revm/CHANGELOG.md +++ b/crates/revm/CHANGELOG.md @@ -1,4 +1,5 @@ # Changelog + All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), @@ -6,6 +7,37 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [29.0.0](https://github.com/bluealloy/revm/compare/revm-v28.0.1...revm-v29.0.0) - 2025-08-23 + +### Other + +- updated the following local packages: revm-bytecode, revm-database-interface, revm-context-interface, revm-context, revm-database, revm-interpreter, revm-precompile, revm-handler, revm-state, revm-inspector + +## [28.0.1](https://github.com/bluealloy/revm/compare/revm-v28.0.0...revm-v28.0.1) - 2025-08-12 + +### Other + +- updated the following local packages: revm-primitives, revm-bytecode, revm-state, revm-context-interface, revm-database, revm-precompile, revm-inspector, revm-database-interface, revm-context, revm-interpreter, revm-handler + +## [28.0.0](https://github.com/bluealloy/revm/compare/revm-v27.1.0...revm-v28.0.0) - 2025-08-06 + +### Added + +- Reuse bls12-381 codepaths to implement kzg point evaluation precompile ([#2809](https://github.com/bluealloy/revm/pull/2809)) +- refactor test utils ([#2813](https://github.com/bluealloy/revm/pull/2813)) +- add system transaction inspection support ([#2808](https://github.com/bluealloy/revm/pull/2808)) + +### Other + +- update README.md ([#2842](https://github.com/bluealloy/revm/pull/2842)) +- reuse global crypto provide idea ([#2786](https://github.com/bluealloy/revm/pull/2786)) +- add rust-version and note about MSRV ([#2789](https://github.com/bluealloy/revm/pull/2789)) +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + ## [27.1.0](https://github.com/bluealloy/revm/compare/revm-v27.0.3...revm-v27.1.0) - 2025-07-23 ### Added diff --git a/crates/revm/Cargo.toml b/crates/revm/Cargo.toml index 9cdfad92c8..a5213197da 100644 --- a/crates/revm/Cargo.toml +++ b/crates/revm/Cargo.toml @@ -1,13 +1,14 @@ [package] name = "revm" description = "Revm - Rust Ethereum Virtual Machine" -version = "27.1.0" +version = "29.0.0" authors.workspace = true edition.workspace = true keywords.workspace = true license.workspace = true repository.workspace = true readme.workspace = true +rust-version.workspace = true [package.metadata.docs.rs] all-features = true @@ -35,7 +36,7 @@ serde_json = { workspace = true, features = ["alloc", "preserve_order"] } serde = { workspace = true, features = ["derive"] } [features] -default = ["std", "c-kzg", "secp256k1", "portable", "blst", "tracer"] +default = ["std", "secp256k1", "portable", "tracer", "c-kzg", "blst"] std = [ "interpreter/std", "precompile/std", @@ -94,13 +95,15 @@ optional_no_base_fee = ["context/optional_no_base_fee"] enable_eip7702 = ["context/enable_eip7702"] enable_eip7623 = ["context/enable_eip7623"] -# Precompiles features +# Precompiles features: Please look at the comments in `precompile` crate for more information. secp256k1 = ["precompile/secp256k1"] # See comments in `precompile` c-kzg = [ "precompile/c-kzg", ] # `kzg-rs` is not audited but useful for `no_std` environment, use it with causing and default to `c-kzg` if possible. kzg-rs = ["precompile/kzg-rs"] + +# blst will enabled both for bls precompiles and for kzg precompile. blst = ["precompile/blst"] bn = ["precompile/bn"] asm-sha2 = ["precompile/asm-sha2"] diff --git a/crates/revm/src/lib.rs b/crates/revm/src/lib.rs index 091f6807e7..759af925ae 100644 --- a/crates/revm/src/lib.rs +++ b/crates/revm/src/lib.rs @@ -35,4 +35,5 @@ pub use handler::{ ExecuteCommitEvm, ExecuteEvm, MainBuilder, MainContext, MainnetEvm, SystemCallCommitEvm, SystemCallEvm, }; -pub use inspector::{InspectCommitEvm, InspectEvm, Inspector}; +pub use inspector::{InspectCommitEvm, InspectEvm, InspectSystemCallEvm, Inspector}; +pub use precompile::install_crypto; diff --git a/crates/revm/tests/common.rs b/crates/revm/tests/common.rs deleted file mode 100644 index c3a909de08..0000000000 --- a/crates/revm/tests/common.rs +++ /dev/null @@ -1,108 +0,0 @@ -//! Common test utilities used to compare execution results against testdata. -#![allow(dead_code)] - -use revm::{ - context::result::ResultAndState, - context_interface::result::{ExecutionResult, HaltReason, Output, SuccessReason}, - primitives::Bytes, - state::EvmState, -}; - -// Constant for testdata directory path -pub(crate) const TESTS_TESTDATA: &str = "tests/testdata"; - -#[cfg(not(feature = "serde"))] -pub(crate) fn compare_or_save_testdata(_filename: &str, _output: I) { - // serde needs to be enabled to use this function -} - -/// Compares or saves the execution output to a testdata file. -/// -/// This utility helps maintain consistent test behavior by comparing -/// execution results against known-good outputs stored in JSON files. -/// -/// # Arguments -/// -/// * `filename` - The name of the testdata file, relative to tests/testdata/ -/// * `output` - The execution output to compare or save -/// -/// # Returns -/// -/// `Ok(())` if the comparison or save was successful -/// `Err(anyhow::Error)` if there was an error -/// -/// # Note -/// -/// Tests using this function require the `serde` feature to be enabled: -/// ```bash -/// cargo test --features serde -/// ``` -#[cfg(feature = "serde")] -pub(crate) fn compare_or_save_testdata< - I: serde::Serialize + for<'a> serde::Deserialize<'a> + PartialEq, ->( - filename: &str, - output: I, -) { - use std::{fs, path::PathBuf}; - - let tests_dir = PathBuf::from(TESTS_TESTDATA); - let testdata_file = tests_dir.join(filename); - - // Create directory if it doesn't exist - if !tests_dir.exists() { - fs::create_dir_all(&tests_dir).unwrap(); - } - - // Serialize the output to JSON for saving - let output_json = serde_json::to_string_pretty(&output).unwrap(); - - // If the testdata file doesn't exist, save the output - if !testdata_file.exists() { - fs::write(&testdata_file, &output_json).unwrap(); - println!("Saved testdata to {}", testdata_file.display()); - return; - } - - // Read the expected output from the testdata file - let expected_json = fs::read_to_string(&testdata_file).unwrap(); - - // Deserialize to actual ResultAndState object for proper comparison - let expected = serde_json::from_str(&expected_json).unwrap(); - - // Compare the output objects directly - if output != expected { - // If they don't match, generate a nicer error by pretty-printing both as JSON - // This helps with debugging by showing the exact differences - let expected_pretty = serde_json::to_string_pretty(&expected).unwrap(); - - panic!( - "Value does not match testdata.\nExpected:\n{expected_pretty}\n\nActual:\n{output_json}" - ); - } -} - -/// Example showing how to migrate an existing test to use the testdata comparison. -/// -/// This example consists of: -/// 1. The "original" test with standard assertions -/// 2. The migration approach - running assertions and saving testdata -/// 3. The final migrated test that only uses testdata comparison -#[test] -fn template_test() { - // Create a minimal result and state - let result = ResultAndState::new( - ExecutionResult::::Success { - reason: SuccessReason::Stop, - gas_used: 1000, - gas_refunded: 0, - logs: vec![], - output: Output::Call(Bytes::from(vec![4, 5, 6])), - }, - EvmState::default(), - ); - - // Simply use the testdata comparison utility - // No assertions needed - full validation is done by comparing with testdata - compare_or_save_testdata("template_test.json", result); -} diff --git a/crates/revm/tests/testdata/template_test.json b/crates/revm/tests/testdata/template_test.json deleted file mode 100644 index 5c35711ddd..0000000000 --- a/crates/revm/tests/testdata/template_test.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "result": { - "Success": { - "reason": "Stop", - "gas_used": 1000, - "gas_refunded": 0, - "logs": [], - "output": { - "Call": "0x040506" - } - } - }, - "state": {} -} \ No newline at end of file diff --git a/crates/state/CHANGELOG.md b/crates/state/CHANGELOG.md index 6399b58a73..94d8d0adff 100644 --- a/crates/state/CHANGELOG.md +++ b/crates/state/CHANGELOG.md @@ -5,6 +5,37 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [Unreleased] + +## [7.0.5](https://github.com/bluealloy/revm/compare/revm-state-v7.0.4...revm-state-v7.0.5) - 2025-08-23 + +### Other + +- updated the following local packages: revm-bytecode + +## [7.0.4](https://github.com/bluealloy/revm/compare/revm-state-v7.0.3...revm-state-v7.0.4) - 2025-08-12 + +### Other + +- small performance and safety improvements ([#2868](https://github.com/bluealloy/revm/pull/2868)) + +## [7.0.3](https://github.com/bluealloy/revm/compare/revm-state-v7.0.2...revm-state-v7.0.3) - 2025-08-06 + +### Fixed + +- manally implementation PartialOrd and Ord for AccountInfo ([#2835](https://github.com/bluealloy/revm/pull/2835)) + +### Other + +- update README.md ([#2842](https://github.com/bluealloy/revm/pull/2842)) +- add rust-version and note about MSRV ([#2789](https://github.com/bluealloy/revm/pull/2789)) +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + ## [4.0.0](https://github.com/bluealloy/revm/compare/revm-state-v3.0.1...revm-state-v4.0.0) - 2025-05-07 diff --git a/crates/state/Cargo.toml b/crates/state/Cargo.toml index 2ec2dbc95e..a9f930af7d 100644 --- a/crates/state/Cargo.toml +++ b/crates/state/Cargo.toml @@ -1,13 +1,14 @@ [package] name = "revm-state" description = "Revm state types" -version = "7.0.2" +version = "7.0.5" authors.workspace = true edition.workspace = true keywords.workspace = true license.workspace = true repository.workspace = true readme.workspace = true +rust-version.workspace = true [package.metadata.docs.rs] all-features = true @@ -29,10 +30,5 @@ serde = { workspace = true, features = ["derive", "rc"], optional = true } [features] default = ["std"] -std = [ - "serde?/std", - "primitives/std", - "bitflags/std", - "bytecode/std" -] +std = ["serde?/std", "primitives/std", "bitflags/std", "bytecode/std"] serde = ["dep:serde", "primitives/serde", "bitflags/serde", "bytecode/serde"] diff --git a/crates/state/src/account_info.rs b/crates/state/src/account_info.rs index 53b27cf6b0..11e39a0e09 100644 --- a/crates/state/src/account_info.rs +++ b/crates/state/src/account_info.rs @@ -1,11 +1,14 @@ use bytecode::Bytecode; -use core::hash::{Hash, Hasher}; +use core::{ + cmp::Ordering, + hash::{Hash, Hasher}, +}; use primitives::{B256, KECCAK_EMPTY, U256}; /// Account information that contains balance, nonce, code hash and code /// /// Code is set as optional. -#[derive(Clone, Debug, Eq, Ord, PartialOrd)] +#[derive(Clone, Debug, Eq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct AccountInfo { /// Account balance. @@ -50,6 +53,21 @@ impl Hash for AccountInfo { } } +impl PartialOrd for AccountInfo { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for AccountInfo { + fn cmp(&self, other: &Self) -> Ordering { + self.balance + .cmp(&other.balance) + .then_with(|| self.nonce.cmp(&other.nonce)) + .then_with(|| self.code_hash.cmp(&other.code_hash)) + } +} + impl AccountInfo { /// Creates a new [`AccountInfo`] with the given fields. #[inline] @@ -274,3 +292,56 @@ impl AccountInfo { } } } + +#[cfg(test)] +mod tests { + use crate::AccountInfo; + use bytecode::Bytecode; + use core::cmp::Ordering; + use primitives::{KECCAK_EMPTY, U256}; + use std::collections::BTreeSet; + + #[test] + fn test_account_info_trait_consistency() { + let bytecode = Bytecode::default(); + let account1 = AccountInfo { + balance: U256::ZERO, + nonce: 0, + code_hash: KECCAK_EMPTY, + code: Some(bytecode.clone()), + }; + + let account2 = AccountInfo { + balance: U256::ZERO, + nonce: 0, + code_hash: KECCAK_EMPTY, + code: None, + }; + + assert_eq!(account1, account2, "Accounts should be equal ignoring code"); + + assert_eq!( + account1.cmp(&account2), + Ordering::Equal, + "Ordering should be equal after ignoring code in Ord" + ); + + let mut set = BTreeSet::new(); + assert!(set.insert(account1.clone()), "Inserted account1"); + assert!( + !set.insert(account2.clone()), + "account2 not inserted (treated as duplicate)" + ); + + assert_eq!(set.len(), 1, "Set should have only one unique account"); + assert!(set.contains(&account1), "Set contains account1"); + assert!( + set.contains(&account2), + "Set contains account2 (since equal)" + ); + + let mut accounts = vec![account2.clone(), account1.clone()]; + accounts.sort(); + assert_eq!(accounts[0], accounts[1], "Sorted vec treats them as equal"); + } +} diff --git a/crates/state/src/lib.rs b/crates/state/src/lib.rs index d10af7eac3..985af53a3d 100644 --- a/crates/state/src/lib.rs +++ b/crates/state/src/lib.rs @@ -52,46 +52,55 @@ impl Account { } /// Marks the account as self destructed. + #[inline] pub fn mark_selfdestruct(&mut self) { self.status |= AccountStatus::SelfDestructed; } /// Unmarks the account as self destructed. + #[inline] pub fn unmark_selfdestruct(&mut self) { self.status -= AccountStatus::SelfDestructed; } /// Is account marked for self destruct. + #[inline] pub fn is_selfdestructed(&self) -> bool { self.status.contains(AccountStatus::SelfDestructed) } /// Marks the account as touched + #[inline] pub fn mark_touch(&mut self) { self.status |= AccountStatus::Touched; } /// Unmarks the touch flag. + #[inline] pub fn unmark_touch(&mut self) { self.status -= AccountStatus::Touched; } /// If account status is marked as touched. + #[inline] pub fn is_touched(&self) -> bool { self.status.contains(AccountStatus::Touched) } /// Marks the account as newly created. + #[inline] pub fn mark_created(&mut self) { self.status |= AccountStatus::Created; } /// Unmarks the created flag. + #[inline] pub fn unmark_created(&mut self) { self.status -= AccountStatus::Created; } /// Marks the account as cold. + #[inline] pub fn mark_cold(&mut self) { self.status |= AccountStatus::Cold; } @@ -393,7 +402,7 @@ impl EvmStorageSlot { pub fn mark_warm_with_transaction_id(&mut self, transaction_id: usize) -> bool { let same_id = self.transaction_id == transaction_id; self.transaction_id = transaction_id; - let was_cold = core::mem::replace(&mut self.is_cold, false); + let was_cold = core::mem::take(&mut self.is_cold); if same_id { // only if transaction id is same we are returning was_cold. diff --git a/crates/statetest-types/CHANGELOG.md b/crates/statetest-types/CHANGELOG.md index ae820d737d..c89d542d84 100644 --- a/crates/statetest-types/CHANGELOG.md +++ b/crates/statetest-types/CHANGELOG.md @@ -7,6 +7,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [9.0.2](https://github.com/bluealloy/revm/compare/revm-statetest-types-v9.0.1...revm-statetest-types-v9.0.2) - 2025-08-23 + +### Other + +- updated the following local packages: revm + +## [9.0.1](https://github.com/bluealloy/revm/compare/revm-statetest-types-v9.0.0...revm-statetest-types-v9.0.1) - 2025-08-12 + +### Other + +- updated the following local packages: revm + +## [9.0.0](https://github.com/bluealloy/revm/compare/revm-statetest-types-v8.0.5...revm-statetest-types-v9.0.0) - 2025-08-06 + +### Other + +- update README.md ([#2842](https://github.com/bluealloy/revm/pull/2842)) +- add rust-version and note about MSRV ([#2789](https://github.com/bluealloy/revm/pull/2789)) + ## [8.0.5](https://github.com/bluealloy/revm/compare/revm-statetest-types-v8.0.4...revm-statetest-types-v8.0.5) - 2025-07-23 ### Other diff --git a/crates/statetest-types/Cargo.toml b/crates/statetest-types/Cargo.toml index e866c2100c..5b8950c772 100644 --- a/crates/statetest-types/Cargo.toml +++ b/crates/statetest-types/Cargo.toml @@ -1,13 +1,14 @@ [package] name = "revm-statetest-types" description = "Statetest types for revme" -version = "8.0.5" +version = "9.0.2" authors.workspace = true edition.workspace = true keywords.workspace = true license.workspace = true repository.workspace = true readme.workspace = true +rust-version.workspace = true [package.metadata.docs.rs] all-features = true diff --git a/examples/README.md b/examples/README.md index d33d5093e3..ade2b456ed 100644 --- a/examples/README.md +++ b/examples/README.md @@ -6,4 +6,4 @@ * `uniswap_v2_usdc_swap`: Similar to `uniswap_get_reserves` with more examples of usage. * `block_traces`: Uses Alloy to fetch blocks transaction and state from provider to execute full block. It uses Eip3155 opcode tracer and saves output to the file. * `custom_opcodes`: Example of introducing a custom instruction to the mainnet Evm. -* `database_components`: Example of decouples Database in `State` and `BlockHash` and how to use it inside Revm. \ No newline at end of file +* `database_components`: Example of decoupled Database in `State` and `BlockHash` and how to use it inside Revm. \ No newline at end of file diff --git a/examples/block_traces/Cargo.toml b/examples/block_traces/Cargo.toml index c21dc78c70..86f232819a 100644 --- a/examples/block_traces/Cargo.toml +++ b/examples/block_traces/Cargo.toml @@ -8,6 +8,7 @@ keywords.workspace = true license.workspace = true repository.workspace = true readme.workspace = true +rust-version.workspace = true [package.metadata.docs.rs] all-features = true diff --git a/examples/cheatcode_inspector/Cargo.toml b/examples/cheatcode_inspector/Cargo.toml index b346d37688..1baa4e61b1 100644 --- a/examples/cheatcode_inspector/Cargo.toml +++ b/examples/cheatcode_inspector/Cargo.toml @@ -8,6 +8,7 @@ keywords.workspace = true license.workspace = true repository.workspace = true readme.workspace = true +rust-version.workspace = true [package.metadata.docs.rs] all-features = true diff --git a/examples/cheatcode_inspector/src/main.rs b/examples/cheatcode_inspector/src/main.rs index 0b1b3f3cab..0e5edb9f28 100644 --- a/examples/cheatcode_inspector/src/main.rs +++ b/examples/cheatcode_inspector/src/main.rs @@ -117,14 +117,8 @@ impl JournalTr for Backend { .warm_account_and_storage(address, storage_keys) } - fn warm_account(&mut self, address: Address) { - self.journaled_state - .warm_preloaded_addresses - .insert(address); - } - fn warm_coinbase_account(&mut self, address: Address) { - self.journaled_state.warm_coinbase_address = Some(address) + self.journaled_state.warm_coinbase_account(address) } fn warm_precompiles(&mut self, addresses: HashSet
) { diff --git a/examples/contract_deployment/Cargo.toml b/examples/contract_deployment/Cargo.toml index 2586794344..2128c754d6 100644 --- a/examples/contract_deployment/Cargo.toml +++ b/examples/contract_deployment/Cargo.toml @@ -8,6 +8,7 @@ keywords.workspace = true license.workspace = true repository.workspace = true readme.workspace = true +rust-version.workspace = true [package.metadata.docs.rs] all-features = true diff --git a/examples/contract_deployment/src/main.rs b/examples/contract_deployment/src/main.rs index 6e900b8cd9..02bf76e96b 100644 --- a/examples/contract_deployment/src/main.rs +++ b/examples/contract_deployment/src/main.rs @@ -92,7 +92,7 @@ fn main() -> anyhow::Result<()> { println!("storage U256(0) at {address}: {storage0:#?}"); assert_eq!( storage0.present_value(), - param.try_into()?, + StorageValue::try_from(param)?, "{:#?}", output.result ); diff --git a/examples/custom_opcodes/Cargo.toml b/examples/custom_opcodes/Cargo.toml index 8a269c1503..f93d35af68 100644 --- a/examples/custom_opcodes/Cargo.toml +++ b/examples/custom_opcodes/Cargo.toml @@ -8,6 +8,7 @@ keywords.workspace = true license.workspace = true repository.workspace = true readme.workspace = true +rust-version.workspace = true [package.metadata.docs.rs] all-features = true @@ -17,4 +18,4 @@ rustdoc-args = ["--cfg", "docsrs"] workspace = true [dependencies] -revm = {workspace = true, features = ["std", "tracer"]} +revm = { workspace = true, features = ["std", "tracer"] } diff --git a/examples/custom_opcodes/src/main.rs b/examples/custom_opcodes/src/main.rs index c08305de5f..c81d99f238 100644 --- a/examples/custom_opcodes/src/main.rs +++ b/examples/custom_opcodes/src/main.rs @@ -10,7 +10,7 @@ use revm::{ interpreter::{ interpreter::EthInterpreter, interpreter_types::{Immediates, Jumps}, - InstructionContext, + Instruction, InstructionContext, }, primitives::TxKind, state::Bytecode, @@ -41,10 +41,13 @@ pub fn main() { // insert our custom opcode instructions.insert_instruction( MY_STATIC_JUMP, - |ctx: InstructionContext<'_, _, EthInterpreter>| { - let offset = ctx.interpreter.bytecode.read_i16(); - ctx.interpreter.bytecode.relative_jump(offset as isize); - }, + Instruction::new( + |ctx: InstructionContext<'_, _, EthInterpreter>| { + let offset = ctx.interpreter.bytecode.read_i16(); + ctx.interpreter.bytecode.relative_jump(offset as isize); + }, + 0, + ), ); // Create a new EVM instance. diff --git a/examples/custom_precompile_journal/Cargo.toml b/examples/custom_precompile_journal/Cargo.toml index cc46f6f2f5..8a052ce301 100644 --- a/examples/custom_precompile_journal/Cargo.toml +++ b/examples/custom_precompile_journal/Cargo.toml @@ -1,11 +1,14 @@ [package] -name = "custom_precompile_journal" +name = "example-custom-precompile-journal" version = "0.1.0" -edition = "2021" - -[[bin]] -name = "custom_precompile_journal" -path = "src/main.rs" +publish = false +authors.workspace = true +edition.workspace = true +keywords.workspace = true +license.workspace = true +repository.workspace = true +readme.workspace = true +rust-version.workspace = true [dependencies] revm = { path = "../../crates/revm", features = ["optional_eip3607"] } diff --git a/examples/custom_precompile_journal/src/main.rs b/examples/custom_precompile_journal/src/main.rs index 2aaf791a62..6a4595775c 100644 --- a/examples/custom_precompile_journal/src/main.rs +++ b/examples/custom_precompile_journal/src/main.rs @@ -6,7 +6,9 @@ //! 3. Modifying account balances and storage from within a precompile //! 4. Integrating the custom precompile into a custom EVM implementation -use custom_precompile_journal::{precompile_provider::CUSTOM_PRECOMPILE_ADDRESS, CustomEvm}; +use example_custom_precompile_journal::{ + precompile_provider::CUSTOM_PRECOMPILE_ADDRESS, CustomEvm, +}; use revm::{ context::{result::InvalidTransaction, Context, ContextSetters, ContextTr, TxEnv}, context_interface::result::EVMError, diff --git a/examples/database_components/Cargo.toml b/examples/database_components/Cargo.toml index 8aff4db8e7..9b06a437e7 100644 --- a/examples/database_components/Cargo.toml +++ b/examples/database_components/Cargo.toml @@ -8,6 +8,7 @@ keywords.workspace = true license.workspace = true repository.workspace = true readme.workspace = true +rust-version.workspace = true [package.metadata.docs.rs] all-features = true diff --git a/examples/erc20_gas/Cargo.toml b/examples/erc20_gas/Cargo.toml index 2101c4a4c0..fb302eb5d8 100644 --- a/examples/erc20_gas/Cargo.toml +++ b/examples/erc20_gas/Cargo.toml @@ -8,6 +8,7 @@ keywords.workspace = true license.workspace = true repository.workspace = true readme.workspace = true +rust-version.workspace = true [package.metadata.docs.rs] all-features = true diff --git a/examples/erc20_gas/src/handler.rs b/examples/erc20_gas/src/handler.rs index c747319899..eeeed76fad 100644 --- a/examples/erc20_gas/src/handler.rs +++ b/examples/erc20_gas/src/handler.rs @@ -83,6 +83,8 @@ where .expect("effective balance is always smaller than max balance so it can't overflow"); let account_balance_slot = erc_address_storage(tx.caller()); + context.journal_mut().load_account(TOKEN)?.data.mark_touch(); + let account_balance = context .journal_mut() .sload(TOKEN, account_balance_slot) @@ -101,7 +103,6 @@ where // Transfer will be done inside `*_inner` functions. if is_balance_check_disabled { // ignore balance check. - // TODO add transfer value to the erc20 slot. } else if max_balance_spending > account_balance { return Err(InvalidTransaction::LackOfFundForMaxFee { fee: Box::new(max_balance_spending), @@ -136,6 +137,7 @@ where let reimbursement = effective_gas_price.saturating_mul((gas.remaining() + gas.refunded() as u64) as u128); + token_operation::( context, TREASURY, diff --git a/examples/my_evm/Cargo.toml b/examples/my_evm/Cargo.toml index 9453097a42..b5a335171a 100644 --- a/examples/my_evm/Cargo.toml +++ b/examples/my_evm/Cargo.toml @@ -8,6 +8,7 @@ keywords.workspace = true license.workspace = true repository.workspace = true readme.workspace = true +rust-version.workspace = true [package.metadata.docs.rs] all-features = true diff --git a/examples/my_evm/README.md b/examples/my_evm/README.md index cc80132fc4..7b0a852968 100644 --- a/examples/my_evm/README.md +++ b/examples/my_evm/README.md @@ -76,5 +76,5 @@ System calls are needed for inserting of fetching data on pre or post block stat ```rust,ignore let mut my_evm = MyEvm::new(Context::mainnet(), revm::inspector::NoOpInspector); // System call with given input to system contract address. -let _res = my_evm.transact_system_call(bytes!("0x0001"), address!("f529c70db0800449ebd81fbc6e4221523a989f05")); +let _res = my_evm.system_call_one(SYSTEM_ADDRESS, address!("f529c70db0800449ebd81fbc6e4221523a989f05"), bytes!("0x0001")); ``` diff --git a/examples/uniswap_get_reserves/Cargo.toml b/examples/uniswap_get_reserves/Cargo.toml index d1d8d8df2d..846e226655 100644 --- a/examples/uniswap_get_reserves/Cargo.toml +++ b/examples/uniswap_get_reserves/Cargo.toml @@ -8,6 +8,7 @@ keywords.workspace = true license.workspace = true repository.workspace = true readme.workspace = true +rust-version.workspace = true [package.metadata.docs.rs] all-features = true diff --git a/examples/uniswap_v2_usdc_swap/Cargo.toml b/examples/uniswap_v2_usdc_swap/Cargo.toml index 90fd3f1372..e4157d015c 100644 --- a/examples/uniswap_v2_usdc_swap/Cargo.toml +++ b/examples/uniswap_v2_usdc_swap/Cargo.toml @@ -8,6 +8,7 @@ keywords.workspace = true license.workspace = true repository.workspace = true readme.workspace = true +rust-version.workspace = true [package.metadata.docs.rs] all-features = true diff --git a/scripts/run-tests.sh b/scripts/run-tests.sh index 5826df605b..0f813f9b8b 100755 --- a/scripts/run-tests.sh +++ b/scripts/run-tests.sh @@ -1,7 +1,7 @@ -# ./run-tests --help +#!/usr/bin/env bash +set -eo pipefail -#!/bin/bash -set -e +# Usage: ./scripts/run-tests.sh --help # Version for the execution spec tests VERSION="v4.4.0"