diff --git a/.github/workflows/ci_l1.yaml b/.github/workflows/ci_l1.yaml index 5d1efa015..22bd57951 100644 --- a/.github/workflows/ci_l1.yaml +++ b/.github/workflows/ci_l1.yaml @@ -101,6 +101,20 @@ jobs: name: ethrex_image path: /tmp/ethrex_image.tar + setup-hive: + name: "Setup Hive" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Setup Hive + run: make setup-hive + - name: Upload hive artifacts + uses: actions/upload-artifact@v4 + with: + name: hive + path: hive + + run-assertoor: name: Assertoor - ${{ matrix.name }} runs-on: ubuntu-latest @@ -119,7 +133,7 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Download artifacts + - name: Download etherex image artifact uses: actions/download-artifact@v4 with: name: ethrex_image @@ -141,7 +155,7 @@ jobs: run-hive: name: Hive - ${{ matrix.name }} runs-on: ubuntu-latest - needs: [docker_build] + needs: [docker_build, setup-hive] if: ${{ github.event_name != 'merge_group' }} strategy: matrix: @@ -157,7 +171,7 @@ jobs: test_pattern: /AccountRange|StorageRanges|ByteCodes|TrieNodes - name: "Devp2p eth tests" simulation: devp2p - test_pattern: eth/Status|GetBlockHeaders|SimultaneousRequests|SameRequestID|ZeroRequestID|GetBlockBodies|MaliciousHandshake|MaliciousStatus|Transaction|InvalidTxs|NewPooledTxs + test_pattern: eth/Status|GetBlockHeaders|SimultaneousRequests|SameRequestID|ZeroRequestID|GetBlockBodies|MaliciousHandshake|MaliciousStatus|Transaction|InvalidTxs|NewPooledTxs|GetBlockReceipts - name: "Engine Auth and EC tests" simulation: ethereum/engine test_pattern: engine-(auth|exchange-capabilities)/ @@ -168,32 +182,26 @@ jobs: simulation: ethereum/engine test_pattern: "engine-api/RPC|Re-Org Back to Canonical Chain From Syncing Chain|Re-org to Previously Validated Sidechain Payload|Re-Org Back into Canonical Chain, Depth=5|Safe Re-Org|Transaction Re-Org|Inconsistent|Suggested Fee|PrevRandao|Fork ID|Unknown|Invalid PayloadAttributes|Bad Hash|Unique Payload ID|Re-Execute Payload|In-Order|Multiple New Payloads|Valid NewPayload|NewPayload with|Invalid NewPayload|Payload Build|Invalid NewPayload, Transaction|ParentHash equals|Build Payload|Invalid Missing Ancestor ReOrg" steps: - - name: Download artifacts + - name: Checkout sources + uses: actions/checkout@v4 + + - name: Download ethrex image artifact uses: actions/download-artifact@v4 with: name: ethrex_image path: /tmp + - name: Download hive artifacts + uses: actions/download-artifact@v4 + with: + name: hive + - name: Load image run: | docker load --input /tmp/ethrex_image.tar - - name: Checkout sources - uses: actions/checkout@v4 - - - name: Rustup toolchain install - uses: dtolnay/rust-toolchain@stable - with: - toolchain: ${{ env.RUST_VERSION }} - - - name: Setup Go - uses: actions/setup-go@v5 - - - name: Setup Hive - run: make setup-hive - - name: Run Hive Simulation - run: cd hive && ./hive --client ethrex --sim ${{ matrix.simulation }} --sim.limit "${{ matrix.test_pattern }}" --sim.parallelism 4 + run: chmod +x hive && ./hive --client ethrex --sim ${{ matrix.simulation }} --sim.limit "${{ matrix.test_pattern }}" --sim.parallelism 4 # The purpose of this job is to add it as a required check in GitHub so that we don't have to add every individual job as a required check all-tests: diff --git a/.github/workflows/ci_l2_prover.yaml b/.github/workflows/ci_l2_prover.yaml index a45097021..b6049bddf 100644 --- a/.github/workflows/ci_l2_prover.yaml +++ b/.github/workflows/ci_l2_prover.yaml @@ -43,17 +43,29 @@ jobs: uses: dtolnay/rust-toolchain@stable # Use cargo-risczero v1.2.0 # The risc0-zkvm crate should match this version - - name: RISC-V zkVM toolchain install + - name: RISC-V RISC0 toolchain install run: | curl -L https://risczero.com/install | bash ~/.risc0/bin/rzup install ~/.risc0/bin/rzup extension install cargo-risczero v1.2.0 ~/.risc0/bin/rzup extension use cargo-risczero v1.2.0 - - name: Build prover and zkVM + - name: Build prover and RISC0's zkVM run: | cd crates/l2/prover - cargo build --release --features build_zkvm + cargo build --release --features build_risc0 - name: Test Prover Execution run: | cd crates/l2/prover - RUST_LOG=info make perf_test_proving + RUST_LOG=info make perf-risc0 + - name: RISC-V SP1 toolchain install + run: | + curl -L https://sp1.succinct.xyz | bash + ~/.sp1/bin/sp1up + - name: Build prover and SP1's zkVM + run: | + cd crates/l2/prover + cargo build --release --features build_sp1 + - name: Test Prover Execution + run: | + cd crates/l2/prover + RUST_LOG=info make perf-sp1 diff --git a/.github/workflows/ci_levm.yaml b/.github/workflows/ci_levm.yaml index 5b3311521..4c1266e8d 100644 --- a/.github/workflows/ci_levm.yaml +++ b/.github/workflows/ci_levm.yaml @@ -41,7 +41,12 @@ jobs: - name: Run tests run: | cd crates/vm/levm - make run-evm-ef-tests-ci + make run-evm-ef-tests-ci | tee test_result.txt + + - name: Show test summary + run: | + cd crates/vm/levm + awk '/Summary: /,0' test_result.txt test: # "Test" is a required check, don't change the name name: Test diff --git a/Cargo.lock b/Cargo.lock index 5e31430d2..1aa4b5195 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,16 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" +dependencies = [ + "lazy_static", + "regex", +] + [[package]] name = "addchain" version = "0.2.0" @@ -256,7 +266,7 @@ dependencies = [ "alloy-primitives 0.8.14", "alloy-rlp", "alloy-serde", - "alloy-sol-types", + "alloy-sol-types 0.8.14", "derive_more 1.0.0", "itertools 0.13.0", "serde", @@ -288,27 +298,59 @@ dependencies = [ "serde_json", ] +[[package]] +name = "alloy-sol-macro" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b40397ddcdcc266f59f959770f601ce1280e699a91fc1862f29cef91707cd09" +dependencies = [ + "alloy-sol-macro-expander 0.7.7", + "alloy-sol-macro-input 0.7.7", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.89", +] + [[package]] name = "alloy-sol-macro" version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3bfd7853b65a2b4f49629ec975fee274faf6dff15ab8894c620943398ef283c0" dependencies = [ - "alloy-sol-macro-expander", - "alloy-sol-macro-input", + "alloy-sol-macro-expander 0.8.14", + "alloy-sol-macro-input 0.8.14", "proc-macro-error2", "proc-macro2", "quote", "syn 2.0.89", ] +[[package]] +name = "alloy-sol-macro-expander" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "867a5469d61480fea08c7333ffeca52d5b621f5ca2e44f271b117ec1fc9a0525" +dependencies = [ + "alloy-sol-macro-input 0.7.7", + "const-hex", + "heck 0.5.0", + "indexmap 2.6.0", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.89", + "syn-solidity 0.7.7", + "tiny-keccak", +] + [[package]] name = "alloy-sol-macro-expander" version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "82ec42f342d9a9261699f8078e57a7a4fda8aaa73c1a212ed3987080e6a9cd13" dependencies = [ - "alloy-sol-macro-input", + "alloy-sol-macro-input 0.8.14", "const-hex", "heck 0.5.0", "indexmap 2.6.0", @@ -316,10 +358,25 @@ dependencies = [ "proc-macro2", "quote", "syn 2.0.89", - "syn-solidity", + "syn-solidity 0.8.14", "tiny-keccak", ] +[[package]] +name = "alloy-sol-macro-input" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e482dc33a32b6fadbc0f599adea520bd3aaa585c141a80b404d0a3e3fa72528" +dependencies = [ + "const-hex", + "dunce", + "heck 0.5.0", + "proc-macro2", + "quote", + "syn 2.0.89", + "syn-solidity 0.7.7", +] + [[package]] name = "alloy-sol-macro-input" version = "0.8.14" @@ -332,7 +389,7 @@ dependencies = [ "proc-macro2", "quote", "syn 2.0.89", - "syn-solidity", + "syn-solidity 0.8.14", ] [[package]] @@ -342,7 +399,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac17c6e89a50fb4a758012e4b409d9a0ba575228e69b539fe37d7a1bd507ca4a" dependencies = [ "serde", - "winnow", + "winnow 0.6.20", +] + +[[package]] +name = "alloy-sol-types" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a91ca40fa20793ae9c3841b83e74569d1cc9af29a2f5237314fd3452d51e38c7" +dependencies = [ + "alloy-primitives 0.7.7", + "alloy-sol-macro 0.7.7", + "const-hex", + "serde", ] [[package]] @@ -353,7 +422,7 @@ checksum = "c9dc0fffe397aa17628160e16b89f704098bf3c9d74d5d369ebc239575936de5" dependencies = [ "alloy-json-abi", "alloy-primitives 0.8.14", - "alloy-sol-macro", + "alloy-sol-macro 0.8.14", "const-hex", "serde", ] @@ -712,6 +781,17 @@ dependencies = [ "syn 2.0.89", ] +[[package]] +name = "async_io_stream" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c" +dependencies = [ + "futures", + "pharos", + "rustc_version 0.4.1", +] + [[package]] name = "atomic-waker" version = "1.1.2" @@ -772,10 +852,10 @@ dependencies = [ "axum-core", "bytes", "futures-util", - "http", - "http-body", + "http 1.1.0", + "http-body 1.0.1", "http-body-util", - "hyper", + "hyper 1.5.1", "hyper-util", "itoa", "matchit", @@ -805,8 +885,8 @@ dependencies = [ "async-trait", "bytes", "futures-util", - "http", - "http-body", + "http 1.1.0", + "http-body 1.0.1", "http-body-util", "mime", "pin-project-lite", @@ -829,8 +909,8 @@ dependencies = [ "fastrand", "futures-util", "headers", - "http", - "http-body", + "http 1.1.0", + "http-body 1.0.1", "http-body-util", "mime", "multer", @@ -853,6 +933,7 @@ dependencies = [ "miniz_oxide", "object 0.36.5", "rustc-demangle", + "serde", "windows-targets 0.52.6", ] @@ -886,6 +967,12 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +[[package]] +name = "bech32" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" + [[package]] name = "bincode" version = "1.3.3" @@ -905,6 +992,8 @@ dependencies = [ "cexpr", "clang-sys", "itertools 0.13.0", + "log", + "prettyplease", "proc-macro2", "quote", "regex", @@ -965,6 +1054,30 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "blake2b_simd" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23285ad32269793932e830392f2fe2f83e26488fd3ec778883a93c8323735780" +dependencies = [ + "arrayref", + "arrayvec", + "constant_time_eq", +] + +[[package]] +name = "blake3" +version = "1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8ee0c1824c4dea5b5f81736aff91bae041d2c07ee1192bec91054e10e3e601e" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", +] + [[package]] name = "block" version = "0.1.6" @@ -977,7 +1090,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ - "generic-array", + "generic-array 0.14.7", ] [[package]] @@ -986,7 +1099,20 @@ version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ - "generic-array", + "generic-array 0.14.7", +] + +[[package]] +name = "bls12_381" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3c196a77437e7cc2fb515ce413a6401291578b5afc8ecb29a3c7ab957f05941" +dependencies = [ + "ff 0.12.1", + "group 0.12.1", + "pairing", + "rand_core 0.6.4", + "subtle", ] [[package]] @@ -1009,7 +1135,7 @@ checksum = "ce58205497760ded0e4c743bc7a7aee28da5ca29b4adb7a635bf3bee2d118ebc" dependencies = [ "duplicate", "maybe-async", - "reqwest", + "reqwest 0.12.9", "serde", "thiserror 1.0.69", ] @@ -1031,12 +1157,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2593a3b8b938bd68373196c9832f516be11fa487ef4ae745eb282e6a56a7244" dependencies = [ "once_cell", - "proc-macro-crate", + "proc-macro-crate 3.2.0", "proc-macro2", "quote", "syn 2.0.89", ] +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "sha2 0.10.8", + "tinyvec", +] + [[package]] name = "bstr" version = "1.11.0" @@ -1251,7 +1387,7 @@ dependencies = [ "bitflags 1.3.2", "strsim 0.8.0", "textwrap", - "unicode-width", + "unicode-width 0.1.14", "vec_map", ] @@ -1304,6 +1440,58 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" +[[package]] +name = "coins-bip32" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b6be4a5df2098cd811f3194f64ddb96c267606bffd9689ac7b0160097b01ad3" +dependencies = [ + "bs58", + "coins-core", + "digest 0.10.7", + "hmac 0.12.1", + "k256", + "serde", + "sha2 0.10.8", + "thiserror 1.0.69", +] + +[[package]] +name = "coins-bip39" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3db8fba409ce3dc04f7d804074039eb68b960b0829161f8e06c95fea3f122528" +dependencies = [ + "bitvec", + "coins-bip32", + "hmac 0.12.1", + "once_cell", + "pbkdf2 0.12.2", + "rand 0.8.5", + "sha2 0.10.8", + "thiserror 1.0.69", +] + +[[package]] +name = "coins-core" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5286a0843c21f8367f7be734f89df9b822e0321d8bcce8d6e735aadff7d74979" +dependencies = [ + "base64 0.21.7", + "bech32", + "bs58", + "digest 0.10.7", + "generic-array 0.14.7", + "hex", + "ripemd", + "serde", + "serde_derive", + "sha2 0.10.8", + "sha3", + "thiserror 1.0.69", +] + [[package]] name = "colorchoice" version = "1.0.3" @@ -1338,7 +1526,7 @@ dependencies = [ "encode_unicode", "lazy_static", "libc", - "unicode-width", + "unicode-width 0.1.14", "windows-sys 0.52.0", ] @@ -1361,6 +1549,12 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "constant_time_eq" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" + [[package]] name = "convert_case" version = "0.4.0" @@ -1489,7 +1683,7 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ - "generic-array", + "generic-array 0.14.7", "rand_core 0.6.4", "subtle", "zeroize", @@ -1501,7 +1695,7 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ - "generic-array", + "generic-array 0.14.7", "typenum", ] @@ -1511,7 +1705,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" dependencies = [ - "generic-array", + "generic-array 0.14.7", "subtle", ] @@ -1524,6 +1718,16 @@ dependencies = [ "cipher", ] +[[package]] +name = "ctrlc" +version = "3.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90eeab0aa92f3f9b4e87f258c72b139c207d251f9cbc1080a0086b86a8870dd3" +dependencies = [ + "nix", + "windows-sys 0.59.0", +] + [[package]] name = "cust" version = "0.3.2" @@ -1616,6 +1820,84 @@ dependencies = [ "serde", ] +[[package]] +name = "dashu" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85b3e5ac1e23ff1995ef05b912e2b012a8784506987a2651552db2c73fb3d7e0" +dependencies = [ + "dashu-base", + "dashu-float", + "dashu-int", + "dashu-macros", + "dashu-ratio", + "rustversion", +] + +[[package]] +name = "dashu-base" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b80bf6b85aa68c58ffea2ddb040109943049ce3fbdf4385d0380aef08ef289" + +[[package]] +name = "dashu-float" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85078445a8dbd2e1bd21f04a816f352db8d333643f0c9b78ca7c3d1df71063e7" +dependencies = [ + "dashu-base", + "dashu-int", + "num-modular", + "num-order", + "rustversion", + "static_assertions", +] + +[[package]] +name = "dashu-int" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee99d08031ca34a4d044efbbb21dff9b8c54bb9d8c82a189187c0651ffdb9fbf" +dependencies = [ + "cfg-if", + "dashu-base", + "num-modular", + "num-order", + "rustversion", + "static_assertions", +] + +[[package]] +name = "dashu-macros" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93381c3ef6366766f6e9ed9cf09e4ef9dec69499baf04f0c60e70d653cf0ab10" +dependencies = [ + "dashu-base", + "dashu-float", + "dashu-int", + "dashu-ratio", + "paste", + "proc-macro2", + "quote", + "rustversion", +] + +[[package]] +name = "dashu-ratio" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47e33b04dd7ce1ccf8a02a69d3419e354f2bbfdf4eb911a0b7465487248764c9" +dependencies = [ + "dashu-base", + "dashu-float", + "dashu-int", + "num-modular", + "num-order", + "rustversion", +] + [[package]] name = "datatest-stable" version = "0.2.9" @@ -1729,7 +2011,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" dependencies = [ - "generic-array", + "generic-array 0.14.7", ] [[package]] @@ -1826,7 +2108,7 @@ dependencies = [ "digest 0.10.7", "futures", "rand 0.8.5", - "reqwest", + "reqwest 0.12.9", "thiserror 1.0.69", "tokio", ] @@ -1928,9 +2210,9 @@ dependencies = [ "base16ct", "crypto-bigint", "digest 0.10.7", - "ff", - "generic-array", - "group", + "ff 0.13.0", + "generic-array 0.14.7", + "group 0.13.0", "hkdf", "pkcs8", "rand_core 0.6.4", @@ -1963,6 +2245,45 @@ dependencies = [ "encoding_rs", ] +[[package]] +name = "enr" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a3d8dc56e02f954cac8eb489772c552c473346fc34f67412bb6244fd647f7e4" +dependencies = [ + "base64 0.21.7", + "bytes", + "hex", + "k256", + "log", + "rand 0.8.5", + "rlp", + "serde", + "sha3", + "zeroize", +] + +[[package]] +name = "enum-map" +version = "2.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6866f3bfdf8207509a033af1a75a7b08abda06bbaaeae6669323fd5a097df2e9" +dependencies = [ + "enum-map-derive", + "serde", +] + +[[package]] +name = "enum-map-derive" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + [[package]] name = "enumn" version = "0.1.14" @@ -2029,30 +2350,267 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5692dd7b5a1978a5aeb0ce83b7655c58ca8efdcb79d21036ea249da95afec2c6" [[package]] -name = "ethbloom" -version = "0.13.0" +name = "eth-keystore" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" +checksum = "1fda3bf123be441da5260717e0661c25a2fd9cb2b2c1d20bf2e05580047158ab" dependencies = [ - "crunchy", - "fixed-hash", - "impl-rlp", - "impl-serde", - "tiny-keccak", + "aes", + "ctr", + "digest 0.10.7", + "hex", + "hmac 0.12.1", + "pbkdf2 0.11.0", + "rand 0.8.5", + "scrypt", + "serde", + "serde_json", + "sha2 0.10.8", + "sha3", + "thiserror 1.0.69", + "uuid", ] [[package]] -name = "ethereum-types" -version = "0.14.1" +name = "ethabi" +version = "18.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" +checksum = "7413c5f74cc903ea37386a8965a936cbeb334bd270862fdece542c1b2dcbc898" dependencies = [ - "ethbloom", - "fixed-hash", - "impl-rlp", - "impl-serde", - "primitive-types 0.12.2", - "uint 0.9.5", + "ethereum-types", + "hex", + "once_cell", + "regex", + "serde", + "serde_json", + "sha3", + "thiserror 1.0.69", + "uint 0.9.5", +] + +[[package]] +name = "ethbloom" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" +dependencies = [ + "crunchy", + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "scale-info", + "tiny-keccak", +] + +[[package]] +name = "ethereum-types" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" +dependencies = [ + "ethbloom", + "fixed-hash", + "impl-codec", + "impl-rlp", + "impl-serde", + "primitive-types 0.12.2", + "scale-info", + "uint 0.9.5", +] + +[[package]] +name = "ethers" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "816841ea989f0c69e459af1cf23a6b0033b19a55424a1ea3a30099becdb8dec0" +dependencies = [ + "ethers-addressbook", + "ethers-contract", + "ethers-core", + "ethers-middleware", + "ethers-providers", + "ethers-signers", +] + +[[package]] +name = "ethers-addressbook" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5495afd16b4faa556c3bba1f21b98b4983e53c1755022377051a975c3b021759" +dependencies = [ + "ethers-core", + "once_cell", + "serde", + "serde_json", +] + +[[package]] +name = "ethers-contract" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fceafa3578c836eeb874af87abacfb041f92b4da0a78a5edd042564b8ecdaaa" +dependencies = [ + "const-hex", + "ethers-contract-abigen", + "ethers-contract-derive", + "ethers-core", + "ethers-providers", + "futures-util", + "once_cell", + "pin-project", + "serde", + "serde_json", + "thiserror 1.0.69", +] + +[[package]] +name = "ethers-contract-abigen" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04ba01fbc2331a38c429eb95d4a570166781f14290ef9fdb144278a90b5a739b" +dependencies = [ + "Inflector", + "const-hex", + "dunce", + "ethers-core", + "eyre", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "serde", + "serde_json", + "syn 2.0.89", + "toml 0.8.19", + "walkdir", +] + +[[package]] +name = "ethers-contract-derive" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87689dcabc0051cde10caaade298f9e9093d65f6125c14575db3fd8c669a168f" +dependencies = [ + "Inflector", + "const-hex", + "ethers-contract-abigen", + "ethers-core", + "proc-macro2", + "quote", + "serde_json", + "syn 2.0.89", +] + +[[package]] +name = "ethers-core" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82d80cc6ad30b14a48ab786523af33b37f28a8623fc06afd55324816ef18fb1f" +dependencies = [ + "arrayvec", + "bytes", + "cargo_metadata", + "chrono", + "const-hex", + "elliptic-curve", + "ethabi", + "generic-array 0.14.7", + "k256", + "num_enum 0.7.3", + "once_cell", + "open-fastrlp", + "rand 0.8.5", + "rlp", + "serde", + "serde_json", + "strum", + "syn 2.0.89", + "tempfile", + "thiserror 1.0.69", + "tiny-keccak", + "unicode-xid", +] + +[[package]] +name = "ethers-middleware" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48f9fdf09aec667c099909d91908d5eaf9be1bd0e2500ba4172c1d28bfaa43de" +dependencies = [ + "async-trait", + "auto_impl", + "ethers-contract", + "ethers-core", + "ethers-providers", + "ethers-signers", + "futures-channel", + "futures-locks", + "futures-util", + "instant", + "reqwest 0.11.27", + "serde", + "serde_json", + "thiserror 1.0.69", + "tokio", + "tracing", + "tracing-futures", + "url", +] + +[[package]] +name = "ethers-providers" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6434c9a33891f1effc9c75472e12666db2fa5a0fec4b29af6221680a6fe83ab2" +dependencies = [ + "async-trait", + "auto_impl", + "base64 0.21.7", + "bytes", + "const-hex", + "enr", + "ethers-core", + "futures-core", + "futures-timer", + "futures-util", + "hashers", + "http 0.2.12", + "instant", + "jsonwebtoken 8.3.0", + "once_cell", + "pin-project", + "reqwest 0.11.27", + "serde", + "serde_json", + "thiserror 1.0.69", + "tokio", + "tracing", + "tracing-futures", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "ws_stream_wasm", +] + +[[package]] +name = "ethers-signers" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "228875491c782ad851773b652dd8ecac62cda8571d3bc32a5853644dd26766c2" +dependencies = [ + "async-trait", + "coins-bip32", + "coins-bip39", + "const-hex", + "elliptic-curve", + "eth-keystore", + "ethers-core", + "rand 0.8.5", + "sha2 0.10.8", + "thiserror 1.0.69", + "tracing", ] [[package]] @@ -2139,9 +2697,9 @@ dependencies = [ "ethereum-types", "ethrex-rpc", "hex", - "jsonwebtoken", + "jsonwebtoken 9.3.0", "keccak-hash 0.10.0", - "reqwest", + "reqwest 0.12.9", "serde", "serde_json", "sha2 0.10.8", @@ -2166,14 +2724,15 @@ dependencies = [ "ethrex-storage", "ethrex-vm", "hex", - "jsonwebtoken", + "jsonwebtoken 9.3.0", "keccak-hash 0.10.0", "rand 0.8.5", - "reqwest", + "reqwest 0.12.9", "risc0-zkvm", "secp256k1", "serde", "serde_json", + "sp1-sdk", "thiserror 1.0.69", "tokio", "tokio-util", @@ -2192,7 +2751,10 @@ dependencies = [ "ethrex-rlp", "hex", "keccak-hash 0.11.0", + "lambdaworks-math", "libsecp256k1", + "num-bigint 0.4.6", + "ripemd", "serde", "serde_json", "sha2 0.10.8", @@ -2259,6 +2821,8 @@ dependencies = [ "risc0-zkvm", "serde", "serde_json", + "sp1-sdk", + "thiserror 1.0.69", "tokio", "tokio-util", "tracing", @@ -2295,9 +2859,9 @@ dependencies = [ "ethrex-vm", "hex", "hex-literal", - "jsonwebtoken", + "jsonwebtoken 9.3.0", "rand 0.8.5", - "reqwest", + "reqwest 0.12.9", "serde", "serde_json", "tokio", @@ -2488,6 +3052,17 @@ dependencies = [ "bytes", ] +[[package]] +name = "ff" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" +dependencies = [ + "bitvec", + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "ff" version = "0.13.0" @@ -2671,6 +3246,16 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +[[package]] +name = "futures-locks" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45ec6fe3675af967e67c5536c0b9d44e34e6c52f86bedc4ea49c5317b8e94d06" +dependencies = [ + "futures-channel", + "futures-task", +] + [[package]] name = "futures-macro" version = "0.3.31" @@ -2694,6 +3279,16 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +[[package]] +name = "futures-timer" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" +dependencies = [ + "gloo-timers", + "send_wrapper 0.4.0", +] + [[package]] name = "futures-util" version = "0.3.31" @@ -2712,6 +3307,21 @@ dependencies = [ "slab", ] +[[package]] +name = "fxhash" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" +dependencies = [ + "byteorder", +] + +[[package]] +name = "gcd" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a" + [[package]] name = "generic-array" version = "0.14.7" @@ -2723,6 +3333,16 @@ dependencies = [ "zeroize", ] +[[package]] +name = "generic-array" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2cb8bc4c28d15ade99c7e90b219f30da4be5c88e586277e8cbe886beeb868ab2" +dependencies = [ + "serde", + "typenum", +] + [[package]] name = "getrandom" version = "0.2.15" @@ -2752,6 +3372,19 @@ version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" +[[package]] +name = "git2" +version = "0.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b903b73e45dc0c6c596f2d37eccece7c1c8bb6e4407b001096387c63d0d93724" +dependencies = [ + "bitflags 2.6.0", + "libc", + "libgit2-sys", + "log", + "url", +] + [[package]] name = "glam" version = "0.20.5" @@ -2791,6 +3424,18 @@ dependencies = [ "walkdir", ] +[[package]] +name = "gloo-timers" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" +dependencies = [ + "futures-channel", + "futures-core", + "js-sys", + "wasm-bindgen", +] + [[package]] name = "grep-matcher" version = "0.1.7" @@ -2815,17 +3460,48 @@ dependencies = [ "memmap2", ] +[[package]] +name = "group" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" +dependencies = [ + "ff 0.12.1", + "memuse", + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "group" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ - "ff", + "ff 0.13.0", "rand_core 0.6.4", "subtle", ] +[[package]] +name = "h2" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http 0.2.12", + "indexmap 2.6.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "h2" version = "0.4.7" @@ -2837,7 +3513,7 @@ dependencies = [ "fnv", "futures-core", "futures-sink", - "http", + "http 1.1.0", "indexmap 2.6.0", "slab", "tokio", @@ -2846,10 +3522,33 @@ dependencies = [ ] [[package]] -name = "hashbrown" -version = "0.12.3" +name = "halo2" +version = "0.1.0-beta.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +checksum = "2a23c779b38253fe1538102da44ad5bd5378495a61d2c4ee18d64eaa61ae5995" +dependencies = [ + "halo2_proofs", +] + +[[package]] +name = "halo2_proofs" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e925780549adee8364c7f2b685c753f6f3df23bde520c67416e93bf615933760" +dependencies = [ + "blake2b_simd", + "ff 0.12.1", + "group 0.12.1", + "pasta_curves 0.4.1", + "rand_core 0.6.4", + "rayon", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" @@ -2868,6 +3567,7 @@ checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" dependencies = [ "ahash", "allocator-api2", + "serde", ] [[package]] @@ -2876,6 +3576,8 @@ version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" dependencies = [ + "allocator-api2", + "equivalent", "foldhash", "serde", ] @@ -2889,6 +3591,15 @@ dependencies = [ "tiny-keccak", ] +[[package]] +name = "hashers" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2bca93b15ea5a746f220e56587f71e73c6165eab783df9e26590069953e3c30" +dependencies = [ + "fxhash", +] + [[package]] name = "headers" version = "0.4.0" @@ -2898,7 +3609,7 @@ dependencies = [ "base64 0.21.7", "bytes", "headers-core", - "http", + "http 1.1.0", "httpdate", "mime", "sha1", @@ -2910,7 +3621,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" dependencies = [ - "http", + "http 1.1.0", ] [[package]] @@ -2998,7 +3709,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1" dependencies = [ "digest 0.9.0", - "generic-array", + "generic-array 0.14.7", "hmac 0.8.1", ] @@ -3011,6 +3722,17 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "http" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" +dependencies = [ + "bytes", + "fnv", + "itoa", +] + [[package]] name = "http" version = "1.1.0" @@ -3022,6 +3744,17 @@ dependencies = [ "itoa", ] +[[package]] +name = "http-body" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +dependencies = [ + "bytes", + "http 0.2.12", + "pin-project-lite", +] + [[package]] name = "http-body" version = "1.0.1" @@ -3029,7 +3762,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http", + "http 1.1.0", ] [[package]] @@ -3040,8 +3773,8 @@ checksum = "793429d76616a256bcb62c2a2ec2bed781c8307e797e2598c50010f2bee2544f" dependencies = [ "bytes", "futures-util", - "http", - "http-body", + "http 1.1.0", + "http-body 1.0.1", "pin-project-lite", ] @@ -3072,6 +3805,30 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +[[package]] +name = "hyper" +version = "0.14.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c08302e8fa335b151b788c775ff56e7a03ae64ff85c548ee820fecb70356e85" +dependencies = [ + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2 0.3.26", + "http 0.2.12", + "http-body 0.4.6", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", +] + [[package]] name = "hyper" version = "1.5.1" @@ -3081,9 +3838,9 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "h2", - "http", - "http-body", + "h2 0.4.7", + "http 1.1.0", + "http-body 1.0.1", "httparse", "httpdate", "itoa", @@ -3100,8 +3857,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" dependencies = [ "futures-util", - "http", - "hyper", + "http 1.1.0", + "hyper 1.5.1", "hyper-util", "rustls", "rustls-pki-types", @@ -3111,6 +3868,19 @@ dependencies = [ "webpki-roots", ] +[[package]] +name = "hyper-tls" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" +dependencies = [ + "bytes", + "hyper 0.14.31", + "native-tls", + "tokio", + "tokio-native-tls", +] + [[package]] name = "hyper-tls" version = "0.6.0" @@ -3119,7 +3889,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper", + "hyper 1.5.1", "hyper-util", "native-tls", "tokio", @@ -3136,9 +3906,9 @@ dependencies = [ "bytes", "futures-channel", "futures-util", - "http", - "http-body", - "hyper", + "http 1.1.0", + "http-body 1.0.1", + "hyper 1.5.1", "pin-project-lite", "socket2", "tokio", @@ -3402,13 +4172,26 @@ dependencies = [ "serde", ] +[[package]] +name = "indicatif" +version = "0.17.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf675b85ed934d3c67b5c5469701eec7db22689d0a2139d856e0925fa28b281" +dependencies = [ + "console", + "number_prefix", + "portable-atomic", + "unicode-width 0.2.0", + "web-time", +] + [[package]] name = "inout" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" dependencies = [ - "generic-array", + "generic-array 0.14.7", ] [[package]] @@ -3447,6 +4230,15 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + [[package]] name = "itertools" version = "0.13.0" @@ -3480,6 +4272,20 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "jsonwebtoken" +version = "8.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6971da4d9c3aa03c3d8f3ff0f4155b534aad021292003895a469716b2a230378" +dependencies = [ + "base64 0.21.7", + "pem 1.1.1", + "ring 0.16.20", + "serde", + "serde_json", + "simple_asn1", +] + [[package]] name = "jsonwebtoken" version = "9.3.0" @@ -3488,13 +4294,27 @@ checksum = "b9ae10193d25051e74945f1ea2d0b42e03cc3b890f7e4cc5faa44997d808193f" dependencies = [ "base64 0.21.7", "js-sys", - "pem", - "ring", + "pem 3.0.4", + "ring 0.17.8", "serde", "serde_json", "simple_asn1", ] +[[package]] +name = "jubjub" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a575df5f985fe1cd5b2b05664ff6accfc46559032b954529fd225a2168d27b0f" +dependencies = [ + "bitvec", + "bls12_381", + "ff 0.12.1", + "group 0.12.1", + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "k256" version = "0.13.4" @@ -3548,6 +4368,17 @@ dependencies = [ "tiny-keccak", ] +[[package]] +name = "lambdaworks-math" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "708d148956bcdc21ae5c432b4e20bbaa26fd68d5376a3a6c461f41095abea0ba" +dependencies = [ + "rayon", + "serde", + "serde_json", +] + [[package]] name = "lazy-regex" version = "3.3.0" @@ -3577,7 +4408,7 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" dependencies = [ - "spin", + "spin 0.9.8", ] [[package]] @@ -3586,6 +4417,18 @@ version = "0.2.166" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2ccc108bbc0b1331bd061864e7cd823c0cab660bbe6970e66e2c0614decde36" +[[package]] +name = "libgit2-sys" +version = "0.17.0+1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10472326a8a6477c3c20a64547b0059e4b0d086869eee31e6d7da728a8eb7224" +dependencies = [ + "cc", + "libc", + "libz-sys", + "pkg-config", +] + [[package]] name = "libloading" version = "0.8.5" @@ -3693,6 +4536,18 @@ dependencies = [ "threadpool", ] +[[package]] +name = "libz-sys" +version = "1.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2d16453e800a8cf6dd2fc3eb4bc99b786a9b90c663b8559a5b1a041bf89e472" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "linux-raw-sys" version = "0.4.14" @@ -3748,6 +4603,15 @@ version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +[[package]] +name = "lru" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" +dependencies = [ + "hashbrown 0.15.2", +] + [[package]] name = "malloc_buf" version = "0.0.6" @@ -3819,6 +4683,12 @@ dependencies = [ "libc", ] +[[package]] +name = "memuse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2145869435ace5ea6ea3d35f59be559317ec9a0d04e1812d5f185a87b6d36f1a" + [[package]] name = "metal" version = "0.29.0" @@ -3882,11 +4752,11 @@ dependencies = [ "bytes", "encoding_rs", "futures-util", - "http", + "http 1.1.0", "httparse", "memchr", "mime", - "spin", + "spin 0.9.8", "version_check", ] @@ -3948,6 +4818,24 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags 2.6.0", + "cfg-if", + "cfg_aliases", + "libc", +] + +[[package]] +name = "nohash-hasher" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" + [[package]] name = "nom" version = "7.1.3" @@ -3958,6 +4846,15 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "ntapi" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4" +dependencies = [ + "winapi", +] + [[package]] name = "nu-ansi-term" version = "0.46.0" @@ -4059,6 +4956,21 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-modular" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17bb261bf36fa7d83f4c294f834e91256769097b3cb505d44831e0a179ac647f" + +[[package]] +name = "num-order" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "537b596b97c40fcf8056d153049eb22f481c17ebce72a513ec9286e4986d1bb6" +dependencies = [ + "num-modular", +] + [[package]] name = "num-rational" version = "0.4.2" @@ -4090,6 +5002,63 @@ dependencies = [ "libc", ] +[[package]] +name = "num_enum" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" +dependencies = [ + "num_enum_derive 0.5.11", +] + +[[package]] +name = "num_enum" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e613fc340b2220f734a8595782c551f1250e969d87d3be1ae0579e8d4065179" +dependencies = [ + "num_enum_derive 0.7.3", +] + +[[package]] +name = "num_enum_derive" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" +dependencies = [ + "proc-macro-crate 3.2.0", + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "num_threads" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" +dependencies = [ + "libc", +] + +[[package]] +name = "number_prefix" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" + [[package]] name = "nvtx" version = "1.3.0" @@ -4140,6 +5109,31 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" +[[package]] +name = "open-fastrlp" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "786393f80485445794f6043fd3138854dd109cc6c4bd1a6383db304c9ce9b9ce" +dependencies = [ + "arrayvec", + "auto_impl", + "bytes", + "ethereum-types", + "open-fastrlp-derive", +] + +[[package]] +name = "open-fastrlp-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "003b2be5c6c53c1cfeb0a238b8a1c3915cd410feb684457a36c10038f764bb1c" +dependencies = [ + "bytes", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "openssl" version = "0.10.68" @@ -4197,35 +5191,303 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" [[package]] -name = "parity-scale-codec" -version = "3.7.0" +name = "p3-air" +version = "0.1.4-succinct" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8be4817d39f3272f69c59fe05d0535ae6456c2dc2fa1ba02910296c7e0a5c590" +checksum = "066f571b2e645505ed5972dd0e1e252ba03352150830c9566769ca711c0f1e9b" dependencies = [ - "arrayvec", - "bitvec", - "byte-slice-cast", - "impl-trait-for-tuples", - "parity-scale-codec-derive", - "rustversion", - "serde", + "p3-field", + "p3-matrix", ] [[package]] -name = "parity-scale-codec-derive" -version = "3.7.0" +name = "p3-baby-bear" +version = "0.1.4-succinct" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8781a75c6205af67215f382092b6e0a4ff3734798523e69073d4bcd294ec767b" +checksum = "ff00f571044d299310d9659c6e51c98422de3bf94b8577f7f30cf59cf2043e40" dependencies = [ - "proc-macro-crate", - "proc-macro2", - "quote", - "syn 2.0.89", + "num-bigint 0.4.6", + "p3-field", + "p3-mds", + "p3-poseidon2", + "p3-symmetric", + "rand 0.8.5", + "serde", ] [[package]] -name = "parking_lot" -version = "0.11.2" +name = "p3-blake3" +version = "0.1.4-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc4cb69ae54a279bbbd477566d1bdb71aa879b528fd658d0fcfc36f54b00217c" +dependencies = [ + "blake3", + "p3-symmetric", +] + +[[package]] +name = "p3-bn254-fr" +version = "0.1.4-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf19917f986d45e9abb6d177e875824ced6eed096480d574fce16f2c45c721ea" +dependencies = [ + "ff 0.13.0", + "num-bigint 0.4.6", + "p3-field", + "p3-poseidon2", + "p3-symmetric", + "rand 0.8.5", + "serde", +] + +[[package]] +name = "p3-challenger" +version = "0.1.4-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3be7e4fbce4566a93091107eadfafa0b5374bd1ffd3e0f6b850da3ff72eb183f" +dependencies = [ + "p3-field", + "p3-maybe-rayon", + "p3-symmetric", + "p3-util", + "serde", + "tracing", +] + +[[package]] +name = "p3-commit" +version = "0.1.4-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a03eb0f99d68a712c41e658e9a7782a0705d4ffcfb6232a43bd3f1ef9591002" +dependencies = [ + "itertools 0.12.1", + "p3-challenger", + "p3-dft", + "p3-field", + "p3-matrix", + "p3-util", + "serde", +] + +[[package]] +name = "p3-dft" +version = "0.1.4-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1556de968523fbe5d804ab50600ea306fcceea3500cfd7601e40882480524664" +dependencies = [ + "p3-field", + "p3-matrix", + "p3-maybe-rayon", + "p3-util", + "tracing", +] + +[[package]] +name = "p3-field" +version = "0.1.4-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cec2af6e1ac47a2035af5165e668d64612c4b9ccabd06df37fc1fd381fdf8a71" +dependencies = [ + "itertools 0.12.1", + "num-bigint 0.4.6", + "num-traits", + "p3-util", + "rand 0.8.5", + "serde", +] + +[[package]] +name = "p3-fri" +version = "0.1.4-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f351ee9f9d4256455164565cd91e3e6d2487cc2a5355515fa2b6d479269188dd" +dependencies = [ + "itertools 0.12.1", + "p3-challenger", + "p3-commit", + "p3-dft", + "p3-field", + "p3-interpolation", + "p3-matrix", + "p3-maybe-rayon", + "p3-util", + "serde", + "tracing", +] + +[[package]] +name = "p3-interpolation" +version = "0.1.4-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d24d0f2907a374ebe4545fcff3120d6376d9630cf0bef30feedcfc5908ea2c37" +dependencies = [ + "p3-field", + "p3-matrix", + "p3-util", +] + +[[package]] +name = "p3-keccak-air" +version = "0.1.4-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e66badd47cedf6570e91a0cabc389b80dfd53ba1a6e9a45a3923fd54b86122ff" +dependencies = [ + "p3-air", + "p3-field", + "p3-matrix", + "p3-maybe-rayon", + "p3-util", + "tracing", +] + +[[package]] +name = "p3-matrix" +version = "0.1.4-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa272f3ae77ed8d73478aa7c89e712efb15bda3ff4aff10fadfe11a012cd5389" +dependencies = [ + "itertools 0.12.1", + "p3-field", + "p3-maybe-rayon", + "p3-util", + "rand 0.8.5", + "serde", + "tracing", +] + +[[package]] +name = "p3-maybe-rayon" +version = "0.1.4-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eecad6292021858f282d643d9d1284ab112a200494d589863a9c4080e578ef0" +dependencies = [ + "rayon", +] + +[[package]] +name = "p3-mds" +version = "0.1.4-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "716c4dbe68a02f1541eb09149d07b8663a3a5951b1864a31cd67ff3bb0826e57" +dependencies = [ + "itertools 0.12.1", + "p3-dft", + "p3-field", + "p3-matrix", + "p3-symmetric", + "p3-util", + "rand 0.8.5", +] + +[[package]] +name = "p3-merkle-tree" +version = "0.1.4-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad7ebab52a03c26025988663a135aed62f5084a2e2ea262176dc8748efb593e5" +dependencies = [ + "itertools 0.12.1", + "p3-commit", + "p3-field", + "p3-matrix", + "p3-maybe-rayon", + "p3-symmetric", + "p3-util", + "serde", + "tracing", +] + +[[package]] +name = "p3-poseidon2" +version = "0.1.4-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39c042efa15beab7a8c4d0ca9b9e4cbda7582be0c08e121e830fec45f082935b" +dependencies = [ + "gcd", + "p3-field", + "p3-mds", + "p3-symmetric", + "rand 0.8.5", + "serde", +] + +[[package]] +name = "p3-symmetric" +version = "0.1.4-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9896a831f5b688adc13f6fbe1dcf66ecfaa4622a500f81aa745610e777acb72" +dependencies = [ + "itertools 0.12.1", + "p3-field", + "serde", +] + +[[package]] +name = "p3-uni-stark" +version = "0.1.4-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8437ebcd060c8a5479898030b114a93da8a86eb4c2e5f313d9eeaaf40c6e6f61" +dependencies = [ + "itertools 0.12.1", + "p3-air", + "p3-challenger", + "p3-commit", + "p3-dft", + "p3-field", + "p3-matrix", + "p3-maybe-rayon", + "p3-util", + "serde", + "tracing", +] + +[[package]] +name = "p3-util" +version = "0.1.4-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dedb9d27ba47ac314c6fac4ca54e55c3e486c864d51ec5ba55dbe47b75121157" +dependencies = [ + "serde", +] + +[[package]] +name = "pairing" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "135590d8bdba2b31346f9cd1fb2a912329f5135e832a4f422942eb6ead8b6b3b" +dependencies = [ + "group 0.12.1", +] + +[[package]] +name = "parity-scale-codec" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be4817d39f3272f69c59fe05d0535ae6456c2dc2fa1ba02910296c7e0a5c590" +dependencies = [ + "arrayvec", + "bitvec", + "byte-slice-cast", + "impl-trait-for-tuples", + "parity-scale-codec-derive", + "rustversion", + "serde", +] + +[[package]] +name = "parity-scale-codec-derive" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8781a75c6205af67215f382092b6e0a4ff3734798523e69073d4bcd294ec767b" +dependencies = [ + "proc-macro-crate 3.2.0", + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "parking_lot" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" dependencies = [ @@ -4280,12 +5542,70 @@ dependencies = [ "regex", ] +[[package]] +name = "pasta_curves" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc65faf8e7313b4b1fbaa9f7ca917a0eed499a9663be71477f87993604341d8" +dependencies = [ + "blake2b_simd", + "ff 0.12.1", + "group 0.12.1", + "lazy_static", + "rand 0.8.5", + "static_assertions", + "subtle", +] + +[[package]] +name = "pasta_curves" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e57598f73cc7e1b2ac63c79c517b31a0877cd7c402cdcaa311b5208de7a095" +dependencies = [ + "blake2b_simd", + "ff 0.13.0", + "group 0.13.0", + "lazy_static", + "rand 0.8.5", + "static_assertions", + "subtle", +] + [[package]] name = "paste" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "pbkdf2" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" +dependencies = [ + "digest 0.10.7", + "hmac 0.12.1", +] + +[[package]] +name = "pem" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" +dependencies = [ + "base64 0.13.1", +] + [[package]] name = "pem" version = "3.0.4" @@ -4347,6 +5667,16 @@ dependencies = [ "sha2 0.10.8", ] +[[package]] +name = "pharos" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414" +dependencies = [ + "futures", + "rustc_version 0.4.1", +] + [[package]] name = "phf" version = "0.11.2" @@ -4385,6 +5715,26 @@ dependencies = [ "siphasher", ] +[[package]] +name = "pin-project" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + [[package]] name = "pin-project-lite" version = "0.2.15" @@ -4443,6 +5793,16 @@ dependencies = [ "zerocopy", ] +[[package]] +name = "prettyplease" +version = "0.2.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" +dependencies = [ + "proc-macro2", + "syn 2.0.89", +] + [[package]] name = "primitive-types" version = "0.12.2" @@ -4453,6 +5813,7 @@ dependencies = [ "impl-codec", "impl-rlp", "impl-serde", + "scale-info", "uint 0.9.5", ] @@ -4466,13 +5827,23 @@ dependencies = [ "uint 0.10.0", ] +[[package]] +name = "proc-macro-crate" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +dependencies = [ + "once_cell", + "toml_edit 0.19.15", +] + [[package]] name = "proc-macro-crate" version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ecf48c7ca261d60b74ab1a7b20da18bede46776b2e55535cb958eb595c5fa7b" dependencies = [ - "toml_edit", + "toml_edit 0.22.22", ] [[package]] @@ -4641,7 +6012,7 @@ dependencies = [ "bytes", "getrandom", "rand 0.8.5", - "ring", + "ring 0.17.8", "rustc-hash 2.0.0", "rustls", "rustls-pki-types", @@ -4775,6 +6146,15 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "rayon-scan" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f87cc11a0140b4b0da0ffc889885760c61b13672d80a908920b2c0df078fa14" +dependencies = [ + "rayon", +] + [[package]] name = "rdrand" version = "0.4.0" @@ -4877,24 +6257,20 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.9" +version = "0.11.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" dependencies = [ - "base64 0.22.1", + "base64 0.21.7", "bytes", "encoding_rs", - "futures-channel", "futures-core", "futures-util", - "h2", - "http", - "http-body", - "http-body-util", - "hyper", - "hyper-rustls", - "hyper-tls", - "hyper-util", + "h2 0.3.26", + "http 0.2.12", + "http-body 0.4.6", + "hyper 0.14.31", + "hyper-tls 0.5.0", "ipnet", "js-sys", "log", @@ -4903,34 +6279,93 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", - "quinn", - "rustls", - "rustls-pemfile", - "rustls-pki-types", + "rustls-pemfile 1.0.4", "serde", "serde_json", "serde_urlencoded", - "sync_wrapper 1.0.2", - "system-configuration", + "sync_wrapper 0.1.2", + "system-configuration 0.5.1", "tokio", "tokio-native-tls", - "tokio-rustls", - "tokio-util", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", - "wasm-streams", "web-sys", - "webpki-roots", - "windows-registry", + "winreg", ] [[package]] -name = "revm" -version = "9.0.0" +name = "reqwest" +version = "0.12.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a2c336f9921588e50871c00024feb51a521eca50ce6d01494bb9c50f837c8ed" +checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f" +dependencies = [ + "base64 0.22.1", + "bytes", + "encoding_rs", + "futures-channel", + "futures-core", + "futures-util", + "h2 0.4.7", + "http 1.1.0", + "http-body 1.0.1", + "http-body-util", + "hyper 1.5.1", + "hyper-rustls", + "hyper-tls 0.6.0", + "hyper-util", + "ipnet", + "js-sys", + "log", + "mime", + "native-tls", + "once_cell", + "percent-encoding", + "pin-project-lite", + "quinn", + "rustls", + "rustls-pemfile 2.2.0", + "rustls-pki-types", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper 1.0.2", + "system-configuration 0.6.1", + "tokio", + "tokio-native-tls", + "tokio-rustls", + "tokio-util", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", + "webpki-roots", + "windows-registry", +] + +[[package]] +name = "reqwest-middleware" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562ceb5a604d3f7c885a792d42c199fd8af239d0a51b2fa6a78aafa092452b04" +dependencies = [ + "anyhow", + "async-trait", + "http 1.1.0", + "reqwest 0.12.9", + "serde", + "thiserror 1.0.69", + "tower-service", +] + +[[package]] +name = "revm" +version = "9.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a2c336f9921588e50871c00024feb51a521eca50ce6d01494bb9c50f837c8ed" dependencies = [ "auto_impl", "cfg-if", @@ -4965,7 +6400,7 @@ dependencies = [ "alloy-primitives 0.8.14", "alloy-rpc-types-eth", "alloy-rpc-types-trace", - "alloy-sol-types", + "alloy-sol-types 0.8.14", "anstyle", "colorchoice", "revm 14.0.3", @@ -5091,6 +6526,21 @@ dependencies = [ "subtle", ] +[[package]] +name = "ring" +version = "0.16.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +dependencies = [ + "cc", + "libc", + "once_cell", + "spin 0.5.2", + "untrusted 0.7.1", + "web-sys", + "winapi", +] + [[package]] name = "ring" version = "0.17.8" @@ -5101,8 +6551,8 @@ dependencies = [ "cfg-if", "getrandom", "libc", - "spin", - "untrusted", + "spin 0.9.8", + "untrusted 0.9.0", "windows-sys 0.52.0", ] @@ -5313,7 +6763,7 @@ dependencies = [ "cfg-if", "cust", "digest 0.10.7", - "ff", + "ff 0.13.0", "hex", "hex-literal", "metal", @@ -5392,9 +6842,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" dependencies = [ "bytes", + "rlp-derive", "rustc-hex", ] +[[package]] +name = "rlp-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e33d7b2abe0c340d8797fe2907d3f20d3b5ea5908683618bfe80df7f621f672a" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "rrs-lib" version = "0.1.0" @@ -5405,6 +6867,17 @@ dependencies = [ "paste", ] +[[package]] +name = "rrs-succinct" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3372685893a9f67d18e98e792d690017287fd17379a83d798d958e517d380fa9" +dependencies = [ + "downcast-rs", + "num_enum 0.5.11", + "paste", +] + [[package]] name = "ruint" version = "1.12.3" @@ -5497,13 +6970,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "934b404430bb06b3fae2cba809eb45a1ab1aecd64491213d7c3301b88393f8d1" dependencies = [ "once_cell", - "ring", + "ring 0.17.8", "rustls-pki-types", "rustls-webpki", "subtle", "zeroize", ] +[[package]] +name = "rustls-pemfile" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +dependencies = [ + "base64 0.21.7", +] + [[package]] name = "rustls-pemfile" version = "2.2.0" @@ -5528,9 +7010,9 @@ version = "0.102.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64ca1bc8749bd4cf37b5ce386cc146580777b4e8572c7b97baf22c83f444bee9" dependencies = [ - "ring", + "ring 0.17.8", "rustls-pki-types", - "untrusted", + "untrusted 0.9.0", ] [[package]] @@ -5568,6 +7050,15 @@ version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +[[package]] +name = "salsa20" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" +dependencies = [ + "cipher", +] + [[package]] name = "same-file" version = "1.0.6" @@ -5577,6 +7068,39 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "scale-info" +version = "2.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "346a3b32eba2640d17a9cb5927056b08f3de90f65b72fe09402c2ad07d684d0b" +dependencies = [ + "cfg-if", + "derive_more 1.0.0", + "parity-scale-codec", + "scale-info-derive", +] + +[[package]] +name = "scale-info-derive" +version = "2.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6630024bf739e2179b91fb424b28898baf819414262c5d376677dbff1fe7ebf" +dependencies = [ + "proc-macro-crate 3.2.0", + "proc-macro2", + "quote", + "syn 2.0.89", +] + +[[package]] +name = "scc" +version = "2.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66b202022bb57c049555430e11fc22fea12909276a80a4c3d368da36ac1d88ed" +dependencies = [ + "sdd", +] + [[package]] name = "schannel" version = "0.1.27" @@ -5592,6 +7116,24 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "scrypt" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f9e24d2b632954ded8ab2ef9fea0a0c769ea56ea98bddbafbad22caeeadf45d" +dependencies = [ + "hmac 0.12.1", + "pbkdf2 0.11.0", + "salsa20", + "sha2 0.10.8", +] + +[[package]] +name = "sdd" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49c1eeaf4b6a87c7479688c6d52b9f1153cedd3c489300564f932b065c6eab95" + [[package]] name = "sealed" version = "0.5.0" @@ -5612,7 +7154,7 @@ checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" dependencies = [ "base16ct", "der", - "generic-array", + "generic-array 0.14.7", "pkcs8", "subtle", "zeroize", @@ -5687,6 +7229,18 @@ dependencies = [ "pest", ] +[[package]] +name = "send_wrapper" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0" + +[[package]] +name = "send_wrapper" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" + [[package]] name = "serde" version = "1.0.215" @@ -5781,6 +7335,31 @@ dependencies = [ "syn 2.0.89", ] +[[package]] +name = "serial_test" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b258109f244e1d6891bf1053a55d63a5cd4f8f4c30cf9a1280989f80e7a1fa9" +dependencies = [ + "futures", + "log", + "once_cell", + "parking_lot 0.12.3", + "scc", + "serial_test_derive", +] + +[[package]] +name = "serial_test_derive" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d69265a08751de7844521fd15003ae0a888e035773ba05695c5c759a6f89eef" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.89", +] + [[package]] name = "sha1" version = "0.10.6" @@ -5901,45 +7480,476 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" [[package]] -name = "slab" -version = "0.4.9" +name = "size" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fed904c7fb2856d868b92464fc8fa597fce366edea1a9cbfaa8cb5fe080bd6d" + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "slug" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "882a80f72ee45de3cc9a5afeb2da0331d58df69e4e7d8eeb5d3c7784ae67e724" +dependencies = [ + "deunicode", + "wasm-bindgen", +] + +[[package]] +name = "smallvec" +version = "1.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" + +[[package]] +name = "snap" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b6b67fb9a61334225b5b790716f609cd58395f895b3fe8b328786812a40bc3b" + +[[package]] +name = "snowbridge-amcl" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460a9ed63cdf03c1b9847e8a12a5f5ba19c4efd5869e4a737e05be25d7c427e5" +dependencies = [ + "parity-scale-codec", + "scale-info", +] + +[[package]] +name = "socket2" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "sp1-build" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e58e5f49cf1481363abb74b55104e215f3b6e58dc2adb748bde7a6e4ea61b51d" +dependencies = [ + "anyhow", + "cargo_metadata", + "chrono", + "clap 4.5.21", + "dirs 5.0.1", +] + +[[package]] +name = "sp1-core-executor" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8324d09601526d2ddfb796efb24996d3cc33ea8802bbd085bdefe93a4989b4dd" +dependencies = [ + "bincode", + "bytemuck", + "elf", + "enum-map", + "eyre", + "hashbrown 0.14.5", + "hex", + "itertools 0.13.0", + "log", + "nohash-hasher", + "num", + "p3-field", + "p3-maybe-rayon", + "rand 0.8.5", + "rrs-succinct", + "serde", + "sp1-curves", + "sp1-primitives", + "sp1-stark", + "strum", + "strum_macros", + "thiserror 1.0.69", + "tiny-keccak", + "tracing", + "typenum", + "vec_map", +] + +[[package]] +name = "sp1-core-machine" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357af5138c7a591d1a612d105d75c1c01cad0ed6cc383d1ae38b7254e85ea227" +dependencies = [ + "bincode", + "cfg-if", + "elliptic-curve", + "generic-array 1.1.1", + "hashbrown 0.14.5", + "hex", + "itertools 0.13.0", + "k256", + "log", + "num", + "num_cpus", + "p3-air", + "p3-baby-bear", + "p3-blake3", + "p3-challenger", + "p3-field", + "p3-keccak-air", + "p3-matrix", + "p3-maybe-rayon", + "p3-uni-stark", + "p3-util", + "rand 0.8.5", + "serde", + "size", + "snowbridge-amcl", + "sp1-core-executor", + "sp1-curves", + "sp1-derive", + "sp1-primitives", + "sp1-stark", + "static_assertions", + "strum", + "strum_macros", + "tempfile", + "thiserror 1.0.69", + "tracing", + "tracing-forest", + "tracing-subscriber 0.3.18", + "typenum", + "web-time", +] + +[[package]] +name = "sp1-cuda" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "553339106b2c30fe9faa32ac9cf03a4c9e6410bd6c4c1c740678f6dbb82f2fe5" +dependencies = [ + "bincode", + "ctrlc", + "prost", + "serde", + "sp1-core-machine", + "sp1-prover", + "tokio", + "tracing", + "twirp-rs", +] + +[[package]] +name = "sp1-curves" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd206bc1fc44b7a215be0ae17c9b79e25ecfc2774dcd4e3753c0a03dee784e" +dependencies = [ + "cfg-if", + "dashu", + "elliptic-curve", + "generic-array 1.1.1", + "itertools 0.13.0", + "k256", + "num", + "p3-field", + "serde", + "snowbridge-amcl", + "sp1-primitives", + "sp1-stark", + "typenum", +] + +[[package]] +name = "sp1-derive" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf59bbd55ee20f0decb602809aadc73f09defb6f6d27067acf16029e84191b4a" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "sp1-primitives" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d10c2078a5dfc5c3a632da1bc59b57a19dadc9c03968047d8ffb06c0f83b476" +dependencies = [ + "bincode", + "hex", + "lazy_static", + "num-bigint 0.4.6", + "p3-baby-bear", + "p3-field", + "p3-poseidon2", + "p3-symmetric", + "serde", + "sha2 0.10.8", +] + +[[package]] +name = "sp1-prover" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc363eda811717369513ca72abafbb5cdec0ed16cda12458ca5321e4167e97ff" +dependencies = [ + "anyhow", + "bincode", + "clap 4.5.21", + "dirs 5.0.1", + "eyre", + "itertools 0.13.0", + "lazy_static", + "lru", + "num-bigint 0.4.6", + "p3-baby-bear", + "p3-bn254-fr", + "p3-challenger", + "p3-commit", + "p3-field", + "p3-matrix", + "p3-symmetric", + "rayon", + "reqwest 0.11.27", + "serde", + "serde_json", + "serial_test", + "sp1-core-executor", + "sp1-core-machine", + "sp1-primitives", + "sp1-recursion-circuit", + "sp1-recursion-compiler", + "sp1-recursion-core", + "sp1-recursion-gnark-ffi", + "sp1-stark", + "subtle-encoding", + "tempfile", + "thiserror 1.0.69", + "tracing", + "tracing-subscriber 0.3.18", +] + +[[package]] +name = "sp1-recursion-circuit" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "108607ce729ab2fedb25f039284baaad022c5df242e0530c5b453e89cc8306a3" +dependencies = [ + "hashbrown 0.14.5", + "itertools 0.13.0", + "num-traits", + "p3-air", + "p3-baby-bear", + "p3-bn254-fr", + "p3-challenger", + "p3-commit", + "p3-dft", + "p3-field", + "p3-fri", + "p3-matrix", + "p3-symmetric", + "p3-util", + "rand 0.8.5", + "rayon", + "serde", + "sp1-core-executor", + "sp1-core-machine", + "sp1-derive", + "sp1-primitives", + "sp1-recursion-compiler", + "sp1-recursion-core", + "sp1-recursion-gnark-ffi", + "sp1-stark", + "tracing", +] + +[[package]] +name = "sp1-recursion-compiler" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673d2c66a48e6d17e1165b5ea38b59de5e80bf64fd45f17ebc9d75e67c4ff414" +dependencies = [ + "backtrace", + "itertools 0.13.0", + "p3-baby-bear", + "p3-bn254-fr", + "p3-field", + "p3-symmetric", + "serde", + "sp1-core-machine", + "sp1-primitives", + "sp1-recursion-core", + "sp1-recursion-derive", + "sp1-stark", + "tracing", + "vec_map", +] + +[[package]] +name = "sp1-recursion-core" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2fb84b20d8ffb922d4c05843406c458a6abef296bc31e68cf5eb64fa739c921" +dependencies = [ + "backtrace", + "ff 0.13.0", + "hashbrown 0.14.5", + "itertools 0.13.0", + "p3-air", + "p3-baby-bear", + "p3-bn254-fr", + "p3-challenger", + "p3-commit", + "p3-dft", + "p3-field", + "p3-fri", + "p3-matrix", + "p3-maybe-rayon", + "p3-merkle-tree", + "p3-poseidon2", + "p3-symmetric", + "p3-util", + "serde", + "sp1-core-machine", + "sp1-derive", + "sp1-primitives", + "sp1-stark", + "static_assertions", + "thiserror 1.0.69", + "tracing", + "vec_map", + "zkhash", +] + +[[package]] +name = "sp1-recursion-derive" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +checksum = "3125726165ff77fb2650ae031075ba747099a6e218e5c10f84ac2715545a2332" dependencies = [ - "autocfg", + "quote", + "syn 1.0.109", ] [[package]] -name = "slug" -version = "0.1.6" +name = "sp1-recursion-gnark-ffi" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "882a80f72ee45de3cc9a5afeb2da0331d58df69e4e7d8eeb5d3c7784ae67e724" +checksum = "a049cdff6b64bc1cd2bebdf494fd314bc4b45eff9058ea69dace55a0fa77e483" dependencies = [ - "deunicode", - "wasm-bindgen", + "anyhow", + "bincode", + "bindgen", + "cc", + "cfg-if", + "hex", + "log", + "num-bigint 0.4.6", + "p3-baby-bear", + "p3-field", + "p3-symmetric", + "serde", + "serde_json", + "sha2 0.10.8", + "sp1-core-machine", + "sp1-recursion-compiler", + "sp1-stark", + "tempfile", ] [[package]] -name = "smallvec" -version = "1.13.2" +name = "sp1-sdk" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +checksum = "ae8dfb448a10491096db03187af55b8334ac52303c280956d0782a9fe78dd814" +dependencies = [ + "alloy-sol-types 0.7.7", + "anyhow", + "async-trait", + "bincode", + "cfg-if", + "dirs 5.0.1", + "ethers", + "futures", + "hashbrown 0.14.5", + "hex", + "indicatif", + "itertools 0.13.0", + "log", + "p3-baby-bear", + "p3-field", + "p3-fri", + "prost", + "reqwest 0.12.9", + "reqwest-middleware", + "serde", + "sp1-core-executor", + "sp1-core-machine", + "sp1-cuda", + "sp1-primitives", + "sp1-prover", + "sp1-stark", + "strum", + "strum_macros", + "tempfile", + "thiserror 1.0.69", + "tokio", + "tracing", + "twirp-rs", + "vergen", +] [[package]] -name = "snap" -version = "1.1.1" +name = "sp1-stark" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b6b67fb9a61334225b5b790716f609cd58395f895b3fe8b328786812a40bc3b" +checksum = "a597ed68cd03f80d9cdb9f4b50924e3c890c35c39956f7e87dd2262b72b2d12b" +dependencies = [ + "arrayref", + "getrandom", + "hashbrown 0.14.5", + "itertools 0.13.0", + "num-traits", + "p3-air", + "p3-baby-bear", + "p3-challenger", + "p3-commit", + "p3-dft", + "p3-field", + "p3-fri", + "p3-matrix", + "p3-maybe-rayon", + "p3-merkle-tree", + "p3-poseidon2", + "p3-symmetric", + "p3-uni-stark", + "p3-util", + "rayon-scan", + "serde", + "sp1-derive", + "sp1-primitives", + "strum", + "strum_macros", + "sysinfo", + "thiserror 1.0.69", + "tracing", +] [[package]] -name = "socket2" -version = "0.5.8" +name = "spin" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" [[package]] name = "spin" @@ -6017,6 +8027,22 @@ name = "strum" version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck 0.5.0", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.89", +] [[package]] name = "substrate-bn" @@ -6037,6 +8063,15 @@ version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" +[[package]] +name = "subtle-encoding" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dcb1ed7b8330c5eed5441052651dd7a12c75e2ed88f2ec024ae1fa3a5e59945" +dependencies = [ + "zeroize", +] + [[package]] name = "syn" version = "1.0.109" @@ -6059,6 +8094,18 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "syn-solidity" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c837dc8852cb7074e46b444afb81783140dab12c58867b49fb3898fbafedf7ea" +dependencies = [ + "paste", + "proc-macro2", + "quote", + "syn 2.0.89", +] + [[package]] name = "syn-solidity" version = "0.8.14" @@ -6097,6 +8144,32 @@ dependencies = [ "syn 2.0.89", ] +[[package]] +name = "sysinfo" +version = "0.30.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a5b4ddaee55fb2bea2bf0e5000747e5f5c0de765e5a5ff87f4cd106439f4bb3" +dependencies = [ + "cfg-if", + "core-foundation-sys", + "libc", + "ntapi", + "once_cell", + "rayon", + "windows", +] + +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys 0.5.0", +] + [[package]] name = "system-configuration" version = "0.6.1" @@ -6105,7 +8178,17 @@ checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ "bitflags 2.6.0", "core-foundation", - "system-configuration-sys", + "system-configuration-sys 0.6.0", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", ] [[package]] @@ -6194,7 +8277,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" dependencies = [ - "unicode-width", + "unicode-width 0.1.14", ] [[package]] @@ -6264,7 +8347,9 @@ checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ "deranged", "itoa", + "libc", "num-conv", + "num_threads", "powerfmt", "serde", "time-core", @@ -6432,7 +8517,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit", + "toml_edit 0.22.22", ] [[package]] @@ -6444,6 +8529,17 @@ dependencies = [ "serde", ] +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap 2.6.0", + "toml_datetime", + "winnow 0.5.40", +] + [[package]] name = "toml_edit" version = "0.22.22" @@ -6454,7 +8550,7 @@ dependencies = [ "serde", "serde_spanned", "toml_datetime", - "winnow", + "winnow 0.6.20", ] [[package]] @@ -6518,6 +8614,29 @@ dependencies = [ "valuable", ] +[[package]] +name = "tracing-forest" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee40835db14ddd1e3ba414292272eddde9dad04d3d4b65509656414d1c42592f" +dependencies = [ + "ansi_term", + "smallvec", + "thiserror 1.0.69", + "tracing", + "tracing-subscriber 0.3.18", +] + +[[package]] +name = "tracing-futures" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" +dependencies = [ + "pin-project", + "tracing", +] + [[package]] name = "tracing-log" version = "0.2.0" @@ -6562,6 +8681,28 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "twirp-rs" +version = "0.13.0-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27dfcc06b8d9262bc2d4b8d1847c56af9971a52dd8a0076876de9db763227d0d" +dependencies = [ + "async-trait", + "axum", + "futures", + "http 1.1.0", + "http-body-util", + "hyper 1.5.1", + "prost", + "reqwest 0.12.9", + "serde", + "serde_json", + "thiserror 1.0.69", + "tokio", + "tower", + "url", +] + [[package]] name = "twox-hash" version = "1.6.3" @@ -6706,12 +8847,24 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" +[[package]] +name = "unicode-width" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" + [[package]] name = "unicode-xid" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + [[package]] name = "untrusted" version = "0.9.0" @@ -6747,6 +8900,16 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" +[[package]] +name = "uuid" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" +dependencies = [ + "getrandom", + "serde", +] + [[package]] name = "valuable" version = "0.1.0" @@ -6764,6 +8927,9 @@ name = "vec_map" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" +dependencies = [ + "serde", +] [[package]] name = "vek" @@ -6777,6 +8943,19 @@ dependencies = [ "rustc_version 0.4.1", ] +[[package]] +name = "vergen" +version = "8.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2990d9ea5967266ea0ccf413a4aa5c42a93dbcfda9cb49a97de6931726b12566" +dependencies = [ + "anyhow", + "cfg-if", + "git2", + "rustversion", + "time", +] + [[package]] name = "version_check" version = "0.9.5" @@ -6981,6 +9160,16 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e48a53791691ab099e5e2ad123536d0fff50652600abaf43bbf952894110d0be" +dependencies = [ + "windows-core", + "windows-targets 0.52.6", +] + [[package]] name = "windows-core" version = "0.52.0" @@ -7168,6 +9357,15 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "winnow" +version = "0.5.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + [[package]] name = "winnow" version = "0.6.20" @@ -7177,6 +9375,16 @@ dependencies = [ "memchr", ] +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + [[package]] name = "winsafe" version = "0.0.19" @@ -7195,6 +9403,25 @@ version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" +[[package]] +name = "ws_stream_wasm" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7999f5f4217fe3818726b66257a4475f71e74ffd190776ad053fa159e50737f5" +dependencies = [ + "async_io_stream", + "futures", + "js-sys", + "log", + "pharos", + "rustc_version 0.4.1", + "send_wrapper 0.6.0", + "thiserror 1.0.69", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "wyz" version = "0.5.1" @@ -7329,6 +9556,33 @@ dependencies = [ "zopfli", ] +[[package]] +name = "zkhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4352d1081da6922701401cdd4cbf29a2723feb4cfabb5771f6fee8e9276da1c7" +dependencies = [ + "ark-ff 0.4.2", + "ark-std 0.4.0", + "bitvec", + "blake2", + "bls12_381", + "byteorder", + "cfg-if", + "group 0.12.1", + "group 0.13.0", + "halo2", + "hex", + "jubjub", + "lazy_static", + "pasta_curves 0.5.1", + "rand 0.8.5", + "serde", + "sha2 0.10.8", + "sha3", + "subtle", +] + [[package]] name = "zkvm_interface" version = "0.1.0" @@ -7341,6 +9595,7 @@ dependencies = [ "risc0-build", "serde", "serde_with", + "sp1-build", "thiserror 1.0.69", ] diff --git a/Makefile b/Makefile index 0e2c1c071..3973f07ad 100644 --- a/Makefile +++ b/Makefile @@ -82,7 +82,7 @@ stop-localnet-silent: @kurtosis enclave stop $(ENCLAVE) >/dev/null 2>&1 || true @kurtosis enclave rm $(ENCLAVE) --force >/dev/null 2>&1 || true -HIVE_REVISION := f220e0c55fb222aaaffdf17d66aa0537cd16a67a +HIVE_REVISION := df7d5103d4ddc772307f9947be4ad1f20ce03ed0 # Shallow clones can't specify a single revision, but at least we avoid working # the whole history by making it shallow since a given date (one day before our # target revision). diff --git a/cmd/ef_tests/ethrex/test_runner.rs b/cmd/ef_tests/ethrex/test_runner.rs index 7d1d13f03..e8b461263 100644 --- a/cmd/ef_tests/ethrex/test_runner.rs +++ b/cmd/ef_tests/ethrex/test_runner.rs @@ -112,7 +112,7 @@ fn check_prestate_against_db(test_key: &str, test: &TestUnit, db: &Store) { /// Panics if any comparison fails /// Tests that previously failed the validation stage shouldn't be executed with this function. fn check_poststate_against_db(test_key: &str, test: &TestUnit, db: &Store) { - let latest_block_number = db.get_latest_block_number().unwrap().unwrap(); + let latest_block_number = db.get_latest_block_number().unwrap(); for (addr, account) in &test.post_state { let expected_account: CoreAccount = account.clone().into(); // Check info @@ -153,7 +153,7 @@ fn check_poststate_against_db(test_key: &str, test: &TestUnit, db: &Store) { } } // Check lastblockhash is in store - let last_block_number = db.get_latest_block_number().unwrap().unwrap(); + let last_block_number = db.get_latest_block_number().unwrap(); let last_block_hash = db .get_block_header(last_block_number) .unwrap() diff --git a/cmd/ef_tests/levm/deserialize.rs b/cmd/ef_tests/levm/deserialize.rs index 2e6a223a3..0a1c40611 100644 --- a/cmd/ef_tests/levm/deserialize.rs +++ b/cmd/ef_tests/levm/deserialize.rs @@ -131,6 +131,22 @@ where ) } +/// This serializes a hexadecimal string to u64 +pub fn deserialize_u64_safe<'de, D>(deserializer: D) -> Result +where + D: serde::Deserializer<'de>, +{ + u64::from_str_radix( + String::deserialize(deserializer)?.trim_start_matches("0x"), + 16, + ) + .map_err(|err| { + serde::de::Error::custom(format!( + "error parsing U64 when deserializing U64 safely: {err}" + )) + }) +} + pub fn deserialize_h256_vec_optional_safe<'de, D>( deserializer: D, ) -> Result>, D::Error> @@ -201,7 +217,22 @@ where .map(|s| { U256::from_str(s.trim_start_matches("0x:bigint ")).map_err(|err| { serde::de::Error::custom(format!( - "error parsing U256 when deserializing U256 safely: {err}" + "error parsing U256 when deserializing U256 vector safely: {err}" + )) + }) + }) + .collect() +} +pub fn deserialize_u64_vec_safe<'de, D>(deserializer: D) -> Result, D::Error> +where + D: serde::Deserializer<'de>, +{ + Vec::::deserialize(deserializer)? + .iter() + .map(|s| { + u64::from_str_radix(s.trim_start_matches("0x"), 16).map_err(|err| { + serde::de::Error::custom(format!( + "error parsing u64 when deserializing u64 vector safely: {err}" )) }) }) diff --git a/cmd/ef_tests/levm/parser.rs b/cmd/ef_tests/levm/parser.rs index 98943f114..d100c591f 100644 --- a/cmd/ef_tests/levm/parser.rs +++ b/cmd/ef_tests/levm/parser.rs @@ -20,6 +20,15 @@ pub enum EFTestParseError { FailedToParseTestFile(String), } +const IGNORED_TESTS: [&str; 6] = [ + "ValueOverflowParis.json", // Skip because of errors + "loopMul.json", // Skip because it takes too long to run + "dynamicAccountOverwriteEmpty_Paris.json", // Skip because it fails on REVM + "RevertInCreateInInitCreate2Paris.json", // Skip because it fails on REVM + "create2collisionStorageParis.json", // Skip because it fails on REVM + "InitCollisionParis.json", // Skip because it fails on REVM +]; + pub fn parse_ef_tests(opts: &EFTestRunnerOptions) -> Result, EFTestParseError> { let parsing_time = std::time::Instant::now(); let cargo_manifest_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")); @@ -87,11 +96,11 @@ pub fn parse_ef_test_dir( { continue; } - // Skip the ValueOverflowParis.json file because of errors, and loopMul.json because it takes too long to run. + // Skip ignored tests if test .path() .file_name() - .is_some_and(|name| name == "ValueOverflowParis.json" || name == "loopMul.json") + .is_some_and(|name| IGNORED_TESTS.contains(&name.to_str().unwrap_or(""))) { continue; } diff --git a/cmd/ef_tests/levm/runner/levm_runner.rs b/cmd/ef_tests/levm/runner/levm_runner.rs index 8036dbe00..fe361c141 100644 --- a/cmd/ef_tests/levm/runner/levm_runner.rs +++ b/cmd/ef_tests/levm/runner/levm_runner.rs @@ -94,7 +94,7 @@ pub fn prepare_vm_for_tx(vector: &TestVector, test: &EFTest) -> Result Result( let chain_spec = initial_state .chain_config() .map_err(|err| EFTestRunnerError::VMInitializationFailed(err.to_string()))?; + let block_env = RevmBlockEnv { number: RevmU256::from_limbs(test.env.current_number.0), coinbase: RevmAddress(test.env.current_coinbase.0.into()), timestamp: RevmU256::from_limbs(test.env.current_timestamp.0), - gas_limit: RevmU256::from_limbs(test.env.current_gas_limit.0), + gas_limit: RevmU256::from(test.env.current_gas_limit), basefee: RevmU256::from_limbs(test.env.current_base_fee.unwrap_or_default().0), difficulty: RevmU256::from_limbs(test.env.current_difficulty.0), prevrandao: test.env.current_random.map(|v| v.0.into()), @@ -137,7 +138,7 @@ pub fn prepare_revm_for_tx<'state>( let tx_env = RevmTxEnv { caller: tx.sender.0.into(), - gas_limit: tx.gas_limit.as_u64(), + gas_limit: tx.gas_limit, gas_price: RevmU256::from_limbs(effective_gas_price(test, tx)?.0), transact_to: match tx.to { TxKind::Call(to) => RevmTxKind::Call(to.0.into()), diff --git a/cmd/ef_tests/levm/types.rs b/cmd/ef_tests/levm/types.rs index e92d304df..a74805be1 100644 --- a/cmd/ef_tests/levm/types.rs +++ b/cmd/ef_tests/levm/types.rs @@ -4,6 +4,7 @@ use crate::{ deserialize_h256_vec_optional_safe, deserialize_hex_bytes, deserialize_hex_bytes_vec, deserialize_transaction_expected_exception, deserialize_u256_optional_safe, deserialize_u256_safe, deserialize_u256_valued_hashmap_safe, deserialize_u256_vec_safe, + deserialize_u64_safe, deserialize_u64_vec_safe, }, report::TestVector, }; @@ -61,7 +62,7 @@ impl From<&EFTest> for Genesis { }, coinbase: test.env.current_coinbase, difficulty: test.env.current_difficulty, - gas_limit: test.env.current_gas_limit.as_u64(), + gas_limit: test.env.current_gas_limit, mix_hash: test.env.current_random.unwrap_or_default(), timestamp: test.env.current_timestamp.as_u64(), base_fee_per_gas: test.env.current_base_fee.map(|v| v.as_u64()), @@ -99,8 +100,8 @@ pub struct EFTestEnv { pub current_difficulty: U256, #[serde(default, deserialize_with = "deserialize_u256_optional_safe")] pub current_excess_blob_gas: Option, - #[serde(deserialize_with = "deserialize_u256_safe")] - pub current_gas_limit: U256, + #[serde(deserialize_with = "deserialize_u64_safe")] + pub current_gas_limit: u64, #[serde(deserialize_with = "deserialize_u256_safe")] pub current_number: U256, pub current_random: Option, @@ -268,8 +269,8 @@ pub struct EFTestAccessListItem { pub struct EFTestRawTransaction { #[serde(deserialize_with = "deserialize_hex_bytes_vec")] pub data: Vec, - #[serde(deserialize_with = "deserialize_u256_vec_safe")] - pub gas_limit: Vec, + #[serde(deserialize_with = "deserialize_u64_vec_safe")] + pub gas_limit: Vec, #[serde(default, deserialize_with = "deserialize_u256_optional_safe")] pub gas_price: Option, #[serde(deserialize_with = "deserialize_u256_safe")] @@ -295,7 +296,7 @@ pub struct EFTestRawTransaction { #[serde(rename_all = "camelCase")] pub struct EFTestTransaction { pub data: Bytes, - pub gas_limit: U256, + pub gas_limit: u64, pub gas_price: Option, #[serde(deserialize_with = "deserialize_u256_safe")] pub nonce: U256, diff --git a/cmd/ethrex/Cargo.toml b/cmd/ethrex/Cargo.toml index 90d55fcd7..47e951aeb 100644 --- a/cmd/ethrex/Cargo.toml +++ b/cmd/ethrex/Cargo.toml @@ -13,7 +13,7 @@ ethrex-net.workspace = true ethrex-storage = { workspace = true, optional = true } ethrex-vm.workspace = true ethrex-rlp.workspace = true -ethrex-l2.workspace = true +ethrex-l2 = { workspace = true, optional = true } bytes.workspace = true hex.workspace = true @@ -46,5 +46,5 @@ dev = ["dep:ethrex-dev"] metrics = ["ethrex-blockchain/metrics"] libmdbx = ["dep:libmdbx", "ethrex-storage/libmdbx"] redb = ["dep:redb", "ethrex-storage/redb"] -l2 = ["ethrex-vm/l2"] +l2 = ["dep:ethrex-l2", "ethrex-vm/l2"] levm = ["ethrex-vm/levm", "ethrex-blockchain/levm"] diff --git a/cmd/ethrex/ethrex.rs b/cmd/ethrex/ethrex.rs index ffc429f15..047c6491b 100644 --- a/cmd/ethrex/ethrex.rs +++ b/cmd/ethrex/ethrex.rs @@ -229,7 +229,7 @@ async fn main() { let authrpc_jwtsecret = std::fs::read(authrpc_jwtsecret).expect("Failed to read JWT secret"); let head_block_hash = { - let current_block_number = store.get_latest_block_number().unwrap().unwrap(); + let current_block_number = store.get_latest_block_number().unwrap(); store.get_canonical_block_hash(current_block_number).unwrap().unwrap() }; let max_tries = 3; diff --git a/cmd/ethrex_l2/src/commands/prove.rs b/cmd/ethrex_l2/src/commands/prove.rs index 9a6480c78..12fa233f7 100644 --- a/cmd/ethrex_l2/src/commands/prove.rs +++ b/cmd/ethrex_l2/src/commands/prove.rs @@ -1,6 +1,6 @@ use clap::Args; use ethrex_l2::utils::test_data_io::{generate_program_input, read_chain_file, read_genesis_file}; -use ethrex_prover_lib::prover::Prover; +use ethrex_prover_lib::prover::create_prover; #[derive(Args)] pub(crate) struct Command { @@ -30,7 +30,7 @@ impl Command { let chain = read_chain_file(&self.chain); let program_input = generate_program_input(genesis, chain, self.block_number)?; - let mut prover = Prover::new(); + let mut prover = create_prover(ethrex_l2::proposer::prover_server::ProverType::RISC0); prover.prove(program_input).expect("proving failed"); println!( "Total gas consumption: {}", diff --git a/cmd/ethrex_l2/src/commands/stack.rs b/cmd/ethrex_l2/src/commands/stack.rs index 567708e02..ed7428194 100644 --- a/cmd/ethrex_l2/src/commands/stack.rs +++ b/cmd/ethrex_l2/src/commands/stack.rs @@ -291,7 +291,7 @@ async fn start_l2(root: PathBuf, l2_rpc_url: &str, start_prover: bool) -> eyre:: .arg("run") .arg("--release") .arg("--features") - .arg("build_zkvm") + .arg("build_risc0") .arg("--bin") .arg("ethrex_prover") .current_dir(root_clone) diff --git a/crates/blockchain/blockchain.rs b/crates/blockchain/blockchain.rs index 451d2a949..db46937a3 100644 --- a/crates/blockchain/blockchain.rs +++ b/crates/blockchain/blockchain.rs @@ -161,11 +161,10 @@ pub fn validate_receipts_root( // Returns the hash of the head of the canonical chain (the latest valid hash). pub fn latest_canonical_block_hash(storage: &Store) -> Result { - if let Some(latest_block_number) = storage.get_latest_block_number()? { - if let Some(latest_valid_header) = storage.get_block_header(latest_block_number)? { - let latest_valid_hash = latest_valid_header.compute_block_hash(); - return Ok(latest_valid_hash); - } + let latest_block_number = storage.get_latest_block_number()?; + if let Some(latest_valid_header) = storage.get_block_header(latest_block_number)? { + let latest_valid_hash = latest_valid_header.compute_block_hash(); + return Ok(latest_valid_hash); } Err(ChainError::StoreError(StoreError::Custom( "Could not find latest valid hash".to_string(), diff --git a/crates/blockchain/fork_choice.rs b/crates/blockchain/fork_choice.rs index 46ba0ed95..43974953d 100644 --- a/crates/blockchain/fork_choice.rs +++ b/crates/blockchain/fork_choice.rs @@ -65,10 +65,7 @@ pub fn apply_fork_choice( total_difficulty_check(&head_hash, &head, store)?; - // TODO(#791): should we panic here? We should never not have a latest block number. - let Some(latest) = store.get_latest_block_number()? else { - return Err(StoreError::Custom("Latest block number not found".to_string()).into()); - }; + let latest = store.get_latest_block_number()?; // If the head block is an already present head ancestor, skip the update. if is_canonical(store, head.number, head_hash)? && head.number < latest { @@ -192,11 +189,7 @@ fn find_link_with_canonical_chain( return Ok(Some(branch)); } - let Some(genesis_number) = store.get_earliest_block_number()? else { - return Err(StoreError::Custom( - "Earliest block number not found. Node setup must have been faulty.".to_string(), - )); - }; + let genesis_number = store.get_earliest_block_number()?; while block_number > genesis_number { block_number -= 1; diff --git a/crates/blockchain/mempool.rs b/crates/blockchain/mempool.rs index 9680f37b2..ffc4aaf9f 100644 --- a/crates/blockchain/mempool.rs +++ b/crates/blockchain/mempool.rs @@ -173,9 +173,7 @@ fn validate_transaction( ) -> Result<(), MempoolError> { // TODO: Add validations here - let header_no = store - .get_latest_block_number()? - .ok_or(MempoolError::NoBlockHeaderError)?; + let header_no = store.get_latest_block_number()?; let header = store .get_block_header(header_no)? .ok_or(MempoolError::NoBlockHeaderError)?; diff --git a/crates/blockchain/smoke_test.rs b/crates/blockchain/smoke_test.rs index 710720cfc..d49ce27df 100644 --- a/crates/blockchain/smoke_test.rs +++ b/crates/blockchain/smoke_test.rs @@ -186,7 +186,7 @@ mod blockchain_integration_test { // Important blocks should still be the same as before. assert!(store.get_finalized_block_number().unwrap() == Some(0)); assert!(store.get_safe_block_number().unwrap() == Some(0)); - assert!(store.get_latest_block_number().unwrap() == Some(2)); + assert!(store.get_latest_block_number().unwrap() == 2); } #[test] diff --git a/crates/common/rlp/decode.rs b/crates/common/rlp/decode.rs index 6418e693a..348999ff4 100644 --- a/crates/common/rlp/decode.rs +++ b/crates/common/rlp/decode.rs @@ -492,10 +492,10 @@ pub fn is_encoded_as_bytes(rlp: &[u8]) -> Result { } /// Receives an RLP bytes item (prefix between 0xb8 and 0xbf) and returns its payload -pub fn get_rlp_bytes_item_payload(rlp: &[u8]) -> &[u8] { - let prefix = rlp.first().unwrap(); +pub fn get_rlp_bytes_item_payload(rlp: &[u8]) -> Result<&[u8], RLPDecodeError> { + let prefix = rlp.first().ok_or(RLPDecodeError::InvalidLength)?; let offset: usize = (prefix - 0xb8 + 1).into(); - &rlp[offset + 1..] + rlp.get(offset + 1..).ok_or(RLPDecodeError::InvalidLength) } /// Decodes the payload of an RLP item from a slice of bytes. diff --git a/crates/common/types/block.rs b/crates/common/types/block.rs index 2f817d3ee..fb4b3eaf9 100644 --- a/crates/common/types/block.rs +++ b/crates/common/types/block.rs @@ -241,7 +241,7 @@ pub fn compute_receipts_root(receipts: &[Receipt]) -> H256 { let iter = receipts .iter() .enumerate() - .map(|(idx, receipt)| (idx.encode_to_vec(), receipt.encode_to_vec())); + .map(|(idx, receipt)| (idx.encode_to_vec(), receipt.encode_inner())); Trie::compute_hash_from_unsorted_iter(iter) } diff --git a/crates/common/types/receipt.rs b/crates/common/types/receipt.rs index e0e888244..31ae45652 100644 --- a/crates/common/types/receipt.rs +++ b/crates/common/types/receipt.rs @@ -1,14 +1,14 @@ use bytes::Bytes; use ethereum_types::{Address, Bloom, BloomInput, H256}; use ethrex_rlp::{ - decode::RLPDecode, + decode::{get_rlp_bytes_item_payload, is_encoded_as_bytes, RLPDecode}, encode::RLPEncode, error::RLPDecodeError, structs::{Decoder, Encoder}, }; use serde::{Deserialize, Serialize}; -use super::TxType; +use crate::types::TxType; pub type Index = u64; /// Result of a transaction @@ -31,6 +31,79 @@ impl Receipt { logs, } } + // By reading the typed transactions EIP, and some geth code: + // - https://eips.ethereum.org/EIPS/eip-2718 + // - https://github.com/ethereum/go-ethereum/blob/330190e476e2a2de4aac712551629a4134f802d5/core/types/receipt.go#L143 + // We've noticed the are some subtleties around encoding receipts and transactions. + // First, `encode_inner` will encode a receipt according + // to the RLP of its fields, if typed, the RLP of the fields + // is padded with the byte representing this type. + // For P2P messages, receipts are re-encoded as bytes + // (see the `encode` implementation for receipt). + // For debug and computing receipt roots, the expected + // RLP encodings are the ones returned by `encode_inner`. + // On some documentations, this is also called the `consensus-encoding` + // for a receipt. + + /// Encodes Receipts in the following formats: + /// A) Legacy receipts: rlp(receipt) + /// B) Non legacy receipts: tx_type | rlp(receipt). + pub fn encode_inner(&self) -> Vec { + let mut encode_buff = match self.tx_type { + TxType::Legacy => { + vec![] + } + _ => { + vec![self.tx_type as u8] + } + }; + Encoder::new(&mut encode_buff) + .encode_field(&self.succeeded) + .encode_field(&self.cumulative_gas_used) + .encode_field(&self.bloom) + .encode_field(&self.logs) + .finish(); + encode_buff + } + + /// Decodes Receipts in the following formats: + /// A) Legacy receipts: rlp(receipt) + /// B) Non legacy receipts: tx_type | rlp(receipt). + pub fn decode_inner(rlp: &[u8]) -> Result { + // Obtain TxType + let (tx_type, rlp) = match rlp.first() { + Some(tx_type) if *tx_type < 0x7f => { + let tx_type = match tx_type { + 0x0 => TxType::Legacy, + 0x1 => TxType::EIP2930, + 0x2 => TxType::EIP1559, + 0x3 => TxType::EIP4844, + 0x7e => TxType::Privileged, + ty => { + return Err(RLPDecodeError::Custom(format!( + "Invalid transaction type: {ty}" + ))) + } + }; + (tx_type, &rlp[1..]) + } + _ => (TxType::Legacy, rlp), + }; + let decoder = Decoder::new(rlp)?; + let (succeeded, decoder) = decoder.decode_field("succeeded")?; + let (cumulative_gas_used, decoder) = decoder.decode_field("cumulative_gas_used")?; + let (bloom, decoder) = decoder.decode_field("bloom")?; + let (logs, decoder) = decoder.decode_field("logs")?; + decoder.finish()?; + + Ok(Receipt { + tx_type, + succeeded, + cumulative_gas_used, + bloom, + logs, + }) + } } fn bloom_from_logs(logs: &[Log]) -> Bloom { @@ -45,55 +118,64 @@ fn bloom_from_logs(logs: &[Log]) -> Bloom { } impl RLPEncode for Receipt { + /// Receipts can be encoded in the following formats: + /// A) Legacy receipts: rlp(receipt) + /// B) Non legacy receipts: rlp(Bytes(tx_type | rlp(receipt))). fn encode(&self, buf: &mut dyn bytes::BufMut) { - // tx_type || RLP(receipt) if tx_type != 0 - // RLP(receipt) else match self.tx_type { - TxType::Legacy => {} - _ => buf.put_u8(self.tx_type as u8), - } - Encoder::new(buf) - .encode_field(&self.succeeded) - .encode_field(&self.cumulative_gas_used) - .encode_field(&self.bloom) - .encode_field(&self.logs) - .finish(); + TxType::Legacy => { + let legacy_encoded = self.encode_inner(); + buf.put_slice(&legacy_encoded); + } + _ => { + let typed_recepipt_encoded = self.encode_inner(); + let bytes = Bytes::from(typed_recepipt_encoded); + bytes.encode(buf); + } + }; } } impl RLPDecode for Receipt { + /// Receipts can be encoded in the following formats: + /// A) Legacy receipts: rlp(receipt) + /// B) Non legacy receipts: rlp(Bytes(tx_type | rlp(receipt))). fn decode_unfinished(rlp: &[u8]) -> Result<(Self, &[u8]), RLPDecodeError> { - // Decode tx type - let (tx_type, rlp) = match rlp.first() { - Some(tx_type) if *tx_type < 0x7f => match tx_type { - 0x0 => (TxType::Legacy, &rlp[1..]), - 0x1 => (TxType::EIP2930, &rlp[1..]), - 0x2 => (TxType::EIP1559, &rlp[1..]), - 0x3 => (TxType::EIP4844, &rlp[1..]), - 0x7e => (TxType::Privileged, &rlp[1..]), + let (tx_type, rlp) = if is_encoded_as_bytes(rlp)? { + let payload = get_rlp_bytes_item_payload(rlp)?; + let tx_type = match payload.first().ok_or(RLPDecodeError::InvalidLength)? { + 0x0 => TxType::Legacy, + 0x1 => TxType::EIP2930, + 0x2 => TxType::EIP1559, + 0x3 => TxType::EIP4844, + 0x7e => TxType::Privileged, ty => { return Err(RLPDecodeError::Custom(format!( "Invalid transaction type: {ty}" ))) } - }, - // Legacy Tx - _ => (TxType::Legacy, rlp), + }; + (tx_type, &payload[1..]) + } else { + (TxType::Legacy, rlp) }; - // Decode the remaining fields + let decoder = Decoder::new(rlp)?; let (succeeded, decoder) = decoder.decode_field("succeeded")?; let (cumulative_gas_used, decoder) = decoder.decode_field("cumulative_gas_used")?; let (bloom, decoder) = decoder.decode_field("bloom")?; let (logs, decoder) = decoder.decode_field("logs")?; - let receipt = Receipt { - tx_type, - succeeded, - cumulative_gas_used, - bloom, - logs, - }; - Ok((receipt, decoder.finish()?)) + + Ok(( + Receipt { + tx_type, + succeeded, + cumulative_gas_used, + bloom, + logs, + }, + decoder.finish()?, + )) } } @@ -129,3 +211,76 @@ impl RLPDecode for Log { Ok((log, decoder.finish()?)) } } + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_encode_decode_receipt_legacy() { + let receipt = Receipt { + tx_type: TxType::Legacy, + succeeded: true, + cumulative_gas_used: 1200, + bloom: Bloom::random(), + logs: vec![Log { + address: Address::random(), + topics: vec![], + data: Bytes::from_static(b"foo"), + }], + }; + let encoded_receipt = receipt.encode_to_vec(); + assert_eq!(receipt, Receipt::decode(&encoded_receipt).unwrap()) + } + + #[test] + fn test_encode_decode_receipt_non_legacy() { + let receipt = Receipt { + tx_type: TxType::EIP4844, + succeeded: true, + cumulative_gas_used: 1500, + bloom: Bloom::random(), + logs: vec![Log { + address: Address::random(), + topics: vec![], + data: Bytes::from_static(b"bar"), + }], + }; + let encoded_receipt = receipt.encode_to_vec(); + assert_eq!(receipt, Receipt::decode(&encoded_receipt).unwrap()) + } + + #[test] + fn test_encode_decode_inner_receipt_legacy() { + let receipt = Receipt { + tx_type: TxType::Legacy, + succeeded: true, + cumulative_gas_used: 1200, + bloom: Bloom::random(), + logs: vec![Log { + address: Address::random(), + topics: vec![], + data: Bytes::from_static(b"foo"), + }], + }; + let encoded_receipt = receipt.encode_inner(); + assert_eq!(receipt, Receipt::decode_inner(&encoded_receipt).unwrap()) + } + + #[test] + fn test_encode_decode_receipt_inner_non_legacy() { + let receipt = Receipt { + tx_type: TxType::EIP4844, + succeeded: true, + cumulative_gas_used: 1500, + bloom: Bloom::random(), + logs: vec![Log { + address: Address::random(), + topics: vec![], + data: Bytes::from_static(b"bar"), + }], + }; + let encoded_receipt = receipt.encode_inner(); + assert_eq!(receipt, Receipt::decode_inner(&encoded_receipt).unwrap()) + } +} diff --git a/crates/common/types/transaction.rs b/crates/common/types/transaction.rs index bfa64df91..ca7abac91 100644 --- a/crates/common/types/transaction.rs +++ b/crates/common/types/transaction.rs @@ -230,9 +230,9 @@ impl RLPDecode for Transaction { fn decode_unfinished(rlp: &[u8]) -> Result<(Self, &[u8]), RLPDecodeError> { if is_encoded_as_bytes(rlp)? { // Adjust the encoding to get the payload - let payload = get_rlp_bytes_item_payload(rlp); - let tx_type = payload.first().unwrap(); - let tx_encoding = &payload[1..]; + let payload = get_rlp_bytes_item_payload(rlp)?; + let tx_type = payload.first().ok_or(RLPDecodeError::InvalidLength)?; + let tx_encoding = &payload.get(1..).ok_or(RLPDecodeError::InvalidLength)?; // Look at the first byte to check if it corresponds to a TransactionType match *tx_type { // Legacy diff --git a/crates/l2/.env.example b/crates/l2/.env.example index dfa93718b..0912ba1c4 100644 --- a/crates/l2/.env.example +++ b/crates/l2/.env.example @@ -1,11 +1,16 @@ ETH_RPC_URL=http://localhost:8545 # If set to 0xAA skip proof verification. # Only use in dev mode. -DEPLOYER_CONTRACT_VERIFIER=0x00000000000000000000000000000000000000AA -# Risc0Groth16Verifier Sepolia Address -# DEPLOYER_CONTRACT_VERIFIER=0xd9b0d07CeCd808a8172F21fA7C97992168f045CA -# Risc0Groth16Verifier Holesky Address -# DEPLOYER_CONTRACT_VERIFIER=0x44c220f0598345195cE99AD6A57aDfFcb9Ea33e7 +DEPLOYER_RISC0_CONTRACT_VERIFIER=0x00000000000000000000000000000000000000AA +# Risc0Groth16Verifier Address +# DEPLOYER_RISC0_CONTRACT_VERIFIER=0xAC292cF957Dd5BA174cdA13b05C16aFC71700327 +# If set to 0xAA skip proof verification. +# Only use in dev mode. +DEPLOYER_SP1_CONTRACT_VERIFIER=0x00000000000000000000000000000000000000AA +# SP1Groth16Verifier Address +# DEPLOYER_SP1_CONTRACT_VERIFIER=0x397A5f7f3dBd538f23DE225B51f532c34448dA9B +# If DEPLOYER_SP1_CONTRACT_VERIFIER was already deployed, set to false +DEPLOYER_SP1_DEPLOY_VERIFIER=false DEPLOYER_ADDRESS=0x3d1e15a1a55578f7c920884a9943b3b35d0d885b DEPLOYER_PRIVATE_KEY=0x385c546456b6a603a1cfcaa9ec9494ba4832da08dd6bcf4de9a71e4a01b74924 # If set to false, the salt will be randomized. @@ -38,3 +43,6 @@ PROPOSER_COINBASE_ADDRESS=0x0007a881CD95B1484fca47615B64803dad620C8d # 1/true means fake proofs # The RISC0_DEV_MODE=1 should only be used with DEPLOYER_CONTRACT_VERIFIER=0xAA RISC0_DEV_MODE=1 +# mock means fake proofs +# local means real proofs +SP1_PROVER=mock diff --git a/crates/l2/Cargo.toml b/crates/l2/Cargo.toml index 95d57fd95..8bdd28b00 100644 --- a/crates/l2/Cargo.toml +++ b/crates/l2/Cargo.toml @@ -30,6 +30,8 @@ thiserror.workspace = true zkvm_interface = { path = "./prover/zkvm/interface/", default-features = false } # risc0 risc0-zkvm = { version = "1.2.0" } +# sp1 +sp1-sdk = { version = "3.4.0" } [dev-dependencies] ethrex-sdk = { path = "./sdk" } diff --git a/crates/l2/Makefile b/crates/l2/Makefile index d0b14bdc7..657ec44da 100644 --- a/crates/l2/Makefile +++ b/crates/l2/Makefile @@ -1,10 +1,11 @@ .DEFAULT_GOAL := help -.PHONY: help init down clean init-local-l1 down-local-l1 clean-local-l1 init-l2 down-l2 deploy-l1 deploy-block-executor deploy-inbox setup-prover test ci_test update-cli-contracts - L2_GENESIS_FILE_PATH=../../test_data/genesis-l2.json L1_GENESIS_FILE_PATH=../../test_data/genesis-l1.json +# Basic +.PHONY: help init down clean restart + help: ## 📚 Show help for each of the Makefile recipes @grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' @@ -16,9 +17,22 @@ clean: clean-contract-deps ## 🧹 Cleans the localnet restart: restart-local-l1 deploy-l1 restart-l2 ## 🔄 Restarts the localnet +# CLI +.PHONY: cli update-cli-contracts + cli: ## 🛠️ Installs the L2 Lambda ethrex CLI cargo install --path ${ethrex_PATH}/cmd/ethrex_l2/ --force +update-cli-contracts: ## 📜 Update the CLI's config contracts + @if [ -z "$$C" ]; then \ + echo "Error: CONFIG_NAME (C) is missing.\nPlease provide it as an argument:\nmake update-cli-contracts C=."; \ + exit 1; \ + fi && \ + CB=$$(grep 'L1_WATCHER_BRIDGE_ADDRESS' .env | cut -d= -f2) && \ + ethrex_l2 config edit --common-bridge $$CB $$C && \ + OP=$$(grep 'COMMITTER_ON_CHAIN_PROPOSER_ADDRESS' .env | cut -d= -f2) && \ + ethrex_l2 config edit --on-chain-proposer $$OP $$C + # Variables ethrex_PATH=$(shell pwd)/../.. @@ -46,6 +60,7 @@ L2_AUTH_PORT=8552 L2_PROMETHEUS_METRICS_PORT = 3702 # Local L1 +.PHONY: init-local-l1 init-l1 down-local-l1 restart-local-l1 rm-db-l1 init-local-l1: ## 🚀 Initializes an L1 Lambda ethrex Client with Docker (Used with make init) docker compose -f ${ethrex_DEV_DOCKER_COMPOSE_PATH} -f ${ethrex_METRICS_OVERRIDES_L1_DOCKER_COMPOSE_PATH} up -d @@ -64,10 +79,11 @@ down-local-l1: ## 🛑 Shuts down the L1 Lambda ethrex Client restart-local-l1: down-local-l1 init-local-l1 ## 🔄 Restarts the L1 Lambda ethrex Client -rm_db_l1: ## 🛑 Removes the DB used by the L1 +rm-db-l1: ## 🛑 Removes the DB used by the L1 cargo run --release --manifest-path ../../Cargo.toml --bin ethrex -- removedb --datadir ${ethrex_L1_DEV_LIBMDBX} # Contracts +PHONY: clean-contract-deps restart-contract-deps deploy-l1 clean-contract-deps: ## 🧹 Cleans the dependencies for the L1 contracts. rm -rf contracts/solc_out @@ -79,6 +95,7 @@ deploy-l1: ## 📜 Deploys the L1 contracts DEPLOYER_CONTRACTS_PATH=contracts cargo run --release --bin ethrex_l2_l1_deployer --manifest-path ${ethrex_L2_CONTRACTS_PATH}/Cargo.toml # L2 +PHONY: init-l2 down-l2 restart-l2 init-prover rm-db-l2 init-l2: init-metrics ## 🚀 Initializes an L2 Lambda ethrex Client cargo run --release --manifest-path ../../Cargo.toml --bin ethrex --features "l2,metrics" -- \ @@ -100,26 +117,27 @@ down-l2: ## 🛑 Shuts down the L2 Lambda ethrex Client restart-l2: down-l2 init-l2 ## 🔄 Restarts the L2 Lambda ethrex Client -init-l2-prover: ## 🚀 Initializes the Prover - cargo run --release --features build_zkvm --manifest-path ../../Cargo.toml --bin ethrex_prover +init-prover: ## 🚀 Initializes the Prover + @if [ -z "$$T" ]; then \ + echo "Error: ProverType (T) is missing."; \ + echo "Please provide it as an argument:"; \ + echo "make init-prover T= ."; \ + echo "The prover can also be run with GPU (G)"; \ + exit 1; \ + fi; \ -init-l2-prover-gpu: ## 🚀 Initializes the Prover with GPU support - cargo run --release --features "build_zkvm,gpu" --manifest-path ../../Cargo.toml --bin ethrex_prover + @if [ -z "$$G" ]; then \ + GPU=""; \ + else \ + GPU=",gpu"; \ + fi; \ + cargo run --release --features "build_$$T$$GPU" --manifest-path ../../Cargo.toml --bin ethrex_prover -- $$T -rm_db_l2: ## 🛑 Removes the DB used by the L2 +rm-db-l2: ## 🛑 Removes the DB used by the L2 cargo run --release --manifest-path ../../Cargo.toml --bin ethrex -- removedb --datadir ${ethrex_L2_DEV_LIBMDBX} -update-cli-contracts: ## 📜 Update the CLI's config contracts - @if [ -z "$$C" ]; then \ - echo "Error: CONFIG_NAME (C) is missing.\nPlease provide it as an argument:\nmake update-cli-contracts C=."; \ - exit 1; \ - fi && \ - CB=$$(grep 'L1_WATCHER_BRIDGE_ADDRESS' .env | cut -d= -f2) && \ - ethrex_l2 config edit --common-bridge $$CB $$C && \ - OP=$$(grep 'COMMITTER_ON_CHAIN_PROPOSER_ADDRESS' .env | cut -d= -f2) && \ - ethrex_l2 config edit --on-chain-proposer $$OP $$C - # Testing +PHONY: ci_test test ci_test: ## 🚧 Runs the L2's integration test, used by the github's CI docker compose -f ${ethrex_L2_DOCKER_COMPOSE_PATH} down diff --git a/crates/l2/contracts/deployer.rs b/crates/l2/contracts/deployer.rs index 80d94d753..6e1358b0c 100644 --- a/crates/l2/contracts/deployer.rs +++ b/crates/l2/contracts/deployer.rs @@ -22,9 +22,11 @@ struct SetupResult { deployer_private_key: SecretKey, committer_address: Address, verifier_address: Address, - contract_verifier_address: Address, + risc0_contract_verifier_address: Address, eth_client: EthClient, contracts_path: PathBuf, + sp1_contract_verifier_address: Address, + sp1_deploy_verifier_on_l1: bool, } #[derive(Debug, thiserror::Error)] @@ -65,14 +67,20 @@ async fn main() -> Result<(), DeployError> { download_contract_deps(&setup_result.contracts_path)?; compile_contracts(&setup_result.contracts_path)?; - let (on_chain_proposer, bridge_address) = deploy_contracts( + let (on_chain_proposer, bridge_address, sp1_verifier_address) = deploy_contracts( setup_result.deployer_address, setup_result.deployer_private_key, &setup_result.eth_client, &setup_result.contracts_path, + setup_result.sp1_deploy_verifier_on_l1, ) .await?; + let sp1_contract_verifier_address = match sp1_verifier_address { + Some(address) => address, + None => setup_result.sp1_contract_verifier_address, + }; + initialize_contracts( setup_result.deployer_address, setup_result.deployer_private_key, @@ -80,7 +88,8 @@ async fn main() -> Result<(), DeployError> { setup_result.verifier_address, on_chain_proposer, bridge_address, - setup_result.contract_verifier_address, + setup_result.risc0_contract_verifier_address, + sp1_contract_verifier_address, &setup_result.eth_client, ) .await?; @@ -99,6 +108,9 @@ async fn main() -> Result<(), DeployError> { "L1_WATCHER_BRIDGE_ADDRESS" => { format!("{envar}={bridge_address:#x}") } + "DEPLOYER_SP1_CONTRACT_VERIFIER" => { + format!("{envar}={sp1_contract_verifier_address:#x}") + } _ => line, }; } @@ -162,15 +174,30 @@ fn setup() -> Result { ))); } }; - let contract_verifier_address = parse_env_var("DEPLOYER_CONTRACT_VERIFIER")?; + let risc0_contract_verifier_address = parse_env_var("DEPLOYER_RISC0_CONTRACT_VERIFIER")?; + + let input = std::env::var("DEPLOYER_SP1_DEPLOY_VERIFIER").unwrap_or("false".to_owned()); + let sp1_deploy_verifier_on_l1 = match input.trim().to_lowercase().as_str() { + "true" | "1" => true, + "false" | "0" => false, + _ => { + return Err(DeployError::ParseError(format!( + "Invalid boolean string: {input}" + ))); + } + }; + let sp1_contract_verifier_address = parse_env_var("DEPLOYER_SP1_CONTRACT_VERIFIER")?; + Ok(SetupResult { deployer_address, deployer_private_key, committer_address, verifier_address, - contract_verifier_address, + risc0_contract_verifier_address, eth_client, contracts_path, + sp1_deploy_verifier_on_l1, + sp1_contract_verifier_address, }) } @@ -201,6 +228,20 @@ fn download_contract_deps(contracts_path: &Path) -> Result<(), DeployError> { .map_err(|err| DeployError::DependencyError(format!("Failed to spawn git: {err}")))? .wait() .map_err(|err| DeployError::DependencyError(format!("Failed to wait for git: {err}")))?; + + Command::new("git") + .arg("clone") + .arg("https://github.com/succinctlabs/sp1-contracts.git") + .arg( + contracts_path + .join("lib/sp1-contracts") + .to_str() + .ok_or(DeployError::FailedToGetStringFromPath)?, + ) + .spawn() + .map_err(|err| DeployError::DependencyError(format!("Failed to spawn git: {err}")))? + .wait() + .map_err(|err| DeployError::DependencyError(format!("Failed to wait for git: {err}")))?; Ok(()) } @@ -271,6 +312,39 @@ fn compile_contracts(contracts_path: &Path) -> Result<(), DeployError> { "Failed to compile CommonBridge.sol".to_owned(), )); } + + if !Command::new("solc") + .arg("--bin") + .arg( + contracts_path + .join("lib/sp1-contracts/contracts/src/v3.0.0/SP1VerifierGroth16.sol") + .to_str() + .ok_or(DeployError::FailedToGetStringFromPath)?, + ) + .arg("-o") + .arg( + contracts_path + .join("solc_out") + .to_str() + .ok_or(DeployError::FailedToGetStringFromPath)?, + ) + .arg("--overwrite") + .arg("--allow-paths") + .arg( + contracts_path + .to_str() + .ok_or(DeployError::FailedToGetStringFromPath)?, + ) + .spawn() + .map_err(|err| DeployError::CompilationError(format!("Failed to spawn solc: {err}")))? + .wait() + .map_err(|err| DeployError::CompilationError(format!("Failed to wait for solc: {err}")))? + .success() + { + return Err(DeployError::CompilationError( + "Failed to compile SP1VerifierGroth16.sol".to_owned(), + )); + } Ok(()) } @@ -279,7 +353,8 @@ async fn deploy_contracts( deployer_private_key: SecretKey, eth_client: &EthClient, contracts_path: &Path, -) -> Result<(Address, Address), DeployError> { + deploy_verifier: bool, +) -> Result<(Address, Address, Option
), DeployError> { let deploy_frames = spinner!(["📭❱❱", "❱📬❱", "❱❱📫"], 220); let mut spinner = Spinner::new( @@ -288,46 +363,74 @@ async fn deploy_contracts( Color::Cyan, ); - let (on_chain_proposer_deployment_tx_hash, on_chain_proposer_address) = - deploy_on_chain_proposer(deployer, deployer_private_key, eth_client, contracts_path) - .await?; + let (on_chain_proposer_deployment_tx_hash, on_chain_proposer_address) = deploy_contract( + deployer, + deployer_private_key, + eth_client, + &contracts_path.join("solc_out/OnChainProposer.bin"), + ) + .await?; let msg = format!( - "OnChainProposer:\n\tDeployed at address {} with tx hash {}", + "OnChainProposer:\n\tDeployed at address {}\n\tWith tx hash {}", format!("{on_chain_proposer_address:#x}").bright_green(), format!("{on_chain_proposer_deployment_tx_hash:#x}").bright_cyan() ); spinner.success(&msg); - let mut spinner = Spinner::new(deploy_frames, "Deploying CommonBridge", Color::Cyan); - let (bridge_deployment_tx_hash, bridge_address) = - deploy_bridge(deployer, deployer_private_key, eth_client, contracts_path).await?; + let mut spinner = Spinner::new(deploy_frames.clone(), "Deploying CommonBridge", Color::Cyan); + let (bridge_deployment_tx_hash, bridge_address) = deploy_bridge( + deployer, + deployer_private_key, + eth_client, + &contracts_path.join("solc_out/CommonBridge.bin"), + ) + .await?; let msg = format!( - "CommonBridge:\n\tDeployed at address {} with tx hash {}", + "CommonBridge:\n\tDeployed at address {}\n\tWith tx hash {}", format!("{bridge_address:#x}").bright_green(), format!("{bridge_deployment_tx_hash:#x}").bright_cyan(), ); spinner.success(&msg); - Ok((on_chain_proposer_address, bridge_address)) + let sp1_verifier_address = if deploy_verifier { + let mut spinner = Spinner::new(deploy_frames, "Deploying SP1Verifier", Color::Cyan); + let (verifier_deployment_tx_hash, sp1_verifier_address) = deploy_contract( + deployer, + deployer_private_key, + eth_client, + &contracts_path.join("solc_out/SP1Verifier.bin"), + ) + .await?; + + let msg = format!( + "SP1Groth16Verifier:\n\tDeployed at address {}\n\tWith tx hash {}", + format!("{sp1_verifier_address:#x}").bright_green(), + format!("{verifier_deployment_tx_hash:#x}").bright_cyan(), + ); + spinner.success(&msg); + Some(sp1_verifier_address) + } else { + None + }; + + Ok(( + on_chain_proposer_address, + bridge_address, + sp1_verifier_address, + )) } -async fn deploy_on_chain_proposer( +async fn deploy_contract( deployer: Address, deployer_private_key: SecretKey, eth_client: &EthClient, - contracts_path: &Path, + contract_path: &Path, ) -> Result<(H256, Address), DeployError> { - let on_chain_proposer_init_code = hex::decode( - std::fs::read_to_string(contracts_path.join("solc_out/OnChainProposer.bin")).map_err( - |err| { - DeployError::DecodingError(format!( - "Failed to read on_chain_proposer_init_code: {err}" - )) - }, - )?, - ) + let init_code = hex::decode(std::fs::read_to_string(contract_path).map_err(|err| { + DeployError::DecodingError(format!("Failed to read on_chain_proposer_init_code: {err}")) + })?) .map_err(|err| { DeployError::DecodingError(format!( "Failed to decode on_chain_proposer_init_code: {err}" @@ -335,32 +438,27 @@ async fn deploy_on_chain_proposer( })? .into(); - let (deploy_tx_hash, on_chain_proposer) = create2_deploy( - deployer, - deployer_private_key, - &on_chain_proposer_init_code, - eth_client, - ) - .await - .map_err(DeployError::from)?; + let (deploy_tx_hash, contract_address) = + create2_deploy(deployer, deployer_private_key, &init_code, eth_client) + .await + .map_err(DeployError::from)?; - Ok((deploy_tx_hash, on_chain_proposer)) + Ok((deploy_tx_hash, contract_address)) } async fn deploy_bridge( deployer: Address, deployer_private_key: SecretKey, eth_client: &EthClient, - contracts_path: &Path, + contract_path: &Path, ) -> Result<(H256, Address), DeployError> { - let mut bridge_init_code = hex::decode( - std::fs::read_to_string(contracts_path.join("solc_out/CommonBridge.bin")).map_err( - |err| DeployError::DecodingError(format!("Failed to read bridge_init_code: {err}")), - )?, - ) - .map_err(|err| { - DeployError::DecodingError(format!("Failed to decode bridge_init_code: {err}")) - })?; + let mut bridge_init_code = + hex::decode(std::fs::read_to_string(contract_path).map_err(|err| { + DeployError::DecodingError(format!("Failed to read bridge_init_code: {err}")) + })?) + .map_err(|err| { + DeployError::DecodingError(format!("Failed to decode bridge_init_code: {err}")) + })?; let encoded_owner = { let offset = 32 - deployer.as_bytes().len() % 32; @@ -448,7 +546,8 @@ async fn initialize_contracts( verifier: Address, on_chain_proposer: Address, bridge: Address, - contract_verifier_address: Address, + risc0_verifier_address: Address, + sp1_verifier_address: Address, eth_client: &EthClient, ) -> Result<(), DeployError> { let initialize_frames = spinner!(["🪄❱❱", "❱🪄❱", "❱❱🪄"], 200); @@ -462,7 +561,8 @@ async fn initialize_contracts( let initialize_tx_hash = initialize_on_chain_proposer( on_chain_proposer, bridge, - contract_verifier_address, + risc0_verifier_address, + sp1_verifier_address, deployer, deployer_private_key, committer, @@ -503,20 +603,22 @@ async fn initialize_contracts( async fn initialize_on_chain_proposer( on_chain_proposer: Address, bridge: Address, - contract_verifier_address: Address, + risc0_verifier_address: Address, + sp1_verifier_address: Address, deployer: Address, deployer_private_key: SecretKey, committer: Address, verifier: Address, eth_client: &EthClient, ) -> Result { - let on_chain_proposer_initialize_selector = keccak(b"initialize(address,address,address[])") - .as_bytes() - .get(..4) - .ok_or(DeployError::DecodingError( - "Failed to get initialize selector".to_owned(), - ))? - .to_vec(); + let on_chain_proposer_initialize_selector = + keccak(b"initialize(address,address,address,address[])") + .as_bytes() + .get(..4) + .ok_or(DeployError::DecodingError( + "Failed to get initialize selector".to_owned(), + ))? + .to_vec(); let encoded_bridge = { let offset = 32 - bridge.as_bytes().len() % 32; let mut encoded_bridge = vec![0; offset]; @@ -524,10 +626,17 @@ async fn initialize_on_chain_proposer( encoded_bridge }; - let encoded_contract_verifier = { - let offset = 32 - contract_verifier_address.as_bytes().len() % 32; + let encoded_risc0_contract_verifier = { + let offset = 32 - risc0_verifier_address.as_bytes().len() % 32; let mut encoded_contract_verifier = vec![0; offset]; - encoded_contract_verifier.extend_from_slice(contract_verifier_address.as_bytes()); + encoded_contract_verifier.extend_from_slice(risc0_verifier_address.as_bytes()); + encoded_contract_verifier + }; + + let encoded_sp1_contract_verifier = { + let offset = 32 - sp1_verifier_address.as_bytes().len() % 32; + let mut encoded_contract_verifier = vec![0; offset]; + encoded_contract_verifier.extend_from_slice(sp1_verifier_address.as_bytes()); encoded_contract_verifier }; @@ -535,10 +644,12 @@ async fn initialize_on_chain_proposer( on_chain_proposer_initialization_calldata .extend_from_slice(&on_chain_proposer_initialize_selector); on_chain_proposer_initialization_calldata.extend_from_slice(&encoded_bridge); - on_chain_proposer_initialization_calldata.extend_from_slice(&encoded_contract_verifier); + on_chain_proposer_initialization_calldata.extend_from_slice(&encoded_risc0_contract_verifier); + on_chain_proposer_initialization_calldata.extend_from_slice(&encoded_sp1_contract_verifier); let mut encoded_offset = [0; 32]; - U256::from(32 * 3).to_big_endian(&mut encoded_offset); + // offset of 3 addresses before the address[] + address[] + U256::from(32 * (3 + 1)).to_big_endian(&mut encoded_offset); on_chain_proposer_initialization_calldata.extend_from_slice(&encoded_offset); let mut allowed_addresses = [0; 32]; U256::from(2).to_big_endian(&mut allowed_addresses); @@ -563,7 +674,6 @@ async fn initialize_on_chain_proposer( .await?; wait_for_transaction_receipt(initialize_tx_hash, eth_client).await?; - Ok(initialize_tx_hash) } diff --git a/crates/l2/contracts/src/l1/OnChainProposer.sol b/crates/l2/contracts/src/l1/OnChainProposer.sol index f4f204072..22725841a 100644 --- a/crates/l2/contracts/src/l1/OnChainProposer.sol +++ b/crates/l2/contracts/src/l1/OnChainProposer.sol @@ -7,6 +7,7 @@ import "./interfaces/IOnChainProposer.sol"; import {CommonBridge} from "./CommonBridge.sol"; import {ICommonBridge} from "./interfaces/ICommonBridge.sol"; import {IRiscZeroVerifier} from "./interfaces/IRiscZeroVerifier.sol"; +import {ISP1Verifier} from "./interfaces/ISP1Verifier.sol"; /// @title OnChainProposer contract. /// @author LambdaClass @@ -34,18 +35,26 @@ contract OnChainProposer is IOnChainProposer, ReentrancyGuard { /// @dev All blocks with a block number less than or equal to `lastCommittedBlock` are considered committed. /// @dev Blocks with a block number greater than `lastCommittedBlock` have not been committed yet. /// @dev This is crucial for ensuring that only subsequents blocks are committed in the contract. - /// @dev In the initialize function, `lastCommittedBlock` is set to u64::MAX == 0xFFFFFFFFFFFFFFFF, this value is used to allow the block 0 to be committed. uint256 public lastCommittedBlock; + /// @notice The next block to commit. + /// @dev This variable holds the block number of the next block to commit. + /// @dev `nextBlockToCommit` should be equal to `lastCommittedBlock` + 1. + /// @dev Only the block with the block number equal to `nextBlockToCommit` will be committed. + /// @dev This variable is called by the `l1_committer.rs`. + uint256 public nextBlockToCommit; + /// @dev The sequencer addresses that are authorized to commit and verify blocks. mapping(address _authorizedAddress => bool) public authorizedSequencerAddresses; address public BRIDGE; address public R0VERIFIER; + address public SP1VERIFIER; /// @notice Address used to avoid the verification process. - /// @dev If the `R0VERIFIER` contract address is set to this address, the verification process will not happen. + /// @dev If the `R0VERIFIER` or the `SP1VERIFIER` contract address is set to this address, + /// the verification process will not happen. /// @dev Used only in dev mode. address public constant DEV_MODE = address(0xAA); @@ -61,8 +70,10 @@ contract OnChainProposer is IOnChainProposer, ReentrancyGuard { function initialize( address bridge, address r0verifier, + address sp1verifier, address[] calldata sequencerAddresses ) public nonReentrant { + // Set the CommonBridge address require( BRIDGE == address(0), "OnChainProposer: contract already initialized" @@ -77,6 +88,7 @@ contract OnChainProposer is IOnChainProposer, ReentrancyGuard { ); BRIDGE = bridge; + // Set the Risc0Groth16Verifier address require( R0VERIFIER == address(0), "OnChainProposer: contract already initialized" @@ -91,11 +103,24 @@ contract OnChainProposer is IOnChainProposer, ReentrancyGuard { ); R0VERIFIER = r0verifier; + // Set the SP1Groth16Verifier address + require( + SP1VERIFIER == address(0), + "OnChainProposer: contract already initialized" + ); + require( + sp1verifier != address(0), + "OnChainProposer: sp1verifier is the zero address" + ); + require( + sp1verifier != address(this), + "OnChainProposer: sp1verifier is the contract address" + ); + SP1VERIFIER = sp1verifier; + for (uint256 i = 0; i < sequencerAddresses.length; i++) { authorizedSequencerAddresses[sequencerAddresses[i]] = true; } - - lastCommittedBlock = 0xFFFFFFFFFFFFFFFF; } /// @inheritdoc IOnChainProposer @@ -106,9 +131,11 @@ contract OnChainProposer is IOnChainProposer, ReentrancyGuard { bytes32 depositLogs ) external override onlySequencer { require( - blockNumber == lastCommittedBlock + 1 || - (blockNumber == 0 && lastCommittedBlock == 0xFFFFFFFFFFFFFFFF), - "OnChainProposer: blockNumber is not the immediate succesor of lastCommittedBlock" + blockNumber == nextBlockToCommit || + (blockNumber == 0 && + lastCommittedBlock == 0 && + nextBlockToCommit == 0), + "OnChainProposer: blockNumber is not the immediate successor of lastCommittedBlock" ); require( blockCommitments[blockNumber].commitmentHash == bytes32(0), @@ -135,6 +162,7 @@ contract OnChainProposer is IOnChainProposer, ReentrancyGuard { depositLogs ); lastCommittedBlock = blockNumber; + nextBlockToCommit = blockNumber + 1; emit BlockCommitted(commitment); } @@ -148,7 +176,10 @@ contract OnChainProposer is IOnChainProposer, ReentrancyGuard { uint256 blockNumber, bytes calldata blockProof, bytes32 imageId, - bytes32 journalDigest + bytes32 journalDigest, + bytes32 programVKey, + bytes calldata publicValues, + bytes calldata proofBytes ) external override onlySequencer { require( blockNumber == lastVerifiedBlock + 1, @@ -169,6 +200,15 @@ contract OnChainProposer is IOnChainProposer, ReentrancyGuard { ); } + if (SP1VERIFIER != DEV_MODE) { + // If the verification fails, it will revert. + ISP1Verifier(SP1VERIFIER).verifyProof( + programVKey, + publicValues, + proofBytes + ); + } + lastVerifiedBlock = blockNumber; // The first 2 bytes are the number of deposits. uint16 deposits_amount = uint16( diff --git a/crates/l2/contracts/src/l1/interfaces/IOnChainProposer.sol b/crates/l2/contracts/src/l1/interfaces/IOnChainProposer.sol index ef31a4a43..13f3ee600 100644 --- a/crates/l2/contracts/src/l1/interfaces/IOnChainProposer.sol +++ b/crates/l2/contracts/src/l1/interfaces/IOnChainProposer.sol @@ -6,10 +6,17 @@ pragma solidity ^0.8.27; /// @notice A OnChainProposer contract ensures the advancement of the L2. It is used /// by the proposer to commit blocks and verify block proofs. interface IOnChainProposer { - /// @notice The latest commited block number. + /// @notice The latest committed block number. + /// @return The latest committed block number as a uint256. function lastCommittedBlock() external view returns (uint256); - /// @notice The latest verified block number + /// @notice The next block number to commit. + /// @dev This value should be equal to `lastCommittedBlock() + 1`. + /// @return The next block number to commit as a uint256. + function nextBlockToCommit() external view returns (uint256); + + /// @notice The latest verified block number. + /// @return The latest verified block number as a uint256. function lastVerifiedBlock() external view returns (uint256); /// @notice A block has been committed. @@ -25,7 +32,13 @@ interface IOnChainProposer { /// @dev It sets the bridge address. /// @param bridge the address of the bridge contract. /// @param r0verifier the address of the risc0 groth16 verifier. - function initialize(address bridge, address r0verifier, address[] calldata sequencerAddress) external; + /// @param sp1verifier the address of the sp1 groth16 verifier. + function initialize( + address bridge, + address r0verifier, + address sp1verifier, + address[] calldata sequencerAddress + ) external; /// @notice Commits to an L2 block. /// @dev Committing to an L2 block means to store the block's commitment @@ -49,10 +62,17 @@ interface IOnChainProposer { /// @param blockProof is the proof of the block to be verified. /// @param imageId Digest of the zkVM imageid. /// @param journalDigest Digest of the public_inputs aka journal + /// ---------------------------------------------------------------------- + /// @param programVKey Public verifying key + /// @param publicValues Values used to perform the execution + /// @param proofBytes Groth16 proof function verify( uint256 blockNumber, bytes calldata blockProof, bytes32 imageId, - bytes32 journalDigest + bytes32 journalDigest, + bytes32 programVKey, + bytes calldata publicValues, + bytes calldata proofBytes ) external; } diff --git a/crates/l2/contracts/src/l1/interfaces/ISP1Verifier.sol b/crates/l2/contracts/src/l1/interfaces/ISP1Verifier.sol new file mode 100644 index 000000000..beb0143b4 --- /dev/null +++ b/crates/l2/contracts/src/l1/interfaces/ISP1Verifier.sol @@ -0,0 +1,25 @@ +// From: https://github.com/succinctlabs/sp1-contracts/blob/65a1d96b720ffa2e6d167fb62527c9c8a534abbe/contracts/src/ISP1Verifier.sol +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +/// @title SP1 Verifier Interface +/// @author Succinct Labs +/// @notice This contract is the interface for the SP1 Verifier. +interface ISP1Verifier { + /// @notice Verifies a proof with given public values and vkey. + /// @dev It is expected that the first 4 bytes of proofBytes must match the first 4 bytes of + /// target verifier's VERIFIER_HASH. + /// @param programVKey The verification key for the RISC-V program. + /// @param publicValues The public values encoded as bytes. + /// @param proofBytes The proof of the program execution the SP1 zkVM encoded as bytes. + function verifyProof( + bytes32 programVKey, + bytes calldata publicValues, + bytes calldata proofBytes + ) external view; +} + +interface ISP1VerifierWithHash is ISP1Verifier { + /// @notice Returns the hash of the verifier. + function VERIFIER_HASH() external pure returns (bytes32); +} diff --git a/crates/l2/docs/README.md b/crates/l2/docs/README.md index 9e591cc39..dc99f0f3d 100644 --- a/crates/l2/docs/README.md +++ b/crates/l2/docs/README.md @@ -11,6 +11,20 @@ For more detailed documentation on each part of the system: - [Proposer](./proposer.md) - [Prover](./prover.md) +## Quick HandsOn + +1. `cd crates/l2` +2. `make rm-db-l2 && make down` + - It will remove any old database, if present, stored in your computer. The absolute path of libmdbx is defined by [data_dir](https://docs.rs/dirs/latest/dirs/fn.data_dir.html). +3. `cp .env.example .env` → check if you want to change any config. +4. `make init` + - Init the L1 in a docker container on port `8545`. + - Deploy the needed contracts for the L2 on the L1. + - Start the L2 locally on port `1729`. + + +For more information on how to run the L2 node with the prover attached to it, the [Prover Docs](./prover.md) provides more insight. + ## Configuration Configuration is done through env vars. A detailed list is available in each part documentation. diff --git a/crates/l2/docs/prover.md b/crates/l2/docs/prover.md index daaf3c2a9..38e1c1410 100644 --- a/crates/l2/docs/prover.md +++ b/crates/l2/docs/prover.md @@ -2,18 +2,17 @@ ## ToC -- [ethrex L2 Prover](#ethrex-l2-prover) - - [ToC](#toc) - - [What](#what) - - [Workflow](#workflow) - - [How](#how) - - [Dev Mode](#dev-mode) - - [Quick Test](#quick-test) - - [Run the whole system with the prover](#run-the-whole-system-with-the-prover) - - [GPU mode](#gpu-mode) - - [Proving Process Test](#proving-process-test) - - [Run the whole system with the prover in Sepolia](#run-the-whole-system-with-the-prover-in-sepolia) - - [Configuration](#configuration) +- [ToC](#toc) +- [What](#what) +- [Workflow](#workflow) +- [How](#how) + - [Dev Mode](#dev-mode) + - [Quick Test](#quick-test) + - [Run the whole system with the prover](#run-the-whole-system-with-the-prover) + - [GPU mode](#gpu-mode) + - [Proving Process Test](#proving-process-test) + - [Run the whole system with a GPU Prover](#run-the-whole-system-with-a-gpu-prover) +- [Configuration](#configuration) >[!NOTE] > The shipping/deploying process and the `Prover` itself are under development. @@ -48,16 +47,21 @@ sequenceDiagram **Dependencies:** - [RISC0](https://dev.risczero.com/api/zkvm/install) +- [SP1](https://docs.succinct.xyz/docs/getting-started/install) -To run the blockchain (`proposer`) and prover in conjunction in a development environment, set the following environment variable: `RISC0_DEV_MODE=1` [(docs)](https://dev.risczero.com/api/generating-proofs/dev-mode). If you are in the `crates/l2` directory, you will need to set the environment variable for `dev_mode`. The `.env.example` file should suffice. +To run the blockchain (`proposer`) and prover in conjunction in a development environment, set the following environment variables in the `.env` file: +- `PROVER_SERVER_DEV_MODE=false` +- Depending on the Proving System: + - RISC0: `RISC0_DEV_MODE=1` [(docs)](https://dev.risczero.com/api/generating-proofs/dev-mode) + - SP1: `SP1_PROVER=local` To start the `prover_client`, use the following command: ```sh -make init-l2-prover +make init-prover T="prover_type (risc0 or sp1) G=true" ``` -The `build_zkvm` flag is used, if you don't have the risc0's "sdk", you can build the prover without the feature to check if all the surrounding components of the `zkvm` can be compiled. +If neither `risc0` nor `sp1` is installed on the system, the prover can be built without the "build" features to check whether all the surrounding components of the prover (except for the RISC-V zkVMs) can be compiled. #### Quick Test @@ -65,22 +69,25 @@ To test the `zkvm` execution quickly, the following test can be run: ```sh cd crates/l2/prover -make perf_test_proving ``` +Then run any of the targets: +- `make perf-risc0` +- `make perf-sp1` + #### Run the whole system with the prover 1. `cd crates/l2` -2. `make rm_dev_libmdbx_l2 && make down` +2. `make rm-db-l2 && make down` - It will remove any old database, if present, stored in your computer. The absolute path of libmdbx is defined by [data_dir](https://docs.rs/dirs/latest/dirs/fn.data_dir.html). 3. `cp .env.example .env` → check if you want to change any config. 4. `make init` - Init the L1 in a docker container on port `8545`. - Deploy the needed contracts for the L2 on the L1. - Start the L2 locally on port `1729`. -5. In a new terminal → `make init-l2-prover`. +5. In a new terminal → `make init-prover T=(risc0 or sp1)`. -After this initialization the system has to be running in `dev-mode` → No proof verification. +After this initialization we should have the prover running in `dev_mode` → No real proofs. ### GPU mode @@ -108,42 +115,47 @@ To test the `zkvm` proving process using a `gpu` quickly, the following test can ```sh cd crates/l2/prover -make perf_gpu ``` -#### Run the whole system with the prover in Sepolia +Then run any of the targets: +- `make perf-risc0-gpu` +- `make perf-sp1-gpu` + +#### Run the whole system with a GPU Prover Two servers are required: one for the `prover` and another for the `proposer`. If you run both components on the same machine, the `prover` may consume all available resources, leading to potential stuttering or performance issues for the `proposer`/`node`. -1. `prover`/`zkvm` → prover with gpu, make sure to have all the required dependencies described at the beginning of [Gpu Mode](#gpu-mode) section. +1. `prover_client`/`zkvm` → prover with gpu, make sure to have all the required dependencies described at the beginning of [Gpu Mode](#gpu-mode) section. 1. `cd ethrex/crates/l2` 2. `cp .example.env` and change the `PROVER_CLIENT_PROVER_SERVER_ENDPOINT` with the ip of the other server. -The env variables needed are: +The important variables are: ```sh PROVER_CLIENT_PROVER_SERVER_ENDPOINT=:3000 RISC0_DEV_MODE=0 +SP1_PROVER=local ``` -Finally, to start the `prover_client`/`zkvm`, run: - -- `make init-l2-prover-gpu` +- `Finally`, to start the `prover_client`/`zkvm`, run: + - `make init-prover T=(risc0 or sp1) G=true` -2.  `proposer` → this server just needs rust installed. +2. `prover_server`/`proposer` → this server just needs rust installed. 1. `cd ethrex/crates/l2` 2. `cp .example.env` and change the addresses and the following fields: - `PROVER_SERVER_LISTEN_IP=0.0.0.0` → used to handle the tcp communication with the other server. - - The `COMMITTER` and `PROVER_SERVER_VERIFIER` must be different accounts, the `DEPLOYER_ADDRESS` as well as the `L1_WATCHER` may be the same account used by the `COMMITTER` - - `DEPLOYER_CONTRACT_VERIFIER=0xd9b0d07CeCd808a8172F21fA7C97992168f045CA` → risc0’s verifier contract deployed on Sepolia. - - Set the `ETH_RPC_URL` to any Sepolia's endpoint. + - The `COMMITTER` and `PROVER_SERVER_VERIFIER` must be different accounts, the `DEPLOYER_ADDRESS` as well as the `L1_WATCHER` may be the same account used by the `COMMITTER`. + - `DEPLOYER_SALT_IS_ZERO=false` → set to false to randomize the salt. + - `DEPLOYER_SP1_DEPLOY_VERIFIER=true` overwrites `DEPLOYER_SP1_CONTRACT_VERIFIER`. Check if the contract is deployed in your preferred network or set to `true` to deploy it. + - `DEPLOYER_CONTRACT_VERIFIER=0xd9b0d07CeCd808a8172F21fA7C97992168f045CA` → risc0’s verifier contract deployed on Sepolia. (Check the if the contract is deployed in your preferred network). + - Set the `ETH_RPC_URL` to any L1 endpoint. >[!NOTE] > Make sure to have funds, if you want to perform a quick test `0.2[ether]` on each account should be enough. -Finally, to start the `proposer`/`l2 node`, run: - - `make rm_dev_libmdbx_l2 && make down` - - `make init` +- `Finally`, to start the `proposer`/`l2 node`, run: + - `make rm-db-l2 && make down` + - `make deploy-l1 && make init-l2` ## Configuration diff --git a/crates/l2/proposer/l1_committer.rs b/crates/l2/proposer/l1_committer.rs index c814e25ad..68601750f 100644 --- a/crates/l2/proposer/l1_committer.rs +++ b/crates/l2/proposer/l1_committer.rs @@ -77,18 +77,12 @@ impl Committer { async fn main_logic(&self) -> Result<(), CommitterError> { loop { - let last_committed_block = EthClient::get_last_committed_block( + let block_number_to_fetch = EthClient::get_next_block_to_commit( &self.eth_client, self.on_chain_proposer_address, ) .await?; - let block_number_to_fetch = if last_committed_block == u64::MAX { - 0 - } else { - last_committed_block + 1 - }; - if let Some(block_to_commit_body) = self .store .get_block_body(block_number_to_fetch) diff --git a/crates/l2/proposer/mod.rs b/crates/l2/proposer/mod.rs index 63efc0dbb..b11a0f41e 100644 --- a/crates/l2/proposer/mod.rs +++ b/crates/l2/proposer/mod.rs @@ -90,9 +90,7 @@ impl Proposer { pub async fn main_logic(&self, store: Store) -> Result<(), ProposerError> { let head_block_hash = { - let current_block_number = store - .get_latest_block_number()? - .ok_or(ProposerError::StorageDataIsNone)?; + let current_block_number = store.get_latest_block_number()?; store .get_canonical_block_hash(current_block_number)? .ok_or(ProposerError::StorageDataIsNone)? diff --git a/crates/l2/proposer/prover_server.rs b/crates/l2/proposer/prover_server.rs index 1e1b3bd17..b4b936358 100644 --- a/crates/l2/proposer/prover_server.rs +++ b/crates/l2/proposer/prover_server.rs @@ -4,7 +4,7 @@ use crate::utils::{ committer::CommitterConfig, errors::ConfigError, eth::EthConfig, prover_server::ProverServerConfig, }, - eth_client::{errors::EthClientError, eth_sender::Overrides, EthClient, WrappedTransaction}, + eth_client::{eth_sender::Overrides, EthClient, WrappedTransaction}, }; use ethrex_core::{ types::{Block, BlockHeader}, @@ -28,7 +28,8 @@ use tokio::{ }; use tracing::{debug, error, info, warn}; -use risc0_zkvm::sha::{Digest, Digestible}; +use risc0_zkvm::sha::Digestible; +use sp1_sdk::HashableKey; #[derive(Debug, Serialize, Deserialize, Default)] pub struct ProverInputData { @@ -37,7 +38,7 @@ pub struct ProverInputData { pub db: ExecutionDB, } -#[derive(Debug, Clone)] +#[derive(Clone)] struct ProverServer { ip: IpAddr, port: u16, @@ -48,8 +49,146 @@ struct ProverServer { verifier_private_key: SecretKey, } +#[derive(Debug, Clone, Copy)] +/// Enum used to identify the different proving systems. +pub enum ProverType { + RISC0, + SP1, +} + +#[derive(Serialize, Deserialize, Clone)] +pub struct Risc0Proof { + pub receipt: Box, + pub prover_id: Vec, +} + +pub struct Risc0ContractData { + pub block_proof: Vec, + pub image_id: Vec, + pub journal_digest: Vec, +} + +impl Risc0Proof { + pub fn new(receipt: risc0_zkvm::Receipt, prover_id: Vec) -> Self { + Risc0Proof { + receipt: Box::new(receipt), + prover_id, + } + } + + pub fn contract_data(&self) -> Result { + // If we run the prover_client with RISC0_DEV_MODE=0 we will have a groth16 proof + // Else, we will have a fake proof. + // + // The RISC0_DEV_MODE=1 should only be used with DEPLOYER_CONTRACT_VERIFIER=0xAA + let block_proof = match self.receipt.inner.groth16() { + Ok(inner) => { + // The SELECTOR is used to perform an extra check inside the groth16 verifier contract. + let mut selector = + hex::encode(inner.verifier_parameters.as_bytes().get(..4).ok_or( + ProverServerError::Custom( + "Failed to get verify_proof_selector in send_proof()".to_owned(), + ), + )?); + let seal = hex::encode(inner.clone().seal); + selector.push_str(&seal); + hex::decode(selector).map_err(|e| { + ProverServerError::Custom(format!("Failed to hex::decode(selector): {e}")) + })? + } + Err(_) => vec![32; 0], + }; + + let mut image_id: [u32; 8] = [0; 8]; + for (i, b) in image_id.iter_mut().enumerate() { + *b = *self.prover_id.get(i).ok_or(ProverServerError::Custom( + "Failed to get image_id in handle_proof_submission()".to_owned(), + ))?; + } + + let image_id: risc0_zkvm::sha::Digest = image_id.into(); + let image_id = image_id.as_bytes().to_vec(); + + let journal_digest = Digestible::digest(&self.receipt.journal) + .as_bytes() + .to_vec(); + + Ok(Risc0ContractData { + block_proof, + image_id, + journal_digest, + }) + } + + pub fn contract_data_empty() -> Risc0ContractData { + Risc0ContractData { + block_proof: vec![0; 32], + image_id: vec![0; 32], + journal_digest: vec![0; 32], + } + } +} + +#[derive(Serialize, Deserialize, Clone)] +pub struct Sp1Proof { + pub proof: Box, + pub vk: sp1_sdk::SP1VerifyingKey, +} + +pub struct Sp1ContractData { + pub public_values: Vec, + pub vk: Vec, + pub proof_bytes: Vec, +} + +impl Sp1Proof { + pub fn new( + proof: sp1_sdk::SP1ProofWithPublicValues, + verifying_key: sp1_sdk::SP1VerifyingKey, + ) -> Self { + Sp1Proof { + proof: Box::new(proof), + vk: verifying_key, + } + } + + pub fn contract_data(&self) -> Result { + let vk = self + .vk + .bytes32() + .strip_prefix("0x") + .ok_or(ProverServerError::Custom( + "Failed to strip_prefix of sp1 vk".to_owned(), + ))? + .to_string(); + let vk_bytes = hex::decode(&vk) + .map_err(|_| ProverServerError::Custom("Failed hex::decode(&vk)".to_owned()))?; + + Ok(Sp1ContractData { + public_values: self.proof.public_values.to_vec(), + vk: vk_bytes, + proof_bytes: self.proof.bytes(), + }) + } + + // TODO: better way of giving empty information + pub fn contract_data_empty() -> Sp1ContractData { + Sp1ContractData { + public_values: vec![0; 32], + vk: vec![0; 32], + proof_bytes: vec![0; 32], + } + } +} + +#[derive(Serialize, Deserialize, Clone)] +pub enum ProvingOutput { + RISC0(Risc0Proof), + SP1(Sp1Proof), +} + /// Enum for the ProverServer <--> ProverClient Communication Protocol. -#[derive(Debug, Serialize, Deserialize)] +#[derive(Serialize, Deserialize)] pub enum ProofData { /// 1. /// The Client initiates the connection with a Request. @@ -67,10 +206,10 @@ pub enum ProofData { /// 3. /// The Client submits the zk Proof generated by the prover /// for the specified block. + /// The [ProvingOutput] has the [ProverType] implicitly. Submit { block_number: u64, - // zk Proof - receipt: Box<(risc0_zkvm::Receipt, Vec)>, + proving_output: ProvingOutput, }, /// 4. @@ -93,10 +232,10 @@ impl ProofData { } /// Builder function for creating a Submit - pub fn submit(block_number: u64, receipt: (risc0_zkvm::Receipt, Vec)) -> Self { + pub fn submit(block_number: u64, proving_output: ProvingOutput) -> Self { ProofData::Submit { block_number, - receipt: Box::new(receipt), + proving_output, } } @@ -112,8 +251,7 @@ pub async fn start_prover_server(store: Store) -> Result<(), ConfigError> { let proposer_config = CommitterConfig::from_env()?; let mut prover_server = ProverServer::new_from_config(server_config.clone(), &proposer_config, eth_config, store) - .await - .map_err(ConfigError::from)?; + .await?; prover_server.run(&server_config).await; Ok(()) } @@ -124,7 +262,7 @@ impl ProverServer { committer_config: &CommitterConfig, eth_config: EthConfig, store: Store, - ) -> Result { + ) -> Result { let eth_client = EthClient::new(ð_config.rpc_url); let on_chain_proposer_address = committer_config.on_chain_proposer_address; @@ -253,15 +391,16 @@ impl ProverServer { } Ok(ProofData::Submit { block_number, - receipt, + proving_output, }) => { self.handle_submit(&mut stream, block_number)?; - self.handle_proof_submission(block_number, receipt).await?; - if block_number != (last_verified_block + 1) { return Err(ProverServerError::Custom(format!("Prover Client submitted an invalid block_number: {block_number}. The last_proved_block is: {}", last_verified_block))); } + + self.handle_proof_submission(block_number, proving_output) + .await?; } Err(e) => { warn!("Failed to parse request: {e}"); @@ -282,10 +421,7 @@ impl ProverServer { ) -> Result<(), ProverServerError> { debug!("Request received"); - let latest_block_number = self - .store - .get_latest_block_number()? - .ok_or(ProverServerError::StorageDataIsNone)?; + let latest_block_number = self.store.get_latest_block_number()?; let response = if block_number > latest_block_number { let response = ProofData::response(None, None); @@ -320,51 +456,6 @@ impl ProverServer { Ok(()) } - async fn handle_proof_submission( - &self, - block_number: u64, - receipt: Box<(risc0_zkvm::Receipt, Vec)>, - ) -> Result<(), ProverServerError> { - // Send Tx - // If we run the prover_client with RISC0_DEV_MODE=0 we will have a groth16 proof - // Else, we will have a fake proof. - // - // The RISC0_DEV_MODE=1 should only be used with DEPLOYER_CONTRACT_VERIFIER=0xAA - let seal = match receipt.0.inner.groth16() { - Ok(inner) => { - // The SELECTOR is used to perform an extra check inside the groth16 verifier contract. - let mut selector = - hex::encode(inner.verifier_parameters.as_bytes().get(..4).ok_or( - ProverServerError::Custom( - "Failed to get verify_proof_selector in send_proof()".to_owned(), - ), - )?); - let seal = hex::encode(inner.clone().seal); - selector.push_str(&seal); - hex::decode(selector).map_err(|e| { - ProverServerError::Custom(format!("Failed to hex::decode(selector): {e}")) - })? - } - Err(_) => vec![32; 0], - }; - - let mut image_id: [u32; 8] = [0; 8]; - for (i, b) in image_id.iter_mut().enumerate() { - *b = *receipt.1.get(i).ok_or(ProverServerError::Custom( - "Failed to get image_id in handle_proof_submission()".to_owned(), - ))?; - } - - let image_id: risc0_zkvm::sha::Digest = image_id.into(); - - let journal_digest = Digestible::digest(&receipt.0.journal); - - self.send_proof(block_number, &seal, image_id, journal_digest) - .await?; - - Ok(()) - } - fn create_prover_input(&self, block_number: u64) -> Result { let header = self .store @@ -393,64 +484,139 @@ impl ProverServer { }) } - pub async fn send_proof( + pub async fn handle_proof_submission( &self, block_number: u64, - seal: &[u8], - image_id: Digest, - journal_digest: Digest, + proving_output: ProvingOutput, ) -> Result { + // TODO: + // Ideally we should wait to have both proofs + // We will have to send them in the same transaction. + let (sp1_contract_data, risc0_contract_data) = match proving_output { + ProvingOutput::RISC0(risc0_proof) => { + let risc0_contract_data = risc0_proof.contract_data()?; + let sp1_contract_data = Sp1Proof::contract_data_empty(); + (sp1_contract_data, risc0_contract_data) + } + ProvingOutput::SP1(sp1_proof) => { + let risc0_contract_data = Risc0Proof::contract_data_empty(); + let sp1_contract_data = sp1_proof.contract_data()?; + (sp1_contract_data, risc0_contract_data) + } + }; + debug!("Sending proof for {block_number}"); - let mut calldata = Vec::new(); // IOnChainProposer - // function verify(uint256,bytes,bytes32,bytes32) - // Verifier - // function verify(bytes,bytes32,bytes32) - // blockNumber, seal, imageId, journalDigest + // function verify(uint256,bytes,bytes32,bytes32,bytes32,bytes,bytes) + // blockNumber, blockProof, imageId, journalDigest, programVKey, publicValues, proofBytes // From crates/l2/contracts/l1/interfaces/IOnChainProposer.sol - let verify_proof_selector = keccak(b"verify(uint256,bytes,bytes32,bytes32)") + let mut calldata = keccak(b"verify(uint256,bytes,bytes32,bytes32,bytes32,bytes,bytes)") .as_bytes() .get(..4) .ok_or(ProverServerError::Custom( "Failed to get verify_proof_selector in send_proof()".to_owned(), ))? .to_vec(); - calldata.extend(verify_proof_selector); // The calldata has to be structured in the following way: // block_number - // size in bytes - // image_id digest - // journal digest - // size of seal - // seal + // offset of first bytes parameter + // image_id + // journal + // programVKey + // offset of second bytes parameter + // offset of third bytes parameter + // size of block_proof + // block_proof + // size of publicValues + // publicValues + // size of proofBytes + // proofBytes // extend with block_number calldata.extend(H256::from_low_u64_be(block_number).as_bytes()); - // extend with size in bytes - // 4 u256 goes after this field so: 0x80 == 128bytes == 32bytes * 4 - calldata.extend(H256::from_low_u64_be(4 * 32).as_bytes()); + // extend with offset in bytes + calldata.extend(H256::from_low_u64_be(7 * 32).as_bytes()); // extend with image_id - calldata.extend(image_id.as_bytes()); + calldata.extend(risc0_contract_data.image_id); // extend with journal_digest - calldata.extend(journal_digest.as_bytes()); - - // extend with size of seal - calldata.extend( - H256::from_low_u64_be(seal.len().try_into().map_err(|err| { - ProverServerError::Custom(format!("Seal length does not fit in u64: {}", err)) - })?) - .as_bytes(), - ); - // extend with seal - calldata.extend(seal); - // extend with zero padding - let leading_zeros = 32 - ((calldata.len() - 4) % 32); - calldata.extend(vec![0; leading_zeros]); + calldata.extend(risc0_contract_data.journal_digest); + + // extend with program_vkey + calldata.extend(sp1_contract_data.vk); + + // extend with offset in bytes of second bytes parameter + let block_proof_len: u64 = + risc0_contract_data + .block_proof + .len() + .try_into() + .map_err(|err| { + ProverServerError::Custom(format!( + "calldata length does not fit in u64: {}", + err + )) + })?; + + let calldata_len: u64 = (calldata.len()).try_into().map_err(|err| { + ProverServerError::Custom(format!("calldata length does not fit in u64: {}", err)) + })?; + + let leading_zeros_after_block_proof: u64 = + calculate_padding(calldata_len + 64 + block_proof_len)? + .try_into() + .map_err(|err| { + ProverServerError::Custom(format!( + "calculate_padding length does not fit in u64: {}", + err + )) + })?; + + // 2 * 32 bytes are the offset of the second and third bytes offsets + // and then 32 bytes more for the len of block_proof + let bytes = 32 * 3; + let offset = calldata_len + block_proof_len + leading_zeros_after_block_proof + bytes; + calldata.extend(H256::from_low_u64_be(offset - 4).as_bytes()); + + // add 32 bytes to reflect the last extend() + let offset = offset + 32; + let public_values_len: u64 = + sp1_contract_data + .public_values + .len() + .try_into() + .map_err(|err| { + ProverServerError::Custom(format!( + "public_values length does not fit in u64: {}", + err + )) + })?; + + let leading_zeros_after_public_values: u64 = calculate_padding(offset + public_values_len)? + .try_into() + .map_err(|err| { + ProverServerError::Custom(format!( + "calculate_padding length does not fit in u64: {}", + err + )) + })?; + + let offset = offset + public_values_len + leading_zeros_after_public_values - 4; + // extend with offset in bytes of third bytes parameter + calldata.extend(H256::from_low_u64_be(offset).as_bytes()); + + // extend with size of block_proof and block_proof + extend_calldata_with_bytes(&mut calldata, &risc0_contract_data.block_proof)?; + + // extend with size of public_values and public_values + extend_calldata_with_bytes(&mut calldata, &sp1_contract_data.public_values)?; + + // extend with size of proof_bytes and proof_bytes + extend_calldata_with_bytes(&mut calldata, &sp1_contract_data.proof_bytes)?; let verify_tx = self .eth_client @@ -507,10 +673,25 @@ impl ProverServer { info!("Last committed: {last_committed_block} - Last verified: {last_verified_block}"); // IOnChainProposer - // function verify(uint256,bytes,bytes32,bytes32) - // blockNumber, seal, imageId, journalDigest + // function verify(uint256,bytes,bytes32,bytes32,bytes32,bytes,bytes) + // blockNumber, blockProof, imageId, journalDigest, programVKey, publicValues, proofBytes // From crates/l2/contracts/l1/interfaces/IOnChainProposer.sol - let mut calldata = keccak(b"verify(uint256,bytes,bytes32,bytes32)") + + // The calldata has to be structured in the following way: + // block_number + // offset of first bytes parameter + // image_id + // journal + // programVKey + // offset of second bytes parameter + // offset of third bytes parameter + // size of block_proof + // block_proof + // size of publicValues + // publicValues + // size of proofBytes + // proofBytes + let mut calldata = keccak(b"verify(uint256,bytes,bytes32,bytes32,bytes32,bytes,bytes)") .as_bytes() .get(..4) .ok_or(ProverServerError::Custom( @@ -518,11 +699,20 @@ impl ProverServer { ))? .to_vec(); calldata.extend(H256::from_low_u64_be(last_verified_block + 1).as_bytes()); - calldata.extend(H256::from_low_u64_be(128).as_bytes()); - calldata.extend(H256::zero().as_bytes()); + // offset of first bytes parameter + calldata.extend(H256::from_low_u64_be(7 * 32).as_bytes()); + // extend with bytes32, bytes32, bytes32 + for _ in 0..=3 { + calldata.extend(H256::zero().as_bytes()); + } + // offset of second bytes parameter calldata.extend(H256::zero().as_bytes()); + // offset of third bytes parameter calldata.extend(H256::zero().as_bytes()); + // extend with size of the third bytes variable -> 32bytes + calldata.extend(H256::from_low_u64_be(32).as_bytes()); calldata.extend(H256::zero().as_bytes()); + let verify_tx = self .eth_client .build_eip1559_transaction( @@ -557,3 +747,46 @@ impl ProverServer { } } } + +pub fn extend_calldata_with_bytes( + calldata: &mut Vec, + bytes: &[u8], +) -> Result<(), ProverServerError> { + // extend with size of bytes + calldata.extend( + H256::from_low_u64_be(bytes.len().try_into().map_err(|err| { + ProverServerError::Custom(format!("bytes length does not fit in u64: {}", err)) + })?) + .as_bytes(), + ); + // extend with bytes + calldata.extend(bytes); + // extend with zero padding + let calldata_len: u64 = calldata.len().try_into().map_err(|err| { + ProverServerError::Custom(format!("calldata length does not fit in u64: {}", err)) + })?; + let leading_zeros = calculate_padding(calldata_len)?; + calldata.extend(vec![0; leading_zeros]); + + Ok(()) +} + +fn calculate_padding(calldata_len: u64) -> Result { + let len = calldata_len - 4; + + // Calculate leading zeros needed for alignment to 32 bytes + let leading_zeros = if len % 32 == 0 { 0 } else { 32 - (len % 32) }; + leading_zeros + .try_into() + .map_err(|_| ProverServerError::Custom("Failed to calculate padding".to_owned())) +} + +// used for debugging purposes +#[allow(unused)] +fn print_calldata(calldata: Vec) { + let mut hex_string = String::new(); + for byte in calldata { + hex_string.push_str(&format!("{:02x}", byte)); + } + println!("CALLDATA: {}", hex_string); +} diff --git a/crates/l2/prover/Cargo.toml b/crates/l2/prover/Cargo.toml index da6d463a2..fe5e3344a 100644 --- a/crates/l2/prover/Cargo.toml +++ b/crates/l2/prover/Cargo.toml @@ -13,6 +13,7 @@ tokio-util.workspace = true tracing-subscriber = { workspace = true, features = ["env-filter"] } tracing.workspace = true hex.workspace = true +thiserror.workspace = true # ethrex ethrex-core.workspace = true @@ -22,10 +23,14 @@ ethrex-rlp.workspace = true # l2 ethrex-l2.workspace = true -# risc0 zkvm_interface = { path = "./zkvm/interface", default-features = false } + +# risc0 risc0-zkvm = { version = "1.2.0" } +# sp1 +sp1-sdk = "3.4.0" + [dev-dependencies] ethrex-vm.workspace = true ethrex-storage.workspace = true @@ -41,8 +46,12 @@ path = "src/main.rs" [features] default = [] -build_zkvm = ["zkvm_interface/build_zkvm"] -gpu = ["risc0-zkvm/cuda"] +## risc0 +build_risc0 = ["zkvm_interface/build_risc0"] +gpu = ["risc0-zkvm/cuda", "sp1-sdk/cuda"] +## sp1 +build_sp1 = ["zkvm_interface/build_sp1"] + [lints.clippy] unwrap_used = "deny" diff --git a/crates/l2/prover/Makefile b/crates/l2/prover/Makefile index f754dad2b..f2d2cd6ec 100644 --- a/crates/l2/prover/Makefile +++ b/crates/l2/prover/Makefile @@ -1,18 +1,41 @@ -.PHONY: perf_test_proving perf_gpu rsp_comparison + +.PHONY: perf_test_sp1_proving ROOT_DIRECTORY := ../../.. +######################################################################## +############### RISC0 ############### +######################################################################## +.PHONY: perf-risc0 perf-risc0-gpu + RISC0_DEV_MODE?=1 RUST_LOG?="info" -perf_test_proving: +perf-risc0: @echo "Using RISC0_DEV_MODE: ${RISC0_DEV_MODE}" - RISC0_DEV_MODE=${RISC0_DEV_MODE} RUST_LOG=${RUST_LOG} cargo test --release --test perf_zkvm --features build_zkvm -- --show-output + RISC0_DEV_MODE=${RISC0_DEV_MODE} RUST_LOG=${RUST_LOG} cargo test --release --test perf_zkvm --features build_risc0 -- test_performance_zkvm --exact --show-output -perf_gpu: - RUSTFLAGS="-C target-cpu=native" RISC0_DEV_MODE=0 RUST_LOG="debug" cargo test --release --test perf_zkvm --features "build_zkvm,gpu" -- --show-output +perf-risc0-gpu: + RUSTFLAGS="-C target-cpu=native" RISC0_DEV_MODE=0 RUST_LOG=${RUST_LOG} cargo test --release --test perf_zkvm --features "build_risc0,gpu" -- test_performance_zkvm --exact --show-output -# L2 Prover comparison with rsp. Uses GPU by default. +######################################################################## +############### SP1 ############### +######################################################################## +######################################################################## +.PHONY: perf-sp1 perf-sp1-gpu + +SP1_PROVER?=mock +RUST_LOG?="info" +perf-sp1: + @echo "Using SP1_PROVER: ${SP1_PROVER}" + SP1_PROVER=${SP1_PROVER} RUST_LOG=${RUST_LOG} cargo test --release --test perf_zkvm --features build_sp1 -- test_performance_sp1_zkvm --exact --show-output + +perf-sp1-gpu: + @echo "Using SP1_PROVER: ${SP1_PROVER}" + SP1_PROVER=${SP1_PROVER} RUST_LOG=${RUST_LOG} cargo test --release --test perf_zkvm --features "build_sp1, gpu" -- test_performance_sp1_zkvm --exact --show-output +######################################################################## +########## L2 Prover comparison with rsp. Uses GPU by default ########## +######################################################################## ETHREX_L2_BIN := ./target/release/ethrex_l2 RSP_BIN := ./target/release/rsp @@ -36,7 +59,7 @@ rsp_comparison: $(ETHREX_L2_BIN) $(RSP_BIN) >/dev/null $(ETHREX_L2_BIN): - CARGO_TARGET_DIR=target cargo build -r --manifest-path $(ROOT_DIRECTORY)/Cargo.toml --bin ethrex_l2 --features "build_zkvm,gpu,disable-dev-mode" + CARGO_TARGET_DIR=target cargo build -r --manifest-path $(ROOT_DIRECTORY)/Cargo.toml --bin ethrex_l2 --features "build_risc0,gpu,disable-dev-mode" $(RSP_BIN): - git clone https://github.com/succinctlabs/rsp.git diff --git a/crates/l2/prover/src/errors.rs b/crates/l2/prover/src/errors.rs new file mode 100644 index 000000000..2ce1ce6b8 --- /dev/null +++ b/crates/l2/prover/src/errors.rs @@ -0,0 +1,7 @@ +#[derive(Debug, thiserror::Error)] +pub enum ProverError { + #[error("Incorrect ProverType")] + IncorrectProverType, + #[error("{0}")] + Custom(String), +} diff --git a/crates/l2/prover/src/lib.rs b/crates/l2/prover/src/lib.rs index ee528391a..4c99e12fe 100644 --- a/crates/l2/prover/src/lib.rs +++ b/crates/l2/prover/src/lib.rs @@ -1,10 +1,13 @@ +pub mod errors; pub mod prover; pub mod prover_client; -use ethrex_l2::utils::config::prover_client::ProverClientConfig; +use ethrex_l2::{ + proposer::prover_server::ProverType, utils::config::prover_client::ProverClientConfig, +}; use tracing::warn; -pub async fn init_client(config: ProverClientConfig) { - prover_client::start_proof_data_client(config).await; +pub async fn init_client(config: ProverClientConfig, prover_type: ProverType) { + prover_client::start_proof_data_client(config, prover_type).await; warn!("Prover finished!"); } diff --git a/crates/l2/prover/src/main.rs b/crates/l2/prover/src/main.rs index 9eb5ce426..a442c5877 100644 --- a/crates/l2/prover/src/main.rs +++ b/crates/l2/prover/src/main.rs @@ -1,6 +1,9 @@ -use ethrex_l2::utils::config::{prover_client::ProverClientConfig, read_env_file}; +use ethrex_l2::{ + proposer::prover_server::ProverType, + utils::config::{prover_client::ProverClientConfig, read_env_file}, +}; use ethrex_prover_lib::init_client; - +use std::env; use tracing::{self, debug, error, warn, Level}; #[tokio::main] @@ -23,6 +26,26 @@ async fn main() { return; }; + let args: Vec = env::args().collect(); + + let prover_type = match args.len() { + 2 => { + let prover_type_str = args.get(1).map_or("none", |v| v); + match prover_type_str { + "sp1" => ProverType::SP1, + "risc0" => ProverType::RISC0, + _ => { + error!("Wrong argument, try with 'risc0' or 'sp1'."); + return; + } + } + } + _ => { + error!("Try passing 'risc0' or 'sp1' as argument."); + return; + } + }; + debug!("Prover Client has started"); - init_client(config).await; + init_client(config, prover_type).await; } diff --git a/crates/l2/prover/src/prover.rs b/crates/l2/prover/src/prover.rs index f366a61b8..4c408df39 100644 --- a/crates/l2/prover/src/prover.rs +++ b/crates/l2/prover/src/prover.rs @@ -1,38 +1,83 @@ +use crate::errors::ProverError; +use ethrex_l2::proposer::prover_server::{ProverType, ProvingOutput, Risc0Proof, Sp1Proof}; use tracing::info; // risc0 +use risc0_zkvm::{default_prover, ExecutorEnv, ProverOpts}; use zkvm_interface::{ io::{ProgramInput, ProgramOutput}, - methods::{ZKVM_PROGRAM_ELF, ZKVM_PROGRAM_ID}, + methods::ZKVM_SP1_PROGRAM_ELF, + methods::{ZKVM_RISC0_PROGRAM_ELF, ZKVM_RISC0_PROGRAM_ID}, }; -use risc0_zkvm::{default_prover, ExecutorEnv, ProverOpts}; +// sp1 +use sp1_sdk::{ProverClient, SP1Stdin}; -pub struct Prover<'a> { +/// Structure that wraps all the needed components for the RISC0 proving system +pub struct Risc0Prover<'a> { elf: &'a [u8], pub id: [u32; 8], pub stdout: Vec, } -impl<'a> Default for Prover<'a> { +impl<'a> Default for Risc0Prover<'a> { fn default() -> Self { Self::new() } } -impl<'a> Prover<'a> { +/// Structure that wraps all the needed components for the SP1 proving system +pub struct Sp1Prover<'a> { + elf: &'a [u8], +} + +impl<'a> Default for Sp1Prover<'a> { + fn default() -> Self { + Self::new() + } +} + +/// Creates a prover depending on the [ProverType] +pub fn create_prover(prover_type: ProverType) -> Box { + match prover_type { + ProverType::RISC0 => Box::new(Risc0Prover::new()), + ProverType::SP1 => Box::new(Sp1Prover::new()), + } +} + +/// Trait in common with all proving systems, it can be thought as the common interface. +pub trait Prover { + /// Generates the groth16 proof + fn prove(&mut self, input: ProgramInput) -> Result>; + /// Verifies the proof + fn verify(&self, proving_output: &ProvingOutput) -> Result<(), Box>; + /// Gets the EVM gas consumed by the verified block + fn get_gas(&self) -> Result>; +} + +impl<'a> Risc0Prover<'a> { pub fn new() -> Self { Self { - elf: ZKVM_PROGRAM_ELF, - id: ZKVM_PROGRAM_ID, + elf: ZKVM_RISC0_PROGRAM_ELF, + id: ZKVM_RISC0_PROGRAM_ID, stdout: Vec::new(), } } - pub fn prove( - &mut self, - input: ProgramInput, - ) -> Result> { + pub fn get_commitment( + &self, + proving_output: &ProvingOutput, + ) -> Result> { + let commitment = match proving_output { + ProvingOutput::RISC0(proof) => proof.receipt.journal.decode()?, + ProvingOutput::SP1(_) => return Err(Box::new(ProverError::IncorrectProverType)), + }; + Ok(commitment) + } +} + +impl<'a> Prover for Risc0Prover<'a> { + fn prove(&mut self, input: ProgramInput) -> Result> { let env = ExecutorEnv::builder() .stdout(&mut self.stdout) .write(&input)? @@ -49,24 +94,69 @@ impl<'a> Prover<'a> { let receipt = prove_info.receipt; info!("Successfully generated execution receipt."); - Ok(receipt) + Ok(ProvingOutput::RISC0(Risc0Proof::new( + receipt, + self.id.to_vec(), + ))) } - pub fn verify(&self, receipt: &risc0_zkvm::Receipt) -> Result<(), Box> { + fn verify(&self, proving_output: &ProvingOutput) -> Result<(), Box> { // Verify the proof. - receipt.verify(self.id)?; + match proving_output { + ProvingOutput::RISC0(proof) => proof.receipt.verify(self.id)?, + ProvingOutput::SP1(_) => return Err(Box::new(ProverError::IncorrectProverType)), + } + Ok(()) } - pub fn get_gas(&self) -> Result> { + fn get_gas(&self) -> Result> { Ok(risc0_zkvm::serde::from_slice( self.stdout.get(..8).unwrap_or_default(), // first 8 bytes )?) } +} - pub fn get_commitment( - receipt: &risc0_zkvm::Receipt, - ) -> Result> { - Ok(receipt.journal.decode()?) +impl<'a> Sp1Prover<'a> { + pub fn new() -> Self { + Self { + elf: ZKVM_SP1_PROGRAM_ELF, + } + } +} + +impl<'a> Prover for Sp1Prover<'a> { + fn prove(&mut self, input: ProgramInput) -> Result> { + let mut stdin = SP1Stdin::new(); + stdin.write(&input); + + // Generate the ProverClient + let client = ProverClient::new(); + let (pk, vk) = client.setup(self.elf); + + // Proof information by proving the specified ELF binary. + // This struct contains the receipt along with statistics about execution of the guest + let proof = client.prove(&pk, stdin).groth16().run()?; + // Wrap Proof and vk + let sp1_proof = Sp1Proof::new(proof, vk); + info!("Successfully generated SP1Proof."); + Ok(ProvingOutput::SP1(sp1_proof)) + } + + fn verify(&self, proving_output: &ProvingOutput) -> Result<(), Box> { + // Verify the proof. + match proving_output { + ProvingOutput::SP1(complete_proof) => { + let client = ProverClient::new(); + client.verify(&complete_proof.proof, &complete_proof.vk)?; + } + ProvingOutput::RISC0(_) => return Err(Box::new(ProverError::IncorrectProverType)), + } + + Ok(()) + } + + fn get_gas(&self) -> Result> { + todo!() } } diff --git a/crates/l2/prover/src/prover_client.rs b/crates/l2/prover/src/prover_client.rs index 26e4c9af9..dcfe4782a 100644 --- a/crates/l2/prover/src/prover_client.rs +++ b/crates/l2/prover/src/prover_client.rs @@ -1,5 +1,7 @@ +use crate::prover::create_prover; use ethrex_l2::{ - proposer::prover_server::ProofData, utils::config::prover_client::ProverClientConfig, + proposer::prover_server::{ProofData, ProverType, ProvingOutput}, + utils::config::prover_client::ProverClientConfig, }; use std::{ io::{BufReader, BufWriter}, @@ -10,11 +12,14 @@ use tokio::time::sleep; use tracing::{debug, error, info, warn}; use zkvm_interface::io::ProgramInput; -use super::prover::Prover; - -pub async fn start_proof_data_client(config: ProverClientConfig) { +pub async fn start_proof_data_client(config: ProverClientConfig, prover_type: ProverType) { let proof_data_client = ProverClient::new(config); - proof_data_client.start().await; + proof_data_client.start(prover_type).await; +} + +struct ProverData { + block_number: u64, + input: ProgramInput, } struct ProverClient { @@ -30,16 +35,19 @@ impl ProverClient { } } - pub async fn start(&self) { - let mut prover = Prover::new(); + pub async fn start(&self, prover_type: ProverType) { + // Build the prover depending on the prover_type passed as argument. + let mut prover = create_prover(prover_type); loop { match self.request_new_input() { - Ok((block_number, input)) => { - match prover.prove(input) { - Ok(proof) => { + // If we get the input + Ok(prover_data) => { + // Generate the Proof + match prover.prove(prover_data.input) { + Ok(proving_output) => { if let Err(e) = - self.submit_proof(block_number, proof, prover.id.to_vec()) + self.submit_proof(prover_data.block_number, proving_output) { // TODO: Retry? warn!("Failed to submit proof: {e}"); @@ -56,7 +64,7 @@ impl ProverClient { } } - fn request_new_input(&self) -> Result<(u64, ProgramInput), String> { + fn request_new_input(&self) -> Result { // Request the input with the correct block_number let request = ProofData::request(); let response = connect_to_prover_server_wr(&self.prover_server_endpoint, &request) @@ -67,30 +75,37 @@ impl ProverClient { block_number, input, } => match (block_number, input) { - (Some(n), Some(i)) => { - info!("Received Response for block_number: {n}"); - Ok((n, ProgramInput { - block: i.block, - parent_block_header: i.parent_block_header, - db: i.db - })) + (Some(block_number), Some(input)) => { + info!("Received Response for block_number: {block_number}"); + let prover_data = ProverData{ + block_number, + input: ProgramInput { + block: input.block, + parent_block_header: input.parent_block_header, + db: input.db + } + }; + Ok(prover_data) } _ => Err( "Received Empty Response, meaning that the ProverServer doesn't have blocks to prove.\nThe Prover may be advancing faster than the Proposer." .to_owned(), ), }, - _ => Err(format!("Expecting ProofData::Response {response:?}")), + _ => Err("Expecting ProofData::Response".to_owned()), } } - fn submit_proof( - &self, - block_number: u64, - receipt: risc0_zkvm::Receipt, - prover_id: Vec, - ) -> Result<(), String> { - let submit = ProofData::submit(block_number, (receipt, prover_id)); + fn submit_proof(&self, block_number: u64, proving_output: ProvingOutput) -> Result<(), String> { + let submit = match proving_output { + ProvingOutput::RISC0(risc0_proof) => { + ProofData::submit(block_number, ProvingOutput::RISC0(risc0_proof)) + } + ProvingOutput::SP1(sp1_proof) => { + ProofData::submit(block_number, ProvingOutput::SP1(sp1_proof)) + } + }; + let submit_ack = connect_to_prover_server_wr(&self.prover_server_endpoint, &submit) .map_err(|e| format!("Failed to get SubmitAck: {e}"))?; @@ -99,7 +114,7 @@ impl ProverClient { info!("Received submit ack for block_number: {}", block_number); Ok(()) } - _ => Err(format!("Expecting ProofData::SubmitAck {submit_ack:?}")), + _ => Err("Expecting ProofData::SubmitAck".to_owned()), } } } diff --git a/crates/l2/prover/tests/perf_zkvm.rs b/crates/l2/prover/tests/perf_zkvm.rs index 0ce7740ed..a43288b87 100644 --- a/crates/l2/prover/tests/perf_zkvm.rs +++ b/crates/l2/prover/tests/perf_zkvm.rs @@ -1,9 +1,11 @@ #![allow(clippy::expect_used)] +#![allow(clippy::unwrap_used)] +use ethrex_core::types::Block; use std::path::Path; use tracing::info; use ethrex_blockchain::add_block; -use ethrex_prover_lib::prover::Prover; +use ethrex_prover_lib::prover::{Prover, Risc0Prover, Sp1Prover}; use ethrex_storage::{EngineType, Store}; use ethrex_vm::execution_db::ExecutionDB; use zkvm_interface::io::ProgramInput; @@ -12,6 +14,51 @@ use zkvm_interface::io::ProgramInput; async fn test_performance_zkvm() { tracing_subscriber::fmt::init(); + let (input, block_to_prove) = setup().await; + + let mut prover = Risc0Prover::new(); + + let start = std::time::Instant::now(); + + let receipt = prover.prove(input).unwrap(); + + let duration = start.elapsed(); + info!( + "Number of EIP1559 transactions in the proven block: {}", + block_to_prove.body.transactions.len() + ); + info!("[SECONDS] Proving Took: {:?}", duration); + info!("[MINUTES] Proving Took: {}[m]", duration.as_secs() / 60); + + prover.verify(&receipt).unwrap(); + + let _program_output = prover.get_commitment(&receipt).unwrap(); +} + +#[tokio::test] +async fn test_performance_sp1_zkvm() { + tracing_subscriber::fmt::init(); + + let (input, block_to_prove) = setup().await; + + let mut prover = Sp1Prover::new(); + + let start = std::time::Instant::now(); + + let output = prover.prove(input).unwrap(); + + let duration = start.elapsed(); + info!( + "Number of EIP1559 transactions in the proven block: {}", + block_to_prove.body.transactions.len() + ); + info!("[SECONDS] Proving Took: {:?}", duration); + info!("[MINUTES] Proving Took: {}[m]", duration.as_secs() / 60); + + prover.verify(&output).unwrap(); +} + +async fn setup() -> (ProgramInput, Block) { let path = Path::new(concat!(env!("CARGO_MANIFEST_DIR"), "/../../../test_data")); // Another use is genesis-execution-api.json in conjunction with chain.rlp(20 blocks not too loaded). @@ -45,22 +92,5 @@ async fn test_performance_zkvm() { parent_block_header, db, }; - - let mut prover = Prover::new(); - - let start = std::time::Instant::now(); - - let receipt = prover.prove(input).unwrap(); - - let duration = start.elapsed(); - info!( - "Number of EIP1559 transactions in the proven block: {}", - block_to_prove.body.transactions.len() - ); - info!("[SECONDS] Proving Took: {:?}", duration); - info!("[MINUTES] Proving Took: {}[m]", duration.as_secs() / 60); - - prover.verify(&receipt).unwrap(); - - let _program_output = Prover::get_commitment(&receipt).unwrap(); + (input, block_to_prove.clone()) } diff --git a/crates/l2/prover/zkvm/interface/Cargo.toml b/crates/l2/prover/zkvm/interface/Cargo.toml index c1b09c65b..a207f9709 100644 --- a/crates/l2/prover/zkvm/interface/Cargo.toml +++ b/crates/l2/prover/zkvm/interface/Cargo.toml @@ -16,13 +16,16 @@ ethrex-trie = { path = "../../../../storage/trie", default-features = false } [build-dependencies] risc0-build = { version = "1.2.0" } +sp1-build = "3.4.0" [package.metadata.risc0] -methods = ["guest"] +methods = ["risc0"] [features] default = [] -build_zkvm = [] +build_risc0 = [] +build_sp1 = [] + [lib] path = "./src/lib.rs" diff --git a/crates/l2/prover/zkvm/interface/build.rs b/crates/l2/prover/zkvm/interface/build.rs index 5dc8be1ee..78dcdd988 100644 --- a/crates/l2/prover/zkvm/interface/build.rs +++ b/crates/l2/prover/zkvm/interface/build.rs @@ -1,5 +1,9 @@ fn main() { #[cfg(not(clippy))] - #[cfg(feature = "build_zkvm")] + #[cfg(feature = "build_risc0")] risc0_build::embed_methods(); + + #[cfg(not(clippy))] + #[cfg(feature = "build_sp1")] + sp1_build::build_program("./sp1"); } diff --git a/crates/l2/prover/zkvm/interface/guest/Cargo.toml b/crates/l2/prover/zkvm/interface/risc0/Cargo.toml similarity index 97% rename from crates/l2/prover/zkvm/interface/guest/Cargo.toml rename to crates/l2/prover/zkvm/interface/risc0/Cargo.toml index a4b709c0c..6b9dc2289 100644 --- a/crates/l2/prover/zkvm/interface/guest/Cargo.toml +++ b/crates/l2/prover/zkvm/interface/risc0/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "zkvm_program" +name = "zkvm-risc0-program" version = "0.1.0" edition = "2021" diff --git a/crates/l2/prover/zkvm/NOTICE b/crates/l2/prover/zkvm/interface/risc0/NOTICE similarity index 100% rename from crates/l2/prover/zkvm/NOTICE rename to crates/l2/prover/zkvm/interface/risc0/NOTICE diff --git a/crates/l2/prover/zkvm/interface/guest/src/main.rs b/crates/l2/prover/zkvm/interface/risc0/src/main.rs similarity index 89% rename from crates/l2/prover/zkvm/interface/guest/src/main.rs rename to crates/l2/prover/zkvm/interface/risc0/src/main.rs index e4c2569bf..c4c9b6251 100644 --- a/crates/l2/prover/zkvm/interface/guest/src/main.rs +++ b/crates/l2/prover/zkvm/interface/risc0/src/main.rs @@ -31,12 +31,12 @@ fn main() { let receipts = execute_block(&block, &mut state).expect("failed to execute block"); validate_gas_used(&receipts, &block.header).expect("invalid gas used"); - env::write( - &receipts - .last() - .expect("no receipts found") - .cumulative_gas_used, - ); + let cumulative_gas_used = match receipts.last() { + Some(last_receipt) => last_receipt.cumulative_gas_used, + None => 0_u64, + }; + + env::write(&cumulative_gas_used); let account_updates = get_state_transitions(&mut state); diff --git a/crates/l2/prover/zkvm/interface/sp1/Cargo.toml b/crates/l2/prover/zkvm/interface/sp1/Cargo.toml new file mode 100644 index 000000000..97a6fbfe4 --- /dev/null +++ b/crates/l2/prover/zkvm/interface/sp1/Cargo.toml @@ -0,0 +1,25 @@ +[package] +version = "0.1.0" +name = "zkvm-sp1-program" +edition = "2021" + +[workspace] + +[dependencies] +sp1-zkvm = "3.4.0" +zkvm_interface = { path = "../" } + +ethrex-core = { path = "../../../../../common", default-features = false } +ethrex-rlp = { path = "../../../../../common/rlp" } +ethrex-vm = { path = "../../../../../vm", default-features = false, features = [ + "l2", +] } +ethrex-blockchain = { path = "../../../../../blockchain", default-features = false } + +[patch.crates-io] +sha3 = { git = "https://github.com/sp1-patches/RustCrypto-hashes", branch = "patch-sha3-v0.10.8", package = "sha3" } +crypto-bigint = { git = "https://github.com/sp1-patches/RustCrypto-bigint", branch = "patch-v0.5.5" } +secp256k1 = { git = "https://github.com/sp1-patches/rust-secp256k1", branch = "patch-secp256k1-v0.29.0" } +sha2 = { git = "https://github.com/sp1-patches/RustCrypto-hashes", branch = "patch-v0.10.8", package = "sha2" } +ecdsa-core = { git = "https://github.com/sp1-patches/signatures", package = "ecdsa", branch = "patch-ecdsa-v0.16.9" } +tiny-keccak = { git = "https://github.com/sp1-patches/tiny-keccak", branch = "patch-v2.0.2" } diff --git a/crates/l2/prover/zkvm/interface/sp1/NOTICE b/crates/l2/prover/zkvm/interface/sp1/NOTICE new file mode 100644 index 000000000..6c440f936 --- /dev/null +++ b/crates/l2/prover/zkvm/interface/sp1/NOTICE @@ -0,0 +1,32 @@ +# APACHE NOTICE +Original work Copyright [Succinct Labs] +Copyright [2024] [LambdaClass] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + + +# MIT NOTICE +The MIT License (MIT) + +Original work Copyright (c) 2023 Succinct Labs +Copyright [2024] [LambdaClass] + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. diff --git a/crates/l2/prover/zkvm/interface/sp1/elf/riscv32im-succinct-zkvm-elf b/crates/l2/prover/zkvm/interface/sp1/elf/riscv32im-succinct-zkvm-elf new file mode 100755 index 000000000..a6fe4d635 Binary files /dev/null and b/crates/l2/prover/zkvm/interface/sp1/elf/riscv32im-succinct-zkvm-elf differ diff --git a/crates/l2/prover/zkvm/interface/sp1/src/main.rs b/crates/l2/prover/zkvm/interface/sp1/src/main.rs new file mode 100644 index 000000000..2ee7abe18 --- /dev/null +++ b/crates/l2/prover/zkvm/interface/sp1/src/main.rs @@ -0,0 +1,59 @@ +#![no_main] + +use ethrex_blockchain::{validate_block, validate_gas_used}; +use ethrex_vm::{execute_block, get_state_transitions, EvmState}; +use zkvm_interface::{ + io::{ProgramInput, ProgramOutput}, + trie::update_tries, +}; + +sp1_zkvm::entrypoint!(main); + +pub fn main() { + let ProgramInput { + block, + parent_block_header, + db, + } = sp1_zkvm::io::read::(); + + let mut state = EvmState::from(db.clone()); + + // Validate the block pre-execution + validate_block(&block, &parent_block_header, &state).expect("invalid block"); + + // Validate the initial state + let (mut state_trie, mut storage_tries) = db + .build_tries() + .expect("failed to build state and storage tries or state is not valid"); + + let initial_state_hash = state_trie.hash_no_commit(); + if initial_state_hash != parent_block_header.state_root { + panic!("invalid initial state trie"); + } + + let receipts = execute_block(&block, &mut state).expect("failed to execute block"); + validate_gas_used(&receipts, &block.header).expect("invalid gas used"); + + let cumulative_gas_used = match receipts.last() { + Some(last_receipt) => last_receipt.cumulative_gas_used, + None => 0_u64, + }; + + sp1_zkvm::io::commit(&cumulative_gas_used); + + let account_updates = get_state_transitions(&mut state); + + // Update tries and calculate final state root hash + update_tries(&mut state_trie, &mut storage_tries, &account_updates) + .expect("failed to update state and storage tries"); + let final_state_hash = state_trie.hash_no_commit(); + + if final_state_hash != block.header.state_root { + panic!("invalid final state trie"); + } + + sp1_zkvm::io::commit(&ProgramOutput { + initial_state_hash, + final_state_hash, + }); +} diff --git a/crates/l2/prover/zkvm/interface/src/lib.rs b/crates/l2/prover/zkvm/interface/src/lib.rs index bbadd459e..078ef26d8 100644 --- a/crates/l2/prover/zkvm/interface/src/lib.rs +++ b/crates/l2/prover/zkvm/interface/src/lib.rs @@ -1,11 +1,18 @@ pub mod methods { - #[cfg(any(clippy, not(feature = "build_zkvm")))] - pub const ZKVM_PROGRAM_ELF: &[u8] = &[0]; - #[cfg(any(clippy, not(feature = "build_zkvm")))] - pub const ZKVM_PROGRAM_ID: [u32; 8] = [0_u32; 8]; + #[cfg(any(clippy, not(feature = "build_risc0")))] + pub const ZKVM_RISC0_PROGRAM_ELF: &[u8] = &[0]; + #[cfg(any(clippy, not(feature = "build_risc0")))] + pub const ZKVM_RISC0_PROGRAM_ID: [u32; 8] = [0_u32; 8]; - #[cfg(all(not(clippy), feature = "build_zkvm"))] + #[cfg(all(not(clippy), feature = "build_risc0"))] include!(concat!(env!("OUT_DIR"), "/methods.rs")); + + #[cfg(all(not(clippy), feature = "build_sp1"))] + pub const ZKVM_SP1_PROGRAM_ELF: &[u8] = + include_bytes!("../sp1/elf/riscv32im-succinct-zkvm-elf"); + + #[cfg(any(clippy, not(feature = "build_sp1")))] + pub const ZKVM_SP1_PROGRAM_ELF: &[u8] = &[0]; } pub mod io { diff --git a/crates/l2/utils/config/errors.rs b/crates/l2/utils/config/errors.rs index 95bd3479c..b5ae77baa 100644 --- a/crates/l2/utils/config/errors.rs +++ b/crates/l2/utils/config/errors.rs @@ -14,4 +14,6 @@ pub enum ConfigError { BuildProposerEngineServerFromConfigError(#[from] engine_client::errors::ConfigError), #[error("Error building Prover server from config: {0}")] BuildProverServerFromConfigError(#[from] EthClientError), + #[error("{0}")] + Custom(String), } diff --git a/crates/l2/utils/eth_client/mod.rs b/crates/l2/utils/eth_client/mod.rs index b34f54137..f27d5e801 100644 --- a/crates/l2/utils/eth_client/mod.rs +++ b/crates/l2/utils/eth_client/mod.rs @@ -974,6 +974,18 @@ impl EthClient { .await } + pub async fn get_next_block_to_commit( + eth_client: &EthClient, + on_chain_proposer_address: Address, + ) -> Result { + Self::_call_block_variable( + eth_client, + b"nextBlockToCommit()", + on_chain_proposer_address, + ) + .await + } + pub async fn get_last_verified_block( eth_client: &EthClient, on_chain_proposer_address: Address, diff --git a/crates/networking/p2p/rlpx/connection.rs b/crates/networking/p2p/rlpx/connection.rs index 0e97fcd26..06e416125 100644 --- a/crates/networking/p2p/rlpx/connection.rs +++ b/crates/networking/p2p/rlpx/connection.rs @@ -6,6 +6,7 @@ use crate::{ eth::{ backend, blocks::{BlockBodies, BlockHeaders}, + receipts::Receipts, transactions::Transactions, }, handshake::encode_ack_message, @@ -22,6 +23,7 @@ use crate::{ use super::{ error::RLPxError, + eth::receipts::GetReceipts, eth::transactions::GetPooledTransactions, frame, handshake::{decode_ack_message, decode_auth_message, encode_auth_message}, @@ -379,6 +381,17 @@ impl RLPxConnection { }; self.send(Message::BlockBodies(response)).await?; } + Message::GetReceipts(GetReceipts { id, block_hashes }) if peer_supports_eth => { + let receipts: Result<_, _> = block_hashes + .iter() + .map(|hash| self.storage.get_receipts_for_block(hash)) + .collect(); + let response = Receipts { + id, + receipts: receipts?, + }; + self.send(Message::Receipts(response)).await?; + } Message::NewPooledTransactionHashes(new_pooled_transaction_hashes) if peer_supports_eth => { diff --git a/crates/networking/p2p/rlpx/eth/backend.rs b/crates/networking/p2p/rlpx/eth/backend.rs index 9ba059dcd..a76d9f03a 100644 --- a/crates/networking/p2p/rlpx/eth/backend.rs +++ b/crates/networking/p2p/rlpx/eth/backend.rs @@ -16,9 +16,7 @@ pub fn get_status(storage: &Store) -> Result { let genesis_header = storage .get_block_header(0)? .ok_or(RLPxError::NotFound("Genesis Block".to_string()))?; - let block_number = storage - .get_latest_block_number()? - .ok_or(RLPxError::NotFound("Latest Block Number".to_string()))?; + let block_number = storage.get_latest_block_number()?; let block_header = storage .get_block_header(block_number)? .ok_or(RLPxError::NotFound(format!("Block {block_number}")))?; @@ -43,9 +41,7 @@ pub fn validate_status(msg_data: StatusMessage, storage: &Store) -> Result<(), R let genesis_header = storage .get_block_header(0)? .ok_or(RLPxError::NotFound("Genesis Block".to_string()))?; - let block_number = storage - .get_latest_block_number()? - .ok_or(RLPxError::NotFound("Latest Block Number".to_string()))?; + let block_number = storage.get_latest_block_number()?; let block_header = storage .get_block_header(block_number)? .ok_or(RLPxError::NotFound(format!("Block {block_number}")))?; diff --git a/crates/networking/p2p/rlpx/eth/receipts.rs b/crates/networking/p2p/rlpx/eth/receipts.rs index 6c02119d8..f3e3b1150 100644 --- a/crates/networking/p2p/rlpx/eth/receipts.rs +++ b/crates/networking/p2p/rlpx/eth/receipts.rs @@ -14,8 +14,8 @@ use ethrex_rlp::{ pub(crate) struct GetReceipts { // id is a u64 chosen by the requesting peer, the responding peer must mirror the value for the response // https://github.com/ethereum/devp2p/blob/master/caps/eth.md#protocol-messages - id: u64, - block_hashes: Vec, + pub id: u64, + pub block_hashes: Vec, } impl GetReceipts { @@ -52,8 +52,8 @@ impl RLPxMessage for GetReceipts { pub(crate) struct Receipts { // id is a u64 chosen by the requesting peer, the responding peer must mirror the value for the response // https://github.com/ethereum/devp2p/blob/master/caps/eth.md#protocol-messages - id: u64, - receipts: Vec>, + pub id: u64, + pub receipts: Vec>, } impl Receipts { diff --git a/crates/networking/p2p/rlpx/message.rs b/crates/networking/p2p/rlpx/message.rs index 7176cf96b..7a1ab1141 100644 --- a/crates/networking/p2p/rlpx/message.rs +++ b/crates/networking/p2p/rlpx/message.rs @@ -3,7 +3,7 @@ use ethrex_rlp::error::{RLPDecodeError, RLPEncodeError}; use std::fmt::Display; use super::eth::blocks::{BlockBodies, BlockHeaders, GetBlockBodies, GetBlockHeaders}; -use super::eth::receipts::Receipts; +use super::eth::receipts::{GetReceipts, Receipts}; use super::eth::status::StatusMessage; use super::eth::transactions::{GetPooledTransactions, NewPooledTransactionHashes, Transactions}; use super::p2p::{DisconnectMessage, HelloMessage, PingMessage, PongMessage}; @@ -32,9 +32,10 @@ pub(crate) enum Message { Transactions(Transactions), GetBlockBodies(GetBlockBodies), BlockBodies(BlockBodies), + GetReceipts(GetReceipts), + Receipts(Receipts), NewPooledTransactionHashes(NewPooledTransactionHashes), GetPooledTransactions(GetPooledTransactions), - Receipts(Receipts), // snap capability GetAccountRange(GetAccountRange), AccountRange(AccountRange), @@ -75,6 +76,7 @@ impl Message { 0x19 => Ok(Message::GetPooledTransactions( GetPooledTransactions::decode(msg_data)?, )), + 0x1F => Ok(Message::GetReceipts(GetReceipts::decode(msg_data)?)), 0x20 => Ok(Message::Receipts(Receipts::decode(msg_data)?)), 0x21 => Ok(Message::GetAccountRange(GetAccountRange::decode(msg_data)?)), 0x22 => Ok(Message::AccountRange(AccountRange::decode(msg_data)?)), @@ -140,6 +142,10 @@ impl Message { 0x19_u8.encode(buf); msg.encode(buf) } + Message::GetReceipts(msg) => { + 0x1F_u8.encode(buf); + msg.encode(buf) + } Message::Receipts(msg) => { 0x20_u8.encode(buf); msg.encode(buf) @@ -195,6 +201,7 @@ impl Display for Message { Message::GetPooledTransactions(_) => "eth::GetPooledTransactions".fmt(f), Message::Transactions(_) => "eth:TransactionsMessage".fmt(f), Message::GetBlockBodies(_) => "eth:GetBlockBodies".fmt(f), + Message::GetReceipts(_) => "eth:GetReceipts".fmt(f), Message::Receipts(_) => "eth:Receipts".fmt(f), Message::GetAccountRange(_) => "snap:GetAccountRange".fmt(f), Message::AccountRange(_) => "snap:AccountRange".fmt(f), diff --git a/crates/networking/rpc/engine/fork_choice.rs b/crates/networking/rpc/engine/fork_choice.rs index 6cc7d0d9e..a7ece628c 100644 --- a/crates/networking/rpc/engine/fork_choice.rs +++ b/crates/networking/rpc/engine/fork_choice.rs @@ -130,8 +130,8 @@ fn parse( let forkchoice_state: ForkChoiceState = serde_json::from_value(params[0].clone())?; // if there is an error when parsing, set to None let payload_attributes: Option = - match serde_json::from_value::(params[1].clone()) { - Ok(attributes) => Some(attributes), + match serde_json::from_value::>(params[1].clone()) { + Ok(attributes) => attributes, Err(error) => { info!("Could not parse params {}", error); None @@ -175,7 +175,7 @@ fn handle_forkchoice( } InvalidForkChoice::Syncing => { // Start sync - let current_number = context.storage.get_latest_block_number()?.unwrap(); + let current_number = context.storage.get_latest_block_number()?; let Some(current_head) = context.storage.get_canonical_block_hash(current_number)? else { diff --git a/crates/networking/rpc/eth/block.rs b/crates/networking/rpc/eth/block.rs index fe014cc79..b226a390f 100644 --- a/crates/networking/rpc/eth/block.rs +++ b/crates/networking/rpc/eth/block.rs @@ -297,7 +297,7 @@ impl RpcHandler for GetRawReceipts { }; let receipts: Vec = get_all_block_receipts(block_number, header, body, storage)? .iter() - .map(|receipt| format!("0x{}", hex::encode(receipt.encode_to_vec()))) + .map(|receipt| format!("0x{}", hex::encode(receipt.encode_inner()))) .collect(); serde_json::to_value(receipts).map_err(|error| RpcErr::Internal(error.to_string())) } @@ -310,12 +310,8 @@ impl RpcHandler for BlockNumberRequest { fn handle(&self, context: RpcApiContext) -> Result { info!("Requested latest block number"); - match context.storage.get_latest_block_number() { - Ok(Some(block_number)) => serde_json::to_value(format!("{:#x}", block_number)) - .map_err(|error| RpcErr::Internal(error.to_string())), - Ok(None) => Err(RpcErr::Internal("No blocks found".to_owned())), - Err(error) => Err(RpcErr::Internal(error.to_string())), - } + serde_json::to_value(format!("{:#x}", context.storage.get_latest_block_number()?)) + .map_err(|error| RpcErr::Internal(error.to_string())) } } @@ -326,25 +322,19 @@ impl RpcHandler for GetBlobBaseFee { fn handle(&self, context: RpcApiContext) -> Result { info!("Requested blob gas price"); - match context.storage.get_latest_block_number() { - Ok(Some(block_number)) => { - let header = match context.storage.get_block_header(block_number)? { - Some(header) => header, - _ => return Err(RpcErr::Internal("Could not get block header".to_owned())), - }; - let parent_header = match find_parent_header(&header, &context.storage) { - Ok(header) => header, - Err(error) => return Err(RpcErr::Internal(error.to_string())), - }; - let blob_base_fee = calculate_base_fee_per_blob_gas( - parent_header.excess_blob_gas.unwrap_or_default(), - ); - serde_json::to_value(format!("{:#x}", blob_base_fee)) - .map_err(|error| RpcErr::Internal(error.to_string())) - } - Ok(None) => Err(RpcErr::Internal("No blocks found".to_owned())), - Err(error) => Err(RpcErr::Internal(error.to_string())), - } + let block_number = context.storage.get_latest_block_number()?; + let header = match context.storage.get_block_header(block_number)? { + Some(header) => header, + _ => return Err(RpcErr::Internal("Could not get block header".to_owned())), + }; + let parent_header = match find_parent_header(&header, &context.storage) { + Ok(header) => header, + Err(error) => return Err(RpcErr::Internal(error.to_string())), + }; + let blob_base_fee = + calculate_base_fee_per_blob_gas(parent_header.excess_blob_gas.unwrap_or_default()); + serde_json::to_value(format!("{:#x}", blob_base_fee)) + .map_err(|error| RpcErr::Internal(error.to_string())) } } diff --git a/crates/networking/rpc/eth/fee_market.rs b/crates/networking/rpc/eth/fee_market.rs index ea01ce612..f926551eb 100644 --- a/crates/networking/rpc/eth/fee_market.rs +++ b/crates/networking/rpc/eth/fee_market.rs @@ -157,16 +157,10 @@ impl FeeHistoryRequest { // TODO: We should probably restrict how many blocks we are fetching to a certain limit // Get earliest block - let earliest_block_num = storage - .get_earliest_block_number()? - .ok_or(RpcErr::Internal( - "Could not get earliest block number".to_owned(), - ))?; + let earliest_block_num = storage.get_earliest_block_number()?; // Get latest block - let latest_block_num = storage.get_latest_block_number()?.ok_or(RpcErr::Internal( - "Could not get latest block number".to_owned(), - ))?; + let latest_block_num = storage.get_latest_block_number()?; // Get finish_block number let finish_block = finish_block diff --git a/crates/networking/rpc/eth/filter.rs b/crates/networking/rpc/eth/filter.rs index 197dbc02b..74dbdb500 100644 --- a/crates/networking/rpc/eth/filter.rs +++ b/crates/networking/rpc/eth/filter.rs @@ -85,10 +85,7 @@ impl NewFilterRequest { return Err(RpcErr::BadParams("Invalid block range".to_string())); } - let Some(last_block_number) = storage.get_latest_block_number()? else { - error!("Latest block number was requested but it does not exist"); - return Err(RpcErr::Internal("Failed to create filter".to_string())); - }; + let last_block_number = storage.get_latest_block_number()?; let id: u64 = random(); let timestamp = Instant::now(); let mut active_filters_guard = filters.lock().unwrap_or_else(|mut poisoned_guard| { @@ -188,10 +185,7 @@ impl FilterChangesRequest { storage: ethrex_storage::Store, filters: ActiveFilters, ) -> Result { - let Some(latest_block_num) = storage.get_latest_block_number()? else { - error!("Latest block number was requested but it does not exist"); - return Err(RpcErr::Internal("Failed to create filter".to_string())); - }; + let latest_block_num = storage.get_latest_block_number()?; let mut active_filters_guard = filters.lock().unwrap_or_else(|mut poisoned_guard| { error!("THREAD CRASHED WITH MUTEX TAKEN; SYSTEM MIGHT BE UNSTABLE"); **poisoned_guard.get_mut() = HashMap::new(); diff --git a/crates/networking/rpc/eth/gas_price.rs b/crates/networking/rpc/eth/gas_price.rs index c34122654..cac45e1c2 100644 --- a/crates/networking/rpc/eth/gas_price.rs +++ b/crates/networking/rpc/eth/gas_price.rs @@ -41,10 +41,7 @@ impl RpcHandler for GasPrice { /// Estimate Gas Price based on already accepted transactions, /// as per the spec, this will be returned in wei. fn handle(&self, context: RpcApiContext) -> Result { - let Some(latest_block_number) = context.storage.get_latest_block_number()? else { - error!("FATAL: LATEST BLOCK NUMBER IS MISSING"); - return Err(RpcErr::Internal("Error calculating gas price".to_string())); - }; + let latest_block_number = context.storage.get_latest_block_number()?; let block_range_lower_bound = latest_block_number.saturating_sub(BLOCK_RANGE_LOWER_BOUND_DEC); // These are the blocks we'll use to estimate the price. diff --git a/crates/networking/rpc/eth/transaction.rs b/crates/networking/rpc/eth/transaction.rs index 2e3d0b076..d19b4c023 100644 --- a/crates/networking/rpc/eth/transaction.rs +++ b/crates/networking/rpc/eth/transaction.rs @@ -277,6 +277,7 @@ impl RpcHandler for GetTransactionReceiptRequest { }; let receipts = block::get_all_block_rpc_receipts(block_number, block.header, block.body, storage)?; + serde_json::to_value(receipts.get(index as usize)) .map_err(|error| RpcErr::Internal(error.to_string())) } diff --git a/crates/networking/rpc/types/block_identifier.rs b/crates/networking/rpc/types/block_identifier.rs index b74963820..d741a4cf7 100644 --- a/crates/networking/rpc/types/block_identifier.rs +++ b/crates/networking/rpc/types/block_identifier.rs @@ -35,10 +35,10 @@ impl BlockIdentifier { match self { BlockIdentifier::Number(num) => Ok(Some(*num)), BlockIdentifier::Tag(tag) => match tag { - BlockTag::Earliest => storage.get_earliest_block_number(), + BlockTag::Earliest => Ok(Some(storage.get_earliest_block_number()?)), BlockTag::Finalized => storage.get_finalized_block_number(), BlockTag::Safe => storage.get_safe_block_number(), - BlockTag::Latest => storage.get_latest_block_number(), + BlockTag::Latest => Ok(Some(storage.get_latest_block_number()?)), BlockTag::Pending => { // TODO(#1112): We need to check individual intrincacies of the pending tag for // each RPC method that uses it. @@ -47,7 +47,7 @@ impl BlockIdentifier { // If there are no pending blocks, we return the latest block number .and_then(|pending_block_number| match pending_block_number { Some(block_number) => Ok(Some(block_number)), - None => storage.get_latest_block_number(), + None => Ok(Some(storage.get_latest_block_number()?)), }) } }, @@ -114,10 +114,8 @@ impl BlockIdentifierOrHash { let result = self.resolve_block_number(storage)?; let latest = storage.get_latest_block_number()?; - match (result, latest) { - (Some(result), Some(latest)) => Ok(result == latest), - _ => Ok(false), - } + + Ok(result.is_some_and(|res| res == latest)) } } diff --git a/crates/storage/store/engines/api.rs b/crates/storage/store/engines/api.rs index 18b71ccad..a9cca6e76 100644 --- a/crates/storage/store/engines/api.rs +++ b/crates/storage/store/engines/api.rs @@ -240,4 +240,6 @@ pub trait StoreEngine: Debug + Send + Sync + RefUnwindSafe { blobs_bundle: BlobsBundle, completed: bool, ) -> Result<(), StoreError>; + + fn get_receipts_for_block(&self, block_hash: &BlockHash) -> Result, StoreError>; } diff --git a/crates/storage/store/engines/in_memory.rs b/crates/storage/store/engines/in_memory.rs index 681581774..767d6a62a 100644 --- a/crates/storage/store/engines/in_memory.rs +++ b/crates/storage/store/engines/in_memory.rs @@ -355,6 +355,23 @@ impl StoreEngine for Store { Ok(self.inner().payloads.get(&payload_id).cloned()) } + fn get_receipts_for_block(&self, block_hash: &BlockHash) -> Result, StoreError> { + let store = self.inner(); + let Some(receipts_for_block) = store.receipts.get(block_hash) else { + return Ok(vec![]); + }; + let mut receipts = receipts_for_block + .iter() + .collect::>(); + + receipts.sort_by_key(|(index, _receipt)| **index); + + Ok(receipts + .into_iter() + .map(|(_index, receipt)| receipt.clone()) + .collect()) + } + fn add_receipts( &self, block_hash: BlockHash, diff --git a/crates/storage/store/engines/libmdbx.rs b/crates/storage/store/engines/libmdbx.rs index 1d2a49c5f..350ae640b 100644 --- a/crates/storage/store/engines/libmdbx.rs +++ b/crates/storage/store/engines/libmdbx.rs @@ -494,6 +494,34 @@ impl StoreEngine for Store { self.write_batch::(key_values) } + + fn get_receipts_for_block( + &self, + block_hash: &BlockHash, + ) -> std::result::Result, StoreError> { + let mut receipts = vec![]; + let mut receipt_index = 0; + let mut key: TupleRLP = (*block_hash, 0).into(); + let txn = self.db.begin_read().map_err(|_| StoreError::ReadError)?; + let mut cursor = txn + .cursor::() + .map_err(|_| StoreError::CursorError("Receipts".to_owned()))?; + + // We're searching receipts for a block, the keys + // for the receipt table are of the kind: rlp((BlockHash, Index)). + // So we search for values in the db that match with this kind + // of key, until we reach an Index that returns None + // and we stop the search. + while let Some((_, encoded_receipt)) = + cursor.seek_exact(key).map_err(|_| StoreError::ReadError)? + { + receipts.push(encoded_receipt); + receipt_index += 1; + key = (*block_hash, receipt_index).into(); + } + + Ok(receipts.into_iter().map(|receipt| receipt.to()).collect()) + } } impl Debug for Store { diff --git a/crates/storage/store/engines/redb.rs b/crates/storage/store/engines/redb.rs index 085846b92..17c4b8e81 100644 --- a/crates/storage/store/engines/redb.rs +++ b/crates/storage/store/engines/redb.rs @@ -650,6 +650,35 @@ impl StoreEngine for RedBStore { ), ) } + + fn get_receipts_for_block( + &self, + block_hash: &BlockHash, + ) -> std::result::Result, StoreError> { + let mut encoded_receipts = vec![]; + let mut receipt_index = 0; + let read_tx = self.db.begin_read()?; + let mut expected_key: TupleRLP = (*block_hash, 0).into(); + let table = read_tx.open_table(RECEIPTS_TABLE)?; + // We're searching receipts for a block, the keys + // for the receipt table are of the kind: rlp((BlockHash, Index)). + // So we search for values in the db that match with this kind + // of key, until we reach an Index that returns None + // and we stop the search. + // TODO(#1436): Make sure this if this is the proper way of + // doing a search for each key, libmdbx has cursors + // for this purpose, we should do the equal here, + // if this approach is not correct. + while let Some(access_guard) = table.get(&expected_key)? { + encoded_receipts.push(access_guard.value()); + receipt_index += 1; + expected_key = (*block_hash, receipt_index).into() + } + Ok(encoded_receipts + .into_iter() + .map(|receipt| receipt.to()) + .collect()) + } } impl redb::Value for ChainDataIndex { diff --git a/crates/storage/store/error.rs b/crates/storage/store/error.rs index 253b071a6..aaa70dfa0 100644 --- a/crates/storage/store/error.rs +++ b/crates/storage/store/error.rs @@ -38,4 +38,12 @@ pub enum StoreError { Trie(#[from] TrieError), #[error("missing store: is an execution DB being used instead?")] MissingStore, + #[error("Could not open DB for reading")] + ReadError, + #[error("Could not instantiate cursor for table {0}")] + CursorError(String), + #[error("Missing latest block number")] + MissingLatestBlockNumber, + #[error("Missing earliest block number")] + MissingEarliestBlockNumber, } diff --git a/crates/storage/store/storage.rs b/crates/storage/store/storage.rs index d647f9467..695ffddf0 100644 --- a/crates/storage/store/storage.rs +++ b/crates/storage/store/storage.rs @@ -635,9 +635,10 @@ impl Store { self.engine.update_earliest_block_number(block_number) } - // TODO(#790): This should not return an option. - pub fn get_earliest_block_number(&self) -> Result, StoreError> { - self.engine.get_earliest_block_number() + pub fn get_earliest_block_number(&self) -> Result { + self.engine + .get_earliest_block_number()? + .ok_or(StoreError::MissingEarliestBlockNumber) } pub fn update_finalized_block_number( @@ -663,9 +664,10 @@ impl Store { self.engine.update_latest_block_number(block_number) } - // TODO(#790): This should not return an option. - pub fn get_latest_block_number(&self) -> Result, StoreError> { - self.engine.get_latest_block_number() + pub fn get_latest_block_number(&self) -> Result { + self.engine + .get_latest_block_number()? + .ok_or(StoreError::MissingLatestBlockNumber) } pub fn update_latest_total_difficulty(&self, block_difficulty: U256) -> Result<(), StoreError> { @@ -956,6 +958,13 @@ impl Store { pub fn open_storage_trie(&self, account_hash: H256, storage_root: H256) -> Trie { self.engine.open_storage_trie(account_hash, storage_root) } + + pub fn get_receipts_for_block( + &self, + block_hash: &BlockHash, + ) -> Result, StoreError> { + self.engine.get_receipts_for_block(block_hash) + } } pub fn hash_address(address: &Address) -> Vec { @@ -1239,10 +1248,10 @@ mod tests { .update_pending_block_number(pending_block_number) .unwrap(); - let stored_earliest_block_number = store.get_earliest_block_number().unwrap().unwrap(); + let stored_earliest_block_number = store.get_earliest_block_number().unwrap(); let stored_finalized_block_number = store.get_finalized_block_number().unwrap().unwrap(); let stored_safe_block_number = store.get_safe_block_number().unwrap().unwrap(); - let stored_latest_block_number = store.get_latest_block_number().unwrap().unwrap(); + let stored_latest_block_number = store.get_latest_block_number().unwrap(); let stored_pending_block_number = store.get_pending_block_number().unwrap().unwrap(); assert_eq!(earliest_block_number, stored_earliest_block_number); diff --git a/crates/vm/levm/Cargo.toml b/crates/vm/levm/Cargo.toml index 8663a751d..bb3036458 100644 --- a/crates/vm/levm/Cargo.toml +++ b/crates/vm/levm/Cargo.toml @@ -17,6 +17,9 @@ keccak-hash = "0.11.0" thiserror = "2.0.3" libsecp256k1 = "0.7.1" sha2 = "0.10.8" +ripemd = "0.1.3" +num-bigint = "0.4.5" +lambdaworks-math = "0.11.0" [dev-dependencies] hex = "0.4.3" diff --git a/crates/vm/levm/src/call_frame.rs b/crates/vm/levm/src/call_frame.rs index 94d2e2724..d62b3fefd 100644 --- a/crates/vm/levm/src/call_frame.rs +++ b/crates/vm/levm/src/call_frame.rs @@ -7,10 +7,7 @@ use crate::{ }; use bytes::Bytes; use ethrex_core::{types::Log, Address, U256}; -use std::collections::{HashMap, HashSet}; - -/// [EIP-1153]: https://eips.ethereum.org/EIPS/eip-1153#reference-implementation -pub type TransientStorage = HashMap<(Address, U256), U256>; +use std::collections::HashSet; #[derive(Debug, Clone, Default, PartialEq, Eq)] pub struct Stack { @@ -56,9 +53,9 @@ impl Stack { /// the EVM is currently executing. pub struct CallFrame { /// Max gas a callframe can use - pub gas_limit: U256, + pub gas_limit: u64, /// Keeps track of the gas that's been used in current context - pub gas_used: U256, + pub gas_used: u64, /// Program Counter pub pc: usize, /// Address of the account that sent the message @@ -81,7 +78,6 @@ pub struct CallFrame { pub sub_return_data: Bytes, /// Indicates if current context is static (if it is, it can't change state) pub is_static: bool, - pub transient_storage: TransientStorage, pub logs: Vec, /// Call stack current depth pub depth: usize, @@ -95,7 +91,7 @@ impl CallFrame { pub fn new_from_bytecode(bytecode: Bytes) -> Self { let valid_jump_destinations = get_valid_jump_destinations(&bytecode).unwrap_or_default(); Self { - gas_limit: U256::MAX, + gas_limit: u64::MAX, bytecode, valid_jump_destinations, ..Default::default() @@ -117,8 +113,8 @@ impl CallFrame { msg_value: U256, calldata: Bytes, is_static: bool, - gas_limit: U256, - gas_used: U256, + gas_limit: u64, + gas_used: u64, depth: usize, create_op_called: bool, ) -> Self { diff --git a/crates/vm/levm/src/constants.rs b/crates/vm/levm/src/constants.rs index 291be9bd5..a179002bf 100644 --- a/crates/vm/levm/src/constants.rs +++ b/crates/vm/levm/src/constants.rs @@ -21,7 +21,7 @@ pub const EMPTY_CODE_HASH: H256 = H256([ pub const MEMORY_EXPANSION_QUOTIENT: usize = 512; // Transaction costs in gas (in wei) -pub const TX_BASE_COST: U256 = U256([21000, 0, 0, 0]); +pub const TX_BASE_COST: u64 = 21000; pub const MAX_CODE_SIZE: usize = 0x6000; pub const INIT_CODE_MAX_SIZE: usize = 49152; diff --git a/crates/vm/levm/src/environment.rs b/crates/vm/levm/src/environment.rs index 692209322..e48052d8a 100644 --- a/crates/vm/levm/src/environment.rs +++ b/crates/vm/levm/src/environment.rs @@ -1,12 +1,17 @@ +use std::collections::HashMap; + use ethrex_core::{Address, H256, U256}; +/// [EIP-1153]: https://eips.ethereum.org/EIPS/eip-1153#reference-implementation +pub type TransientStorage = HashMap<(Address, U256), U256>; + #[derive(Debug, Default, Clone)] pub struct Environment { /// The sender address of the transaction that originated /// this execution. pub origin: Address, - pub refunded_gas: U256, - pub gas_limit: U256, + pub refunded_gas: u64, + pub gas_limit: u64, pub block_number: U256, pub coinbase: Address, pub timestamp: U256, @@ -20,15 +25,16 @@ pub struct Environment { pub tx_max_priority_fee_per_gas: Option, pub tx_max_fee_per_gas: Option, pub tx_max_fee_per_blob_gas: Option, - pub block_gas_limit: U256, + pub block_gas_limit: u64, + pub transient_storage: TransientStorage, } impl Environment { pub fn default_from_address(origin: Address) -> Self { Self { origin, - refunded_gas: U256::default(), - gas_limit: U256::MAX, + refunded_gas: 0, + gas_limit: u64::MAX, block_number: Default::default(), coinbase: Default::default(), timestamp: Default::default(), @@ -43,6 +49,7 @@ impl Environment { tx_max_fee_per_gas: Default::default(), tx_max_fee_per_blob_gas: Default::default(), block_gas_limit: Default::default(), + transient_storage: Default::default(), } } } diff --git a/crates/vm/levm/src/errors.rs b/crates/vm/levm/src/errors.rs index 3621e5903..df3e00b1b 100644 --- a/crates/vm/levm/src/errors.rs +++ b/crates/vm/levm/src/errors.rs @@ -152,6 +152,8 @@ pub enum InternalError { DivisionError, #[error("Tried to access last call frame but found none")] CouldNotAccessLastCallframe, // Last callframe before execution is the same as the first, but after execution the last callframe is actually the initial CF + #[error("Tried to access blobhash but was out of range")] + BlobHashOutOfRange, #[error("Tried to read from empty code")] TriedToIndexEmptyCode, #[error("Failed computing CREATE address")] diff --git a/crates/vm/levm/src/gas_cost.rs b/crates/vm/levm/src/gas_cost.rs index 0cecb9681..5fde6a53a 100644 --- a/crates/vm/levm/src/gas_cost.rs +++ b/crates/vm/levm/src/gas_cost.rs @@ -5,164 +5,165 @@ use crate::{ memory, StorageSlot, }; use bytes::Bytes; -/// Contains the gas costs of the EVM instructions (in wei) +/// Contains the gas costs of the EVM instructions use ethrex_core::U256; +use num_bigint::BigUint; // Opcodes cost -pub const STOP: U256 = U256::zero(); -pub const ADD: U256 = U256([3, 0, 0, 0]); -pub const MUL: U256 = U256([5, 0, 0, 0]); -pub const SUB: U256 = U256([3, 0, 0, 0]); -pub const DIV: U256 = U256([5, 0, 0, 0]); -pub const SDIV: U256 = U256([5, 0, 0, 0]); -pub const MOD: U256 = U256([5, 0, 0, 0]); -pub const SMOD: U256 = U256([5, 0, 0, 0]); -pub const ADDMOD: U256 = U256([8, 0, 0, 0]); -pub const MULMOD: U256 = U256([8, 0, 0, 0]); -pub const EXP_STATIC: U256 = U256([10, 0, 0, 0]); -pub const EXP_DYNAMIC_BASE: U256 = U256([50, 0, 0, 0]); -pub const SIGNEXTEND: U256 = U256([5, 0, 0, 0]); -pub const LT: U256 = U256([3, 0, 0, 0]); -pub const GT: U256 = U256([3, 0, 0, 0]); -pub const SLT: U256 = U256([3, 0, 0, 0]); -pub const SGT: U256 = U256([3, 0, 0, 0]); -pub const EQ: U256 = U256([3, 0, 0, 0]); -pub const ISZERO: U256 = U256([3, 0, 0, 0]); -pub const AND: U256 = U256([3, 0, 0, 0]); -pub const OR: U256 = U256([3, 0, 0, 0]); -pub const XOR: U256 = U256([3, 0, 0, 0]); -pub const NOT: U256 = U256([3, 0, 0, 0]); -pub const BYTE: U256 = U256([3, 0, 0, 0]); -pub const SHL: U256 = U256([3, 0, 0, 0]); -pub const SHR: U256 = U256([3, 0, 0, 0]); -pub const SAR: U256 = U256([3, 0, 0, 0]); -pub const KECCAK25_STATIC: U256 = U256([30, 0, 0, 0]); -pub const KECCAK25_DYNAMIC_BASE: U256 = U256([6, 0, 0, 0]); -pub const CALLDATALOAD: U256 = U256([3, 0, 0, 0]); -pub const CALLDATASIZE: U256 = U256([2, 0, 0, 0]); -pub const CALLDATACOPY_STATIC: U256 = U256([3, 0, 0, 0]); -pub const CALLDATACOPY_DYNAMIC_BASE: U256 = U256([3, 0, 0, 0]); -pub const RETURNDATASIZE: U256 = U256([2, 0, 0, 0]); -pub const RETURNDATACOPY_STATIC: U256 = U256([3, 0, 0, 0]); -pub const RETURNDATACOPY_DYNAMIC_BASE: U256 = U256([3, 0, 0, 0]); -pub const ADDRESS: U256 = U256([2, 0, 0, 0]); -pub const ORIGIN: U256 = U256([2, 0, 0, 0]); -pub const CALLER: U256 = U256([2, 0, 0, 0]); -pub const BLOCKHASH: U256 = U256([20, 0, 0, 0]); -pub const COINBASE: U256 = U256([2, 0, 0, 0]); -pub const TIMESTAMP: U256 = U256([2, 0, 0, 0]); -pub const NUMBER: U256 = U256([2, 0, 0, 0]); -pub const PREVRANDAO: U256 = U256([2, 0, 0, 0]); -pub const GASLIMIT: U256 = U256([2, 0, 0, 0]); -pub const CHAINID: U256 = U256([2, 0, 0, 0]); -pub const SELFBALANCE: U256 = U256([5, 0, 0, 0]); -pub const BASEFEE: U256 = U256([2, 0, 0, 0]); -pub const BLOBHASH: U256 = U256([3, 0, 0, 0]); -pub const BLOBBASEFEE: U256 = U256([2, 0, 0, 0]); -pub const POP: U256 = U256([2, 0, 0, 0]); -pub const MLOAD_STATIC: U256 = U256([3, 0, 0, 0]); -pub const MSTORE_STATIC: U256 = U256([3, 0, 0, 0]); -pub const MSTORE8_STATIC: U256 = U256([3, 0, 0, 0]); -pub const JUMP: U256 = U256([8, 0, 0, 0]); -pub const JUMPI: U256 = U256([10, 0, 0, 0]); -pub const PC: U256 = U256([2, 0, 0, 0]); -pub const MSIZE: U256 = U256([2, 0, 0, 0]); -pub const GAS: U256 = U256([2, 0, 0, 0]); -pub const JUMPDEST: U256 = U256([1, 0, 0, 0]); -pub const TLOAD: U256 = U256([100, 0, 0, 0]); -pub const TSTORE: U256 = U256([100, 0, 0, 0]); -pub const MCOPY_STATIC: U256 = U256([3, 0, 0, 0]); -pub const MCOPY_DYNAMIC_BASE: U256 = U256([3, 0, 0, 0]); -pub const PUSH0: U256 = U256([2, 0, 0, 0]); -pub const PUSHN: U256 = U256([3, 0, 0, 0]); -pub const DUPN: U256 = U256([3, 0, 0, 0]); -pub const SWAPN: U256 = U256([3, 0, 0, 0]); -pub const LOGN_STATIC: U256 = U256([375, 0, 0, 0]); -pub const LOGN_DYNAMIC_BASE: U256 = U256([375, 0, 0, 0]); -pub const LOGN_DYNAMIC_BYTE_BASE: U256 = U256([8, 0, 0, 0]); -pub const CALLVALUE: U256 = U256([2, 0, 0, 0]); -pub const CODESIZE: U256 = U256([2, 0, 0, 0]); -pub const CODECOPY_STATIC: U256 = U256([3, 0, 0, 0]); -pub const CODECOPY_DYNAMIC_BASE: U256 = U256([3, 0, 0, 0]); -pub const GASPRICE: U256 = U256([2, 0, 0, 0]); -pub const SELFDESTRUCT_STATIC: U256 = U256([5000, 0, 0, 0]); -pub const SELFDESTRUCT_DYNAMIC: U256 = U256([25000, 0, 0, 0]); - -pub const DEFAULT_STATIC: U256 = U256::zero(); -pub const DEFAULT_COLD_DYNAMIC: U256 = U256([2600, 0, 0, 0]); -pub const DEFAULT_WARM_DYNAMIC: U256 = U256([100, 0, 0, 0]); - -pub const SLOAD_STATIC: U256 = U256::zero(); -pub const SLOAD_COLD_DYNAMIC: U256 = U256([2100, 0, 0, 0]); -pub const SLOAD_WARM_DYNAMIC: U256 = U256([100, 0, 0, 0]); - -pub const SSTORE_STATIC: U256 = U256::zero(); -pub const SSTORE_COLD_DYNAMIC: U256 = U256([2100, 0, 0, 0]); -pub const SSTORE_DEFAULT_DYNAMIC: U256 = U256([100, 0, 0, 0]); -pub const SSTORE_STORAGE_CREATION: U256 = U256([20000, 0, 0, 0]); -pub const SSTORE_STORAGE_MODIFICATION: U256 = U256([2900, 0, 0, 0]); -pub const SSTORE_STIPEND: U256 = U256([2300, 0, 0, 0]); - -pub const BALANCE_STATIC: U256 = DEFAULT_STATIC; -pub const BALANCE_COLD_DYNAMIC: U256 = DEFAULT_COLD_DYNAMIC; -pub const BALANCE_WARM_DYNAMIC: U256 = DEFAULT_WARM_DYNAMIC; - -pub const EXTCODESIZE_STATIC: U256 = DEFAULT_STATIC; -pub const EXTCODESIZE_COLD_DYNAMIC: U256 = DEFAULT_COLD_DYNAMIC; -pub const EXTCODESIZE_WARM_DYNAMIC: U256 = DEFAULT_WARM_DYNAMIC; - -pub const EXTCODEHASH_STATIC: U256 = DEFAULT_STATIC; -pub const EXTCODEHASH_COLD_DYNAMIC: U256 = DEFAULT_COLD_DYNAMIC; -pub const EXTCODEHASH_WARM_DYNAMIC: U256 = DEFAULT_WARM_DYNAMIC; - -pub const EXTCODECOPY_STATIC: U256 = U256::zero(); -pub const EXTCODECOPY_DYNAMIC_BASE: U256 = U256([3, 0, 0, 0]); -pub const EXTCODECOPY_COLD_DYNAMIC: U256 = DEFAULT_COLD_DYNAMIC; -pub const EXTCODECOPY_WARM_DYNAMIC: U256 = DEFAULT_WARM_DYNAMIC; - -pub const CALL_STATIC: U256 = DEFAULT_STATIC; -pub const CALL_COLD_DYNAMIC: U256 = DEFAULT_COLD_DYNAMIC; -pub const CALL_WARM_DYNAMIC: U256 = DEFAULT_WARM_DYNAMIC; -pub const CALL_POSITIVE_VALUE: U256 = U256([9000, 0, 0, 0]); -pub const CALL_POSITIVE_VALUE_STIPEND: U256 = U256([2300, 0, 0, 0]); -pub const CALL_TO_EMPTY_ACCOUNT: U256 = U256([25000, 0, 0, 0]); - -pub const CALLCODE_STATIC: U256 = DEFAULT_STATIC; -pub const CALLCODE_COLD_DYNAMIC: U256 = DEFAULT_COLD_DYNAMIC; -pub const CALLCODE_WARM_DYNAMIC: U256 = DEFAULT_WARM_DYNAMIC; -pub const CALLCODE_POSITIVE_VALUE: U256 = U256([9000, 0, 0, 0]); -pub const CALLCODE_POSITIVE_VALUE_STIPEND: U256 = U256([2300, 0, 0, 0]); - -pub const DELEGATECALL_STATIC: U256 = DEFAULT_STATIC; -pub const DELEGATECALL_COLD_DYNAMIC: U256 = DEFAULT_COLD_DYNAMIC; -pub const DELEGATECALL_WARM_DYNAMIC: U256 = DEFAULT_WARM_DYNAMIC; - -pub const STATICCALL_STATIC: U256 = DEFAULT_STATIC; -pub const STATICCALL_COLD_DYNAMIC: U256 = DEFAULT_COLD_DYNAMIC; -pub const STATICCALL_WARM_DYNAMIC: U256 = DEFAULT_WARM_DYNAMIC; - -// Costs in gas for call opcodes (in wei) -pub const WARM_ADDRESS_ACCESS_COST: U256 = U256([100, 0, 0, 0]); -pub const COLD_ADDRESS_ACCESS_COST: U256 = U256([2600, 0, 0, 0]); -pub const NON_ZERO_VALUE_COST: U256 = U256([9000, 0, 0, 0]); -pub const BASIC_FALLBACK_FUNCTION_STIPEND: U256 = U256([2300, 0, 0, 0]); -pub const VALUE_TO_EMPTY_ACCOUNT_COST: U256 = U256([25000, 0, 0, 0]); - -// Costs in gas for create opcodes (in wei) -pub const INIT_CODE_WORD_COST: U256 = U256([2, 0, 0, 0]); -pub const CODE_DEPOSIT_COST: U256 = U256([200, 0, 0, 0]); -pub const CREATE_BASE_COST: U256 = U256([32000, 0, 0, 0]); +pub const STOP: u64 = 0; +pub const ADD: u64 = 3; +pub const MUL: u64 = 5; +pub const SUB: u64 = 3; +pub const DIV: u64 = 5; +pub const SDIV: u64 = 5; +pub const MOD: u64 = 5; +pub const SMOD: u64 = 5; +pub const ADDMOD: u64 = 8; +pub const MULMOD: u64 = 8; +pub const EXP_STATIC: u64 = 10; +pub const EXP_DYNAMIC_BASE: u64 = 50; +pub const SIGNEXTEND: u64 = 5; +pub const LT: u64 = 3; +pub const GT: u64 = 3; +pub const SLT: u64 = 3; +pub const SGT: u64 = 3; +pub const EQ: u64 = 3; +pub const ISZERO: u64 = 3; +pub const AND: u64 = 3; +pub const OR: u64 = 3; +pub const XOR: u64 = 3; +pub const NOT: u64 = 3; +pub const BYTE: u64 = 3; +pub const SHL: u64 = 3; +pub const SHR: u64 = 3; +pub const SAR: u64 = 3; +pub const KECCAK25_STATIC: u64 = 30; +pub const KECCAK25_DYNAMIC_BASE: u64 = 6; +pub const CALLDATALOAD: u64 = 3; +pub const CALLDATASIZE: u64 = 2; +pub const CALLDATACOPY_STATIC: u64 = 3; +pub const CALLDATACOPY_DYNAMIC_BASE: u64 = 3; +pub const RETURNDATASIZE: u64 = 2; +pub const RETURNDATACOPY_STATIC: u64 = 3; +pub const RETURNDATACOPY_DYNAMIC_BASE: u64 = 3; +pub const ADDRESS: u64 = 2; +pub const ORIGIN: u64 = 2; +pub const CALLER: u64 = 2; +pub const BLOCKHASH: u64 = 20; +pub const COINBASE: u64 = 2; +pub const TIMESTAMP: u64 = 2; +pub const NUMBER: u64 = 2; +pub const PREVRANDAO: u64 = 2; +pub const GASLIMIT: u64 = 2; +pub const CHAINID: u64 = 2; +pub const SELFBALANCE: u64 = 5; +pub const BASEFEE: u64 = 2; +pub const BLOBHASH: u64 = 3; +pub const BLOBBASEFEE: u64 = 2; +pub const POP: u64 = 2; +pub const MLOAD_STATIC: u64 = 3; +pub const MSTORE_STATIC: u64 = 3; +pub const MSTORE8_STATIC: u64 = 3; +pub const JUMP: u64 = 8; +pub const JUMPI: u64 = 10; +pub const PC: u64 = 2; +pub const MSIZE: u64 = 2; +pub const GAS: u64 = 2; +pub const JUMPDEST: u64 = 1; +pub const TLOAD: u64 = 100; +pub const TSTORE: u64 = 100; +pub const MCOPY_STATIC: u64 = 3; +pub const MCOPY_DYNAMIC_BASE: u64 = 3; +pub const PUSH0: u64 = 2; +pub const PUSHN: u64 = 3; +pub const DUPN: u64 = 3; +pub const SWAPN: u64 = 3; +pub const LOGN_STATIC: u64 = 375; +pub const LOGN_DYNAMIC_BASE: u64 = 375; +pub const LOGN_DYNAMIC_BYTE_BASE: u64 = 8; +pub const CALLVALUE: u64 = 2; +pub const CODESIZE: u64 = 2; +pub const CODECOPY_STATIC: u64 = 3; +pub const CODECOPY_DYNAMIC_BASE: u64 = 3; +pub const GASPRICE: u64 = 2; +pub const SELFDESTRUCT_STATIC: u64 = 5000; +pub const SELFDESTRUCT_DYNAMIC: u64 = 25000; + +pub const DEFAULT_STATIC: u64 = 0; +pub const DEFAULT_COLD_DYNAMIC: u64 = 2600; +pub const DEFAULT_WARM_DYNAMIC: u64 = 100; + +pub const SLOAD_STATIC: u64 = 0; +pub const SLOAD_COLD_DYNAMIC: u64 = 2100; +pub const SLOAD_WARM_DYNAMIC: u64 = 100; + +pub const SSTORE_STATIC: u64 = 0; +pub const SSTORE_COLD_DYNAMIC: u64 = 2100; +pub const SSTORE_DEFAULT_DYNAMIC: u64 = 100; +pub const SSTORE_STORAGE_CREATION: u64 = 20000; +pub const SSTORE_STORAGE_MODIFICATION: u64 = 2900; +pub const SSTORE_STIPEND: u64 = 2300; + +pub const BALANCE_STATIC: u64 = DEFAULT_STATIC; +pub const BALANCE_COLD_DYNAMIC: u64 = DEFAULT_COLD_DYNAMIC; +pub const BALANCE_WARM_DYNAMIC: u64 = DEFAULT_WARM_DYNAMIC; + +pub const EXTCODESIZE_STATIC: u64 = DEFAULT_STATIC; +pub const EXTCODESIZE_COLD_DYNAMIC: u64 = DEFAULT_COLD_DYNAMIC; +pub const EXTCODESIZE_WARM_DYNAMIC: u64 = DEFAULT_WARM_DYNAMIC; + +pub const EXTCODEHASH_STATIC: u64 = DEFAULT_STATIC; +pub const EXTCODEHASH_COLD_DYNAMIC: u64 = DEFAULT_COLD_DYNAMIC; +pub const EXTCODEHASH_WARM_DYNAMIC: u64 = DEFAULT_WARM_DYNAMIC; + +pub const EXTCODECOPY_STATIC: u64 = 0; +pub const EXTCODECOPY_DYNAMIC_BASE: u64 = 3; +pub const EXTCODECOPY_COLD_DYNAMIC: u64 = DEFAULT_COLD_DYNAMIC; +pub const EXTCODECOPY_WARM_DYNAMIC: u64 = DEFAULT_WARM_DYNAMIC; + +pub const CALL_STATIC: u64 = DEFAULT_STATIC; +pub const CALL_COLD_DYNAMIC: u64 = DEFAULT_COLD_DYNAMIC; +pub const CALL_WARM_DYNAMIC: u64 = DEFAULT_WARM_DYNAMIC; +pub const CALL_POSITIVE_VALUE: u64 = 9000; +pub const CALL_POSITIVE_VALUE_STIPEND: u64 = 2300; +pub const CALL_TO_EMPTY_ACCOUNT: u64 = 25000; + +pub const CALLCODE_STATIC: u64 = DEFAULT_STATIC; +pub const CALLCODE_COLD_DYNAMIC: u64 = DEFAULT_COLD_DYNAMIC; +pub const CALLCODE_WARM_DYNAMIC: u64 = DEFAULT_WARM_DYNAMIC; +pub const CALLCODE_POSITIVE_VALUE: u64 = 9000; +pub const CALLCODE_POSITIVE_VALUE_STIPEND: u64 = 2300; + +pub const DELEGATECALL_STATIC: u64 = DEFAULT_STATIC; +pub const DELEGATECALL_COLD_DYNAMIC: u64 = DEFAULT_COLD_DYNAMIC; +pub const DELEGATECALL_WARM_DYNAMIC: u64 = DEFAULT_WARM_DYNAMIC; + +pub const STATICCALL_STATIC: u64 = DEFAULT_STATIC; +pub const STATICCALL_COLD_DYNAMIC: u64 = DEFAULT_COLD_DYNAMIC; +pub const STATICCALL_WARM_DYNAMIC: u64 = DEFAULT_WARM_DYNAMIC; + +// Costs in gas for call opcodes +pub const WARM_ADDRESS_ACCESS_COST: u64 = 100; +pub const COLD_ADDRESS_ACCESS_COST: u64 = 2600; +pub const NON_ZERO_VALUE_COST: u64 = 9000; +pub const BASIC_FALLBACK_FUNCTION_STIPEND: u64 = 2300; +pub const VALUE_TO_EMPTY_ACCOUNT_COST: u64 = 25000; + +// Costs in gas for create opcodes +pub const INIT_CODE_WORD_COST: u64 = 2; +pub const CODE_DEPOSIT_COST: u64 = 200; +pub const CREATE_BASE_COST: u64 = 32000; // Calldata costs -pub const CALLDATA_COST_ZERO_BYTE: U256 = U256([4, 0, 0, 0]); -pub const CALLDATA_COST_NON_ZERO_BYTE: U256 = U256([16, 0, 0, 0]); +pub const CALLDATA_COST_ZERO_BYTE: u64 = 4; +pub const CALLDATA_COST_NON_ZERO_BYTE: u64 = 16; // Blob gas costs -pub const BLOB_GAS_PER_BLOB: U256 = U256([131072, 0, 0, 0]); +pub const BLOB_GAS_PER_BLOB: u64 = 131072; // Access lists costs -pub const ACCESS_LIST_STORAGE_KEY_COST: U256 = U256([1900, 0, 0, 0]); -pub const ACCESS_LIST_ADDRESS_COST: U256 = U256([2400, 0, 0, 0]); +pub const ACCESS_LIST_STORAGE_KEY_COST: u64 = 1900; +pub const ACCESS_LIST_ADDRESS_COST: u64 = 2400; // Precompile costs pub const ECRECOVER_COST: u64 = 3000; @@ -176,31 +177,38 @@ pub const RIPEMD_160_DYNAMIC_BASE: u64 = 120; pub const IDENTITY_STATIC_COST: u64 = 15; pub const IDENTITY_DYNAMIC_BASE: u64 = 3; -pub const MODEXP_STATIC_COST: u64 = 0; +pub const MODEXP_STATIC_COST: u64 = 200; pub const MODEXP_DYNAMIC_BASE: u64 = 200; pub const MODEXP_DYNAMIC_QUOTIENT: u64 = 3; -pub fn exp(exponent: U256) -> Result { +pub const ECADD_COST: u64 = 150; +pub const ECMUL_COST: u64 = 6000; + +pub fn exp(exponent: U256) -> Result { let exponent_byte_size = (exponent .bits() .checked_add(7) - .ok_or(OutOfGasError::GasCostOverflow)?) + .ok_or(VMError::OutOfGas(OutOfGasError::GasCostOverflow))?) / 8; + let exponent_byte_size: u64 = exponent_byte_size + .try_into() + .map_err(|_| VMError::VeryLargeNumber)?; + let exponent_byte_size_cost = EXP_DYNAMIC_BASE - .checked_mul(exponent_byte_size.into()) - .ok_or(OutOfGasError::GasCostOverflow)?; + .checked_mul(exponent_byte_size) + .ok_or(VMError::OutOfGas(OutOfGasError::GasCostOverflow))?; EXP_STATIC .checked_add(exponent_byte_size_cost) - .ok_or(OutOfGasError::GasCostOverflow) + .ok_or(VMError::OutOfGas(OutOfGasError::GasCostOverflow)) } pub fn calldatacopy( new_memory_size: usize, current_memory_size: usize, size: usize, -) -> Result { +) -> Result { copy_behavior( new_memory_size, current_memory_size, @@ -214,7 +222,7 @@ pub fn codecopy( new_memory_size: usize, current_memory_size: usize, size: usize, -) -> Result { +) -> Result { copy_behavior( new_memory_size, current_memory_size, @@ -228,7 +236,7 @@ pub fn returndatacopy( new_memory_size: usize, current_memory_size: usize, size: usize, -) -> Result { +) -> Result { copy_behavior( new_memory_size, current_memory_size, @@ -242,24 +250,31 @@ fn copy_behavior( new_memory_size: usize, current_memory_size: usize, size: usize, - dynamic_base: U256, - static_cost: U256, -) -> Result { + dynamic_base: u64, + static_cost: u64, +) -> Result { let minimum_word_size = (size .checked_add(WORD_SIZE) .ok_or(OutOfGasError::GasCostOverflow)? .saturating_sub(1)) / WORD_SIZE; + let minimum_word_size: u64 = minimum_word_size + .try_into() + .map_err(|_| VMError::VeryLargeNumber)?; + let memory_expansion_cost = memory::expansion_cost(new_memory_size, current_memory_size)?; + let memory_expansion_cost: u64 = memory_expansion_cost + .try_into() + .map_err(|_| VMError::VeryLargeNumber)?; let minimum_word_size_cost = dynamic_base - .checked_mul(minimum_word_size.into()) + .checked_mul(minimum_word_size) .ok_or(OutOfGasError::GasCostOverflow)?; Ok(static_cost .checked_add(minimum_word_size_cost) .ok_or(OutOfGasError::GasCostOverflow)? - .checked_add(memory_expansion_cost.into()) + .checked_add(memory_expansion_cost) .ok_or(OutOfGasError::GasCostOverflow)?) } @@ -267,7 +282,7 @@ pub fn keccak256( new_memory_size: usize, current_memory_size: usize, size: usize, -) -> Result { +) -> Result { copy_behavior( new_memory_size, current_memory_size, @@ -282,48 +297,59 @@ pub fn log( current_memory_size: usize, size: usize, number_of_topics: u8, -) -> Result { +) -> Result { let memory_expansion_cost = memory::expansion_cost(new_memory_size, current_memory_size)?; let topics_cost = LOGN_DYNAMIC_BASE .checked_mul(number_of_topics.into()) .ok_or(OutOfGasError::GasCostOverflow)?; + + let size: u64 = size.try_into().map_err(|_| VMError::VeryLargeNumber)?; let bytes_cost = LOGN_DYNAMIC_BYTE_BASE - .checked_mul(size.into()) + .checked_mul(size) .ok_or(OutOfGasError::GasCostOverflow)?; + + let memory_expansion_cost: u64 = memory_expansion_cost + .try_into() + .map_err(|_| VMError::VeryLargeNumber)?; + Ok(topics_cost .checked_add(LOGN_STATIC) .ok_or(OutOfGasError::GasCostOverflow)? .checked_add(bytes_cost) .ok_or(OutOfGasError::GasCostOverflow)? - .checked_add(memory_expansion_cost.into()) + .checked_add(memory_expansion_cost) .ok_or(OutOfGasError::GasCostOverflow)?) } -pub fn mload(new_memory_size: usize, current_memory_size: usize) -> Result { +pub fn mload(new_memory_size: usize, current_memory_size: usize) -> Result { mem_expansion_behavior(new_memory_size, current_memory_size, MLOAD_STATIC) } -pub fn mstore(new_memory_size: usize, current_memory_size: usize) -> Result { +pub fn mstore(new_memory_size: usize, current_memory_size: usize) -> Result { mem_expansion_behavior(new_memory_size, current_memory_size, MSTORE_STATIC) } -pub fn mstore8(new_memory_size: usize, current_memory_size: usize) -> Result { +pub fn mstore8(new_memory_size: usize, current_memory_size: usize) -> Result { mem_expansion_behavior(new_memory_size, current_memory_size, MSTORE8_STATIC) } fn mem_expansion_behavior( new_memory_size: usize, current_memory_size: usize, - static_cost: U256, -) -> Result { + static_cost: u64, +) -> Result { let memory_expansion_cost = memory::expansion_cost(new_memory_size, current_memory_size)?; + let memory_expansion_cost: u64 = memory_expansion_cost + .try_into() + .map_err(|_| VMError::RevertOpcode)?; + Ok(static_cost - .checked_add(memory_expansion_cost.into()) + .checked_add(memory_expansion_cost) .ok_or(OutOfGasError::GasCostOverflow)?) } -pub fn sload(storage_slot_was_cold: bool) -> Result { +pub fn sload(storage_slot_was_cold: bool) -> Result { let static_gas = SLOAD_STATIC; let dynamic_cost = if storage_slot_was_cold { @@ -342,7 +368,7 @@ pub fn sstore( new_value: U256, storage_slot_was_cold: bool, current_call_frame: &CallFrame, -) -> Result { +) -> Result { // EIP-2200 let gas_left = current_call_frame .gas_limit @@ -381,7 +407,7 @@ pub fn mcopy( new_memory_size: usize, current_memory_size: usize, size: usize, -) -> Result { +) -> Result { let words_copied = (size .checked_add(WORD_SIZE) .ok_or(OutOfGasError::GasCostOverflow)? @@ -389,15 +415,22 @@ pub fn mcopy( / WORD_SIZE; let memory_expansion_cost = memory::expansion_cost(new_memory_size, current_memory_size)?; + let memory_expansion_cost: u64 = memory_expansion_cost + .try_into() + .map_err(|_| VMError::VeryLargeNumber)?; + + let words_copied: u64 = words_copied + .try_into() + .map_err(|_| VMError::VeryLargeNumber)?; let copied_words_cost = MCOPY_DYNAMIC_BASE - .checked_mul(words_copied.into()) + .checked_mul(words_copied) .ok_or(OutOfGasError::GasCostOverflow)?; Ok(MCOPY_STATIC .checked_add(copied_words_cost) .ok_or(OutOfGasError::GasCostOverflow)? - .checked_add(memory_expansion_cost.into()) + .checked_add(memory_expansion_cost) .ok_or(OutOfGasError::GasCostOverflow)?) } @@ -405,7 +438,7 @@ pub fn create( new_memory_size: usize, current_memory_size: usize, code_size_in_memory: usize, -) -> Result { +) -> Result { compute_gas_create( new_memory_size, current_memory_size, @@ -418,7 +451,7 @@ pub fn create_2( new_memory_size: usize, current_memory_size: usize, code_size_in_memory: usize, -) -> Result { +) -> Result { compute_gas_create( new_memory_size, current_memory_size, @@ -432,41 +465,50 @@ fn compute_gas_create( current_memory_size: usize, code_size_in_memory: usize, is_create_2: bool, -) -> Result { +) -> Result { let minimum_word_size = (code_size_in_memory .checked_add(31) .ok_or(OutOfGasError::GasCostOverflow)?) .checked_div(32) .ok_or(OutOfGasError::ArithmeticOperationDividedByZero)?; // '32' will never be zero + let minimum_word_size: u64 = minimum_word_size + .try_into() + .map_err(|_| VMError::VeryLargeNumber)?; + let init_code_cost = minimum_word_size - .checked_mul(INIT_CODE_WORD_COST.as_usize()) // will not panic since it's 2 - .ok_or(OutOfGasError::GasCostOverflow)?; + .checked_mul(INIT_CODE_WORD_COST) + .ok_or(OutOfGasError::GasCostOverflow)?; // will not panic since it's 2 let memory_expansion_cost = memory::expansion_cost(new_memory_size, current_memory_size)?; + let memory_expansion_cost: u64 = memory_expansion_cost + .try_into() + .map_err(|_| VMError::VeryLargeNumber)?; let hash_cost = if is_create_2 { minimum_word_size - .checked_mul(KECCAK25_DYNAMIC_BASE.as_usize()) // will not panic since it's 6 - .ok_or(OutOfGasError::GasCostOverflow)? + .checked_mul(KECCAK25_DYNAMIC_BASE) + .ok_or(OutOfGasError::GasCostOverflow)? // will not panic since it's 6 } else { 0 }; - Ok(U256::from(memory_expansion_cost) - .checked_add(init_code_cost.into()) + let gas_create_cost = memory_expansion_cost + .checked_add(init_code_cost) .ok_or(OutOfGasError::CreationCostIsTooHigh)? .checked_add(CREATE_BASE_COST) .ok_or(OutOfGasError::CreationCostIsTooHigh)? - .checked_add(hash_cost.into()) - .ok_or(OutOfGasError::CreationCostIsTooHigh)?) + .checked_add(hash_cost) + .ok_or(OutOfGasError::CreationCostIsTooHigh)?; + + Ok(gas_create_cost) } pub fn selfdestruct( address_was_cold: bool, account_is_empty: bool, balance_to_transfer: U256, -) -> Result { +) -> Result { let mut gas_cost = SELFDESTRUCT_STATIC; if address_was_cold { @@ -485,10 +527,10 @@ pub fn selfdestruct( Ok(gas_cost) } -pub fn tx_calldata(calldata: &Bytes) -> Result { +pub fn tx_calldata(calldata: &Bytes) -> Result { // This cost applies both for call and create // 4 gas for each zero byte in the transaction data 16 gas for each non-zero byte in the transaction. - let mut calldata_cost: U256 = U256::zero(); + let mut calldata_cost: u64 = 0; for byte in calldata { if *byte != 0 { calldata_cost = calldata_cost @@ -522,12 +564,12 @@ pub fn tx_creation(code_length: u64, number_of_words: u64) -> Result Result { + static_cost: u64, + cold_dynamic_cost: u64, + warm_dynamic_cost: u64, +) -> Result { let static_gas = static_cost; - let dynamic_cost: U256 = if address_was_cold { + let dynamic_cost: u64 = if address_was_cold { cold_dynamic_cost } else { warm_dynamic_cost @@ -538,7 +580,7 @@ fn address_access_cost( .ok_or(OutOfGasError::GasCostOverflow)?) } -pub fn balance(address_was_cold: bool) -> Result { +pub fn balance(address_was_cold: bool) -> Result { address_access_cost( address_was_cold, BALANCE_STATIC, @@ -547,7 +589,7 @@ pub fn balance(address_was_cold: bool) -> Result { ) } -pub fn extcodesize(address_was_cold: bool) -> Result { +pub fn extcodesize(address_was_cold: bool) -> Result { address_access_cost( address_was_cold, EXTCODESIZE_STATIC, @@ -561,7 +603,7 @@ pub fn extcodecopy( new_memory_size: usize, current_memory_size: usize, address_was_cold: bool, -) -> Result { +) -> Result { let base_access_cost = copy_behavior( new_memory_size, current_memory_size, @@ -581,7 +623,7 @@ pub fn extcodecopy( .ok_or(OutOfGasError::GasCostOverflow)?) } -pub fn extcodehash(address_was_cold: bool) -> Result { +pub fn extcodehash(address_was_cold: bool) -> Result { address_access_cost( address_was_cold, EXTCODEHASH_STATIC, @@ -596,10 +638,14 @@ pub fn call( address_was_cold: bool, address_is_empty: bool, value_to_transfer: U256, -) -> Result { +) -> Result { let static_gas = CALL_STATIC; let memory_expansion_cost = memory::expansion_cost(new_memory_size, current_memory_size)?; + let memory_expansion_cost: u64 = memory_expansion_cost + .try_into() + .map_err(|_| VMError::VeryLargeNumber)?; + let address_access_cost = address_access_cost( address_was_cold, CALL_STATIC, @@ -611,16 +657,16 @@ pub fn call( .checked_sub(CALL_POSITIVE_VALUE_STIPEND) .ok_or(InternalError::ArithmeticOperationUnderflow)? } else { - U256::zero() + 0 }; let value_to_empty_account = if address_is_empty && !value_to_transfer.is_zero() { CALL_TO_EMPTY_ACCOUNT } else { - U256::zero() + 0 }; // Note: code_execution_cost will be charged from the sub context post-state. - let dynamic_gas = U256::from(memory_expansion_cost) + let dynamic_gas = memory_expansion_cost .checked_add(address_access_cost) .ok_or(OutOfGasError::GasCostOverflow)? .checked_add(positive_value_cost) @@ -638,10 +684,14 @@ pub fn callcode( current_memory_size: usize, address_was_cold: bool, value_to_transfer: U256, -) -> Result { +) -> Result { let static_gas = CALLCODE_STATIC; let memory_expansion_cost = memory::expansion_cost(new_memory_size, current_memory_size)?; + let memory_expansion_cost: u64 = memory_expansion_cost + .try_into() + .map_err(|_| VMError::VeryLargeNumber)?; + let address_access_cost = address_access_cost( address_was_cold, CALLCODE_STATIC, @@ -653,11 +703,11 @@ pub fn callcode( .checked_sub(CALLCODE_POSITIVE_VALUE_STIPEND) .ok_or(InternalError::ArithmeticOperationUnderflow)? } else { - U256::zero() + 0 }; // Note: code_execution_cost will be charged from the sub context post-state. - let dynamic_gas = U256::from(memory_expansion_cost) + let dynamic_gas = memory_expansion_cost .checked_add(address_access_cost) .ok_or(OutOfGasError::GasCostOverflow)? .checked_add(positive_value_cost) @@ -672,10 +722,14 @@ pub fn delegatecall( new_memory_size: usize, current_memory_size: usize, address_was_cold: bool, -) -> Result { +) -> Result { let static_gas = DELEGATECALL_STATIC; let memory_expansion_cost = memory::expansion_cost(new_memory_size, current_memory_size)?; + let memory_expansion_cost: u64 = memory_expansion_cost + .try_into() + .map_err(|_| VMError::VeryLargeNumber)?; + let address_access_cost = address_access_cost( address_was_cold, DELEGATECALL_STATIC, @@ -684,7 +738,7 @@ pub fn delegatecall( )?; // Note: code_execution_cost will be charged from the sub context post-state. - let dynamic_gas = U256::from(memory_expansion_cost) + let dynamic_gas = memory_expansion_cost .checked_add(address_access_cost) .ok_or(OutOfGasError::GasCostOverflow)?; @@ -697,10 +751,14 @@ pub fn staticcall( new_memory_size: usize, current_memory_size: usize, address_was_cold: bool, -) -> Result { +) -> Result { let static_gas = STATICCALL_STATIC; let memory_expansion_cost = memory::expansion_cost(new_memory_size, current_memory_size)?; + let memory_expansion_cost: u64 = memory_expansion_cost + .try_into() + .map_err(|_| VMError::VeryLargeNumber)?; + let address_access_cost = address_access_cost( address_was_cold, STATICCALL_STATIC, @@ -709,7 +767,7 @@ pub fn staticcall( )?; // Note: code_execution_cost will be charged from the sub context post-state. - let dynamic_gas = U256::from(memory_expansion_cost) + let dynamic_gas = memory_expansion_cost .checked_add(address_access_cost) .ok_or(OutOfGasError::GasCostOverflow)?; @@ -718,7 +776,7 @@ pub fn staticcall( .ok_or(OutOfGasError::GasCostOverflow)?) } -pub fn fake_exponential(factor: u64, numerator: u64, denominator: u64) -> Result { +pub fn fake_exponential(factor: u64, numerator: u64, denominator: u64) -> Result { let mut i = 1; let mut output: u64 = 0; @@ -751,90 +809,80 @@ pub fn fake_exponential(factor: u64, numerator: u64, denominator: u64) -> Result .ok_or(InternalError::ArithmeticOperationOverflow)?; } - Ok(U256::from( - output - .checked_div(denominator) - .ok_or(InternalError::ArithmeticOperationOverflow)?, - )) + Ok(output + .checked_div(denominator) + .ok_or(InternalError::ArithmeticOperationOverflow)?) } -pub fn sha2_256(data_size: usize) -> Result { +pub fn sha2_256(data_size: usize) -> Result { precompile(data_size, SHA2_256_STATIC_COST, SHA2_256_DYNAMIC_BASE) } -pub fn ripemd_160(data_size: usize) -> Result { +pub fn ripemd_160(data_size: usize) -> Result { precompile(data_size, RIPEMD_160_STATIC_COST, RIPEMD_160_DYNAMIC_BASE) } -pub fn identity(data_size: usize) -> Result { +pub fn identity(data_size: usize) -> Result { precompile(data_size, IDENTITY_STATIC_COST, IDENTITY_DYNAMIC_BASE) } pub fn modexp( - exponent: U256, - base_size: u64, - exponent_size: u64, - modulus_size: u64, + exponent: &BigUint, + base_size: usize, + exponent_size: usize, + modulus_size: usize, ) -> Result { + let base_size: u64 = base_size + .try_into() + .map_err(|_| PrecompileError::ParsingInputError)?; + let exponent_size: u64 = exponent_size + .try_into() + .map_err(|_| PrecompileError::ParsingInputError)?; + let modulus_size: u64 = modulus_size + .try_into() + .map_err(|_| PrecompileError::ParsingInputError)?; + let max_length = base_size.max(modulus_size); let words = (max_length .checked_add(7) .ok_or(OutOfGasError::GasCostOverflow)?) - / WORD_SIZE_IN_BYTES_U64; + .checked_div(8) + .ok_or(InternalError::DivisionError)?; + let multiplication_complexity = words.checked_pow(2).ok_or(OutOfGasError::GasCostOverflow)?; - let mut iteration_count: u64 = 0; - if exponent_size <= WORD_SIZE_IN_BYTES_U64 && exponent.is_zero() { - iteration_count = 0; - } else if exponent_size <= WORD_SIZE_IN_BYTES_U64 { - iteration_count = exponent + let iteration_count = if exponent_size <= 32 && *exponent != BigUint::ZERO { + exponent .bits() .checked_sub(1) .ok_or(InternalError::ArithmeticOperationUnderflow)? - .try_into() - .map_err(|_| InternalError::ConversionError)?; - } else if exponent_size > WORD_SIZE_IN_BYTES_U64 { - iteration_count = 8u64 - .checked_mul( - exponent_size - .checked_sub(WORD_SIZE_IN_BYTES_U64) - .ok_or(InternalError::ArithmeticOperationUnderflow)?, - ) - .ok_or(InternalError::ArithmeticOperationOverflow)? - .checked_add( - (exponent - & (2usize - .checked_pow(256) - .ok_or(InternalError::ArithmeticOperationOverflow)?) - .checked_sub(1) - .ok_or(InternalError::ArithmeticOperationOverflow)? - .into()) - .bits() - .checked_sub(1) - .ok_or(InternalError::ArithmeticOperationUnderflow)? - .try_into() - .map_err(|_| InternalError::ConversionError)?, - ) - .ok_or(InternalError::ArithmeticOperationOverflow)?; - } - + } else if exponent_size > 32 { + let extra_size = (exponent_size + .checked_sub(32) + .ok_or(InternalError::ArithmeticOperationUnderflow)?) + .checked_mul(8) + .ok_or(OutOfGasError::GasCostOverflow)?; + extra_size + .checked_add(exponent.bits().max(1)) + .ok_or(OutOfGasError::GasCostOverflow)? + .checked_sub(1) + .ok_or(InternalError::ArithmeticOperationUnderflow)? + } else { + 0 + }; let calculate_iteration_count = iteration_count.max(1); - let static_gas = MODEXP_STATIC_COST; - - let dynamic_gas = MODEXP_DYNAMIC_BASE.max( + let cost = MODEXP_STATIC_COST.max( multiplication_complexity .checked_mul(calculate_iteration_count) .ok_or(OutOfGasError::GasCostOverflow)? / MODEXP_DYNAMIC_QUOTIENT, ); - Ok(static_gas - .checked_add(dynamic_gas) - .ok_or(OutOfGasError::GasCostOverflow)?) + Ok(cost) } -fn precompile(data_size: usize, static_cost: u64, dynamic_base: u64) -> Result { +fn precompile(data_size: usize, static_cost: u64, dynamic_base: u64) -> Result { let data_size: u64 = data_size .try_into() .map_err(|_| PrecompileError::ParsingInputError)?; @@ -851,8 +899,7 @@ fn precompile(data_size: usize, static_cost: u64, dynamic_base: u64) -> Result Result Result { let mut remaining_gas = current_call_frame .gas_limit - .low_u64() - .checked_sub(current_call_frame.gas_used.low_u64()) + .checked_sub(current_call_frame.gas_used) .ok_or(InternalError::GasOverflow)?; remaining_gas = remaining_gas diff --git a/crates/vm/levm/src/memory.rs b/crates/vm/levm/src/memory.rs index a94c0d7cf..e20de3db2 100644 --- a/crates/vm/levm/src/memory.rs +++ b/crates/vm/levm/src/memory.rs @@ -139,7 +139,10 @@ pub fn try_copy_within( .map_err(|_err| VMError::VeryLargeNumber)?; try_resize( memory, - to_offset.checked_add(size).ok_or(VMError::OutOfBounds)?, + to_offset + .max(from_offset) + .checked_add(size) + .ok_or(VMError::OutOfBounds)?, )?; let mut temporary_buffer = vec![0u8; size]; diff --git a/crates/vm/levm/src/opcode_handlers/block.rs b/crates/vm/levm/src/opcode_handlers/block.rs index a5796f012..562c2691c 100644 --- a/crates/vm/levm/src/opcode_handlers/block.rs +++ b/crates/vm/levm/src/opcode_handlers/block.rs @@ -110,7 +110,9 @@ impl VM { ) -> Result { self.increase_consumed_gas(current_call_frame, gas_cost::GASLIMIT)?; - current_call_frame.stack.push(self.env.block_gas_limit)?; + current_call_frame + .stack + .push(self.env.block_gas_limit.into())?; Ok(OpcodeSuccess::Continue) } @@ -160,21 +162,26 @@ impl VM { ) -> Result { self.increase_consumed_gas(current_call_frame, gas_cost::BLOBHASH)?; - let Ok(index) = TryInto::::try_into(current_call_frame.stack.pop()?) else { + let index = current_call_frame.stack.pop()?; + + let blob_hashes = &self.env.tx_blob_hashes; + if index > blob_hashes.len().into() { current_call_frame.stack.push(U256::zero())?; return Ok(OpcodeSuccess::Continue); - }; + } - let blob_hashes = &self.env.tx_blob_hashes; + let index: usize = index + .try_into() + .map_err(|_| VMError::Internal(InternalError::ConversionError))?; - blob_hashes + //This should never fail because we check if the index fits above + let blob_hash = blob_hashes .get(index) - .map(|el| { - current_call_frame - .stack - .push(U256::from_big_endian(el.as_bytes())) - }) - .unwrap_or_else(|| current_call_frame.stack.push(U256::zero()))?; + .ok_or(VMError::Internal(InternalError::BlobHashOutOfRange))?; + + current_call_frame + .stack + .push(U256::from_big_endian(blob_hash.as_bytes()))?; Ok(OpcodeSuccess::Continue) } diff --git a/crates/vm/levm/src/opcode_handlers/logging.rs b/crates/vm/levm/src/opcode_handlers/logging.rs index 9ba7e2504..ed6df2552 100644 --- a/crates/vm/levm/src/opcode_handlers/logging.rs +++ b/crates/vm/levm/src/opcode_handlers/logging.rs @@ -49,7 +49,7 @@ impl VM { )?; let log = Log { - address: current_call_frame.msg_sender, // Should change the addr if we are on a Call/Create transaction (Call should be the contract we are calling, Create should be the original caller) + address: current_call_frame.to, topics, data: Bytes::from( memory::load_range(&mut current_call_frame.memory, offset, size)?.to_vec(), diff --git a/crates/vm/levm/src/opcode_handlers/stack_memory_storage_flow.rs b/crates/vm/levm/src/opcode_handlers/stack_memory_storage_flow.rs index 0c803c1f1..36a50e5e3 100644 --- a/crates/vm/levm/src/opcode_handlers/stack_memory_storage_flow.rs +++ b/crates/vm/levm/src/opcode_handlers/stack_memory_storage_flow.rs @@ -27,7 +27,8 @@ impl VM { self.increase_consumed_gas(current_call_frame, gas_cost::TLOAD)?; let key = current_call_frame.stack.pop()?; - let value = current_call_frame + let value = self + .env .transient_storage .get(&(current_call_frame.msg_sender, key)) .cloned() @@ -44,9 +45,13 @@ impl VM { ) -> Result { self.increase_consumed_gas(current_call_frame, gas_cost::TSTORE)?; + if current_call_frame.is_static { + return Err(VMError::OpcodeNotAllowedInStaticContext); + } + let key = current_call_frame.stack.pop()?; let value = current_call_frame.stack.pop()?; - current_call_frame + self.env .transient_storage .insert((current_call_frame.msg_sender, key), value); @@ -178,46 +183,42 @@ impl VM { )?; // Gas Refunds - // TODO: Think about what to do in case of underflow of gas refunds (when we try to substract from it if the value is low) - let mut gas_refunds = U256::zero(); + // Sync gas refund with global env, ensuring consistency accross contexts. + let mut gas_refunds = self.env.refunded_gas; + if new_storage_slot_value != storage_slot.current_value { if storage_slot.current_value == storage_slot.original_value { if !storage_slot.original_value.is_zero() && new_storage_slot_value.is_zero() { gas_refunds = gas_refunds - .checked_add(U256::from(4800)) + .checked_add(4800) .ok_or(VMError::GasRefundsOverflow)?; } } else if !storage_slot.original_value.is_zero() { if storage_slot.current_value.is_zero() { gas_refunds = gas_refunds - .checked_sub(U256::from(4800)) + .checked_sub(4800) .ok_or(VMError::GasRefundsUnderflow)?; } else if new_storage_slot_value.is_zero() { gas_refunds = gas_refunds - .checked_add(U256::from(4800)) + .checked_add(4800) .ok_or(VMError::GasRefundsOverflow)?; } } else if new_storage_slot_value == storage_slot.original_value { if storage_slot.original_value.is_zero() { gas_refunds = gas_refunds - .checked_add(U256::from(19900)) + .checked_add(19900) .ok_or(VMError::GasRefundsOverflow)?; } else { gas_refunds = gas_refunds - .checked_add(U256::from(2800)) + .checked_add(2800) .ok_or(VMError::GasRefundsOverflow)?; } } }; - self.env.refunded_gas = self - .env - .refunded_gas - .checked_add(gas_refunds) - .ok_or(VMError::GasLimitPriceProductOverflow)?; + self.env.refunded_gas = gas_refunds; self.update_account_storage(current_call_frame.to, key, new_storage_slot_value)?; - Ok(OpcodeSuccess::Continue) } @@ -242,7 +243,7 @@ impl VM { .checked_sub(current_call_frame.gas_used) .ok_or(OutOfGasError::ConsumedGasOverflow)?; // Note: These are not consumed gas calculations, but are related, so I used this wrapping here - current_call_frame.stack.push(remaining_gas)?; + current_call_frame.stack.push(remaining_gas.into())?; Ok(OpcodeSuccess::Continue) } diff --git a/crates/vm/levm/src/opcode_handlers/system.rs b/crates/vm/levm/src/opcode_handlers/system.rs index 2cb3700a3..fa06122d5 100644 --- a/crates/vm/levm/src/opcode_handlers/system.rs +++ b/crates/vm/levm/src/opcode_handlers/system.rs @@ -71,7 +71,7 @@ impl VM { // We add the stipend gas for the subcall. This ensures that the callee has enough gas to perform basic operations let gas_for_subcall = if !value_to_transfer.is_zero() { - gas.saturating_add(CALL_POSITIVE_VALUE_STIPEND) + gas.saturating_add(CALL_POSITIVE_VALUE_STIPEND.into()) } else { gas }; @@ -142,7 +142,7 @@ impl VM { // We add the stipend gas for the subcall. This ensures that the callee has enough gas to perform basic operations let gas_for_subcall = if !value_to_transfer.is_zero() { - gas.saturating_add(CALLCODE_POSITIVE_VALUE_STIPEND) + gas.saturating_add(CALLCODE_POSITIVE_VALUE_STIPEND.into()) } else { gas }; @@ -180,10 +180,13 @@ impl VM { } let new_memory_size = calculate_memory_size(offset, size)?; - self.increase_consumed_gas( - current_call_frame, - memory::expansion_cost(new_memory_size, current_call_frame.memory.len())?.into(), - )?; + + let memory_expansion_cost: u64 = + memory::expansion_cost(new_memory_size, current_call_frame.memory.len())? + .try_into() + .map_err(|_err| VMError::Internal(InternalError::ConversionError))?; + + self.increase_consumed_gas(current_call_frame, memory_expansion_cost)?; current_call_frame.output = memory::load_range(&mut current_call_frame.memory, offset, size)? @@ -396,10 +399,13 @@ impl VM { .map_err(|_err| VMError::VeryLargeNumber)?; let new_memory_size = calculate_memory_size(offset, size)?; - self.increase_consumed_gas( - current_call_frame, - memory::expansion_cost(new_memory_size, current_call_frame.memory.len())?.into(), - )?; + + let memory_expansion_cost: u64 = + memory::expansion_cost(new_memory_size, current_call_frame.memory.len())? + .try_into() + .map_err(|_err| VMError::Internal(InternalError::ConversionError))?; + + self.increase_consumed_gas(current_call_frame, memory_expansion_cost)?; current_call_frame.output = memory::load_range(&mut current_call_frame.memory, offset, size)? @@ -486,32 +492,16 @@ impl VM { return Err(VMError::OutOfGas(OutOfGasError::ConsumedGasOverflow)); } - // SECOND: Validations that push 0 to the stack - let deployer_address = current_call_frame.to; - - let deployer_account_info = self.access_account(deployer_address).0; + // Reserve gas for subcall + let max_message_call_gas = max_message_call_gas(current_call_frame)?; + self.increase_consumed_gas(current_call_frame, max_message_call_gas)?; - // 1. Sender doesn't have enough balance to send value. - if deployer_account_info.balance < value_in_wei_to_send { - current_call_frame.stack.push(CREATE_DEPLOYMENT_FAIL)?; - return Ok(OpcodeSuccess::Continue); - } + // Clear callframe subreturn data + current_call_frame.sub_return_data = Bytes::new(); - // 2. Depth limit has been reached - let new_depth = current_call_frame - .depth - .checked_add(1) - .ok_or(InternalError::ArithmeticOperationOverflow)?; - if new_depth > 1024 { - current_call_frame.stack.push(CREATE_DEPLOYMENT_FAIL)?; - return Ok(OpcodeSuccess::Continue); - } + let deployer_address = current_call_frame.to; - // 3. Sender nonce is max. - if deployer_account_info.nonce == u64::MAX { - current_call_frame.stack.push(CREATE_DEPLOYMENT_FAIL)?; - return Ok(OpcodeSuccess::Continue); - } + let deployer_account_info = self.access_account(deployer_address).0; let code = Bytes::from( memory::load_range( @@ -527,15 +517,48 @@ impl VM { None => Self::calculate_create_address(deployer_address, deployer_account_info.nonce)?, }; - // 3. Account has nonce or code. - if self.get_account(new_address).has_code_or_nonce() { + // touch account + self.accrued_substate.touched_accounts.insert(new_address); + + let new_depth = current_call_frame + .depth + .checked_add(1) + .ok_or(InternalError::ArithmeticOperationOverflow)?; + // SECOND: Validations that push 0 to the stack and return reserved_gas + // 1. Sender doesn't have enough balance to send value. + // 2. Depth limit has been reached + // 3. Sender nonce is max. + if deployer_account_info.balance < value_in_wei_to_send + || new_depth > 1024 + || deployer_account_info.nonce == u64::MAX + { + // Return reserved gas + current_call_frame.gas_used = current_call_frame + .gas_used + .checked_sub(max_message_call_gas) + .ok_or(VMError::Internal(InternalError::GasOverflow))?; + // Push 0 + current_call_frame.stack.push(CREATE_DEPLOYMENT_FAIL)?; + return Ok(OpcodeSuccess::Continue); + } + + // THIRD: Validations that push 0 to the stack without returning reserved gas but incrementing deployer's nonce + let new_account = self.get_account(new_address); + if new_account.has_code_or_nonce() { + self.increment_account_nonce(deployer_address)?; current_call_frame.stack.push(CREATE_DEPLOYMENT_FAIL)?; return Ok(OpcodeSuccess::Continue); } - // THIRD: Changes to the state + // FOURTH: Changes to the state // 1. Creating contract. - let new_account = Account::new(value_in_wei_to_send, Bytes::new(), 1, Default::default()); + + // If the address has balance but there is no account associated with it, we need to add the value to it + let new_balance = value_in_wei_to_send + .checked_add(new_account.info.balance) + .ok_or(VMError::BalanceOverflow)?; + + let new_account = Account::new(new_balance, Bytes::new(), 1, Default::default()); cache::insert_account(&mut self.cache, new_address, new_account); // 2. Increment sender's nonce. @@ -544,7 +567,6 @@ impl VM { // 3. Decrease sender's balance. self.decrease_account_balance(deployer_address, value_in_wei_to_send)?; - let max_message_call_gas = max_message_call_gas(current_call_frame)?; let mut new_call_frame = CallFrame::new( deployer_address, new_address, @@ -553,21 +575,25 @@ impl VM { value_in_wei_to_send, Bytes::new(), false, - U256::from(max_message_call_gas), - U256::zero(), + max_message_call_gas, + 0, new_depth, true, ); self.accrued_substate.created_accounts.insert(new_address); // Mostly for SELFDESTRUCT during initcode. - self.accrued_substate.touched_accounts.insert(new_address); let tx_report = self.execute(&mut new_call_frame)?; + let unused_gas = max_message_call_gas + .checked_sub(tx_report.gas_used) + .ok_or(InternalError::GasOverflow)?; + // Return reserved gas current_call_frame.gas_used = current_call_frame .gas_used - .checked_add(tx_report.gas_used.into()) - .ok_or(VMError::OutOfGas(OutOfGasError::ConsumedGasOverflow))?; + .checked_sub(unused_gas) + .ok_or(InternalError::GasOverflow)?; + current_call_frame.logs.extend(tx_report.logs); match tx_report.result { @@ -576,15 +602,18 @@ impl VM { .stack .push(address_to_word(new_address))?; } - TxResult::Revert(_) => { + TxResult::Revert(err) => { // Return value to sender self.increase_account_balance(deployer_address, value_in_wei_to_send)?; // Deployment failed so account shouldn't exist cache::remove_account(&mut self.cache, &new_address); self.accrued_substate.created_accounts.remove(&new_address); - self.accrued_substate.touched_accounts.remove(&new_address); + // If revert we have to copy the return_data + if err == VMError::RevertOpcode { + current_call_frame.sub_return_data = tx_report.output; + } current_call_frame.stack.push(CREATE_DEPLOYMENT_FAIL)?; } } @@ -593,6 +622,9 @@ impl VM { } #[allow(clippy::too_many_arguments)] + /// This (should) be the only function where gas is used as a + /// U256. This is because we have to use the values that are + /// pushed to the stack. pub fn generic_call( &mut self, current_call_frame: &mut CallFrame, @@ -608,6 +640,12 @@ impl VM { ret_offset: U256, ret_size: usize, ) -> Result { + // Clear callframe subreturn data + current_call_frame.sub_return_data = Bytes::new(); + + let calldata = + memory::load_range(&mut current_call_frame.memory, args_offset, args_size)?.to_vec(); + // 1. Validate sender has enough value let sender_account_info = self.access_account(msg_sender).0; if should_transfer_value && sender_account_info.balance < value { @@ -627,12 +665,16 @@ impl VM { } let recipient_bytecode = self.access_account(code_address).0.bytecode; - let calldata = - memory::load_range(&mut current_call_frame.memory, args_offset, args_size)?.to_vec(); // Gas Limit for the child context is capped. let gas_cap = max_message_call_gas(current_call_frame)?; let gas_limit = std::cmp::min(gas_limit, gas_cap.into()); + // This should always cast correcly because the gas_cap is in + // u64; therefore, at most, it will be u64::MAX + let gas_limit: u64 = gas_limit + .try_into() + .map_err(|_| VMError::Internal(InternalError::ConversionError))?; + let mut new_call_frame = CallFrame::new( msg_sender, to, @@ -642,7 +684,7 @@ impl VM { calldata.into(), is_static, gas_limit, - U256::zero(), + 0, new_depth, false, ); @@ -658,7 +700,7 @@ impl VM { // Add gas used by the sub-context to the current one after it's execution. current_call_frame.gas_used = current_call_frame .gas_used - .checked_add(tx_report.gas_used.into()) + .checked_add(tx_report.gas_used) .ok_or(VMError::OutOfGas(OutOfGasError::ConsumedGasOverflow))?; current_call_frame.logs.extend(tx_report.logs); memory::try_store_range( diff --git a/crates/vm/levm/src/precompiles.rs b/crates/vm/levm/src/precompiles.rs index 73fc99ece..1c9412d09 100644 --- a/crates/vm/levm/src/precompiles.rs +++ b/crates/vm/levm/src/precompiles.rs @@ -1,13 +1,23 @@ use bytes::Bytes; use ethrex_core::{Address, H160, U256}; use keccak_hash::keccak256; +use lambdaworks_math::{ + cyclic_group::IsGroup, + elliptic_curve::{ + short_weierstrass::curves::bn_254::curve::{BN254Curve, BN254FieldElement}, + traits::IsEllipticCurve, + }, + traits::ByteConversion, + unsigned_integer::element, +}; use libsecp256k1::{self, Message, RecoveryId, Signature}; +use num_bigint::BigUint; use sha3::Digest; use crate::{ call_frame::CallFrame, - errors::{InternalError, PrecompileError, VMError}, - gas_cost::{sha2_256 as sha2_256_cost, ECRECOVER_COST}, + errors::{InternalError, OutOfGasError, PrecompileError, VMError}, + gas_cost::{self, ECADD_COST, ECMUL_COST, ECRECOVER_COST, MODEXP_STATIC_COST}, }; pub const ECRECOVER_ADDRESS: H160 = H160([ @@ -101,9 +111,9 @@ pub fn execute_precompile(current_call_frame: &mut CallFrame) -> Result Result<(), VMError> { if gas_for_call < gas_cost { return Err(VMError::PrecompileError(PrecompileError::NotEnoughGas)); @@ -118,32 +128,30 @@ fn increase_precompile_consumed_gas( /// When slice length is less than 128, the rest is filled with zeros. If slice length is /// more than 128 the excess bytes are discarded. -fn fill_with_zeros(slice: &[u8]) -> Result<[u8; 128], VMError> { - let mut result = [0; 128]; - - let n = slice.len().min(128); - - let trimmed_slice: &[u8] = slice.get(..n).unwrap_or_default(); - - for i in 0..n { - let byte: &mut u8 = result.get_mut(i).ok_or(InternalError::SlicingError)?; - *byte = *trimmed_slice.get(i).ok_or(InternalError::SlicingError)?; +fn fill_with_zeros(calldata: &Bytes, target_len: usize) -> Result { + let mut padded_calldata = calldata.to_vec(); + if padded_calldata.len() < target_len { + let size_diff = target_len + .checked_sub(padded_calldata.len()) + .ok_or(InternalError::ArithmeticOperationUnderflow)?; + padded_calldata.extend(vec![0u8; size_diff]); } - - Ok(result) + Ok(padded_calldata.into()) } +/// ECDSA (Elliptic curve digital signature algorithm) public key recovery function. +/// Given a hash, a Signature and a recovery Id, returns the public key recovered by secp256k1 pub fn ecrecover( calldata: &Bytes, - gas_for_call: U256, - consumed_gas: &mut U256, + gas_for_call: u64, + consumed_gas: &mut u64, ) -> Result { - let gas_cost = ECRECOVER_COST.into(); + let gas_cost = ECRECOVER_COST; increase_precompile_consumed_gas(gas_for_call, gas_cost, consumed_gas)?; // If calldata does not reach the required length, we should fill the rest with zeros - let calldata = fill_with_zeros(calldata)?; + let calldata = fill_with_zeros(calldata, 128)?; // Parse the input elements, first as a slice of bytes and then as an specific type of the crate let hash = calldata.get(0..32).ok_or(InternalError::SlicingError)?; @@ -191,20 +199,25 @@ pub fn ecrecover( Ok(Bytes::from(output.to_vec())) } -fn identity( - _calldata: &Bytes, - _gas_for_call: U256, - _consumed_gas: &mut U256, +pub fn identity( + calldata: &Bytes, + gas_for_call: u64, + consumed_gas: &mut u64, ) -> Result { - Ok(Bytes::new()) + let gas_cost = gas_cost::identity(calldata.len())?; + + increase_precompile_consumed_gas(gas_for_call, gas_cost, consumed_gas)?; + + Ok(calldata.clone()) } -fn sha2_256( +/// Returns the calldata hashed by sha2-256 algorithm +pub fn sha2_256( calldata: &Bytes, - gas_for_call: U256, - consumed_gas: &mut U256, + gas_for_call: u64, + consumed_gas: &mut u64, ) -> Result { - let gas_cost = sha2_256_cost(calldata.len())?; + let gas_cost = gas_cost::sha2_256(calldata.len())?; increase_precompile_consumed_gas(gas_for_call, gas_cost, consumed_gas)?; @@ -213,58 +226,301 @@ fn sha2_256( Ok(Bytes::from(result)) } -fn ripemd_160( - _calldata: &Bytes, - _gas_for_call: U256, - _consumed_gas: &mut U256, +/// Returns the calldata hashed by ripemd-160 algorithm, padded by zeros at left +pub fn ripemd_160( + calldata: &Bytes, + gas_for_call: u64, + consumed_gas: &mut u64, ) -> Result { - Ok(Bytes::new()) + let gas_cost = gas_cost::ripemd_160(calldata.len())?; + + increase_precompile_consumed_gas(gas_for_call, gas_cost, consumed_gas)?; + + let mut hasher = ripemd::Ripemd160::new(); + hasher.update(calldata); + let result = hasher.finalize(); + + let mut output = vec![0; 12]; + output.extend_from_slice(&result); + + Ok(Bytes::from(output)) } -fn modexp( - _calldata: &Bytes, - _gas_for_call: U256, - _consumed_gas: &mut U256, +pub fn modexp( + calldata: &Bytes, + gas_for_call: u64, + consumed_gas: &mut u64, ) -> Result { - Ok(Bytes::new()) + // If calldata does not reach the required length, we should fill the rest with zeros + let calldata = fill_with_zeros(calldata, 96)?; + + let b_size: U256 = calldata + .get(0..32) + .ok_or(PrecompileError::ParsingInputError)? + .into(); + + let e_size: U256 = calldata + .get(32..64) + .ok_or(PrecompileError::ParsingInputError)? + .into(); + + let m_size: U256 = calldata + .get(64..96) + .ok_or(PrecompileError::ParsingInputError)? + .into(); + + if b_size == U256::zero() && m_size == U256::zero() { + *consumed_gas = consumed_gas + .checked_add(MODEXP_STATIC_COST) + .ok_or(OutOfGasError::ConsumedGasOverflow)?; + return Ok(Bytes::new()); + } + + // Because on some cases conversions to usize exploded before the check of the zero value could be done + let b_size = usize::try_from(b_size).map_err(|_| PrecompileError::ParsingInputError)?; + let e_size = usize::try_from(e_size).map_err(|_| PrecompileError::ParsingInputError)?; + let m_size = usize::try_from(m_size).map_err(|_| PrecompileError::ParsingInputError)?; + + let base_limit = b_size + .checked_add(96) + .ok_or(InternalError::ArithmeticOperationOverflow)?; + + let exponent_limit = e_size + .checked_add(base_limit) + .ok_or(InternalError::ArithmeticOperationOverflow)?; + + // The reason I use unwrap_or_default is to cover the case where calldata does not reach the required + // length, so then we should fill the rest with zeros. The same is done in modulus parsing + let b = get_slice_or_default(&calldata, 96, base_limit, b_size)?; + let base = BigUint::from_bytes_be(&b); + + let e = get_slice_or_default(&calldata, base_limit, exponent_limit, e_size)?; + let exponent = BigUint::from_bytes_be(&e); + + let m = match calldata.get(exponent_limit..) { + Some(m) => { + let m_extended = fill_with_zeros(&Bytes::from(m.to_vec()), m_size)?; + m_extended.get(..m_size).unwrap_or_default().to_vec() + } + None => Default::default(), + }; + let modulus = BigUint::from_bytes_be(&m); + + let gas_cost = gas_cost::modexp(&exponent, b_size, e_size, m_size)?; + increase_precompile_consumed_gas(gas_for_call, gas_cost, consumed_gas)?; + + let result = mod_exp(base, exponent, modulus); + + let res_bytes = result.to_bytes_be(); + let res_bytes = increase_left_pad(&Bytes::from(res_bytes), m_size)?; + + Ok(res_bytes.slice(..m_size)) } -fn ecadd( - _calldata: &Bytes, - _gas_for_call: U256, - _consumed_gas: &mut U256, +fn get_slice_or_default( + calldata: &Bytes, + lower_limit: usize, + upper_limit: usize, + size_to_expand: usize, +) -> Result, VMError> { + match calldata.get(lower_limit..upper_limit) { + Some(e) => { + let e_extended = fill_with_zeros(&Bytes::from(e.to_vec()), size_to_expand)?; + Ok(e_extended + .get(..size_to_expand) + .unwrap_or_default() + .to_vec()) + } + None => Ok(Default::default()), + } +} + +/// I allow this clippy alert because in the code modulus could never be +/// zero because that case is covered in the if above that line +#[allow(clippy::arithmetic_side_effects)] +fn mod_exp(base: BigUint, exponent: BigUint, modulus: BigUint) -> BigUint { + if modulus == BigUint::ZERO { + BigUint::ZERO + } else if exponent == BigUint::ZERO { + BigUint::from(1_u8) % modulus + } else { + base.modpow(&exponent, &modulus) + } +} + +pub fn increase_left_pad(result: &Bytes, m_size: usize) -> Result { + let mut padded_result = vec![0u8; m_size]; + if result.len() < m_size { + let size_diff = m_size + .checked_sub(result.len()) + .ok_or(InternalError::ArithmeticOperationUnderflow)?; + padded_result + .get_mut(size_diff..) + .ok_or(InternalError::SlicingError)? + .copy_from_slice(result); + + Ok(padded_result.into()) + } else { + Ok(result.clone()) + } +} + +pub fn ecadd( + calldata: &Bytes, + gas_for_call: u64, + consumed_gas: &mut u64, ) -> Result { - Ok(Bytes::new()) + // If calldata does not reach the required length, we should fill the rest with zeros + let calldata = fill_with_zeros(calldata, 128)?; + + increase_precompile_consumed_gas(gas_for_call, ECADD_COST, consumed_gas)?; + + let first_point_x = calldata + .get(0..32) + .ok_or(PrecompileError::ParsingInputError)?; + + let first_point_y = calldata + .get(32..64) + .ok_or(PrecompileError::ParsingInputError)?; + + let second_point_x = calldata + .get(64..96) + .ok_or(PrecompileError::ParsingInputError)?; + + let second_point_y = calldata + .get(96..128) + .ok_or(PrecompileError::ParsingInputError)?; + + // If points are zero the precompile should not fail, but the conversion in + // BN254Curve::create_point_from_affine will, so we verify it before the conversion + let first_point_is_zero = U256::from_big_endian(first_point_x).is_zero() + && U256::from_big_endian(first_point_y).is_zero(); + let second_point_is_zero = U256::from_big_endian(second_point_x).is_zero() + && U256::from_big_endian(second_point_y).is_zero(); + + let first_point_x = BN254FieldElement::from_bytes_be(first_point_x) + .map_err(|_| PrecompileError::ParsingInputError)?; + let first_point_y = BN254FieldElement::from_bytes_be(first_point_y) + .map_err(|_| PrecompileError::ParsingInputError)?; + let second_point_x = BN254FieldElement::from_bytes_be(second_point_x) + .map_err(|_| PrecompileError::ParsingInputError)?; + let second_point_y = BN254FieldElement::from_bytes_be(second_point_y) + .map_err(|_| PrecompileError::ParsingInputError)?; + + if first_point_is_zero && second_point_is_zero { + // If both points are zero, return is zero + Ok(Bytes::from([0u8; 64].to_vec())) + } else if first_point_is_zero { + // If first point is zero, return is second point + let second_point = BN254Curve::create_point_from_affine(second_point_x, second_point_y) + .map_err(|_| PrecompileError::ParsingInputError)?; + let res = [ + second_point.x().to_bytes_be(), + second_point.y().to_bytes_be(), + ] + .concat(); + Ok(Bytes::from(res)) + } else if second_point_is_zero { + // If second point is zero, return is first point + let first_point = BN254Curve::create_point_from_affine(first_point_x, first_point_y) + .map_err(|_| PrecompileError::ParsingInputError)?; + let res = [first_point.x().to_bytes_be(), first_point.y().to_bytes_be()].concat(); + Ok(Bytes::from(res)) + } else { + // If none of the points is zero, return is the sum of both in the EC + let first_point = BN254Curve::create_point_from_affine(first_point_x, first_point_y) + .map_err(|_| PrecompileError::ParsingInputError)?; + let second_point = BN254Curve::create_point_from_affine(second_point_x, second_point_y) + .map_err(|_| PrecompileError::ParsingInputError)?; + let sum = first_point.operate_with(&second_point).to_affine(); + + if U256::from_big_endian(&sum.x().to_bytes_be()) == U256::zero() + || U256::from_big_endian(&sum.y().to_bytes_be()) == U256::zero() + { + Ok(Bytes::from([0u8; 64].to_vec())) + } else { + let res = [sum.x().to_bytes_be(), sum.y().to_bytes_be()].concat(); + Ok(Bytes::from(res)) + } + } } -fn ecmul( - _calldata: &Bytes, - _gas_for_call: U256, - _consumed_gas: &mut U256, +pub fn ecmul( + calldata: &Bytes, + gas_for_call: u64, + consumed_gas: &mut u64, ) -> Result { - Ok(Bytes::new()) + // If calldata does not reach the required length, we should fill the rest with zeros + let calldata = fill_with_zeros(calldata, 96)?; + + increase_precompile_consumed_gas(gas_for_call, ECMUL_COST, consumed_gas)?; + + let point_x = calldata + .get(0..32) + .ok_or(PrecompileError::ParsingInputError)?; + + let point_y = calldata + .get(32..64) + .ok_or(PrecompileError::ParsingInputError)?; + + let scalar = calldata + .get(64..96) + .ok_or(PrecompileError::ParsingInputError)?; + let scalar = + element::U256::from_bytes_be(scalar).map_err(|_| PrecompileError::ParsingInputError)?; + + // If point is zero the precompile should not fail, but the conversion in + // BN254Curve::create_point_from_affine will, so we verify it before the conversion + let point_is_zero = + U256::from_big_endian(point_x).is_zero() && U256::from_big_endian(point_y).is_zero(); + if point_is_zero { + return Ok(Bytes::from([0u8; 64].to_vec())); + } + + let point_x = BN254FieldElement::from_bytes_be(point_x) + .map_err(|_| PrecompileError::ParsingInputError)?; + let point_y = BN254FieldElement::from_bytes_be(point_y) + .map_err(|_| PrecompileError::ParsingInputError)?; + + let point = BN254Curve::create_point_from_affine(point_x, point_y) + .map_err(|_| PrecompileError::ParsingInputError)?; + + let zero_u256 = element::U256::from(0_u16); + if scalar.eq(&zero_u256) { + Ok(Bytes::from([0u8; 64].to_vec())) + } else { + let mul = point.operate_with_self(scalar).to_affine(); + if U256::from_big_endian(&mul.x().to_bytes_be()) == U256::zero() + || U256::from_big_endian(&mul.y().to_bytes_be()) == U256::zero() + { + Ok(Bytes::from([0u8; 64].to_vec())) + } else { + let res = [mul.x().to_bytes_be(), mul.y().to_bytes_be()].concat(); + Ok(Bytes::from(res)) + } + } } fn ecpairing( _calldata: &Bytes, - _gas_for_call: U256, - _consumed_gas: &mut U256, + _gas_for_call: u64, + _consumed_gas: &mut u64, ) -> Result { Ok(Bytes::new()) } fn blake2f( _calldata: &Bytes, - _gas_for_call: U256, - _consumed_gas: &mut U256, + _gas_for_call: u64, + _consumed_gas: &mut u64, ) -> Result { Ok(Bytes::new()) } fn point_evaluation( _calldata: &Bytes, - _gas_for_call: U256, - _consumed_gas: &mut U256, + _gas_for_call: u64, + _consumed_gas: &mut u64, ) -> Result { Ok(Bytes::new()) } diff --git a/crates/vm/levm/src/vm.rs b/crates/vm/levm/src/vm.rs index d33388af2..846d98a05 100644 --- a/crates/vm/levm/src/vm.rs +++ b/crates/vm/levm/src/vm.rs @@ -17,7 +17,7 @@ use crate::{ }, opcodes::Opcode, precompiles::{execute_precompile, is_precompile}, - AccountInfo, + AccountInfo, TransientStorage, }; use bytes::Bytes; use ethrex_core::{types::TxKind, Address, H256, U256}; @@ -158,25 +158,19 @@ impl VM { TxKind::Call(address_to) => { default_touched_accounts.insert(address_to); - // add address_to to cache - let recipient_account_info = db.get_account_info(address_to); - cache::insert_account( - &mut cache, - address_to, - Account::from(recipient_account_info.clone()), - ); + let bytecode = get_account(&mut cache, &db, address_to).info.bytecode; // CALL tx let initial_call_frame = CallFrame::new( env.origin, address_to, address_to, - recipient_account_info.bytecode, + bytecode, value, calldata.clone(), false, env.gas_limit, - U256::zero(), + 0, 0, false, ); @@ -201,18 +195,14 @@ impl VM { TxKind::Create => { // CREATE tx - let new_contract_address = - VM::calculate_create_address(env.origin, db.get_account_info(env.origin).nonce) - .map_err(|_| { - VMError::Internal(InternalError::CouldNotComputeCreateAddress) - })?; + let sender_nonce = get_account(&mut cache, &db, env.origin).info.nonce; + let new_contract_address = VM::calculate_create_address(env.origin, sender_nonce) + .map_err(|_| { + VMError::Internal(InternalError::CouldNotComputeCreateAddress) + })?; default_touched_accounts.insert(new_contract_address); - let created_contract = Account::new(value, Bytes::new(), 1, HashMap::new()); - - cache::insert_account(&mut cache, new_contract_address, created_contract); - let initial_call_frame = CallFrame::new( env.origin, new_contract_address, @@ -222,7 +212,7 @@ impl VM { calldata, // Calldata is removed after passing validations. false, env.gas_limit, - U256::zero(), + 0, 0, false, ); @@ -251,11 +241,12 @@ impl VM { &mut self, current_call_frame: &mut CallFrame, ) -> Result { - // Backup of Database, Substate and Gas Refunds if sub-context is reverted - let (backup_db, backup_substate, backup_refunded_gas) = ( + // Backup of Database, Substate, Gas Refunds and Transient Storage if sub-context is reverted + let (backup_db, backup_substate, backup_refunded_gas, backup_transient_storage) = ( self.cache.clone(), self.accrued_substate.clone(), self.env.refunded_gas, + self.env.transient_storage.clone(), ); if is_precompile(¤t_call_frame.code_address) { @@ -268,7 +259,7 @@ impl VM { return Ok(TransactionReport { result: TxResult::Success, new_state: self.cache.clone(), - gas_used: current_call_frame.gas_used.low_u64(), + gas_used: current_call_frame.gas_used, gas_refunded: 0, output, logs: current_call_frame.logs.clone(), @@ -282,12 +273,17 @@ impl VM { self.call_frames.push(current_call_frame.clone()); - self.restore_state(backup_db, backup_substate, backup_refunded_gas); + self.restore_state( + backup_db, + backup_substate, + backup_refunded_gas, + backup_transient_storage, + ); return Ok(TransactionReport { result: TxResult::Revert(error), new_state: self.cache.clone(), - gas_used: current_call_frame.gas_limit.low_u64(), + gas_used: current_call_frame.gas_limit, gas_refunded: 0, output: Bytes::new(), logs: current_call_frame.logs.clone(), @@ -420,11 +416,15 @@ impl VM { { let contract_code = current_call_frame.output.clone(); let code_length = contract_code.len(); - let code_deposit_cost = U256::from(code_length) - .checked_mul(CODE_DEPOSIT_COST) - .ok_or(VMError::Internal( - InternalError::ArithmeticOperationOverflow, - ))?; + + let code_length_u64: u64 = code_length + .try_into() + .map_err(|_| VMError::Internal(InternalError::ConversionError))?; + + let code_deposit_cost: u64 = + code_length_u64.checked_mul(CODE_DEPOSIT_COST).ok_or( + VMError::Internal(InternalError::ArithmeticOperationOverflow), + )?; // Revert // If the first byte of code is 0xef @@ -451,13 +451,18 @@ impl VM { Err(error) => { // Revert if error current_call_frame.gas_used = current_call_frame.gas_limit; - self.restore_state(backup_db, backup_substate, backup_refunded_gas); + self.restore_state( + backup_db, + backup_substate, + backup_refunded_gas, + backup_transient_storage, + ); return Ok(TransactionReport { result: TxResult::Revert(error), new_state: self.cache.clone(), - gas_used: current_call_frame.gas_used.low_u64(), - gas_refunded: self.env.refunded_gas.low_u64(), + gas_used: current_call_frame.gas_used, + gas_refunded: self.env.refunded_gas, output: current_call_frame.output.clone(), logs: current_call_frame.logs.clone(), created_address: None, @@ -469,8 +474,8 @@ impl VM { return Ok(TransactionReport { result: TxResult::Success, new_state: self.cache.clone(), - gas_used: current_call_frame.gas_used.low_u64(), - gas_refunded: self.env.refunded_gas.low_u64(), + gas_used: current_call_frame.gas_used, + gas_refunded: self.env.refunded_gas, output: current_call_frame.output.clone(), logs: current_call_frame.logs.clone(), created_address: None, @@ -492,13 +497,18 @@ impl VM { current_call_frame.gas_used.saturating_add(left_gas); } - self.restore_state(backup_db, backup_substate, backup_refunded_gas); + self.restore_state( + backup_db, + backup_substate, + backup_refunded_gas, + backup_transient_storage, + ); return Ok(TransactionReport { result: TxResult::Revert(error), new_state: self.cache.clone(), - gas_used: current_call_frame.gas_used.low_u64(), - gas_refunded: self.env.refunded_gas.low_u64(), + gas_used: current_call_frame.gas_used, + gas_refunded: self.env.refunded_gas, output: current_call_frame.output.clone(), // Bytes::new() if error is not RevertOpcode logs: current_call_frame.logs.clone(), created_address: None, @@ -512,11 +522,13 @@ impl VM { &mut self, backup_cache: CacheDB, backup_substate: Substate, - backup_refunded_gas: U256, + backup_refunded_gas: u64, + backup_transient_storage: TransientStorage, ) { self.cache = backup_cache; self.accrued_substate = backup_substate; self.env.refunded_gas = backup_refunded_gas; + self.env.transient_storage = backup_transient_storage; } fn is_create(&self) -> bool { @@ -527,7 +539,7 @@ impl VM { // Intrinsic gas is the gas consumed by the transaction before the execution of the opcodes. Section 6.2 in the Yellow Paper. // Intrinsic Gas = Calldata cost + Create cost + Base cost + Access list cost - let mut intrinsic_gas = U256::zero(); + let mut intrinsic_gas: u64 = 0; // Calldata Cost // 4 gas for each zero byte in the transaction data 16 gas for each non-zero byte in the transaction. @@ -550,18 +562,19 @@ impl VM { .ok_or(OutOfGasError::ConsumedGasOverflow)?; let number_of_words = initial_call_frame.calldata.len().div_ceil(WORD_SIZE); + let double_number_of_words: u64 = number_of_words + .checked_mul(2) + .ok_or(OutOfGasError::ConsumedGasOverflow)? + .try_into() + .map_err(|_| VMError::Internal(InternalError::ConversionError))?; intrinsic_gas = intrinsic_gas - .checked_add( - U256::from(number_of_words) - .checked_mul(U256::from(2)) - .ok_or(OutOfGasError::ConsumedGasOverflow)?, - ) + .checked_add(double_number_of_words) .ok_or(OutOfGasError::ConsumedGasOverflow)?; } // Access List Cost - let mut access_lists_cost = U256::zero(); + let mut access_lists_cost: u64 = 0; for (_, keys) in self.access_list.clone() { access_lists_cost = access_lists_cost .checked_add(ACCESS_LIST_ADDRESS_COST) @@ -584,27 +597,62 @@ impl VM { } /// Gets the max blob gas cost for a transaction that a user is willing to pay. - fn get_max_blob_gas_cost(&self) -> Result { - let blob_gas_used = U256::from(self.env.tx_blob_hashes.len()) + fn get_max_blob_gas_price(&self) -> Result { + let blobhash_amount: u64 = self + .env + .tx_blob_hashes + .len() + .try_into() + .map_err(|_| VMError::Internal(InternalError::ConversionError))?; + + let blob_gas_used: u64 = blobhash_amount .checked_mul(BLOB_GAS_PER_BLOB) .unwrap_or_default(); - let blob_gas_cost = self + let max_blob_gas_cost = self .env .tx_max_fee_per_blob_gas .unwrap_or_default() - .checked_mul(blob_gas_used) + .checked_mul(blob_gas_used.into()) .ok_or(InternalError::UndefinedState(1))?; - Ok(blob_gas_cost) + Ok(max_blob_gas_cost) + } + + /// Gets the actual blob gas cost. + fn get_blob_gas_price(&self) -> Result { + let blobhash_amount: u64 = self + .env + .tx_blob_hashes + .len() + .try_into() + .map_err(|_| VMError::Internal(InternalError::ConversionError))?; + + let blob_gas_price: u64 = blobhash_amount + .checked_mul(BLOB_GAS_PER_BLOB) + .unwrap_or_default(); + + let base_fee_per_blob_gas = self.get_base_fee_per_blob_gas()?; + + let blob_gas_price: U256 = blob_gas_price.into(); + let blob_fee: U256 = blob_gas_price + .checked_mul(base_fee_per_blob_gas) + .ok_or(VMError::Internal(InternalError::UndefinedState(1)))?; + + Ok(blob_fee) } pub fn get_base_fee_per_blob_gas(&self) -> Result { fake_exponential( MIN_BASE_FEE_PER_BLOB_GAS, - self.env.block_excess_blob_gas.unwrap_or_default().low_u64(), //Maybe replace unwrap_or_default for sth else later. + self.env + .block_excess_blob_gas + .unwrap_or_default() + .try_into() + .map_err(|_| VMError::VeryLargeNumber)?, //Maybe replace unwrap_or_default for sth else later. BLOB_BASE_FEE_UPDATE_FRACTION, ) + .map(|ok_value| ok_value.into()) } /// ## Description @@ -616,32 +664,24 @@ impl VM { /// - It calculates and adds intrinsic gas to the 'gas used' of callframe and environment. /// See 'docs' for more information about validations. fn prepare_execution(&mut self, initial_call_frame: &mut CallFrame) -> Result<(), VMError> { - //TODO: This should revert the transaction, not throw an error. And I don't know if it should be done here... - // if self.is_create() { - // // If address is already in db, there's an error - // let new_address_acc = self.db.get_account_info(call_frame.to); - // if !new_address_acc.is_empty() { - // return Err(VMError::AddressAlreadyOccupied); - // } - // } let sender_address = self.env.origin; let sender_account = self.get_account(sender_address); // (1) GASLIMIT_PRICE_PRODUCT_OVERFLOW - let gaslimit_price_product = - self.env - .gas_price - .checked_mul(self.env.gas_limit) - .ok_or(VMError::TxValidation( - TxValidationError::GasLimitPriceProductOverflow, - ))?; + let gaslimit_price_product = self + .env + .gas_price + .checked_mul(self.env.gas_limit.into()) + .ok_or(VMError::TxValidation( + TxValidationError::GasLimitPriceProductOverflow, + ))?; // Up front cost is the maximum amount of wei that a user is willing to pay for. Gaslimit * gasprice + value + blob_gas_cost let value = initial_call_frame.msg_value; // blob gas cost = max fee per blob gas * blob gas used // https://eips.ethereum.org/EIPS/eip-4844 - let blob_gas_cost = self.get_max_blob_gas_cost()?; + let max_blob_gas_cost = self.get_max_blob_gas_price()?; // For the transaction to be valid the sender account has to have a balance >= gas_price * gas_limit + value if tx is type 0 and 1 // balance >= max_fee_per_gas * gas_limit + value + blob_gas_cost if tx is type 2 or 3 @@ -649,7 +689,7 @@ impl VM { .env .tx_max_fee_per_gas .unwrap_or(self.env.gas_price) - .checked_mul(self.env.gas_limit) + .checked_mul(self.env.gas_limit.into()) .ok_or(VMError::TxValidation( TxValidationError::GasLimitPriceProductOverflow, ))?; @@ -659,7 +699,7 @@ impl VM { .ok_or(VMError::TxValidation( TxValidationError::InsufficientAccountFunds, ))? - .checked_add(blob_gas_cost) + .checked_add(max_blob_gas_cost) .ok_or(VMError::TxValidation( TxValidationError::InsufficientAccountFunds, ))?; @@ -669,6 +709,8 @@ impl VM { )); } + let blob_gas_cost = self.get_blob_gas_price()?; + // The real cost to deduct is calculated as effective_gas_price * gas_limit + value + blob_gas_cost let up_front_cost = gaslimit_price_product .checked_add(value) @@ -792,7 +834,6 @@ impl VM { initial_call_frame.assign_bytecode(initial_call_frame.calldata.clone()); initial_call_frame.calldata = Bytes::new(); } - Ok(()) } @@ -812,15 +853,13 @@ impl VM { // 1. Undo value transfer if the transaction was reverted if let TxResult::Revert(_) = report.result { - // msg_value was not increased in the receiver account when is a create transaction. - if !self.is_create() { - self.decrease_account_balance(receiver_address, initial_call_frame.msg_value)?; - } + // We remove the receiver account from the cache, like nothing changed in it's state. + remove_account(&mut self.cache, &receiver_address); self.increase_account_balance(sender_address, initial_call_frame.msg_value)?; } // 2. Return unused gas + gas refunds to the sender. - let max_gas = self.env.gas_limit.low_u64(); + let max_gas = self.env.gas_limit; let consumed_gas = report.gas_used; let refunded_gas = report.gas_refunded.min( consumed_gas @@ -880,11 +919,29 @@ impl VM { self.prepare_execution(&mut initial_call_frame)?; - let mut report = self.execute(&mut initial_call_frame)?; - if self.is_create() && !report.is_success() { - remove_account(&mut self.cache, &initial_call_frame.to); + // In CREATE type transactions: + // Add created contract to cache, reverting transaction if the address is already occupied + if self.is_create() { + let new_contract_address = initial_call_frame.to; + let new_account = self.get_account(new_contract_address); + + let value = initial_call_frame.msg_value; + let balance = new_account + .info + .balance + .checked_add(value) + .ok_or(InternalError::ArithmeticOperationOverflow)?; + + if new_account.has_code_or_nonce() { + return self.handle_create_non_empty_account(&initial_call_frame); + } + + let created_contract = Account::new(balance, Bytes::new(), 1, HashMap::new()); + cache::insert_account(&mut self.cache, new_contract_address, created_contract); } + let mut report = self.execute(&mut initial_call_frame)?; + self.post_execution_changes(&initial_call_frame, &mut report)?; // There shouldn't be any errors here but I don't know what the desired behavior is if something goes wrong. @@ -953,7 +1010,7 @@ impl VM { pub fn increase_consumed_gas( &mut self, current_call_frame: &mut CallFrame, - gas: U256, + gas: u64, ) -> Result<(), VMError> { let potential_consumed_gas = current_call_frame .gas_used @@ -968,18 +1025,6 @@ impl VM { Ok(()) } - pub fn cache_from_db(&mut self, address: Address) { - let acc_info = self.db.get_account_info(address); - cache::insert_account( - &mut self.cache, - address, - Account { - info: acc_info.clone(), - storage: HashMap::new(), - }, - ); - } - /// Accesses to an account's information. /// /// Accessed accounts are stored in the `touched_accounts` set. @@ -1129,18 +1174,27 @@ impl VM { /// Gets account, first checking the cache and then the database (caching in the second case) pub fn get_account(&mut self, address: Address) -> Account { - match cache::get_account(&self.cache, &address) { - Some(acc) => acc.clone(), - None => { - let account_info = self.db.get_account_info(address); - let account = Account { - info: account_info, - storage: HashMap::new(), - }; - cache::insert_account(&mut self.cache, address, account.clone()); - account - } - } + get_account(&mut self.cache, &self.db, address) + } + + fn handle_create_non_empty_account( + &mut self, + initial_call_frame: &CallFrame, + ) -> Result { + let mut report = TransactionReport { + result: TxResult::Revert(VMError::AddressAlreadyOccupied), + gas_used: self.env.gas_limit, + gas_refunded: 0, + logs: vec![], + new_state: self.cache.clone(), + output: Bytes::new(), + created_address: None, + }; + + self.post_execution_changes(initial_call_frame, &mut report)?; + report.new_state.clone_from(&self.cache); + + Ok(report) } } @@ -1161,3 +1215,19 @@ fn get_number_of_topics(op: Opcode) -> Result { Ok(number_of_topics) } + +/// Gets account, first checking the cache and then the database (caching in the second case) +pub fn get_account(cache: &mut CacheDB, db: &Arc, address: Address) -> Account { + match cache::get_account(cache, &address) { + Some(acc) => acc.clone(), + None => { + let account_info = db.get_account_info(address); + let account = Account { + info: account_info, + storage: HashMap::new(), + }; + cache::insert_account(cache, address, account.clone()); + account + } + } +} diff --git a/crates/vm/levm/tests/edge_case_tests.rs b/crates/vm/levm/tests/edge_case_tests.rs index 80a759552..80ece79c7 100644 --- a/crates/vm/levm/tests/edge_case_tests.rs +++ b/crates/vm/levm/tests/edge_case_tests.rs @@ -17,7 +17,7 @@ fn test_extcodecopy_memory_allocation() { ])) .unwrap(); let mut current_call_frame = vm.call_frames.pop().unwrap(); - current_call_frame.gas_limit = U256::from(100_000_000); + current_call_frame.gas_limit = 100_000_000; vm.env.gas_price = U256::from(10_000); vm.execute(&mut current_call_frame).unwrap(); } @@ -293,8 +293,8 @@ fn test_non_compliance_codecopy_memory_resize() { fn test_non_compliance_log_gas_cost() { let mut vm = new_vm_with_bytecode(Bytes::copy_from_slice(&[56, 68, 68, 68, 131, 163])).unwrap(); vm.env.gas_price = U256::zero(); - vm.env.gas_limit = U256::from(100_000_000); - vm.env.block_gas_limit = U256::from(100_000_001); + vm.env.gas_limit = 100_000_000; + vm.env.block_gas_limit = 100_000_001; let res = vm.transact().unwrap(); assert_eq!(res.gas_used, 22511); } diff --git a/crates/vm/levm/tests/tests.rs b/crates/vm/levm/tests/tests.rs index 86281f309..a4b1993fa 100644 --- a/crates/vm/levm/tests/tests.rs +++ b/crates/vm/levm/tests/tests.rs @@ -8,14 +8,19 @@ use ethrex_levm::{ constants::*, db::{cache, CacheDB, Db}, errors::{OutOfGasError, TxResult, VMError}, - gas_cost, memory, + gas_cost::{ + self, ECADD_COST, ECMUL_COST, ECRECOVER_COST, IDENTITY_DYNAMIC_BASE, IDENTITY_STATIC_COST, + MODEXP_STATIC_COST, RIPEMD_160_DYNAMIC_BASE, RIPEMD_160_STATIC_COST, SHA2_256_DYNAMIC_BASE, + SHA2_256_STATIC_COST, + }, + memory, operations::Operation, - precompiles::ecrecover, + precompiles::{ecadd, ecmul, ecrecover, identity, modexp, ripemd_160, sha2_256}, utils::{new_vm_with_ops, new_vm_with_ops_addr_bal_db, new_vm_with_ops_db, ops_to_bytecode}, vm::{word_to_address, Storage, VM}, Environment, }; -use std::{collections::HashMap, sync::Arc}; +use std::{borrow::BorrowMut, collections::HashMap, sync::Arc}; fn create_opcodes(size: usize, offset: usize, value_to_transfer: usize) -> Vec { vec![ @@ -437,7 +442,7 @@ fn and_basic() { let result = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(result, U256::from(0b1000)); - assert_eq!(current_call_frame.gas_used, U256::from(9)); + assert_eq!(current_call_frame.gas_used, 9); } #[test] @@ -449,7 +454,7 @@ fn and_binary_with_zero() { Operation::Stop, ]) .unwrap(); - let expected_consumed_gas = gas_cost::AND + gas_cost::PUSHN.checked_mul(U256::from(2)).unwrap(); + let expected_consumed_gas = gas_cost::AND + gas_cost::PUSHN.checked_mul(2).unwrap(); let mut current_call_frame = vm.call_frames.pop().unwrap(); vm.execute(&mut current_call_frame).unwrap(); @@ -474,7 +479,7 @@ fn and_with_hex_numbers() { let result = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(result, U256::from(0xF0F0)); - assert_eq!(current_call_frame.gas_used, U256::from(9)); + assert_eq!(current_call_frame.gas_used, 9); let mut vm = new_vm_with_ops(&[ Operation::Push((32, U256::from(0xF000))), @@ -489,7 +494,7 @@ fn and_with_hex_numbers() { let result = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(result, U256::from(0xF000)); - assert_eq!(current_call_frame.gas_used, U256::from(9)); + assert_eq!(current_call_frame.gas_used, 9); let mut vm = new_vm_with_ops(&[ Operation::Push((32, U256::from(0xB020))), @@ -504,7 +509,7 @@ fn and_with_hex_numbers() { let result = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(result, U256::from(0b1000000000000)); - assert_eq!(current_call_frame.gas_used, U256::from(9)); + assert_eq!(current_call_frame.gas_used, 9); } #[test] @@ -522,7 +527,7 @@ fn or_basic() { let result = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(result, U256::from(0b1110)); - assert_eq!(current_call_frame.gas_used, U256::from(9)); + assert_eq!(current_call_frame.gas_used, 9); let mut vm = new_vm_with_ops(&[ Operation::Push((32, U256::from(0b1010))), @@ -537,7 +542,7 @@ fn or_basic() { let result = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(result, U256::from(0b1010)); - assert_eq!(current_call_frame.gas_used, U256::from(9)); + assert_eq!(current_call_frame.gas_used, 9); let mut vm = new_vm_with_ops(&[ Operation::Push((32, U256::from(u64::MAX))), @@ -552,7 +557,7 @@ fn or_basic() { let result = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(result, U256::from(0xFFFFFFFFFFFFFFFF_u64)); - assert_eq!(current_call_frame.gas_used, U256::from(9)); + assert_eq!(current_call_frame.gas_used, 9); } #[test] @@ -570,7 +575,7 @@ fn or_with_hex_numbers() { let result = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(result, U256::from(0xFFFF)); - assert_eq!(current_call_frame.gas_used, U256::from(9)); + assert_eq!(current_call_frame.gas_used, 9); let mut vm = new_vm_with_ops(&[ Operation::Push((32, U256::from(0xF000))), @@ -585,7 +590,7 @@ fn or_with_hex_numbers() { let result = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(result, U256::from(0xF0F0)); - assert_eq!(current_call_frame.gas_used, U256::from(9)); + assert_eq!(current_call_frame.gas_used, 9); let mut vm = new_vm_with_ops(&[ Operation::Push((32, U256::from(0xB020))), @@ -600,7 +605,7 @@ fn or_with_hex_numbers() { let result = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(result, U256::from(0b1011111100101111)); - assert_eq!(current_call_frame.gas_used, U256::from(9)); + assert_eq!(current_call_frame.gas_used, 9); } #[test] @@ -618,7 +623,7 @@ fn xor_basic() { let result = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(result, U256::from(0b110)); - assert_eq!(current_call_frame.gas_used, U256::from(9)); + assert_eq!(current_call_frame.gas_used, 9); let mut vm = new_vm_with_ops(&[ Operation::Push((32, U256::from(0b1010))), @@ -633,7 +638,7 @@ fn xor_basic() { let result = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(result, U256::from(0b1010)); - assert_eq!(current_call_frame.gas_used, U256::from(9)); + assert_eq!(current_call_frame.gas_used, 9); let mut vm = new_vm_with_ops(&[ Operation::Push((32, U256::from(u64::MAX))), @@ -648,7 +653,7 @@ fn xor_basic() { let result = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(result, U256::from(u64::MAX)); - assert_eq!(current_call_frame.gas_used, U256::from(9)); + assert_eq!(current_call_frame.gas_used, 9); let mut vm = new_vm_with_ops(&[ Operation::Push((32, U256::from(u64::MAX))), @@ -663,7 +668,7 @@ fn xor_basic() { let result = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(result, U256::zero()); - assert_eq!(current_call_frame.gas_used, U256::from(9)); + assert_eq!(current_call_frame.gas_used, 9); } #[test] @@ -681,7 +686,7 @@ fn xor_with_hex_numbers() { let result = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(result, U256::from(0xFF)); - assert_eq!(current_call_frame.gas_used, U256::from(9)); + assert_eq!(current_call_frame.gas_used, 9); let mut vm = new_vm_with_ops(&[ Operation::Push((32, U256::from(0xFF))), @@ -696,7 +701,7 @@ fn xor_with_hex_numbers() { let result = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(result, U256::zero()); - assert_eq!(current_call_frame.gas_used, U256::from(9)); + assert_eq!(current_call_frame.gas_used, 9); let mut vm = new_vm_with_ops(&[ Operation::Push((32, U256::from(0xFFFF))), @@ -711,7 +716,7 @@ fn xor_with_hex_numbers() { let result = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(result, U256::from(0xF0F)); - assert_eq!(current_call_frame.gas_used, U256::from(9)); + assert_eq!(current_call_frame.gas_used, 9); let mut vm = new_vm_with_ops(&[ Operation::Push((32, U256::from(0xF000))), @@ -726,7 +731,7 @@ fn xor_with_hex_numbers() { let result = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(result, U256::from(0xF0)); - assert_eq!(current_call_frame.gas_used, U256::from(9)); + assert_eq!(current_call_frame.gas_used, 9); let mut vm = new_vm_with_ops(&[ Operation::Push((32, U256::from(0x4C0F))), @@ -741,7 +746,7 @@ fn xor_with_hex_numbers() { let result = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(result, U256::from(0b111011001000100)); - assert_eq!(current_call_frame.gas_used, U256::from(9)); + assert_eq!(current_call_frame.gas_used, 9); } #[test] @@ -759,7 +764,7 @@ fn not() { let result = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); let expected = !U256::from(0b1010); assert_eq!(result, expected); - assert_eq!(current_call_frame.gas_used, U256::from(6)); + assert_eq!(current_call_frame.gas_used, 6); let mut vm = new_vm_with_ops(&[ Operation::Push((32, U256::MAX)), @@ -773,7 +778,7 @@ fn not() { let result = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(result, U256::zero()); - assert_eq!(current_call_frame.gas_used, U256::from(6)); + assert_eq!(current_call_frame.gas_used, 6); let mut vm = new_vm_with_ops(&[ Operation::Push((32, U256::zero())), @@ -787,7 +792,7 @@ fn not() { let result = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(result, U256::MAX); - assert_eq!(current_call_frame.gas_used, U256::from(6)); + assert_eq!(current_call_frame.gas_used, 6); let mut vm = new_vm_with_ops(&[ Operation::Push((32, U256::from(1))), @@ -801,7 +806,7 @@ fn not() { let result = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(result, U256::MAX - 1); - assert_eq!(current_call_frame.gas_used, U256::from(6)); + assert_eq!(current_call_frame.gas_used, 6); } #[test] @@ -819,7 +824,7 @@ fn byte_basic() { let result = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(result, U256::from(0xF1)); - assert_eq!(current_call_frame.gas_used, U256::from(9)); + assert_eq!(current_call_frame.gas_used, 9); let mut vm = new_vm_with_ops(&[ Operation::Push((32, U256::from(0x33ED))), @@ -834,7 +839,7 @@ fn byte_basic() { let result = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(result, U256::from(0x33)); - assert_eq!(current_call_frame.gas_used, U256::from(9)); + assert_eq!(current_call_frame.gas_used, 9); } #[test] @@ -852,7 +857,7 @@ fn byte_edge_cases() { let result = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(result, U256::from(0xFF)); - assert_eq!(current_call_frame.gas_used, U256::from(9)); + assert_eq!(current_call_frame.gas_used, 9); let mut vm = new_vm_with_ops(&[ Operation::Push((32, U256::MAX)), @@ -867,7 +872,7 @@ fn byte_edge_cases() { let result = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(result, U256::from(0xFF)); - assert_eq!(current_call_frame.gas_used, U256::from(9)); + assert_eq!(current_call_frame.gas_used, 9); let mut vm = new_vm_with_ops(&[ Operation::Push((32, U256::from(0x00E0D0000))), @@ -882,7 +887,7 @@ fn byte_edge_cases() { let result = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(result, U256::from(0x0D)); - assert_eq!(current_call_frame.gas_used, U256::from(9)); + assert_eq!(current_call_frame.gas_used, 9); let mut vm = new_vm_with_ops(&[ Operation::Push((32, U256::from(0xFDEA179))), @@ -897,7 +902,7 @@ fn byte_edge_cases() { let result = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(result, U256::zero()); - assert_eq!(current_call_frame.gas_used, U256::from(9)); + assert_eq!(current_call_frame.gas_used, 9); let mut vm = new_vm_with_ops(&[ Operation::Push((32, U256::from(0xFDEA179))), @@ -912,7 +917,7 @@ fn byte_edge_cases() { let result = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(result, U256::zero()); - assert_eq!(current_call_frame.gas_used, U256::from(9)); + assert_eq!(current_call_frame.gas_used, 9); let mut vm = new_vm_with_ops(&[ Operation::Push((32, U256::zero())), @@ -927,7 +932,7 @@ fn byte_edge_cases() { let result = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(result, U256::zero()); - assert_eq!(current_call_frame.gas_used, U256::from(9)); + assert_eq!(current_call_frame.gas_used, 9); let word = U256::from_big_endian(&[ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x57, 0x08, 0x09, 0x90, 0x0B, 0x0C, 0x0D, 0x0E, @@ -948,7 +953,7 @@ fn byte_edge_cases() { let result = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(result, U256::from(0x90)); - assert_eq!(current_call_frame.gas_used, U256::from(9)); + assert_eq!(current_call_frame.gas_used, 9); let mut vm = new_vm_with_ops(&[ Operation::Push((32, word)), @@ -963,7 +968,7 @@ fn byte_edge_cases() { let result = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(result, U256::from(0x57)); - assert_eq!(current_call_frame.gas_used, U256::from(9)); + assert_eq!(current_call_frame.gas_used, 9); let mut vm = new_vm_with_ops(&[ Operation::Push((32, word)), @@ -978,7 +983,7 @@ fn byte_edge_cases() { let result = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(result, U256::from(0xDD)); - assert_eq!(current_call_frame.gas_used, U256::from(9)); + assert_eq!(current_call_frame.gas_used, 9); let mut vm = new_vm_with_ops(&[ Operation::Push((32, word)), @@ -993,7 +998,7 @@ fn byte_edge_cases() { let result = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(result, U256::from(0x40)); - assert_eq!(current_call_frame.gas_used, U256::from(9)); + assert_eq!(current_call_frame.gas_used, 9); } #[test] @@ -1011,7 +1016,7 @@ fn shl_basic() { let result = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(result, U256::from(0xDDDD)); - assert_eq!(current_call_frame.gas_used, U256::from(9)); + assert_eq!(current_call_frame.gas_used, 9); let mut vm = new_vm_with_ops(&[ Operation::Push((32, U256::from(0x12345678))), @@ -1026,7 +1031,7 @@ fn shl_basic() { let result = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(result, U256::from(0x2468acf0)); - assert_eq!(current_call_frame.gas_used, U256::from(9)); + assert_eq!(current_call_frame.gas_used, 9); let mut vm = new_vm_with_ops(&[ Operation::Push((32, U256::from(0x12345678))), @@ -1041,7 +1046,7 @@ fn shl_basic() { let result = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(result, U256::from(4886718336_u64)); - assert_eq!(current_call_frame.gas_used, U256::from(9)); + assert_eq!(current_call_frame.gas_used, 9); let mut vm = new_vm_with_ops(&[ Operation::Push((32, U256::from(0xFF))), @@ -1056,7 +1061,7 @@ fn shl_basic() { let result = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(result, U256::from(0xFF << 4)); - assert_eq!(current_call_frame.gas_used, U256::from(9)); + assert_eq!(current_call_frame.gas_used, 9); } #[test] @@ -1074,7 +1079,7 @@ fn shl_edge_cases() { let result = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(result, U256::zero()); - assert_eq!(current_call_frame.gas_used, U256::from(9)); + assert_eq!(current_call_frame.gas_used, 9); let mut vm = new_vm_with_ops(&[ Operation::Push((32, U256::zero())), @@ -1089,7 +1094,7 @@ fn shl_edge_cases() { let result = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(result, U256::zero()); - assert_eq!(current_call_frame.gas_used, U256::from(9)); + assert_eq!(current_call_frame.gas_used, 9); let mut vm = new_vm_with_ops(&[ Operation::Push((32, U256::MAX)), @@ -1104,7 +1109,7 @@ fn shl_edge_cases() { let result = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(result, U256::MAX - 1); - assert_eq!(current_call_frame.gas_used, U256::from(9)); + assert_eq!(current_call_frame.gas_used, 9); } #[test] @@ -1122,7 +1127,7 @@ fn shr_basic() { let result = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(result, U256::from(0xDDDD)); - assert_eq!(current_call_frame.gas_used, U256::from(9)); + assert_eq!(current_call_frame.gas_used, 9); let mut vm = new_vm_with_ops(&[ Operation::Push((32, U256::from(0x12345678))), @@ -1137,7 +1142,7 @@ fn shr_basic() { let result = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(result, U256::from(0x91a2b3c)); - assert_eq!(current_call_frame.gas_used, U256::from(9)); + assert_eq!(current_call_frame.gas_used, 9); let mut vm = new_vm_with_ops(&[ Operation::Push((32, U256::from(0x12345678))), @@ -1152,7 +1157,7 @@ fn shr_basic() { let result = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(result, U256::from(0x1234567)); - assert_eq!(current_call_frame.gas_used, U256::from(9)); + assert_eq!(current_call_frame.gas_used, 9); let mut vm = new_vm_with_ops(&[ Operation::Push((32, U256::from(0xFF))), @@ -1167,7 +1172,7 @@ fn shr_basic() { let result = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(result, U256::from(0xF)); - assert_eq!(current_call_frame.gas_used, U256::from(9)); + assert_eq!(current_call_frame.gas_used, 9); } #[test] @@ -1185,7 +1190,7 @@ fn shr_edge_cases() { let result = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(result, U256::zero()); - assert_eq!(current_call_frame.gas_used, U256::from(9)); + assert_eq!(current_call_frame.gas_used, 9); let mut vm = new_vm_with_ops(&[ Operation::Push((32, U256::zero())), @@ -1200,7 +1205,7 @@ fn shr_edge_cases() { let result = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(result, U256::zero()); - assert_eq!(current_call_frame.gas_used, U256::from(9)); + assert_eq!(current_call_frame.gas_used, 9); let mut vm = new_vm_with_ops(&[ Operation::Push((32, U256::MAX)), @@ -1215,7 +1220,7 @@ fn shr_edge_cases() { let result = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(result, U256::MAX >> 1); - assert_eq!(current_call_frame.gas_used, U256::from(9)); + assert_eq!(current_call_frame.gas_used, 9); } #[test] @@ -1233,7 +1238,7 @@ fn sar_shift_by_0() { let result = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(result, U256::from(0x12345678)); - assert_eq!(current_call_frame.gas_used, U256::from(9)); + assert_eq!(current_call_frame.gas_used, 9); } #[test] @@ -1262,7 +1267,7 @@ fn sar_shifting_large_value_with_all_bits_set() { 0xff, 0xff, ]); assert_eq!(result, expected); - assert_eq!(current_call_frame.gas_used, U256::from(9)); + assert_eq!(current_call_frame.gas_used, 9); } #[test] @@ -1291,7 +1296,7 @@ fn sar_shifting_negative_value_and_small_shift() { 0x00, 0x00, ]); assert_eq!(result, expected); - assert_eq!(current_call_frame.gas_used, U256::from(9)); + assert_eq!(current_call_frame.gas_used, 9); } #[test] @@ -1309,7 +1314,7 @@ fn sar_shift_positive_value() { let result = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(result, U256::from(0x07FFFF)); - assert_eq!(current_call_frame.gas_used, U256::from(9)); + assert_eq!(current_call_frame.gas_used, 9); } #[test] @@ -1339,7 +1344,7 @@ fn sar_shift_negative_value() { ]); // change 0x8f to 0xf8 assert_eq!(result, expected); - assert_eq!(current_call_frame.gas_used, U256::from(9)); + assert_eq!(current_call_frame.gas_used, 9); } #[test] @@ -1369,7 +1374,7 @@ fn keccak256_zero_offset_size_four() { U256::from("0x29045a592007d0c246ef02c2223570da9522d0cf0f73282c79a1bc8f0bb2c238") ); assert_eq!(vm.current_call_frame_mut().unwrap().pc(), 40); - assert_eq!(current_call_frame.gas_used, U256::from(52)); + assert_eq!(current_call_frame.gas_used, 52); } #[test] @@ -1399,7 +1404,7 @@ fn keccak256_zero_offset_size_bigger_than_actual_memory() { == U256::from("0xae75624a7d0413029c1e0facdd38cc8e177d9225892e2490a69c2f1f89512061") ); assert_eq!(vm.current_call_frame_mut().unwrap().pc(), 40); - assert_eq!(current_call_frame.gas_used, U256::from(61)); + assert_eq!(current_call_frame.gas_used, 61); } #[test] @@ -1421,7 +1426,7 @@ fn keccak256_zero_offset_zero_size() { U256::from("0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470") ); assert_eq!(vm.current_call_frame_mut().unwrap().pc(), 4); - assert_eq!(current_call_frame.gas_used, U256::from(34)); + assert_eq!(current_call_frame.gas_used, 34); } #[test] @@ -1451,7 +1456,7 @@ fn keccak256_offset_four_size_four() { U256::from("0xe8e77626586f73b955364c7b4bbf0bb7f7685ebd40e852b164633a4acbd3244c") ); assert_eq!(vm.current_call_frame_mut().unwrap().pc(), 41); - assert_eq!(current_call_frame.gas_used, U256::from(53)); + assert_eq!(current_call_frame.gas_used, 53); } #[test] @@ -1473,7 +1478,7 @@ fn mstore() { U256::from(32) ); assert_eq!(vm.current_call_frame_mut().unwrap().pc(), 69); - assert_eq!(current_call_frame.gas_used, U256::from(14)); + assert_eq!(current_call_frame.gas_used, 14); } #[test] @@ -1500,7 +1505,7 @@ fn mstore_saves_correct_value() { let memory_size = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(memory_size, U256::from(32)); - assert_eq!(current_call_frame.gas_used, U256::from(14)); + assert_eq!(current_call_frame.gas_used, 14); } #[test] @@ -1527,7 +1532,7 @@ fn mstore8() { stored_value.to_big_endian(&mut value_bytes); assert_eq!(value_bytes[0..1], [0xAB]); - assert_eq!(current_call_frame.gas_used, U256::from(12)); + assert_eq!(current_call_frame.gas_used, 12); } #[test] @@ -1558,7 +1563,7 @@ fn mcopy() { let memory_size = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(memory_size, U256::from(96)); - assert_eq!(current_call_frame.gas_used, U256::from(35)); + assert_eq!(current_call_frame.gas_used, 35); } #[test] @@ -1579,7 +1584,7 @@ fn mload() { let loaded_value = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(loaded_value, U256::from(0x33333)); - assert_eq!(current_call_frame.gas_used, U256::from(18)); + assert_eq!(current_call_frame.gas_used, 18); } #[test] @@ -1593,7 +1598,7 @@ fn msize() { let initial_size = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(initial_size, U256::zero()); - assert_eq!(current_call_frame.gas_used, U256::from(2)); + assert_eq!(current_call_frame.gas_used, 2); let operations = [ Operation::Push((32, U256::from(0x33333))), // value @@ -1610,7 +1615,7 @@ fn msize() { let after_store_size = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(after_store_size, U256::from(32)); - assert_eq!(current_call_frame.gas_used, U256::from(14)); + assert_eq!(current_call_frame.gas_used, 14); let operations = [ Operation::Push((32, U256::from(0x55555))), // value @@ -1627,7 +1632,7 @@ fn msize() { let final_size = vm.current_call_frame_mut().unwrap().stack.pop().unwrap(); assert_eq!(final_size, U256::from(96)); - assert_eq!(current_call_frame.gas_used, U256::from(20)); + assert_eq!(current_call_frame.gas_used, 20); } #[test] @@ -1652,7 +1657,7 @@ fn mstore_mload_offset_not_multiple_of_32() { assert_eq!(loaded_value, U256::from(0xabcdef)); assert_eq!(memory_size, U256::from(64)); - assert_eq!(current_call_frame.gas_used, U256::from(23)); + assert_eq!(current_call_frame.gas_used, 23); // check with big offset @@ -1676,7 +1681,7 @@ fn mstore_mload_offset_not_multiple_of_32() { assert_eq!(loaded_value, U256::from(0x123456)); assert_eq!(memory_size, U256::from(2048)); - assert_eq!(current_call_frame.gas_used, U256::from(217)); + assert_eq!(current_call_frame.gas_used, 217); } #[test] @@ -1698,7 +1703,7 @@ fn mload_uninitialized_memory() { assert_eq!(loaded_value, U256::zero()); assert_eq!(memory_size, U256::from(96)); - assert_eq!(current_call_frame.gas_used, U256::from(17)); + assert_eq!(current_call_frame.gas_used, 17); } #[test] @@ -1998,7 +2003,7 @@ fn pc_op() { vm.current_call_frame_mut().unwrap().stack.pop().unwrap(), U256::zero() ); - assert_eq!(current_call_frame.gas_used, U256::from(2)); + assert_eq!(current_call_frame.gas_used, 2); } #[test] @@ -2018,7 +2023,7 @@ fn pc_op_with_push_offset() { vm.current_call_frame_mut().unwrap().stack.pop().unwrap(), U256::from(33) ); - assert_eq!(current_call_frame.gas_used, U256::from(5)); + assert_eq!(current_call_frame.gas_used, 5); } // #[test] @@ -2316,7 +2321,7 @@ fn jumpi_not_zero() { vm.current_call_frame_mut().unwrap().stack.pop().unwrap(), U256::from(10) ); - assert_eq!(current_call_frame.gas_used, U256::from(20)); + assert_eq!(current_call_frame.gas_used, 20); } #[test] @@ -2341,7 +2346,7 @@ fn jumpi_for_zero() { vm.current_call_frame_mut().unwrap().stack.pop().unwrap(), U256::from(100) ); - assert_eq!(current_call_frame.gas_used, U256::from(19)); + assert_eq!(current_call_frame.gas_used, 19); } // This test is just for trying things out, not a real test. But it is useful to have this as an example for conversions between bytes and u256. @@ -2419,7 +2424,7 @@ fn calldataload() { 0x00, 0x00, 0x00, 0x00 ]) ); - assert_eq!(current_call_frame.gas_used, U256::from(6)); + assert_eq!(current_call_frame.gas_used, 6); } #[test] @@ -2515,7 +2520,7 @@ fn calldatasize() { let current_call_frame = vm.current_call_frame_mut().unwrap(); let top_of_stack = current_call_frame.stack.pop().unwrap(); assert_eq!(top_of_stack, U256::from(3)); - assert_eq!(current_call_frame.gas_used, U256::from(2)); + assert_eq!(current_call_frame.gas_used, 2); } #[test] @@ -2538,7 +2543,7 @@ fn calldatacopy() { let current_call_frame = vm.current_call_frame_mut().unwrap(); let memory = memory::load_range(&mut current_call_frame.memory, U256::zero(), 2).unwrap(); assert_eq!(memory, vec![0x22, 0x33]); - assert_eq!(current_call_frame.gas_used, U256::from(18)); + assert_eq!(current_call_frame.gas_used, 18); } #[test] @@ -2555,7 +2560,7 @@ fn returndatasize() { let current_call_frame = vm.current_call_frame_mut().unwrap(); let top_of_stack = current_call_frame.stack.pop().unwrap(); assert_eq!(top_of_stack, U256::from(3)); - assert_eq!(current_call_frame.gas_used, U256::from(2)); + assert_eq!(current_call_frame.gas_used, 2); } #[test] @@ -2578,7 +2583,7 @@ fn returndatacopy() { let current_call_frame = vm.current_call_frame_mut().unwrap(); let memory = memory::load_range(&mut current_call_frame.memory, U256::zero(), 2).unwrap(); assert_eq!(memory, vec![0xBB, 0xCC]); - assert_eq!(current_call_frame.gas_used, U256::from(18)); + assert_eq!(current_call_frame.gas_used, 18); } #[test] @@ -2665,7 +2670,7 @@ fn blockhash_op() { vm.current_call_frame_mut().unwrap().stack.pop().unwrap(), expected_block_hash ); - assert_eq!(current_call_frame.gas_used, U256::from(23)); + assert_eq!(current_call_frame.gas_used, 23); } #[test] @@ -2697,7 +2702,7 @@ fn blockhash_same_block_number() { vm.current_call_frame_mut().unwrap().stack.pop().unwrap(), expected_block_hash ); - assert_eq!(current_call_frame.gas_used, U256::from(23)); + assert_eq!(current_call_frame.gas_used, 23); } #[test] @@ -2733,7 +2738,7 @@ fn blockhash_block_number_not_from_recent_256() { vm.current_call_frame_mut().unwrap().stack.pop().unwrap(), expected_block_hash ); - assert_eq!(current_call_frame.gas_used, U256::from(23)); + assert_eq!(current_call_frame.gas_used, 23); } #[test] @@ -2752,7 +2757,7 @@ fn coinbase_op() { vm.current_call_frame_mut().unwrap().stack.pop().unwrap(), U256::from(coinbase_address) ); - assert_eq!(current_call_frame.gas_used, U256::from(2)); + assert_eq!(current_call_frame.gas_used, 2); } #[test] @@ -2771,7 +2776,7 @@ fn timestamp_op() { vm.current_call_frame_mut().unwrap().stack.pop().unwrap(), timestamp ); - assert_eq!(current_call_frame.gas_used, U256::from(2)); + assert_eq!(current_call_frame.gas_used, 2); } #[test] @@ -2790,7 +2795,7 @@ fn number_op() { vm.current_call_frame_mut().unwrap().stack.pop().unwrap(), block_number ); - assert_eq!(current_call_frame.gas_used, U256::from(2)); + assert_eq!(current_call_frame.gas_used, 2); } #[test] @@ -2809,7 +2814,7 @@ fn prevrandao_op() { vm.current_call_frame_mut().unwrap().stack.pop().unwrap(), U256::from_big_endian(&prevrandao.0) ); - assert_eq!(current_call_frame.gas_used, U256::from(2)); + assert_eq!(current_call_frame.gas_used, 2); } #[test] @@ -2826,9 +2831,9 @@ fn gaslimit_op() { assert_eq!( vm.current_call_frame_mut().unwrap().stack.pop().unwrap(), - gas_limit + gas_limit.into() ); - assert_eq!(current_call_frame.gas_used, U256::from(2)); + assert_eq!(current_call_frame.gas_used, 2); } #[test] @@ -2873,7 +2878,7 @@ fn chain_id_op() { vm.current_call_frame_mut().unwrap().stack.pop().unwrap(), chain_id ); - assert_eq!(current_call_frame.gas_used, U256::from(2)); + assert_eq!(current_call_frame.gas_used, 2); } #[test] @@ -2892,7 +2897,7 @@ fn basefee_op() { vm.current_call_frame_mut().unwrap().stack.pop().unwrap(), base_fee_per_gas ); - assert_eq!(current_call_frame.gas_used, U256::from(2)); + assert_eq!(current_call_frame.gas_used, 2); } // TODO: Add excess_blob_gas and blob_gas_used to env @@ -2911,7 +2916,7 @@ fn blobbasefee_op() { vm.current_call_frame_mut().unwrap().stack.pop().unwrap(), U256::from(2) ); - assert_eq!(current_call_frame.gas_used, U256::from(2)); + assert_eq!(current_call_frame.gas_used, 2); } // TODO: Add excess_blob_gas and blob_gas_used to env @@ -2930,7 +2935,7 @@ fn blobbasefee_minimum_cost() { vm.current_call_frame_mut().unwrap().stack.pop().unwrap(), U256::one() ); - assert_eq!(current_call_frame.gas_used, U256::from(2)); + assert_eq!(current_call_frame.gas_used, 2); } #[test] @@ -2951,7 +2956,7 @@ fn pop_op() { vm.current_call_frame_mut().unwrap().stack.pop().unwrap(), U256::one() ); - assert_eq!(current_call_frame.gas_used, U256::from(8)); + assert_eq!(current_call_frame.gas_used, 8); } #[test] @@ -2975,7 +2980,7 @@ fn jump_op() { U256::from(10) ); assert_eq!(vm.current_call_frame_mut().unwrap().pc(), 70); - assert_eq!(current_call_frame.gas_used, U256::from(15)); + assert_eq!(current_call_frame.gas_used, 15); } #[test] @@ -3144,7 +3149,7 @@ fn log0() { assert_eq!(logs.len(), 1); assert_eq!(logs[0].data, data.to_vec()); assert_eq!(logs[0].topics.len(), 0); - assert_eq!(current_call_frame.gas_used, U256::from(649)); + assert_eq!(current_call_frame.gas_used, 649); } #[test] @@ -3174,7 +3179,7 @@ fn log1() { assert_eq!(logs.len(), 1); assert_eq!(logs[0].data, data.to_vec()); assert_eq!(logs[0].topics, vec![H256::from_slice(&topic1)]); - assert_eq!(current_call_frame.gas_used, U256::from(1027)); + assert_eq!(current_call_frame.gas_used, 1027); } #[test] @@ -3210,7 +3215,7 @@ fn log2() { logs[0].topics, vec![H256::from_slice(&topic1), H256::from_slice(&topic2)] ); - assert_eq!(current_call_frame.gas_used, U256::from(1405)); + assert_eq!(current_call_frame.gas_used, 1405); } #[test] @@ -3253,7 +3258,7 @@ fn log3() { H256::from_slice(&topic3) ] ); - assert_eq!(current_call_frame.gas_used, U256::from(1783)); + assert_eq!(current_call_frame.gas_used, 1783); } #[test] @@ -3300,7 +3305,7 @@ fn log4() { H256::from_slice(&topic4) ] ); - assert_eq!(current_call_frame.gas_used, U256::from(2161)); + assert_eq!(current_call_frame.gas_used, 2161); } #[test] @@ -3325,7 +3330,7 @@ fn log_with_0_data_size() { assert_eq!(logs.len(), 1); assert_eq!(logs[0].data, Vec::new()); assert_eq!(logs[0].topics.len(), 0); - assert_eq!(current_call_frame.gas_used, U256::from(393)); + assert_eq!(current_call_frame.gas_used, 393); } #[test] @@ -3378,7 +3383,7 @@ fn log_with_data_in_memory_smaller_than_size() { assert_eq!(logs.len(), 1); assert_eq!(logs[0].data, data); assert_eq!(logs[0].topics.len(), 0); - assert_eq!(current_call_frame.gas_used, U256::from(649)); + assert_eq!(current_call_frame.gas_used, 649); } #[test] @@ -3724,20 +3729,18 @@ fn transient_store() { let mut vm = new_vm_with_ops(&operations).unwrap(); - let current_call_frame = vm.current_call_frame_mut().unwrap(); - - assert!(current_call_frame.transient_storage.is_empty()); + { + let env_mut = vm.env.borrow_mut(); + assert!(env_mut.transient_storage.is_empty()); + } let mut current_call_frame = vm.call_frames.pop().unwrap(); vm.execute(&mut current_call_frame).unwrap(); - let current_call_frame = vm.current_call_frame_mut().unwrap(); + let msg_sender = current_call_frame.msg_sender; assert_eq!( - *current_call_frame - .transient_storage - .get(&(current_call_frame.msg_sender, key)) - .unwrap(), + *vm.env.transient_storage.get(&(msg_sender, key)).unwrap(), value ) } @@ -3747,11 +3750,7 @@ fn transient_store_stack_underflow() { let operations = [Operation::Tstore, Operation::Stop]; let mut vm = new_vm_with_ops(&operations).unwrap(); - assert!(vm - .current_call_frame_mut() - .unwrap() - .transient_storage - .is_empty()); + assert!(vm.env.transient_storage.is_empty()); let mut current_call_frame = vm.call_frames.pop().unwrap(); let tx_report = vm.execute(&mut current_call_frame).unwrap(); @@ -3777,10 +3776,7 @@ fn transient_load() { let caller = vm.current_call_frame_mut().unwrap().msg_sender; - vm.current_call_frame_mut() - .unwrap() - .transient_storage - .insert((caller, key), value); + vm.env.transient_storage.insert((caller, key), value); let mut current_call_frame = vm.call_frames.pop().unwrap(); vm.execute(&mut current_call_frame).unwrap(); @@ -4262,10 +4258,7 @@ fn codecopy_op() { .unwrap(), expected_memory ); - assert_eq!( - current_call_frame.gas_used, - U256::from(9) + U256::from(3) * gas_cost::PUSHN - ); + assert_eq!(current_call_frame.gas_used, 9 + 3 * gas_cost::PUSHN); } #[test] @@ -4291,7 +4284,7 @@ fn extcodesize_existing_account() { vm.current_call_frame_mut().unwrap().stack.pop().unwrap(), 23.into() ); - assert_eq!(current_call_frame.gas_used, 2603.into()); + assert_eq!(current_call_frame.gas_used, 2603); } #[test] @@ -4311,7 +4304,7 @@ fn extcodesize_non_existing_account() { vm.current_call_frame_mut().unwrap().stack.pop().unwrap(), 0.into() ); - assert_eq!(current_call_frame.gas_used, 2603.into()); + assert_eq!(current_call_frame.gas_used, 2603); } #[test] @@ -4347,7 +4340,7 @@ fn extcodecopy_existing_account() { .unwrap(), vec![0x60] ); - assert_eq!(current_call_frame.gas_used, 2616.into()); + assert_eq!(current_call_frame.gas_used, 2616); } #[test] @@ -4377,7 +4370,7 @@ fn extcodecopy_non_existing_account() { .unwrap(), vec![0; size] ); - assert_eq!(current_call_frame.gas_used, 2616.into()); + assert_eq!(current_call_frame.gas_used, 2616); } #[test] @@ -4401,7 +4394,7 @@ fn extcodehash_account_with_zero_bytecode_but_not_empty() { vm.current_call_frame_mut().unwrap().stack.pop().unwrap(), "c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470".into() ); - assert_eq!(current_call_frame.gas_used, 2603.into()); + assert_eq!(current_call_frame.gas_used, 2603); } #[test] @@ -4422,7 +4415,7 @@ fn extcodehash_non_existing_account() { vm.current_call_frame_mut().unwrap().stack.pop().unwrap(), U256::zero() ); - assert_eq!(current_call_frame.gas_used, 2603.into()); + assert_eq!(current_call_frame.gas_used, 2603); } #[test] @@ -4497,12 +4490,135 @@ fn recover_test() { let calldata = hex::decode("456e9aea5e197a1f1af7a3e85a3212fa4049a3ba34c2289b4c860fc0b0c64ef3000000000000000000000000000000000000000000000000000000000000001c9242685bf161793cc25603c231bc2f568eb630ea16aa137d2664ac80388256084f8ae3bd7535248d0bd448298cc2e2071e56992d0774dc340c368ae950852ada").unwrap(); let calldata = Bytes::from(calldata); - let mut consumed_gas = U256::zero(); - let result = ecrecover(&calldata, 10000.into(), &mut consumed_gas).unwrap(); + let mut consumed_gas = 0; + let result = ecrecover(&calldata, 10000, &mut consumed_gas).unwrap(); let expected_result = Bytes::from( hex::decode("0000000000000000000000007156526fbd7a3c72969b54f64e42c10fbb768c8a").unwrap(), ); - assert_eq!(result, expected_result) + assert_eq!(result, expected_result); + assert_eq!(consumed_gas, ECRECOVER_COST); +} + +#[test] +fn sha2_256_test() { + let calldata = hex::decode("ff").unwrap(); + let calldata = Bytes::from(calldata); + + let mut consumed_gas = 0; + let result = sha2_256(&calldata, 10000, &mut consumed_gas).unwrap(); + + let expected_result = Bytes::from( + hex::decode("a8100ae6aa1940d0b663bb31cd466142ebbdbd5187131b92d93818987832eb89").unwrap(), + ); + + assert_eq!(result, expected_result); + assert_eq!(consumed_gas, (SHA2_256_STATIC_COST + SHA2_256_DYNAMIC_BASE)); +} + +#[test] +fn ripemd_160_test() { + let calldata = hex::decode("ff").unwrap(); + let calldata = Bytes::from(calldata); + + let mut consumed_gas = 0; + let result = ripemd_160(&calldata, 10000, &mut consumed_gas).unwrap(); + + let expected_result = Bytes::from( + hex::decode("0000000000000000000000002c0c45d3ecab80fe060e5f1d7057cd2f8de5e557").unwrap(), + ); + + assert_eq!(result, expected_result); + assert_eq!( + consumed_gas, + (RIPEMD_160_STATIC_COST + RIPEMD_160_DYNAMIC_BASE) + ); +} + +#[test] +fn identity_test() { + let calldata = hex::decode("ff").unwrap(); + let calldata = Bytes::from(calldata); + + let mut consumed_gas = 0; + let result = identity(&calldata, 10000, &mut consumed_gas).unwrap(); + + let expected_result = Bytes::from(hex::decode("ff").unwrap()); + + assert_eq!(result, expected_result); + assert_eq!(consumed_gas, IDENTITY_STATIC_COST + IDENTITY_DYNAMIC_BASE); +} + +#[test] +fn modexp_test() { + let calldata = hex::decode("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000108090a").unwrap(); + let calldata = Bytes::from(calldata); + + let mut consumed_gas = 0; + let result = modexp(&calldata, 10000, &mut consumed_gas).unwrap(); + + let expected_result = Bytes::from(hex::decode("08").unwrap()); + + assert_eq!(result, expected_result); + assert_eq!(consumed_gas, MODEXP_STATIC_COST); +} + +#[test] +fn modexp_test_2() { + // This tests that in case of the sizes read first are bigger than the calldata len then the calldata is filled with zeros + let calldata = hex::decode("00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000002003ffff80").unwrap(); + let calldata = Bytes::from(calldata); + + let mut consumed_gas = 0; + let result = modexp(&calldata, 10000, &mut consumed_gas).unwrap(); + + let expected_result = Bytes::from( + hex::decode("3b01b01ac41f2d6e917c6d6a221ce793802469026d9ab7578fa2e79e4da6aaab").unwrap(), + ); + + assert_eq!(result, expected_result); + assert_eq!(consumed_gas, MODEXP_STATIC_COST); +} +#[test] +fn ecadd_test() { + let calldata = hex::decode("0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000002").unwrap(); + let calldata = Bytes::from(calldata); + + let mut consumed_gas = 0; + let result = ecadd(&calldata, 10000, &mut consumed_gas).unwrap(); + + let expected_result = Bytes::from(hex::decode("030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd315ed738c0e0a7c92e7845f96b2ae9c0a68a6a449e3538fc7ff3ebf7a5a18a2c4").unwrap()); + + assert_eq!(result, expected_result); + assert_eq!(consumed_gas, ECADD_COST); +} + +#[test] +fn ecmul_test() { + let calldata = hex::decode("000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000002").unwrap(); + let calldata = Bytes::from(calldata); + + let mut consumed_gas = 0; + let result = ecmul(&calldata, 10000, &mut consumed_gas).unwrap(); + + let expected_result = Bytes::from(hex::decode("030644e72e131a029b85045b68181585d97816a916871ca8d3c208c16d87cfd315ed738c0e0a7c92e7845f96b2ae9c0a68a6a449e3538fc7ff3ebf7a5a18a2c4").unwrap()); + + assert_eq!(result, expected_result); + assert_eq!(consumed_gas, ECMUL_COST); +} + +#[test] +fn ecmul_test_2() { + // This tests that an infinite in one coordinate implies a zero result + let calldata = hex::decode("0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000230644e72e131a029b85045b68181585d2833e84879b9709143e1f593f00000010000000000000000000000000000000000000000000000000000000000000000").unwrap(); + let calldata = Bytes::from(calldata); + + let mut consumed_gas = 0; + let result = ecmul(&calldata, 10000, &mut consumed_gas).unwrap(); + + let expected_result = Bytes::from(hex::decode("00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap()); + + assert_eq!(result, expected_result); + assert_eq!(consumed_gas, ECMUL_COST); } diff --git a/crates/vm/vm.rs b/crates/vm/vm.rs index ee0d06c79..c2940edc3 100644 --- a/crates/vm/vm.rs +++ b/crates/vm/vm.rs @@ -169,8 +169,8 @@ cfg_if::cfg_if! { let env = Environment { origin: tx.sender(), - refunded_gas: U256::zero(), - gas_limit: tx.gas_limit().into(), + refunded_gas: 0, + gas_limit: tx.gas_limit(), block_number: block_header.number.into(), coinbase: block_header.coinbase, timestamp: block_header.timestamp.into(), @@ -184,7 +184,8 @@ cfg_if::cfg_if! { tx_max_priority_fee_per_gas: tx.max_priority_fee().map(U256::from), tx_max_fee_per_gas: tx.max_fee_per_gas().map(U256::from), tx_max_fee_per_blob_gas: tx.max_fee_per_blob_gas().map(U256::from), - block_gas_limit: block_header.gas_limit.into(), + block_gas_limit: block_header.gas_limit, + transient_storage: HashMap::new(), }; let mut vm = VM::new(