diff --git a/.github/workflows/action_tests.yaml b/.github/workflows/action_tests.yaml index a90dd32535..64c4b81e4b 100644 --- a/.github/workflows/action_tests.yaml +++ b/.github/workflows/action_tests.yaml @@ -16,6 +16,10 @@ jobs: uses: actions/checkout@v4 - uses: taiki-e/install-action@just - uses: dtolnay/rust-toolchain@stable + with: + components: llvm-tools-preview + toolchain: 1.81 + - uses: taiki-e/install-action@cargo-llvm-cov - name: Clone monorepo run: just monorepo - uses: Swatinem/rust-cache@v2 @@ -31,8 +35,25 @@ jobs: uses: autero1/action-gotestsum@v2.0.0 with: gotestsum_version: 1.12.0 + - name: Setup yq + uses: dcarbone/install-yq-action@v1 + - name: Extract monorepo forge version + id: collect-versions + run: | + echo "forge-version=$(yq '.tools.forge' monorepo/mise.toml | tr -d '\n')" >> $GITHUB_OUTPUT - name: Install Foundry uses: foundry-rs/foundry-toolchain@v1 - - name: Run Actions Tests + with: + version: ${{ steps.collect-versions.outputs.forge-version }} + - name: Run Action Tests run: | + source <(cargo llvm-cov show-env --export-prefix) just action-tests + cargo llvm-cov report --lcov --output-path actions_cov.lcov + - name: Upload coverage to codecov.io + uses: codecov/codecov-action@v5 + with: + fail_ci_if_error: true + token: ${{ secrets.CODECOV_TOKEN }} + env_vars: OS,RUST + files: actions_cov.lcov diff --git a/.github/workflows/book.yaml b/.github/workflows/book.yaml index 7b2464809c..b1d75c7bae 100644 --- a/.github/workflows/book.yaml +++ b/.github/workflows/book.yaml @@ -14,6 +14,8 @@ jobs: steps: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@stable + with: + toolchain: 1.81 - name: Setup mdbook run: | cargo install --version 0.4.40 mdbook diff --git a/.github/workflows/client_host.yaml b/.github/workflows/client_host.yaml index faa2b5e133..2e0fbdf8cb 100644 --- a/.github/workflows/client_host.yaml +++ b/.github/workflows/client_host.yaml @@ -12,15 +12,19 @@ jobs: strategy: matrix: target: ["native", "asterisc"] - name: ["OP Sepolia (Granite) - Block #16491249"] + name: ["OP Sepolia (Holocene) - Block #22012816"] runs-on: ubuntu-latest timeout-minutes: 20 steps: - name: Checkout sources uses: actions/checkout@v4 - uses: taiki-e/install-action@just + - uses: taiki-e/install-action@cargo-llvm-cov - name: Install Rust stable toolchain uses: dtolnay/rust-toolchain@stable + with: + components: llvm-tools-preview + toolchain: 1.81 - uses: Swatinem/rust-cache@v2 with: cache-on-failure: true @@ -45,19 +49,19 @@ jobs: - name: Build `asterisc` if: "!contains(matrix.target, 'native')" run: | - cd asterisc && git checkout v1.1.2 && make build-rvgo + cd asterisc && git checkout v1.2.0 && make build-rvgo mv ./rvgo/bin/asterisc /usr/local/bin/ - name: Set run environment run: | - if [[ ${{ contains(matrix.name, 16491249) }} == true ]]; then - BLOCK_NUMBER=16491249 + if [[ ${{ contains(matrix.name, 22012816) }} == true ]]; then + BLOCK_NUMBER=22012816 echo "BLOCK_NUMBER=$BLOCK_NUMBER" >> $GITHUB_ENV - echo "L2_CLAIM=0x82da7204148ba4d8d59e587b6b3fdde5561dc31d9e726220f7974bf9f2158d75" >> $GITHUB_ENV - echo "L2_OUTPUT_ROOT=0xa548f22e1aa590de7ed271e3eab5b66c6c3db9b8cb0e3f91618516ea9ececde4" >> $GITHUB_ENV - echo "L2_HEAD=0x09b298a83baf4c2e3c6a2e355bb09e27e3fdca435080e8754f8749233d7333b2" >> $GITHUB_ENV - echo "L1_HEAD=0x33a3e5721faa4dc6f25e75000d9810fd6c41320868f3befcc0c261a71da398e1" >> $GITHUB_ENV + echo "L2_CLAIM=0x42ff78e504c207c3786cb30ecb74fe915984b48649165f95bbf6f9248584be69" >> $GITHUB_ENV + echo "L2_OUTPUT_ROOT=0x9084f101b85cd1c7c624946feca169768896d88b3ecf4eea3a7760bfceb9cd73" >> $GITHUB_ENV + echo "L2_HEAD=0x6a34183664b9ad39de024a8d4077c78abf05198148b6dbfc6e39fbe4a70de299" >> $GITHUB_ENV + echo "L1_HEAD=0x02a50d0b5a3226758a6e9b2bdeb5deb5f0779ab55b2b34a52331d0eac48c9389" >> $GITHUB_ENV echo "L2_CHAIN_ID=11155420" >> $GITHUB_ENV - echo "WITNESS_TAR_NAME=granite-op-sepolia-$BLOCK_NUMBER-witness.tar.zst" >> $GITHUB_ENV + echo "WITNESS_TAR_NAME=holocene-op-sepolia-$BLOCK_NUMBER-witness.tar.zst" >> $GITHUB_ENV fi - name: Decompress witness data directory run: | @@ -65,6 +69,8 @@ jobs: - name: Run host + client offline working-directory: ./bin/client run: | + source <(cargo llvm-cov show-env --export-prefix) + mkdir -p ../../target just run-client-${{ matrix.target }}-offline \ $BLOCK_NUMBER \ @@ -73,3 +79,12 @@ jobs: $L2_HEAD \ $L1_HEAD \ $L2_CHAIN_ID + + cargo llvm-cov report --lcov --output-path client_host_cov.lcov + - name: Upload coverage to codecov.io + uses: codecov/codecov-action@v5 + with: + fail_ci_if_error: true + token: ${{ secrets.CODECOV_TOKEN }} + env_vars: OS,RUST + files: client_host_cov.lcov diff --git a/.github/workflows/monorepo_pin_update.yaml b/.github/workflows/monorepo_pin_update.yaml index bbcc5641f7..1b95189fc5 100644 --- a/.github/workflows/monorepo_pin_update.yaml +++ b/.github/workflows/monorepo_pin_update.yaml @@ -17,6 +17,8 @@ jobs: token: ${{ secrets.PAT_TOKEN }} - uses: taiki-e/install-action@just - uses: dtolnay/rust-toolchain@stable + with: + toolchain: 1.81 - name: Update Monorepo Commit run: just update-monorepo - name: Create Pull Request diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 81b1e80be8..4b7f5bed84 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -18,6 +18,8 @@ jobs: submodules: true - name: Install Rust toolchain uses: dtolnay/rust-toolchain@stable + with: + toolchain: 1.81 - name: Commit Cargo.lock run: | git config --local user.email "action@github.com" diff --git a/.github/workflows/rust_ci.yaml b/.github/workflows/rust_ci.yaml index e8addfdb19..537d7c6c4d 100644 --- a/.github/workflows/rust_ci.yaml +++ b/.github/workflows/rust_ci.yaml @@ -19,6 +19,8 @@ jobs: - uses: taiki-e/install-action@just - name: Install Rust stable toolchain uses: dtolnay/rust-toolchain@stable + with: + toolchain: 1.81 - uses: Swatinem/rust-cache@v2 with: cache-on-failure: true @@ -70,6 +72,8 @@ jobs: - uses: taiki-e/install-action@just - name: Install Rust stable toolchain uses: dtolnay/rust-toolchain@stable + with: + toolchain: 1.81 - uses: Swatinem/rust-cache@v2 with: cache-on-failure: true @@ -94,6 +98,8 @@ jobs: - uses: taiki-e/install-action@just - name: Install Rust stable toolchain uses: dtolnay/rust-toolchain@stable + with: + toolchain: 1.81 - uses: Swatinem/rust-cache@v2 with: cache-on-failure: true @@ -120,6 +126,8 @@ jobs: - uses: taiki-e/install-action@just - name: Install Rust stable toolchain uses: dtolnay/rust-toolchain@stable + with: + toolchain: 1.81 - uses: Swatinem/rust-cache@v2 with: cache-on-failure: true @@ -138,9 +146,55 @@ jobs: - uses: taiki-e/install-action@just - name: Install Rust stable toolchain uses: dtolnay/rust-toolchain@stable + with: + toolchain: 1.81 - uses: taiki-e/install-action@cargo-hack - uses: Swatinem/rust-cache@v2 with: cache-on-failure: true - name: cargo hack run: just hack + coverage: + runs-on: ubuntu-latest + name: coverage + steps: + - uses: actions/checkout@v4 + with: + submodules: true + - uses: dtolnay/rust-toolchain@stable + with: + components: llvm-tools-preview + toolchain: 1.81 + - uses: Swatinem/rust-cache@v2 + with: + cache-on-failure: true + - uses: taiki-e/install-action@cargo-llvm-cov + - uses: taiki-e/install-action@nextest + - name: cargo generate-lockfile + if: hashFiles('Cargo.lock') == '' + run: cargo generate-lockfile + - name: cargo llvm-cov + run: | + RUST_MIN_STACK=33554432 cargo llvm-cov nextest \ + --locked \ + --workspace \ + --lcov \ + --output-path lcov.info \ + --features test-utils \ + --profile ci \ + -E '!test(test_online)' && \ + mv ./target/nextest/ci/junit.xml ./junit.xml + - name: Record Rust version + run: echo "RUST=$(rustc --version)" >> "$GITHUB_ENV" + - name: Upload coverage to codecov.io + uses: codecov/codecov-action@v5 + with: + fail_ci_if_error: true + token: ${{ secrets.CODECOV_TOKEN }} + env_vars: OS,RUST + files: lcov.info + - name: Upload test results to codecov.io + if: ${{ !cancelled() }} + uses: codecov/test-results-action@v1 + with: + token: ${{ secrets.CODECOV_TOKEN }} diff --git a/.gitignore b/.gitignore index 42cc707b36..ed486344d0 100644 --- a/.gitignore +++ b/.gitignore @@ -10,5 +10,7 @@ monorepo/ # Environment Variables .env +.idea + # kona-host data-dir data/ \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index ea8f2861a9..ee71439508 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 4 +version = 3 [[package]] name = "addr2line" @@ -24,10 +24,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", - "getrandom", + "getrandom 0.2.15", "once_cell", "version_check", - "zerocopy", + "zerocopy 0.7.35", ] [[package]] @@ -41,28 +41,13 @@ dependencies = [ [[package]] name = "aligned-vec" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e0966165eaf052580bd70eb1b32cb3d6245774c0104d1b2793e9650bf83b52a" +checksum = "af15ccceeacb9304119d97925de463bc97ae3555ee8dc8056f67b119f66e5934" dependencies = [ "equator", ] -[[package]] -name = "alloc-no-stdlib" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" - -[[package]] -name = "alloc-stdlib" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" -dependencies = [ - "alloc-no-stdlib", -] - [[package]] name = "allocator-api2" version = "0.2.21" @@ -71,20 +56,20 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "alloy-chains" -version = "0.1.47" +version = "0.1.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18c5c520273946ecf715c0010b4e3503d7eba9893cd9ce6b7fff5654c4a3c470" +checksum = "996564c1782285d4e0299c29b318bc74f24b1d7f456cef3e040810b061ee3256" dependencies = [ "alloy-primitives", "num_enum", - "strum", + "strum 0.27.1", ] [[package]] name = "alloy-consensus" -version = "0.8.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ba14856660f31807ebb26ce8f667e814c72694e1077e97ef102e326ad580f3f" +checksum = "69e32ef5c74bbeb1733c37f4ac7f866f8c8af208b7b4265e21af609dcac5bd5e" dependencies = [ "alloy-eips", "alloy-primitives", @@ -93,16 +78,16 @@ dependencies = [ "alloy-trie", "auto_impl", "c-kzg", - "derive_more", + "derive_more 1.0.0", "k256", "serde", ] [[package]] name = "alloy-consensus-any" -version = "0.8.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28666307e76441e7af37a2b90cde7391c28112121bea59f4e0d804df8b20057e" +checksum = "0fa13b7b1e1e3fedc42f0728103bfa3b4d566d3d42b606db449504d88dbdbdcf" dependencies = [ "alloy-consensus", "alloy-eips", @@ -113,54 +98,58 @@ dependencies = [ ] [[package]] -name = "alloy-eip2930" +name = "alloy-eip2124" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0069cf0642457f87a01a014f6dc29d5d893cd4fd8fddf0c3cdfad1bb3ebafc41" +checksum = "675264c957689f0fd75f5993a73123c2cc3b5c235a38f5b9037fe6c826bfb2c0" dependencies = [ "alloy-primitives", "alloy-rlp", - "serde", + "crc", + "thiserror 2.0.12", ] [[package]] -name = "alloy-eip7702" -version = "0.2.0" +name = "alloy-eip2930" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eeffd2590ce780ddfaa9d0ae340eb2b4e08627650c4676eef537cef0b4bf535d" +checksum = "0069cf0642457f87a01a014f6dc29d5d893cd4fd8fddf0c3cdfad1bb3ebafc41" dependencies = [ "alloy-primitives", "alloy-rlp", - "k256", "serde", ] [[package]] name = "alloy-eip7702" -version = "0.4.2" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c986539255fb839d1533c128e190e557e52ff652c9ef62939e233a81dd93f7e" +checksum = "9b15b13d38b366d01e818fe8e710d4d702ef7499eacd44926a06171dd9585d0c" dependencies = [ "alloy-primitives", "alloy-rlp", - "derive_more", "k256", "serde", + "thiserror 2.0.12", ] [[package]] name = "alloy-eips" -version = "0.8.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47e922d558006ba371681d484d12aa73fe673d84884f83747730af7433c0e86d" +checksum = "5591581ca2ab0b3e7226a4047f9a1bfcf431da1d0cce3752fda609fea3c27e37" dependencies = [ + "alloy-eip2124", "alloy-eip2930", - "alloy-eip7702 0.4.2", + "alloy-eip7702", "alloy-primitives", "alloy-rlp", "alloy-serde", + "auto_impl", "c-kzg", - "derive_more", + "derive_more 1.0.0", + "ethereum_ssz", + "ethereum_ssz_derive", "once_cell", "serde", "sha2", @@ -168,23 +157,23 @@ dependencies = [ [[package]] name = "alloy-json-rpc" -version = "0.8.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9335278f50b0273e0a187680ee742bb6b154a948adf036f448575bacc5ccb315" +checksum = "762414662d793d7aaa36ee3af6928b6be23227df1681ce9c039f6f11daadef64" dependencies = [ "alloy-primitives", "alloy-sol-types", "serde", "serde_json", - "thiserror 2.0.4", + "thiserror 2.0.12", "tracing", ] [[package]] name = "alloy-network" -version = "0.8.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad4e6ad4230df8c4a254c20f8d6a84ab9df151bfca13f463177dbc96571cc1f8" +checksum = "8be03f2ebc00cf88bd06d3c6caf387dceaa9c7e6b268216779fa68a9bf8ab4e6" dependencies = [ "alloy-consensus", "alloy-consensus-any", @@ -202,14 +191,14 @@ dependencies = [ "futures-utils-wasm", "serde", "serde_json", - "thiserror 2.0.4", + "thiserror 2.0.12", ] [[package]] name = "alloy-network-primitives" -version = "0.8.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4df88a2f8020801e0fefce79471d3946d39ca3311802dbbd0ecfdeee5e972e3" +checksum = "3a00ce618ae2f78369918be0c20f620336381502c83b6ed62c2f7b2db27698b0" dependencies = [ "alloy-consensus", "alloy-eips", @@ -220,9 +209,9 @@ dependencies = [ [[package]] name = "alloy-primitives" -version = "0.8.15" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6259a506ab13e1d658796c31e6e39d2e2ee89243bcc505ddc613b35732e0a430" +checksum = "8c66bb6715b7499ea755bde4c96223ae8eb74e05c014ab38b9db602879ffb825" dependencies = [ "alloy-rlp", "arbitrary", @@ -230,10 +219,9 @@ dependencies = [ "cfg-if", "const-hex", "derive_arbitrary", - "derive_more", + "derive_more 2.0.1", "foldhash", "hashbrown 0.15.2", - "hex-literal", "indexmap", "itoa", "k256", @@ -241,9 +229,9 @@ dependencies = [ "paste", "proptest", "proptest-derive", - "rand", + "rand 0.8.5", "ruint", - "rustc-hash 2.1.0", + "rustc-hash 2.1.1", "serde", "sha3", "tiny-keccak", @@ -251,9 +239,9 @@ dependencies = [ [[package]] name = "alloy-provider" -version = "0.8.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5115c74c037714e1b02a86f742289113afa5d494b5ea58308ba8aa378e739101" +checksum = "cbe0a2acff0c4bd1669c71251ce10fc455cbffa1b4d0a817d5ea4ba7e5bb3db7" dependencies = [ "alloy-chains", "alloy-consensus", @@ -262,35 +250,57 @@ dependencies = [ "alloy-network", "alloy-network-primitives", "alloy-primitives", + "alloy-pubsub", "alloy-rpc-client", "alloy-rpc-types-eth", + "alloy-sol-types", "alloy-transport", "alloy-transport-http", + "alloy-transport-ipc", + "alloy-transport-ws", "async-stream", "async-trait", "auto_impl", "dashmap", "futures", "futures-utils-wasm", - "lru", + "lru 0.13.0", "parking_lot", "pin-project", "reqwest", - "schnellru", "serde", "serde_json", - "thiserror 2.0.4", + "thiserror 2.0.12", "tokio", "tracing", "url", "wasmtimer", ] +[[package]] +name = "alloy-pubsub" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3a68996f193f542f9e29c88dfa8ed1369d6ee04fa764c1bf23dc11b2f9e4a2" +dependencies = [ + "alloy-json-rpc", + "alloy-primitives", + "alloy-transport", + "bimap", + "futures", + "serde", + "serde_json", + "tokio", + "tokio-stream", + "tower", + "tracing", +] + [[package]] name = "alloy-rlp" -version = "0.3.9" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0822426598f95e45dd1ea32a738dac057529a709ee645fcc516ffa4cbde08f" +checksum = "3d6c1d995bff8d011f7cd6c81820d51825e6e06d6db73914c1630ecf544d83d6" dependencies = [ "alloy-rlp-derive", "arrayvec", @@ -299,25 +309,28 @@ dependencies = [ [[package]] name = "alloy-rlp-derive" -version = "0.3.9" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b09cae092c27b6f1bde952653a22708691802e57bfef4a2973b80bea21efd3f" +checksum = "a40e1ef334153322fd878d07e86af7a529bcb86b2439525920a88eba87bcf943" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.99", ] [[package]] name = "alloy-rpc-client" -version = "0.8.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c6a0bd0ce5660ac48e4f3bb0c7c5c3a94db287a0be94971599d83928476cbcd" +checksum = "b37cc3c7883dc41be1b01460127ad7930466d0a4bb6ba15a02ee34d2745e2d7c" dependencies = [ "alloy-json-rpc", "alloy-primitives", + "alloy-pubsub", "alloy-transport", "alloy-transport-http", + "alloy-transport-ipc", + "alloy-transport-ws", "futures", "pin-project", "reqwest", @@ -333,9 +346,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types" -version = "0.8.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374ac12e35bb90ebccd86e7c943ddba9590149a6e35cc4d9cd860d6635fd1018" +checksum = "6f18e68a3882f372e045ddc89eb455469347767d17878ca492cfbac81e71a111" dependencies = [ "alloy-primitives", "alloy-rpc-types-debug", @@ -346,9 +359,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-any" -version = "0.8.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea98f81bcd759dbfa3601565f9d7a02220d8ef1d294ec955948b90aaafbfd857" +checksum = "318ae46dd12456df42527c3b94c1ae9001e1ceb707f7afe2c7807ac4e49ebad9" dependencies = [ "alloy-consensus-any", "alloy-rpc-types-eth", @@ -357,24 +370,23 @@ dependencies = [ [[package]] name = "alloy-rpc-types-beacon" -version = "0.8.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e13e94be8f6f5cb735e604f9db436430bf3773fdd41db7221edaa58c07c4c8a" +checksum = "799103aa44270c7bea076ec5d3d7b6c6d29557ab5485c91a74d3068327adb485" dependencies = [ "alloy-eips", "alloy-primitives", "alloy-rpc-types-engine", - "alloy-serde", "serde", "serde_with", - "thiserror 2.0.4", + "thiserror 2.0.12", ] [[package]] name = "alloy-rpc-types-debug" -version = "0.8.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fd14f68a482e67dfba52d404dfff1d3b0d9fc3b4775bd0923f3175d7661c3bd" +checksum = "2834b7012054cb2f90ee9893b7cc97702edca340ec1ef386c30c42e55e6cd691" dependencies = [ "alloy-primitives", "serde", @@ -382,25 +394,27 @@ dependencies = [ [[package]] name = "alloy-rpc-types-engine" -version = "0.8.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ca5898f753ff0d15a0dc955c169523d8fee57e05bb5a38a398b3451b0b988be" +checksum = "e83dde9fcf1ccb9b815cc0c89bba26bbbbaae5150a53ae624ed0fc63cb3676c1" dependencies = [ "alloy-consensus", "alloy-eips", "alloy-primitives", "alloy-rlp", "alloy-serde", - "derive_more", + "derive_more 1.0.0", + "ethereum_ssz", + "ethereum_ssz_derive", "serde", - "strum", + "strum 0.26.3", ] [[package]] name = "alloy-rpc-types-eth" -version = "0.8.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e518b0a7771e00728f18be0708f828b18a1cfc542a7153bef630966a26388e0" +checksum = "8b4dbee4d82f8a22dde18c28257bed759afeae7ba73da4a1479a039fd1445d04" dependencies = [ "alloy-consensus", "alloy-consensus-any", @@ -410,17 +424,17 @@ dependencies = [ "alloy-rlp", "alloy-serde", "alloy-sol-types", - "derive_more", - "itertools 0.13.0", + "itertools 0.14.0", "serde", "serde_json", + "thiserror 2.0.12", ] [[package]] name = "alloy-serde" -version = "0.8.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed3dc8d4a08ffc90c1381d39a4afa2227668259a42c97ab6eecf51cbd82a8761" +checksum = "8732058f5ca28c1d53d241e8504620b997ef670315d7c8afab856b3e3b80d945" dependencies = [ "alloy-primitives", "serde", @@ -429,37 +443,38 @@ dependencies = [ [[package]] name = "alloy-signer" -version = "0.8.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16188684100f6e0f2a2b949968fe3007749c5be431549064a1bce4e7b3a196a9" +checksum = "f96b3526fdd779a4bd0f37319cfb4172db52a7ac24cdbb8804b72091c18e1701" dependencies = [ "alloy-primitives", "async-trait", "auto_impl", + "either", "elliptic-curve", "k256", - "thiserror 2.0.4", + "thiserror 2.0.12", ] [[package]] name = "alloy-sol-macro" -version = "0.8.15" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9d64f851d95619233f74b310f12bcf16e0cbc27ee3762b6115c14a84809280a" +checksum = "c7f9c3c7bc1f4e334e5c5fc59ec8dac894973a71b11da09065affc6094025049" dependencies = [ "alloy-sol-macro-expander", "alloy-sol-macro-input", "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.99", ] [[package]] name = "alloy-sol-macro-expander" -version = "0.8.15" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bf7ed1574b699f48bf17caab4e6e54c6d12bc3c006ab33d58b1e227c1c3559f" +checksum = "46ff7aa715eb2404cb87fa94390d2c5d5addd70d9617e20b2398ee6f48cb21f0" dependencies = [ "alloy-sol-macro-input", "const-hex", @@ -468,31 +483,31 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.99", "syn-solidity", "tiny-keccak", ] [[package]] name = "alloy-sol-macro-input" -version = "0.8.15" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c02997ccef5f34f9c099277d4145f183b422938ed5322dc57a089fe9b9ad9ee" +checksum = "6f105fa700140c0cc6e2c3377adef650c389ac57b8ead8318a2e6bd52f1ae841" dependencies = [ "const-hex", "dunce", "heck", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.99", "syn-solidity", ] [[package]] name = "alloy-sol-types" -version = "0.8.15" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1174cafd6c6d810711b4e00383037bdb458efc4fe3dbafafa16567e0320c54d8" +checksum = "5f819635439ebb06aa13c96beac9b2e7360c259e90f5160a6848ae0d94d10452" dependencies = [ "alloy-primitives", "alloy-sol-macro", @@ -501,17 +516,16 @@ dependencies = [ [[package]] name = "alloy-transport" -version = "0.8.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628be5b9b75e4f4c4f2a71d985bbaca4f23de356dc83f1625454c505f5eef4df" +checksum = "5a8d762eadce3e9b65eac09879430c6f4fce3736cac3cac123f9b1bf435ddd13" dependencies = [ "alloy-json-rpc", "base64", - "futures-util", "futures-utils-wasm", "serde", "serde_json", - "thiserror 2.0.4", + "thiserror 2.0.12", "tokio", "tower", "tracing", @@ -521,9 +535,9 @@ dependencies = [ [[package]] name = "alloy-transport-http" -version = "0.8.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e24412cf72f79c95cd9b1d9482e3a31f9d94c24b43c4b3b710cc8d4341eaab0" +checksum = "20819c4cb978fb39ce6ac31991ba90f386d595f922f42ef888b4a18be190713e" dependencies = [ "alloy-json-rpc", "alloy-transport", @@ -534,16 +548,54 @@ dependencies = [ "url", ] +[[package]] +name = "alloy-transport-ipc" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e88304aa8b796204e5e2500dfe235933ed692745e3effd94c3733643db6d218" +dependencies = [ + "alloy-json-rpc", + "alloy-pubsub", + "alloy-transport", + "bytes", + "futures", + "interprocess", + "pin-project", + "serde", + "serde_json", + "tokio", + "tokio-util", + "tracing", +] + +[[package]] +name = "alloy-transport-ws" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9653ea9aa06d0e02fcbe2f04f1c47f35a85c378ccefa98e54ae85210bc8bbfa" +dependencies = [ + "alloy-pubsub", + "alloy-transport", + "futures", + "http", + "rustls", + "serde_json", + "tokio", + "tokio-tungstenite", + "tracing", + "ws_stream_wasm", +] + [[package]] name = "alloy-trie" -version = "0.7.6" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a5fd8fea044cc9a8c8a50bb6f28e31f0385d820f116c5b98f6f4e55d6e5590b" +checksum = "d95a94854e420f07e962f7807485856cde359ab99ab6413883e15235ad996e8b" dependencies = [ "alloy-primitives", "alloy-rlp", "arrayvec", - "derive_more", + "derive_more 1.0.0", "nybbles", "serde", "smallvec", @@ -597,19 +649,20 @@ dependencies = [ [[package]] name = "anstyle-wincon" -version = "3.0.6" +version = "3.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2109dbce0e72be3ec00bed26e6a7479ca384ad226efdd66db8fa2e3a38c83125" +checksum = "ca3534e77181a9cc07539ad51f2141fe32f6c3ffd4df76db8ad92346b003ae4e" dependencies = [ "anstyle", + "once_cell", "windows-sys 0.59.0", ] [[package]] name = "anyhow" -version = "1.0.94" +version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1fd03a028ef38ba2276dce7e33fcd6369c158a1bca17946c4b1b701891c1ff7" +checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" [[package]] name = "arbitrary" @@ -617,6 +670,39 @@ version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dde20b3d026af13f561bdd0f15edf01fc734f0dafcedbaf42bba506a9517f223" +[[package]] +name = "ark-bn254" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d69eab57e8d2663efa5c63135b2af4f396d66424f88954c21104125ab6b3e6bc" +dependencies = [ + "ark-ec", + "ark-ff 0.5.0", + "ark-std 0.5.0", +] + +[[package]] +name = "ark-ec" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d68f2d516162846c1238e755a7c4d131b892b70cc70c471a8e3ca3ed818fce" +dependencies = [ + "ahash", + "ark-ff 0.5.0", + "ark-poly", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "educe", + "fnv", + "hashbrown 0.15.2", + "itertools 0.13.0", + "num-bigint", + "num-integer", + "num-traits", + "rayon", + "zeroize", +] + [[package]] name = "ark-ff" version = "0.3.0" @@ -655,6 +741,27 @@ dependencies = [ "zeroize", ] +[[package]] +name = "ark-ff" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a177aba0ed1e0fbb62aa9f6d0502e9b46dad8c2eab04c14258a1212d2557ea70" +dependencies = [ + "ark-ff-asm 0.5.0", + "ark-ff-macros 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "arrayvec", + "digest 0.10.7", + "educe", + "itertools 0.13.0", + "num-bigint", + "num-traits", + "paste", + "rayon", + "zeroize", +] + [[package]] name = "ark-ff-asm" version = "0.3.0" @@ -675,6 +782,16 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "ark-ff-asm" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" +dependencies = [ + "quote", + "syn 2.0.99", +] + [[package]] name = "ark-ff-macros" version = "0.3.0" @@ -700,6 +817,35 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "ark-ff-macros" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09be120733ee33f7693ceaa202ca41accd5653b779563608f1234f78ae07c4b3" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 2.0.99", +] + +[[package]] +name = "ark-poly" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "579305839da207f02b89cd1679e50e67b4331e2f9294a57693e5051b7703fe27" +dependencies = [ + "ahash", + "ark-ff 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "educe", + "fnv", + "hashbrown 0.15.2", + "rayon", +] + [[package]] name = "ark-serialize" version = "0.3.0" @@ -721,6 +867,31 @@ dependencies = [ "num-bigint", ] +[[package]] +name = "ark-serialize" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f4d068aaf107ebcd7dfb52bc748f8030e0fc930ac8e360146ca54c1203088f7" +dependencies = [ + "ark-serialize-derive", + "ark-std 0.5.0", + "arrayvec", + "digest 0.10.7", + "num-bigint", + "rayon", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.99", +] + [[package]] name = "ark-std" version = "0.3.0" @@ -728,7 +899,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" dependencies = [ "num-traits", - "rand", + "rand 0.8.5", ] [[package]] @@ -738,7 +909,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" dependencies = [ "num-traits", - "rand", + "rand 0.8.5", +] + +[[package]] +name = "ark-std" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "246a225cc6131e9ee4f24619af0f19d67761fff15d7ccc22e42b80846e69449a" +dependencies = [ + "num-traits", + "rand 0.8.5", + "rayon", ] [[package]] @@ -781,18 +963,29 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.99", ] [[package]] name = "async-trait" -version = "0.1.83" +version = "0.1.87" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" +checksum = "d556ec1359574147ec0c4fc5eb525f3f23263a592b1a9c07e0a75b427de55c97" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.99", +] + +[[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]] @@ -803,9 +996,9 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" [[package]] name = "aurora-engine-modexp" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0aef7712851e524f35fbbb74fa6599c5cd8692056a1c36f9ca0d2001b670e7e5" +checksum = "518bc5745a6264b5fd7b09dffb9667e400ee9e2bbe18555fac75e1fe9afa0df9" dependencies = [ "hex", "num", @@ -813,13 +1006,13 @@ dependencies = [ [[package]] name = "auto_impl" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" +checksum = "e12882f59de5360c748c4cbf569a042d5fb0eb515f7bea9c1f470b47f6ffbd73" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.99", ] [[package]] @@ -861,13 +1054,19 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +[[package]] +name = "bimap" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "230c5f1ca6a325a32553f8640d31ac9b49f2411e901e427570154868b46da4f7" + [[package]] name = "bindgen" version = "0.69.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.0", "cexpr", "clang-sys", "itertools 0.12.1", @@ -878,23 +1077,23 @@ dependencies = [ "regex", "rustc-hash 1.1.0", "shlex", - "syn 2.0.90", + "syn 2.0.99", ] [[package]] name = "bit-set" -version = "0.5.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" dependencies = [ "bit-vec", ] [[package]] name = "bit-vec" -version = "0.6.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" [[package]] name = "bitflags" @@ -904,9 +1103,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.6.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" [[package]] name = "bitvec" @@ -931,9 +1130,9 @@ dependencies = [ [[package]] name = "blst" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4378725facc195f1a538864863f6de233b500a8862747e7f165078a419d5e874" +checksum = "47c79a94619fade3c0b887670333513a67ac28a6a7e653eb260bf0d4103db38d" dependencies = [ "cc", "glob", @@ -941,44 +1140,23 @@ dependencies = [ "zeroize", ] -[[package]] -name = "brotli" -version = "7.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc97b8f16f944bba54f0433f07e30be199b6dc2bd25937444bbad560bcea29bd" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", - "brotli-decompressor", -] - -[[package]] -name = "brotli-decompressor" -version = "4.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a45bd2e4095a8b518033b128020dd4a55aab1c0a381ba4404a472630f4bc362" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", -] - [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "byte-slice-cast" -version = "1.2.2" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" +checksum = "7575182f7272186991736b70173b0ea045398f984bf5ebbb3804736ce1330c9d" [[package]] name = "bytecheck" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50c8f430744b23b54ad15161fcbc22d82a29b73eacbe425fea23ec822600bc6f" +checksum = "50690fb3370fb9fe3550372746084c46f2ac8c9685c583d2be10eefd89d3d1a3" dependencies = [ "bytecheck_derive", "ptr_meta", @@ -988,20 +1166,20 @@ dependencies = [ [[package]] name = "bytecheck_derive" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523363cbe1df49b68215efdf500b103ac3b0fb4836aed6d15689a076eadb8fff" +checksum = "efb7846e0cb180355c2dec69e721edafa36919850f1a9f52ffba4ebc0393cb71" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.99", ] [[package]] name = "bytemuck" -version = "1.20.0" +version = "1.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b37c88a63ffd85d15b406896cc343916d7cf57838a847b3a6f2ca5d39a5695a" +checksum = "b6b1fc10dbac614ebc03540c9dbd60e83887fda27794998c6528f1782047d540" [[package]] name = "byteorder" @@ -1011,21 +1189,20 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" +checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9" dependencies = [ "serde", ] [[package]] name = "bzip2-sys" -version = "0.1.11+1.0.8" +version = "0.1.13+1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" +checksum = "225bff33b2141874fe80d71e07d6eec4f85c5c216453dd96388240f96e1acc14" dependencies = [ "cc", - "libc", "pkg-config", ] @@ -1052,9 +1229,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.2" +version = "1.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f34d93e62b03caf570cccc334cbc6c2fceca82f39211051345108adcba3eebdc" +checksum = "be714c154be609ec7f5dad223a33bf1482fff90472de28f7362806e6d4832b8c" dependencies = [ "jobserver", "libc", @@ -1078,9 +1255,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "chrono" -version = "0.4.38" +version = "0.4.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" dependencies = [ "num-traits", "serde", @@ -1126,9 +1303,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.22" +version = "4.5.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69371e34337c4c984bbe322360c2547210bf632eb2814bbe78a6e87a2935bd2b" +checksum = "027bb0d98429ae334a8698531da7077bdf906419543a35a55c2cb1b66437d767" dependencies = [ "clap_builder", "clap_derive", @@ -1136,9 +1313,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.22" +version = "4.5.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e24c1b4099818523236a8ca881d2b45db98dadfb4625cf6608c12069fcbbde1" +checksum = "5589e0cba072e0f3d23791efac0fd8627b49c829c196a492e88168e6a669d863" dependencies = [ "anstream", "anstyle", @@ -1148,21 +1325,21 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.18" +version = "4.5.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ac6a0c7b1a9e9a5186361f67dfa1b88213572f427fb9ab038efb2bd8c582dab" +checksum = "bf4ced95c6f4a675af3da73304b9ac4ed991640c36374e4b46795c49e17cf1ed" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.99", ] [[package]] name = "clap_lex" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" +checksum = "f46ad14479a25103f283c0f10005961cf086d8dc42205bb44c46ac563475dca6" [[package]] name = "colorchoice" @@ -1198,6 +1375,26 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "const_format" +version = "0.2.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126f97965c8ad46d6d9163268ff28432e8f6a1196a55578867832e3049df63dd" +dependencies = [ + "const_format_proc_macros", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + [[package]] name = "core-foundation" version = "0.9.4" @@ -1225,13 +1422,28 @@ dependencies = [ [[package]] name = "cpufeatures" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" dependencies = [ "libc", ] +[[package]] +name = "crc" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69e6e4d7b33a94f0991c26729976b10ebde1d34c3ee82408fb536164fa10d636" +dependencies = [ + "crc-catalog", +] + +[[package]] +name = "crc-catalog" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" + [[package]] name = "criterion" version = "0.5.1" @@ -1268,11 +1480,20 @@ dependencies = [ "itertools 0.10.5", ] +[[package]] +name = "crossbeam-channel" +version = "0.5.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-deque" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -1289,15 +1510,15 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.20" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crunchy" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" [[package]] name = "crypto-bigint" @@ -1306,7 +1527,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" dependencies = [ "generic-array", - "rand_core", + "rand_core 0.6.4", "subtle", "zeroize", ] @@ -1342,7 +1563,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.90", + "syn 2.0.99", ] [[package]] @@ -1353,7 +1574,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.90", + "syn 2.0.99", ] [[package]] @@ -1370,6 +1591,12 @@ dependencies = [ "parking_lot_core", ] +[[package]] +name = "data-encoding" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "575f75dfd25738df5b91b8e43e14d44bda14637a58fae779fd2b064f8bf3e010" + [[package]] name = "debugid" version = "0.8.0" @@ -1417,7 +1644,7 @@ checksum = "30542c1ad912e0e3d22a1935c290e12e8a29d704a420177a31faad4a601a0800" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.99", ] [[package]] @@ -1426,7 +1653,16 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a9b99b9cbbe49445b21764dc0625032a89b145a2642e67603e1c936f5458d05" dependencies = [ - "derive_more-impl", + "derive_more-impl 1.0.0", +] + +[[package]] +name = "derive_more" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "093242cf7570c207c83073cf82f79706fe7b8317e98620a47d5be7c3d8497678" +dependencies = [ + "derive_more-impl 2.0.1", ] [[package]] @@ -1437,7 +1673,19 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.99", + "unicode-xid", +] + +[[package]] +name = "derive_more-impl" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda628edc44c4bb645fbe0f758797143e4e07926f7ebf4e9bdfbd3d2ce621df3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.99", "unicode-xid", ] @@ -1470,9 +1718,15 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.99", ] +[[package]] +name = "doctest-file" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aac81fa3e28d21450aa4d2ac065992ba96a1d7303efbce51a95f4fd175b67562" + [[package]] name = "dunce" version = "1.0.5" @@ -1481,9 +1735,9 @@ checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" [[package]] name = "dyn-clone" -version = "1.0.17" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" +checksum = "1c7a8fb8a9fbf66c1f703fe16184d10ca0ee9d23be5b4436400408ba54a95005" [[package]] name = "ecdsa" @@ -1499,11 +1753,37 @@ dependencies = [ "spki", ] +[[package]] +name = "educe" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn 2.0.99", +] + +[[package]] +name = "eigen-da" +version = "0.1.0" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "bytes", + "hex", + "kona-derive", + "rust-kzg-bn254-primitives", + "serde_json", + "tracing", +] + [[package]] name = "either" -version = "1.13.0" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" +checksum = "b7914353092ddf589ad78f25c5c1c21b7f80b0ff8621e7c814c3485b5306da9d" [[package]] name = "elliptic-curve" @@ -1518,7 +1798,7 @@ dependencies = [ "generic-array", "group", "pkcs8", - "rand_core", + "rand_core 0.6.4", "sec1", "subtle", "zeroize", @@ -1533,6 +1813,26 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "enum-ordinalize" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fea0dcfa4e54eeb516fe454635a95753ddd39acda650ce703031c6973e315dd5" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.99", +] + [[package]] name = "enumn" version = "0.1.14" @@ -1541,34 +1841,34 @@ checksum = "2f9ed6b3789237c8a0c1c505af1c7eb2c560df6186f01b098c3a1064ea532f38" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.99", ] [[package]] name = "equator" -version = "0.2.2" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c35da53b5a021d2484a7cc49b2ac7f2d840f8236a286f84202369bd338d761ea" +checksum = "4711b213838dfee0117e3be6ac926007d7f433d7bbe33595975d4190cb07e6fc" dependencies = [ "equator-macro", ] [[package]] name = "equator-macro" -version = "0.2.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bf679796c0322556351f287a51b49e48f7c4986e727b5dd78c972d30e2e16cc" +checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.99", ] [[package]] name = "equivalent" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" @@ -1580,11 +1880,51 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "ethereum_serde_utils" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70cbccfccf81d67bff0ab36e591fa536c8a935b078a7b0e58c1d00d418332fc9" +dependencies = [ + "alloy-primitives", + "hex", + "serde", + "serde_derive", + "serde_json", +] + +[[package]] +name = "ethereum_ssz" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86da3096d1304f5f28476ce383005385459afeaf0eea08592b65ddbc9b258d16" +dependencies = [ + "alloy-primitives", + "ethereum_serde_utils", + "itertools 0.13.0", + "serde", + "serde_derive", + "smallvec", + "typenum", +] + +[[package]] +name = "ethereum_ssz_derive" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d832a5c38eba0e7ad92592f7a22d693954637fbb332b4f669590d66a5c3183e5" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.99", +] + [[package]] name = "event-listener" -version = "5.3.1" +version = "5.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" +checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" dependencies = [ "concurrent-queue", "parking", @@ -1603,9 +1943,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "fastrlp" @@ -1618,13 +1958,24 @@ dependencies = [ "bytes", ] +[[package]] +name = "fastrlp" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce8dba4714ef14b8274c371879b175aa55b16b30f269663f19d576f380018dc4" +dependencies = [ + "arrayvec", + "auto_impl", + "bytes", +] + [[package]] name = "ff" version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" dependencies = [ - "rand_core", + "rand_core 0.6.4", "subtle", ] @@ -1647,7 +1998,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" dependencies = [ "byteorder", - "rand", + "rand 0.8.5", "rustc-hex", "static_assertions", ] @@ -1660,9 +2011,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "foldhash" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" +checksum = "a0d2fde1f7b3d48b8395d5f2de76c18a528bd6a9cdde438df747bfcba3e05d6f" [[package]] name = "foreign-types" @@ -1750,7 +2101,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.99", ] [[package]] @@ -1765,6 +2116,12 @@ 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" + [[package]] name = "futures-util" version = "0.3.31" @@ -1808,7 +2165,19 @@ checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.13.3+wasi-0.2.2", + "windows-targets", ] [[package]] @@ -1819,9 +2188,9 @@ checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "glob" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +checksum = "a8d1add55171497b4705a648c6b583acafb01d58050a51727785f0b2c8e0a2b2" [[package]] name = "group" @@ -1830,15 +2199,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ "ff", - "rand_core", + "rand_core 0.6.4", "subtle", ] [[package]] name = "h2" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e" +checksum = "5017294ff4bb30944501348f6f8e42e6ad28f42c8bbef7a74029aff064a4e3c2" dependencies = [ "atomic-waker", "bytes", @@ -1863,12 +2232,6 @@ dependencies = [ "crunchy", ] -[[package]] -name = "hashbrown" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" - [[package]] name = "hashbrown" version = "0.14.5" @@ -1914,12 +2277,6 @@ dependencies = [ "serde", ] -[[package]] -name = "hex-literal" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" - [[package]] name = "hmac" version = "0.12.1" @@ -1965,15 +2322,15 @@ dependencies = [ [[package]] name = "httparse" -version = "1.9.5" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] name = "hyper" -version = "1.5.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97818827ef4f364230e16705d4706e2897df2bb60617d6ca15d598025a3c481f" +checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" dependencies = [ "bytes", "futures-channel", @@ -1991,9 +2348,9 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.27.3" +version = "0.27.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08afdbb5c31130e3034af566421053ab03787c640246a446327f550d11bcb333" +checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" dependencies = [ "futures-util", "http", @@ -2156,7 +2513,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.99", ] [[package]] @@ -2203,14 +2560,14 @@ checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.99", ] [[package]] name = "indexmap" -version = "2.7.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" +checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" dependencies = [ "arbitrary", "equivalent", @@ -2236,21 +2593,36 @@ dependencies = [ "str_stack", ] +[[package]] +name = "interprocess" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "894148491d817cb36b6f778017b8ac46b17408d522dd90f539d677ea938362eb" +dependencies = [ + "doctest-file", + "futures-core", + "libc", + "recvmsg", + "tokio", + "widestring", + "windows-sys 0.52.0", +] + [[package]] name = "ipnet" -version = "2.10.1" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" +checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" [[package]] name = "is-terminal" -version = "0.4.13" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" +checksum = "e19b23d53f35ce9f56aebc7d1bb4e6ac1e9c0db7ac85c8d1760c04379edced37" dependencies = [ "hermit-abi 0.4.0", "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -2286,11 +2658,20 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b192c782037fadd9cfa75548310488aabdbf3d2da73885b31bd0abd03351285" +dependencies = [ + "either", +] + [[package]] name = "itoa" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jobserver" @@ -2303,9 +2684,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.74" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a865e038f7f6ed956f788f0d7d60c541fff74c7bd74272c5d4cf15c63743e705" +checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" dependencies = [ "once_cell", "wasm-bindgen", @@ -2362,7 +2743,7 @@ dependencies = [ "kona-proof", "kona-std-fpvm", "kona-std-fpvm-proc", - "lru", + "lru 0.12.5", "op-alloy-consensus", "op-alloy-genesis", "op-alloy-protocol", @@ -2371,13 +2752,13 @@ dependencies = [ "serde", "serde_json", "spin", - "thiserror 2.0.4", + "thiserror 2.0.12", "tracing", ] [[package]] name = "kona-derive" -version = "0.2.0" +version = "0.2.3" dependencies = [ "alloy-consensus", "alloy-eips", @@ -2385,15 +2766,20 @@ dependencies = [ "alloy-rlp", "alloy-rpc-types-engine", "async-trait", + "bytes", + "hex", + "log", + "miniz_oxide", "op-alloy-consensus", "op-alloy-genesis", "op-alloy-protocol", - "op-alloy-registry", "op-alloy-rpc-types-engine", "proptest", + "prost", + "rlp 0.6.1", "serde_json", "spin", - "thiserror 2.0.4", + "thiserror 2.0.12", "tokio", "tracing", "tracing-subscriber", @@ -2401,18 +2787,20 @@ dependencies = [ [[package]] name = "kona-driver" -version = "0.2.0" +version = "0.2.3" dependencies = [ "alloy-consensus", "alloy-primitives", "alloy-rlp", "async-trait", "kona-derive", + "kona-executor", "op-alloy-consensus", "op-alloy-genesis", "op-alloy-protocol", "op-alloy-rpc-types-engine", - "thiserror 2.0.4", + "spin", + "thiserror 2.0.12", "tracing", ] @@ -2423,20 +2811,27 @@ dependencies = [ "alloy-consensus", "alloy-eips", "alloy-primitives", + "alloy-provider", "alloy-rlp", + "alloy-rpc-client", "alloy-rpc-types-engine", - "anyhow", + "alloy-transport", + "alloy-transport-http", + "alloy-trie", "criterion", + "kona-host", "kona-mpt", "op-alloy-consensus", "op-alloy-genesis", "op-alloy-rpc-types-engine", "pprof", - "rand", + "rand 0.8.5", "revm", + "rstest", "serde", "serde_json", - "thiserror 2.0.4", + "thiserror 2.0.12", + "tokio", "tracing", ] @@ -2455,21 +2850,29 @@ dependencies = [ "alloy-serde", "alloy-transport-http", "anyhow", + "ark-bn254", + "ark-ff 0.5.0", "async-trait", "clap", + "eigen-da", "kona-client", "kona-derive", "kona-mpt", "kona-preimage", "kona-proof", + "kona-providers-alloy", "kona-std-fpvm", + "num", "op-alloy-genesis", + "op-alloy-network", "op-alloy-protocol", "op-alloy-rpc-types-engine", "proptest", "reqwest", "revm", "rocksdb", + "rust-kzg-bn254-primitives", + "rust-kzg-bn254-prover", "serde", "serde_json", "tokio", @@ -2492,10 +2895,10 @@ dependencies = [ "criterion", "pprof", "proptest", - "rand", + "rand 0.8.5", "reqwest", "serde", - "thiserror 2.0.4", + "thiserror 2.0.12", "tokio", "tracing-subscriber", ] @@ -2509,39 +2912,64 @@ dependencies = [ "async-trait", "rkyv", "serde", - "thiserror 2.0.4", + "thiserror 2.0.12", "tokio", "tracing", ] [[package]] name = "kona-proof" -version = "0.2.0" +version = "0.2.3" dependencies = [ "alloy-consensus", "alloy-eips", "alloy-primitives", "alloy-rlp", "async-trait", + "eigen-da", "kona-derive", "kona-driver", "kona-executor", "kona-mpt", "kona-preimage", - "lru", + "lru 0.12.5", "op-alloy-consensus", "op-alloy-genesis", "op-alloy-protocol", - "op-alloy-registry", "op-alloy-rpc-types-engine", "serde", "serde_json", "spin", - "thiserror 2.0.4", + "thiserror 2.0.12", "tokio", "tracing", ] +[[package]] +name = "kona-providers-alloy" +version = "0.1.0" +dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-primitives", + "alloy-provider", + "alloy-rlp", + "alloy-rpc-types-beacon", + "alloy-serde", + "alloy-transport", + "async-trait", + "eigen-da", + "kona-derive", + "lru 0.12.5", + "op-alloy-consensus", + "op-alloy-genesis", + "op-alloy-protocol", + "reqwest", + "serde", + "thiserror 2.0.12", + "tokio", +] + [[package]] name = "kona-std-fpvm" version = "0.1.1" @@ -2550,7 +2978,7 @@ dependencies = [ "cfg-if", "kona-preimage", "linked_list_allocator", - "thiserror 2.0.4", + "thiserror 2.0.12", "tracing", ] @@ -2563,7 +2991,7 @@ dependencies = [ "kona-std-fpvm", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.99", ] [[package]] @@ -2583,9 +3011,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.167" +version = "0.2.170" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc" +checksum = "875b3680cb2f8f71bdcf9a30f38d48282f5d3c95cbf9b3fa57269bb5d5c06828" [[package]] name = "libloading" @@ -2619,9 +3047,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.20" +version = "1.1.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2d16453e800a8cf6dd2fc3eb4bc99b786a9b90c663b8559a5b1a041bf89e472" +checksum = "df9b68e50e6e0b26f672573834882eb57759f6db9b3be2ea3c35c91188bb4eaa" dependencies = [ "cc", "pkg-config", @@ -2639,15 +3067,15 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.4.14" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] name = "litemap" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" +checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" [[package]] name = "lock_api" @@ -2661,9 +3089,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.22" +version = "0.4.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e" [[package]] name = "lru" @@ -2674,6 +3102,15 @@ dependencies = [ "hashbrown 0.15.2", ] +[[package]] +name = "lru" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "227748d55f2f0ab4735d87fd623798cb6b664512fe979705f829c9f81c934465" +dependencies = [ + "hashbrown 0.15.2", +] + [[package]] name = "memchr" version = "2.7.4" @@ -2703,9 +3140,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.8.0" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d80299ef12ff69b16a84bb182e3b9df68b5a91574d3d4fa6e41b65deec4df1" +checksum = "8e3e04debbb59698c15bacbb6d93584a8c0ca9cc3213cb423d31f760d8843ce5" dependencies = [ "adler2", ] @@ -2717,35 +3154,35 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys 0.52.0", ] [[package]] name = "munge" -version = "0.4.1" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64142d38c84badf60abf06ff9bd80ad2174306a5b11bd4706535090a30a419df" +checksum = "a0091202c98cf06da46c279fdf50cccb6b1c43b4521abdf6a27b4c7e71d5d9d7" dependencies = [ "munge_macro", ] [[package]] name = "munge_macro" -version = "0.4.1" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bb5c1d8184f13f7d0ccbeeca0def2f9a181bce2624302793005f5ca8aa62e5e" +checksum = "734799cf91479720b2f970c61a22850940dd91e27d4f02b1c6fc792778df2459" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.99", ] [[package]] name = "native-tls" -version = "0.2.12" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8614eb2c83d59d1c8cc974dd3f920198647674a0a035e1af1fa58707e317466" +checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" dependencies = [ "libc", "log", @@ -2906,14 +3343,14 @@ checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.99", ] [[package]] name = "nybbles" -version = "0.2.1" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95f06be0417d97f81fe4e5c86d7d01b392655a9cac9c19a848aa033e18937b23" +checksum = "8983bb634df7248924ee0c4c3a749609b5abcb082c28fffe3254b3eb3602b307" dependencies = [ "const-hex", "serde", @@ -2922,18 +3359,18 @@ dependencies = [ [[package]] name = "object" -version = "0.36.5" +version = "0.36.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" +checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.20.2" +version = "1.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" [[package]] name = "oorandom" @@ -2943,25 +3380,23 @@ checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" [[package]] name = "op-alloy-consensus" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24aaf487dd59beed72931e31b11b305cdcb6a20651a1cccf992a20706a54cc3b" +version = "0.6.5" +source = "git+https://github.com/mantle-xyz/op-alloy?branch=alloy-0.11.1#8d6fee26f2530f4d2b1745448c63ac1d05202247" dependencies = [ "alloy-consensus", "alloy-eips", "alloy-primitives", "alloy-rlp", "alloy-serde", - "derive_more", + "derive_more 1.0.0", "serde", - "thiserror 2.0.4", + "spin", ] [[package]] name = "op-alloy-genesis" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ad6c33c2711611e19092a7d17c076542e27687ef975f67bf57039fa3d57e06" +version = "0.6.5" +source = "git+https://github.com/mantle-xyz/op-alloy?branch=alloy-0.11.1#8d6fee26f2530f4d2b1745448c63ac1d05202247" dependencies = [ "alloy-consensus", "alloy-eips", @@ -2969,71 +3404,82 @@ dependencies = [ "alloy-sol-types", "serde", "serde_repr", - "thiserror 2.0.4", +] + +[[package]] +name = "op-alloy-network" +version = "0.6.5" +source = "git+https://github.com/mantle-xyz/op-alloy?branch=alloy-0.11.1#8d6fee26f2530f4d2b1745448c63ac1d05202247" +dependencies = [ + "alloy-consensus", + "alloy-network", + "alloy-primitives", + "alloy-rpc-types-eth", + "alloy-signer", + "op-alloy-consensus", + "op-alloy-rpc-types", ] [[package]] name = "op-alloy-protocol" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccb98f90d0101cdaabb739c44f4d4b2d0ad0ad1a3dd68ce525683ffafd97dd13" +version = "0.6.5" +source = "git+https://github.com/mantle-xyz/op-alloy?branch=alloy-0.11.1#8d6fee26f2530f4d2b1745448c63ac1d05202247" dependencies = [ - "alloc-no-stdlib", "alloy-consensus", "alloy-eips", "alloy-primitives", "alloy-rlp", "alloy-serde", "async-trait", - "brotli", - "cfg-if", - "miniz_oxide", + "derive_more 1.0.0", "op-alloy-consensus", "op-alloy-genesis", "serde", - "thiserror 2.0.4", "tracing", "unsigned-varint", ] [[package]] -name = "op-alloy-registry" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "892a3b296687acf306d2a25f96bf542f55b10ca741ae92b2ebdd492dd41e48b3" +name = "op-alloy-rpc-types" +version = "0.6.5" +source = "git+https://github.com/mantle-xyz/op-alloy?branch=alloy-0.11.1#8d6fee26f2530f4d2b1745448c63ac1d05202247" dependencies = [ + "alloy-consensus", + "alloy-eips", + "alloy-network-primitives", "alloy-primitives", - "lazy_static", - "op-alloy-genesis", + "alloy-rpc-types-eth", + "alloy-serde", + "derive_more 1.0.0", + "op-alloy-consensus", "serde", "serde_json", ] [[package]] name = "op-alloy-rpc-types-engine" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c63ba3f50dba410d1ce18aa16242c198f91ad44da5221f7347c1525958a9b09" +version = "0.6.5" +source = "git+https://github.com/mantle-xyz/op-alloy?branch=alloy-0.11.1#8d6fee26f2530f4d2b1745448c63ac1d05202247" dependencies = [ "alloy-eips", "alloy-primitives", "alloy-rpc-types-engine", "alloy-serde", - "derive_more", + "derive_more 1.0.0", + "ethereum_ssz", "op-alloy-consensus", - "op-alloy-genesis", "op-alloy-protocol", "serde", - "thiserror 2.0.4", + "snap", ] [[package]] name = "openssl" -version = "0.10.68" +version = "0.10.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" +checksum = "5e14130c6a98cd258fdcb0fb6d744152343ff729cbfcb28c656a9d12b999fbcd" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.0", "cfg-if", "foreign-types", "libc", @@ -3050,20 +3496,20 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.99", ] [[package]] name = "openssl-probe" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-sys" -version = "0.9.104" +version = "0.9.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" +checksum = "8bb61ea9811cc39e3c2069f40b8b8e2e70d8569b361f879786cc7ed48b777cdd" dependencies = [ "cc", "libc", @@ -3091,28 +3537,30 @@ dependencies = [ [[package]] name = "parity-scale-codec" -version = "3.6.12" +version = "3.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" +checksum = "c9fde3d0718baf5bc92f577d652001da0f8d54cd03a7974e118d04fc888dc23d" dependencies = [ "arrayvec", "bitvec", "byte-slice-cast", + "const_format", "impl-trait-for-tuples", "parity-scale-codec-derive", + "rustversion", "serde", ] [[package]] name = "parity-scale-codec-derive" -version = "3.6.12" +version = "3.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" +checksum = "581c837bb6b9541ce7faa9377c20616e4fb7650f6b0f68bc93c827ee504fb7b3" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.99", ] [[package]] @@ -3158,40 +3606,50 @@ checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "pest" -version = "2.7.14" +version = "2.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442" +checksum = "8b7cafe60d6cf8e62e1b9b2ea516a089c008945bb5a275416789e7db0bc199dc" dependencies = [ "memchr", - "thiserror 1.0.69", + "thiserror 2.0.12", "ucd-trie", ] +[[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 = "pin-project" -version = "1.1.7" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95" +checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.7" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" +checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.99", ] [[package]] name = "pin-project-lite" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915a1e146535de9163f3987b8944ed8cf49a18bb0056bcebcdcece385cece4ff" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" [[package]] name = "pin-utils" @@ -3211,9 +3669,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "plotters" @@ -3278,7 +3736,7 @@ version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77957b295656769bb8ad2b6a6b09d897d94f05c41b069aede1fcdaa675eaea04" dependencies = [ - "zerocopy", + "zerocopy 0.7.35", ] [[package]] @@ -3329,31 +3787,31 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.99", ] [[package]] name = "proc-macro2" -version = "1.0.92" +version = "1.0.94" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" +checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" dependencies = [ "unicode-ident", ] [[package]] name = "proptest" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4c2511913b88df1637da85cc8d96ec8e43a3f8bb8ccb71ee1ac240d6f3df58d" +checksum = "14cae93065090804185d3b75f0bf93b8eeda30c7a9b4a33d3bdb3988d6229e50" dependencies = [ "bit-set", "bit-vec", - "bitflags 2.6.0", + "bitflags 2.9.0", "lazy_static", "num-traits", - "rand", - "rand_chacha", + "rand 0.8.5", + "rand_chacha 0.3.1", "rand_xorshift", "regex-syntax", "rusty-fork", @@ -3363,13 +3821,36 @@ dependencies = [ [[package]] name = "proptest-derive" -version = "0.5.0" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ee1c9ac207483d5e7db4940700de86a9aae46ef90c48b57f99fe7edb8345e49" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.99", +] + +[[package]] +name = "prost" +version = "0.13.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2796faa41db3ec313a31f7624d9286acf277b52de526150b7e69f3debf891ee5" +dependencies = [ + "bytes", + "prost-derive", +] + +[[package]] +name = "prost-derive" +version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff7ff745a347b87471d859a377a9a404361e7efc2a971d73424a6d183c0fc77" +checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" dependencies = [ + "anyhow", + "itertools 0.14.0", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.99", ] [[package]] @@ -3389,7 +3870,7 @@ checksum = "ca414edb151b4c8d125c12566ab0d74dc9cdba36fb80eb7b848c15f495fd32d1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.99", ] [[package]] @@ -3409,9 +3890,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.37" +version = "1.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +checksum = "c1f1914ce909e1658d9907913b4b91947430c7d9be598b15a1912935b8c04801" dependencies = [ "proc-macro2", ] @@ -3438,11 +3919,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", - "rand_chacha", - "rand_core", + "rand_chacha 0.3.1", + "rand_core 0.6.4", "serde", ] +[[package]] +name = "rand" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.3", + "zerocopy 0.8.21", +] + [[package]] name = "rand_chacha" version = "0.3.1" @@ -3450,7 +3942,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" +dependencies = [ + "ppv-lite86", + "rand_core 0.9.3", ] [[package]] @@ -3459,7 +3961,16 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom 0.2.15", +] + +[[package]] +name = "rand_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +dependencies = [ + "getrandom 0.3.1", ] [[package]] @@ -3468,7 +3979,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" dependencies = [ - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -3491,13 +4002,19 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "recvmsg" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3edd4d5d42c92f0a659926464d4cce56b562761267ecf0f469d85b7de384175" + [[package]] name = "redox_syscall" -version = "0.5.7" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" +checksum = "0b8c0c260b63a8219631167be35e6a988e9554dbd323f8bd08439c8ed1302bd1" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.0", ] [[package]] @@ -3529,6 +4046,12 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +[[package]] +name = "relative-path" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2" + [[package]] name = "rend" version = "0.5.2" @@ -3540,9 +4063,9 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.9" +version = "0.12.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a77c62af46e79de0a562e1a9849205ffcb7fc1238876e9bd743357570e04046f" +checksum = "43e734407157c3c2034e0258f5e4473ddb361b1e85f95a66690d67264d7cd1da" dependencies = [ "base64", "bytes", @@ -3569,10 +4092,11 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", - "sync_wrapper 1.0.2", + "sync_wrapper", "system-configuration", "tokio", "tokio-native-tls", + "tower", "tower-service", "url", "wasm-bindgen", @@ -3583,24 +4107,23 @@ dependencies = [ [[package]] name = "revm" -version = "16.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34e44692d5736cc44c697a372e507890f8797f06d1541c5f4b9bec594d90fd8a" +version = "17.0.0" +source = "git+https://github.com/mantle-xyz/revm?branch=dev#9a355b02deb81dc367f8d764af2e4f3dd8fc8c4b" dependencies = [ "auto_impl", "cfg-if", "dyn-clone", "revm-interpreter", "revm-precompile", + "revm-primitives", "serde", "serde_json", ] [[package]] name = "revm-interpreter" -version = "12.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f89940d17d5d077570de1977f52f69049595322e237cb6c754c3d47f668f023" +version = "13.0.0" +source = "git+https://github.com/mantle-xyz/revm?branch=dev#9a355b02deb81dc367f8d764af2e4f3dd8fc8c4b" dependencies = [ "revm-primitives", "serde", @@ -3608,9 +4131,8 @@ dependencies = [ [[package]] name = "revm-precompile" -version = "13.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8f816aaea3245cbdbe7fdd84955df33597f9322c7912c3e3ba7bc855e03211f" +version = "14.0.0" +source = "git+https://github.com/mantle-xyz/revm?branch=dev#9a355b02deb81dc367f8d764af2e4f3dd8fc8c4b" dependencies = [ "aurora-engine-modexp", "blst", @@ -3628,15 +4150,14 @@ dependencies = [ [[package]] name = "revm-primitives" -version = "12.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "532411bbde45a46707c1d434dcdc29866cf261c1b748fb01b303ce3b4310b361" +version = "13.0.0" +source = "git+https://github.com/mantle-xyz/revm?branch=dev#9a355b02deb81dc367f8d764af2e4f3dd8fc8c4b" dependencies = [ "alloy-eip2930", - "alloy-eip7702 0.2.0", + "alloy-eip7702", "alloy-primitives", "auto_impl", - "bitflags 2.6.0", + "bitflags 2.9.0", "bitvec", "c-kzg", "cfg-if", @@ -3667,15 +4188,14 @@ dependencies = [ [[package]] name = "ring" -version = "0.17.8" +version = "0.17.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +checksum = "da5349ae27d3887ca812fb375b45a4fbb36d8d12d2df394968cd86e35683fe73" dependencies = [ "cc", "cfg-if", - "getrandom", + "getrandom 0.2.15", "libc", - "spin", "untrusted", "windows-sys 0.52.0", ] @@ -3691,9 +4211,9 @@ dependencies = [ [[package]] name = "rkyv" -version = "0.8.9" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b11a153aec4a6ab60795f8ebe2923c597b16b05bb1504377451e705ef1a45323" +checksum = "1e147371c75553e1e2fcdb483944a8540b8438c31426279553b9a8182a9b7b65" dependencies = [ "bytecheck", "bytes", @@ -3710,13 +4230,13 @@ dependencies = [ [[package]] name = "rkyv_derive" -version = "0.8.9" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "beb382a4d9f53bd5c0be86b10d8179c3f8a14c30bf774ff77096ed6581e35981" +checksum = "246b40ac189af6c675d124b802e8ef6d5246c53e17367ce9501f8f66a81abb7a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.99", ] [[package]] @@ -3729,6 +4249,16 @@ dependencies = [ "rustc-hex", ] +[[package]] +name = "rlp" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa24e92bb2a83198bb76d661a71df9f7076b8c420b8696e4d3d97d50d94479e3" +dependencies = [ + "bytes", + "rustc-hex", +] + [[package]] name = "rocksdb" version = "0.22.0" @@ -3739,25 +4269,57 @@ dependencies = [ "librocksdb-sys", ] +[[package]] +name = "rstest" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03e905296805ab93e13c1ec3a03f4b6c4f35e9498a3d5fa96dc626d22c03cd89" +dependencies = [ + "futures-timer", + "futures-util", + "rstest_macros", + "rustc_version 0.4.1", +] + +[[package]] +name = "rstest_macros" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef0053bbffce09062bee4bcc499b0fbe7a57b879f1efe088d6d8d4c7adcdef9b" +dependencies = [ + "cfg-if", + "glob", + "proc-macro-crate", + "proc-macro2", + "quote", + "regex", + "relative-path", + "rustc_version 0.4.1", + "syn 2.0.99", + "unicode-ident", +] + [[package]] name = "ruint" -version = "1.12.3" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c3cc4c2511671f327125da14133d0c5c5d137f006a1017a16f557bc85b16286" +checksum = "825df406ec217a8116bd7b06897c6cc8f65ffefc15d030ae2c9540acc9ed50b6" dependencies = [ "alloy-rlp", "arbitrary", "ark-ff 0.3.0", "ark-ff 0.4.2", "bytes", - "fastrlp", + "fastrlp 0.3.1", + "fastrlp 0.4.0", "num-bigint", + "num-integer", "num-traits", "parity-scale-codec", "primitive-types", "proptest", - "rand", - "rlp", + "rand 0.8.5", + "rlp 0.5.2", "ruint-macro", "serde", "valuable", @@ -3770,6 +4332,39 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" +[[package]] +name = "rust-kzg-bn254-primitives" +version = "0.1.0" +source = "git+https://github.com/Layr-Labs/rust-kzg-bn254?rev=b3e532e9aad533009849755d5ad7b9578a16bfb2#b3e532e9aad533009849755d5ad7b9578a16bfb2" +dependencies = [ + "ark-bn254", + "ark-ec", + "ark-ff 0.5.0", + "ark-poly", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "num-traits", + "sha2", + "thiserror 2.0.12", +] + +[[package]] +name = "rust-kzg-bn254-prover" +version = "0.1.0" +source = "git+https://github.com/Layr-Labs/rust-kzg-bn254?rev=b3e532e9aad533009849755d5ad7b9578a16bfb2#b3e532e9aad533009849755d5ad7b9578a16bfb2" +dependencies = [ + "ark-bn254", + "ark-ec", + "ark-ff 0.5.0", + "ark-poly", + "ark-std 0.5.0", + "crossbeam-channel", + "num-traits", + "num_cpus", + "rayon", + "rust-kzg-bn254-primitives", +] + [[package]] name = "rustc-demangle" version = "0.1.24" @@ -3784,9 +4379,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustc-hash" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fb8039b3032c191086b10f11f319a6e99e1e82889c5cc6046f515c9db1d497" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" [[package]] name = "rustc-hex" @@ -3809,29 +4404,30 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ - "semver 1.0.23", + "semver 1.0.26", ] [[package]] name = "rustix" -version = "0.38.41" +version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.0", "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] name = "rustls" -version = "0.23.19" +version = "0.23.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "934b404430bb06b3fae2cba809eb45a1ab1aecd64491213d7c3301b88393f8d1" +checksum = "47796c98c480fce5406ef69d1c76378375492c3b0a0de587be0c1d9feb12f395" dependencies = [ "once_cell", + "ring", "rustls-pki-types", "rustls-webpki", "subtle", @@ -3849,9 +4445,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" +checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" [[package]] name = "rustls-webpki" @@ -3866,9 +4462,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" +checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" [[package]] name = "rusty-fork" @@ -3884,9 +4480,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.18" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" [[package]] name = "same-file" @@ -3906,17 +4502,6 @@ dependencies = [ "windows-sys 0.59.0", ] -[[package]] -name = "schnellru" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9a8ef13a93c54d20580de1e5c413e624e53121d42fc7e2c11d10ef7f8b02367" -dependencies = [ - "ahash", - "cfg-if", - "hashbrown 0.13.2", -] - [[package]] name = "scopeguard" version = "1.2.0" @@ -3943,7 +4528,7 @@ version = "0.29.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113" dependencies = [ - "rand", + "rand 0.8.5", "secp256k1-sys", ] @@ -3962,7 +4547,7 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.0", "core-foundation", "core-foundation-sys", "libc", @@ -3971,9 +4556,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.12.1" +version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa39c7303dc58b5543c94d22c1766b0d31f2ee58306363ea622b10bbc075eaa2" +checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" dependencies = [ "core-foundation-sys", "libc", @@ -3990,9 +4575,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.23" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" +checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" [[package]] name = "semver-parser" @@ -4003,31 +4588,37 @@ dependencies = [ "pest", ] +[[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" +version = "1.0.218" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" +checksum = "e8dfc9d19bdbf6d17e22319da49161d5d0108e4188e8b680aef6299eed22df60" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.215" +version = "1.0.218" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" +checksum = "f09503e191f4e797cb8aac08e9a4a4695c5edf6a2e70e376d961ddd5c969f82b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.99", ] [[package]] name = "serde_json" -version = "1.0.133" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" +checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" dependencies = [ "indexmap", "itoa", @@ -4038,13 +4629,13 @@ dependencies = [ [[package]] name = "serde_repr" -version = "0.1.19" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" +checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.99", ] [[package]] @@ -4061,9 +4652,9 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.11.0" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817" +checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa" dependencies = [ "base64", "chrono", @@ -4077,14 +4668,25 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.11.0" +version = "3.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d846214a9854ef724f3da161b426242d8de7c1fc7de2f89bb1efcb154dca79d" +checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.99", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", ] [[package]] @@ -4149,7 +4751,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ "digest 0.10.7", - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -4169,13 +4771,19 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.13.2" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" +checksum = "7fcf8323ef1faaee30a44a340193b1ac6814fd9b7b4e88e9d4519a3e4abe1cfd" dependencies = [ "serde", ] +[[package]] +name = "snap" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b6b67fb9a61334225b5b790716f609cd58395f895b3fe8b328786812a40bc3b" + [[package]] name = "socket2" version = "0.5.8" @@ -4244,7 +4852,16 @@ version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" dependencies = [ - "strum_macros", + "strum_macros 0.26.4", +] + +[[package]] +name = "strum" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f64def088c51c9510a8579e3c5d67c65349dcf755e5479ad3d010aa6454e2c32" +dependencies = [ + "strum_macros 0.27.1", ] [[package]] @@ -4257,7 +4874,20 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.90", + "syn 2.0.99", +] + +[[package]] +name = "strum_macros" +version = "0.27.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c77a8c5abcaf0f9ce05d62342b7d298c346515365c36b673df4ebe3ced01fde8" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.99", ] [[package]] @@ -4269,7 +4899,7 @@ dependencies = [ "byteorder", "crunchy", "lazy_static", - "rand", + "rand 0.8.5", "rustc-hex", ] @@ -4281,9 +4911,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "symbolic-common" -version = "12.12.3" +version = "12.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ba5365997a4e375660bed52f5b42766475d5bc8ceb1bb13fea09c469ea0f49" +checksum = "b6189977df1d6ec30c920647919d76f29fb8d8f25e8952e835b0fcda25e8f792" dependencies = [ "debugid", "memmap2", @@ -4293,9 +4923,9 @@ dependencies = [ [[package]] name = "symbolic-demangle" -version = "12.12.3" +version = "12.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "beff338b2788519120f38c59ff4bb15174f52a183e547bac3d6072c2c0aa48aa" +checksum = "d234917f7986498e7f62061438cee724bafb483fe84cfbe2486f68dce48240d7" dependencies = [ "cpp_demangle", "rustc-demangle", @@ -4315,9 +4945,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.90" +version = "2.0.99" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" +checksum = "e02e925281e18ffd9d640e234264753c43edc62d64b2d4cf898f1bc5e75f3fc2" dependencies = [ "proc-macro2", "quote", @@ -4326,22 +4956,16 @@ dependencies = [ [[package]] name = "syn-solidity" -version = "0.8.15" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "219389c1ebe89f8333df8bdfb871f6631c552ff399c23cac02480b6088aad8f0" +checksum = "ac9f9798a84bca5cd4d1760db691075fda8f2c3a5d9647e8bfd29eb9b3fabb87" dependencies = [ "paste", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.99", ] -[[package]] -name = "sync_wrapper" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" - [[package]] name = "sync_wrapper" version = "1.0.2" @@ -4359,7 +4983,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.99", ] [[package]] @@ -4368,7 +4992,7 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ - "bitflags 2.6.0", + "bitflags 2.9.0", "core-foundation", "system-configuration-sys", ] @@ -4391,12 +5015,13 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.14.0" +version = "3.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" +checksum = "22e5a0acb1f3f55f65cc4a866c361b2fb2a0ff6366785ae6fbb5f85df07ba230" dependencies = [ "cfg-if", "fastrand", + "getrandom 0.3.1", "once_cell", "rustix", "windows-sys 0.59.0", @@ -4413,11 +5038,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.4" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f49a1853cf82743e3b7950f77e0f4d622ca36cf4317cba00c767838bac8d490" +checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" dependencies = [ - "thiserror-impl 2.0.4", + "thiserror-impl 2.0.12", ] [[package]] @@ -4428,18 +5053,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.99", ] [[package]] name = "thiserror-impl" -version = "2.0.4" +version = "2.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8381894bb3efe0c4acac3ded651301ceee58a15d47c2e34885ed1908ad667061" +checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.99", ] [[package]] @@ -4511,9 +5136,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" dependencies = [ "tinyvec_macros", ] @@ -4526,9 +5151,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.42.0" +version = "1.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551" +checksum = "3d61fa4ffa3de412bfea335c6ecff681de2b609ba3c77ef3e00e521813a9ed9e" dependencies = [ "backtrace", "bytes", @@ -4544,13 +5169,13 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" +checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.99", ] [[package]] @@ -4565,20 +5190,19 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.26.0" +version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c7bc40d0e5a97695bb96e27995cd3a08538541b0a846f65bba7a359f36700d4" +checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" dependencies = [ "rustls", - "rustls-pki-types", "tokio", ] [[package]] name = "tokio-stream" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f4e6ce100d0eb49a2734f8c0812bcd324cf357d21810932c5df6b96ef2b86f1" +checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" dependencies = [ "futures-core", "pin-project-lite", @@ -4586,6 +5210,22 @@ dependencies = [ "tokio-util", ] +[[package]] +name = "tokio-tungstenite" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a9daff607c6d2bf6c16fd681ccb7eecc83e4e2cdc1ca067ffaadfca5de7f084" +dependencies = [ + "futures-util", + "log", + "rustls", + "rustls-pki-types", + "tokio", + "tokio-rustls", + "tungstenite", + "webpki-roots", +] + [[package]] name = "tokio-util" version = "0.7.13" @@ -4607,9 +5247,9 @@ checksum = "0dd7358ecb8fc2f8d014bf86f6f638ce72ba252a2c3a2572f2a795f1d23efb41" [[package]] name = "toml_edit" -version = "0.22.22" +version = "0.22.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" dependencies = [ "indexmap", "toml_datetime", @@ -4618,14 +5258,15 @@ dependencies = [ [[package]] name = "tower" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2873938d487c3cfb9aed7546dc9f2711d867c9f90c46b889989a2cb84eba6b4f" +checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" dependencies = [ "futures-core", "futures-util", "pin-project-lite", - "sync_wrapper 0.1.2", + "sync_wrapper", + "tokio", "tower-layer", "tower-service", ] @@ -4661,7 +5302,7 @@ checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.99", ] [[package]] @@ -4705,11 +5346,30 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "tungstenite" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4793cb5e56680ecbb1d843515b23b6de9a75eb04b66643e256a396d43be33c13" +dependencies = [ + "bytes", + "data-encoding", + "http", + "httparse", + "log", + "rand 0.9.0", + "rustls", + "rustls-pki-types", + "sha1", + "thiserror 2.0.12", + "utf-8", +] + [[package]] name = "typenum" -version = "1.17.0" +version = "1.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" [[package]] name = "ucd-trie" @@ -4737,9 +5397,9 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicode-ident" -version = "1.0.14" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "unicode-xid" @@ -4770,6 +5430,12 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + [[package]] name = "utf16_iter" version = "1.0.5" @@ -4790,15 +5456,15 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.11.0" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" +checksum = "e0f540e3240398cce6128b64ba83fdbdd86129c16a3aa1a3a252efd66eb3d587" [[package]] name = "valuable" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" [[package]] name = "vcpkg" @@ -4814,9 +5480,9 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "wait-timeout" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +checksum = "09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11" dependencies = [ "libc", ] @@ -4846,37 +5512,46 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasi" +version = "0.13.3+wasi-0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +dependencies = [ + "wit-bindgen-rt", +] + [[package]] name = "wasm-bindgen" -version = "0.2.97" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d15e63b4482863c109d70a7b8706c1e364eb6ea449b201a76c5b89cedcec2d5c" +checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" dependencies = [ "cfg-if", "once_cell", + "rustversion", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.97" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d36ef12e3aaca16ddd3f67922bc63e48e953f126de60bd33ccc0101ef9998cd" +checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" dependencies = [ "bumpalo", "log", - "once_cell", "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.99", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.47" +version = "0.4.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dfaf8f50e5f293737ee323940c7d8b08a66a95a419223d9f41610ca08b0833d" +checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" dependencies = [ "cfg-if", "js-sys", @@ -4887,9 +5562,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.97" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "705440e08b42d3e4b36de7d66c944be628d579796b8090bfa3471478a2260051" +checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4897,22 +5572,25 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.97" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98c9ae5a76e46f4deecd0f0255cc223cfa18dc9b261213b8aa0c7b36f61b3f1d" +checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.99", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.97" +version = "0.2.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ee99da9c5ba11bd675621338ef6fa52296b76b83305e9b6e5c77d4c286d6d49" +checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +dependencies = [ + "unicode-ident", +] [[package]] name = "wasmtimer" @@ -4930,14 +5608,29 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.74" +version = "0.3.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a98bc3c33f0fe7e59ad7cd041b89034fa82a7c2d4365ca538dda6cdaf513863c" +checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" dependencies = [ "js-sys", "wasm-bindgen", ] +[[package]] +name = "webpki-roots" +version = "0.26.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2210b291f7ea53617fbafcc4939f10914214ec15aace5ba62293a668f322c5c9" +dependencies = [ + "rustls-pki-types", +] + +[[package]] +name = "widestring" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311" + [[package]] name = "winapi" version = "0.3.9" @@ -5083,13 +5776,22 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.6.20" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36c1fec1a2bb5866f07c25f68c26e565c4c200aebb96d7e55710c19d3e8ac49b" +checksum = "0e7f4ea97f6f78012141bcdb6a216b2609f0979ada50b20ca5b52dde2eac2bb1" dependencies = [ "memchr", ] +[[package]] +name = "wit-bindgen-rt" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" +dependencies = [ + "bitflags 2.9.0", +] + [[package]] name = "write16" version = "1.0.0" @@ -5102,6 +5804,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", + "thiserror 1.0.69", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + [[package]] name = "wyz" version = "0.5.1" @@ -5131,7 +5852,7 @@ checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.99", "synstructure", ] @@ -5142,7 +5863,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" dependencies = [ "byteorder", - "zerocopy-derive", + "zerocopy-derive 0.7.35", +] + +[[package]] +name = "zerocopy" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf01143b2dd5d134f11f545cf9f1431b13b749695cb33bcce051e7568f99478" +dependencies = [ + "zerocopy-derive 0.8.21", ] [[package]] @@ -5153,27 +5883,38 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.99", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712c8386f4f4299382c9abee219bee7084f78fb939d88b6840fcc1320d5f6da2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.99", ] [[package]] name = "zerofrom" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.99", "synstructure", ] @@ -5194,7 +5935,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.99", ] [[package]] @@ -5216,5 +5957,5 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.90", + "syn 2.0.99", ] diff --git a/Cargo.toml b/Cargo.toml index 61fbd43d98..1db8929a36 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,21 +3,21 @@ edition = "2021" license = "MIT" rust-version = "1.81" authors = ["clabby", "refcell"] -homepage = "https://github.com/anton-rs/kona" -repository = "https://github.com/anton-rs/kona" +homepage = "https://github.com/op-rs/kona" +repository = "https://github.com/op-rs/kona" keywords = ["ethereum", "optimism", "crypto"] categories = ["cryptography", "cryptography::cryptocurrencies"] exclude = ["**/target"] [workspace] members = [ - "crates/derive", - "crates/driver", - "crates/executor", - "crates/mpt", - "crates/proof-sdk/*", - "bin/*" -] + "crates/derive", + "crates/driver", + "crates/executor", + "crates/mpt", + "crates/providers-alloy", + "crates/proof-sdk/*", + "bin/*", "crates/eigen-da", ] default-members = ["bin/host", "bin/client"] # Explicitly set the resolver to version 2, which is the default for packages with edition >= 2021 @@ -62,75 +62,108 @@ lto = "fat" [workspace.dependencies] # Workspace -kona-mpt = { path = "crates/mpt", version = "0.1.1", default-features = false } +kona-host = { path = "bin/host", version = "0.1.0", default-features = false } kona-client = { path = "bin/client", version = "0.1.0", default-features = false } -kona-derive = { path = "crates/derive", version = "0.2.0", default-features = false } -kona-driver = { path = "crates/driver", version = "0.2.0", default-features = false } +kona-mpt = { path = "crates/mpt", version = "0.1.1", default-features = false } +kona-derive = { path = "crates/derive", version = "0.2.3", default-features = false } +kona-driver = { path = "crates/driver", version = "0.2.3", default-features = false } +kona-providers-alloy = { path = "crates/providers-alloy", version = "0.1.0", default-features = false } kona-executor = { path = "crates/executor", version = "0.2.0", default-features = false } -kona-proof = { path = "crates/proof-sdk/proof", version = "0.2.0", default-features = false } +kona-proof = { path = "crates/proof-sdk/proof", version = "0.2.3", default-features = false } kona-std-fpvm = { path = "crates/proof-sdk/std-fpvm", version = "0.1.1", default-features = false } kona-preimage = { path = "crates/proof-sdk/preimage", version = "0.2.0", default-features = false } kona-std-fpvm-proc = { path = "crates/proof-sdk/std-fpvm-proc", version = "0.1.1", default-features = false } +eigen-da = { path = "crates/eigen-da" , version = "0.1.0", default-features = false } + # Alloy -alloy-rlp = { version = "0.3.9", default-features = false } -alloy-trie = { version = "0.7.4", default-features = false } -alloy-eips = { version = "0.8.0", default-features = false } -alloy-serde = { version = "0.8.0", default-features = false } -alloy-provider = { version = "0.8.0", default-features = false } -alloy-consensus = { version = "0.8.0", default-features = false } -alloy-transport = { version = "0.8.0", default-features = false } -alloy-rpc-types = { version = "0.8.0", default-features = false } -alloy-rpc-client = { version = "0.8.0", default-features = false } -alloy-primitives = { version = "0.8.14", default-features = false } -alloy-node-bindings = { version = "0.8.0", default-features = false } -alloy-transport-http = { version = "0.8.0", default-features = false } -alloy-rpc-types-engine = { version = "0.8.0", default-features = false } -alloy-rpc-types-beacon = { version = "0.8.0", default-features = false } +alloy-rlp = { version = "0.3.11", default-features = false } +alloy-trie = { version = "0.7.9", default-features = false } +alloy-eips = { version = "0.11.1", default-features = false } +alloy-serde = { version = "0.11.1", default-features = false } +alloy-provider = { version = "0.11.1", default-features = false } +alloy-consensus = { version = "0.11.1", default-features = false } +alloy-transport = { version = "0.11.1", default-features = false } +alloy-rpc-types = { version = "0.11.1", default-features = false } +alloy-rpc-client = { version = "0.11.1", default-features = false } +alloy-primitives = { version = "0.8.21", default-features = false } +alloy-node-bindings = { version = "0.11.1", default-features = false } +alloy-transport-http = { version = "0.11.1", default-features = false } +alloy-rpc-types-engine = { version = "0.11.1", default-features = false } +alloy-rpc-types-beacon = { version = "0.11.1", default-features = false } +alloy-sol-types = { version = "0.8.19", default-features = false } # OP Alloy -op-alloy-genesis = { version = "0.8.2", default-features = false } -op-alloy-registry = { version = "0.8.2", default-features = false } -op-alloy-protocol = { version = "0.8.2", default-features = false } -op-alloy-consensus = { version = "0.8.2", default-features = false } -op-alloy-rpc-types-engine = { version = "0.8.2", default-features = false } +#op-alloy-genesis = { version = "0.5.2", default-features = false } +#op-alloy-protocol = { version = "0.5.2", default-features = false } +#op-alloy-consensus = { version = "0.5.2", default-features = false } +#op-alloy-rpc-types-engine = { version = "0.5.2", default-features = false } + +# Mantle Alloy +op-alloy-genesis = { git = "https://github.com/mantle-xyz/op-alloy", branch = "alloy-0.11.1" } +op-alloy-protocol = { git = "https://github.com/mantle-xyz/op-alloy", branch = "alloy-0.11.1" } +op-alloy-consensus = { git = "https://github.com/mantle-xyz/op-alloy", branch = "alloy-0.11.1" } +op-alloy-rpc-types-engine = { git = "https://github.com/mantle-xyz/op-alloy", branch = "alloy-0.11.1" } +op-alloy-network = { git = "https://github.com/mantle-xyz/op-alloy", branch = "alloy-0.11.1" } + + + # General -lru = "0.12.4" +lru = "0.12.5" spin = "0.9.8" rand = "0.8.5" -clap = "4.5.19" +clap = "4.5.24" tokio = "1.42.0" async-channel = "2.3.1" cfg-if = "1.0.0" -reqwest = "0.12.9" -async-trait = "0.1.83" +reqwest = "0.12.12" +async-trait = "0.1.85" linked_list_allocator = "0.10.5" +rstest = "0.24.0" # General sha2 = { version = "0.10.8", default-features = false } c-kzg = { version = "2.0.0", default-features = false } -anyhow = { version = "1.0.93", default-features = false } -thiserror = { version = "2.0.4", default-features = false } +anyhow = { version = "1.0.95", default-features = false } +thiserror = { version = "2.0.9", default-features = false } # Tracing tracing-loki = "0.2.5" tracing-subscriber = "0.3.19" tracing = { version = "0.1.41", default-features = false } +# Encoding +miniz_oxide = "0.8.0" +brotli = { version = "7.0.0", default-features = false } + # Testing pprof = "0.14.0" -proptest = "1.5.0" +proptest = "1.6.0" criterion = "0.5.1" # Serialization rkyv = "0.8.9" -serde = { version = "1.0.215", default-features = false } -serde_json = { version = "1.0.133", default-features = false } +serde = { version = "1.0.217", default-features = false } +serde_json = { version = "1.0.135", default-features = false } # Ethereum unsigned-varint = "0.8.0" -revm = { version = "16.0.0", default-features = false } +revm = { git = "https://github.com/mantle-xyz/revm", branch = "dev", default-features = false } # K/V database rocksdb = { version = "0.22.0", default-features = false } + +# proto +prost = "0.13.3" +bytes = "1.8.0" +hex = "0.4.3" +rlp = "0.6.1" + +#eigenlayer +rust-kzg-bn254-primitives = { git = "https://github.com/Layr-Labs/rust-kzg-bn254", rev = "b3e532e9aad533009849755d5ad7b9578a16bfb2", default-features = false } +rust-kzg-bn254-prover = { git = "https://github.com/Layr-Labs/rust-kzg-bn254", rev = "b3e532e9aad533009849755d5ad7b9578a16bfb2", default-features = false } + +ark-bn254 = "0.5.0" +ark-ff = { version = "0.5.0", features = ["parallel"] } +num = "0.4" diff --git a/README.md b/README.md index adf8a1d749..4a0d9d55b9 100644 --- a/README.md +++ b/README.md @@ -7,17 +7,17 @@

- CI - License - Book + CI + License + Book OP Stack - Codecov + Codecov

What's Kona?Overview • - Contributing • + ContributingCredits

@@ -37,7 +37,7 @@ program! Kona is also used by: - [`op-succinct`][op-succinct] To build your own backend for kona, or build a new application on top of its libraries, -see the [SDK section of the book](https://anton-rs.github.io/kona/sdk/intro.html). +see the [SDK section of the book](https://op-rs.github.io/kona/sdk/intro.html). ### Development Status @@ -53,7 +53,8 @@ see the [SDK section of the book](https://anton-rs.github.io/kona/sdk/intro.html **Build Pipelines** - [`cannon`](./build/cannon): Docker image for compiling to the bare-metal `mips-unknown-none` target. -- [`asterisc`](./build/asterisc): Docker image for compiling to the bare-metal `riscv64gc-unknown-none-elf` target. +- [`asterisc`](./build/asterisc): Docker image for compiling to the bare-metal `riscv64imac-unknown-none-elf` target. + **Protocol** - [`mpt`](./crates/mpt): Utilities for interacting with the Merkle Patricia Trie in the client program. @@ -83,11 +84,11 @@ getting started with building your own programs, and a reference for the librari [op-stack]: https://github.com/ethereum-optimism/optimism [op-program]: https://github.com/ethereum-optimism/optimism/tree/develop/op-program [cannon]: https://github.com/ethereum-optimism/optimism/tree/develop/cannon -[cannon-rs]: https://github.com/anton-rs/cannon-rs +[cannon-rs]: https://github.com/op-rs/cannon-rs [badboi-cannon-rs]: https://github.com/BadBoiLabs/cannon-rs [asterisc]: https://github.com/etheruem-optimism/asterisc [fpp-specs]: https://specs.optimism.io/experimental/fault-proof/index.html -[book]: https://anton-rs.github.io/kona/ +[book]: https://op-rs.github.io/kona/ [op-succinct]: https://github.com/succinctlabs/op-succinct [op-labs]: https://github.com/ethereum-optimism [bad-boi-labs]: https://github.com/BadBoiLabs diff --git a/bin/client/justfile b/bin/client/justfile index 5bd260a295..4964c3aa99 100644 --- a/bin/client/justfile +++ b/bin/client/justfile @@ -14,7 +14,7 @@ run-client-asterisc block_number l1_rpc l1_beacon_rpc l2_rpc rollup_node_rpc ver OP_NODE_ADDRESS="{{rollup_node_rpc}}" HOST_BIN_PATH="./target/release/kona-host" - CLIENT_BIN_PATH="./target/riscv64gc-unknown-none-elf/release-client-lto/kona" + CLIENT_BIN_PATH="./target/riscv64imac-unknown-none-elf/release-client-lto/kona" STATE_PATH="./state.bin.gz" CLAIMED_L2_BLOCK_NUMBER={{block_number}} @@ -140,7 +140,7 @@ run-client-asterisc-offline block_number l2_claim l2_output_root l2_head l1_head #!/usr/bin/env bash HOST_BIN_PATH="./target/release/kona-host" - CLIENT_BIN_PATH="./target/riscv64gc-unknown-none-elf/release-client-lto/kona" + CLIENT_BIN_PATH="./target/riscv64imac-unknown-none-elf/release-client-lto/kona" STATE_PATH="./state.bin.gz" CLAIMED_L2_BLOCK_NUMBER={{block_number}} diff --git a/bin/client/src/kona.rs b/bin/client/src/kona.rs index cf166c1424..2e91cd30e4 100644 --- a/bin/client/src/kona.rs +++ b/bin/client/src/kona.rs @@ -39,7 +39,7 @@ fn main() -> Result<(), String> { .expect("Failed to set tracing subscriber"); } - kona_proof::block_on(kona_client::run( + kona_proof::block_on(kona_client::single::run( ORACLE_READER, HINT_WRITER, Some(precompiles::fpvm_handle_register), diff --git a/bin/client/src/lib.rs b/bin/client/src/lib.rs index 83c4c70cd3..c15be9de25 100644 --- a/bin/client/src/lib.rs +++ b/bin/client/src/lib.rs @@ -7,173 +7,4 @@ extern crate alloc; -use alloc::sync::Arc; -use alloy_consensus::{Header, Sealed}; -use alloy_primitives::B256; -use core::fmt::Debug; -use kona_driver::{Driver, DriverError}; -use kona_executor::{ExecutorError, KonaHandleRegister, TrieDBProvider}; -use kona_preimage::{ - CommsClient, HintWriterClient, PreimageKey, PreimageKeyType, PreimageOracleClient, -}; -use kona_proof::{ - errors::OracleProviderError, - executor::KonaExecutor, - l1::{OracleBlobProvider, OracleL1ChainProvider, OraclePipeline}, - l2::OracleL2ChainProvider, - sync::new_pipeline_cursor, - BootInfo, CachingOracle, HintType, -}; -use thiserror::Error; -use tracing::{error, info, warn}; - -/// An error that can occur when running the fault proof program. -#[derive(Error, Debug)] -pub enum FaultProofProgramError { - /// The claim is invalid. - #[error("Invalid claim. Expected {0}, actual {1}")] - InvalidClaim(B256, B256), - /// An error occurred in the Oracle provider. - #[error(transparent)] - OracleProviderError(#[from] OracleProviderError), - /// An error occurred in the driver. - #[error(transparent)] - Driver(#[from] DriverError), -} - -/// Executes the fault proof program with the given [PreimageOracleClient] and [HintWriterClient]. -#[inline] -pub async fn run( - oracle_client: P, - hint_client: H, - handle_register: Option< - KonaHandleRegister< - OracleL2ChainProvider>, - OracleL2ChainProvider>, - >, - >, -) -> Result<(), FaultProofProgramError> -where - P: PreimageOracleClient + Send + Sync + Debug + Clone, - H: HintWriterClient + Send + Sync + Debug + Clone, -{ - const ORACLE_LRU_SIZE: usize = 1024; - - //////////////////////////////////////////////////////////////// - // PROLOGUE // - //////////////////////////////////////////////////////////////// - - let oracle = Arc::new(CachingOracle::new(ORACLE_LRU_SIZE, oracle_client, hint_client)); - let boot = match BootInfo::load(oracle.as_ref()).await { - Ok(boot) => Arc::new(boot), - Err(e) => { - error!(target: "client", "Failed to load boot info: {:?}", e); - return Err(e.into()); - } - }; - let mut l1_provider = OracleL1ChainProvider::new(boot.clone(), oracle.clone()); - let mut l2_provider = OracleL2ChainProvider::new(boot.clone(), oracle.clone()); - let beacon = OracleBlobProvider::new(oracle.clone()); - - // If the claimed L2 block number is less than the safe head of the L2 chain, the claim is - // invalid. - let safe_head = fetch_safe_head(oracle.as_ref(), boot.as_ref(), &mut l2_provider).await?; - if boot.claimed_l2_block_number < safe_head.number { - error!( - target: "client", - "Claimed L2 block number {claimed} is less than the safe head {safe}", - claimed = boot.claimed_l2_block_number, - safe = safe_head.number - ); - return Err(FaultProofProgramError::InvalidClaim( - boot.agreed_l2_output_root, - boot.claimed_l2_output_root, - )); - } - - // In the case where the agreed upon L2 output root is the same as the claimed L2 output root, - // trace extension is detected and we can skip the derivation and execution steps. - if boot.agreed_l2_output_root == boot.claimed_l2_output_root { - info!( - target: "client", - "Trace extension detected. State transition is already agreed upon.", - ); - return Ok(()); - } - - //////////////////////////////////////////////////////////////// - // DERIVATION & EXECUTION // - //////////////////////////////////////////////////////////////// - - // Create a new derivation driver with the given boot information and oracle. - let cursor = new_pipeline_cursor(&boot, safe_head, &mut l1_provider, &mut l2_provider).await?; - let cfg = Arc::new(boot.rollup_config.clone()); - let pipeline = OraclePipeline::new( - cfg.clone(), - cursor.clone(), - oracle.clone(), - beacon, - l1_provider.clone(), - l2_provider.clone(), - ); - let executor = KonaExecutor::new(&cfg, l2_provider.clone(), l2_provider, handle_register, None); - let mut driver = Driver::new(cursor, executor, pipeline); - - // Run the derivation pipeline until we are able to produce the output root of the claimed - // L2 block. - let (number, output_root) = - driver.advance_to_target(&boot.rollup_config, Some(boot.claimed_l2_block_number)).await?; - - //////////////////////////////////////////////////////////////// - // EPILOGUE // - //////////////////////////////////////////////////////////////// - - if output_root != boot.claimed_l2_output_root { - error!( - target: "client", - "Failed to validate L2 block #{number} with output root {output_root}", - number = number, - output_root = output_root - ); - return Err(FaultProofProgramError::InvalidClaim(output_root, boot.claimed_l2_output_root)); - } - - info!( - target: "client", - "Successfully validated L2 block #{number} with output root {output_root}", - number = number, - output_root = output_root - ); - - Ok(()) -} - -/// Fetches the safe head of the L2 chain based on the agreed upon L2 output root in the -/// [BootInfo]. -async fn fetch_safe_head( - caching_oracle: &O, - boot_info: &BootInfo, - l2_chain_provider: &mut OracleL2ChainProvider, -) -> Result, OracleProviderError> -where - O: CommsClient, -{ - caching_oracle - .write(&HintType::StartingL2Output.encode_with(&[boot_info.agreed_l2_output_root.as_ref()])) - .await - .map_err(OracleProviderError::Preimage)?; - let mut output_preimage = [0u8; 128]; - caching_oracle - .get_exact( - PreimageKey::new(*boot_info.agreed_l2_output_root, PreimageKeyType::Keccak256), - &mut output_preimage, - ) - .await - .map_err(OracleProviderError::Preimage)?; - - let safe_hash = - output_preimage[96..128].try_into().map_err(OracleProviderError::SliceConversion)?; - l2_chain_provider - .header_by_hash(safe_hash) - .map(|header| Sealed::new_unchecked(header, safe_hash)) -} +pub mod single; diff --git a/bin/client/src/precompiles/bls12_g1_add.rs b/bin/client/src/precompiles/bls12_g1_add.rs new file mode 100644 index 0000000000..17ee6d3f13 --- /dev/null +++ b/bin/client/src/precompiles/bls12_g1_add.rs @@ -0,0 +1,81 @@ +//! Contains the accelerated precompile for the BLS12-381 curve G1 Point Addition. +//! +//! BLS12-381 is introduced in [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537). +//! +//! For constants and logic, see the [revm implementation]. +//! +//! [revm implementation]: https://github.com/bluealloy/revm/blob/main/crates/precompile/src/bls12_381/g1_add.rs + +use crate::precompiles::utils::precompile_run; +use alloc::{string::ToString, vec::Vec}; +use alloy_primitives::{address, keccak256, Address, Bytes}; +use revm::{ + precompile::{Error as PrecompileError, Precompile, PrecompileResult, PrecompileWithAddress}, + primitives::PrecompileOutput, +}; + +/// The address of the BLS12-381 g1 addition check precompile. +/// +/// See: +const BLS12_G1_ADD_CHECK: Address = address!("0x000000000000000000000000000000000000000b"); + +/// Input length of G1 Addition operation. +const INPUT_LENGTH: usize = 256; + +/// Base gas fee for the BLS12-381 g1 addition operation. +const G1_ADD_BASE_FEE: u64 = 375; + +/// The address of the BLS12-381 g1 addition precompile. +pub(crate) const FPVM_BLS12_G1_ADD_ISTHMUS: PrecompileWithAddress = + PrecompileWithAddress(BLS12_G1_ADD_CHECK, Precompile::Standard(fpvm_bls12_g1_add)); + +/// Performs an FPVM-accelerated BLS12-381 G1 addition check. +/// +/// Notice, there is no input size limit for this precompile. +/// See: +fn fpvm_bls12_g1_add(input: &Bytes, gas_limit: u64) -> PrecompileResult { + if G1_ADD_BASE_FEE > gas_limit { + return Err(PrecompileError::OutOfGas.into()); + } + + let input_len = input.len(); + if input_len != INPUT_LENGTH { + return Err(PrecompileError::Other(alloc::format!( + "G1 addition input length should be multiple of {INPUT_LENGTH}, was {input_len}" + )) + .into()); + } + + let result_data = kona_proof::block_on(precompile_run! { + &[BLS12_G1_ADD_CHECK.as_ref(), input.as_ref()] + }) + .map_err(|e| PrecompileError::Other(e.to_string()))?; + + Ok(PrecompileOutput::new(G1_ADD_BASE_FEE, result_data.into())) +} + +#[cfg(test)] +mod tests { + use super::*; + use alloc::vec; + + #[test] + fn test_fpvm_bls12_g1_add_input_len() { + let input = Bytes::from(vec![0u8; INPUT_LENGTH + 1]); + let err = PrecompileError::Other(alloc::format!( + "G1 addition input length should be multiple of {}, was {}", + INPUT_LENGTH, + INPUT_LENGTH + 1 + )); + assert_eq!(fpvm_bls12_g1_add(&input, G1_ADD_BASE_FEE), Err(err.into())); + } + + #[test] + fn test_fpvm_bls12_g1_add_out_of_gas() { + let input = Bytes::from(vec![0u8; INPUT_LENGTH * 2]); + assert_eq!( + fpvm_bls12_g1_add(&input, G1_ADD_BASE_FEE - 1), + Err(PrecompileError::OutOfGas.into()) + ); + } +} diff --git a/bin/client/src/precompiles/bls12_g1_msm.rs b/bin/client/src/precompiles/bls12_g1_msm.rs new file mode 100644 index 0000000000..db8106a387 --- /dev/null +++ b/bin/client/src/precompiles/bls12_g1_msm.rs @@ -0,0 +1,122 @@ +//! Contains the accelerated precompile for the BLS12-381 curve G1 MSM. +//! +//! BLS12-381 is introduced in [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537). +//! +//! For constants and logic, see the [revm implementation]. +//! +//! [revm implementation]: https://github.com/bluealloy/revm/blob/main/crates/precompile/src/bls12_381/g1_msm.rs + +use crate::precompiles::utils::{msm_required_gas, precompile_run}; +use alloc::{string::ToString, vec::Vec}; +use alloy_primitives::{address, keccak256, Address, Bytes}; +use revm::{ + precompile::{Error as PrecompileError, Precompile, PrecompileResult, PrecompileWithAddress}, + primitives::PrecompileOutput, +}; + +/// The maximum input size for the BLS12-381 g1 msm operation after the Isthmus Hardfork. +/// +/// See: +const BLS12_MAX_G1_MSM_SIZE_ISTHMUS: usize = 513760; + +/// The address of the BLS12-381 g1 msm check precompile. +/// +/// See: +const BLS12_G1_MSM_CHECK: Address = address!("0x000000000000000000000000000000000000000c"); + +/// Input length of g1 msm operation. +const INPUT_LENGTH: usize = 160; + +/// Base gas fee for the BLS12-381 g1 msm operation. +const G1_MSM_BASE_FEE: u64 = 12000; + +/// The address of the BLS12-381 g1 msm precompile. +pub(crate) const FPVM_BLS12_G1_MSM_ISTHMUS: PrecompileWithAddress = + PrecompileWithAddress(BLS12_G1_MSM_CHECK, Precompile::Standard(fpvm_bls12_g1_msm_isthmus)); + +/// Discounts table for G1 MSM as a vector of pairs `[k, discount]`. +static DISCOUNT_TABLE: [u16; 128] = [ + 1000, 949, 848, 797, 764, 750, 738, 728, 719, 712, 705, 698, 692, 687, 682, 677, 673, 669, 665, + 661, 658, 654, 651, 648, 645, 642, 640, 637, 635, 632, 630, 627, 625, 623, 621, 619, 617, 615, + 613, 611, 609, 608, 606, 604, 603, 601, 599, 598, 596, 595, 593, 592, 591, 589, 588, 586, 585, + 584, 582, 581, 580, 579, 577, 576, 575, 574, 573, 572, 570, 569, 568, 567, 566, 565, 564, 563, + 562, 561, 560, 559, 558, 557, 556, 555, 554, 553, 552, 551, 550, 549, 548, 547, 547, 546, 545, + 544, 543, 542, 541, 540, 540, 539, 538, 537, 536, 536, 535, 534, 533, 532, 532, 531, 530, 529, + 528, 528, 527, 526, 525, 525, 524, 523, 522, 522, 521, 520, 520, 519, +]; + +/// Performs an FPVM-accelerated BLS12-381 G1 msm check. +fn fpvm_bls12_g1_msm(input: &Bytes, gas_limit: u64) -> PrecompileResult { + let input_len = input.len(); + if input_len == 0 || input_len % INPUT_LENGTH != 0 { + return Err(PrecompileError::Other(alloc::format!( + "G1MSM input length should be multiple of {}, was {}", + INPUT_LENGTH, + input_len + )) + .into()); + } + + let k = input_len / INPUT_LENGTH; + let required_gas = msm_required_gas(k, &DISCOUNT_TABLE, G1_MSM_BASE_FEE); + if required_gas > gas_limit { + return Err(PrecompileError::OutOfGas.into()); + } + + let result_data = kona_proof::block_on(precompile_run! { + &[BLS12_G1_MSM_CHECK.as_ref(), input.as_ref()] + }) + .map_err(|e| PrecompileError::Other(e.to_string()))?; + + Ok(PrecompileOutput::new(G1_MSM_BASE_FEE, result_data.into())) +} + +/// Performs an FPVM-accelerated `bls12` g1 msm check precompile call +/// after the Isthmus Hardfork. +fn fpvm_bls12_g1_msm_isthmus(input: &Bytes, gas_limit: u64) -> PrecompileResult { + if input.len() > BLS12_MAX_G1_MSM_SIZE_ISTHMUS { + return Err(PrecompileError::Other(alloc::format!( + "G1MSM input length must be at most {}", + BLS12_MAX_G1_MSM_SIZE_ISTHMUS + )) + .into()); + } + + fpvm_bls12_g1_msm(input, gas_limit) +} + +#[cfg(test)] +mod tests { + use super::*; + use alloc::vec; + + #[test] + fn test_fpvm_bls12_g1_msm_isthmus_max_bytes() { + let input = Bytes::from(vec![0u8; BLS12_MAX_G1_MSM_SIZE_ISTHMUS + 1]); + let gas_limit = G1_MSM_BASE_FEE; + let err = PrecompileError::Other(alloc::format!( + "G1MSM input length must be at most {}", + BLS12_MAX_G1_MSM_SIZE_ISTHMUS + )); + assert_eq!(fpvm_bls12_g1_msm_isthmus(&input, gas_limit), Err(err.into())); + } + + #[test] + fn test_fpvm_bls12_g1_msm_offset() { + let input = Bytes::from(vec![0u8; INPUT_LENGTH + 1]); + let gas_limit = G1_MSM_BASE_FEE; + let err = PrecompileError::Other(alloc::format!( + "G1MSM input length should be multiple of {}, was {}", + INPUT_LENGTH, + input.len(), + )); + assert_eq!(fpvm_bls12_g1_msm(&input, gas_limit), Err(err.into())); + } + + #[test] + fn test_fpvm_bls12_g1_msm_out_of_gas() { + let input = Bytes::from(vec![0u8; INPUT_LENGTH * 2]); + let gas_limit = G1_MSM_BASE_FEE - 1; + assert_eq!(fpvm_bls12_g1_msm(&input, gas_limit), Err(PrecompileError::OutOfGas.into())); + } +} diff --git a/bin/client/src/precompiles/bls12_g2_add.rs b/bin/client/src/precompiles/bls12_g2_add.rs new file mode 100644 index 0000000000..b6dfdc5a83 --- /dev/null +++ b/bin/client/src/precompiles/bls12_g2_add.rs @@ -0,0 +1,81 @@ +//! Contains the accelerated precompile for the BLS12-381 curve G2 Point Addition. +//! +//! BLS12-381 is introduced in [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537). +//! +//! For constants and logic, see the [revm implementation]. +//! +//! [revm implementation]: https://github.com/bluealloy/revm/blob/main/crates/precompile/src/bls12_381/g2_add.rs + +use crate::precompiles::utils::precompile_run; +use alloc::{string::ToString, vec::Vec}; +use alloy_primitives::{address, keccak256, Address, Bytes}; +use revm::{ + precompile::{Error as PrecompileError, Precompile, PrecompileResult, PrecompileWithAddress}, + primitives::PrecompileOutput, +}; + +/// The address of the BLS12-381 g2 addition check precompile. +/// +/// See: +const BLS12_G2_ADD_CHECK: Address = address!("0x000000000000000000000000000000000000000d"); + +/// Input length of g2 addition operation. +const INPUT_LENGTH: usize = 512; + +/// Base gas fee for the BLS12-381 g2 addition operation. +const G2_ADD_BASE_FEE: u64 = 600; + +/// The address of the BLS12-381 g2 addition precompile. +pub(crate) const FPVM_BLS12_G2_ADD_ISTHMUS: PrecompileWithAddress = + PrecompileWithAddress(BLS12_G2_ADD_CHECK, Precompile::Standard(fpvm_bls12_g2_add)); + +/// Performs an FPVM-accelerated BLS12-381 G2 addition check. +/// +/// Notice, there is no input size limit for this precompile. +/// See: +fn fpvm_bls12_g2_add(input: &Bytes, gas_limit: u64) -> PrecompileResult { + if G2_ADD_BASE_FEE > gas_limit { + return Err(PrecompileError::OutOfGas.into()); + } + + let input_len = input.len(); + if input_len != INPUT_LENGTH { + return Err(PrecompileError::Other(alloc::format!( + "G2 addition input length should be multiple of {INPUT_LENGTH}, was {input_len}" + )) + .into()); + } + + let result_data = kona_proof::block_on(precompile_run! { + &[BLS12_G2_ADD_CHECK.as_ref(), input.as_ref()] + }) + .map_err(|e| PrecompileError::Other(e.to_string()))?; + + Ok(PrecompileOutput::new(G2_ADD_BASE_FEE, result_data.into())) +} + +#[cfg(test)] +mod tests { + use super::*; + use alloc::vec; + + #[test] + fn test_fpvm_bls12_g2_add_input_len() { + let input = Bytes::from(vec![0u8; INPUT_LENGTH + 1]); + let err = PrecompileError::Other(alloc::format!( + "G2 addition input length should be multiple of {}, was {}", + INPUT_LENGTH, + INPUT_LENGTH + 1 + )); + assert_eq!(fpvm_bls12_g2_add(&input, G2_ADD_BASE_FEE), Err(err.into())); + } + + #[test] + fn test_fpvm_bls12_g2_add_out_of_gas() { + let input = Bytes::from(vec![0u8; INPUT_LENGTH * 2]); + assert_eq!( + fpvm_bls12_g2_add(&input, G2_ADD_BASE_FEE - 1), + Err(PrecompileError::OutOfGas.into()) + ); + } +} diff --git a/bin/client/src/precompiles/bls12_g2_msm.rs b/bin/client/src/precompiles/bls12_g2_msm.rs new file mode 100644 index 0000000000..059838adee --- /dev/null +++ b/bin/client/src/precompiles/bls12_g2_msm.rs @@ -0,0 +1,122 @@ +//! Contains the accelerated precompile for the BLS12-381 curve G2 MSM. +//! +//! BLS12-381 is introduced in [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537). +//! +//! For constants and logic, see the [revm implementation]. +//! +//! [revm implementation]: https://github.com/bluealloy/revm/blob/main/crates/precompile/src/bls12_381/g2_msm.rs + +use crate::precompiles::utils::{msm_required_gas, precompile_run}; +use alloc::{string::ToString, vec::Vec}; +use alloy_primitives::{address, keccak256, Address, Bytes}; +use revm::{ + precompile::{Error as PrecompileError, Precompile, PrecompileResult, PrecompileWithAddress}, + primitives::PrecompileOutput, +}; + +/// The maximum input size for the BLS12-381 g2 msm operation after the Isthmus Hardfork. +/// +/// See: +const BLS12_MAX_G2_MSM_SIZE_ISTHMUS: usize = 488448; + +/// The address of the BLS12-381 g2 msm check precompile. +/// +/// See: +const BLS12_G2_MSM_CHECK: Address = address!("0x000000000000000000000000000000000000000e"); + +/// Input length of g2 msm operation. +const INPUT_LENGTH: usize = 288; + +/// Base gas fee for the BLS12-381 g2 msm operation. +const G2_MSM_BASE_FEE: u64 = 22500; + +/// The address of the BLS12-381 g2 msm precompile. +pub(crate) const FPVM_BLS12_G2_MSM_ISTHMUS: PrecompileWithAddress = + PrecompileWithAddress(BLS12_G2_MSM_CHECK, Precompile::Standard(fpvm_bls12_g2_msm_isthmus)); + +// Discounts table for G2 MSM as a vector of pairs `[k, discount]`: +static DISCOUNT_TABLE: [u16; 128] = [ + 1000, 1000, 923, 884, 855, 832, 812, 796, 782, 770, 759, 749, 740, 732, 724, 717, 711, 704, + 699, 693, 688, 683, 679, 674, 670, 666, 663, 659, 655, 652, 649, 646, 643, 640, 637, 634, 632, + 629, 627, 624, 622, 620, 618, 615, 613, 611, 609, 607, 606, 604, 602, 600, 598, 597, 595, 593, + 592, 590, 589, 587, 586, 584, 583, 582, 580, 579, 578, 576, 575, 574, 573, 571, 570, 569, 568, + 567, 566, 565, 563, 562, 561, 560, 559, 558, 557, 556, 555, 554, 553, 552, 552, 551, 550, 549, + 548, 547, 546, 545, 545, 544, 543, 542, 541, 541, 540, 539, 538, 537, 537, 536, 535, 535, 534, + 533, 532, 532, 531, 530, 530, 529, 528, 528, 527, 526, 526, 525, 524, 524, +]; + +/// Performs an FPVM-accelerated BLS12-381 G2 msm check. +fn fpvm_bls12_g2_msm(input: &Bytes, gas_limit: u64) -> PrecompileResult { + let input_len = input.len(); + if input_len == 0 || input_len % INPUT_LENGTH != 0 { + return Err(PrecompileError::Other(alloc::format!( + "G2MSM input length should be multiple of {}, was {}", + INPUT_LENGTH, + input_len + )) + .into()); + } + + let k = input_len / INPUT_LENGTH; + let required_gas = msm_required_gas(k, &DISCOUNT_TABLE, G2_MSM_BASE_FEE); + if required_gas > gas_limit { + return Err(PrecompileError::OutOfGas.into()); + } + + let result_data = kona_proof::block_on(precompile_run! { + &[BLS12_G2_MSM_CHECK.as_ref(), input.as_ref()] + }) + .map_err(|e| PrecompileError::Other(e.to_string()))?; + + Ok(PrecompileOutput::new(G2_MSM_BASE_FEE, result_data.into())) +} + +/// Performs an FPVM-accelerated `bls12` g2 msm check precompile call +/// after the Isthmus Hardfork. +fn fpvm_bls12_g2_msm_isthmus(input: &Bytes, gas_limit: u64) -> PrecompileResult { + if input.len() > BLS12_MAX_G2_MSM_SIZE_ISTHMUS { + return Err(PrecompileError::Other(alloc::format!( + "G2MSM input length must be at most {}", + BLS12_MAX_G2_MSM_SIZE_ISTHMUS + )) + .into()); + } + + fpvm_bls12_g2_msm(input, gas_limit) +} + +#[cfg(test)] +mod tests { + use super::*; + use alloc::vec; + + #[test] + fn test_fpvm_bls12_g2_msm_isthmus_max_bytes() { + let input = Bytes::from(vec![0u8; BLS12_MAX_G2_MSM_SIZE_ISTHMUS + 1]); + let gas_limit = G2_MSM_BASE_FEE; + let err = PrecompileError::Other(alloc::format!( + "G2MSM input length must be at most {}", + BLS12_MAX_G2_MSM_SIZE_ISTHMUS + )); + assert_eq!(fpvm_bls12_g2_msm_isthmus(&input, gas_limit), Err(err.into())); + } + + #[test] + fn test_fpvm_bls12_g2_msm_offset() { + let input = Bytes::from(vec![0u8; INPUT_LENGTH + 1]); + let gas_limit = G2_MSM_BASE_FEE; + let err = PrecompileError::Other(alloc::format!( + "G2MSM input length should be multiple of {}, was {}", + INPUT_LENGTH, + input.len(), + )); + assert_eq!(fpvm_bls12_g2_msm(&input, gas_limit), Err(err.into())); + } + + #[test] + fn test_fpvm_bls12_g2_msm_out_of_gas() { + let input = Bytes::from(vec![0u8; INPUT_LENGTH * 2]); + let gas_limit = G2_MSM_BASE_FEE - 1; + assert_eq!(fpvm_bls12_g2_msm(&input, gas_limit), Err(PrecompileError::OutOfGas.into())); + } +} diff --git a/bin/client/src/precompiles/bls12_map_fp.rs b/bin/client/src/precompiles/bls12_map_fp.rs new file mode 100644 index 0000000000..9a6d3ea9bf --- /dev/null +++ b/bin/client/src/precompiles/bls12_map_fp.rs @@ -0,0 +1,80 @@ +//! Contains the accelerated precompile for the BLS12-381 curve FP to G1 Mapping. +//! +//! BLS12-381 is introduced in [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537). +//! +//! For constants and logic, see the [revm implementation]. +//! +//! [revm implementation]: https://github.com/bluealloy/revm/blob/main/crates/precompile/src/bls12_381/map_fp_to_g1.rs + +use crate::precompiles::utils::precompile_run; +use alloc::{string::ToString, vec::Vec}; +use alloy_primitives::{address, keccak256, Address, Bytes}; +use revm::{ + precompile::{Error as PrecompileError, Precompile, PrecompileResult, PrecompileWithAddress}, + primitives::PrecompileOutput, +}; + +/// The address of the BLS12-381 map fp to g1 check precompile. +/// +/// See: +const BLS12_MAP_FP_CHECK: Address = address!("0x0000000000000000000000000000000000000010"); + +/// Base gas fee for the BLS12-381 map fp to g1 operation. +const MAP_FP_BASE_FEE: u64 = 5500; + +/// The padded FP length. +const PADDED_FP_LENGTH: usize = 64; + +/// The address of the BLS12-381 map fp to g1 precompile. +pub(crate) const FPVM_BLS12_MAP_FP_ISTHMUS: PrecompileWithAddress = + PrecompileWithAddress(BLS12_MAP_FP_CHECK, Precompile::Standard(fpvm_bls12_map_fp)); + +/// Performs an FPVM-accelerated BLS12-381 map fp check. +/// +/// Notice, there is no input size limit for this precompile. +/// See: +fn fpvm_bls12_map_fp(input: &Bytes, gas_limit: u64) -> PrecompileResult { + if MAP_FP_BASE_FEE > gas_limit { + return Err(PrecompileError::OutOfGas.into()); + } + + if input.len() != PADDED_FP_LENGTH { + return Err(PrecompileError::Other(alloc::format!( + "MAP_FP_TO_G1 input should be {PADDED_FP_LENGTH} bytes, was {}", + input.len() + )) + .into()); + } + + let result_data = kona_proof::block_on(precompile_run! { + &[BLS12_MAP_FP_CHECK.as_ref(), input.as_ref()] + }) + .map_err(|e| PrecompileError::Other(e.to_string()))?; + + Ok(PrecompileOutput::new(MAP_FP_BASE_FEE, result_data.into())) +} + +#[cfg(test)] +mod tests { + use super::*; + use alloc::vec; + + #[test] + fn test_fpvm_bls12_map_fp_offset() { + let input = Bytes::from(vec![0u8; PADDED_FP_LENGTH + 1]); + let gas_limit = MAP_FP_BASE_FEE; + let err = PrecompileError::Other(alloc::format!( + "MAP_FP_TO_G1 input should be {} bytes, was {}", + PADDED_FP_LENGTH, + input.len(), + )); + assert_eq!(fpvm_bls12_map_fp(&input, gas_limit), Err(err.into())); + } + + #[test] + fn test_fpvm_bls12_map_fp_out_of_gas() { + let input = Bytes::from(vec![0u8; PADDED_FP_LENGTH]); + let gas_limit = MAP_FP_BASE_FEE - 1; + assert_eq!(fpvm_bls12_map_fp(&input, gas_limit), Err(PrecompileError::OutOfGas.into())); + } +} diff --git a/bin/client/src/precompiles/bls12_map_fp2.rs b/bin/client/src/precompiles/bls12_map_fp2.rs new file mode 100644 index 0000000000..edc3df7305 --- /dev/null +++ b/bin/client/src/precompiles/bls12_map_fp2.rs @@ -0,0 +1,80 @@ +//! Contains the accelerated precompile for the BLS12-381 curve FP2 to G2 Mapping. +//! +//! BLS12-381 is introduced in [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537). +//! +//! For constants and logic, see the [revm implementation]. +//! +//! [revm implementation]: https://github.com/bluealloy/revm/blob/main/crates/precompile/src/bls12_381/map_fp_to_g1.rs + +use crate::precompiles::utils::precompile_run; +use alloc::{string::ToString, vec::Vec}; +use alloy_primitives::{address, keccak256, Address, Bytes}; +use revm::{ + precompile::{Error as PrecompileError, Precompile, PrecompileResult, PrecompileWithAddress}, + primitives::PrecompileOutput, +}; + +/// The address of the BLS12-381 map fp2 to g2 check precompile. +/// +/// See: +const BLS12_MAP_FP2_CHECK: Address = address!("0x0000000000000000000000000000000000000011"); + +/// Base gas fee for the BLS12-381 map fp2 to g2 operation. +const MAP_FP2_BASE_FEE: u64 = 23800; + +/// The padded FP2 length. +const PADDED_FP2_LENGTH: usize = 128; + +/// The address of the BLS12-381 map fp2 to g2 precompile. +pub(crate) const FPVM_BLS12_MAP_FP2_ISTHMUS: PrecompileWithAddress = + PrecompileWithAddress(BLS12_MAP_FP2_CHECK, Precompile::Standard(fpvm_bls12_map_fp2)); + +/// Performs an FPVM-accelerated BLS12-381 map fp2 check. +/// +/// Notice, there is no input size limit for this precompile. +/// See: +fn fpvm_bls12_map_fp2(input: &Bytes, gas_limit: u64) -> PrecompileResult { + if MAP_FP2_BASE_FEE > gas_limit { + return Err(PrecompileError::OutOfGas.into()); + } + + if input.len() != PADDED_FP2_LENGTH { + return Err(PrecompileError::Other(alloc::format!( + "MAP_FP2_TO_G2 input should be {PADDED_FP2_LENGTH} bytes, was {}", + input.len() + )) + .into()); + } + + let result_data = kona_proof::block_on(precompile_run! { + &[BLS12_MAP_FP2_CHECK.as_ref(), input.as_ref()] + }) + .map_err(|e| PrecompileError::Other(e.to_string()))?; + + Ok(PrecompileOutput::new(MAP_FP2_BASE_FEE, result_data.into())) +} + +#[cfg(test)] +mod tests { + use super::*; + use alloc::vec; + + #[test] + fn test_fpvm_bls12_map_fp2_offset() { + let input = Bytes::from(vec![0u8; PADDED_FP2_LENGTH + 1]); + let gas_limit = MAP_FP2_BASE_FEE; + let err = PrecompileError::Other(alloc::format!( + "MAP_FP2_TO_G2 input should be {} bytes, was {}", + PADDED_FP2_LENGTH, + input.len(), + )); + assert_eq!(fpvm_bls12_map_fp2(&input, gas_limit), Err(err.into())); + } + + #[test] + fn test_fpvm_bls12_map_fp_out_of_gas() { + let input = Bytes::from(vec![0u8; PADDED_FP2_LENGTH]); + let gas_limit = MAP_FP2_BASE_FEE - 1; + assert_eq!(fpvm_bls12_map_fp2(&input, gas_limit), Err(PrecompileError::OutOfGas.into())); + } +} diff --git a/bin/client/src/precompiles/bls12_pairing.rs b/bin/client/src/precompiles/bls12_pairing.rs new file mode 100644 index 0000000000..0015fcb3b0 --- /dev/null +++ b/bin/client/src/precompiles/bls12_pairing.rs @@ -0,0 +1,103 @@ +//! Contains the accelerated precompile for the BLS12-381 curve. +//! +//! BLS12-381 is introduced in [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537). +//! +//! For constants and logic, see the [revm implementation]. +//! +//! [revm implementation]: https://github.com/bluealloy/revm/blob/main/crates/precompile/src/bls12_381/pairing.rs + +use crate::precompiles::utils::precompile_run; +use alloc::{string::ToString, vec::Vec}; +use alloy_primitives::{address, keccak256, Address, Bytes}; +use revm::{ + precompile::{Error as PrecompileError, Precompile, PrecompileResult, PrecompileWithAddress}, + primitives::PrecompileOutput, +}; + +/// The max pairing size for BLS12-381 input given a 20M gas limit. +const BLS12_MAX_PAIRING_SIZE_ISTHMUS: usize = 235_008; + +/// The address of the BLS12-381 pairing check precompile. +const BLS12_PAIRING_CHECK: Address = address!("0x000000000000000000000000000000000000000f"); + +/// Input length of pairing operation. +const INPUT_LENGTH: usize = 384; + +/// Multiplier gas fee for BLS12-381 pairing operation. +const PAIRING_MULTIPLIER_BASE: u64 = 32600; + +/// Offset gas fee for BLS12-381 pairing operation. +const PAIRING_OFFSET_BASE: u64 = 37700; + +/// The address of the BLS12-381 pairing precompile. +pub(crate) const FPVM_BLS12_PAIRING_ISTHMUS: PrecompileWithAddress = + PrecompileWithAddress(BLS12_PAIRING_CHECK, Precompile::Standard(fpvm_bls12_pairing_isthmus)); + +/// Performs an FPVM-accelerated BLS12-381 pairing check. +fn fpvm_bls12_pairing(input: &Bytes, gas_limit: u64) -> PrecompileResult { + let input_len = input.len(); + if input_len % INPUT_LENGTH != 0 { + return Err(PrecompileError::Other(alloc::format!( + "Pairing input length should be multiple of {INPUT_LENGTH}, was {input_len}" + )) + .into()); + } + + let k = input_len / INPUT_LENGTH; + let required_gas: u64 = PAIRING_MULTIPLIER_BASE * k as u64 + PAIRING_OFFSET_BASE; + if required_gas > gas_limit { + return Err(PrecompileError::OutOfGas.into()); + } + + let result_data = kona_proof::block_on(precompile_run! { + &[BLS12_PAIRING_CHECK.as_ref(), input.as_ref()] + }) + .map_err(|e| PrecompileError::Other(e.to_string()))?; + + Ok(PrecompileOutput::new(required_gas, result_data.into())) +} + +/// Performs an FPVM-accelerated `bls12` pairing check precompile call +/// after the Isthmus Hardfork. +fn fpvm_bls12_pairing_isthmus(input: &Bytes, gas_limit: u64) -> PrecompileResult { + if input.len() > BLS12_MAX_PAIRING_SIZE_ISTHMUS { + return Err(PrecompileError::Other(alloc::format!( + "Pairing input length must be at most {}", + BLS12_MAX_PAIRING_SIZE_ISTHMUS + )) + .into()); + } + + fpvm_bls12_pairing(input, gas_limit) +} + +#[cfg(test)] +mod tests { + use super::*; + use alloc::vec; + + #[test] + fn test_fpvm_bls12_pairing_isthmus_max_bytes() { + let input = Bytes::from(vec![0u8; BLS12_MAX_PAIRING_SIZE_ISTHMUS + 1]); + let gas_limit = PAIRING_MULTIPLIER_BASE; + let err = PrecompileError::Other("Pairing input length must be at most 235008".to_string()); + assert_eq!(fpvm_bls12_pairing_isthmus(&input, gas_limit), Err(err.into())); + } + + #[test] + fn test_fpvm_bls12_offset() { + let input = Bytes::from(vec![0u8; INPUT_LENGTH + 1]); + let gas_limit = PAIRING_OFFSET_BASE; + let err = PrecompileError::Other( + "Pairing input length should be multiple of 384, was 385".to_string(), + ); + assert_eq!(fpvm_bls12_pairing(&input, gas_limit), Err(err.into())); + } + + #[test] + fn test_fpvm_bls12_out_of_gas() { + let input = Bytes::from(vec![0u8; INPUT_LENGTH * 2]); + let gas_limit = PAIRING_MULTIPLIER_BASE - 1; + assert_eq!(fpvm_bls12_pairing(&input, gas_limit), Err(PrecompileError::OutOfGas.into())); + } +} diff --git a/bin/client/src/precompiles/bn128_pair.rs b/bin/client/src/precompiles/bn128_pair.rs index a62eff284f..fce1b9719c 100644 --- a/bin/client/src/precompiles/bn128_pair.rs +++ b/bin/client/src/precompiles/bn128_pair.rs @@ -1,13 +1,8 @@ //! Contains the accelerated version of the `ecPairing` precompile. -use crate::{HINT_WRITER, ORACLE_READER}; +use crate::precompiles::utils::precompile_run; use alloc::{string::ToString, vec::Vec}; use alloy_primitives::{keccak256, Address, Bytes}; -use kona_preimage::{ - errors::PreimageOracleError, HintWriterClient, PreimageKey, PreimageKeyType, - PreimageOracleClient, -}; -use kona_proof::{errors::OracleProviderError, HintType}; use revm::{ precompile::{ bn128::pair::{ISTANBUL_PAIR_BASE, ISTANBUL_PAIR_PER_POINT}, @@ -38,40 +33,8 @@ fn fpvm_ecpairing(input: &Bytes, gas_limit: u64) -> PrecompileResult { return Err(PrecompileError::Bn128PairLength.into()); } - let result_data = kona_proof::block_on(async move { - // Write the hint for the ecrecover precompile run. - let hint_data = &[ECPAIRING_ADDRESS.as_ref(), input.as_ref()]; - HINT_WRITER - .write(&HintType::L1Precompile.encode_with(hint_data)) - .await - .map_err(OracleProviderError::Preimage)?; - - // Construct the key hash for the ecrecover precompile run. - let raw_key_data = hint_data.iter().copied().flatten().copied().collect::>(); - let key_hash = keccak256(&raw_key_data); - - // Fetch the result of the ecrecover precompile run from the host. - let result_data = ORACLE_READER - .get(PreimageKey::new(*key_hash, PreimageKeyType::Precompile)) - .await - .map_err(OracleProviderError::Preimage)?; - - // Ensure we've received valid result data. - if result_data.is_empty() { - return Err(OracleProviderError::Preimage(PreimageOracleError::Other( - "Invalid result data".to_string(), - ))); - } - - // Ensure we've not received an error from the host. - if result_data[0] == 0 { - return Err(OracleProviderError::Preimage(PreimageOracleError::Other( - "Error executing ecrecover precompile in host".to_string(), - ))); - } - - // Return the result data. - Ok(result_data[1..].to_vec()) + let result_data = kona_proof::block_on(precompile_run! { + &[ECPAIRING_ADDRESS.as_ref(), input.as_ref()] }) .map_err(|e| PrecompileError::Other(e.to_string()))?; diff --git a/bin/client/src/precompiles/ecrecover.rs b/bin/client/src/precompiles/ecrecover.rs index cf0a78976f..da988f86ae 100644 --- a/bin/client/src/precompiles/ecrecover.rs +++ b/bin/client/src/precompiles/ecrecover.rs @@ -1,13 +1,8 @@ //! Contains the accelerated version of the `ecrecover` precompile. -use crate::{HINT_WRITER, ORACLE_READER}; +use crate::precompiles::utils::precompile_run; use alloc::{string::ToString, vec::Vec}; use alloy_primitives::{keccak256, Address, Bytes}; -use kona_preimage::{ - errors::PreimageOracleError, HintWriterClient, PreimageKey, PreimageKeyType, - PreimageOracleClient, -}; -use kona_proof::{errors::OracleProviderError, HintType}; use revm::{ precompile::{u64_to_address, Error as PrecompileError, PrecompileWithAddress}, primitives::{Precompile, PrecompileOutput, PrecompileResult}, @@ -26,40 +21,8 @@ fn fpvm_ecrecover(input: &Bytes, gas_limit: u64) -> PrecompileResult { return Err(PrecompileError::OutOfGas.into()); } - let result_data = kona_proof::block_on(async move { - // Write the hint for the ecrecover precompile run. - let hint_data = &[ECRECOVER_ADDRESS.as_ref(), input.as_ref()]; - HINT_WRITER - .write(&HintType::L1Precompile.encode_with(hint_data)) - .await - .map_err(OracleProviderError::Preimage)?; - - // Construct the key hash for the ecrecover precompile run. - let raw_key_data = hint_data.iter().copied().flatten().copied().collect::>(); - let key_hash = keccak256(&raw_key_data); - - // Fetch the result of the ecrecover precompile run from the host. - let result_data = ORACLE_READER - .get(PreimageKey::new(*key_hash, PreimageKeyType::Precompile)) - .await - .map_err(OracleProviderError::Preimage)?; - - // Ensure we've received valid result data. - if result_data.is_empty() { - return Err(OracleProviderError::Preimage(PreimageOracleError::Other( - "Invalid result data".to_string(), - ))); - } - - // Ensure we've not received an error from the host. - if result_data[0] == 0 { - return Err(OracleProviderError::Preimage(PreimageOracleError::Other( - "Error executing ecrecover precompile in host".to_string(), - ))); - } - - // Return the result data. - Ok(result_data[1..].to_vec()) + let result_data = kona_proof::block_on(precompile_run! { + &[ECRECOVER_ADDRESS.as_ref(), input.as_ref()] }) .map_err(|e| PrecompileError::Other(e.to_string()))?; diff --git a/bin/client/src/precompiles/kzg_point_eval.rs b/bin/client/src/precompiles/kzg_point_eval.rs index 84b04d61b1..ddbc6834f4 100644 --- a/bin/client/src/precompiles/kzg_point_eval.rs +++ b/bin/client/src/precompiles/kzg_point_eval.rs @@ -1,13 +1,8 @@ //! Contains the accelerated version of the KZG point evaluation precompile. -use crate::{HINT_WRITER, ORACLE_READER}; +use crate::precompiles::utils::precompile_run; use alloc::{string::ToString, vec::Vec}; use alloy_primitives::{keccak256, Address, Bytes}; -use kona_preimage::{ - errors::PreimageOracleError, HintWriterClient, PreimageKey, PreimageKeyType, - PreimageOracleClient, -}; -use kona_proof::{errors::OracleProviderError, HintType}; use revm::{ precompile::{u64_to_address, Error as PrecompileError, PrecompileWithAddress}, primitives::{Precompile, PrecompileOutput, PrecompileResult}, @@ -30,40 +25,8 @@ fn fpvm_kzg_point_eval(input: &Bytes, gas_limit: u64) -> PrecompileResult { return Err(PrecompileError::BlobInvalidInputLength.into()); } - let result_data = kona_proof::block_on(async move { - // Write the hint for the ecrecover precompile run. - let hint_data = &[POINT_EVAL_ADDRESS.as_ref(), input.as_ref()]; - HINT_WRITER - .write(&HintType::L1Precompile.encode_with(hint_data)) - .await - .map_err(OracleProviderError::Preimage)?; - - // Construct the key hash for the ecrecover precompile run. - let raw_key_data = hint_data.iter().copied().flatten().copied().collect::>(); - let key_hash = keccak256(&raw_key_data); - - // Fetch the result of the ecrecover precompile run from the host. - let result_data = ORACLE_READER - .get(PreimageKey::new(*key_hash, PreimageKeyType::Precompile)) - .await - .map_err(OracleProviderError::Preimage)?; - - // Ensure we've received valid result data. - if result_data.is_empty() { - return Err(OracleProviderError::Preimage(PreimageOracleError::Other( - "Invalid result data".to_string(), - ))); - } - - // Ensure we've not received an error from the host. - if result_data[0] == 0 { - return Err(OracleProviderError::Preimage(PreimageOracleError::Other( - "Error executing ecrecover precompile in host".to_string(), - ))); - } - - // Return the result data. - Ok(result_data[1..].to_vec()) + let result_data = kona_proof::block_on(precompile_run! { + &[POINT_EVAL_ADDRESS.as_ref(), input.as_ref()] }) .map_err(|e| PrecompileError::Other(e.to_string()))?; diff --git a/bin/client/src/precompiles/mod.rs b/bin/client/src/precompiles/mod.rs index 910e343a16..282d6748e4 100644 --- a/bin/client/src/precompiles/mod.rs +++ b/bin/client/src/precompiles/mod.rs @@ -14,6 +14,15 @@ use revm::{ mod bn128_pair; mod ecrecover; mod kzg_point_eval; +pub(crate) mod utils; + +mod bls12_g1_add; +mod bls12_g1_msm; +mod bls12_g2_add; +mod bls12_g2_msm; +mod bls12_map_fp; +mod bls12_map_fp2; +mod bls12_pairing; /// The [KonaHandleRegister] function for registering the FPVM-accelerated precompiles. /// @@ -43,6 +52,16 @@ pub(crate) fn fpvm_handle_register( ctx_precompiles.extend([bn128_pair::FPVM_ECPAIRING_GRANITE]); } + // if spec_id.is_enabled_in(SpecId::ISTHMUS) { + // ctx_precompiles.extend([bls12_g1_add::FPVM_BLS12_G1_ADD_ISTHMUS]); + // ctx_precompiles.extend([bls12_g1_msm::FPVM_BLS12_G1_MSM_ISTHMUS]); + // ctx_precompiles.extend([bls12_g2_add::FPVM_BLS12_G2_ADD_ISTHMUS]); + // ctx_precompiles.extend([bls12_g2_msm::FPVM_BLS12_G2_MSM_ISTHMUS]); + // ctx_precompiles.extend([bls12_map_fp::FPVM_BLS12_MAP_FP_ISTHMUS]); + // ctx_precompiles.extend([bls12_map_fp2::FPVM_BLS12_MAP_FP2_ISTHMUS]); + // ctx_precompiles.extend([bls12_pairing::FPVM_BLS12_PAIRING_ISTHMUS]); + // } + ctx_precompiles }); } diff --git a/bin/client/src/precompiles/utils.rs b/bin/client/src/precompiles/utils.rs new file mode 100644 index 0000000000..0f2b6c58f0 --- /dev/null +++ b/bin/client/src/precompiles/utils.rs @@ -0,0 +1,72 @@ +//! Utility functions for precompiles + +// TODO: replace this with revm::precompiles::bls12_381::msm::msm_required_gas +// once the `msm` module is public. As of v19.4.0 the `msm` module is private. +/// Implements the gas schedule for G1/G2 Multiscalar-multiplication assuming 30 +/// MGas/second, see also: +#[inline] +pub(crate) fn msm_required_gas(k: usize, discount_table: &[u16], multiplication_cost: u64) -> u64 { + /// Amount used to calculate the multi-scalar-multiplication discount + const MSM_MULTIPLIER: u64 = 1000; + + if k == 0 { + return 0; + } + + let index = core::cmp::min(k - 1, discount_table.len() - 1); + let discount = discount_table[index] as u64; + + (k as u64 * discount * multiplication_cost) / MSM_MULTIPLIER +} + +/// A macro that generates an async block that sends a hint to the host, constructs a key hash +/// from the hint data, fetches the result of the precompile run from the host, and returns the +/// result data. +/// +/// The macro takes the following arguments: +/// - `hint_data`: The hint data to send to the host. +#[macro_export] +macro_rules! precompile_run { + ($hint_data:expr) => { + async move { + use kona_preimage::{ + errors::PreimageOracleError, PreimageKey, PreimageKeyType, PreimageOracleClient, + }; + use kona_proof::{errors::OracleProviderError, HintType}; + use $crate::{HINT_WRITER, ORACLE_READER}; + + // Write the hint for the precompile run. + let hint_data = $hint_data; + HintType::L1Precompile.with_data(hint_data).send(&HINT_WRITER).await?; + + // Construct the key hash for the precompile run. + let raw_key_data = hint_data.iter().copied().flatten().copied().collect::>(); + let key_hash = keccak256(&raw_key_data); + + // Fetch the result of the precompile run from the host. + let result_data = ORACLE_READER + .get(PreimageKey::new(*key_hash, PreimageKeyType::Precompile)) + .await + .map_err(OracleProviderError::Preimage)?; + + // Ensure we've received valid result data. + if result_data.is_empty() { + return Err(OracleProviderError::Preimage(PreimageOracleError::Other( + "Invalid result data".to_string(), + ))); + } + + // Ensure we've not received an error from the host. + if result_data[0] == 0 { + return Err(OracleProviderError::Preimage(PreimageOracleError::Other( + "Error executing precompile in host".to_string(), + ))); + } + + // Return the result data. + Ok(result_data[1..].to_vec()) + } + }; +} + +pub(crate) use precompile_run; diff --git a/bin/client/src/single.rs b/bin/client/src/single.rs new file mode 100644 index 0000000000..b884a406b5 --- /dev/null +++ b/bin/client/src/single.rs @@ -0,0 +1,176 @@ +//! Single-chain fault proof program entrypoint. + +use alloc::sync::Arc; +use alloy_consensus::Sealed; +use alloy_primitives::B256; +use core::fmt::Debug; +use kona_driver::{Driver, DriverError}; +use kona_executor::{ExecutorError, KonaHandleRegister, TrieDBProvider}; +use kona_preimage::{CommsClient, HintWriterClient, PreimageKey, PreimageOracleClient}; +use kona_proof::l1::OracleEigenDaProvider; +use kona_proof::{ + errors::OracleProviderError, + executor::KonaExecutor, + l1::{OracleBlobProvider, OracleL1ChainProvider, OraclePipeline}, + l2::OracleL2ChainProvider, + sync::new_pipeline_cursor, + BootInfo, CachingOracle, HintType, +}; +use thiserror::Error; +use tracing::{error, info}; + +/// An error that can occur when running the fault proof program. +#[derive(Error, Debug)] +pub enum FaultProofProgramError { + /// The claim is invalid. + #[error("Invalid claim. Expected {0}, actual {1}")] + InvalidClaim(B256, B256), + /// An error occurred in the Oracle provider. + #[error(transparent)] + OracleProviderError(#[from] OracleProviderError), + /// An error occurred in the driver. + #[error(transparent)] + Driver(#[from] DriverError), +} + +/// Executes the fault proof program with the given [PreimageOracleClient] and [HintWriterClient]. +#[inline] +pub async fn run( + oracle_client: P, + hint_client: H, + handle_register: Option< + KonaHandleRegister< + OracleL2ChainProvider>, + OracleL2ChainProvider>, + >, + >, +) -> Result<(), FaultProofProgramError> +where + P: PreimageOracleClient + Send + Sync + Debug + Clone, + H: HintWriterClient + Send + Sync + Debug + Clone, +{ + const ORACLE_LRU_SIZE: usize = 1024; + + //////////////////////////////////////////////////////////////// + // PROLOGUE // + //////////////////////////////////////////////////////////////// + + let oracle = Arc::new(CachingOracle::new(ORACLE_LRU_SIZE, oracle_client, hint_client)); + let boot = BootInfo::load(oracle.as_ref()).await?; + let rollup_config = Arc::new(boot.rollup_config); + let safe_head_hash = fetch_safe_head_hash(oracle.as_ref(), boot.agreed_l2_output_root).await?; + + let mut l1_provider = OracleL1ChainProvider::new(boot.l1_head, oracle.clone()); + let mut l2_provider = + OracleL2ChainProvider::new(safe_head_hash, rollup_config.clone(), oracle.clone()); + let beacon = OracleBlobProvider::new(oracle.clone()); + let eigen_da_provider = OracleEigenDaProvider::new(oracle.clone()); + + // Fetch the safe head's block header. + let safe_head = l2_provider + .header_by_hash(safe_head_hash) + .map(|header| Sealed::new_unchecked(header, safe_head_hash))?; + + // If the claimed L2 block number is less than the safe head of the L2 chain, the claim is + // invalid. + if boot.claimed_l2_block_number < safe_head.number { + error!( + target: "client", + "Claimed L2 block number {claimed} is less than the safe head {safe}", + claimed = boot.claimed_l2_block_number, + safe = safe_head.number + ); + return Err(FaultProofProgramError::InvalidClaim( + boot.agreed_l2_output_root, + boot.claimed_l2_output_root, + )); + } + + // In the case where the agreed upon L2 output root is the same as the claimed L2 output root, + // trace extension is detected and we can skip the derivation and execution steps. + if boot.agreed_l2_output_root == boot.claimed_l2_output_root { + info!( + target: "client", + "Trace extension detected. State transition is already agreed upon.", + ); + return Ok(()); + } + + //////////////////////////////////////////////////////////////// + // DERIVATION & EXECUTION // + //////////////////////////////////////////////////////////////// + + // Create a new derivation driver with the given boot information and oracle. + let cursor = + new_pipeline_cursor(rollup_config.as_ref(), safe_head, &mut l1_provider, &mut l2_provider) + .await?; + l2_provider.set_cursor(cursor.clone()); + + let pipeline = OraclePipeline::new( + rollup_config.clone(), + cursor.clone(), + oracle.clone(), + beacon, + eigen_da_provider, + l1_provider.clone(), + l2_provider.clone(), + ); + let executor = KonaExecutor::new( + rollup_config.as_ref(), + l2_provider.clone(), + l2_provider, + handle_register, + None, + ); + let mut driver = Driver::new(cursor, executor, pipeline); + + // Run the derivation pipeline until we are able to produce the output root of the claimed + // L2 block. + let (safe_head, output_root) = driver + .advance_to_target(rollup_config.as_ref(), Some(boot.claimed_l2_block_number)) + .await?; + + //////////////////////////////////////////////////////////////// + // EPILOGUE // + //////////////////////////////////////////////////////////////// + + if output_root != boot.claimed_l2_output_root { + error!( + target: "client", + "Failed to validate L2 block #{number} with output root {output_root}", + number = safe_head.block_info.number, + output_root = output_root + ); + return Err(FaultProofProgramError::InvalidClaim(output_root, boot.claimed_l2_output_root)); + } + + info!( + target: "client", + "Successfully validated L2 block #{number} with output root {output_root}", + number = safe_head.block_info.number, + output_root = output_root + ); + + Ok(()) +} + +/// Fetches the safe head hash of the L2 chain based on the agreed upon L2 output root in the +/// [BootInfo]. +pub async fn fetch_safe_head_hash( + caching_oracle: &O, + agreed_l2_output_root: B256, +) -> Result +where + O: CommsClient, +{ + let mut output_preimage = [0u8; 128]; + HintType::StartingL2Output + .with_data(&[agreed_l2_output_root.as_ref()]) + .send(caching_oracle) + .await?; + caching_oracle + .get_exact(PreimageKey::new_keccak256(*agreed_l2_output_root), output_preimage.as_mut()) + .await?; + + output_preimage[96..128].try_into().map_err(OracleProviderError::SliceConversion) +} diff --git a/bin/host/Cargo.toml b/bin/host/Cargo.toml index a512a5ee23..b0df2d0434 100644 --- a/bin/host/Cargo.toml +++ b/bin/host/Cargo.toml @@ -19,6 +19,9 @@ kona-std-fpvm.workspace = true kona-preimage = { workspace = true, features = ["std"] } kona-proof = { workspace = true, features = ["std"] } kona-client.workspace = true +kona-providers-alloy.workspace = true +eigen-da.workspace = true + # Alloy alloy-rlp.workspace = true @@ -36,21 +39,39 @@ alloy-rpc-types-beacon.workspace = true op-alloy-genesis = { workspace = true, features = ["std", "serde"] } op-alloy-protocol = { workspace = true, features = ["std", "serde"] } op-alloy-rpc-types-engine = { workspace = true, features = ["serde"] } +op-alloy-network.workspace = true # Revm revm = { workspace = true, features = ["std", "c-kzg", "secp256k1", "portable", "blst"] } +# Eigenda +rust-kzg-bn254-prover.workspace = true +rust-kzg-bn254-primitives.workspace = true +num.workspace = true +ark-bn254.workspace = true +ark-ff.workspace = true + + # General anyhow.workspace = true tracing.workspace = true reqwest.workspace = true serde_json.workspace = true async-trait.workspace = true +rocksdb = { workspace = true, features = ["snappy"] } tokio = { workspace = true, features = ["full"] } serde = { workspace = true, features = ["derive"] } -rocksdb = { workspace = true, features = ["snappy"] } clap = { workspace = true, features = ["derive", "env"] } tracing-subscriber = { workspace = true, features = ["fmt"] } [dev-dependencies] proptest.workspace = true + +[features] +default = ["single", "interop"] +single = [] +interop = ["single"] + +[[bin]] +name = "kona-host" +path = "src/bin/host.rs" \ No newline at end of file diff --git a/bin/host/src/backend/mod.rs b/bin/host/src/backend/mod.rs new file mode 100644 index 0000000000..7892bd2eb2 --- /dev/null +++ b/bin/host/src/backend/mod.rs @@ -0,0 +1,9 @@ +//! Backend for the preimage server. + +mod offline; +pub use offline::OfflineHostBackend; + +mod online; +pub use online::{HintHandler, OnlineHostBackend, OnlineHostBackendCfg}; + +pub(crate) mod util; diff --git a/bin/host/src/backend/offline.rs b/bin/host/src/backend/offline.rs new file mode 100644 index 0000000000..0f97d2e01b --- /dev/null +++ b/bin/host/src/backend/offline.rs @@ -0,0 +1,50 @@ +//! Contains the implementations of the [HintRouter] and [PreimageFetcher] traits.] + +use crate::kv::KeyValueStore; +use async_trait::async_trait; +use kona_preimage::{ + errors::{PreimageOracleError, PreimageOracleResult}, + HintRouter, PreimageFetcher, PreimageKey, +}; +use std::sync::Arc; +use tokio::sync::RwLock; + +/// A [KeyValueStore]-backed implementation of the [PreimageFetcher] trait. +#[derive(Debug)] +pub struct OfflineHostBackend +where + KV: KeyValueStore + ?Sized, +{ + inner: Arc>, +} + +impl OfflineHostBackend +where + KV: KeyValueStore + ?Sized, +{ + /// Create a new [OfflineHostBackend] from the given [KeyValueStore]. + pub const fn new(kv_store: Arc>) -> Self { + Self { inner: kv_store } + } +} + +#[async_trait] +impl PreimageFetcher for OfflineHostBackend +where + KV: KeyValueStore + Send + Sync + ?Sized, +{ + async fn get_preimage(&self, key: PreimageKey) -> PreimageOracleResult> { + let kv_store = self.inner.read().await; + kv_store.get(key.into()).ok_or(PreimageOracleError::KeyNotFound) + } +} + +#[async_trait] +impl HintRouter for OfflineHostBackend +where + KV: KeyValueStore + Send + Sync + ?Sized, +{ + async fn route_hint(&self, _hint: String) -> PreimageOracleResult<()> { + Ok(()) + } +} diff --git a/bin/host/src/backend/online.rs b/bin/host/src/backend/online.rs new file mode 100644 index 0000000000..bf71bb78b3 --- /dev/null +++ b/bin/host/src/backend/online.rs @@ -0,0 +1,151 @@ +//! Contains the [OnlineHostBackend] definition. + +use crate::SharedKeyValueStore; +use anyhow::Result; +use async_trait::async_trait; +use kona_preimage::{ + errors::{PreimageOracleError, PreimageOracleResult}, + HintRouter, PreimageFetcher, PreimageKey, +}; +use kona_proof::{errors::HintParsingError, Hint}; +use std::{collections::HashSet, hash::Hash, str::FromStr, sync::Arc}; +use tokio::sync::RwLock; +use tracing::{debug, error, trace}; + +/// The [OnlineHostBackendCfg] trait is used to define the type configuration for the +/// [OnlineHostBackend]. +pub trait OnlineHostBackendCfg { + /// The hint type describing the range of hints that can be received. + type HintType: FromStr + Hash + Eq + PartialEq + Clone + Send + Sync; + + /// The providers that are used to fetch data in response to hints. + type Providers: Send + Sync; +} + +/// A [HintHandler] is an interface for receiving hints, fetching remote data, and storing it in the +/// key-value store. +#[async_trait] +pub trait HintHandler { + /// The type configuration for the [HintHandler]. + type Cfg: OnlineHostBackendCfg; + + /// Fetches data in response to a hint. + async fn fetch_hint( + hint: Hint<::HintType>, + cfg: &Self::Cfg, + providers: &::Providers, + kv: SharedKeyValueStore, + ) -> Result<()>; +} + +/// The [OnlineHostBackend] is a [HintRouter] and [PreimageFetcher] that is used to fetch data from +/// remote sources in response to hints. +/// +/// [PreimageKey]: kona_preimage::PreimageKey +#[allow(missing_debug_implementations)] +pub struct OnlineHostBackend +where + C: OnlineHostBackendCfg, + H: HintHandler, +{ + /// The configuration that is used to route hints. + cfg: C, + /// The key-value store that is used to store preimages. + kv: SharedKeyValueStore, + /// The providers that are used to fetch data in response to hints. + providers: C::Providers, + /// Hints that should be immediately executed by the host. + proactive_hints: HashSet, + /// The last hint that was received. + last_hint: Arc>>>, + /// Phantom marker for the [HintHandler]. + _hint_handler: std::marker::PhantomData, +} + +impl OnlineHostBackend +where + C: OnlineHostBackendCfg, + H: HintHandler, +{ + /// Creates a new [HintHandler] with the given configuration, key-value store, providers, and + /// external configuration. + pub fn new(cfg: C, kv: SharedKeyValueStore, providers: C::Providers, _: H) -> Self { + Self { + cfg, + kv, + providers, + proactive_hints: HashSet::default(), + last_hint: Arc::new(RwLock::new(None)), + _hint_handler: std::marker::PhantomData, + } + } + + /// Adds a new proactive hint to the [OnlineHostBackend]. + pub fn with_proactive_hint(mut self, hint_type: C::HintType) -> Self { + self.proactive_hints.insert(hint_type); + self + } +} + +#[async_trait] +impl HintRouter for OnlineHostBackend +where + C: OnlineHostBackendCfg + Send + Sync, + H: HintHandler + Send + Sync, +{ + /// Set the last hint to be received. + async fn route_hint(&self, hint: String) -> PreimageOracleResult<()> { + trace!(target: "host-backend", "Received hint: {hint}"); + + let parsed_hint = + hint.parse::>().map_err(|_| PreimageOracleError::KeyNotFound)?; + if self.proactive_hints.contains(&parsed_hint.ty) { + debug!(target: "host-backend", "Proactive hint received; Immediately fetching {hint}"); + H::fetch_hint(parsed_hint, &self.cfg, &self.providers, self.kv.clone()) + .await + .map_err(|e| PreimageOracleError::Other(e.to_string()))?; + } else { + let mut hint_lock = self.last_hint.write().await; + hint_lock.replace(parsed_hint); + } + + Ok(()) + } +} + +#[async_trait] +impl PreimageFetcher for OnlineHostBackend +where + C: OnlineHostBackendCfg + Send + Sync, + H: HintHandler + Send + Sync, +{ + /// Get the preimage for the given key. + async fn get_preimage(&self, key: PreimageKey) -> PreimageOracleResult> { + trace!(target: "host-backend", "Pre-image requested. Key: {key}"); + + // Acquire a read lock on the key-value store. + let kv_lock = self.kv.read().await; + let mut preimage = kv_lock.get(key.into()); + + // Drop the read lock before beginning the retry loop. + drop(kv_lock); + + // Use a loop to keep retrying the prefetch as long as the key is not found + while preimage.is_none() { + if let Some(hint) = self.last_hint.read().await.as_ref() { + let value = + H::fetch_hint(hint.clone(), &self.cfg, &self.providers, self.kv.clone()).await; + + if let Err(e) = value { + error!(target: "host-backend", "Failed to prefetch hint: {e}"); + continue; + } + + let kv_lock = self.kv.read().await; + preimage = kv_lock.get(key.into()); + } + } + + preimage.ok_or(PreimageOracleError::KeyNotFound) + } +} diff --git a/bin/host/src/backend/util.rs b/bin/host/src/backend/util.rs new file mode 100644 index 0000000000..79a3c07a4d --- /dev/null +++ b/bin/host/src/backend/util.rs @@ -0,0 +1,41 @@ +//! Utilities for the preimage server backend. + +use crate::KeyValueStore; +use alloy_consensus::EMPTY_ROOT_HASH; +use alloy_primitives::keccak256; +use alloy_rlp::EMPTY_STRING_CODE; +use anyhow::Result; +use kona_preimage::{PreimageKey, PreimageKeyType}; +use tokio::sync::RwLock; + +/// Constructs a merkle patricia trie from the ordered list passed and stores all encoded +/// intermediate nodes of the trie in the [KeyValueStore]. +pub(crate) async fn store_ordered_trie>( + kv: &RwLock, + values: &[T], +) -> Result<()> { + let mut kv_write_lock = kv.write().await; + + // If the list of nodes is empty, store the empty root hash and exit early. + // The `HashBuilder` will not push the preimage of the empty root hash to the + // `ProofRetainer` in the event that there are no leaves inserted. + if values.is_empty() { + let empty_key = PreimageKey::new(*EMPTY_ROOT_HASH, PreimageKeyType::Keccak256); + return kv_write_lock.set(empty_key.into(), [EMPTY_STRING_CODE].into()); + } + + let mut hb = kona_mpt::ordered_trie_with_encoder(values, |node, buf| { + buf.put_slice(node.as_ref()); + }); + hb.root(); + let intermediates = hb.take_proof_nodes().into_inner(); + + for (_, value) in intermediates.into_iter() { + let value_hash = keccak256(value.as_ref()); + let key = PreimageKey::new(*value_hash, PreimageKeyType::Keccak256); + + kv_write_lock.set(key.into(), value.into())?; + } + + Ok(()) +} diff --git a/bin/host/src/bin/host.rs b/bin/host/src/bin/host.rs new file mode 100644 index 0000000000..c10415b374 --- /dev/null +++ b/bin/host/src/bin/host.rs @@ -0,0 +1,55 @@ +//! Main entrypoint for the host binary. + +#![warn(missing_debug_implementations, missing_docs, unreachable_pub, rustdoc::all)] +#![deny(unused_must_use, rust_2018_idioms)] +#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] + +use anyhow::Result; +use clap::{ArgAction, Parser, Subcommand}; +use kona_host::cli::{cli_styles, init_tracing_subscriber}; +use serde::Serialize; +use tracing::info; + +const ABOUT: &str = " +kona-host is a CLI application that runs the Kona pre-image server and client program. The host +can run in two modes: server mode and native mode. In server mode, the host runs the pre-image +server and waits for the client program in the parent process to request pre-images. In native +mode, the host runs the client program in a separate thread with the pre-image server in the +primary thread. +"; + +/// The host binary CLI application arguments. +#[derive(Parser, Serialize, Clone, Debug)] +#[command(about = ABOUT, version, styles = cli_styles())] +pub struct HostCli { + /// Verbosity level (0-2) + #[arg(long, short, action = ArgAction::Count)] + pub v: u8, + /// Host mode + #[clap(subcommand)] + pub mode: HostMode, +} + +/// Operation modes for the host binary. +#[derive(Subcommand, Serialize, Clone, Debug)] +#[allow(clippy::large_enum_variant)] +pub enum HostMode { + /// Run the host in single-chain mode. + #[cfg(feature = "single")] + Single(kona_host::single::SingleChainHost), +} + +#[tokio::main(flavor = "multi_thread")] +async fn main() -> Result<()> { + let cfg = HostCli::parse(); + init_tracing_subscriber(cfg.v)?; + + match cfg.mode { + #[cfg(feature = "single")] + HostMode::Single(cfg) => { + cfg.start().await?; + } + } + + Ok(()) +} diff --git a/bin/host/src/cli/mod.rs b/bin/host/src/cli/mod.rs index 4acdab56b1..d1117753ea 100644 --- a/bin/host/src/cli/mod.rs +++ b/bin/host/src/cli/mod.rs @@ -1,204 +1,14 @@ //! This module contains all CLI-specific code for the host binary. -use crate::{ - blobs::OnlineBlobProvider, - kv::{ - DiskKeyValueStore, LocalKeyValueStore, MemoryKeyValueStore, SharedKeyValueStore, - SplitKeyValueStore, - }, -}; -use alloy_primitives::B256; -use alloy_provider::ReqwestProvider; -use alloy_rpc_client::RpcClient; -use alloy_transport_http::Http; -use anyhow::{anyhow, Result}; -use clap::{ - builder::styling::{AnsiColor, Color, Style}, - ArgAction, Parser, -}; -use op_alloy_genesis::RollupConfig; -use reqwest::Client; -use serde::Serialize; -use std::{path::PathBuf, sync::Arc}; -use tokio::sync::RwLock; +use clap::builder::styling::{AnsiColor, Color, Style}; -mod parser; -pub(crate) use parser::parse_b256; +pub mod parser; mod tracing_util; pub use tracing_util::init_tracing_subscriber; -const ABOUT: &str = " -kona-host is a CLI application that runs the Kona pre-image server and client program. The host -can run in two modes: server mode and native mode. In server mode, the host runs the pre-image -server and waits for the client program in the parent process to request pre-images. In native -mode, the host runs the client program in a separate thread with the pre-image server in the -primary thread. -"; - -/// The host binary CLI application arguments. -#[derive(Default, Parser, Serialize, Clone, Debug)] -#[command(about = ABOUT, version, styles = cli_styles())] -pub struct HostCli { - /// Verbosity level (0-2) - #[arg(long, short, action = ArgAction::Count)] - pub v: u8, - /// Hash of the L1 head block. Derivation stops after this block is processed. - #[clap(long, value_parser = parse_b256, env)] - pub l1_head: B256, - /// Hash of the agreed upon safe L2 block committed to by `--agreed-l2-output-root`. - #[clap(long, visible_alias = "l2-head", value_parser = parse_b256, env)] - pub agreed_l2_head_hash: B256, - /// Agreed safe L2 Output Root to start derivation from. - #[clap(long, visible_alias = "l2-output-root", value_parser = parse_b256, env)] - pub agreed_l2_output_root: B256, - /// Claimed L2 output root at block # `--claimed-l2-block-number` to validate. - #[clap(long, visible_alias = "l2-claim", value_parser = parse_b256, env)] - pub claimed_l2_output_root: B256, - /// Number of the L2 block that the claimed output root commits to. - #[clap(long, visible_alias = "l2-block-number", env)] - pub claimed_l2_block_number: u64, - /// Address of L2 JSON-RPC endpoint to use (eth and debug namespace required). - #[clap( - long, - visible_alias = "l2", - requires = "l1_node_address", - requires = "l1_beacon_address", - env - )] - pub l2_node_address: Option, - /// Address of L1 JSON-RPC endpoint to use (eth and debug namespace required) - #[clap( - long, - visible_alias = "l1", - requires = "l2_node_address", - requires = "l1_beacon_address", - env - )] - pub l1_node_address: Option, - /// Address of the L1 Beacon API endpoint to use. - #[clap( - long, - visible_alias = "beacon", - requires = "l1_node_address", - requires = "l2_node_address", - env - )] - pub l1_beacon_address: Option, - /// The Data Directory for preimage data storage. Optional if running in online mode, - /// required if running in offline mode. - #[clap( - long, - visible_alias = "db", - required_unless_present_all = ["l2_node_address", "l1_node_address", "l1_beacon_address"], - env - )] - pub data_dir: Option, - /// Run the client program natively. - #[clap(long, conflicts_with = "server", required_unless_present = "server")] - pub native: bool, - /// Run in pre-image server mode without executing any client program. If not provided, the - /// host will run the client program in the host process. - #[clap(long, conflicts_with = "native", required_unless_present = "native")] - pub server: bool, - /// The L2 chain ID of a supported chain. If provided, the host will look for the corresponding - /// rollup config in the superchain registry. - #[clap( - long, - conflicts_with = "rollup_config_path", - required_unless_present = "rollup_config_path", - env - )] - pub l2_chain_id: Option, - /// Path to rollup config. If provided, the host will use this config instead of attempting to - /// look up the config in the superchain registry. - #[clap( - long, - alias = "rollup-cfg", - conflicts_with = "l2_chain_id", - required_unless_present = "l2_chain_id", - env - )] - pub rollup_config_path: Option, -} - -impl HostCli { - /// Returns `true` if the host is running in offline mode. - pub const fn is_offline(&self) -> bool { - self.l1_node_address.is_none() && - self.l2_node_address.is_none() && - self.l1_beacon_address.is_none() - } - - /// Returns an HTTP provider for the given URL. - fn http_provider(url: &str) -> ReqwestProvider { - let url = url.parse().unwrap(); - let http = Http::::new(url); - ReqwestProvider::new(RpcClient::new(http, true)) - } - - /// Creates the providers associated with the [HostCli] configuration. - /// - /// ## Returns - /// - A [ReqwestProvider] for the L1 node. - /// - An [OnlineBlobProvider] for the L1 beacon node. - /// - A [ReqwestProvider] for the L2 node. - pub async fn create_providers( - &self, - ) -> Result<(ReqwestProvider, OnlineBlobProvider, ReqwestProvider)> { - let blob_provider = OnlineBlobProvider::new_http( - self.l1_beacon_address.clone().ok_or(anyhow!("Beacon API URL must be set"))?, - ) - .await - .map_err(|e| anyhow!("Failed to load blob provider configuration: {e}"))?; - let l1_provider = Self::http_provider( - self.l1_node_address.as_ref().ok_or(anyhow!("Provider must be set"))?, - ); - let l2_provider = Self::http_provider( - self.l2_node_address.as_ref().ok_or(anyhow!("L2 node address must be set"))?, - ); - - Ok((l1_provider, blob_provider, l2_provider)) - } - - /// Parses the CLI arguments and returns a new instance of a [SharedKeyValueStore], as it is - /// configured to be created. - pub fn construct_kv_store(&self) -> SharedKeyValueStore { - let local_kv_store = LocalKeyValueStore::new(self.clone()); - - let kv_store: SharedKeyValueStore = if let Some(ref data_dir) = self.data_dir { - let disk_kv_store = DiskKeyValueStore::new(data_dir.clone()); - let split_kv_store = SplitKeyValueStore::new(local_kv_store, disk_kv_store); - Arc::new(RwLock::new(split_kv_store)) - } else { - let mem_kv_store = MemoryKeyValueStore::new(); - let split_kv_store = SplitKeyValueStore::new(local_kv_store, mem_kv_store); - Arc::new(RwLock::new(split_kv_store)) - }; - - kv_store - } - - /// Reads the [RollupConfig] from the file system and returns it as a string. - pub fn read_rollup_config(&self) -> Result { - let path = self.rollup_config_path.as_ref().ok_or_else(|| { - anyhow::anyhow!( - "No rollup config path provided. Please provide a path to the rollup config." - ) - })?; - - // Read the serialized config from the file system. - let ser_config = std::fs::read_to_string(path) - .map_err(|e| anyhow!("Error reading RollupConfig file: {e}"))?; - - // Deserialize the config and return it. - serde_json::from_str(&ser_config) - .map_err(|e| anyhow!("Error deserializing RollupConfig: {e}")) - } -} - /// Styles for the CLI application. -const fn cli_styles() -> clap::builder::Styles { +pub const fn cli_styles() -> clap::builder::Styles { clap::builder::Styles::styled() .usage(Style::new().bold().underline().fg_color(Some(Color::Ansi(AnsiColor::Yellow)))) .header(Style::new().bold().underline().fg_color(Some(Color::Ansi(AnsiColor::Yellow)))) @@ -208,69 +18,3 @@ const fn cli_styles() -> clap::builder::Styles { .valid(Style::new().bold().underline().fg_color(Some(Color::Ansi(AnsiColor::Green)))) .placeholder(Style::new().fg_color(Some(Color::Ansi(AnsiColor::White)))) } - -#[cfg(test)] -mod test { - use crate::HostCli; - use alloy_primitives::B256; - use clap::Parser; - - #[test] - fn test_flags() { - let zero_hash_str = &B256::ZERO.to_string(); - let default_flags = [ - "host", - "--l1-head", - zero_hash_str, - "--l2-head", - zero_hash_str, - "--l2-output-root", - zero_hash_str, - "--l2-claim", - zero_hash_str, - "--l2-block-number", - "0", - ]; - - let cases = [ - // valid - (["--server", "--l2-chain-id", "0", "--data-dir", "dummy"].as_slice(), true), - (["--server", "--rollup-config-path", "dummy", "--data-dir", "dummy"].as_slice(), true), - (["--native", "--l2-chain-id", "0", "--data-dir", "dummy"].as_slice(), true), - (["--native", "--rollup-config-path", "dummy", "--data-dir", "dummy"].as_slice(), true), - ( - [ - "--l1-node-address", - "dummy", - "--l2-node-address", - "dummy", - "--l1-beacon-address", - "dummy", - "--server", - "--l2-chain-id", - "0", - ] - .as_slice(), - true, - ), - // invalid - (["--server", "--native", "--l2-chain-id", "0"].as_slice(), false), - (["--l2-chain-id", "0", "--rollup-config-path", "dummy", "--server"].as_slice(), false), - (["--server"].as_slice(), false), - (["--native"].as_slice(), false), - (["--rollup-config-path", "dummy"].as_slice(), false), - (["--l2-chain-id", "0"].as_slice(), false), - (["--l1-node-address", "dummy", "--server", "--l2-chain-id", "0"].as_slice(), false), - (["--l2-node-address", "dummy", "--server", "--l2-chain-id", "0"].as_slice(), false), - (["--l1-beacon-address", "dummy", "--server", "--l2-chain-id", "0"].as_slice(), false), - ([].as_slice(), false), - ]; - - for (args_ext, valid) in cases.into_iter() { - let args = default_flags.iter().chain(args_ext.iter()).cloned().collect::>(); - - let parsed = HostCli::try_parse_from(args); - assert_eq!(parsed.is_ok(), valid); - } - } -} diff --git a/bin/host/src/cli/parser.rs b/bin/host/src/cli/parser.rs index a83ba55993..93ea29b279 100644 --- a/bin/host/src/cli/parser.rs +++ b/bin/host/src/cli/parser.rs @@ -1,13 +1,14 @@ -use alloy_primitives::B256; +//! Parser functions for CLI arguments. + +use alloy_primitives::{hex, Bytes, B256}; use std::str::FromStr; -/// Parse string slices into alloy_primitives bytes -/// -/// # Arguments -/// * `s` - string slice -/// -/// # Returns -/// * `Result` - Ok if successful, Err otherwise. -pub(crate) fn parse_b256(s: &str) -> Result { +/// Parse a string slice into [B256]. +pub fn parse_b256(s: &str) -> Result { B256::from_str(s).map_err(|_| format!("Invalid B256 value: {}", s)) } + +/// Parse a string slice into [Bytes]. +pub fn parse_bytes(s: &str) -> Result { + hex::decode(s).map_err(|e| format!("Invalid hex string: {}", e)).map(Bytes::from) +} diff --git a/bin/host/src/eth/mod.rs b/bin/host/src/eth/mod.rs new file mode 100644 index 0000000000..fbb1e1c919 --- /dev/null +++ b/bin/host/src/eth/mod.rs @@ -0,0 +1,16 @@ +//! Ethereum utilities for the host binary. + +use alloy_provider::{Network, RootProvider}; +use alloy_rpc_client::RpcClient; +use alloy_transport_http::Http; +use reqwest::Client; + +mod precompiles; +pub(crate) use precompiles::execute; + +/// Returns an HTTP provider for the given URL. +pub fn http_provider(url: &str) -> RootProvider { + let url = url.parse().unwrap(); + let http = Http::::new(url); + RootProvider::new(RpcClient::new(http, true)) +} diff --git a/bin/host/src/fetcher/precompiles.rs b/bin/host/src/eth/precompiles.rs similarity index 67% rename from bin/host/src/fetcher/precompiles.rs rename to bin/host/src/eth/precompiles.rs index e6c3bf1ba7..3950e90d49 100644 --- a/bin/host/src/fetcher/precompiles.rs +++ b/bin/host/src/eth/precompiles.rs @@ -9,8 +9,16 @@ use revm::{ /// List of precompiles that are accelerated by the host program. pub(crate) const ACCELERATED_PRECOMPILES: &[PrecompileWithAddress] = &[ - precompile::secp256k1::ECRECOVER, // ecRecover - precompile::bn128::pair::ISTANBUL, // ecPairing + precompile::secp256k1::ECRECOVER, // ecRecover + precompile::bn128::pair::ISTANBUL, // ecPairing + precompile::bls12_381::g1_add::PRECOMPILE, // BLS12-381 G1 Point Addition + precompile::bls12_381::g1_msm::PRECOMPILE, /* BLS12-381 G1 Point Multi-scalar + * Multiplication */ + precompile::bls12_381::g2_add::PRECOMPILE, // BLS12-381 G2 Point Addition + precompile::bls12_381::g2_msm::PRECOMPILE, // BLS12-381 G2 Point Multi-scalar Multiplication + precompile::bls12_381::map_fp2_to_g2::PRECOMPILE, // BLS12-381 FP2 to G2 Point Mapping + precompile::bls12_381::map_fp_to_g1::PRECOMPILE, // BLS12-381 FP to G1 Point Mapping + precompile::bls12_381::pairing::PRECOMPILE, // BLS12-381 pairing precompile::kzg_point_evaluation::POINT_EVALUATION, // KZG point evaluation ]; diff --git a/bin/host/src/fetcher/mod.rs b/bin/host/src/fetcher/mod.rs deleted file mode 100644 index 75a87a801b..0000000000 --- a/bin/host/src/fetcher/mod.rs +++ /dev/null @@ -1,596 +0,0 @@ -//! This module contains the [Fetcher] struct, which is responsible for fetching preimages from a -//! remote source. - -use crate::{blobs::OnlineBlobProvider, kv::KeyValueStore}; -use alloy_consensus::{Header, TxEnvelope, EMPTY_ROOT_HASH}; -use alloy_eips::{ - eip2718::Encodable2718, - eip4844::{IndexedBlobHash, FIELD_ELEMENTS_PER_BLOB}, - BlockId, -}; -use alloy_primitives::{address, keccak256, map::HashMap, Address, Bytes, B256}; -use alloy_provider::{Provider, ReqwestProvider}; -use alloy_rlp::{Decodable, EMPTY_STRING_CODE}; -use alloy_rpc_types::{ - debug::ExecutionWitness, Block, BlockNumberOrTag, BlockTransactions, BlockTransactionsKind, - Transaction, -}; -use anyhow::{anyhow, Result}; -use kona_preimage::{PreimageKey, PreimageKeyType}; -use kona_proof::{Hint, HintType}; -use op_alloy_protocol::BlockInfo; -use op_alloy_rpc_types_engine::OpPayloadAttributes; -use std::sync::Arc; -use tokio::sync::RwLock; -use tracing::{error, trace, warn}; - -mod precompiles; - -/// The [Fetcher] struct is responsible for fetching preimages from a remote source. -#[derive(Debug)] -pub struct Fetcher -where - KV: KeyValueStore + ?Sized, -{ - /// Key-value store for preimages. - kv_store: Arc>, - /// L1 chain provider. - l1_provider: ReqwestProvider, - /// The blob provider - blob_provider: OnlineBlobProvider, - /// L2 chain provider. - l2_provider: ReqwestProvider, - /// L2 head - l2_head: B256, - /// The last hint that was received. [None] if no hint has been received yet. - last_hint: Option, -} - -impl Fetcher -where - KV: KeyValueStore + ?Sized, -{ - /// Create a new [Fetcher] with the given [KeyValueStore]. - pub const fn new( - kv_store: Arc>, - l1_provider: ReqwestProvider, - blob_provider: OnlineBlobProvider, - l2_provider: ReqwestProvider, - l2_head: B256, - ) -> Self { - Self { kv_store, l1_provider, blob_provider, l2_provider, l2_head, last_hint: None } - } - - /// Set the last hint to be received. - pub fn hint(&mut self, hint: &str) { - trace!(target: "fetcher", "Received hint: {hint}"); - self.last_hint = Some(hint.to_string()); - } - - /// Get the preimage for the given key. - pub async fn get_preimage(&self, key: B256) -> Result> { - trace!(target: "fetcher", "Pre-image requested. Key: {key}"); - - // Acquire a read lock on the key-value store. - let kv_lock = self.kv_store.read().await; - let mut preimage = kv_lock.get(key); - - // Drop the read lock before beginning the retry loop. - drop(kv_lock); - - // Use a loop to keep retrying the prefetch as long as the key is not found - while preimage.is_none() && self.last_hint.is_some() { - let hint = self.last_hint.as_ref().expect("Cannot be None"); - - if let Err(e) = self.prefetch(hint).await { - error!(target: "fetcher", "Failed to prefetch hint: {e}"); - warn!(target: "fetcher", "Retrying hint fetch: {hint}"); - continue; - } - - let kv_lock = self.kv_store.read().await; - preimage = kv_lock.get(key); - } - - preimage.ok_or_else(|| anyhow!("Preimage not found.")) - } - - /// Fetch the preimage for the given hint and insert it into the key-value store. - async fn prefetch(&self, hint: &str) -> Result<()> { - let hint = Hint::parse(hint)?; - let (hint_type, hint_data) = hint.split(); - trace!(target: "fetcher", "Fetching hint: {hint_type} {hint_data}"); - - match hint_type { - HintType::L1BlockHeader => { - // Validate the hint data length. - if hint_data.len() != 32 { - anyhow::bail!("Invalid hint data length: {}", hint_data.len()); - } - - // Fetch the raw header from the L1 chain provider. - let hash: B256 = hint_data - .as_ref() - .try_into() - .map_err(|e| anyhow!("Failed to convert bytes to B256: {e}"))?; - let raw_header: Bytes = self - .l1_provider - .client() - .request("debug_getRawHeader", [hash]) - .await - .map_err(|e| anyhow!(e))?; - - // Acquire a lock on the key-value store and set the preimage. - let mut kv_lock = self.kv_store.write().await; - kv_lock.set( - PreimageKey::new(*hash, PreimageKeyType::Keccak256).into(), - raw_header.into(), - )?; - } - HintType::L1Transactions => { - // Validate the hint data length. - if hint_data.len() != 32 { - anyhow::bail!("Invalid hint data length: {}", hint_data.len()); - } - - // Fetch the block from the L1 chain provider and store the transactions within its - // body in the key-value store. - let hash: B256 = hint_data - .as_ref() - .try_into() - .map_err(|e| anyhow!("Failed to convert bytes to B256: {e}"))?; - let Block { transactions, .. } = self - .l1_provider - .get_block_by_hash(hash, BlockTransactionsKind::Full) - .await - .map_err(|e| anyhow!("Failed to fetch block: {e}"))? - .ok_or(anyhow!("Block not found."))?; - self.store_transactions(transactions).await?; - } - HintType::L1Receipts => { - // Validate the hint data length. - if hint_data.len() != 32 { - anyhow::bail!("Invalid hint data length: {}", hint_data.len()); - } - - // Fetch the receipts from the L1 chain provider and store the receipts within the - // key-value store. - let hash: B256 = hint_data - .as_ref() - .try_into() - .map_err(|e| anyhow!("Failed to convert bytes to B256: {e}"))?; - let raw_receipts: Vec = self - .l1_provider - .client() - .request("debug_getRawReceipts", [hash]) - .await - .map_err(|e| anyhow!(e))?; - self.store_trie_nodes(raw_receipts.as_slice()).await?; - } - HintType::L1Blob => { - if hint_data.len() != 48 { - anyhow::bail!("Invalid hint data length: {}", hint_data.len()); - } - - let hash_data_bytes: [u8; 32] = hint_data[0..32] - .try_into() - .map_err(|e| anyhow!("Failed to convert bytes to B256: {e}"))?; - let index_data_bytes: [u8; 8] = hint_data[32..40] - .try_into() - .map_err(|e| anyhow!("Failed to convert bytes to u64: {e}"))?; - let timestamp_data_bytes: [u8; 8] = hint_data[40..48] - .try_into() - .map_err(|e| anyhow!("Failed to convert bytes to u64: {e}"))?; - - let hash: B256 = hash_data_bytes.into(); - let index = u64::from_be_bytes(index_data_bytes); - let timestamp = u64::from_be_bytes(timestamp_data_bytes); - - let partial_block_ref = BlockInfo { timestamp, ..Default::default() }; - let indexed_hash = IndexedBlobHash { index, hash }; - - // Fetch the blob sidecar from the blob provider. - let mut sidecars = self - .blob_provider - .fetch_filtered_sidecars(&partial_block_ref, &[indexed_hash]) - .await - .map_err(|e| anyhow!("Failed to fetch blob sidecars: {e}"))?; - if sidecars.len() != 1 { - anyhow::bail!("Expected 1 sidecar, got {}", sidecars.len()); - } - let sidecar = sidecars.remove(0); - - // Acquire a lock on the key-value store and set the preimages. - let mut kv_write_lock = self.kv_store.write().await; - - // Set the preimage for the blob commitment. - kv_write_lock.set( - PreimageKey::new(*hash, PreimageKeyType::Sha256).into(), - sidecar.kzg_commitment.to_vec(), - )?; - - // Write all the field elements to the key-value store. There should be 4096. - // The preimage oracle key for each field element is the keccak256 hash of - // `abi.encodePacked(sidecar.KZGCommitment, uint256(i))` - let mut blob_key = [0u8; 80]; - blob_key[..48].copy_from_slice(sidecar.kzg_commitment.as_ref()); - for i in 0..FIELD_ELEMENTS_PER_BLOB { - blob_key[72..].copy_from_slice(i.to_be_bytes().as_ref()); - let blob_key_hash = keccak256(blob_key.as_ref()); - - kv_write_lock.set( - PreimageKey::new(*blob_key_hash, PreimageKeyType::Keccak256).into(), - blob_key.into(), - )?; - kv_write_lock.set( - PreimageKey::new(*blob_key_hash, PreimageKeyType::Blob).into(), - sidecar.blob[(i as usize) << 5..(i as usize + 1) << 5].to_vec(), - )?; - } - - // Write the KZG Proof as the 4096th element. - blob_key[72..].copy_from_slice((FIELD_ELEMENTS_PER_BLOB).to_be_bytes().as_ref()); - let blob_key_hash = keccak256(blob_key.as_ref()); - - kv_write_lock.set( - PreimageKey::new(*blob_key_hash, PreimageKeyType::Keccak256).into(), - blob_key.into(), - )?; - kv_write_lock.set( - PreimageKey::new(*blob_key_hash, PreimageKeyType::Blob).into(), - sidecar.kzg_proof.to_vec(), - )?; - } - HintType::L1Precompile => { - // Validate the hint data length. - if hint_data.len() < 20 { - anyhow::bail!("Invalid hint data length: {}", hint_data.len()); - } - - // Fetch the precompile address from the hint data. - let precompile_address = Address::from_slice(&hint_data.as_ref()[..20]); - let precompile_input = hint_data[20..].to_vec(); - let input_hash = keccak256(hint_data.as_ref()); - - let result = precompiles::execute(precompile_address, precompile_input) - .map_or_else( - |_| vec![0u8; 1], - |raw_res| { - let mut res = Vec::with_capacity(1 + raw_res.len()); - res.push(0x01); - res.extend_from_slice(&raw_res); - res - }, - ); - - // Acquire a lock on the key-value store and set the preimages. - let mut kv_lock = self.kv_store.write().await; - kv_lock.set( - PreimageKey::new(*input_hash, PreimageKeyType::Keccak256).into(), - hint_data.into(), - )?; - kv_lock.set( - PreimageKey::new(*input_hash, PreimageKeyType::Precompile).into(), - result, - )?; - } - HintType::L2BlockHeader => { - // Validate the hint data length. - if hint_data.len() != 32 { - anyhow::bail!("Invalid hint data length: {}", hint_data.len()); - } - - // Fetch the raw header from the L2 chain provider. - let hash: B256 = hint_data - .as_ref() - .try_into() - .map_err(|e| anyhow!("Failed to convert bytes to B256: {e}"))?; - let raw_header: Bytes = self - .l2_provider - .client() - .request("debug_getRawHeader", [hash]) - .await - .map_err(|e| anyhow!(e))?; - - // Acquire a lock on the key-value store and set the preimage. - let mut kv_lock = self.kv_store.write().await; - kv_lock.set( - PreimageKey::new(*hash, PreimageKeyType::Keccak256).into(), - raw_header.into(), - )?; - } - HintType::L2Transactions => { - // Validate the hint data length. - if hint_data.len() != 32 { - anyhow::bail!("Invalid hint data length: {}", hint_data.len()); - } - - // Fetch the block from the L2 chain provider and store the transactions within its - // body in the key-value store. - let hash: B256 = hint_data - .as_ref() - .try_into() - .map_err(|e| anyhow!("Failed to convert bytes to B256: {e}"))?; - let Block { transactions, .. } = self - .l2_provider - .get_block_by_hash(hash, BlockTransactionsKind::Hashes) - .await - .map_err(|e| anyhow!("Failed to fetch block: {e}"))? - .ok_or(anyhow!("Block not found."))?; - - match transactions { - BlockTransactions::Hashes(transactions) => { - let mut encoded_transactions = Vec::with_capacity(transactions.len()); - for tx_hash in transactions { - let tx = self - .l2_provider - .client() - .request::<&[B256; 1], Bytes>("debug_getRawTransaction", &[tx_hash]) - .await - .map_err(|e| anyhow!("Error fetching transaction: {e}"))?; - encoded_transactions.push(tx); - } - - self.store_trie_nodes(encoded_transactions.as_slice()).await?; - } - _ => anyhow::bail!("Only BlockTransactions::Hashes are supported."), - }; - } - HintType::L2Code => { - // geth hashdb scheme code hash key prefix - const CODE_PREFIX: u8 = b'c'; - - if hint_data.len() != 32 { - anyhow::bail!("Invalid hint data length: {}", hint_data.len()); - } - - let hash: B256 = hint_data - .as_ref() - .try_into() - .map_err(|e| anyhow!("Failed to convert bytes to B256: {e}"))?; - - // Attempt to fetch the code from the L2 chain provider. - let code_hash = [&[CODE_PREFIX], hash.as_slice()].concat(); - let code = self - .l2_provider - .client() - .request::<&[Bytes; 1], Bytes>("debug_dbGet", &[code_hash.into()]) - .await; - - // Check if the first attempt to fetch the code failed. If it did, try fetching the - // code hash preimage without the geth hashdb scheme prefix. - let code = match code { - Ok(code) => code, - Err(_) => self - .l2_provider - .client() - .request::<&[B256; 1], Bytes>("debug_dbGet", &[hash]) - .await - .map_err(|e| anyhow!("Error fetching code hash preimage: {e}"))?, - }; - - let mut kv_write_lock = self.kv_store.write().await; - kv_write_lock - .set(PreimageKey::new(*hash, PreimageKeyType::Keccak256).into(), code.into())?; - } - HintType::StartingL2Output => { - const OUTPUT_ROOT_VERSION: u8 = 0; - const L2_TO_L1_MESSAGE_PASSER_ADDRESS: Address = - address!("4200000000000000000000000000000000000016"); - - if hint_data.len() != 32 { - anyhow::bail!("Invalid hint data length: {}", hint_data.len()); - } - - // Fetch the header for the L2 head block. - let raw_header: Bytes = self - .l2_provider - .client() - .request("debug_getRawHeader", &[self.l2_head]) - .await - .map_err(|e| anyhow!("Failed to fetch header RLP: {e}"))?; - let header = Header::decode(&mut raw_header.as_ref()) - .map_err(|e| anyhow!("Failed to decode header: {e}"))?; - - // Fetch the storage root for the L2 head block. - let l2_to_l1_message_passer = self - .l2_provider - .get_proof(L2_TO_L1_MESSAGE_PASSER_ADDRESS, Default::default()) - .block_id(BlockId::Hash(self.l2_head.into())) - .await - .map_err(|e| anyhow!("Failed to fetch account proof: {e}"))?; - - let mut raw_output = [0u8; 128]; - raw_output[31] = OUTPUT_ROOT_VERSION; - raw_output[32..64].copy_from_slice(header.state_root.as_ref()); - raw_output[64..96].copy_from_slice(l2_to_l1_message_passer.storage_hash.as_ref()); - raw_output[96..128].copy_from_slice(self.l2_head.as_ref()); - let output_root = keccak256(raw_output); - - if output_root.as_slice() != hint_data.as_ref() { - anyhow::bail!("Output root does not match L2 head."); - } - - let mut kv_write_lock = self.kv_store.write().await; - kv_write_lock.set( - PreimageKey::new(*output_root, PreimageKeyType::Keccak256).into(), - raw_output.into(), - )?; - } - HintType::L2StateNode => { - if hint_data.len() != 32 { - anyhow::bail!("Invalid hint data length: {}", hint_data.len()); - } - - let hash: B256 = hint_data - .as_ref() - .try_into() - .map_err(|e| anyhow!("Failed to convert bytes to B256: {e}"))?; - - // Fetch the preimage from the L2 chain provider. - let preimage: Bytes = self - .l2_provider - .client() - .request("debug_dbGet", &[hash]) - .await - .map_err(|e| anyhow!("Failed to fetch preimage: {e}"))?; - - let mut kv_write_lock = self.kv_store.write().await; - kv_write_lock.set( - PreimageKey::new(*hash, PreimageKeyType::Keccak256).into(), - preimage.into(), - )?; - } - HintType::L2AccountProof => { - if hint_data.len() != 8 + 20 { - anyhow::bail!("Invalid hint data length: {}", hint_data.len()); - } - - let block_number = u64::from_be_bytes( - hint_data.as_ref()[..8] - .try_into() - .map_err(|e| anyhow!("Error converting hint data to u64: {e}"))?, - ); - let address = Address::from_slice(&hint_data.as_ref()[8..28]); - - let proof_response = self - .l2_provider - .get_proof(address, Default::default()) - .block_id(BlockId::Number(BlockNumberOrTag::Number(block_number))) - .await - .map_err(|e| anyhow!("Failed to fetch account proof: {e}"))?; - - let mut kv_write_lock = self.kv_store.write().await; - - // Write the account proof nodes to the key-value store. - proof_response.account_proof.into_iter().try_for_each(|node| { - let node_hash = keccak256(node.as_ref()); - let key = PreimageKey::new(*node_hash, PreimageKeyType::Keccak256); - kv_write_lock.set(key.into(), node.into())?; - Ok::<(), anyhow::Error>(()) - })?; - } - HintType::L2AccountStorageProof => { - if hint_data.len() != 8 + 20 + 32 { - anyhow::bail!("Invalid hint data length: {}", hint_data.len()); - } - - let block_number = u64::from_be_bytes( - hint_data.as_ref()[..8] - .try_into() - .map_err(|e| anyhow!("Error converting hint data to u64: {e}"))?, - ); - let address = Address::from_slice(&hint_data.as_ref()[8..28]); - let slot = B256::from_slice(&hint_data.as_ref()[28..]); - - let mut proof_response = self - .l2_provider - .get_proof(address, vec![slot]) - .block_id(BlockId::Number(BlockNumberOrTag::Number(block_number))) - .await - .map_err(|e| anyhow!("Failed to fetch account proof: {e}"))?; - - let mut kv_write_lock = self.kv_store.write().await; - - // Write the account proof nodes to the key-value store. - proof_response.account_proof.into_iter().try_for_each(|node| { - let node_hash = keccak256(node.as_ref()); - let key = PreimageKey::new(*node_hash, PreimageKeyType::Keccak256); - kv_write_lock.set(key.into(), node.into())?; - Ok::<(), anyhow::Error>(()) - })?; - - // Write the storage proof nodes to the key-value store. - let storage_proof = proof_response.storage_proof.remove(0); - storage_proof.proof.into_iter().try_for_each(|node| { - let node_hash = keccak256(node.as_ref()); - let key = PreimageKey::new(*node_hash, PreimageKeyType::Keccak256); - kv_write_lock.set(key.into(), node.into())?; - Ok::<(), anyhow::Error>(()) - })?; - } - HintType::L2PayloadWitness => { - if hint_data.len() < 32 { - anyhow::bail!("Invalid hint data length: {}", hint_data.len()); - } - let parent_block_hash = B256::from_slice(&hint_data.as_ref()[..32]); - let payload_attributes: OpPayloadAttributes = - serde_json::from_slice(&hint_data[32..])?; - - let execute_payload_response: ExecutionWitness = self - .l2_provider - .client() - .request::<(B256, OpPayloadAttributes), ExecutionWitness>( - "debug_executePayload", - (parent_block_hash, payload_attributes), - ) - .await - .map_err(|e| anyhow!("Failed to fetch preimage: {e}"))?; - - let mut merged = HashMap::::default(); - merged.extend(execute_payload_response.state); - merged.extend(execute_payload_response.codes); - merged.extend(execute_payload_response.keys); - - let mut kv_write_lock = self.kv_store.write().await; - for (hash, preimage) in merged.into_iter() { - let computed_hash = keccak256(preimage.as_ref()); - assert_eq!(computed_hash, hash, "Preimage hash does not match expected hash"); - - let key = PreimageKey::new(*hash, PreimageKeyType::Keccak256); - kv_write_lock.set(key.into(), preimage.into())?; - } - } - } - - Ok(()) - } - - /// Stores a list of [BlockTransactions] in the key-value store. - async fn store_transactions(&self, transactions: BlockTransactions) -> Result<()> { - match transactions { - BlockTransactions::Full(transactions) => { - let encoded_transactions = transactions - .into_iter() - .map(|tx| { - let envelope: TxEnvelope = tx.into(); - - Ok::<_, anyhow::Error>(envelope.encoded_2718()) - }) - .collect::>>()?; - - self.store_trie_nodes(encoded_transactions.as_slice()).await - } - _ => anyhow::bail!("Only BlockTransactions::Full are supported."), - } - } - - /// Stores intermediate trie nodes in the key-value store. Assumes that all nodes passed are - /// raw, RLP encoded trie nodes. - async fn store_trie_nodes>(&self, nodes: &[T]) -> Result<()> { - let mut kv_write_lock = self.kv_store.write().await; - - // If the list of nodes is empty, store the empty root hash and exit early. - // The `HashBuilder` will not push the preimage of the empty root hash to the - // `ProofRetainer` in the event that there are no leaves inserted. - if nodes.is_empty() { - let empty_key = PreimageKey::new(*EMPTY_ROOT_HASH, PreimageKeyType::Keccak256); - return kv_write_lock.set(empty_key.into(), [EMPTY_STRING_CODE].into()); - } - - let mut hb = kona_mpt::ordered_trie_with_encoder(nodes, |node, buf| { - buf.put_slice(node.as_ref()); - }); - hb.root(); - let intermediates = hb.take_proof_nodes().into_inner(); - - for (_, value) in intermediates.into_iter() { - let value_hash = keccak256(value.as_ref()); - let key = PreimageKey::new(*value_hash, PreimageKeyType::Keccak256); - - kv_write_lock.set(key.into(), value.into())?; - } - - Ok(()) - } -} diff --git a/bin/host/src/kv/mod.rs b/bin/host/src/kv/mod.rs index 78ef8c4fa4..65f41bce35 100644 --- a/bin/host/src/kv/mod.rs +++ b/bin/host/src/kv/mod.rs @@ -14,9 +14,6 @@ pub use disk::DiskKeyValueStore; mod split; pub use split::SplitKeyValueStore; -mod local; -pub use local::LocalKeyValueStore; - /// A type alias for a shared key-value store. pub type SharedKeyValueStore = Arc>; diff --git a/bin/host/src/lib.rs b/bin/host/src/lib.rs index 0337777c91..e68d6416e9 100644 --- a/bin/host/src/lib.rs +++ b/bin/host/src/lib.rs @@ -1,122 +1,22 @@ #![doc = include_str!("../README.md")] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] -#![cfg_attr(not(test), warn(unused_crate_dependencies))] -pub mod blobs; -pub mod cli; -pub use cli::{init_tracing_subscriber, HostCli}; - -pub mod fetcher; -pub mod kv; -pub mod preimage; -pub mod server; +mod server; +pub use server::PreimageServer; -use anyhow::Result; -use fetcher::Fetcher; -use kona_preimage::{ - BidirectionalChannel, HintReader, HintWriter, NativeChannel, OracleReader, OracleServer, +mod kv; +pub use kv::{ + DiskKeyValueStore, KeyValueStore, MemoryKeyValueStore, SharedKeyValueStore, SplitKeyValueStore, }; -use kona_std_fpvm::{FileChannel, FileDescriptor}; -use kv::KeyValueStore; -use server::PreimageServer; -use std::sync::Arc; -use tokio::{sync::RwLock, task}; -use tracing::info; - -/// Starts the [PreimageServer] in the primary thread. In this mode, the host program has been -/// invoked by the Fault Proof VM and the client program is running in the parent process. -pub async fn start_server(cfg: HostCli) -> Result<()> { - let (preimage_chan, hint_chan) = ( - FileChannel::new(FileDescriptor::PreimageRead, FileDescriptor::PreimageWrite), - FileChannel::new(FileDescriptor::HintRead, FileDescriptor::HintWrite), - ); - let oracle_server = OracleServer::new(preimage_chan); - let hint_reader = HintReader::new(hint_chan); - let kv_store = cfg.construct_kv_store(); - let fetcher = if !cfg.is_offline() { - let (l1_provider, blob_provider, l2_provider) = cfg.create_providers().await?; - Some(Arc::new(RwLock::new(Fetcher::new( - kv_store.clone(), - l1_provider, - blob_provider, - l2_provider, - cfg.agreed_l2_head_hash, - )))) - } else { - None - }; - - // Start the server and wait for it to complete. - info!("Starting preimage server."); - PreimageServer::new(oracle_server, hint_reader, kv_store, fetcher).start().await?; - info!("Preimage server has exited."); - - Ok(()) -} -/// Starts the [PreimageServer] and the client program in separate threads. The client program is -/// ran natively in this mode. -/// -/// ## Takes -/// - `cfg`: The host configuration. -/// -/// ## Returns -/// - `Ok(exit_code)` if the client program exits successfully. -/// - `Err(_)` if the client program failed to execute, was killed by a signal, or the host program -/// exited first. -pub async fn start_server_and_native_client(cfg: HostCli) -> Result { - let hint_chan = BidirectionalChannel::new()?; - let preimage_chan = BidirectionalChannel::new()?; - let kv_store = cfg.construct_kv_store(); - let fetcher = if !cfg.is_offline() { - let (l1_provider, blob_provider, l2_provider) = cfg.create_providers().await?; - Some(Arc::new(RwLock::new(Fetcher::new( - kv_store.clone(), - l1_provider, - blob_provider, - l2_provider, - cfg.agreed_l2_head_hash, - )))) - } else { - None - }; +mod backend; +pub use backend::{HintHandler, OfflineHostBackend, OnlineHostBackend, OnlineHostBackendCfg}; - // Create the server and start it. - let server_task = task::spawn(start_native_preimage_server( - kv_store, - fetcher, - hint_chan.host, - preimage_chan.host, - )); - - // Start the client program in a separate child process. - let program_task = task::spawn(kona_client::run( - OracleReader::new(preimage_chan.client), - HintWriter::new(hint_chan.client), - None, - )); - - // Execute both tasks and wait for them to complete. - info!("Starting preimage server and client program."); - let (_, client_result) = tokio::try_join!(server_task, program_task,)?; - info!(target: "kona_host", "Preimage server and client program have joined."); - - Ok(client_result.is_err() as i32) -} +pub mod cli; -/// Starts the preimage server in a separate thread. The client program is ran natively in this -/// mode. -pub async fn start_native_preimage_server( - kv_store: Arc>, - fetcher: Option>>>, - hint_chan: NativeChannel, - preimage_chan: NativeChannel, -) -> Result<()> -where - KV: KeyValueStore + Send + Sync + ?Sized + 'static, -{ - let hint_reader = HintReader::new(hint_chan); - let oracle_server = OracleServer::new(preimage_chan); +pub mod eth; - PreimageServer::new(oracle_server, hint_reader, kv_store, fetcher).start().await -} +#[cfg(feature = "single")] +pub mod single; +mod witness; +pub use witness::{EigenDABlobWitness}; diff --git a/bin/host/src/main.rs b/bin/host/src/main.rs deleted file mode 100644 index d6992589f1..0000000000 --- a/bin/host/src/main.rs +++ /dev/null @@ -1,30 +0,0 @@ -//! Main entrypoint for the host binary. - -use anyhow::Result; -use clap::Parser; -use kona_host::{init_tracing_subscriber, start_server, start_server_and_native_client, HostCli}; -use tracing::{error, info}; - -#[tokio::main(flavor = "multi_thread")] -async fn main() -> Result<()> { - let cfg = HostCli::parse(); - init_tracing_subscriber(cfg.v)?; - - if cfg.server { - start_server(cfg).await?; - } else { - let status = match start_server_and_native_client(cfg).await { - Ok(status) => status, - Err(e) => { - error!(target: "kona_host", "Exited with an error: {:?}", e); - panic!("{e}"); - } - }; - - // Bubble up the exit status of the client program. - std::process::exit(status as i32); - } - - info!("Exiting host program."); - Ok(()) -} diff --git a/bin/host/src/preimage.rs b/bin/host/src/preimage.rs deleted file mode 100644 index d184016f25..0000000000 --- a/bin/host/src/preimage.rs +++ /dev/null @@ -1,115 +0,0 @@ -//! Contains the implementations of the [HintRouter] and [PreimageFetcher] traits.] - -use crate::{fetcher::Fetcher, kv::KeyValueStore}; -use async_trait::async_trait; -use kona_preimage::{ - errors::{PreimageOracleError, PreimageOracleResult}, - HintRouter, PreimageFetcher, PreimageKey, -}; -use std::sync::Arc; -use tokio::sync::RwLock; - -/// A [Fetcher]-backed implementation of the [PreimageFetcher] trait. -#[derive(Debug)] -pub struct OnlinePreimageFetcher -where - KV: KeyValueStore + ?Sized, -{ - inner: Arc>>, -} - -#[async_trait] -impl PreimageFetcher for OnlinePreimageFetcher -where - KV: KeyValueStore + Send + Sync + ?Sized, -{ - async fn get_preimage(&self, key: PreimageKey) -> PreimageOracleResult> { - let fetcher = self.inner.read().await; - fetcher - .get_preimage(key.into()) - .await - .map_err(|e| PreimageOracleError::Other(e.to_string())) - } -} - -impl OnlinePreimageFetcher -where - KV: KeyValueStore + ?Sized, -{ - /// Create a new [OnlinePreimageFetcher] from the given [Fetcher]. - pub const fn new(fetcher: Arc>>) -> Self { - Self { inner: fetcher } - } -} - -/// A [KeyValueStore]-backed implementation of the [PreimageFetcher] trait. -#[derive(Debug)] -pub struct OfflinePreimageFetcher -where - KV: KeyValueStore + ?Sized, -{ - inner: Arc>, -} - -#[async_trait] -impl PreimageFetcher for OfflinePreimageFetcher -where - KV: KeyValueStore + Send + Sync + ?Sized, -{ - async fn get_preimage(&self, key: PreimageKey) -> PreimageOracleResult> { - let kv_store = self.inner.read().await; - kv_store.get(key.into()).ok_or(PreimageOracleError::KeyNotFound) - } -} - -impl OfflinePreimageFetcher -where - KV: KeyValueStore + ?Sized, -{ - /// Create a new [OfflinePreimageFetcher] from the given [KeyValueStore]. - pub const fn new(kv_store: Arc>) -> Self { - Self { inner: kv_store } - } -} - -/// A [Fetcher]-backed implementation of the [HintRouter] trait. -#[derive(Debug)] -pub struct OnlineHintRouter -where - KV: KeyValueStore + ?Sized, -{ - inner: Arc>>, -} - -#[async_trait] -impl HintRouter for OnlineHintRouter -where - KV: KeyValueStore + Send + Sync + ?Sized, -{ - async fn route_hint(&self, hint: String) -> PreimageOracleResult<()> { - let mut fetcher = self.inner.write().await; - fetcher.hint(&hint); - Ok(()) - } -} - -impl OnlineHintRouter -where - KV: KeyValueStore + ?Sized, -{ - /// Create a new [OnlineHintRouter] from the given [Fetcher]. - pub const fn new(fetcher: Arc>>) -> Self { - Self { inner: fetcher } - } -} - -/// An [OfflineHintRouter] is a [HintRouter] that does nothing. -#[derive(Debug)] -pub struct OfflineHintRouter; - -#[async_trait] -impl HintRouter for OfflineHintRouter { - async fn route_hint(&self, _hint: String) -> PreimageOracleResult<()> { - Ok(()) - } -} diff --git a/bin/host/src/server.rs b/bin/host/src/server.rs index 5d857676be..f1601bbd9b 100644 --- a/bin/host/src/server.rs +++ b/bin/host/src/server.rs @@ -1,70 +1,44 @@ //! This module contains the [PreimageServer] struct and its implementation. -use crate::{ - fetcher::Fetcher, - kv::KeyValueStore, - preimage::{ - OfflineHintRouter, OfflinePreimageFetcher, OnlineHintRouter, OnlinePreimageFetcher, - }, -}; use anyhow::{anyhow, Result}; use kona_preimage::{ - errors::PreimageOracleError, HintReaderServer, HintRouter, PreimageFetcher, - PreimageOracleServer, + errors::PreimageOracleError, HintReaderServer, PreimageOracleServer, PreimageServerBackend, }; use std::sync::Arc; -use tokio::{spawn, sync::RwLock}; +use tokio::spawn; use tracing::{error, info}; /// The [PreimageServer] is responsible for waiting for incoming preimage requests and /// serving them to the client. #[derive(Debug)] -pub struct PreimageServer -where - P: PreimageOracleServer, - H: HintReaderServer, - KV: KeyValueStore + ?Sized, -{ +pub struct PreimageServer { /// The oracle server. oracle_server: P, /// The hint router. hint_reader: H, - /// Key-value store for preimages. - kv_store: Arc>, - /// The fetcher for fetching preimages from a remote source. If [None], the server will only - /// serve preimages that are already in the key-value store. - fetcher: Option>>>, + /// [PreimageServerBackend] that routes hints and retrieves preimages. + backend: Arc, } -impl PreimageServer +impl PreimageServer where P: PreimageOracleServer + Send + Sync + 'static, H: HintReaderServer + Send + Sync + 'static, - KV: KeyValueStore + Send + Sync + ?Sized + 'static, + B: PreimageServerBackend + Send + Sync + 'static, { /// Create a new [PreimageServer] with the given [PreimageOracleServer], - /// [HintReaderServer], and [KeyValueStore]. Holds onto the file descriptors for the pipes - /// that are created, so that the pipes are not closed until the server is dropped. - pub const fn new( - oracle_server: P, - hint_reader: H, - kv_store: Arc>, - fetcher: Option>>>, - ) -> Self { - Self { oracle_server, hint_reader, kv_store, fetcher } + /// [HintReaderServer], and [PreimageServerBackend]. + pub const fn new(oracle_server: P, hint_reader: H, backend: Arc) -> Self { + Self { oracle_server, hint_reader, backend } } /// Starts the [PreimageServer] and waits for incoming requests. pub async fn start(self) -> Result<()> { // Create the futures for the oracle server and hint router. - let server = spawn(Self::start_oracle_server( - self.kv_store.clone(), - self.fetcher.clone(), - self.oracle_server, - )); - let hint_router = spawn(Self::start_hint_router(self.hint_reader, self.fetcher)); + let server = spawn(Self::start_oracle_server(self.oracle_server, self.backend.clone())); + let hint_router = spawn(Self::start_hint_router(self.hint_reader, self.backend.clone())); - // Spawn tasks for the futures and wait for them to complete. + // Race the two futures to completion, returning the result of the first one to finish. tokio::select! { s = server => s.map_err(|e| anyhow!(e))?, h = hint_router => h.map_err(|e| anyhow!(e))?, @@ -73,66 +47,37 @@ where /// Starts the oracle server, which waits for incoming preimage requests and serves them to the /// client. - async fn start_oracle_server( - kv_store: Arc>, - fetcher: Option>>>, - oracle_server: P, - ) -> Result<()> { - #[inline(always)] - async fn do_loop(fetcher: &F, server: &P) -> Result<()> - where - F: PreimageFetcher + Send + Sync, - P: PreimageOracleServer, - { - loop { - match server.next_preimage_request(fetcher).await { - Ok(_) => continue, - Err(PreimageOracleError::IOError(_)) => return Ok(()), - Err(e) => { - error!("Failed to serve preimage request: {e}"); - return Err(anyhow!("Failed to serve preimage request: {e}")); - } + async fn start_oracle_server(oracle_server: P, backend: Arc) -> Result<()> { + info!(target: "host-server", "Starting oracle server"); + loop { + // Serve the next preimage request. This `await` will yield to the runtime + // if no progress can be made. + match oracle_server.next_preimage_request(backend.as_ref()).await { + Ok(_) => continue, + Err(PreimageOracleError::IOError(_)) => return Ok(()), + Err(e) => { + error!("Failed to serve preimage request: {e}"); + return Err(anyhow!("Failed to serve preimage request: {e}")); } } } - - info!("Starting oracle server"); - if let Some(fetcher) = fetcher.as_ref() { - do_loop(&OnlinePreimageFetcher::new(Arc::clone(fetcher)), &oracle_server).await - } else { - do_loop(&OfflinePreimageFetcher::new(Arc::clone(&kv_store)), &oracle_server).await - } } /// Starts the hint router, which waits for incoming hints and routes them to the appropriate /// handler. - async fn start_hint_router( - hint_reader: H, - fetcher: Option>>>, - ) -> Result<()> { - #[inline(always)] - async fn do_loop(router: &R, server: &H) -> Result<()> - where - R: HintRouter + Send + Sync, - H: HintReaderServer, - { - loop { - match server.next_hint(router).await { - Ok(_) => continue, - Err(PreimageOracleError::IOError(_)) => return Ok(()), - Err(e) => { - error!("Failed to serve route hint: {e}"); - return Err(anyhow!("Failed to route hint: {e}")); - } + async fn start_hint_router(hint_reader: H, backend: Arc) -> Result<()> { + info!(target: "host-server", "Starting hint router"); + loop { + // Route the next hint. This `await` will yield to the runtime if no progress can be + // made. + match hint_reader.next_hint(backend.as_ref()).await { + Ok(_) => continue, + Err(PreimageOracleError::IOError(_)) => return Ok(()), + Err(e) => { + error!("Failed to serve route hint: {e}"); + return Err(anyhow!("Failed to route hint: {e}")); } } } - - info!("Starting hint router"); - if let Some(fetcher) = fetcher.as_ref() { - do_loop(&OnlineHintRouter::new(Arc::clone(fetcher)), &hint_reader).await - } else { - do_loop(&OfflineHintRouter, &hint_reader).await - } } } diff --git a/bin/host/src/single/cfg.rs b/bin/host/src/single/cfg.rs new file mode 100644 index 0000000000..0ca4f36cb9 --- /dev/null +++ b/bin/host/src/single/cfg.rs @@ -0,0 +1,389 @@ +//! This module contains all CLI-specific code for the single chain entrypoint. + +use super::{SingleChainHintHandler, SingleChainLocalInputs}; +use crate::{ + cli::{cli_styles, parser::parse_b256}, + eth::http_provider, + DiskKeyValueStore, MemoryKeyValueStore, OfflineHostBackend, OnlineHostBackend, + OnlineHostBackendCfg, PreimageServer, SharedKeyValueStore, SplitKeyValueStore, +}; +use alloy_primitives::B256; +use alloy_provider::RootProvider; +use anyhow::{anyhow, Result}; +use clap::Parser; +use eigen_da::EigenDaConfig; +use kona_preimage::{ + BidirectionalChannel, Channel, HintReader, HintWriter, OracleReader, OracleServer, +}; +use kona_proof::HintType; +use kona_providers_alloy::{ + EigenDaProxy, OnlineBeaconClient, OnlineBlobProvider, OnlineEigenDaProvider, +}; +use kona_std_fpvm::{FileChannel, FileDescriptor}; +use op_alloy_genesis::RollupConfig; +use op_alloy_network::Optimism; +use serde::Serialize; +use std::time::Duration; +use std::{path::PathBuf, sync::Arc}; +use tokio::{ + sync::RwLock, + task::{self, JoinHandle}, +}; + +/// The host binary CLI application arguments. +#[derive(Default, Parser, Serialize, Clone, Debug)] +#[command(styles = cli_styles())] +pub struct SingleChainHost { + /// Hash of the L1 head block. Derivation stops after this block is processed. + #[clap(long, value_parser = parse_b256, env)] + pub l1_head: B256, + /// Hash of the agreed upon safe L2 block committed to by `--agreed-l2-output-root`. + #[clap(long, visible_alias = "l2-head", value_parser = parse_b256, env)] + pub agreed_l2_head_hash: B256, + /// Agreed safe L2 Output Root to start derivation from. + #[clap(long, visible_alias = "l2-output-root", value_parser = parse_b256, env)] + pub agreed_l2_output_root: B256, + /// Claimed L2 output root at block # `--claimed-l2-block-number` to validate. + #[clap(long, visible_alias = "l2-claim", value_parser = parse_b256, env)] + pub claimed_l2_output_root: B256, + /// Number of the L2 block that the claimed output root commits to. + #[clap(long, visible_alias = "l2-block-number", env)] + pub claimed_l2_block_number: u64, + /// Address of L2 JSON-RPC endpoint to use (eth and debug namespace required). + #[clap( + long, + visible_alias = "l2", + requires = "l1_node_address", + requires = "l1_beacon_address", + env + )] + pub l2_node_address: Option, + /// Address of L1 JSON-RPC endpoint to use (eth and debug namespace required) + #[clap( + long, + visible_alias = "l1", + requires = "l2_node_address", + requires = "l1_beacon_address", + env + )] + pub l1_node_address: Option, + /// Address of the L1 Beacon API endpoint to use. + #[clap( + long, + visible_alias = "beacon", + requires = "l1_node_address", + requires = "l2_node_address", + env + )] + pub l1_beacon_address: Option, + /// The Data Directory for preimage data storage. Optional if running in online mode, + /// required if running in offline mode. + #[clap( + long, + visible_alias = "db", + required_unless_present_all = ["l2_node_address", "l1_node_address", "l1_beacon_address"], + env + )] + pub data_dir: Option, + /// Run the client program natively. + #[clap(long, conflicts_with = "server", required_unless_present = "server")] + pub native: bool, + /// Run in pre-image server mode without executing any client program. If not provided, the + /// host will run the client program in the host process. + #[clap(long, conflicts_with = "native", required_unless_present = "native")] + pub server: bool, + /// The L2 chain ID of a supported chain. If provided, the host will look for the corresponding + /// rollup config in the superchain registry. + #[clap( + long, + conflicts_with = "rollup_config_path", + required_unless_present = "rollup_config_path", + env + )] + pub l2_chain_id: Option, + /// Path to rollup config. If provided, the host will use this config instead of attempting to + /// look up the config in the superchain registry. + #[clap( + long, + alias = "rollup-cfg", + conflicts_with = "l2_chain_id", + required_unless_present = "l2_chain_id", + env + )] + pub rollup_config_path: Option, + /// The url of Mantle da indexer. + #[clap(long, alias = "da-indexer-url", env)] + pub mantle_da_indexer_url: Option, + /// The url of EigenDA Proxy service + #[clap( + long, + alias = "proxy-url", + conflicts_with = "mantle_da_indexer_url", + required_unless_present = "mantle_da_indexer_url", + env + )] + pub proxy_url: Option, + /// EigenDA Disperser RPC URL + /// does not need to be configured in derive. + #[clap(long, alias = "disperse-url", conflicts_with = "mantle_da_indexer_url", env)] + pub disperse_url: Option, + /// The total amount of time that the batcher will spend waiting for EigenDA to disperse a blob + /// does not need to be configured in derive. + #[clap(long, + alias = "disperse-timeout", + conflicts_with = "mantle_da_indexer_url", + default_value = "120", + value_parser = parse_duration, + env + )] + pub disperse_timeout: Duration, + /// The total amount of time that the batcher will spend waiting for EigenDA to retrieve a blob + #[clap(long, + alias = "retrieve-timeout", + conflicts_with = "mantle_da_indexer_url", + default_value = "120", + value_parser = parse_duration, + env + )] + pub retrieve_timeout: Duration, +} + +fn parse_duration(input: &str) -> Result { + input + .parse::() + .map(Duration::from_secs) + .map_err(|e| format!("Failed to parse duration: {}", e)) +} + +impl SingleChainHost { + /// Starts the [SingleChainHost] application. + pub async fn start(self) -> Result<()> { + if self.server { + let hint = FileChannel::new(FileDescriptor::HintRead, FileDescriptor::HintWrite); + let preimage = + FileChannel::new(FileDescriptor::PreimageRead, FileDescriptor::PreimageWrite); + + self.start_server(hint, preimage).await?.await? + } else { + self.start_native().await + } + } + + /// Starts the preimage server, communicating with the client over the provided channels. + pub async fn start_server(&self, hint: C, preimage: C) -> Result>> + where + C: Channel + Send + Sync + 'static, + { + let kv_store = self.create_key_value_store()?; + + let task_handle = if self.is_offline() { + task::spawn( + PreimageServer::new( + OracleServer::new(preimage), + HintReader::new(hint), + Arc::new(OfflineHostBackend::new(kv_store)), + ) + .start(), + ) + } else { + let providers = self.create_providers().await?; + let backend = OnlineHostBackend::new( + self.clone(), + kv_store.clone(), + providers, + SingleChainHintHandler, + ); + + task::spawn( + PreimageServer::new( + OracleServer::new(preimage), + HintReader::new(hint), + Arc::new(backend), + ) + .start(), + ) + }; + + Ok(task_handle) + } + + /// Starts the host in native mode, running both the client and preimage server in the same + /// process. + async fn start_native(&self) -> Result<()> { + let hint = BidirectionalChannel::new()?; + let preimage = BidirectionalChannel::new()?; + + let server_task = self.start_server(hint.host, preimage.host).await?; + let client_task = task::spawn(kona_client::single::run( + OracleReader::new(preimage.client), + HintWriter::new(hint.client), + None, + )); + + let (_, client_result) = tokio::try_join!(server_task, client_task)?; + + // Bubble up the exit status of the client program if execution completes. + std::process::exit(client_result.is_err() as i32) + } + + /// Returns `true` if the host is running in offline mode. + pub const fn is_offline(&self) -> bool { + self.l1_node_address.is_none() + && self.l2_node_address.is_none() + && self.l1_beacon_address.is_none() + && self.data_dir.is_some() + } + + /// Reads the [RollupConfig] from the file system and returns it as a string. + pub fn read_rollup_config(&self) -> Result { + let path = self.rollup_config_path.as_ref().ok_or_else(|| { + anyhow::anyhow!( + "No rollup config path provided. Please provide a path to the rollup config." + ) + })?; + + // Read the serialized config from the file system. + let ser_config = std::fs::read_to_string(path) + .map_err(|e| anyhow!("Error reading RollupConfig file: {e}"))?; + + // Deserialize the config and return it. + serde_json::from_str(&ser_config) + .map_err(|e| anyhow!("Error deserializing RollupConfig: {e}")) + } + + /// Creates the key-value store for the host backend. + fn create_key_value_store(&self) -> Result { + let local_kv_store = SingleChainLocalInputs::new(self.clone()); + + let kv_store: SharedKeyValueStore = if let Some(ref data_dir) = self.data_dir { + let disk_kv_store = DiskKeyValueStore::new(data_dir.clone()); + let split_kv_store = SplitKeyValueStore::new(local_kv_store, disk_kv_store); + Arc::new(RwLock::new(split_kv_store)) + } else { + let mem_kv_store = MemoryKeyValueStore::new(); + let split_kv_store = SplitKeyValueStore::new(local_kv_store, mem_kv_store); + Arc::new(RwLock::new(split_kv_store)) + }; + + Ok(kv_store) + } + + /// Creates the providers required for the host backend. + async fn create_providers(&self) -> Result { + let l1_provider = + http_provider(self.l1_node_address.as_ref().ok_or(anyhow!("Provider must be set"))?); + let blob_provider = OnlineBlobProvider::init(OnlineBeaconClient::new_http( + self.l1_beacon_address.clone().ok_or(anyhow!("Beacon API URL must be set"))?, + )) + .await; + let l2_provider = http_provider::( + self.l2_node_address.as_ref().ok_or(anyhow!("L2 node address must be set"))?, + ); + + let mut eigen_da_config = EigenDaConfig::default(); + let mut eigen_proxy_url = "".to_string(); + let da_indexer_url = "".to_string(); + let mantle_da_indexer = false; + + if da_indexer_url.is_empty() { + eigen_proxy_url = + self.proxy_url.clone().ok_or(anyhow!("EigenDA Proxy URL must be set"))?; + } + eigen_da_config.proxy_url = eigen_proxy_url; + eigen_da_config.retrieve_blob_timeout = self.retrieve_timeout; + let eigen_da_provider = EigenDaProxy::new(eigen_da_config); + let eigen_da = + OnlineEigenDaProvider::new(eigen_da_provider, da_indexer_url, mantle_da_indexer); + + Ok(SingleChainProviders { + l1: l1_provider, + blobs: blob_provider, + l2: l2_provider, + eigen_da, + }) + } +} + +impl OnlineHostBackendCfg for SingleChainHost { + type HintType = HintType; + type Providers = SingleChainProviders; +} + +/// The providers required for the single chain host. +#[derive(Debug, Clone)] +pub struct SingleChainProviders { + /// The L1 EL provider. + pub l1: RootProvider, + /// The L1 beacon node provider. + pub blobs: OnlineBlobProvider, + /// The L2 EL provider. + pub l2: RootProvider, + /// The EigenDa provider. + pub eigen_da: OnlineEigenDaProvider, +} + +#[cfg(test)] +mod test { + use crate::single::SingleChainHost; + use alloy_primitives::B256; + use clap::Parser; + + #[test] + fn test_flags() { + let zero_hash_str = &B256::ZERO.to_string(); + let default_flags = [ + "single", + "--l1-head", + zero_hash_str, + "--l2-head", + zero_hash_str, + "--l2-output-root", + zero_hash_str, + "--l2-claim", + zero_hash_str, + "--l2-block-number", + "0", + ]; + + let cases = [ + // valid + (["--server", "--l2-chain-id", "0", "--data-dir", "dummy"].as_slice(), true), + (["--server", "--rollup-config-path", "dummy", "--data-dir", "dummy"].as_slice(), true), + (["--native", "--l2-chain-id", "0", "--data-dir", "dummy"].as_slice(), true), + (["--native", "--rollup-config-path", "dummy", "--data-dir", "dummy"].as_slice(), true), + ( + [ + "--l1-node-address", + "dummy", + "--l2-node-address", + "dummy", + "--l1-beacon-address", + "dummy", + "--server", + "--l2-chain-id", + "0", + ] + .as_slice(), + true, + ), + // invalid + (["--server", "--native", "--l2-chain-id", "0"].as_slice(), false), + (["--l2-chain-id", "0", "--rollup-config-path", "dummy", "--server"].as_slice(), false), + (["--server"].as_slice(), false), + (["--native"].as_slice(), false), + (["--rollup-config-path", "dummy"].as_slice(), false), + (["--l2-chain-id", "0"].as_slice(), false), + (["--l1-node-address", "dummy", "--server", "--l2-chain-id", "0"].as_slice(), false), + (["--l2-node-address", "dummy", "--server", "--l2-chain-id", "0"].as_slice(), false), + (["--l1-beacon-address", "dummy", "--server", "--l2-chain-id", "0"].as_slice(), false), + ([].as_slice(), false), + ]; + + for (args_ext, valid) in cases.into_iter() { + let args = default_flags.iter().chain(args_ext.iter()).cloned().collect::>(); + + let parsed = SingleChainHost::try_parse_from(args); + assert_eq!(parsed.is_ok(), valid); + } + } +} diff --git a/bin/host/src/single/handler.rs b/bin/host/src/single/handler.rs new file mode 100644 index 0000000000..0c798888b2 --- /dev/null +++ b/bin/host/src/single/handler.rs @@ -0,0 +1,483 @@ +//! [HintHandler] for the [SingleChainHost]. + +use crate::{ + backend::util::store_ordered_trie, kv::SharedKeyValueStore, single::cfg::SingleChainHost, + EigenDABlobWitness, HintHandler, OnlineHostBackendCfg, +}; +use alloy_consensus::Header; +use alloy_eips::{ + eip2718::Encodable2718, + eip4844::{IndexedBlobHash, FIELD_ELEMENTS_PER_BLOB}, +}; +use alloy_primitives::{address, keccak256, Address, Bytes, B256}; +use alloy_provider::Provider; +use alloy_rlp::Decodable; +use alloy_rpc_types::{debug::ExecutionWitness, Block, BlockTransactionsKind}; +use anyhow::{anyhow, ensure, Result}; +use async_trait::async_trait; +use eigen_da::{BlobInfo, EigenDABlobData, BYTES_PER_FIELD_ELEMENT}; +use kona_preimage::{PreimageKey, PreimageKeyType}; +use kona_proof::{Hint, HintType}; +use op_alloy_protocol::BlockInfo; +use op_alloy_rpc_types_engine::OpPayloadAttributes; +use std::collections::HashMap; +use tracing::{debug, info}; + +/// The [HintHandler] for the [SingleChainHost]. +#[derive(Debug, Clone, Copy)] +pub struct SingleChainHintHandler; + +#[async_trait] +impl HintHandler for SingleChainHintHandler { + type Cfg = SingleChainHost; + + async fn fetch_hint( + hint: Hint<::HintType>, + cfg: &Self::Cfg, + providers: &::Providers, + kv: SharedKeyValueStore, + ) -> Result<()> { + match hint.ty { + HintType::L1BlockHeader => { + ensure!(hint.data.len() == 32, "Invalid hint data length"); + + let hash: B256 = hint.data.as_ref().try_into()?; + let raw_header: Bytes = + providers.l1.client().request("debug_getRawHeader", [hash]).await?; + + let mut kv_lock = kv.write().await; + kv_lock.set(PreimageKey::new_keccak256(*hash).into(), raw_header.into())?; + } + HintType::L1Transactions => { + ensure!(hint.data.len() == 32, "Invalid hint data length"); + + let hash: B256 = hint.data.as_ref().try_into()?; + let Block { transactions, .. } = providers + .l1 + .get_block_by_hash(hash, BlockTransactionsKind::Full) + .await? + .ok_or(anyhow!("Block not found"))?; + let encoded_transactions = transactions + .into_transactions() + .map(|tx| tx.inner.encoded_2718()) + .collect::>(); + + store_ordered_trie(kv.as_ref(), encoded_transactions.as_slice()).await?; + } + HintType::L1Receipts => { + ensure!(hint.data.len() == 32, "Invalid hint data length"); + + let hash: B256 = hint.data.as_ref().try_into()?; + let raw_receipts: Vec = + providers.l1.client().request("debug_getRawReceipts", [hash]).await?; + + store_ordered_trie(kv.as_ref(), raw_receipts.as_slice()).await?; + } + HintType::L1Blob => { + ensure!(hint.data.len() == 48, "Invalid hint data length"); + + let hash_data_bytes: [u8; 32] = hint.data[0..32].try_into()?; + let index_data_bytes: [u8; 8] = hint.data[32..40].try_into()?; + let timestamp_data_bytes: [u8; 8] = hint.data[40..48].try_into()?; + + let hash: B256 = hash_data_bytes.into(); + let index = u64::from_be_bytes(index_data_bytes); + let timestamp = u64::from_be_bytes(timestamp_data_bytes); + + let partial_block_ref = BlockInfo { timestamp, ..Default::default() }; + let indexed_hash = IndexedBlobHash { index, hash }; + + // Fetch the blob sidecar from the blob provider. + let mut sidecars = providers + .blobs + .fetch_filtered_sidecars(&partial_block_ref, &[indexed_hash]) + .await + .map_err(|e| anyhow!("Failed to fetch blob sidecars: {e}"))?; + if sidecars.len() != 1 { + anyhow::bail!("Expected 1 sidecar, got {}", sidecars.len()); + } + let sidecar = sidecars.remove(0); + + // Acquire a lock on the key-value store and set the preimages. + let mut kv_lock = kv.write().await; + + // Set the preimage for the blob commitment. + kv_lock.set( + PreimageKey::new(*hash, PreimageKeyType::Sha256).into(), + sidecar.kzg_commitment.to_vec(), + )?; + + // Write all the field elements to the key-value store. There should be 4096. + // The preimage oracle key for each field element is the keccak256 hash of + // `abi.encodePacked(sidecar.KZGCommitment, uint256(i))` + let mut blob_key = [0u8; 80]; + blob_key[..48].copy_from_slice(sidecar.kzg_commitment.as_ref()); + for i in 0..FIELD_ELEMENTS_PER_BLOB { + blob_key[72..].copy_from_slice(i.to_be_bytes().as_ref()); + let blob_key_hash = keccak256(blob_key.as_ref()); + + kv_lock + .set(PreimageKey::new_keccak256(*blob_key_hash).into(), blob_key.into())?; + kv_lock.set( + PreimageKey::new(*blob_key_hash, PreimageKeyType::Blob).into(), + sidecar.blob[(i as usize) << 5..(i as usize + 1) << 5].to_vec(), + )?; + } + + // Write the KZG Proof as the 4096th element. + blob_key[72..].copy_from_slice((FIELD_ELEMENTS_PER_BLOB).to_be_bytes().as_ref()); + let blob_key_hash = keccak256(blob_key.as_ref()); + kv_lock.set(PreimageKey::new_keccak256(*blob_key_hash).into(), blob_key.into())?; + kv_lock.set( + PreimageKey::new(*blob_key_hash, PreimageKeyType::Blob).into(), + sidecar.kzg_proof.to_vec(), + )?; + } + HintType::L1Precompile => { + ensure!(hint.data.len() >= 20, "Invalid hint data length"); + + let address = Address::from_slice(&hint.data.as_ref()[..20]); + let input = hint.data[20..].to_vec(); + let input_hash = keccak256(hint.data.as_ref()); + + let result = crate::eth::execute(address, input).map_or_else( + |_| vec![0u8; 1], + |raw_res| { + let mut res = Vec::with_capacity(1 + raw_res.len()); + res.push(0x01); + res.extend_from_slice(&raw_res); + res + }, + ); + + let mut kv_lock = kv.write().await; + kv_lock.set(PreimageKey::new_keccak256(*input_hash).into(), hint.data.into())?; + kv_lock.set( + PreimageKey::new(*input_hash, PreimageKeyType::Precompile).into(), + result, + )?; + } + HintType::L2BlockHeader => { + ensure!(hint.data.len() == 32, "Invalid hint data length"); + + // Fetch the raw header from the L2 chain provider. + let hash: B256 = hint.data.as_ref().try_into()?; + let raw_header: Bytes = + providers.l2.client().request("debug_getRawHeader", [hash]).await?; + + // Acquire a lock on the key-value store and set the preimage. + let mut kv_lock = kv.write().await; + kv_lock.set(PreimageKey::new_keccak256(*hash).into(), raw_header.into())?; + } + HintType::L2Transactions => { + ensure!(hint.data.len() == 32, "Invalid hint data length"); + + let hash: B256 = hint.data.as_ref().try_into()?; + let Block { transactions, .. } = providers + .l2 + .get_block_by_hash(hash, BlockTransactionsKind::Full) + .await? + .ok_or(anyhow!("Block not found."))?; + + let encoded_transactions = transactions + .into_transactions() + .map(|tx| tx.inner.inner.encoded_2718()) + .collect::>(); + store_ordered_trie(kv.as_ref(), encoded_transactions.as_slice()).await?; + } + HintType::StartingL2Output => { + const OUTPUT_ROOT_VERSION: u8 = 0; + const L2_TO_L1_MESSAGE_PASSER_ADDRESS: Address = + address!("4200000000000000000000000000000000000016"); + + ensure!(hint.data.len() == 32, "Invalid hint data length"); + + // Fetch the header for the L2 head block. + let raw_header: Bytes = providers + .l2 + .client() + .request("debug_getRawHeader", &[cfg.agreed_l2_head_hash]) + .await?; + let header = Header::decode(&mut raw_header.as_ref())?; + + // Fetch the storage root for the L2 head block. + let l2_to_l1_message_passer = providers + .l2 + .get_proof(L2_TO_L1_MESSAGE_PASSER_ADDRESS, Default::default()) + .block_id(cfg.agreed_l2_head_hash.into()) + .await?; + + let mut raw_output = [0u8; 128]; + raw_output[31] = OUTPUT_ROOT_VERSION; + raw_output[32..64].copy_from_slice(header.state_root.as_ref()); + raw_output[64..96].copy_from_slice(l2_to_l1_message_passer.storage_hash.as_ref()); + raw_output[96..128].copy_from_slice(cfg.agreed_l2_head_hash.as_ref()); + let output_root = keccak256(raw_output); + + ensure!( + output_root == cfg.agreed_l2_output_root, + "Output root does not match L2 head." + ); + + let mut kv_write_lock = kv.write().await; + kv_write_lock + .set(PreimageKey::new_keccak256(*output_root).into(), raw_output.into())?; + } + HintType::L2Code => { + // geth hashdb scheme code hash key prefix + const CODE_PREFIX: u8 = b'c'; + + ensure!(hint.data.len() == 32, "Invalid hint data length"); + + let hash: B256 = hint.data.as_ref().try_into()?; + + // Attempt to fetch the code from the L2 chain provider. + let code_key = [&[CODE_PREFIX], hash.as_slice()].concat(); + let code = providers + .l2 + .client() + .request::<&[Bytes; 1], Bytes>("debug_dbGet", &[code_key.into()]) + .await; + + // Check if the first attempt to fetch the code failed. If it did, try fetching the + // code hash preimage without the geth hashdb scheme prefix. + let code = match code { + Ok(code) => code, + Err(_) => providers + .l2 + .client() + .request::<&[B256; 1], Bytes>("debug_dbGet", &[hash]) + .await + .map_err(|e| anyhow!("Error fetching code hash preimage: {e}"))?, + }; + + let mut kv_lock = kv.write().await; + kv_lock.set(PreimageKey::new_keccak256(*hash).into(), code.into())?; + } + HintType::L2StateNode => { + ensure!(hint.data.len() == 32, "Invalid hint data length"); + + let hash: B256 = hint.data.as_ref().try_into()?; + + // Fetch the preimage from the L2 chain provider. + let preimage: Bytes = providers.l2.client().request("debug_dbGet", &[hash]).await?; + + let mut kv_write_lock = kv.write().await; + kv_write_lock.set(PreimageKey::new_keccak256(*hash).into(), preimage.into())?; + } + HintType::L2AccountProof => { + ensure!(hint.data.len() == 8 + 20, "Invalid hint data length"); + + let block_number = u64::from_be_bytes(hint.data.as_ref()[..8].try_into()?); + let address = Address::from_slice(&hint.data.as_ref()[8..28]); + + let proof_response = providers + .l2 + .get_proof(address, Default::default()) + .block_id(block_number.into()) + .await?; + + // Write the account proof nodes to the key-value store. + let mut kv_lock = kv.write().await; + proof_response.account_proof.into_iter().try_for_each(|node| { + let node_hash = keccak256(node.as_ref()); + let key = PreimageKey::new_keccak256(*node_hash); + kv_lock.set(key.into(), node.into())?; + Ok::<(), anyhow::Error>(()) + })?; + } + HintType::L2AccountStorageProof => { + ensure!(hint.data.len() == 8 + 20 + 32, "Invalid hint data length"); + + let block_number = u64::from_be_bytes(hint.data.as_ref()[..8].try_into()?); + let address = Address::from_slice(&hint.data.as_ref()[8..28]); + let slot = B256::from_slice(&hint.data.as_ref()[28..]); + + let mut proof_response = providers + .l2 + .get_proof(address, vec![slot]) + .block_id(block_number.into()) + .await?; + + let mut kv_lock = kv.write().await; + + // Write the account proof nodes to the key-value store. + proof_response.account_proof.into_iter().try_for_each(|node| { + let node_hash = keccak256(node.as_ref()); + let key = PreimageKey::new_keccak256(*node_hash); + kv_lock.set(key.into(), node.into())?; + Ok::<(), anyhow::Error>(()) + })?; + + // Write the storage proof nodes to the key-value store. + let storage_proof = proof_response.storage_proof.remove(0); + storage_proof.proof.into_iter().try_for_each(|node| { + let node_hash = keccak256(node.as_ref()); + let key = PreimageKey::new_keccak256(*node_hash); + kv_lock.set(key.into(), node.into())?; + Ok::<(), anyhow::Error>(()) + })?; + } + HintType::L2PayloadWitness => { + ensure!(hint.data.len() >= 32, "Invalid hint data length"); + + let parent_block_hash = B256::from_slice(&hint.data.as_ref()[..32]); + let payload_attributes: OpPayloadAttributes = + serde_json::from_slice(&hint.data[32..])?; + + let execute_payload_response: ExecutionWitness = providers + .l2 + .client() + .request::<(B256, OpPayloadAttributes), ExecutionWitness>( + "debug_executePayload", + (parent_block_hash, payload_attributes), + ) + .await + .map_err(|e| anyhow!("Failed to fetch preimage: {e}"))?; + + let mut merged = HashMap::::default(); + merged.extend(execute_payload_response.state); + merged.extend(execute_payload_response.codes); + merged.extend(execute_payload_response.keys); + + let mut kv_lock = kv.write().await; + for (hash, preimage) in merged.into_iter() { + let computed_hash = keccak256(preimage.as_ref()); + assert_eq!(computed_hash, hash, "Preimage hash does not match expected hash"); + + let key = PreimageKey::new_keccak256(*hash); + kv_lock.set(key.into(), preimage.into())?; + } + } + HintType::EigenDa => { + ensure!(hint.data.len() > 32, "Invalid hint data length"); + + let commitment = hint.data.to_vec(); + // Fetch the blob from the eigen da provider. + let blob = providers + .eigen_da + .get_blob(&commitment) + .await + .map_err(|e| anyhow!("Failed to fetch blob: {e}"))?; + let mut kv_lock = kv.write().await; + + // the fourth because 0x01010000 in the beginning is metadata + let cert_blob_info = BlobInfo::decode(&mut &commitment[3..]) + .map_err(|e| anyhow!("Failed to decode blob info: {e}"))?; + // Proxy should return a cert whose data_length measured in symbol (i.e. 32 Bytes) + let blob_length = cert_blob_info.blob_header.data_length as u64; + + let eigenda_blob = EigenDABlobData::encode(blob.as_ref()); + + assert_eq!( + eigenda_blob.blob.len() < blob_length as usize * BYTES_PER_FIELD_ELEMENT, + true, + "data size from cert is smaller than the reconstructed data" + ); + + // + // Write all the field elements to the key-value store. + // The preimage oracle key for each field element is the keccak256 hash of + // `abi.encodePacked(cert.KZGCommitment, uint256(i))` + + // TODO figure out the key size, most likely dependent on smart contract parsing + let mut blob_key = [0u8; 96]; + blob_key[..32].copy_from_slice(cert_blob_info.blob_header.commitment.x.as_ref()); + blob_key[32..64].copy_from_slice(cert_blob_info.blob_header.commitment.y.as_ref()); + + for i in 0..blob_length { + blob_key[88..].copy_from_slice(i.to_be_bytes().as_ref()); + let blob_key_hash = keccak256(blob_key.as_ref()); + + kv_lock.set( + PreimageKey::new(*blob_key_hash, PreimageKeyType::Keccak256).into(), + blob_key.into(), + )?; + debug!("save block key, hash {:?}", blob_key_hash); + let start = (i as usize) << 5; + let end = start + 32; + let actual_end = eigenda_blob.blob.len().min(end); + let data_slice = if start >= eigenda_blob.blob.len() { + vec![0u8; 32] + } else { + let mut padded_data = vec![0u8; 32]; + padded_data[..(actual_end - start)] + .copy_from_slice(&eigenda_blob.blob[start..actual_end]); + padded_data + }; + kv_lock.set( + PreimageKey::new(*blob_key_hash, PreimageKeyType::GlobalGeneric).into(), + data_slice.into(), + )?; + debug!("save blob slice, hash {:?}", blob_key_hash); + } + + // proof is at the random point + //TODO + // Because the blob_length in EigenDA is variable-length, KZG proofs cannot be cached at the position corresponding to blob_length + // For now, they are placed at the position corresponding to commit x y. Further optimization will follow the EigenLayer approach + let mut kzg_proof_key = [0u8; 64]; + kzg_proof_key[..64].copy_from_slice(blob_key[..64].as_ref()); + let kzg_proof_key_hash = keccak256(kzg_proof_key.as_ref()); + + //TODO + // In fact, the calculation result following the EigenLayer approach is not the same as the cert blob info. + // need to save the real commitment x y + let mut kzg_commitment_key = [0u8; 65]; + kzg_commitment_key[..64].copy_from_slice(blob_key[..64].as_ref()); + kzg_commitment_key[64] = 0u8; + let kzg_commitment_key_hash = keccak256(kzg_commitment_key.as_ref()); + + let mut witness = EigenDABlobWitness::new(); + + let _ = witness + .push_witness(&blob) + .map_err(|e| anyhow!("eigen da blob push witness error {e}"))?; + + // let last_commitment = witness.commitments.last().unwrap(); + + // make sure locally computed proof equals to returned proof from the provider + // TODO In fact, the calculation result following the EigenLayer approach is not the same as the cert blob info. + // if last_commitment[..32] != cert_blob_info.blob_header.commitment.x[..] + // || last_commitment[32..64] != cert_blob_info.blob_header.commitment.y[..] + // { + // return Err( + // anyhow!("proxy commitment is different from computed commitment proxy", + // )); + // }; + let proof: Vec = + witness.proofs.iter().flat_map(|x| x.as_ref().iter().copied()).collect(); + + kv_lock.set( + PreimageKey::new(*kzg_proof_key_hash, PreimageKeyType::Keccak256).into(), + kzg_proof_key.into(), + )?; + debug!("save proof key, hash {:?}", kzg_proof_key_hash); + // proof to be done + kv_lock.set( + PreimageKey::new(*kzg_proof_key_hash, PreimageKeyType::GlobalGeneric).into(), + proof.into(), + )?; + debug!("save proof value, hash {:?}", kzg_proof_key_hash); + + let commitment: Vec = + witness.commitments.iter().flat_map(|x| x.as_ref().iter().copied()).collect(); + kv_lock.set( + PreimageKey::new(*kzg_commitment_key_hash, PreimageKeyType::Keccak256).into(), + kzg_commitment_key.into(), + )?; + debug!("save commitment key, hash {:?}", kzg_commitment_key_hash); + + // proof to be done + kv_lock.set( + PreimageKey::new(*kzg_commitment_key_hash, PreimageKeyType::GlobalGeneric) + .into(), + commitment.into(), + )?; + debug!("save commitment value, hash {:?}", kzg_commitment_key_hash); + } + } + + Ok(()) + } +} diff --git a/bin/host/src/kv/local.rs b/bin/host/src/single/local_kv.rs similarity index 71% rename from bin/host/src/kv/local.rs rename to bin/host/src/single/local_kv.rs index ace48fbefc..1f565b3f16 100644 --- a/bin/host/src/kv/local.rs +++ b/bin/host/src/single/local_kv.rs @@ -1,7 +1,8 @@ -//! Contains a concrete implementation of the [KeyValueStore] trait that stores data on disk. +//! Contains a concrete implementation of the [KeyValueStore] trait that stores data on disk, +//! using the [SingleChainHost] config. -use super::KeyValueStore; -use crate::cli::HostCli; +use super::SingleChainHost; +use crate::KeyValueStore; use alloy_primitives::B256; use anyhow::Result; use kona_preimage::PreimageKey; @@ -10,23 +11,20 @@ use kona_proof::boot::{ L2_ROLLUP_CONFIG_KEY, }; -/// The default chain ID to use if none is provided. -const DEFAULT_CHAIN_ID: u64 = 0xbeefbabe; - -/// A simple, synchronous key-value store that returns data from a [HostCli] config. +/// A simple, synchronous key-value store that returns data from a [SingleChainHost] config. #[derive(Debug)] -pub struct LocalKeyValueStore { - cfg: HostCli, +pub struct SingleChainLocalInputs { + cfg: SingleChainHost, } -impl LocalKeyValueStore { - /// Create a new [LocalKeyValueStore] with the given [HostCli] config. - pub const fn new(cfg: HostCli) -> Self { +impl SingleChainLocalInputs { + /// Create a new [SingleChainLocalInputs] with the given [SingleChainHost] config. + pub const fn new(cfg: SingleChainHost) -> Self { Self { cfg } } } -impl KeyValueStore for LocalKeyValueStore { +impl KeyValueStore for SingleChainLocalInputs { fn get(&self, key: B256) -> Option> { let preimage_key = PreimageKey::try_from(*key).ok()?; match preimage_key.key_value() { @@ -37,7 +35,7 @@ impl KeyValueStore for LocalKeyValueStore { Some(self.cfg.claimed_l2_block_number.to_be_bytes().to_vec()) } L2_CHAIN_ID_KEY => { - Some(self.cfg.l2_chain_id.unwrap_or(DEFAULT_CHAIN_ID).to_be_bytes().to_vec()) + Some(self.cfg.l2_chain_id.unwrap_or_default().to_be_bytes().to_vec()) } L2_ROLLUP_CONFIG_KEY => { let rollup_config = self.cfg.read_rollup_config().ok()?; diff --git a/bin/host/src/single/mod.rs b/bin/host/src/single/mod.rs new file mode 100644 index 0000000000..186d85b3a3 --- /dev/null +++ b/bin/host/src/single/mod.rs @@ -0,0 +1,10 @@ +//! This module contains the single-chain mode for the host. + +mod cfg; +pub use cfg::{SingleChainHost, SingleChainProviders}; + +mod local_kv; +pub use local_kv::SingleChainLocalInputs; + +mod handler; +pub use handler::SingleChainHintHandler; diff --git a/bin/host/src/witness/mod.rs b/bin/host/src/witness/mod.rs new file mode 100644 index 0000000000..53ffdc6fcc --- /dev/null +++ b/bin/host/src/witness/mod.rs @@ -0,0 +1,2 @@ +mod witness; +pub use witness::*; \ No newline at end of file diff --git a/bin/host/src/witness/witness.rs b/bin/host/src/witness/witness.rs new file mode 100644 index 0000000000..2b88fd16be --- /dev/null +++ b/bin/host/src/witness/witness.rs @@ -0,0 +1,91 @@ +extern crate alloc; +use alloc::vec::Vec; +use alloy_primitives::Bytes; +use ark_bn254::{Fq, G1Affine}; +use ark_ff::PrimeField; +use num::BigUint; +use rust_kzg_bn254_primitives::blob::Blob; +use rust_kzg_bn254_primitives::errors::KzgError; +use rust_kzg_bn254_prover::kzg::KZG; +use rust_kzg_bn254_prover::srs::SRS; +use tracing::info; + +/// stores +#[derive(Debug, Clone, Default)] +pub struct EigenDABlobWitness { + pub eigenda_blobs: Vec, + pub commitments: Vec, + pub proofs: Vec, +} + +/// +impl EigenDABlobWitness { + pub fn new() -> Self { + EigenDABlobWitness { + eigenda_blobs: Vec::new(), + commitments: Vec::new(), + proofs: Vec::new(), + } + } + + /// This function computes a witness for a eigenDA blob + /// nitro code https://github.com/Layr-Labs/nitro/blob/14f09745b74321f91d1f702c3e7bb5eb7d0e49ce/arbitrator/prover/src/kzgbn254.rs#L141 + /// could refactor in the future, such that both host and client can compute the proof + pub fn push_witness(&mut self, blob: &[u8]) -> Result<(), KzgError> { + // TODO remove the need for G2 access + // Add command line to specify where are g1 and g2 path + // In the future, it might make sense to let the proxy to return such + // value, instead of local computation + let srs = SRS::new("resources/g1.point", 268435456, 1000000).unwrap(); + let mut kzg = KZG::new(); + + let input = Blob::new(blob); + let input_poly = input.to_polynomial_eval_form(); + + kzg.calculate_and_store_roots_of_unity(blob.len() as u64).unwrap(); + + let mut commitment_bytes = vec![0u8; 0]; + + let commitment = kzg.commit_eval_form(&input_poly, &srs)?; + + // TODO the library should have returned the bytes, or provide a helper + // for conversion. For both proof and commitment + let commitment_x_bigint: BigUint = commitment.x.into(); + let commitment_y_bigint: BigUint = commitment.y.into(); + + append_left_padded_biguint_be(&mut commitment_bytes, &commitment_x_bigint); + append_left_padded_biguint_be(&mut commitment_bytes, &commitment_y_bigint); + + let mut proof_bytes = vec![0u8; 0]; + + let proof = kzg.compute_blob_proof(&input, &commitment, &srs)?; + let proof_x_bigint: BigUint = proof.x.into(); + let proof_y_bigint: BigUint = proof.y.into(); + + append_left_padded_biguint_be(&mut proof_bytes, &proof_x_bigint); + append_left_padded_biguint_be(&mut proof_bytes, &proof_y_bigint); + + // push data into witness + self.write( + Bytes::copy_from_slice(blob), + Bytes::copy_from_slice(&commitment_bytes), + proof_bytes.into(), + ); + + Ok(()) + } + + pub fn write(&mut self, blob: Bytes, commitment: Bytes, proof: Bytes) { + self.eigenda_blobs.push(blob); + self.commitments.push(commitment); + self.proofs.push(proof); + } +} + +/// This function convert a BigUint into 32Bytes vector in big endian format +pub fn append_left_padded_biguint_be(vec: &mut Vec, biguint: &BigUint) { + let bytes = biguint.to_bytes_be(); + let padding = 32 - bytes.len(); + vec.extend(std::iter::repeat(0).take(padding)); + vec.extend_from_slice(&bytes); +} diff --git a/book/README.md b/book/README.md index 0269e8d686..88b80daadb 100644 --- a/book/README.md +++ b/book/README.md @@ -1,6 +1,6 @@ # `kona-book` -This repository contains the source code for the Kona book, which is available at [anton-rs.github.io/kona](https://anton-rs.github.io/kona/). +This repository contains the source code for the Kona book, which is available at [op-rs.github.io/kona](https://op-rs.github.io/kona/). ## Contributing diff --git a/book/book.toml b/book/book.toml index c6541b7639..cf226755ef 100644 --- a/book/book.toml +++ b/book/book.toml @@ -13,7 +13,7 @@ command = "mdbook-mermaid" [output.html] default-theme = "ferra" preferred-dark-theme = "ferra" -git-repository-url = "https://github.com/anton-rs/kona" -edit-url-template = "https://github.com/anton-rs/kona/edit/main/book/{path}" +git-repository-url = "https://github.com/op-rs/kona" +edit-url-template = "https://github.com/op-rs/kona/edit/main/book/{path}" additional-css = ["custom.css"] additional-js = ["mermaid.min.js", "mermaid-init.js"] diff --git a/book/src/CONTRIBUTING.md b/book/src/CONTRIBUTING.md index d522cc9ef6..c7e9397df6 100644 --- a/book/src/CONTRIBUTING.md +++ b/book/src/CONTRIBUTING.md @@ -20,7 +20,7 @@ Before working with this repository locally, you'll need to install several depe ## Pull Request Process -1. Before anything, [create an issue](https://github.com/anton-rs/kona/issues/new) to discuss the change you're +1. Before anything, [create an issue](https://github.com/op-rs/kona/issues/new) to discuss the change you're wanting to make, if it is significant or changes functionality. Feel free to skip this step for trivial changes. 1. Once your change is implemented, ensure that all checks are passing before creating a PR. The full CI pipeline can be run locally via the `justfile`s in the repository. diff --git a/book/src/intro.md b/book/src/intro.md index 294637bceb..a2ebecc9e3 100644 --- a/book/src/intro.md +++ b/book/src/intro.md @@ -2,7 +2,7 @@ _Documentation for the Kona project._ - + > 📖 `kona` is in active development, and is not yet ready for use in production. During development, this book will evolve quickly and may contain inaccuracies. > diff --git a/book/src/links.md b/book/src/links.md index 9d68ad149c..424fb4c78a 100644 --- a/book/src/links.md +++ b/book/src/links.md @@ -3,7 +3,7 @@ [op-stack]: https://github.com/ethereum-optimism/optimism [op-program]: https://github.com/ethereum-optimism/optimism/tree/develop/op-program [cannon]: https://github.com/ethereum-optimism/optimism/tree/develop/cannon -[cannon-rs]: https://github.com/anton-rs/cannon-rs +[cannon-rs]: https://github.com/op-rs/cannon-rs [asterisc]: https://github.com/ethereum-optimism/asterisc [fp-specs]: https://specs.optimism.io/experimental/fault-proof/index.html [fpp-specs]: https://specs.optimism.io/experimental/fault-proof/index.html#fault-proof-program @@ -15,11 +15,11 @@ -[kona]: https://github.com/anton-rs/kona -[book]: https://anton-rs.github.io/kona/ -[issues]: https://github.com/anton-rs/kona/issues -[new-issue]: https://github.com/anton-rs/kona/issues/new -[contributing]: https://github.com/anton-rs/kona/tree/main/CONTRIBUTING.md +[kona]: https://github.com/op-rs/kona +[book]: https://op-rs.github.io/kona/ +[issues]: https://github.com/op-rs/kona/issues +[new-issue]: https://github.com/op-rs/kona/issues/new +[contributing]: https://github.com/op-rs/kona/tree/main/CONTRIBUTING.md diff --git a/book/src/sdk/custom-backend.md b/book/src/sdk/custom-backend.md index ffafdaf99f..7cb7431384 100644 --- a/book/src/sdk/custom-backend.md +++ b/book/src/sdk/custom-backend.md @@ -85,7 +85,7 @@ let pipeline = PipelineBuilder::new() ``` From here, a custom derivation driver is needed to produce the desired execution payload(s). An example of this for -`kona-client` can be found in the [DerivationDriver](https://github.com/anton-rs/kona/blob/main/bin/client/src/l1/driver.rs#L77). +`kona-client` can be found in the [DerivationDriver](https://github.com/op-rs/kona/blob/main/bin/client/src/l1/driver.rs#L77). ### `kona-mpt` / `kona-executor` sources @@ -113,7 +113,7 @@ let header = executor.execute_payload(...).expect("Failed execution"); ### Bringing it Together Once your custom backend traits for both `kona-derive` and `kona-executor` have been implemented, -your final binary may look something like [that of `kona-client`'s](https://github.com/anton-rs/kona/blob/main/bin/client/src/kona.rs). +your final binary may look something like [that of `kona-client`'s](https://github.com/op-rs/kona/blob/main/bin/client/src/kona.rs). Alternatively, if you're looking to prove a wider range of blocks, [`op-succinct`'s `range` program](https://github.com/succinctlabs/op-succinct/tree/main/programs/range) offers a good example of running the pipeline and executor across a string of contiguous blocks. diff --git a/book/src/sdk/exec-ext.md b/book/src/sdk/exec-ext.md index fef15caa9b..8709356347 100644 --- a/book/src/sdk/exec-ext.md +++ b/book/src/sdk/exec-ext.md @@ -46,7 +46,7 @@ let cfg = RollupConfig::default(); let provider = ...; let hinter = ...; -let executor = StatelessL2BlcokExecutor::builder(&cfg, provider, hinter) +let executor = StatelessL2BlockExecutor::builder(&cfg, provider, hinter) .with_parent_header(...) .with_handle_register(custom_handle_register) .build(); diff --git a/book/src/sdk/fpvm-backend.md b/book/src/sdk/fpvm-backend.md index d1fc6725c4..64c08fe253 100644 --- a/book/src/sdk/fpvm-backend.md +++ b/book/src/sdk/fpvm-backend.md @@ -100,7 +100,7 @@ Finally, in `kona-proof`, implementations of data source traits from `kona-deriv to pull in untyped data from the host by `PreimageKey`. These data source traits are covered in more detail within the [Custom Backend](./custom-backend.md) section, but we'll quickly gloss over them here to build intuition. -Let's take, for example, [`OracleL1ChainProvider`](https://github.com/anton-rs/kona/blob/40a8d7ec3def4a1eeb26492a1e4338d8b032e428/bin/client/src/l1/chain_provider.rs#L16-L23). +Let's take, for example, [`OracleL1ChainProvider`](https://github.com/op-rs/kona/blob/40a8d7ec3def4a1eeb26492a1e4338d8b032e428/bin/client/src/l1/chain_provider.rs#L16-L23). The [`ChainProvider`](https://docs.rs/kona-derive/latest/kona_derive/traits/trait.ChainProvider.html) trait in `kona-derive` defines a simple interface for fetching information about the L1 chain. In the `OracleL1ChainProvider`, this information is pulled in over the [PreimageOracle ABI][preimage-specs]. There are many other examples of these data source traits, diff --git a/book/src/sdk/pipeline/intro.md b/book/src/sdk/pipeline/intro.md index 146aae8cf8..c88519262b 100644 --- a/book/src/sdk/pipeline/intro.md +++ b/book/src/sdk/pipeline/intro.md @@ -182,7 +182,7 @@ use core::iter::Iterator; let l2_safe_head = L2BlockInfo::default(); loop { if matches!(pipeline.step(l2_safe_head).await, StepResult::PreparedAttributes) { - // The pipeline has succesfully prepared payload attributes, break the loop. + // The pipeline has successfully prepared payload attributes, break the loop. break; } } @@ -285,12 +285,12 @@ So, [@clabby][clabby] and [@refcell][refcell] stood up [kona][kona] in a few mon -[driver]: https://github.com/anton-rs/kona/blob/main/bin/client/src/l1/driver.rs#L74 +[driver]: https://github.com/op-rs/kona/blob/main/bin/client/src/l1/driver.rs#L74 [next]: https://doc.rust-lang.org/nightly/core/iter/trait.Iterator.html#tymethod.next [builder]: https://docs.rs/kona-derive/latest/kona_derive/pipeline/struct.PipelineBuilder.html [alloy]: https://github.com/alloy-rs/alloy [ethers-rs]: https://github.com/gakonst/ethers-rs -[kona]: https://github.com/anton-rs/kona +[kona]: https://github.com/op-rs/kona [clabby]: https://github.com/clabby [refcell]: https://github.com/refcell [go]: https://go.dev/ diff --git a/build/README.md b/build/README.md index a8b70973b9..f8c50cc658 100644 --- a/build/README.md +++ b/build/README.md @@ -18,7 +18,7 @@ docker run \ --platform linux/amd64 \ -v `pwd`/:/workdir \ -w="/workdir" \ - ghcr.io/anton-rs/kona/cannon-builder:main cargo build --release -Zbuild-std=core,alloc + ghcr.io/op-rs/kona/cannon-builder:main cargo build --release -Zbuild-std=core,alloc ``` **asterisc** @@ -29,5 +29,5 @@ docker run \ --platform linux/amd64 \ -v `pwd`/:/workdir \ -w="/workdir" \ - ghcr.io/anton-rs/kona/asterisc-builder:main cargo build --release -Zbuild-std=core,alloc + ghcr.io/op-rs/kona/asterisc-builder:main cargo build --release -Zbuild-std=core,alloc ``` diff --git a/build/asterisc/asterisc-repro.dockerfile b/build/asterisc/asterisc-repro.dockerfile index a644df1739..38cc432afd 100644 --- a/build/asterisc/asterisc-repro.dockerfile +++ b/build/asterisc/asterisc-repro.dockerfile @@ -29,7 +29,7 @@ RUN git clone https://github.com/ethereum-optimism/asterisc && \ # Build kona-client @ `CLIENT_TAG` # ################################################################ -FROM ghcr.io/anton-rs/kona/asterisc-builder@sha256:523f0455b25b28917a8e7d02cd3ecb8c8af93e5e5b85ec7d7bcf2df4458e65a5 AS client-build +FROM ghcr.io/op-rs/kona/asterisc-builder@sha256:56c57453ebe09875e96df527d3734d781e987dbdc1e0ce9e813e1e88590036bd AS client-build SHELL ["/bin/bash", "-c"] ARG CLIENT_TAG @@ -47,7 +47,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends git # Build kona-client on the selected tag RUN git checkout $CLIENT_TAG && \ cargo build -Zbuild-std=core,alloc --workspace --bin kona --locked --profile release-client-lto --exclude kona-host --exclude kona-derive-alloy && \ - mv ./target/riscv64gc-unknown-none-elf/release-client-lto/kona /kona-client-elf + mv ./target/riscv64imac-unknown-none-elf/release-client-lto/kona /kona-client-elf ################################################################ # Build kona-host @ `CLIENT_TAG` # diff --git a/build/asterisc/asterisc.dockerfile b/build/asterisc/asterisc.dockerfile index 5e8e4a4c5b..2499758359 100644 --- a/build/asterisc/asterisc.dockerfile +++ b/build/asterisc/asterisc.dockerfile @@ -17,7 +17,7 @@ RUN apt-get update && apt-get install --assume-yes --no-install-recommends \ clang \ make \ cmake \ - git + git # Install Rustup and Rust RUN curl https://sh.rustup.rs -sSf | bash -s -- -y --default-toolchain ${RUST_VERSION} --component rust-src @@ -28,6 +28,6 @@ ENV PATH="/root/.cargo/bin:${PATH}" ENV CC_riscv64_unknown_none_elf=riscv64-linux-gnu-gcc \ CXX_riscv64_unknown_none_elf=riscv64-linux-gnu-g++ \ CARGO_TARGET_RISCV64_UNKNOWN_NONE_ELF_LINKER=riscv64-linux-gnu-gcc \ - RUSTFLAGS="-Clink-arg=-e_start -Ctarget-feature=-c" \ - CARGO_BUILD_TARGET="riscv64gc-unknown-none-elf" \ + RUSTFLAGS="-Clink-arg=-e_start -Ctarget-feature=-c,-zicsr,-zifencei,-zicntr,zihpm" \ + CARGO_BUILD_TARGET="riscv64imac-unknown-none-elf" \ RUSTUP_TOOLCHAIN=${RUST_VERSION} diff --git a/crates/derive/CHANGELOG.md b/crates/derive/CHANGELOG.md index 30f89fab4b..f85f5e242a 100644 --- a/crates/derive/CHANGELOG.md +++ b/crates/derive/CHANGELOG.md @@ -6,248 +6,248 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -## [0.2.0](https://github.com/anton-rs/kona/compare/kona-derive-v0.1.0...kona-derive-v0.2.0) - 2024-12-03 +## [0.2.0](https://github.com/op-rs/kona/compare/kona-derive-v0.1.0...kona-derive-v0.2.0) - 2024-12-03 ### Added -- *(workspace)* Isolate FPVM-specific platform code ([#821](https://github.com/anton-rs/kona/pull/821)) +- *(workspace)* Isolate FPVM-specific platform code ([#821](https://github.com/op-rs/kona/pull/821)) ### Fixed -- bump ([#855](https://github.com/anton-rs/kona/pull/855)) -- nightly lint ([#858](https://github.com/anton-rs/kona/pull/858)) +- bump ([#855](https://github.com/op-rs/kona/pull/855)) +- nightly lint ([#858](https://github.com/op-rs/kona/pull/858)) ### Other -- *(derive)* remove indexed blob hash ([#847](https://github.com/anton-rs/kona/pull/847)) +- *(derive)* remove indexed blob hash ([#847](https://github.com/op-rs/kona/pull/847)) -## [0.0.7](https://github.com/anton-rs/kona/compare/kona-derive-v0.0.6...kona-derive-v0.0.7) - 2024-11-20 +## [0.0.7](https://github.com/op-rs/kona/compare/kona-derive-v0.0.6...kona-derive-v0.0.7) - 2024-11-20 ### Added -- *(driver)* Abstract, Default Pipeline ([#796](https://github.com/anton-rs/kona/pull/796)) +- *(driver)* Abstract, Default Pipeline ([#796](https://github.com/op-rs/kona/pull/796)) ### Other -- *(derive)* remove batch reader ([#826](https://github.com/anton-rs/kona/pull/826)) -- op-alloy 0.6.8 ([#830](https://github.com/anton-rs/kona/pull/830)) -- *(driver)* use tracing macros ([#823](https://github.com/anton-rs/kona/pull/823)) -- *(deps)* op-alloy 0.6.7 ([#824](https://github.com/anton-rs/kona/pull/824)) -- v0.6.6 op-alloy ([#804](https://github.com/anton-rs/kona/pull/804)) -- *(workspace)* Migrate back to `thiserror` v2 ([#811](https://github.com/anton-rs/kona/pull/811)) -- *(derive)* Re-export types ([#790](https://github.com/anton-rs/kona/pull/790)) -- Revert "chore: bump alloy deps ([#788](https://github.com/anton-rs/kona/pull/788))" ([#791](https://github.com/anton-rs/kona/pull/791)) +- *(derive)* remove batch reader ([#826](https://github.com/op-rs/kona/pull/826)) +- op-alloy 0.6.8 ([#830](https://github.com/op-rs/kona/pull/830)) +- *(driver)* use tracing macros ([#823](https://github.com/op-rs/kona/pull/823)) +- *(deps)* op-alloy 0.6.7 ([#824](https://github.com/op-rs/kona/pull/824)) +- v0.6.6 op-alloy ([#804](https://github.com/op-rs/kona/pull/804)) +- *(workspace)* Migrate back to `thiserror` v2 ([#811](https://github.com/op-rs/kona/pull/811)) +- *(derive)* Re-export types ([#790](https://github.com/op-rs/kona/pull/790)) +- Revert "chore: bump alloy deps ([#788](https://github.com/op-rs/kona/pull/788))" ([#791](https://github.com/op-rs/kona/pull/791)) -## [0.0.6](https://github.com/anton-rs/kona/compare/kona-derive-v0.0.5...kona-derive-v0.0.6) - 2024-11-06 +## [0.0.6](https://github.com/op-rs/kona/compare/kona-derive-v0.0.5...kona-derive-v0.0.6) - 2024-11-06 ### Added -- *(derive)* `From for PipelineErrorKind` ([#780](https://github.com/anton-rs/kona/pull/780)) -- *(client)* Remove `anyhow` ([#779](https://github.com/anton-rs/kona/pull/779)) -- *(derive)* sources docs ([#754](https://github.com/anton-rs/kona/pull/754)) +- *(derive)* `From for PipelineErrorKind` ([#780](https://github.com/op-rs/kona/pull/780)) +- *(client)* Remove `anyhow` ([#779](https://github.com/op-rs/kona/pull/779)) +- *(derive)* sources docs ([#754](https://github.com/op-rs/kona/pull/754)) ### Fixed -- *(derive)* Data Availability Provider Abstraction ([#782](https://github.com/anton-rs/kona/pull/782)) -- *(derive)* hoist types out of traits ([#781](https://github.com/anton-rs/kona/pull/781)) -- *(client)* Trace extension support ([#778](https://github.com/anton-rs/kona/pull/778)) -- *(derive)* use signal value updated with system config. ([#776](https://github.com/anton-rs/kona/pull/776)) +- *(derive)* Data Availability Provider Abstraction ([#782](https://github.com/op-rs/kona/pull/782)) +- *(derive)* hoist types out of traits ([#781](https://github.com/op-rs/kona/pull/781)) +- *(client)* Trace extension support ([#778](https://github.com/op-rs/kona/pull/778)) +- *(derive)* use signal value updated with system config. ([#776](https://github.com/op-rs/kona/pull/776)) ### Other -- bump alloy deps ([#788](https://github.com/anton-rs/kona/pull/788)) -- *(derive)* pipeline error test coverage ([#784](https://github.com/anton-rs/kona/pull/784)) -- Only fill blob data when there is no calldata ([#764](https://github.com/anton-rs/kona/pull/764)) -- *(derive)* touchup kona-derive readme ([#762](https://github.com/anton-rs/kona/pull/762)) -- *(derive)* Error Exports ([#758](https://github.com/anton-rs/kona/pull/758)) -- *(derive)* Cleanup Exports ([#757](https://github.com/anton-rs/kona/pull/757)) +- bump alloy deps ([#788](https://github.com/op-rs/kona/pull/788)) +- *(derive)* pipeline error test coverage ([#784](https://github.com/op-rs/kona/pull/784)) +- Only fill blob data when there is no calldata ([#764](https://github.com/op-rs/kona/pull/764)) +- *(derive)* touchup kona-derive readme ([#762](https://github.com/op-rs/kona/pull/762)) +- *(derive)* Error Exports ([#758](https://github.com/op-rs/kona/pull/758)) +- *(derive)* Cleanup Exports ([#757](https://github.com/op-rs/kona/pull/757)) -## [0.0.5](https://github.com/anton-rs/kona/compare/kona-derive-v0.0.4...kona-derive-v0.0.5) - 2024-10-29 +## [0.0.5](https://github.com/op-rs/kona/compare/kona-derive-v0.0.4...kona-derive-v0.0.5) - 2024-10-29 ### Added -- *(derive)* use upstream op-alloy batch types ([#746](https://github.com/anton-rs/kona/pull/746)) -- *(derive)* Remove metrics ([#743](https://github.com/anton-rs/kona/pull/743)) -- *(derive)* sys config accessor ([#722](https://github.com/anton-rs/kona/pull/722)) +- *(derive)* use upstream op-alloy batch types ([#746](https://github.com/op-rs/kona/pull/746)) +- *(derive)* Remove metrics ([#743](https://github.com/op-rs/kona/pull/743)) +- *(derive)* sys config accessor ([#722](https://github.com/op-rs/kona/pull/722)) ### Fixed -- tracing_subscriber problem in `kona-derive` tests ([#741](https://github.com/anton-rs/kona/pull/741)) -- *(derive)* Holocene action tests / fixes ([#733](https://github.com/anton-rs/kona/pull/733)) +- tracing_subscriber problem in `kona-derive` tests ([#741](https://github.com/op-rs/kona/pull/741)) +- *(derive)* Holocene action tests / fixes ([#733](https://github.com/op-rs/kona/pull/733)) ### Other -- *(derive)* import hygiene ([#744](https://github.com/anton-rs/kona/pull/744)) +- *(derive)* import hygiene ([#744](https://github.com/op-rs/kona/pull/744)) -## [0.0.4](https://github.com/anton-rs/kona/compare/kona-derive-v0.0.3...kona-derive-v0.0.4) - 2024-10-25 +## [0.0.4](https://github.com/op-rs/kona/compare/kona-derive-v0.0.3...kona-derive-v0.0.4) - 2024-10-25 ### Added -- remove thiserror ([#735](https://github.com/anton-rs/kona/pull/735)) -- *(derive)* `BatchProvider` multiplexed stage ([#726](https://github.com/anton-rs/kona/pull/726)) -- *(derive)* hoist stage traits ([#723](https://github.com/anton-rs/kona/pull/723)) -- frame queue test asserter ([#619](https://github.com/anton-rs/kona/pull/619)) -- *(workspace)* Distribute pipeline, not providers ([#717](https://github.com/anton-rs/kona/pull/717)) -- *(derive)* `BatchValidator` stage ([#703](https://github.com/anton-rs/kona/pull/703)) -- *(derive)* Add `ChannelAssembler` size limitation ([#700](https://github.com/anton-rs/kona/pull/700)) -- *(derive)* signal receiver logic ([#696](https://github.com/anton-rs/kona/pull/696)) -- *(derive)* Stage multiplexer ([#693](https://github.com/anton-rs/kona/pull/693)) -- *(derive)* `Past` batch validity variant ([#684](https://github.com/anton-rs/kona/pull/684)) -- codecov sources ([#657](https://github.com/anton-rs/kona/pull/657)) -- frame queue tests ([#613](https://github.com/anton-rs/kona/pull/613)) -- *(derive)* Holocene flush signal ([#612](https://github.com/anton-rs/kona/pull/612)) -- *(derive)* Add `Signal` API ([#611](https://github.com/anton-rs/kona/pull/611)) -- *(derive)* BatchQueue Update [Holocene] ([#601](https://github.com/anton-rs/kona/pull/601)) -- *(derive)* bump op-alloy dep ([#605](https://github.com/anton-rs/kona/pull/605)) -- kona-providers ([#596](https://github.com/anton-rs/kona/pull/596)) -- *(derive)* Span batch prefix checks ([#592](https://github.com/anton-rs/kona/pull/592)) -- *(derive)* `BatchStream` buffering ([#590](https://github.com/anton-rs/kona/pull/590)) -- *(derive)* BatchStreamProvider ([#591](https://github.com/anton-rs/kona/pull/591)) -- *(derive)* Refactor out Online Providers ([#569](https://github.com/anton-rs/kona/pull/569)) -- *(derive)* interleaved channel tests ([#585](https://github.com/anton-rs/kona/pull/585)) -- *(derive)* Holocene Buffer Flushing ([#575](https://github.com/anton-rs/kona/pull/575)) -- *(derive)* Holocene Channel Bank Checks ([#572](https://github.com/anton-rs/kona/pull/572)) -- *(derive)* Holocene Frame Queue ([#579](https://github.com/anton-rs/kona/pull/579)) -- *(derive)* Holocene Activation ([#574](https://github.com/anton-rs/kona/pull/574)) -- *(derive)* wire up the batch span stage ([#567](https://github.com/anton-rs/kona/pull/567)) -- *(derive)* New BatchStream Stage for Holocene ([#566](https://github.com/anton-rs/kona/pull/566)) -- *(derive)* Hoist AttributesBuilder ([#571](https://github.com/anton-rs/kona/pull/571)) -- *(derive)* Touchup Docs ([#555](https://github.com/anton-rs/kona/pull/555)) -- *(derive)* Latest BN ([#521](https://github.com/anton-rs/kona/pull/521)) -- Remove L2 Execution Payload ([#542](https://github.com/anton-rs/kona/pull/542)) -- *(derive)* Typed error handling ([#540](https://github.com/anton-rs/kona/pull/540)) -- *(primitives)* Remove Attributes ([#529](https://github.com/anton-rs/kona/pull/529)) -- large dependency update ([#528](https://github.com/anton-rs/kona/pull/528)) -- *(primitives)* reuse op-alloy-protocol channel and block types ([#499](https://github.com/anton-rs/kona/pull/499)) +- remove thiserror ([#735](https://github.com/op-rs/kona/pull/735)) +- *(derive)* `BatchProvider` multiplexed stage ([#726](https://github.com/op-rs/kona/pull/726)) +- *(derive)* hoist stage traits ([#723](https://github.com/op-rs/kona/pull/723)) +- frame queue test asserter ([#619](https://github.com/op-rs/kona/pull/619)) +- *(workspace)* Distribute pipeline, not providers ([#717](https://github.com/op-rs/kona/pull/717)) +- *(derive)* `BatchValidator` stage ([#703](https://github.com/op-rs/kona/pull/703)) +- *(derive)* Add `ChannelAssembler` size limitation ([#700](https://github.com/op-rs/kona/pull/700)) +- *(derive)* signal receiver logic ([#696](https://github.com/op-rs/kona/pull/696)) +- *(derive)* Stage multiplexer ([#693](https://github.com/op-rs/kona/pull/693)) +- *(derive)* `Past` batch validity variant ([#684](https://github.com/op-rs/kona/pull/684)) +- codecov sources ([#657](https://github.com/op-rs/kona/pull/657)) +- frame queue tests ([#613](https://github.com/op-rs/kona/pull/613)) +- *(derive)* Holocene flush signal ([#612](https://github.com/op-rs/kona/pull/612)) +- *(derive)* Add `Signal` API ([#611](https://github.com/op-rs/kona/pull/611)) +- *(derive)* BatchQueue Update [Holocene] ([#601](https://github.com/op-rs/kona/pull/601)) +- *(derive)* bump op-alloy dep ([#605](https://github.com/op-rs/kona/pull/605)) +- kona-providers ([#596](https://github.com/op-rs/kona/pull/596)) +- *(derive)* Span batch prefix checks ([#592](https://github.com/op-rs/kona/pull/592)) +- *(derive)* `BatchStream` buffering ([#590](https://github.com/op-rs/kona/pull/590)) +- *(derive)* BatchStreamProvider ([#591](https://github.com/op-rs/kona/pull/591)) +- *(derive)* Refactor out Online Providers ([#569](https://github.com/op-rs/kona/pull/569)) +- *(derive)* interleaved channel tests ([#585](https://github.com/op-rs/kona/pull/585)) +- *(derive)* Holocene Buffer Flushing ([#575](https://github.com/op-rs/kona/pull/575)) +- *(derive)* Holocene Channel Bank Checks ([#572](https://github.com/op-rs/kona/pull/572)) +- *(derive)* Holocene Frame Queue ([#579](https://github.com/op-rs/kona/pull/579)) +- *(derive)* Holocene Activation ([#574](https://github.com/op-rs/kona/pull/574)) +- *(derive)* wire up the batch span stage ([#567](https://github.com/op-rs/kona/pull/567)) +- *(derive)* New BatchStream Stage for Holocene ([#566](https://github.com/op-rs/kona/pull/566)) +- *(derive)* Hoist AttributesBuilder ([#571](https://github.com/op-rs/kona/pull/571)) +- *(derive)* Touchup Docs ([#555](https://github.com/op-rs/kona/pull/555)) +- *(derive)* Latest BN ([#521](https://github.com/op-rs/kona/pull/521)) +- Remove L2 Execution Payload ([#542](https://github.com/op-rs/kona/pull/542)) +- *(derive)* Typed error handling ([#540](https://github.com/op-rs/kona/pull/540)) +- *(primitives)* Remove Attributes ([#529](https://github.com/op-rs/kona/pull/529)) +- large dependency update ([#528](https://github.com/op-rs/kona/pull/528)) +- *(primitives)* reuse op-alloy-protocol channel and block types ([#499](https://github.com/op-rs/kona/pull/499)) ### Fixed -- hashmap ([#732](https://github.com/anton-rs/kona/pull/732)) -- *(derive)* SpanBatch element limit + channel RLP size limit ([#692](https://github.com/anton-rs/kona/pull/692)) -- *(derive)* Holocene `SpanBatch` prefix checks ([#688](https://github.com/anton-rs/kona/pull/688)) -- *(derive)* Retain L1 blocks ([#683](https://github.com/anton-rs/kona/pull/683)) -- *(executor)* Holocene EIP-1559 params in Header ([#622](https://github.com/anton-rs/kona/pull/622)) -- derive pipeline params ([#587](https://github.com/anton-rs/kona/pull/587)) -- *(workspace)* hoist and fix lints ([#577](https://github.com/anton-rs/kona/pull/577)) -- *(derive)* move attributes builder trait ([#570](https://github.com/anton-rs/kona/pull/570)) -- *(client)* Channel reader error handling ([#539](https://github.com/anton-rs/kona/pull/539)) -- *(derive)* Sequence window expiry ([#532](https://github.com/anton-rs/kona/pull/532)) -- *(primitives)* use consensus hardforks ([#497](https://github.com/anton-rs/kona/pull/497)) -- *(primitives)* re-use op-alloy frame type ([#492](https://github.com/anton-rs/kona/pull/492)) +- hashmap ([#732](https://github.com/op-rs/kona/pull/732)) +- *(derive)* SpanBatch element limit + channel RLP size limit ([#692](https://github.com/op-rs/kona/pull/692)) +- *(derive)* Holocene `SpanBatch` prefix checks ([#688](https://github.com/op-rs/kona/pull/688)) +- *(derive)* Retain L1 blocks ([#683](https://github.com/op-rs/kona/pull/683)) +- *(executor)* Holocene EIP-1559 params in Header ([#622](https://github.com/op-rs/kona/pull/622)) +- derive pipeline params ([#587](https://github.com/op-rs/kona/pull/587)) +- *(workspace)* hoist and fix lints ([#577](https://github.com/op-rs/kona/pull/577)) +- *(derive)* move attributes builder trait ([#570](https://github.com/op-rs/kona/pull/570)) +- *(client)* Channel reader error handling ([#539](https://github.com/op-rs/kona/pull/539)) +- *(derive)* Sequence window expiry ([#532](https://github.com/op-rs/kona/pull/532)) +- *(primitives)* use consensus hardforks ([#497](https://github.com/op-rs/kona/pull/497)) +- *(primitives)* re-use op-alloy frame type ([#492](https://github.com/op-rs/kona/pull/492)) ### Other -- re-org imports ([#711](https://github.com/anton-rs/kona/pull/711)) -- hoist trait test utilities ([#708](https://github.com/anton-rs/kona/pull/708)) -- *(workspace)* Removes Primitives ([#638](https://github.com/anton-rs/kona/pull/638)) -- *(derive)* Add tracing to `ChannelAssembler` ([#701](https://github.com/anton-rs/kona/pull/701)) -- *(derive)* remove span batch todo comments ([#682](https://github.com/anton-rs/kona/pull/682)) -- refactor test utils ([#677](https://github.com/anton-rs/kona/pull/677)) -- *(derive)* stage coverage ([#673](https://github.com/anton-rs/kona/pull/673)) -- *(executor)* Use Upstreamed op-alloy Methods ([#651](https://github.com/anton-rs/kona/pull/651)) -- *(derive)* Test and Clean Batch Types ([#670](https://github.com/anton-rs/kona/pull/670)) -- *(derive)* Test Stage Resets and Flushes ([#669](https://github.com/anton-rs/kona/pull/669)) -- *(derive)* Batch Timestamp Tests ([#664](https://github.com/anton-rs/kona/pull/664)) -- *(derive)* test channel reader flushing ([#661](https://github.com/anton-rs/kona/pull/661)) -- *(derive)* adds more channel bank coverage ([#659](https://github.com/anton-rs/kona/pull/659)) -- *(derive)* test channel reader resets ([#660](https://github.com/anton-rs/kona/pull/660)) -- *(derive)* test channel bank reset ([#658](https://github.com/anton-rs/kona/pull/658)) -- *(derive)* hoist attributes queue test utils ([#654](https://github.com/anton-rs/kona/pull/654)) -- *(derive)* Pipeline Core Test Coverage ([#642](https://github.com/anton-rs/kona/pull/642)) -- *(derive)* Single Batch Test Coverage ([#643](https://github.com/anton-rs/kona/pull/643)) -- *(derive)* Blob Source Test Coverage ([#631](https://github.com/anton-rs/kona/pull/631)) -- refactor test providers ([#623](https://github.com/anton-rs/kona/pull/623)) -- doc logos ([#609](https://github.com/anton-rs/kona/pull/609)) -- use alloy primitives map ([#586](https://github.com/anton-rs/kona/pull/586)) -- *(derive)* [Holocene] Drain previous channel in one iteration ([#583](https://github.com/anton-rs/kona/pull/583)) -- channel reader docs ([#568](https://github.com/anton-rs/kona/pull/568)) -- Bumps Dependency Versions ([#520](https://github.com/anton-rs/kona/pull/520)) -- *(primitives)* rm RawTransaction ([#505](https://github.com/anton-rs/kona/pull/505)) - -## [0.0.3](https://github.com/anton-rs/kona/compare/kona-derive-v0.0.2...kona-derive-v0.0.3) - 2024-09-04 +- re-org imports ([#711](https://github.com/op-rs/kona/pull/711)) +- hoist trait test utilities ([#708](https://github.com/op-rs/kona/pull/708)) +- *(workspace)* Removes Primitives ([#638](https://github.com/op-rs/kona/pull/638)) +- *(derive)* Add tracing to `ChannelAssembler` ([#701](https://github.com/op-rs/kona/pull/701)) +- *(derive)* remove span batch todo comments ([#682](https://github.com/op-rs/kona/pull/682)) +- refactor test utils ([#677](https://github.com/op-rs/kona/pull/677)) +- *(derive)* stage coverage ([#673](https://github.com/op-rs/kona/pull/673)) +- *(executor)* Use Upstreamed op-alloy Methods ([#651](https://github.com/op-rs/kona/pull/651)) +- *(derive)* Test and Clean Batch Types ([#670](https://github.com/op-rs/kona/pull/670)) +- *(derive)* Test Stage Resets and Flushes ([#669](https://github.com/op-rs/kona/pull/669)) +- *(derive)* Batch Timestamp Tests ([#664](https://github.com/op-rs/kona/pull/664)) +- *(derive)* test channel reader flushing ([#661](https://github.com/op-rs/kona/pull/661)) +- *(derive)* adds more channel bank coverage ([#659](https://github.com/op-rs/kona/pull/659)) +- *(derive)* test channel reader resets ([#660](https://github.com/op-rs/kona/pull/660)) +- *(derive)* test channel bank reset ([#658](https://github.com/op-rs/kona/pull/658)) +- *(derive)* hoist attributes queue test utils ([#654](https://github.com/op-rs/kona/pull/654)) +- *(derive)* Pipeline Core Test Coverage ([#642](https://github.com/op-rs/kona/pull/642)) +- *(derive)* Single Batch Test Coverage ([#643](https://github.com/op-rs/kona/pull/643)) +- *(derive)* Blob Source Test Coverage ([#631](https://github.com/op-rs/kona/pull/631)) +- refactor test providers ([#623](https://github.com/op-rs/kona/pull/623)) +- doc logos ([#609](https://github.com/op-rs/kona/pull/609)) +- use alloy primitives map ([#586](https://github.com/op-rs/kona/pull/586)) +- *(derive)* [Holocene] Drain previous channel in one iteration ([#583](https://github.com/op-rs/kona/pull/583)) +- channel reader docs ([#568](https://github.com/op-rs/kona/pull/568)) +- Bumps Dependency Versions ([#520](https://github.com/op-rs/kona/pull/520)) +- *(primitives)* rm RawTransaction ([#505](https://github.com/op-rs/kona/pull/505)) + +## [0.0.3](https://github.com/op-rs/kona/compare/kona-derive-v0.0.2...kona-derive-v0.0.3) - 2024-09-04 ### Added -- Run cargo hack against workspace ([#485](https://github.com/anton-rs/kona/pull/485)) -- *(workspace)* Workspace Re-exports ([#468](https://github.com/anton-rs/kona/pull/468)) -- *(ci)* Add scheduled FPP differential tests ([#408](https://github.com/anton-rs/kona/pull/408)) -- *(derive+trusted-sync)* online blob provider with fallback ([#410](https://github.com/anton-rs/kona/pull/410)) -- increase granularity ([#365](https://github.com/anton-rs/kona/pull/365)) -- *(derive)* histogram for number of channels for given frame counts ([#337](https://github.com/anton-rs/kona/pull/337)) -- *(derive)* track the current channel size ([#331](https://github.com/anton-rs/kona/pull/331)) -- *(derive)* more stage metrics ([#326](https://github.com/anton-rs/kona/pull/326)) -- *(derive)* Granular Provider Metrics ([#325](https://github.com/anton-rs/kona/pull/325)) -- *(derive)* Stage Level Metrics ([#309](https://github.com/anton-rs/kona/pull/309)) -- *(examples)* Trusted Sync Metrics ([#308](https://github.com/anton-rs/kona/pull/308)) +- Run cargo hack against workspace ([#485](https://github.com/op-rs/kona/pull/485)) +- *(workspace)* Workspace Re-exports ([#468](https://github.com/op-rs/kona/pull/468)) +- *(ci)* Add scheduled FPP differential tests ([#408](https://github.com/op-rs/kona/pull/408)) +- *(derive+trusted-sync)* online blob provider with fallback ([#410](https://github.com/op-rs/kona/pull/410)) +- increase granularity ([#365](https://github.com/op-rs/kona/pull/365)) +- *(derive)* histogram for number of channels for given frame counts ([#337](https://github.com/op-rs/kona/pull/337)) +- *(derive)* track the current channel size ([#331](https://github.com/op-rs/kona/pull/331)) +- *(derive)* more stage metrics ([#326](https://github.com/op-rs/kona/pull/326)) +- *(derive)* Granular Provider Metrics ([#325](https://github.com/op-rs/kona/pull/325)) +- *(derive)* Stage Level Metrics ([#309](https://github.com/op-rs/kona/pull/309)) +- *(examples)* Trusted Sync Metrics ([#308](https://github.com/op-rs/kona/pull/308)) ### Fixed -- downgrade for release plz ([#458](https://github.com/anton-rs/kona/pull/458)) -- *(workspace)* Add Unused Dependency Lint ([#453](https://github.com/anton-rs/kona/pull/453)) -- *(derive)* remove fpvm tests ([#447](https://github.com/anton-rs/kona/pull/447)) -- *(derive)* Granite Hardfork Support ([#420](https://github.com/anton-rs/kona/pull/420)) -- remove data iter option ([#405](https://github.com/anton-rs/kona/pull/405)) -- *(deps)* Bump Alloy Dependencies ([#409](https://github.com/anton-rs/kona/pull/409)) -- *(kona-derive)* Remove SignedRecoverable Shim ([#400](https://github.com/anton-rs/kona/pull/400)) -- *(derive)* Pipeline Reset ([#383](https://github.com/anton-rs/kona/pull/383)) -- *(examples)* Start N Blocks Back from Tip ([#349](https://github.com/anton-rs/kona/pull/349)) -- *(derive)* Unused var w/o `metrics` feature ([#345](https://github.com/anton-rs/kona/pull/345)) -- *(derive)* bind the Pipeline trait to Iterator ([#334](https://github.com/anton-rs/kona/pull/334)) -- *(derive)* prefix all metric names ([#330](https://github.com/anton-rs/kona/pull/330)) -- *(examples)* don't panic on validation fetch failure ([#327](https://github.com/anton-rs/kona/pull/327)) -- *(derive)* Warnings with metrics macro ([#322](https://github.com/anton-rs/kona/pull/322)) +- downgrade for release plz ([#458](https://github.com/op-rs/kona/pull/458)) +- *(workspace)* Add Unused Dependency Lint ([#453](https://github.com/op-rs/kona/pull/453)) +- *(derive)* remove fpvm tests ([#447](https://github.com/op-rs/kona/pull/447)) +- *(derive)* Granite Hardfork Support ([#420](https://github.com/op-rs/kona/pull/420)) +- remove data iter option ([#405](https://github.com/op-rs/kona/pull/405)) +- *(deps)* Bump Alloy Dependencies ([#409](https://github.com/op-rs/kona/pull/409)) +- *(kona-derive)* Remove SignedRecoverable Shim ([#400](https://github.com/op-rs/kona/pull/400)) +- *(derive)* Pipeline Reset ([#383](https://github.com/op-rs/kona/pull/383)) +- *(examples)* Start N Blocks Back from Tip ([#349](https://github.com/op-rs/kona/pull/349)) +- *(derive)* Unused var w/o `metrics` feature ([#345](https://github.com/op-rs/kona/pull/345)) +- *(derive)* bind the Pipeline trait to Iterator ([#334](https://github.com/op-rs/kona/pull/334)) +- *(derive)* prefix all metric names ([#330](https://github.com/op-rs/kona/pull/330)) +- *(examples)* don't panic on validation fetch failure ([#327](https://github.com/op-rs/kona/pull/327)) +- *(derive)* Warnings with metrics macro ([#322](https://github.com/op-rs/kona/pull/322)) ### Other -- *(workspace)* Alloy Version Bumps ([#467](https://github.com/anton-rs/kona/pull/467)) -- *(workspace)* Update for `anton-rs` org transfer ([#474](https://github.com/anton-rs/kona/pull/474)) -- *(workspace)* Hoist Dependencies ([#466](https://github.com/anton-rs/kona/pull/466)) -- *(derive)* reset docs ([#464](https://github.com/anton-rs/kona/pull/464)) -- *(derive)* Remove udeps ([#462](https://github.com/anton-rs/kona/pull/462)) -- *(bin)* Remove `kt` ([#461](https://github.com/anton-rs/kona/pull/461)) -- refactor types out of kona-derive ([#454](https://github.com/anton-rs/kona/pull/454)) -- *(derive)* Channel timeout ([#437](https://github.com/anton-rs/kona/pull/437)) -- *(derive)* remove previous stage trait ([#423](https://github.com/anton-rs/kona/pull/423)) -- *(examples)* Add logs to trusted-sync ([#415](https://github.com/anton-rs/kona/pull/415)) -- *(derive)* refine channel frame count buckets ([#378](https://github.com/anton-rs/kona/pull/378)) -- *(derive)* Remove noisy batch logs ([#329](https://github.com/anton-rs/kona/pull/329)) -- clean up trusted sync loop ([#318](https://github.com/anton-rs/kona/pull/318)) -- *(docs)* Label Cleanup ([#307](https://github.com/anton-rs/kona/pull/307)) -- *(derive)* add targets to stage logs ([#310](https://github.com/anton-rs/kona/pull/310)) - -## [0.0.2](https://github.com/anton-rs/kona/compare/kona-derive-v0.0.1...kona-derive-v0.0.2) - 2024-06-22 +- *(workspace)* Alloy Version Bumps ([#467](https://github.com/op-rs/kona/pull/467)) +- *(workspace)* Update for `op-rs` org transfer ([#474](https://github.com/op-rs/kona/pull/474)) +- *(workspace)* Hoist Dependencies ([#466](https://github.com/op-rs/kona/pull/466)) +- *(derive)* reset docs ([#464](https://github.com/op-rs/kona/pull/464)) +- *(derive)* Remove udeps ([#462](https://github.com/op-rs/kona/pull/462)) +- *(bin)* Remove `kt` ([#461](https://github.com/op-rs/kona/pull/461)) +- refactor types out of kona-derive ([#454](https://github.com/op-rs/kona/pull/454)) +- *(derive)* Channel timeout ([#437](https://github.com/op-rs/kona/pull/437)) +- *(derive)* remove previous stage trait ([#423](https://github.com/op-rs/kona/pull/423)) +- *(examples)* Add logs to trusted-sync ([#415](https://github.com/op-rs/kona/pull/415)) +- *(derive)* refine channel frame count buckets ([#378](https://github.com/op-rs/kona/pull/378)) +- *(derive)* Remove noisy batch logs ([#329](https://github.com/op-rs/kona/pull/329)) +- clean up trusted sync loop ([#318](https://github.com/op-rs/kona/pull/318)) +- *(docs)* Label Cleanup ([#307](https://github.com/op-rs/kona/pull/307)) +- *(derive)* add targets to stage logs ([#310](https://github.com/op-rs/kona/pull/310)) + +## [0.0.2](https://github.com/op-rs/kona/compare/kona-derive-v0.0.1...kona-derive-v0.0.2) - 2024-06-22 ### Added -- *(fjord)* fjord parameter changes ([#284](https://github.com/anton-rs/kona/pull/284)) -- *(client/host)* Oracle-backed Blob fetcher ([#255](https://github.com/anton-rs/kona/pull/255)) -- *(kona-derive)* Towards Derivation ([#243](https://github.com/anton-rs/kona/pull/243)) -- *(kona-derive)* Updated interface ([#230](https://github.com/anton-rs/kona/pull/230)) -- *(ci)* Dependabot config ([#236](https://github.com/anton-rs/kona/pull/236)) -- *(client)* `StatelessL2BlockExecutor` ([#210](https://github.com/anton-rs/kona/pull/210)) -- Pipeline Builder ([#217](https://github.com/anton-rs/kona/pull/217)) -- Minimal ResetProvider Implementation ([#208](https://github.com/anton-rs/kona/pull/208)) -- refactor the pipeline builder ([#209](https://github.com/anton-rs/kona/pull/209)) -- refactor reset provider ([#207](https://github.com/anton-rs/kona/pull/207)) -- *(preimage)* Async server components ([#183](https://github.com/anton-rs/kona/pull/183)) -- *(workspace)* Client programs in workspace ([#178](https://github.com/anton-rs/kona/pull/178)) -- *(primitives)* move attributes into primitives ([#163](https://github.com/anton-rs/kona/pull/163)) -- *(derive)* return the concrete online attributes queue type from the online stack constructor ([#158](https://github.com/anton-rs/kona/pull/158)) -- *(derive)* Abstract Alt DA out of `kona-derive` ([#156](https://github.com/anton-rs/kona/pull/156)) -- *(derive)* Online Data Source Factory Wiring ([#150](https://github.com/anton-rs/kona/pull/150)) -- *(plasma)* Implements Plasma Support for kona derive ([#152](https://github.com/anton-rs/kona/pull/152)) -- *(derive)* Pipeline Builder ([#127](https://github.com/anton-rs/kona/pull/127)) -- *(primitives)* kona-derive type refactor ([#135](https://github.com/anton-rs/kona/pull/135)) -- *(derive)* Span Batch Validation ([#121](https://github.com/anton-rs/kona/pull/121)) -- *(derive)* Use `L2ChainProvider` for system config fetching in attributes builder ([#123](https://github.com/anton-rs/kona/pull/123)) -- *(derive)* Online Blob Provider ([#117](https://github.com/anton-rs/kona/pull/117)) -- *(derive)* payload builder tests ([#106](https://github.com/anton-rs/kona/pull/106)) -- *(derive)* deposit derivation testing ([#115](https://github.com/anton-rs/kona/pull/115)) -- *(derive)* Build `L1BlockInfoTx` in payload builder ([#102](https://github.com/anton-rs/kona/pull/102)) -- *(derive)* `L2ChainProvider` w/ `op-alloy-consensus` ([#98](https://github.com/anton-rs/kona/pull/98)) -- *(derive)* Add `L1BlockInfoTx` ([#100](https://github.com/anton-rs/kona/pull/100)) -- *(derive)* Payload Attribute Building ([#92](https://github.com/anton-rs/kona/pull/92)) -- *(derive)* Online `ChainProvider` ([#93](https://github.com/anton-rs/kona/pull/93)) -- *(derive)* Move to `tracing` for telemetry ([#94](https://github.com/anton-rs/kona/pull/94)) -- *(derive)* Batch Queue Logging ([#86](https://github.com/anton-rs/kona/pull/86)) -- *(derive)* Add `ecrecover` trait + features ([#90](https://github.com/anton-rs/kona/pull/90)) -- *(derive)* Use upstream alloy ([#89](https://github.com/anton-rs/kona/pull/89)) +- *(fjord)* fjord parameter changes ([#284](https://github.com/op-rs/kona/pull/284)) +- *(client/host)* Oracle-backed Blob fetcher ([#255](https://github.com/op-rs/kona/pull/255)) +- *(kona-derive)* Towards Derivation ([#243](https://github.com/op-rs/kona/pull/243)) +- *(kona-derive)* Updated interface ([#230](https://github.com/op-rs/kona/pull/230)) +- *(ci)* Dependabot config ([#236](https://github.com/op-rs/kona/pull/236)) +- *(client)* `StatelessL2BlockExecutor` ([#210](https://github.com/op-rs/kona/pull/210)) +- Pipeline Builder ([#217](https://github.com/op-rs/kona/pull/217)) +- Minimal ResetProvider Implementation ([#208](https://github.com/op-rs/kona/pull/208)) +- refactor the pipeline builder ([#209](https://github.com/op-rs/kona/pull/209)) +- refactor reset provider ([#207](https://github.com/op-rs/kona/pull/207)) +- *(preimage)* Async server components ([#183](https://github.com/op-rs/kona/pull/183)) +- *(workspace)* Client programs in workspace ([#178](https://github.com/op-rs/kona/pull/178)) +- *(primitives)* move attributes into primitives ([#163](https://github.com/op-rs/kona/pull/163)) +- *(derive)* return the concrete online attributes queue type from the online stack constructor ([#158](https://github.com/op-rs/kona/pull/158)) +- *(derive)* Abstract Alt DA out of `kona-derive` ([#156](https://github.com/op-rs/kona/pull/156)) +- *(derive)* Online Data Source Factory Wiring ([#150](https://github.com/op-rs/kona/pull/150)) +- *(plasma)* Implements Plasma Support for kona derive ([#152](https://github.com/op-rs/kona/pull/152)) +- *(derive)* Pipeline Builder ([#127](https://github.com/op-rs/kona/pull/127)) +- *(primitives)* kona-derive type refactor ([#135](https://github.com/op-rs/kona/pull/135)) +- *(derive)* Span Batch Validation ([#121](https://github.com/op-rs/kona/pull/121)) +- *(derive)* Use `L2ChainProvider` for system config fetching in attributes builder ([#123](https://github.com/op-rs/kona/pull/123)) +- *(derive)* Online Blob Provider ([#117](https://github.com/op-rs/kona/pull/117)) +- *(derive)* payload builder tests ([#106](https://github.com/op-rs/kona/pull/106)) +- *(derive)* deposit derivation testing ([#115](https://github.com/op-rs/kona/pull/115)) +- *(derive)* Build `L1BlockInfoTx` in payload builder ([#102](https://github.com/op-rs/kona/pull/102)) +- *(derive)* `L2ChainProvider` w/ `op-alloy-consensus` ([#98](https://github.com/op-rs/kona/pull/98)) +- *(derive)* Add `L1BlockInfoTx` ([#100](https://github.com/op-rs/kona/pull/100)) +- *(derive)* Payload Attribute Building ([#92](https://github.com/op-rs/kona/pull/92)) +- *(derive)* Online `ChainProvider` ([#93](https://github.com/op-rs/kona/pull/93)) +- *(derive)* Move to `tracing` for telemetry ([#94](https://github.com/op-rs/kona/pull/94)) +- *(derive)* Batch Queue Logging ([#86](https://github.com/op-rs/kona/pull/86)) +- *(derive)* Add `ecrecover` trait + features ([#90](https://github.com/op-rs/kona/pull/90)) +- *(derive)* Use upstream alloy ([#89](https://github.com/op-rs/kona/pull/89)) - *(derive)* add next_attributes test - *(workspace)* Add `rustfmt.toml` - *(derive)* `SpanBatch` type implementation WIP @@ -258,40 +258,40 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - *(derive)* fixed bytes and encoding - *(derive)* raw span type refactoring - *(types)* span batches -- *(derive)* Channel Reader Implementation ([#65](https://github.com/anton-rs/kona/pull/65)) +- *(derive)* Channel Reader Implementation ([#65](https://github.com/op-rs/kona/pull/65)) - *(derive)* share the rollup config across stages using an arc -- *(derive)* Test Utilities ([#62](https://github.com/anton-rs/kona/pull/62)) -- Single batch type ([#43](https://github.com/anton-rs/kona/pull/43)) -- *(derive)* channel bank ([#46](https://github.com/anton-rs/kona/pull/46)) -- Frame queue stage ([#45](https://github.com/anton-rs/kona/pull/45)) -- L1 retrieval ([#44](https://github.com/anton-rs/kona/pull/44)) -- System config update event parsing ([#42](https://github.com/anton-rs/kona/pull/42)) -- Add OP receipt fields ([#41](https://github.com/anton-rs/kona/pull/41)) -- Add `TxDeposit` type ([#40](https://github.com/anton-rs/kona/pull/40)) -- L1 traversal ([#39](https://github.com/anton-rs/kona/pull/39)) +- *(derive)* Test Utilities ([#62](https://github.com/op-rs/kona/pull/62)) +- Single batch type ([#43](https://github.com/op-rs/kona/pull/43)) +- *(derive)* channel bank ([#46](https://github.com/op-rs/kona/pull/46)) +- Frame queue stage ([#45](https://github.com/op-rs/kona/pull/45)) +- L1 retrieval ([#44](https://github.com/op-rs/kona/pull/44)) +- System config update event parsing ([#42](https://github.com/op-rs/kona/pull/42)) +- Add OP receipt fields ([#41](https://github.com/op-rs/kona/pull/41)) +- Add `TxDeposit` type ([#40](https://github.com/op-rs/kona/pull/40)) +- L1 traversal ([#39](https://github.com/op-rs/kona/pull/39)) ### Fixed -- *(derive)* Fjord brotli decompression ([#298](https://github.com/anton-rs/kona/pull/298)) -- *(examples)* Dynamic Rollup Config Loading ([#293](https://github.com/anton-rs/kona/pull/293)) -- type re-exports ([#280](https://github.com/anton-rs/kona/pull/280)) -- *(kona-derive)* reuse upstream reqwest provider ([#229](https://github.com/anton-rs/kona/pull/229)) -- Derivation Pipeline ([#220](https://github.com/anton-rs/kona/pull/220)) -- *(derive)* Alloy EIP4844 Blob Type ([#215](https://github.com/anton-rs/kona/pull/215)) -- Strong Error Typing ([#187](https://github.com/anton-rs/kona/pull/187)) -- *(derive)* inline blob verification into the blob provider ([#175](https://github.com/anton-rs/kona/pull/175)) -- *(derive)* fix span batch utils read_tx_data() ([#170](https://github.com/anton-rs/kona/pull/170)) -- *(derive)* Ethereum Data Source ([#159](https://github.com/anton-rs/kona/pull/159)) -- *(derive)* remove unnecessary online feature decorator ([#160](https://github.com/anton-rs/kona/pull/160)) -- *(ci)* Release plz ([#145](https://github.com/anton-rs/kona/pull/145)) -- *(derive)* move span batch conversion to try from trait ([#142](https://github.com/anton-rs/kona/pull/142)) -- *(derive)* Small Fixes and Span Batch Validation Fix ([#139](https://github.com/anton-rs/kona/pull/139)) -- *(workspace)* Release plz ([#138](https://github.com/anton-rs/kona/pull/138)) -- *(workspace)* Release plz ([#137](https://github.com/anton-rs/kona/pull/137)) -- *(derive)* Rebase span batch validation tests ([#125](https://github.com/anton-rs/kona/pull/125)) -- *(derive)* Span batch bitlist encoding ([#122](https://github.com/anton-rs/kona/pull/122)) -- *(derive)* Doc Touchups and Telemetry ([#105](https://github.com/anton-rs/kona/pull/105)) -- *(derive)* Derive full `SpanBatch` in channel reader ([#97](https://github.com/anton-rs/kona/pull/97)) -- *(derive)* Stage Decoupling ([#88](https://github.com/anton-rs/kona/pull/88)) +- *(derive)* Fjord brotli decompression ([#298](https://github.com/op-rs/kona/pull/298)) +- *(examples)* Dynamic Rollup Config Loading ([#293](https://github.com/op-rs/kona/pull/293)) +- type re-exports ([#280](https://github.com/op-rs/kona/pull/280)) +- *(kona-derive)* reuse upstream reqwest provider ([#229](https://github.com/op-rs/kona/pull/229)) +- Derivation Pipeline ([#220](https://github.com/op-rs/kona/pull/220)) +- *(derive)* Alloy EIP4844 Blob Type ([#215](https://github.com/op-rs/kona/pull/215)) +- Strong Error Typing ([#187](https://github.com/op-rs/kona/pull/187)) +- *(derive)* inline blob verification into the blob provider ([#175](https://github.com/op-rs/kona/pull/175)) +- *(derive)* fix span batch utils read_tx_data() ([#170](https://github.com/op-rs/kona/pull/170)) +- *(derive)* Ethereum Data Source ([#159](https://github.com/op-rs/kona/pull/159)) +- *(derive)* remove unnecessary online feature decorator ([#160](https://github.com/op-rs/kona/pull/160)) +- *(ci)* Release plz ([#145](https://github.com/op-rs/kona/pull/145)) +- *(derive)* move span batch conversion to try from trait ([#142](https://github.com/op-rs/kona/pull/142)) +- *(derive)* Small Fixes and Span Batch Validation Fix ([#139](https://github.com/op-rs/kona/pull/139)) +- *(workspace)* Release plz ([#138](https://github.com/op-rs/kona/pull/138)) +- *(workspace)* Release plz ([#137](https://github.com/op-rs/kona/pull/137)) +- *(derive)* Rebase span batch validation tests ([#125](https://github.com/op-rs/kona/pull/125)) +- *(derive)* Span batch bitlist encoding ([#122](https://github.com/op-rs/kona/pull/122)) +- *(derive)* Doc Touchups and Telemetry ([#105](https://github.com/op-rs/kona/pull/105)) +- *(derive)* Derive full `SpanBatch` in channel reader ([#97](https://github.com/op-rs/kona/pull/97)) +- *(derive)* Stage Decoupling ([#88](https://github.com/op-rs/kona/pull/88)) - *(derive)* add back removed test - *(derive)* lints - *(derive)* extend attributes queue unit test @@ -301,8 +301,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - *(derive)* attributes queue - *(derive)* hoist params - *(derive)* merge upstream changes -- *(derive)* fix bricked arc stage param construction ([#84](https://github.com/anton-rs/kona/pull/84)) -- *(derive)* l1 retrieval docs ([#80](https://github.com/anton-rs/kona/pull/80)) +- *(derive)* fix bricked arc stage param construction ([#84](https://github.com/op-rs/kona/pull/84)) +- *(derive)* l1 retrieval docs ([#80](https://github.com/op-rs/kona/pull/80)) - *(derive)* clean up frame queue docs - *(derive)* frame queue error bubbling and docs - *(derive)* rebase @@ -313,32 +313,32 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - *(derive)* span batch tx rlp - *(derive)* span type encodings and decodings - *(derive)* more types -- *(derive)* small l1 retrieval doc comment fix ([#61](https://github.com/anton-rs/kona/pull/61)) +- *(derive)* small l1 retrieval doc comment fix ([#61](https://github.com/op-rs/kona/pull/61)) ### Other -- version dependencies ([#296](https://github.com/anton-rs/kona/pull/296)) -- payload decoding tests ([#287](https://github.com/anton-rs/kona/pull/287)) -- payload decoding tests ([#289](https://github.com/anton-rs/kona/pull/289)) -- re-export input types ([#279](https://github.com/anton-rs/kona/pull/279)) -- *(deps)* fast forward op alloy dep ([#267](https://github.com/anton-rs/kona/pull/267)) -- *(derive)* cleanup pipeline tracing ([#264](https://github.com/anton-rs/kona/pull/264)) -- *(derive)* online module touchups ([#265](https://github.com/anton-rs/kona/pull/265)) -- *(derive)* Sources Touchups ([#266](https://github.com/anton-rs/kona/pull/266)) -- *(kona-derive)* Online Pipeline Cleanup ([#241](https://github.com/anton-rs/kona/pull/241)) -- *(derive)* data source unit tests ([#181](https://github.com/anton-rs/kona/pull/181)) -- *(workspace)* Move `alloy-primitives` to workspace dependencies ([#103](https://github.com/anton-rs/kona/pull/103)) -- *(ci)* Fail CI on doclint failure ([#101](https://github.com/anton-rs/kona/pull/101)) -- *(derive)* cleanups ([#91](https://github.com/anton-rs/kona/pull/91)) +- version dependencies ([#296](https://github.com/op-rs/kona/pull/296)) +- payload decoding tests ([#287](https://github.com/op-rs/kona/pull/287)) +- payload decoding tests ([#289](https://github.com/op-rs/kona/pull/289)) +- re-export input types ([#279](https://github.com/op-rs/kona/pull/279)) +- *(deps)* fast forward op alloy dep ([#267](https://github.com/op-rs/kona/pull/267)) +- *(derive)* cleanup pipeline tracing ([#264](https://github.com/op-rs/kona/pull/264)) +- *(derive)* online module touchups ([#265](https://github.com/op-rs/kona/pull/265)) +- *(derive)* Sources Touchups ([#266](https://github.com/op-rs/kona/pull/266)) +- *(kona-derive)* Online Pipeline Cleanup ([#241](https://github.com/op-rs/kona/pull/241)) +- *(derive)* data source unit tests ([#181](https://github.com/op-rs/kona/pull/181)) +- *(workspace)* Move `alloy-primitives` to workspace dependencies ([#103](https://github.com/op-rs/kona/pull/103)) +- *(ci)* Fail CI on doclint failure ([#101](https://github.com/op-rs/kona/pull/101)) +- *(derive)* cleanups ([#91](https://github.com/op-rs/kona/pull/91)) - Merge branch 'main' into refcell/data-sources -- Merge pull request [#87](https://github.com/anton-rs/kona/pull/87) from anton-rs/refcell/origin-providers +- Merge pull request [#87](https://github.com/op-rs/kona/pull/87) from op-rs/refcell/origin-providers - Merge branch 'main' into refcell/channel-bank-tests - Merge branch 'main' into refcell/payload-queue -- *(derive)* L1Traversal Doc and Test Cleanup ([#79](https://github.com/anton-rs/kona/pull/79)) -- Merge pull request [#67](https://github.com/anton-rs/kona/pull/67) from anton-rs/refcell/batch-queue +- *(derive)* L1Traversal Doc and Test Cleanup ([#79](https://github.com/op-rs/kona/pull/79)) +- Merge pull request [#67](https://github.com/op-rs/kona/pull/67) from op-rs/refcell/batch-queue - *(derive)* Channel reader tests + fixes, batch type fixes - *(derive)* `RawSpanBatch` diff decoding/encoding test - *(derive)* rebase + move `alloy` module - *(derive)* Clean up RLP encoding + use `TxType` rather than ints -- Update `derive` lint rules ([#47](https://github.com/anton-rs/kona/pull/47)) -- scaffold ([#37](https://github.com/anton-rs/kona/pull/37)) -- Make versions of packages independent ([#36](https://github.com/anton-rs/kona/pull/36)) +- Update `derive` lint rules ([#47](https://github.com/op-rs/kona/pull/47)) +- scaffold ([#37](https://github.com/op-rs/kona/pull/37)) +- Make versions of packages independent ([#36](https://github.com/op-rs/kona/pull/36)) diff --git a/crates/derive/Cargo.toml b/crates/derive/Cargo.toml index 7da5a04f65..8d5c533656 100644 --- a/crates/derive/Cargo.toml +++ b/crates/derive/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "kona-derive" description = "A no_std derivation pipeline implementation for the OP Stack" -version = "0.2.0" +version = "0.2.3" edition.workspace = true authors.workspace = true license.workspace = true @@ -25,6 +25,7 @@ op-alloy-protocol.workspace = true op-alloy-rpc-types-engine.workspace = true op-alloy-consensus = { workspace = true, features = ["k256"] } + # General tracing.workspace = true async-trait.workspace = true @@ -34,11 +35,18 @@ thiserror.workspace = true spin = { workspace = true, optional = true } tracing-subscriber = { workspace = true, optional = true, features = ["fmt"] } +bytes = { workspace = true} +hex = {workspace = true} +prost = { workspace = true, default-features = false} +rlp = {workspace = true, default-features = false} +log = "0.4.22" +miniz_oxide.workspace = true + + [dev-dependencies] spin.workspace = true proptest.workspace = true serde_json.workspace = true -op-alloy-registry.workspace = true tokio = { workspace = true, features = ["full"] } tracing-subscriber = { workspace = true, features = ["fmt"] } alloy-primitives = { workspace = true, features = ["rlp", "k256", "map", "arbitrary"] } diff --git a/crates/derive/README.md b/crates/derive/README.md index bbf2935a2a..e8cdbad1b6 100644 --- a/crates/derive/README.md +++ b/crates/derive/README.md @@ -1,9 +1,9 @@ # `kona-derive` -CI +CI Kona Derive -License -Codecov +License +Codecov A `no_std` compatible implementation of the OP Stack's [derivation pipeline][derive]. diff --git a/crates/derive/src/attributes/stateful.rs b/crates/derive/src/attributes/stateful.rs index c9390da662..bba03f247b 100644 --- a/crates/derive/src/attributes/stateful.rs +++ b/crates/derive/src/attributes/stateful.rs @@ -1,4 +1,3 @@ -#![allow(clippy::unnecessary_map_or)] //! The [`AttributesBuilder`] and it's default implementation. use crate::{ @@ -13,9 +12,9 @@ use alloy_primitives::{address, Address, Bytes, B256}; use alloy_rlp::Encodable; use alloy_rpc_types_engine::PayloadAttributes; use async_trait::async_trait; -use op_alloy_consensus::{Hardfork, Hardforks}; use op_alloy_genesis::RollupConfig; -use op_alloy_protocol::{decode_deposit, L1BlockInfoTx, L2BlockInfo, DEPOSIT_EVENT_ABI_HASH}; +use op_alloy_protocol::L2BlockInfo; +use op_alloy_protocol::{decode_deposit, L1BlockInfoTx, DEPOSIT_EVENT_ABI_HASH}; use op_alloy_rpc_types_engine::OpPayloadAttributes; /// The sequencer fee vault address. @@ -90,11 +89,7 @@ where .await .map_err(|e| PipelineError::BadEncoding(e).crit())?; sys_config - .update_with_receipts( - &receipts, - self.rollup_cfg.l1_system_config_address, - self.rollup_cfg.is_ecotone_active(header.timestamp), - ) + .update_with_receipts(&receipts, self.rollup_cfg.l1_system_config_address) .map_err(|e| PipelineError::SystemConfigUpdate(e).crit())?; l1_header = header; deposit_transactions = deposits; @@ -129,18 +124,6 @@ where )); } - let mut upgrade_transactions: Vec = vec![]; - if self.rollup_cfg.is_ecotone_active(next_l2_time) && - !self.rollup_cfg.is_ecotone_active(l2_parent.block_info.timestamp) - { - upgrade_transactions = Hardforks::ECOTONE.txs().collect(); - } - if self.rollup_cfg.is_fjord_active(next_l2_time) && - !self.rollup_cfg.is_fjord_active(l2_parent.block_info.timestamp) - { - upgrade_transactions.append(&mut Hardforks::FJORD.txs().collect()); - } - // Build and encode the L1 info transaction for the current payload. let (_, l1_info_tx_envelope) = L1BlockInfoTx::try_new_with_deposit_tx( &self.rollup_cfg, @@ -155,23 +138,12 @@ where let mut encoded_l1_info_tx = Vec::with_capacity(l1_info_tx_envelope.length()); l1_info_tx_envelope.encode_2718(&mut encoded_l1_info_tx); - let mut txs = - Vec::with_capacity(1 + deposit_transactions.len() + upgrade_transactions.len()); + let mut txs = Vec::with_capacity(1 + deposit_transactions.len()); txs.push(encoded_l1_info_tx.into()); txs.extend(deposit_transactions); - txs.extend(upgrade_transactions); let mut withdrawals = None; - if self.rollup_cfg.is_canyon_active(next_l2_time) { - withdrawals = Some(Vec::default()); - } - let mut parent_beacon_root = None; - if self.rollup_cfg.is_ecotone_active(next_l2_time) { - // if the parent beacon root is not available, default to zero hash - parent_beacon_root = Some(l1_header.parent_beacon_block_root.unwrap_or_default()); - } - Ok(OpPayloadAttributes { payload_attributes: PayloadAttributes { timestamp: next_l2_time, @@ -179,19 +151,13 @@ where suggested_fee_recipient: SEQUENCER_FEE_VAULT_ADDRESS, parent_beacon_block_root: parent_beacon_root, withdrawals, - target_blobs_per_block: None, - max_blobs_per_block: None, }, transactions: Some(txs), no_tx_pool: Some(true), gas_limit: Some(u64::from_be_bytes( alloy_primitives::U64::from(sys_config.gas_limit).to_be_bytes(), )), - eip_1559_params: sys_config.eip_1559_params( - &self.rollup_cfg, - l2_parent.block_info.timestamp, - next_l2_time, - ), + base_fee: None, }) } } @@ -239,7 +205,9 @@ mod tests { use alloy_consensus::Header; use alloy_primitives::{Log, LogData, B256, U256, U64}; use op_alloy_genesis::SystemConfig; - use op_alloy_protocol::{BlockInfo, DepositError}; + use op_alloy_protocol::BlockInfo; + use op_alloy_protocol::DepositError; + use proptest::num::u128; fn generate_valid_log() -> Log { let deposit_contract = address!("1111111111111111111111111111111111111111"); @@ -453,164 +421,17 @@ mod tests { suggested_fee_recipient: SEQUENCER_FEE_VAULT_ADDRESS, parent_beacon_block_root: None, withdrawals: None, - target_blobs_per_block: None, - max_blobs_per_block: None, }, transactions: payload.transactions.clone(), no_tx_pool: Some(true), gas_limit: Some(u64::from_be_bytes( alloy_primitives::U64::from(SystemConfig::default().gas_limit).to_be_bytes(), )), - eip_1559_params: None, - }; - assert_eq!(payload, expected); - assert_eq!(payload.transactions.unwrap().len(), 1); - } - - #[tokio::test] - async fn test_prepare_payload_with_canyon() { - let block_time = 10; - let timestamp = 100; - let cfg = Arc::new(RollupConfig { block_time, canyon_time: Some(0), ..Default::default() }); - let l2_number = 1; - let mut fetcher = TestSystemConfigL2Fetcher::default(); - fetcher.insert(l2_number, SystemConfig::default()); - let mut provider = TestChainProvider::default(); - let header = Header { timestamp, ..Default::default() }; - let prev_randao = header.mix_hash; - let hash = header.hash_slow(); - provider.insert_header(hash, header); - let mut builder = StatefulAttributesBuilder::new(cfg, fetcher, provider); - let epoch = BlockNumHash { hash, number: l2_number }; - let l2_parent = L2BlockInfo { - block_info: BlockInfo { - hash: B256::ZERO, - number: l2_number, - timestamp, - parent_hash: hash, - }, - l1_origin: BlockNumHash { hash, number: l2_number }, - seq_num: 0, - }; - let next_l2_time = l2_parent.block_info.timestamp + block_time; - let payload = builder.prepare_payload_attributes(l2_parent, epoch).await.unwrap(); - let expected = OpPayloadAttributes { - payload_attributes: PayloadAttributes { - timestamp: next_l2_time, - prev_randao, - suggested_fee_recipient: SEQUENCER_FEE_VAULT_ADDRESS, - parent_beacon_block_root: None, - withdrawals: Some(Vec::default()), - target_blobs_per_block: None, - max_blobs_per_block: None, - }, - transactions: payload.transactions.clone(), - no_tx_pool: Some(true), - gas_limit: Some(u64::from_be_bytes( - alloy_primitives::U64::from(SystemConfig::default().gas_limit).to_be_bytes(), + base_fee: Some(u128::from_be_bytes( + alloy_primitives::U256::from(SystemConfig::default().base_fee).to_be_bytes(), )), - eip_1559_params: None, }; assert_eq!(payload, expected); assert_eq!(payload.transactions.unwrap().len(), 1); } - - #[tokio::test] - async fn test_prepare_payload_with_ecotone() { - let block_time = 2; - let timestamp = 100; - let cfg = - Arc::new(RollupConfig { block_time, ecotone_time: Some(102), ..Default::default() }); - let l2_number = 1; - let mut fetcher = TestSystemConfigL2Fetcher::default(); - fetcher.insert(l2_number, SystemConfig::default()); - let mut provider = TestChainProvider::default(); - let header = Header { timestamp, ..Default::default() }; - let parent_beacon_block_root = Some(header.parent_beacon_block_root.unwrap_or_default()); - let prev_randao = header.mix_hash; - let hash = header.hash_slow(); - provider.insert_header(hash, header); - let mut builder = StatefulAttributesBuilder::new(cfg, fetcher, provider); - let epoch = BlockNumHash { hash, number: l2_number }; - let l2_parent = L2BlockInfo { - block_info: BlockInfo { - hash: B256::ZERO, - number: l2_number, - timestamp, - parent_hash: hash, - }, - l1_origin: BlockNumHash { hash, number: l2_number }, - seq_num: 0, - }; - let next_l2_time = l2_parent.block_info.timestamp + block_time; - let payload = builder.prepare_payload_attributes(l2_parent, epoch).await.unwrap(); - let expected = OpPayloadAttributes { - payload_attributes: PayloadAttributes { - timestamp: next_l2_time, - prev_randao, - suggested_fee_recipient: SEQUENCER_FEE_VAULT_ADDRESS, - parent_beacon_block_root, - withdrawals: Some(vec![]), - target_blobs_per_block: None, - max_blobs_per_block: None, - }, - transactions: payload.transactions.clone(), - no_tx_pool: Some(true), - gas_limit: Some(u64::from_be_bytes( - alloy_primitives::U64::from(SystemConfig::default().gas_limit).to_be_bytes(), - )), - eip_1559_params: None, - }; - assert_eq!(payload, expected); - assert_eq!(payload.transactions.unwrap().len(), 7); - } - - #[tokio::test] - async fn test_prepare_payload_with_fjord() { - let block_time = 2; - let timestamp = 100; - let cfg = - Arc::new(RollupConfig { block_time, fjord_time: Some(102), ..Default::default() }); - let l2_number = 1; - let mut fetcher = TestSystemConfigL2Fetcher::default(); - fetcher.insert(l2_number, SystemConfig::default()); - let mut provider = TestChainProvider::default(); - let header = Header { timestamp, ..Default::default() }; - let prev_randao = header.mix_hash; - let hash = header.hash_slow(); - provider.insert_header(hash, header); - let mut builder = StatefulAttributesBuilder::new(cfg, fetcher, provider); - let epoch = BlockNumHash { hash, number: l2_number }; - let l2_parent = L2BlockInfo { - block_info: BlockInfo { - hash: B256::ZERO, - number: l2_number, - timestamp, - parent_hash: hash, - }, - l1_origin: BlockNumHash { hash, number: l2_number }, - seq_num: 0, - }; - let next_l2_time = l2_parent.block_info.timestamp + block_time; - let payload = builder.prepare_payload_attributes(l2_parent, epoch).await.unwrap(); - let expected = OpPayloadAttributes { - payload_attributes: PayloadAttributes { - timestamp: next_l2_time, - prev_randao, - suggested_fee_recipient: SEQUENCER_FEE_VAULT_ADDRESS, - parent_beacon_block_root: Some(B256::ZERO), - withdrawals: Some(vec![]), - target_blobs_per_block: None, - max_blobs_per_block: None, - }, - transactions: payload.transactions.clone(), - no_tx_pool: Some(true), - gas_limit: Some(u64::from_be_bytes( - alloy_primitives::U64::from(SystemConfig::default().gas_limit).to_be_bytes(), - )), - eip_1559_params: None, - }; - assert_eq!(payload.transactions.as_ref().unwrap().len(), 10); - assert_eq!(payload, expected); - } } diff --git a/crates/derive/src/da/da.rs b/crates/derive/src/da/da.rs new file mode 100644 index 0000000000..2e62a335d1 --- /dev/null +++ b/crates/derive/src/da/da.rs @@ -0,0 +1,16 @@ +use alloc::boxed::Box; +use alloc::vec::Vec; +use async_trait::async_trait; +use core::fmt::Display; + +#[async_trait] +pub trait IEigenDA { + /// The error type for the [IEigenDA]. + type Error: Display; + + /// get blob from EigenDA with commitment + async fn retrieve_blob_with_commitment( + &self, + commitment: &[u8], + ) -> Result, Self::Error>; +} diff --git a/crates/derive/src/da/mod.rs b/crates/derive/src/da/mod.rs new file mode 100644 index 0000000000..003e7e65d5 --- /dev/null +++ b/crates/derive/src/da/mod.rs @@ -0,0 +1,2 @@ +pub mod da; +pub use da::*; diff --git a/crates/derive/src/errors/da.rs b/crates/derive/src/errors/da.rs new file mode 100644 index 0000000000..c0c8bf31ed --- /dev/null +++ b/crates/derive/src/errors/da.rs @@ -0,0 +1,49 @@ +use alloc::string::String; +use thiserror::Error; + +/// An [EigenDAProxyError] Error. + +#[derive(Error, Debug, PartialEq, Eq)] +pub enum EigenDAProxyError { + /// Retrieve blob error. + #[error("Failed to retrieve blob, error: {0}")] + RetrieveBlob(String), + /// Retrieve blob with commitment error. + #[error("Failed to retrieve blob with commitment, error: {0}")] + RetrieveBlobWithCommitment(String), + /// Disperse blob error. + #[error("Failed to disperse blob, error: {0}")] + DisperseBlob(String), + /// Get blob status error. + #[error("Failed to get blob status, error: {0}")] + GetBlobStatus(String), + /// No fund blob from EigenDA. + #[error("Blob not fund from EigenDA")] + NotFound, + /// Invalid input data len. + #[error("Invalid input data len for disperse blob from EigenDA")] + InvalidInput, + /// Request timeout. + #[error("Request blob timeout, error: {0}")] + TimeOut(String), +} + +/// An error returned by the [EigenDAProviderError] +#[derive(Error, Debug, PartialEq, Eq)] +pub enum EigenDAProviderError { + /// Retrieve Frame from da indexer error. + #[error("Failed to retrieve blob from da indexer, error: {0}")] + RetrieveFramesFromDaIndexer(String), + /// Request timeout. + #[error("Request blob timeout, error: {0}")] + TimeOut(String), + #[error("Get blob from indexer da, status: {0}")] + Status(String), + /// Error pertaining to the backend transport. + #[error("{0}")] + Backend(String), + #[error("Failed to decode blob, error: {0}")] + RLPDecodeError(String), + #[error("Failed to decode proto buf, error: {0}")] + ProtoDecodeError(String), +} diff --git a/crates/derive/src/errors/mod.rs b/crates/derive/src/errors/mod.rs index f4b66f72c5..2af527fb1b 100644 --- a/crates/derive/src/errors/mod.rs +++ b/crates/derive/src/errors/mod.rs @@ -11,3 +11,6 @@ pub use pipeline::{PipelineEncodingError, PipelineError, PipelineErrorKind, Rese mod sources; pub use sources::{BlobDecodingError, BlobProviderError}; + +mod da; +pub use da::{EigenDAProviderError, EigenDAProxyError}; diff --git a/crates/derive/src/errors/stages.rs b/crates/derive/src/errors/stages.rs index bced73789e..53c3e039d1 100644 --- a/crates/derive/src/errors/stages.rs +++ b/crates/derive/src/errors/stages.rs @@ -1,12 +1,12 @@ //! Error types for derivation pipeline stages. -use op_alloy_protocol::MAX_SPAN_BATCH_ELEMENTS; +use op_alloy_protocol::MAX_RLP_BYTES_PER_CHANNEL; use thiserror::Error; /// A frame decompression error. #[derive(Error, Debug, PartialEq, Eq)] pub enum BatchDecompressionError { - /// The buffer exceeds the [MAX_SPAN_BATCH_ELEMENTS] protocol parameter. - #[error("The batch exceeds the maximum number of elements: {max_size}", max_size = MAX_SPAN_BATCH_ELEMENTS)] + /// The buffer exceeds the [MAX_RLP_BYTES_PER_CHANNEL] protocol parameter. + #[error("The batch exceeds the maximum number of elements: {max_size}", max_size = MAX_RLP_BYTES_PER_CHANNEL)] BatchTooLarge, } diff --git a/crates/derive/src/lib.rs b/crates/derive/src/lib.rs index 732c8db86a..aad0cf6c90 100644 --- a/crates/derive/src/lib.rs +++ b/crates/derive/src/lib.rs @@ -1,7 +1,7 @@ #![doc = include_str!("../README.md")] #![doc( - html_logo_url = "https://raw.githubusercontent.com/anton-rs/kona/main/assets/square.png", - html_favicon_url = "https://raw.githubusercontent.com/anton-rs/kona/main/assets/favicon.ico" + html_logo_url = "https://raw.githubusercontent.com/op-rs/kona/main/assets/square.png", + html_favicon_url = "https://raw.githubusercontent.com/op-rs/kona/main/assets/favicon.ico" )] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] #![cfg_attr(not(test), warn(unused_crate_dependencies))] @@ -27,5 +27,7 @@ pub mod stages; pub mod traits; pub mod types; +pub mod da; +mod proto; #[cfg(any(test, feature = "test-utils"))] pub mod test_utils; diff --git a/crates/derive/src/pipeline/builder.rs b/crates/derive/src/pipeline/builder.rs index eb6ba26c99..44d2bada3d 100644 --- a/crates/derive/src/pipeline/builder.rs +++ b/crates/derive/src/pipeline/builder.rs @@ -18,9 +18,9 @@ type L1RetrievalStage = L1Retrieval>; type FrameQueueStage = FrameQueue>; type ChannelProviderStage = ChannelProvider>; type ChannelReaderStage = ChannelReader>; -type BatchStreamStage = BatchStream, T>; -type BatchProviderStage = BatchProvider, T>; -type AttributesQueueStage = AttributesQueue, B>; +type BatchStreamStage = BatchStream>; +type BatchProviderStage = BatchProvider>; +type AttributesQueueStage = AttributesQueue, B>; /// The `PipelineBuilder` constructs a [DerivationPipeline] using a builder pattern. #[derive(Debug)] @@ -107,13 +107,13 @@ where } /// Builds the pipeline. - pub fn build(self) -> DerivationPipeline, T> { + pub fn build(self) -> DerivationPipeline, T> { self.into() } } impl From> - for DerivationPipeline, T> + for DerivationPipeline, T> where B: AttributesBuilder + Send + Debug, P: ChainProvider + Send + Sync + Debug, @@ -135,10 +135,8 @@ where let frame_queue = FrameQueue::new(l1_retrieval, Arc::clone(&rollup_config)); let channel_provider = ChannelProvider::new(Arc::clone(&rollup_config), frame_queue); let channel_reader = ChannelReader::new(channel_provider, Arc::clone(&rollup_config)); - let batch_stream = - BatchStream::new(channel_reader, rollup_config.clone(), l2_chain_provider.clone()); - let batch_provider = - BatchProvider::new(rollup_config.clone(), batch_stream, l2_chain_provider.clone()); + let batch_stream = BatchStream::new(channel_reader); + let batch_provider = BatchProvider::new(rollup_config.clone(), batch_stream); let attributes = AttributesQueue::new(rollup_config.clone(), batch_provider, attributes_builder); diff --git a/crates/derive/src/pipeline/core.rs b/crates/derive/src/pipeline/core.rs index 927f8cf1ea..c794b8797f 100644 --- a/crates/derive/src/pipeline/core.rs +++ b/crates/derive/src/pipeline/core.rs @@ -91,8 +91,8 @@ where /// The `signal` is contains the signal variant with any necessary parameters. async fn signal(&mut self, signal: Signal) -> PipelineResult<()> { match signal { - mut s @ Signal::Reset(ResetSignal { l2_safe_head, .. }) | - mut s @ Signal::Activation(ActivationSignal { l2_safe_head, .. }) => { + mut s @ Signal::Reset(ResetSignal { l2_safe_head, .. }) + | mut s @ Signal::Activation(ActivationSignal { l2_safe_head, .. }) => { let system_config = self .l2_chain_provider .system_config_by_number( @@ -176,6 +176,10 @@ where } StepResult::AdvancedOrigin } + PipelineErrorKind::Temporary(_) => { + trace!(target: "pipeline", "Attributes queue step failed due to temporary error: {:?}", err); + StepResult::StepFailed(err) + } _ => { warn!(target: "pipeline", "Attributes queue step failed: {:?}", err); StepResult::StepFailed(err) @@ -210,10 +214,9 @@ mod tests { transactions: None, no_tx_pool: None, gas_limit: None, - eip_1559_params: None, + base_fee: None, }, parent: Default::default(), - is_last_in_span: false, } } diff --git a/crates/derive/src/proto/calldata.proto b/crates/derive/src/proto/calldata.proto new file mode 100644 index 0000000000..3d218bdae7 --- /dev/null +++ b/crates/derive/src/proto/calldata.proto @@ -0,0 +1,25 @@ +syntax = "proto3"; + +package calldata; + +// CalldataFrame wraps the frame data or the eigenda blob reference to the frame data +message CalldataFrame { + oneof value { + bytes frame = 1; + FrameRef frame_ref = 2; + } +} + +// This is a copy of BlobRequest here: https://github.com/Layr-Labs/eigenda/blob/main/api/proto/retriever/retriever.proto#L10 +message FrameRef { + // defined by eigenda + bytes batch_header_hash = 1; + uint32 blob_index = 2; + uint32 reference_block_number = 3; + repeated uint32 quorum_ids = 4; + uint32 blob_length = 5; + + // defined by mantle + bytes request_id = 100; + bytes commitment = 101; +} diff --git a/crates/derive/src/proto/calldata.rs b/crates/derive/src/proto/calldata.rs new file mode 100644 index 0000000000..1a7476fe91 --- /dev/null +++ b/crates/derive/src/proto/calldata.rs @@ -0,0 +1,40 @@ +// This file is @generated by prost-build. +/// CalldataFrame wraps the frame data or the eigenda blob reference to the frame data +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct CalldataFrame { + #[prost(oneof = "calldata_frame::Value", tags = "1, 2")] + pub value: ::core::option::Option, +} +/// Nested message and enum types in `CalldataFrame`. +pub mod calldata_frame { + #[allow(clippy::derive_partial_eq_without_eq)] + #[derive(Clone, PartialEq, ::prost::Oneof)] + pub enum Value { + #[prost(bytes, tag = "1")] + Frame(::prost::alloc::vec::Vec), + #[prost(message, tag = "2")] + FrameRef(super::FrameRef), + } +} +/// This is a copy of BlobRequest here: +#[allow(clippy::derive_partial_eq_without_eq)] +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct FrameRef { + /// defined by eigenda + #[prost(bytes = "vec", tag = "1")] + pub batch_header_hash: ::prost::alloc::vec::Vec, + #[prost(uint32, tag = "2")] + pub blob_index: u32, + #[prost(uint32, tag = "3")] + pub reference_block_number: u32, + #[prost(uint32, repeated, tag = "4")] + pub quorum_ids: ::prost::alloc::vec::Vec, + #[prost(uint32, tag = "5")] + pub blob_length: u32, + /// defined by mantle + #[prost(bytes = "vec", tag = "100")] + pub request_id: ::prost::alloc::vec::Vec, + #[prost(bytes = "vec", tag = "101")] + pub commitment: ::prost::alloc::vec::Vec, +} diff --git a/crates/derive/src/proto/mod.rs b/crates/derive/src/proto/mod.rs new file mode 100644 index 0000000000..46a3376206 --- /dev/null +++ b/crates/derive/src/proto/mod.rs @@ -0,0 +1,2 @@ +mod calldata; +pub use calldata::*; diff --git a/crates/derive/src/sources/calldata.rs b/crates/derive/src/sources/calldata.rs index 7c0a32cd12..f056bf0bc7 100644 --- a/crates/derive/src/sources/calldata.rs +++ b/crates/derive/src/sources/calldata.rs @@ -91,7 +91,7 @@ mod tests { use super::*; use crate::{errors::PipelineErrorKind, test_utils::TestChainProvider}; use alloc::{vec, vec::Vec}; - use alloy_consensus::{Signed, TxEip2930, TxEip4844, TxEip4844Variant, TxLegacy}; + use alloy_consensus::{Signed, TxEip2930, TxEip4844, TxEip4844Variant, TxEip7702, TxLegacy}; use alloy_primitives::{address, Address, PrimitiveSignature as Signature, TxKind}; pub(crate) fn test_legacy_tx(to: Address) -> TxEnvelope { @@ -112,6 +112,15 @@ mod tests { )) } + pub(crate) fn test_eip7702_tx(to: Address) -> TxEnvelope { + let sig = Signature::test_signature(); + TxEnvelope::Eip7702(Signed::new_unchecked( + TxEip7702 { to, ..Default::default() }, + sig, + Default::default(), + )) + } + pub(crate) fn test_blob_tx(to: Address) -> TxEnvelope { let sig = Signature::test_signature(); TxEnvelope::Eip4844(Signed::new_unchecked( @@ -231,6 +240,21 @@ mod tests { assert!(source.open); } + #[tokio::test] + async fn test_load_calldata_eip7702_tx_ignored() { + let batch_inbox_address = address!("0123456789012345678901234567890123456789"); + let mut source = default_test_calldata_source(); + source.batch_inbox_address = batch_inbox_address; + let tx = test_eip7702_tx(batch_inbox_address); + source.signer = tx.recover_signer().unwrap(); + let block_info = BlockInfo::default(); + source.chain_provider.insert_block_with_transactions(0, block_info, vec![tx]); + assert!(!source.open); // Source is not open by default. + assert!(source.load_calldata(&BlockInfo::default()).await.is_ok()); + assert!(source.calldata.is_empty()); + assert!(source.open); + } + #[tokio::test] async fn test_next_err_loading_calldata() { let mut source = default_test_calldata_source(); diff --git a/crates/derive/src/sources/eigen_da.rs b/crates/derive/src/sources/eigen_da.rs new file mode 100644 index 0000000000..7c3c930a3e --- /dev/null +++ b/crates/derive/src/sources/eigen_da.rs @@ -0,0 +1,350 @@ +use crate::errors::{ + BlobDecodingError, BlobProviderError, EigenDAProviderError, EigenDAProxyError, PipelineError, +}; +use crate::prelude::ChainProvider; +use crate::proto::{calldata_frame, CalldataFrame}; +use crate::sources::BlobData; +use crate::traits::{BlobProvider, DataAvailabilityProvider, EigenDAProvider}; +use crate::types::PipelineResult; +use alloc::boxed::Box; +use alloc::format; +use alloc::string::ToString; +use alloc::vec::Vec; +use alloy_consensus::{Transaction, TxEip4844Variant, TxEnvelope, TxType}; +use alloy_eips::eip4844::IndexedBlobHash; +use alloy_primitives::{hex, Address, Bytes}; +use alloy_rlp::Rlp; +use async_trait::async_trait; +use core::ops::Deref; +use op_alloy_protocol::BlockInfo; +use prost::Message; +use rlp::{decode, Decodable, DecoderError}; +use tracing::{error, info, warn}; + +/// Useful to dinstiguish between plain calldata and alt-da blob refs +/// Support seamless migration of existing rollups using ETH DA +pub const DERIVATION_VERSION_EIGEN_DA: u8 = 0xed; + +pub struct VecOfBytes(pub Vec>); + +impl Decodable for VecOfBytes { + fn decode(rlp: &rlp::Rlp<'_>) -> Result { + let inner = rlp.as_list::>()?; + Ok(VecOfBytes(inner)) + } +} + +/// A data iterator that reads from eigen da. +#[derive(Debug, Clone)] +pub struct EigenDaSource +where + F: ChainProvider + Send, + B: BlobProvider + Send, + E: EigenDAProvider + Send, +{ + /// Chain provider. + pub chain_provider: F, + /// Fetches blobs. + pub blob_provider: B, + /// Fetches eigen da blobs. + pub eigen_da_provider: E, + /// The address of the batcher contract. + pub batcher_address: Address, + /// The L1 Signer. + pub signer: Address, + /// Data. + pub data: Vec, + /// Whether the source is open. + pub open: bool, +} + +impl EigenDaSource +where + F: ChainProvider + Send, + B: BlobProvider + Send, + E: EigenDAProvider + Send, +{ + /// Creates a new EigenDA blob source. + pub const fn new( + chain_provider: F, + blob_provider: B, + eigen_da_provider: E, + batcher_address: Address, + signer: Address, + ) -> Self { + Self { + chain_provider, + blob_provider, + eigen_da_provider, + batcher_address, + signer, + data: Vec::new(), + open: false, + } + } + + async fn data_from_eigen_da( + &mut self, + txs: Vec, + ) -> Result<(Vec, Vec), EigenDAProviderError> { + let mut out: Vec = Vec::new(); + let mut hashes = Vec::new(); + let mut number: u64 = 0; + + for tx in txs { + let (tx_kind, calldata, blob_hashes) = match &tx { + TxEnvelope::Legacy(tx) => (tx.tx().to(), tx.tx().input.clone(), None), + TxEnvelope::Eip2930(tx) => (tx.tx().to(), tx.tx().input.clone(), None), + TxEnvelope::Eip1559(tx) => (tx.tx().to(), tx.tx().input.clone(), None), + TxEnvelope::Eip4844(blob_tx_wrapper) => match blob_tx_wrapper.tx() { + TxEip4844Variant::TxEip4844(tx) => { + (tx.to(), tx.input.clone(), Some(tx.blob_versioned_hashes.clone())) + } + TxEip4844Variant::TxEip4844WithSidecar(tx) => { + let tx = tx.tx(); + (tx.to(), tx.input.clone(), Some(tx.blob_versioned_hashes.clone())) + } + }, + _ => continue, + }; + let Some(to) = tx_kind else { continue }; + if to != self.batcher_address { + number += blob_hashes.map_or(0, |h| h.len() as u64); + continue; + } + if tx.recover_signer().unwrap_or_default() != self.signer { + number += blob_hashes.map_or(0, |h| h.len() as u64); + continue; + } + if self.eigen_da_provider.da_indexer_enable() { + error!("eigen_da_provider.da_indexer_enable() not implemented"); + break; + } + + if calldata.len() == 0 { + if tx.tx_type() == TxType::Eip4844 { + let blob_hashes = if let Some(b) = blob_hashes { + b + } else { + continue; + }; + for blob in blob_hashes { + let indexed = IndexedBlobHash { hash: blob, index: number }; + hashes.push(indexed); + number += 1; + } + } + continue; + } + + if calldata[0] == DERIVATION_VERSION_EIGEN_DA { + let blob_data = calldata.slice(1..); + let calldata_frame: CalldataFrame = CalldataFrame::decode(blob_data) + .map_err(|e| EigenDAProviderError::ProtoDecodeError(e.to_string()))?; + if let Some(value) = calldata_frame.value { + match value { + calldata_frame::Value::Frame(frame) => out.push(Bytes::from(frame)), + calldata_frame::Value::FrameRef(frame_ref) => { + if frame_ref.quorum_ids.len() == 0 { + warn!(target: "eigen-da-source", "decoded frame ref contains no quorum IDs"); + continue; + } + let blob_data = self + .eigen_da_provider + .retrieve_blob_with_commitment( + &frame_ref.commitment, + frame_ref.blob_length, + ) + .await + .map_err(|e| EigenDAProviderError::Status(e.to_string()))?; + let blobs = &blob_data[..frame_ref.blob_length as usize]; + let blob_data: VecOfBytes = decode(blobs) + .map_err(|e| EigenDAProviderError::RLPDecodeError(e.to_string()))?; + for blob in blob_data.0 { + out.push(Bytes::from(blob)); + } + } + } + } + } + } + Ok((out, hashes)) + } + + async fn load_blobs(&mut self, block_ref: &BlockInfo) -> Result<(), EigenDAProviderError> { + if self.open { + return Ok(()); + } + let info = self + .chain_provider + .block_info_and_transactions_by_hash(block_ref.hash) + .await + .map_err(|e| EigenDAProviderError::Backend(e.to_string()))?; + let (mut blob_data, blob_hashes) = self.data_from_eigen_da(info.1).await?; + info!(target: "eigen_da", "loading eigen blobs blob hashes len {}, blob data len {}", blob_hashes.len(), blob_data.len()); + if blob_hashes.len() > 0 { + let blobs = + self.blob_provider.get_blobs(block_ref, &blob_hashes).await.map_err(|e| { + warn!(target: "eigen-da-source", "Failed to fetch blobs: {e}"); + EigenDAProviderError::Backend( + BlobProviderError::Backend(e.to_string()).to_string(), + ) + })?; + let mut whole_blob_data = Vec::new(); + + let mut blob_index: usize = 0; + for _ in blob_hashes { + let mut blob = BlobData::default(); + match blob.fill(&blobs, blob_index ) { + Ok(should_increment) => { + if should_increment { + blob_index += 1; + } + } + Err(e) => { + return Err(EigenDAProviderError::Backend(e.to_string())); + } + } + match blob.decode() { + Ok(d) => whole_blob_data.append(&mut d.to_vec()), + Err(_) => { + warn!(target: "blob-source", "Failed to decode blob data, skipping"); + } + } + } + info!("whole blob data size {}", whole_blob_data.len()); + + let rlp_blob: VecOfBytes = decode(&whole_blob_data) + .map_err(|e| EigenDAProviderError::RLPDecodeError(e.to_string()))?; + + info!("rlp blob data len {}", rlp_blob.0.len()); + + for blob in rlp_blob.0 { + info!("rlp decode blob vec size {}", blob.len()); + blob_data.push(Bytes::from(blob)); + } + } + self.open = true; + info!(target: "eigen_da", "loaded eigen blobs blob data len {}", blob_data.len()); + self.data = blob_data; + Ok(()) + } + + /// Extracts the next data from the source. + fn next_data(&mut self) -> Result> { + if self.data.is_empty() { + return Err(Err(PipelineError::Eof.temp())); + } + + Ok(self.data.remove(0)) + } +} + +#[async_trait] +impl DataAvailabilityProvider for EigenDaSource +where + F: ChainProvider + Send, + B: BlobProvider + Send, + E: EigenDAProvider + Send, +{ + type Item = Bytes; + + async fn next(&mut self, block_ref: &BlockInfo) -> PipelineResult { + let result = self.load_blobs(block_ref).await; + match result { + Ok(_) => (), + + Err(e) => { + return Err(PipelineError::Provider(format!( + "Failed to load eigen_da blobs from stream: {}, err: {}", + block_ref.hash, + e.to_string() + )) + .temp()); + } + } + + let next_data = match self.next_data() { + Ok(d) => d, + Err(e) => return e, + }; + //TODO EigenDA decode + + Ok(next_data) + } + + fn clear(&mut self) { + self.data.clear(); + self.open = false; + } +} + +#[cfg(test)] +pub(crate) mod tests { + use super::*; + use crate::test_utils::TestEigenDaProvider; + use alloc::vec; + use alloy_primitives::keccak256; + use alloy_rlp::Decodable; + + #[tokio::test] + async fn test_calldata_frame_decode() { + let txs = valid_eigen_da_txs(); + let mut eigen_da_provider = TestEigenDaProvider::default(); + for tx in txs { + let (tx_kind, calldata, blob_hashes) = match &tx { + TxEnvelope::Legacy(tx) => (tx.tx().to(), tx.tx().input.clone(), None), + TxEnvelope::Eip2930(tx) => (tx.tx().to(), tx.tx().input.clone(), None), + TxEnvelope::Eip1559(tx) => (tx.tx().to(), tx.tx().input.clone(), None), + TxEnvelope::Eip4844(blob_tx_wrapper) => match blob_tx_wrapper.tx() { + TxEip4844Variant::TxEip4844(tx) => { + (tx.to(), tx.input.clone(), Some(tx.blob_versioned_hashes.clone())) + } + TxEip4844Variant::TxEip4844WithSidecar(tx) => { + let tx = tx.tx(); + (tx.to(), tx.input.clone(), Some(tx.blob_versioned_hashes.clone())) + } + }, + _ => continue, + }; + assert_eq!(calldata[0], DERIVATION_VERSION_EIGEN_DA); + + let blob_data = calldata.slice(1..); + let calldata_frame: CalldataFrame = CalldataFrame::decode(blob_data).unwrap(); + if let Some(value) = calldata_frame.value { + match value { + calldata_frame::Value::Frame(frame) => {} + calldata_frame::Value::FrameRef(frame_ref) => { + if frame_ref.quorum_ids.len() == 0 { + warn!(target: "eigen-da-source", "decoded frame ref contains no quorum IDs"); + continue; + } + let commitment = hex::encode(frame_ref.commitment.as_slice()).to_string(); + + assert_eq!(commitment, "010000f901d8f852f842a00dbbd22149b419a9a751c25065b58745f4216dc3ae4e9ad583306c395387b6a3a02673dfa25dd3095246eeffb639d3e11108a1ba75dd29b86c3a4200ed00210e4e820200cac480213701c401213710f90181830148ae81a5f873eba0c42bcd27bcd22ba55c4189a25d362343838cb75f57979baa0686ec5381a944c3820001826362832a79cba07263089b84cbb2963e4f50a930243c081ab14b01c0c92d57c3029590bd9dfc9200832a7a20a05419bc29ac025512311c14f23d9613e408448e47bb31f71614e1f82b6c63966cb9010074b13a3acaba35d3749063c19806c9a2f2004b318d55edd6cb5129d958807ea7ac09584a2c6ea029ed34c72f849862e4189928e90931e07093209016f5fc70a6c4a8c3237c25c4f236bb25c105fd7dbd6e4a00153c69c0757d8cbf02f966167ccae243412c20de1c3a38a50818dc7f9f3e02dcb3bc4e54800f2224b8c1eaa9955e41792fa0e401f2814ee209331126149c630c34e1b8e2f804955582022676e232d24d7784b496fc997d98db2849b1bfa8443b362723fc603da8de11704a1ef50414e11234496cfac67aebdd2faa24840ffe7f04506652b8a11a534b024a40bc7e99fee042336f425eb16e40e4267593415860204c9069723dbaca8cf2e596dc820001".to_string()); + let blob_data = eigen_da_provider + .retrieve_blob_with_commitment( + &frame_ref.commitment, + frame_ref.blob_length, + ) + .await + .map_err(|e| EigenDAProviderError::Status(e.to_string())) + .unwrap(); + let blobs = &blob_data[..frame_ref.blob_length as usize]; + let blob_data: VecOfBytes = decode(blobs) + .map_err(|e| EigenDAProviderError::RLPDecodeError(e.to_string())) + .unwrap(); + } + } + } + } + } + + pub(crate) fn valid_eigen_da_txs() -> Vec { + // https://sepolia.etherscan.io/getRawTx?tx=0xfd10d26ace7eec30487bdad54ef5348dfdff48061129cf6e2adf6182a950d5a9 + let raw_tx = + alloy_primitives::hex::decode("0x02f9026483aa36a7830107f1830f424085083f58abbe8271f49454da4d1124b2310757562b8ee9cea69b25bb46a180b901f2ed12ee0318cbf3a9012202000128a15baa06de03010000f901d8f852f842a00dbbd22149b419a9a751c25065b58745f4216dc3ae4e9ad583306c395387b6a3a02673dfa25dd3095246eeffb639d3e11108a1ba75dd29b86c3a4200ed00210e4e820200cac480213701c401213710f90181830148ae81a5f873eba0c42bcd27bcd22ba55c4189a25d362343838cb75f57979baa0686ec5381a944c3820001826362832a79cba07263089b84cbb2963e4f50a930243c081ab14b01c0c92d57c3029590bd9dfc9200832a7a20a05419bc29ac025512311c14f23d9613e408448e47bb31f71614e1f82b6c63966cb9010074b13a3acaba35d3749063c19806c9a2f2004b318d55edd6cb5129d958807ea7ac09584a2c6ea029ed34c72f849862e4189928e90931e07093209016f5fc70a6c4a8c3237c25c4f236bb25c105fd7dbd6e4a00153c69c0757d8cbf02f966167ccae243412c20de1c3a38a50818dc7f9f3e02dcb3bc4e54800f2224b8c1eaa9955e41792fa0e401f2814ee209331126149c630c34e1b8e2f804955582022676e232d24d7784b496fc997d98db2849b1bfa8443b362723fc603da8de11704a1ef50414e11234496cfac67aebdd2faa24840ffe7f04506652b8a11a534b024a40bc7e99fee042336f425eb16e40e4267593415860204c9069723dbaca8cf2e596dc820001c001a0f421ccc336435722bdf41ef041a278b0851790dae1946be7033c2e057ffede46a027493ede5c5e490f14fc2b06cc444433b3f2d6e1079451d519311c1f4ab8f4b0").unwrap(); + let eoa = TxEnvelope::decode(&mut raw_tx.as_slice()).unwrap(); + vec![eoa] + } +} diff --git a/crates/derive/src/sources/ethereum.rs b/crates/derive/src/sources/ethereum.rs index 22e01bcd5b..d72ed4b6b3 100644 --- a/crates/derive/src/sources/ethereum.rs +++ b/crates/derive/src/sources/ethereum.rs @@ -1,85 +1,94 @@ //! Contains the [EthereumDataSource], which is a concrete implementation of the //! [DataAvailabilityProvider] trait for the Ethereum protocol. +use crate::sources::eigen_da::EigenDaSource; use crate::{ sources::{BlobSource, CalldataSource}, - traits::{BlobProvider, ChainProvider, DataAvailabilityProvider}, + traits::{BlobProvider, ChainProvider, DataAvailabilityProvider, EigenDAProvider}, types::PipelineResult, }; use alloc::{boxed::Box, fmt::Debug}; -use alloy_primitives::Bytes; +use alloy_primitives::{Address, Bytes}; use async_trait::async_trait; use op_alloy_genesis::RollupConfig; use op_alloy_protocol::BlockInfo; /// A factory for creating an Ethereum data source provider. #[derive(Debug, Clone)] -pub struct EthereumDataSource +pub struct EthereumDataSource where C: ChainProvider + Send + Clone, B: BlobProvider + Send + Clone, + E: EigenDAProvider + Send + Clone, { - /// The ecotone timestamp. - pub ecotone_timestamp: Option, - /// The blob source. - pub blob_source: BlobSource, /// The calldata source. pub calldata_source: CalldataSource, + /// The eigen da source. + pub eigen_da_source: EigenDaSource, + /// Mantle da switch + pub mantle_da_switch: bool, } -impl EthereumDataSource +impl EthereumDataSource where C: ChainProvider + Send + Clone + Debug, B: BlobProvider + Send + Clone + Debug, + E: EigenDAProvider + Send + Clone + Debug, { /// Instantiates a new [EthereumDataSource]. pub const fn new( - blob_source: BlobSource, calldata_source: CalldataSource, + eigen_da_source: EigenDaSource, cfg: &RollupConfig, ) -> Self { - Self { ecotone_timestamp: cfg.ecotone_time, blob_source, calldata_source } + Self { calldata_source, eigen_da_source, mantle_da_switch: cfg.mantle_da_switch } } - /// Instantiates a new [EthereumDataSource] from parts. - pub fn new_from_parts(provider: C, blobs: B, cfg: &RollupConfig) -> Self { + /// Creates a new factory. + pub fn new_from_parts(provider: C, blobs: B, eigen_da_provider: E, cfg: &RollupConfig) -> Self { let signer = cfg.genesis.system_config.as_ref().map(|sc| sc.batcher_address).unwrap_or_default(); Self { - ecotone_timestamp: cfg.ecotone_time, - blob_source: BlobSource::new(provider.clone(), blobs, cfg.batch_inbox_address, signer), - calldata_source: CalldataSource::new(provider, cfg.batch_inbox_address, signer), + calldata_source: CalldataSource::new(provider.clone(), cfg.batch_inbox_address, signer), + eigen_da_source: EigenDaSource::new( + provider, + blobs, + eigen_da_provider, + cfg.batch_inbox_address, + signer, + ), + mantle_da_switch: cfg.mantle_da_switch, } } } #[async_trait] -impl DataAvailabilityProvider for EthereumDataSource +impl DataAvailabilityProvider for EthereumDataSource where C: ChainProvider + Send + Sync + Clone + Debug, B: BlobProvider + Send + Sync + Clone + Debug, + E: EigenDAProvider + Send + Sync + Clone + Debug, { type Item = Bytes; async fn next(&mut self, block_ref: &BlockInfo) -> PipelineResult { - let ecotone_enabled = - self.ecotone_timestamp.map(|e| block_ref.timestamp >= e).unwrap_or(false); - if ecotone_enabled { - self.blob_source.next(block_ref).await + if self.mantle_da_switch { + self.eigen_da_source.next(block_ref).await } else { self.calldata_source.next(block_ref).await } } fn clear(&mut self) { - self.blob_source.clear(); self.calldata_source.clear(); + self.eigen_da_source.clear(); } } #[cfg(test)] mod tests { use super::*; + use crate::test_utils::TestEigenDaProvider; use crate::{ sources::BlobData, test_utils::{TestBlobProvider, TestChainProvider}, @@ -103,36 +112,22 @@ mod tests { let chain = TestChainProvider::default(); let blob = TestBlobProvider::default(); let cfg = RollupConfig::default(); + let eigen_da = TestEigenDaProvider::default(); let mut calldata = CalldataSource::new(chain.clone(), Address::ZERO, Address::ZERO); calldata.calldata.insert(0, Default::default()); calldata.open = true; - let mut blob = BlobSource::new(chain, blob, Address::ZERO, Address::ZERO); - blob.data = vec![Default::default()]; - blob.open = true; - let mut data_source = EthereumDataSource::new(blob, calldata, &cfg); + let mut eigen = EigenDaSource::new(chain, blob, eigen_da, Address::ZERO, Address::ZERO); + eigen.data = vec![Default::default()]; + eigen.open = true; + let mut data_source = EthereumDataSource::new(calldata, eigen, &cfg); data_source.clear(); - assert!(data_source.blob_source.data.is_empty()); - assert!(!data_source.blob_source.open); + assert!(data_source.eigen_da_source.data.is_empty()); + assert!(!data_source.eigen_da_source.open); assert!(data_source.calldata_source.calldata.is_empty()); assert!(!data_source.calldata_source.open); } - #[tokio::test] - async fn test_open_blob_source() { - let chain = TestChainProvider::default(); - let mut blob = default_test_blob_source(); - blob.open = true; - blob.data.push(BlobData { data: None, calldata: Some(Bytes::default()) }); - let calldata = CalldataSource::new(chain.clone(), Address::ZERO, Address::ZERO); - let cfg = RollupConfig { ecotone_time: Some(0), ..Default::default() }; - - // Should successfully retrieve a blob batch from the block - let mut data_source = EthereumDataSource::new(blob, calldata, &cfg); - let data = data_source.next(&BlockInfo::default()).await.unwrap(); - assert_eq!(data, Bytes::default()); - } - #[tokio::test] async fn test_open_ethereum_calldata_source_pre_ecotone() { let mut chain = TestChainProvider::default(); diff --git a/crates/derive/src/sources/mod.rs b/crates/derive/src/sources/mod.rs index e0c9772d3e..377111a802 100644 --- a/crates/derive/src/sources/mod.rs +++ b/crates/derive/src/sources/mod.rs @@ -18,3 +18,7 @@ pub use blobs::BlobSource; mod calldata; pub use calldata::CalldataSource; + +mod eigen_da; + +pub use eigen_da::EigenDaSource; diff --git a/crates/derive/src/sources/variant.rs b/crates/derive/src/sources/variant.rs deleted file mode 100644 index 44588e39c7..0000000000 --- a/crates/derive/src/sources/variant.rs +++ /dev/null @@ -1,78 +0,0 @@ -//! Data source - -use crate::{ - sources::{BlobSource, CalldataSource}, - traits::{AsyncIterator, BlobProvider, ChainProvider}, - types::PipelineResult, -}; -use alloc::boxed::Box; -use alloy_primitives::Bytes; -use async_trait::async_trait; - -/// An enum over the various data sources. -#[derive(Debug, Clone)] -pub enum EthereumDataSourceVariant -where - CP: ChainProvider + Send, - B: BlobProvider + Send, -{ - /// A calldata source. - Calldata(CalldataSource), - /// A blob source. - Blob(BlobSource), -} - -#[async_trait] -impl AsyncIterator for EthereumDataSourceVariant -where - CP: ChainProvider + Send, - B: BlobProvider + Send, -{ - type Item = Bytes; - - async fn next(&mut self) -> PipelineResult { - match self { - Self::Calldata(c) => c.next().await, - Self::Blob(b) => b.next().await, - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::test_utils::TestChainProvider; - use op_alloy_protocol::BlockInfo; - - use crate::{ - sources::{BlobData, EthereumDataSourceVariant}, - test_utils::TestBlobProvider, - }; - - #[tokio::test] - async fn test_variant_next_calldata() { - let chain = TestChainProvider::default(); - let block_ref = BlockInfo::default(); - let mut source = - CalldataSource::new(chain, Default::default(), block_ref, Default::default()); - source.open = true; - source.calldata.push_back(Default::default()); - let mut variant: EthereumDataSourceVariant = - EthereumDataSourceVariant::Calldata(source); - assert!(variant.next().await.is_ok()); - } - - #[tokio::test] - async fn test_variant_next_blob() { - let chain = TestChainProvider::default(); - let blob = TestBlobProvider::default(); - let block_ref = BlockInfo::default(); - let mut source = - BlobSource::new(chain, blob, Default::default(), block_ref, Default::default()); - source.open = true; - source.data.push(BlobData { calldata: Some(Default::default()), ..Default::default() }); - let mut variant: EthereumDataSourceVariant = - EthereumDataSourceVariant::Blob(source); - assert!(variant.next().await.is_ok()); - } -} diff --git a/crates/derive/src/stages/attributes_queue.rs b/crates/derive/src/stages/attributes_queue.rs index d872ea6a1c..ab7bac176c 100644 --- a/crates/derive/src/stages/attributes_queue.rs +++ b/crates/derive/src/stages/attributes_queue.rs @@ -12,7 +12,8 @@ use alloc::{boxed::Box, sync::Arc}; use async_trait::async_trait; use core::fmt::Debug; use op_alloy_genesis::RollupConfig; -use op_alloy_protocol::{BlockInfo, L2BlockInfo, SingleBatch}; +use op_alloy_protocol::SingleBatch; +use op_alloy_protocol::{BlockInfo, L2BlockInfo}; use op_alloy_rpc_types_engine::{OpAttributesWithParent, OpPayloadAttributes}; /// [AttributesQueue] accepts batches from the [BatchQueue] stage @@ -38,8 +39,6 @@ where cfg: Arc, /// The previous stage of the derivation pipeline. prev: P, - /// Whether the current batch is the last in its span. - is_last_in_span: bool, /// The current batch being processed. batch: Option, /// The attributes builder. @@ -53,7 +52,7 @@ where { /// Create a new [AttributesQueue] stage. pub const fn new(cfg: Arc, prev: P, builder: AB) -> Self { - Self { cfg, prev, is_last_in_span: false, batch: None, builder } + Self { cfg, prev, batch: None, builder } } /// Loads a [SingleBatch] from the [AttributesProvider] if needed. @@ -61,7 +60,6 @@ where if self.batch.is_none() { let batch = self.prev.next_batch(parent).await?; self.batch = Some(batch); - self.is_last_in_span = self.prev.is_last_in_span(); } self.batch.as_ref().cloned().ok_or(PipelineError::Eof.temp()) } @@ -85,12 +83,10 @@ where return Err(e); } }; - let populated_attributes = - OpAttributesWithParent { attributes, parent, is_last_in_span: self.is_last_in_span }; + let populated_attributes = OpAttributesWithParent { attributes, parent }; // Clear out the local state once payload attributes are prepared. self.batch = None; - self.is_last_in_span = false; Ok(populated_attributes) } @@ -181,7 +177,6 @@ where s @ Signal::Reset(_) | s @ Signal::Activation(_) => { self.prev.signal(s).await?; self.batch = None; - self.is_last_in_span = false; } s @ Signal::FlushChannel => { self.batch = None; @@ -212,13 +207,11 @@ mod tests { prev_randao: B256::default(), withdrawals: None, parent_beacon_block_root: None, - target_blobs_per_block: None, - max_blobs_per_block: None, }, no_tx_pool: Some(false), transactions: None, gas_limit: None, - eip_1559_params: None, + base_fee: None, } } @@ -270,7 +263,6 @@ mod tests { let parent = L2BlockInfo::default(); let result = attributes_queue.load_batch(parent).await.unwrap(); assert_eq!(result, Default::default()); - assert!(attributes_queue.is_last_in_span); } #[tokio::test] @@ -374,19 +366,14 @@ mod tests { // If we load the batch, we should get the last in span. // But it won't take it so it will be available in the next_attributes call. let _ = aq.load_batch(L2BlockInfo::default()).await.unwrap(); - assert!(aq.is_last_in_span); assert!(aq.batch.is_some()); // This should successfully construct the next payload attributes. // It should also reset the last in span flag and clear the batch. let attributes = aq.next_attributes(L2BlockInfo::default()).await.unwrap(); pa.no_tx_pool = Some(true); - let populated_attributes = OpAttributesWithParent { - attributes: pa, - parent: L2BlockInfo::default(), - is_last_in_span: true, - }; + let populated_attributes = + OpAttributesWithParent { attributes: pa, parent: L2BlockInfo::default() }; assert_eq!(attributes, populated_attributes); - assert!(!aq.is_last_in_span); assert!(aq.batch.is_none()); } } diff --git a/crates/derive/src/stages/batch/batch_provider.rs b/crates/derive/src/stages/batch/batch_provider.rs index df153a9f3f..b851a07006 100644 --- a/crates/derive/src/stages/batch/batch_provider.rs +++ b/crates/derive/src/stages/batch/batch_provider.rs @@ -3,7 +3,7 @@ use super::NextBatchProvider; use crate::{ errors::PipelineError, - stages::{BatchQueue, BatchValidator}, + stages::BatchQueue, traits::{AttributesProvider, L2ChainProvider, OriginAdvancer, OriginProvider, SignalReceiver}, types::{PipelineResult, Signal}, }; @@ -22,15 +22,12 @@ use op_alloy_protocol::{BlockInfo, L2BlockInfo, SingleBatch}; /// When transitioning between the two stages, the mux will reset the active stage, but /// retain `l1_blocks`. #[derive(Debug)] -pub struct BatchProvider +pub struct BatchProvider

where P: NextBatchProvider + OriginAdvancer + OriginProvider + SignalReceiver + Debug, - F: L2ChainProvider + Clone + Debug, { /// The rollup configuration. cfg: Arc, - /// The L2 chain provider. - provider: F, /// The previous stage of the derivation pipeline. /// /// If this is set to [None], the multiplexer has been activated and the active stage @@ -41,68 +38,38 @@ where /// The batch queue stage of the provider. /// /// Must be [None] if `prev` or `batch_validator` is [Some]. - batch_queue: Option>, - /// The batch validator stage of the provider. - /// - /// Must be [None] if `prev` or `batch_queue` is [Some]. - batch_validator: Option>, + batch_queue: Option>, } -impl BatchProvider +impl

BatchProvider

where P: NextBatchProvider + OriginAdvancer + OriginProvider + SignalReceiver + Debug, - F: L2ChainProvider + Clone + Debug, { /// Creates a new [BatchProvider] with the given configuration and previous stage. - pub const fn new(cfg: Arc, prev: P, provider: F) -> Self { - Self { cfg, provider, prev: Some(prev), batch_queue: None, batch_validator: None } + pub const fn new(cfg: Arc, prev: P) -> Self { + Self { cfg, prev: Some(prev), batch_queue: None } } /// Attempts to update the active stage of the mux. pub(crate) fn attempt_update(&mut self) -> PipelineResult<()> { - let origin = self.origin().ok_or(PipelineError::MissingOrigin.crit())?; if let Some(prev) = self.prev.take() { // On the first call to `attempt_update`, we need to determine the active stage to // initialize the mux with. - if self.cfg.is_holocene_active(origin.timestamp) { - self.batch_validator = Some(BatchValidator::new(self.cfg.clone(), prev)); - } else { - self.batch_queue = - Some(BatchQueue::new(self.cfg.clone(), prev, self.provider.clone())); - } - } else if self.batch_queue.is_some() && self.cfg.is_holocene_active(origin.timestamp) { - // If the batch queue is active and Holocene is also active, transition to the batch - // validator. - let batch_queue = self.batch_queue.take().expect("Must have batch queue"); - let mut bv = BatchValidator::new(self.cfg.clone(), batch_queue.prev); - bv.l1_blocks = batch_queue.l1_blocks; - self.batch_validator = Some(bv); - } else if self.batch_validator.is_some() && !self.cfg.is_holocene_active(origin.timestamp) { - // If the batch validator is active, and Holocene is not active, it indicates an L1 - // reorg around Holocene activation. Transition back to the batch queue - // until Holocene re-activates. - let batch_validator = self.batch_validator.take().expect("Must have batch validator"); - let mut bq = - BatchQueue::new(self.cfg.clone(), batch_validator.prev, self.provider.clone()); - bq.l1_blocks = batch_validator.l1_blocks; - self.batch_queue = Some(bq); + self.batch_queue = Some(BatchQueue::new(self.cfg.clone(), prev)); } Ok(()) } } #[async_trait] -impl OriginAdvancer for BatchProvider +impl

OriginAdvancer for BatchProvider

where P: NextBatchProvider + OriginAdvancer + OriginProvider + SignalReceiver + Send + Debug, - F: L2ChainProvider + Clone + Send + Debug, { async fn advance_origin(&mut self) -> PipelineResult<()> { self.attempt_update()?; - if let Some(batch_validator) = self.batch_validator.as_mut() { - batch_validator.advance_origin().await - } else if let Some(batch_queue) = self.batch_queue.as_mut() { + if let Some(batch_queue) = self.batch_queue.as_mut() { batch_queue.advance_origin().await } else { Err(PipelineError::NotEnoughData.temp()) @@ -110,36 +77,27 @@ where } } -impl OriginProvider for BatchProvider +impl

OriginProvider for BatchProvider

where P: NextBatchProvider + OriginAdvancer + OriginProvider + SignalReceiver + Debug, - F: L2ChainProvider + Clone + Debug, { fn origin(&self) -> Option { - self.batch_validator.as_ref().map_or_else( - || { - self.batch_queue.as_ref().map_or_else( - || self.prev.as_ref().and_then(|prev| prev.origin()), - |batch_queue| batch_queue.origin(), - ) - }, - |batch_validator| batch_validator.origin(), + self.batch_queue.as_ref().map_or_else( + || self.prev.as_ref().and_then(|prev| prev.origin()), + |batch_queue| batch_queue.origin(), ) } } #[async_trait] -impl SignalReceiver for BatchProvider +impl

SignalReceiver for BatchProvider

where P: NextBatchProvider + OriginAdvancer + OriginProvider + SignalReceiver + Send + Debug, - F: L2ChainProvider + Clone + Send + Debug, { async fn signal(&mut self, signal: Signal) -> PipelineResult<()> { self.attempt_update()?; - if let Some(batch_validator) = self.batch_validator.as_mut() { - batch_validator.signal(signal).await - } else if let Some(batch_queue) = self.batch_queue.as_mut() { + if let Some(batch_queue) = self.batch_queue.as_mut() { batch_queue.signal(signal).await } else { Err(PipelineError::NotEnoughData.temp()) @@ -148,24 +106,14 @@ where } #[async_trait] -impl AttributesProvider for BatchProvider +impl

AttributesProvider for BatchProvider

where P: NextBatchProvider + OriginAdvancer + OriginProvider + SignalReceiver + Debug + Send, - F: L2ChainProvider + Clone + Send + Debug, { - fn is_last_in_span(&self) -> bool { - self.batch_validator.as_ref().map_or_else( - || self.batch_queue.as_ref().is_some_and(|batch_queue| batch_queue.is_last_in_span()), - |batch_validator| batch_validator.is_last_in_span(), - ) - } - async fn next_batch(&mut self, parent: L2BlockInfo) -> PipelineResult { self.attempt_update()?; - if let Some(batch_validator) = self.batch_validator.as_mut() { - batch_validator.next_batch(parent).await - } else if let Some(batch_queue) = self.batch_queue.as_mut() { + if let Some(batch_queue) = self.batch_queue.as_mut() { batch_queue.next_batch(parent).await } else { Err(PipelineError::NotEnoughData.temp()) @@ -189,13 +137,12 @@ mod test { fn test_batch_provider_validator_active() { let provider = TestNextBatchProvider::new(vec![]); let l2_provider = TestL2ChainProvider::default(); - let cfg = Arc::new(RollupConfig { holocene_time: Some(0), ..Default::default() }); - let mut batch_provider = BatchProvider::new(cfg, provider, l2_provider); + let cfg = Arc::new(RollupConfig { ..Default::default() }); + let mut batch_provider = BatchProvider::new(cfg, provider); assert!(batch_provider.attempt_update().is_ok()); assert!(batch_provider.prev.is_none()); assert!(batch_provider.batch_queue.is_none()); - assert!(batch_provider.batch_validator.is_some()); } #[test] @@ -203,20 +150,19 @@ mod test { let provider = TestNextBatchProvider::new(vec![]); let l2_provider = TestL2ChainProvider::default(); let cfg = Arc::new(RollupConfig::default()); - let mut batch_provider = BatchProvider::new(cfg, provider, l2_provider); + let mut batch_provider = BatchProvider::new(cfg, provider); assert!(batch_provider.attempt_update().is_ok()); assert!(batch_provider.prev.is_none()); assert!(batch_provider.batch_queue.is_some()); - assert!(batch_provider.batch_validator.is_none()); } #[test] fn test_batch_provider_transition_stage() { let provider = TestNextBatchProvider::new(vec![]); let l2_provider = TestL2ChainProvider::default(); - let cfg = Arc::new(RollupConfig { holocene_time: Some(2), ..Default::default() }); - let mut batch_provider = BatchProvider::new(cfg, provider, l2_provider); + let cfg = Arc::new(RollupConfig { ..Default::default() }); + let mut batch_provider = BatchProvider::new(cfg, provider); batch_provider.attempt_update().unwrap(); @@ -229,7 +175,6 @@ mod test { // Transition to the BatchValidator stage. batch_provider.attempt_update().unwrap(); assert!(batch_provider.batch_queue.is_none()); - assert!(batch_provider.batch_validator.is_some()); assert_eq!(batch_provider.origin().unwrap().number, 1); } @@ -238,31 +183,30 @@ mod test { fn test_batch_provider_transition_stage_backwards() { let provider = TestNextBatchProvider::new(vec![]); let l2_provider = TestL2ChainProvider::default(); - let cfg = Arc::new(RollupConfig { holocene_time: Some(2), ..Default::default() }); - let mut batch_provider = BatchProvider::new(cfg, provider, l2_provider); + let cfg = Arc::new(RollupConfig { ..Default::default() }); + let mut batch_provider = BatchProvider::new(cfg, provider); batch_provider.attempt_update().unwrap(); // Update the L1 origin to Holocene activation. - let Some(ref mut stage) = batch_provider.batch_queue else { + if let Some(ref mut stage) = batch_provider.batch_queue { + stage.prev.origin = Some(BlockInfo { number: 1, timestamp: 2, ..Default::default() }); + } else { panic!("Expected BatchQueue"); }; - stage.prev.origin = Some(BlockInfo { number: 1, timestamp: 2, ..Default::default() }); // Transition to the BatchValidator stage. batch_provider.attempt_update().unwrap(); assert!(batch_provider.batch_queue.is_none()); - assert!(batch_provider.batch_validator.is_some()); - // Update the L1 origin to before Holocene activation, to simulate a re-org. - let Some(ref mut stage) = batch_provider.batch_validator else { - panic!("Expected BatchValidator"); - }; - stage.prev.origin = Some(BlockInfo::default()); + if let Some(ref mut stage) = batch_provider.batch_queue { + stage.prev.origin = Some(BlockInfo::default()); + } else { + panic!("BatchQueue is unexpectedly None"); + } batch_provider.attempt_update().unwrap(); assert!(batch_provider.batch_queue.is_some()); - assert!(batch_provider.batch_validator.is_none()); } #[tokio::test] @@ -270,7 +214,7 @@ mod test { let provider = TestNextBatchProvider::new(vec![]); let l2_provider = TestL2ChainProvider::default(); let cfg = Arc::new(RollupConfig::default()); - let mut batch_provider = BatchProvider::new(cfg, provider, l2_provider); + let mut batch_provider = BatchProvider::new(cfg, provider); // Reset the batch provider. batch_provider.signal(ResetSignal::default().signal()).await.unwrap(); @@ -285,15 +229,10 @@ mod test { async fn test_batch_provider_reset_validator() { let provider = TestNextBatchProvider::new(vec![]); let l2_provider = TestL2ChainProvider::default(); - let cfg = Arc::new(RollupConfig { holocene_time: Some(0), ..Default::default() }); - let mut batch_provider = BatchProvider::new(cfg, provider, l2_provider); + let cfg = Arc::new(RollupConfig { ..Default::default() }); + let mut batch_provider = BatchProvider::new(cfg, provider); // Reset the batch provider. batch_provider.signal(ResetSignal::default().signal()).await.unwrap(); - - let Some(bv) = batch_provider.batch_validator else { - panic!("Expected BatchValidator"); - }; - assert!(bv.l1_blocks.len() == 1); } } diff --git a/crates/derive/src/stages/batch/batch_queue.rs b/crates/derive/src/stages/batch/batch_queue.rs index ade7749802..a6ca681fb4 100644 --- a/crates/derive/src/stages/batch/batch_queue.rs +++ b/crates/derive/src/stages/batch/batch_queue.rs @@ -14,8 +14,8 @@ use op_alloy_protocol::{ Batch, BatchValidity, BatchWithInclusionBlock, BlockInfo, L2BlockInfo, SingleBatch, }; -/// [BatchQueue] is responsible for o rdering unordered batches -/// and gnerating empty batches when the sequence window has passed. +/// [BatchQueue] is responsible for ordering unordered batches +/// and generating empty batches when the sequence window has passed. /// /// It receives batches that are tagged with the L1 Inclusion block of the batch. /// It only considers batches that are inside the sequencing window of a specific L1 Origin. @@ -29,10 +29,9 @@ use op_alloy_protocol::{ /// It is internally responsible for making sure that batches with L1 inclusions block outside it's /// working range are not considered or pruned. #[derive(Debug)] -pub struct BatchQueue +pub struct BatchQueue

where P: NextBatchProvider + OriginAdvancer + OriginProvider + SignalReceiver + Debug, - BF: L2ChainProvider + Debug, { /// The rollup config. pub(crate) cfg: Arc, @@ -49,43 +48,16 @@ where pub(crate) l1_blocks: Vec, /// A set of batches in order from when we've seen them. pub(crate) batches: Vec, - /// A set of cached [SingleBatch]es derived from [SpanBatch]es. - /// - /// [SpanBatch]: op_alloy_protocol::SpanBatch - pub(crate) next_spans: Vec, - /// Used to validate the batches. - pub(crate) fetcher: BF, } -impl BatchQueue +impl

BatchQueue

where P: NextBatchProvider + OriginAdvancer + OriginProvider + SignalReceiver + Debug, - BF: L2ChainProvider + Debug, { /// Creates a new [BatchQueue] stage. #[allow(clippy::missing_const_for_fn)] - pub fn new(cfg: Arc, prev: P, fetcher: BF) -> Self { - Self { - cfg, - prev, - origin: None, - l1_blocks: Default::default(), - batches: Default::default(), - next_spans: Default::default(), - fetcher, - } - } - - /// Pops the next batch from the current queued up span-batch cache. - /// The parent is used to set the parent hash of the batch. - /// The parent is verified when the batch is later validated. - pub fn pop_next_batch(&mut self, parent: L2BlockInfo) -> Option { - if self.next_spans.is_empty() { - panic!("Invalid state: must have next spans to pop"); - } - let mut next = self.next_spans.remove(0); - next.parent_hash = parent.block_info.hash; - Some(next) + pub fn new(cfg: Arc, prev: P) -> Self { + Self { cfg, prev, origin: None, l1_blocks: Default::default(), batches: Default::default() } } /// Derives the next batch to apply on top of the current L2 safe head. @@ -130,24 +102,13 @@ where let mut remaining = Vec::new(); for i in 0..self.batches.len() { let batch = &self.batches[i]; - let validity = - batch.check_batch(&self.cfg, &self.l1_blocks, parent, &mut self.fetcher).await; + let validity = batch.check_batch(&self.cfg, &self.l1_blocks, parent).await; match validity { BatchValidity::Future => { - // Drop Future batches post-holocene. - // - // See: - if !self.cfg.is_holocene_active(origin.timestamp) { - remaining.push(batch.clone()); - } else { - self.prev.flush(); - warn!(target: "batch-queue", "[HOLOCENE] Dropping future batch with parent: {}", parent.block_info.number); - } + self.prev.flush(); + warn!(target: "batch-queue", "[HOLOCENE] Dropping future batch with parent: {}", parent.block_info.number); } BatchValidity::Drop => { - // If we drop a batch, flush previous batches buffered in the BatchStream - // stage. - self.prev.flush(); warn!(target: "batch-queue", "Dropping batch with parent: {}", parent.block_info); continue; } @@ -164,13 +125,8 @@ where return Err(PipelineError::Eof.temp()); } BatchValidity::Past => { - if !self.cfg.is_holocene_active(origin.timestamp) { - error!(target: "batch-queue", "BatchValidity::Past is not allowed pre-holocene"); - return Err(PipelineError::InvalidBatchValidity.crit()); - } - - warn!(target: "batch-queue", "[HOLOCENE] Dropping outdated batch with parent: {}", parent.block_info.number); - continue; + error!(target: "batch-queue", "BatchValidity::Past is not allowed pre-holocene"); + return Err(PipelineError::InvalidBatchValidity.crit()); } } } @@ -242,13 +198,11 @@ where let origin = self.origin.ok_or(PipelineError::MissingOrigin.crit())?; let data = BatchWithInclusionBlock { inclusion_block: origin, batch }; // If we drop the batch, validation logs the drop reason with WARN level. - let validity = - data.check_batch(&self.cfg, &self.l1_blocks, parent, &mut self.fetcher).await; + let validity = data.check_batch(&self.cfg, &self.l1_blocks, parent).await; // Post-Holocene, future batches are dropped due to prevent gaps. - let drop = validity.is_drop() || - (self.cfg.is_holocene_active(origin.timestamp) && validity.is_future()); + let drop = validity.is_drop(); if drop { - self.prev.flush(); + // If we do drop the batch, CheckBatch will log the drop reason with WARN level. return Ok(()); } else if validity.is_outdated() { // If the batch is outdated, we drop it without flushing the previous stage. @@ -260,10 +214,9 @@ where } #[async_trait] -impl OriginAdvancer for BatchQueue +impl

OriginAdvancer for BatchQueue

where P: NextBatchProvider + OriginAdvancer + OriginProvider + SignalReceiver + Send + Debug, - BF: L2ChainProvider + Send + Debug, { async fn advance_origin(&mut self) -> PipelineResult<()> { self.prev.advance_origin().await @@ -271,31 +224,13 @@ where } #[async_trait] -impl AttributesProvider for BatchQueue +impl

AttributesProvider for BatchQueue

where P: NextBatchProvider + OriginAdvancer + OriginProvider + SignalReceiver + Send + Debug, - BF: L2ChainProvider + Send + Debug, { /// Returns the next valid batch upon the given safe head. /// Also returns the boolean that indicates if the batch is the last block in the batch. async fn next_batch(&mut self, parent: L2BlockInfo) -> PipelineResult { - if !self.next_spans.is_empty() { - // There are cached singular batches derived from the span batch. - // Check if the next cached batch matches the given parent block. - if self.next_spans[0].timestamp == parent.block_info.timestamp + self.cfg.block_time { - return self.pop_next_batch(parent).ok_or(PipelineError::BatchQueueEmpty.crit()); - } - // Parent block does not match the next batch. - // Means the previously returned batch is invalid. - // Drop cached batches and find another batch. - warn!( - target: "batch-queue", - "Parent block does not match the next batch. Dropping {} cached batches.", - self.next_spans.len() - ); - self.next_spans.clear(); - } - // If the epoch is advanced, update the l1 blocks. // Advancing epoch must be done after the pipeline successfully applies the entire span // batch to the chain. @@ -344,7 +279,7 @@ where // Load more data into the batch queue. let mut out_of_data = false; - match self.prev.next_batch(parent, &self.l1_blocks).await { + match self.prev.next_batch().await { Ok(b) => { if !origin_behind { self.add_batch(b, parent).await.ok(); @@ -388,40 +323,13 @@ where // For singular batches, the span batch cache should be empty. match batch { Batch::Single(sb) => Ok(sb), - Batch::Span(sb) => { - let batches = match sb.get_singular_batches(&self.l1_blocks, parent).map_err(|e| { - PipelineError::BadEncoding(PipelineEncodingError::SpanBatchError(e)).crit() - }) { - Ok(b) => b, - Err(e) => { - return Err(e); - } - }; - self.next_spans = batches; - let nb = match self - .pop_next_batch(parent) - .ok_or(PipelineError::BatchQueueEmpty.crit()) - { - Ok(b) => b, - Err(e) => { - return Err(e); - } - }; - Ok(nb) - } } } - - /// Returns if the previous batch was the last in the span. - fn is_last_in_span(&self) -> bool { - self.next_spans.is_empty() - } } -impl OriginProvider for BatchQueue +impl

OriginProvider for BatchQueue

where P: NextBatchProvider + OriginAdvancer + OriginProvider + SignalReceiver + Debug, - BF: L2ChainProvider + Debug, { fn origin(&self) -> Option { self.prev.origin() @@ -429,10 +337,9 @@ where } #[async_trait] -impl SignalReceiver for BatchQueue +impl

SignalReceiver for BatchQueue

where P: NextBatchProvider + OriginAdvancer + OriginProvider + SignalReceiver + Send + Debug, - BF: L2ChainProvider + Send + Debug, { async fn signal(&mut self, signal: Signal) -> PipelineResult<()> { match signal { @@ -445,12 +352,10 @@ where // During normal resets we will later throw out this block. self.l1_blocks.clear(); self.l1_blocks.push(l1_origin); - self.next_spans.clear(); } s @ Signal::Activation(_) | s @ Signal::FlushChannel => { self.prev.signal(s).await?; self.batches.clear(); - self.next_spans.clear(); } } Ok(()) @@ -469,8 +374,8 @@ mod tests { use alloy_primitives::{address, b256, Address, Bytes, TxKind, B256, U256}; use alloy_rlp::{BytesMut, Encodable}; use op_alloy_consensus::{OpBlock, OpTxEnvelope, OpTxType, TxDeposit}; - use op_alloy_genesis::{ChainGenesis, MAX_RLP_BYTES_PER_CHANNEL_FJORD}; - use op_alloy_protocol::{BatchReader, L1BlockInfoBedrock, L1BlockInfoTx}; + use op_alloy_genesis::{ChainGenesis, MAX_RLP_BYTES_PER_CHANNEL_BEDROCK}; + use op_alloy_protocol::{L1BlockInfoBedrock, L1BlockInfoTx}; use tracing::Level; use tracing_subscriber::layer::SubscriberExt; @@ -480,42 +385,7 @@ mod tests { let file_contents = &(&*file_contents)[..file_contents.len() - 1]; let data = alloy_primitives::hex::decode(file_contents).unwrap(); let bytes: alloy_primitives::Bytes = data.into(); - BatchReader::new(bytes, MAX_RLP_BYTES_PER_CHANNEL_FJORD as usize) - } - - #[test] - fn test_pop_next_batch() { - let cfg = Arc::new(RollupConfig::default()); - let mock = TestNextBatchProvider::new(vec![]); - let fetcher = TestL2ChainProvider::default(); - let mut bq = BatchQueue::new(cfg, mock, fetcher); - let parent = L2BlockInfo::default(); - let sb = SingleBatch::default(); - bq.next_spans.push(sb.clone()); - let next = bq.pop_next_batch(parent).unwrap(); - assert_eq!(next, sb); - assert!(bq.next_spans.is_empty()); - } - - #[tokio::test] - async fn test_batch_queue_reset() { - let cfg = Arc::new(RollupConfig::default()); - let mock = TestNextBatchProvider::new(vec![]); - let fetcher = TestL2ChainProvider::default(); - let mut bq = BatchQueue::new(cfg.clone(), mock, fetcher); - bq.l1_blocks.push(BlockInfo::default()); - bq.next_spans.push(SingleBatch::default()); - bq.batches.push(BatchWithInclusionBlock { - inclusion_block: BlockInfo::default(), - batch: Batch::Single(SingleBatch::default()), - }); - assert!(!bq.prev.reset); - bq.signal(ResetSignal::default().signal()).await.unwrap(); - assert!(bq.prev.reset); - assert_eq!(bq.origin, Some(BlockInfo::default())); - assert!(bq.batches.is_empty()); - assert_eq!(bq.l1_blocks, vec![BlockInfo::default()]); - assert!(bq.next_spans.is_empty()); + BatchReader::new(bytes, MAX_RLP_BYTES_PER_CHANNEL_BEDROCK as usize) } #[tokio::test] @@ -523,9 +393,8 @@ mod tests { let cfg = Arc::new(RollupConfig::default()); let mock = TestNextBatchProvider::new(vec![]); let fetcher = TestL2ChainProvider::default(); - let mut bq = BatchQueue::new(cfg.clone(), mock, fetcher); + let mut bq = BatchQueue::new(cfg.clone(), mock); bq.l1_blocks.push(BlockInfo::default()); - bq.next_spans.push(SingleBatch::default()); bq.batches.push(BatchWithInclusionBlock { inclusion_block: BlockInfo::default(), batch: Batch::Single(SingleBatch::default()), @@ -534,118 +403,12 @@ mod tests { assert!(bq.prev.flushed); assert!(bq.batches.is_empty()); assert!(!bq.l1_blocks.is_empty()); - assert!(bq.next_spans.is_empty()); - } - - #[tokio::test] - async fn test_holocene_add_batch_valid() { - // Construct a future single batch. - let cfg = Arc::new(RollupConfig { - max_sequencer_drift: 700, - holocene_time: Some(0), - ..Default::default() - }); - assert!(cfg.is_holocene_active(0)); - let batch = SingleBatch { - parent_hash: B256::default(), - epoch_num: 0, - epoch_hash: B256::default(), - timestamp: 100, - transactions: Vec::new(), - }; - let parent = L2BlockInfo { - block_info: BlockInfo { timestamp: 100, ..Default::default() }, - ..Default::default() - }; - - // Setup batch queue deps - let batch_vec = vec![PipelineResult::Ok(Batch::Single(batch.clone()))]; - let mut mock = TestNextBatchProvider::new(batch_vec); - mock.origin = Some(BlockInfo::default()); - let fetcher = TestL2ChainProvider::default(); - - // Configure batch queue - let mut bq = BatchQueue::new(cfg.clone(), mock, fetcher); - bq.origin = Some(BlockInfo::default()); // Set the origin - bq.l1_blocks.push(BlockInfo::default()); // Push the origin into the l1 blocks - bq.l1_blocks.push(BlockInfo::default()); // Push the next origin into the bq - - // Add the batch to the batch queue - bq.add_batch(Batch::Single(batch), parent).await.unwrap(); - assert_eq!(bq.batches.len(), 1); - } - - #[tokio::test] - async fn test_holocene_add_batch_future() { - // Construct a future single batch. - let cfg = Arc::new(RollupConfig { holocene_time: Some(0), ..Default::default() }); - assert!(cfg.is_holocene_active(0)); - let batch = SingleBatch { - parent_hash: B256::default(), - epoch_num: 0, - epoch_hash: B256::default(), - timestamp: 100, - transactions: Vec::new(), - }; - let parent = L2BlockInfo::default(); - - // Setup batch queue deps - let batch_vec = vec![PipelineResult::Ok(Batch::Single(batch.clone()))]; - let mut mock = TestNextBatchProvider::new(batch_vec); - mock.origin = Some(BlockInfo::default()); - let fetcher = TestL2ChainProvider::default(); - - // Configure batch queue - let mut bq = BatchQueue::new(cfg.clone(), mock, fetcher); - bq.origin = Some(BlockInfo::default()); // Set the origin - bq.l1_blocks.push(BlockInfo::default()); // Push the origin into the l1 blocks - bq.l1_blocks.push(BlockInfo::default()); // Push the next origin into the bq - - // Add the batch to the batch queue - bq.add_batch(Batch::Single(batch), parent).await.unwrap(); - assert!(bq.batches.is_empty()); } #[tokio::test] async fn test_add_batch_drop() { // Construct a single batch with BatchValidity::Drop. let cfg = Arc::new(RollupConfig::default()); - assert!(!cfg.is_holocene_active(0)); - let batch = SingleBatch { - parent_hash: B256::default(), - epoch_num: 0, - epoch_hash: B256::default(), - timestamp: 100, - transactions: Vec::new(), - }; - let parent = L2BlockInfo { - block_info: BlockInfo { timestamp: 101, ..Default::default() }, - ..Default::default() - }; - - // Setup batch queue deps - let batch_vec = vec![PipelineResult::Ok(Batch::Single(batch.clone()))]; - let mut mock = TestNextBatchProvider::new(batch_vec); - mock.origin = Some(BlockInfo::default()); - let fetcher = TestL2ChainProvider::default(); - - // Configure batch queue - let mut bq = BatchQueue::new(cfg.clone(), mock, fetcher); - bq.origin = Some(BlockInfo::default()); // Set the origin - bq.l1_blocks.push(BlockInfo::default()); // Push the origin into the l1 blocks - bq.l1_blocks.push(BlockInfo::default()); // Push the next origin into the bq - - // Add the batch to the batch queue - bq.add_batch(Batch::Single(batch), parent).await.unwrap(); - assert!(bq.batches.is_empty()); - } - - #[tokio::test] - async fn test_add_old_batch_drop_holocene() { - // Construct a single batch with BatchValidity::Past. - let cfg = - Arc::new(RollupConfig { holocene_time: Some(0), block_time: 2, ..Default::default() }); - assert!(cfg.is_holocene_active(0)); let batch = SingleBatch { parent_hash: B256::default(), epoch_num: 0, @@ -665,7 +428,7 @@ mod tests { let fetcher = TestL2ChainProvider::default(); // Configure batch queue - let mut bq = BatchQueue::new(cfg.clone(), mock, fetcher); + let mut bq = BatchQueue::new(cfg.clone(), mock); bq.origin = Some(BlockInfo::default()); // Set the origin bq.l1_blocks.push(BlockInfo::default()); // Push the origin into the l1 blocks bq.l1_blocks.push(BlockInfo::default()); // Push the next origin into the bq @@ -681,7 +444,7 @@ mod tests { let cfg = Arc::new(RollupConfig::default()); let mock = TestNextBatchProvider::new(data); let fetcher = TestL2ChainProvider::default(); - let mut bq = BatchQueue::new(cfg, mock, fetcher); + let mut bq = BatchQueue::new(cfg, mock); let parent = L2BlockInfo::default(); let result = bq.derive_next_batch(false, parent).await.unwrap_err(); assert_eq!(result, PipelineError::MissingOrigin.crit()); @@ -698,7 +461,7 @@ mod tests { let mut mock = TestNextBatchProvider::new(batch_vec); mock.origin = Some(BlockInfo::default()); let fetcher = TestL2ChainProvider::default(); - let mut bq = BatchQueue::new(cfg, mock, fetcher); + let mut bq = BatchQueue::new(cfg, mock); let parent = L2BlockInfo { l1_origin: BlockNumHash { number: 10, ..Default::default() }, ..Default::default() @@ -719,7 +482,7 @@ mod tests { let mut mock = TestNextBatchProvider::new(batch_vec); mock.origin = Some(BlockInfo::default()); let fetcher = TestL2ChainProvider::default(); - let mut bq = BatchQueue::new(cfg, mock, fetcher); + let mut bq = BatchQueue::new(cfg, mock); bq.origin = Some(BlockInfo::default()); bq.l1_blocks.push(BlockInfo::default()); @@ -728,7 +491,6 @@ mod tests { assert_eq!(bq.l1_blocks.len(), 1); let result = bq.derive_next_batch(true, L2BlockInfo::default()).await.unwrap_err(); assert_eq!(result, PipelineError::Eof.temp()); - assert!(bq.is_last_in_span()); } #[tokio::test] @@ -743,7 +505,7 @@ mod tests { let mut mock = TestNextBatchProvider::new(batch_vec); mock.origin = Some(BlockInfo::default()); let fetcher = TestL2ChainProvider::default(); - let mut bq = BatchQueue::new(cfg, mock, fetcher); + let mut bq = BatchQueue::new(cfg, mock); bq.origin = Some(BlockInfo::default()); bq.l1_blocks.push(BlockInfo::default()); @@ -752,7 +514,6 @@ mod tests { assert_eq!(bq.l1_blocks.len(), 1); let result = bq.derive_next_batch(false, L2BlockInfo::default()).await.unwrap_err(); assert_eq!(result, PipelineError::Eof.temp()); - assert!(bq.is_last_in_span()); } #[tokio::test] @@ -767,7 +528,7 @@ mod tests { let mut mock = TestNextBatchProvider::new(batch_vec); mock.origin = Some(BlockInfo::default()); let fetcher = TestL2ChainProvider::default(); - let mut bq = BatchQueue::new(cfg, mock, fetcher); + let mut bq = BatchQueue::new(cfg, mock); bq.origin = Some(BlockInfo::default()); bq.l1_blocks.push(BlockInfo::default()); bq.l1_blocks.push(BlockInfo::default()); @@ -777,7 +538,6 @@ mod tests { assert_eq!(bq.l1_blocks.len(), 2); let result = bq.derive_next_batch(true, L2BlockInfo::default()).await.unwrap_err(); assert_eq!(result, PipelineError::Eof.temp()); - assert!(bq.is_last_in_span()); assert_eq!(bq.l1_blocks.len(), 1); } @@ -785,7 +545,6 @@ mod tests { async fn test_derive_next_batch_future_batch() { // Construct a future single batch. let cfg = Arc::new(RollupConfig::default()); - assert!(!cfg.is_holocene_active(0)); // Asserts holocene is not active. let batch = SingleBatch { parent_hash: B256::default(), epoch_num: 0, @@ -802,7 +561,7 @@ mod tests { let fetcher = TestL2ChainProvider::default(); // Configure batch queue - let mut bq = BatchQueue::new(cfg.clone(), mock, fetcher); + let mut bq = BatchQueue::new(cfg.clone(), mock); bq.origin = Some(BlockInfo::default()); // Set the origin bq.l1_blocks.push(BlockInfo::default()); // Push the origin into the l1 blocks bq.l1_blocks.push(BlockInfo::default()); // Push the next origin into the bq @@ -814,7 +573,6 @@ mod tests { // Derive next batch let result = bq.derive_next_batch(true, L2BlockInfo::default()).await.unwrap_err(); assert_eq!(result, PipelineError::Eof.temp()); - assert!(bq.is_last_in_span()); assert_eq!(bq.batches.len(), 1); } @@ -826,8 +584,7 @@ mod tests { let _guard = tracing::subscriber::set_default(subscriber); // Construct a future single batch. - let cfg = Arc::new(RollupConfig { holocene_time: Some(0), ..Default::default() }); - assert!(cfg.is_holocene_active(0)); + let cfg = Arc::new(RollupConfig { ..Default::default() }); let batch = SingleBatch { parent_hash: B256::default(), epoch_num: 0, @@ -844,7 +601,7 @@ mod tests { let fetcher = TestL2ChainProvider::default(); // Configure batch queue - let mut bq = BatchQueue::new(cfg.clone(), mock, fetcher); + let mut bq = BatchQueue::new(cfg.clone(), mock); bq.origin = Some(BlockInfo::default()); // Set the origin bq.l1_blocks.push(BlockInfo::default()); // Push the origin into the l1 blocks bq.l1_blocks.push(BlockInfo::default()); // Push the next origin into the bq @@ -860,7 +617,6 @@ mod tests { // Derive next batch let result = bq.derive_next_batch(true, L2BlockInfo::default()).await.unwrap_err(); assert_eq!(result, PipelineError::Eof.temp()); - assert!(bq.is_last_in_span()); assert!(bq.batches.is_empty()); // Validate logs @@ -870,25 +626,6 @@ mod tests { assert!(logs[0].contains(warn_str)); } - #[tokio::test] - async fn test_next_batch_cached_single_batch() { - let mut reader = new_batch_reader(); - let cfg = Arc::new(RollupConfig::default()); - let mut batch_vec: Vec> = vec![]; - while let Some(batch) = reader.next_batch(cfg.as_ref()) { - batch_vec.push(Ok(batch)); - } - let mut mock = TestNextBatchProvider::new(batch_vec); - mock.origin = Some(BlockInfo::default()); - let fetcher = TestL2ChainProvider::default(); - let mut bq = BatchQueue::new(cfg, mock, fetcher); - let sb = SingleBatch::default(); - bq.next_spans.push(sb.clone()); - let next = bq.next_batch(L2BlockInfo::default()).await.unwrap(); - assert_eq!(next, sb); - assert!(bq.next_spans.is_empty()); - } - #[tokio::test] async fn test_next_batch_clear_next_spans() { let mut reader = new_batch_reader(); @@ -900,12 +637,10 @@ mod tests { let mut mock = TestNextBatchProvider::new(batch_vec); mock.origin = Some(BlockInfo::default()); let fetcher = TestL2ChainProvider::default(); - let mut bq = BatchQueue::new(cfg, mock, fetcher); + let mut bq = BatchQueue::new(cfg, mock); let sb = SingleBatch::default(); - bq.next_spans.push(sb.clone()); let res = bq.next_batch(L2BlockInfo::default()).await.unwrap_err(); assert_eq!(res, PipelineError::NotEnoughData.temp()); - assert!(bq.is_last_in_span()); } #[tokio::test] @@ -915,10 +650,9 @@ mod tests { let batch = reader.next_batch(cfg.as_ref()).unwrap(); let mock = TestNextBatchProvider::new(vec![Ok(batch)]); let fetcher = TestL2ChainProvider::default(); - let mut bq = BatchQueue::new(cfg, mock, fetcher); + let mut bq = BatchQueue::new(cfg, mock); let res = bq.next_batch(L2BlockInfo::default()).await.unwrap_err(); assert_eq!(res, PipelineError::NotEnoughData.temp()); - assert!(bq.is_last_in_span()); } #[tokio::test] @@ -932,7 +666,7 @@ mod tests { let mut mock = TestNextBatchProvider::new(batch_vec); mock.origin = Some(BlockInfo::default()); let fetcher = TestL2ChainProvider::default(); - let mut bq = BatchQueue::new(cfg, mock, fetcher); + let mut bq = BatchQueue::new(cfg, mock); let parent = L2BlockInfo { l1_origin: BlockNumHash { number: 10, ..Default::default() }, ..Default::default() @@ -952,7 +686,6 @@ mod tests { let payload_block_hash = b256!("4444444444444444444444444444444444444444444444444444444444444444"); let cfg = Arc::new(RollupConfig { - delta_time: Some(0), block_time: 100, max_sequencer_drift: 10000000, seq_window_size: 10000000, @@ -968,9 +701,14 @@ mod tests { let mut batch_txs: Vec = vec![]; let mut second_batch_txs: Vec = vec![]; while let Some(batch) = reader.next_batch(cfg.as_ref()) { - if let Batch::Span(span) = &batch { - batch_txs.extend(span.batches[0].transactions.clone()); - second_batch_txs.extend(span.batches[1].transactions.clone()); + if let Batch::Single(span) = &batch { + SingleBatch { + parent_hash: B256::default(), + epoch_num: 0, + epoch_hash: B256::default(), + timestamp: 100, + transactions: Vec::new(), + }; } batch_vec.push(Ok(batch)); } @@ -995,6 +733,8 @@ mod tests { value: U256::from(4_u64), input: deposit_tx_calldata, is_system_transaction: false, + eth_value: None, + eth_tx_value: None, }; let mut buf = BytesMut::new(); tx.encode(&mut buf); @@ -1045,6 +785,7 @@ mod tests { transactions: batch_txs, ommers: Vec::new(), withdrawals: None, + requests: None, }, }; let second = OpBlock { @@ -1053,6 +794,7 @@ mod tests { transactions: second_batch_txs, ommers: Vec::new(), withdrawals: None, + requests: None, }, }; let fetcher = TestL2ChainProvider { @@ -1060,7 +802,7 @@ mod tests { op_blocks: vec![block, second], ..Default::default() }; - let mut bq = BatchQueue::new(cfg, mock, fetcher); + let mut bq = BatchQueue::new(cfg, mock); let parent = L2BlockInfo { block_info: BlockInfo { number: 9, @@ -1089,7 +831,7 @@ mod tests { let cfg = Arc::new(RollupConfig::default()); let mock = TestNextBatchProvider::new(data); let fetcher = TestL2ChainProvider::default(); - let mut bq = BatchQueue::new(cfg, mock, fetcher); + let mut bq = BatchQueue::new(cfg, mock); let parent = L2BlockInfo::default(); let batch = bq.next_batch(parent).await.unwrap(); assert_eq!(batch, SingleBatch::default()); diff --git a/crates/derive/src/stages/batch/batch_stream.rs b/crates/derive/src/stages/batch/batch_stream.rs index abc561f080..d0d87306b1 100644 --- a/crates/derive/src/stages/batch/batch_stream.rs +++ b/crates/derive/src/stages/batch/batch_stream.rs @@ -11,7 +11,7 @@ use async_trait::async_trait; use core::fmt::Debug; use op_alloy_genesis::RollupConfig; use op_alloy_protocol::{ - Batch, BatchValidity, BatchWithInclusionBlock, BlockInfo, L2BlockInfo, SingleBatch, SpanBatch, + Batch, BatchValidity, BatchWithInclusionBlock, BlockInfo, L2BlockInfo, SingleBatch, }; /// Provides [Batch]es for the [BatchStream] stage. @@ -34,169 +34,51 @@ pub trait BatchStreamProvider { /// [ChannelReader]: crate::stages::ChannelReader /// [BatchQueue]: crate::stages::BatchQueue #[derive(Debug)] -pub struct BatchStream +pub struct BatchStream

where P: BatchStreamProvider + OriginAdvancer + OriginProvider + SignalReceiver + Debug, - BF: L2ChainProvider + Debug, { /// The previous stage in the derivation pipeline. prev: P, - /// There can only be a single staged span batch. - span: Option, - /// A buffer of single batches derived from the [SpanBatch]. - buffer: VecDeque, - /// A reference to the rollup config, used to check - /// if the [BatchStream] stage should be activated. - config: Arc, - /// Used to validate the batches. - fetcher: BF, } -impl BatchStream +impl

BatchStream

where P: BatchStreamProvider + OriginAdvancer + OriginProvider + SignalReceiver + Debug, - BF: L2ChainProvider + Debug, { /// Create a new [BatchStream] stage. - pub const fn new(prev: P, config: Arc, fetcher: BF) -> Self { - Self { prev, span: None, buffer: VecDeque::new(), config, fetcher } - } - - /// Returns if the [BatchStream] stage is active based on the - /// origin timestamp and holocene activation timestamp. - pub fn is_active(&self) -> PipelineResult { - let origin = self.prev.origin().ok_or(PipelineError::MissingOrigin.crit())?; - Ok(self.config.is_holocene_active(origin.timestamp)) - } - - /// Gets a [SingleBatch] from the in-memory buffer. - pub fn get_single_batch( - &mut self, - parent: L2BlockInfo, - l1_origins: &[BlockInfo], - ) -> PipelineResult { - trace!(target: "batch_span", "Attempting to get a SingleBatch from buffer len: {}", self.buffer.len()); - - self.try_hydrate_buffer(parent, l1_origins)?; - self.buffer.pop_front().ok_or_else(|| PipelineError::NotEnoughData.temp()) - } - - /// Hydrates the buffer with single batches derived from the span batch, if there is one - /// queued up. - pub fn try_hydrate_buffer( - &mut self, - parent: L2BlockInfo, - l1_origins: &[BlockInfo], - ) -> PipelineResult<()> { - if let Some(span) = self.span.take() { - self.buffer.extend( - span.get_singular_batches(l1_origins, parent).map_err(|e| { - PipelineError::BadEncoding(PipelineEncodingError::from(e)).crit() - })?, - ); - } - Ok(()) + pub const fn new(prev: P) -> Self { + Self { prev } } } #[async_trait] -impl NextBatchProvider for BatchStream +impl

NextBatchProvider for BatchStream

where P: BatchStreamProvider + OriginAdvancer + OriginProvider + SignalReceiver + Send + Debug, - BF: L2ChainProvider + Send + Debug, { fn flush(&mut self) { - if self.is_active().unwrap_or(false) { - self.prev.flush(); - self.span = None; - self.buffer.clear(); - } + // mantle have no holocene version } - fn span_buffer_size(&self) -> usize { - self.buffer.len() - } - - async fn next_batch( - &mut self, - parent: L2BlockInfo, - l1_origins: &[BlockInfo], - ) -> PipelineResult { - // If the stage is not active, "pass" the next batch - // through this stage to the BatchQueue stage. - if !self.is_active()? { - trace!(target: "batch_span", "BatchStream stage is inactive, pass-through."); - return self.prev.next_batch().await; - } - - // If the buffer is empty, attempt to pull a batch from the previous stage. - if self.buffer.is_empty() { - // Safety: bubble up any errors from the batch reader. - let batch_with_inclusion = BatchWithInclusionBlock::new( - self.origin().ok_or(PipelineError::MissingOrigin.crit())?, - self.prev.next_batch().await?, - ); - - // If the next batch is a singular batch, it is immediately - // forwarded to the `BatchQueue` stage. Otherwise, we buffer - // the span batch in this stage if it passes the validity checks. - match batch_with_inclusion.batch { - Batch::Single(b) => return Ok(Batch::Single(b)), - Batch::Span(b) => { - let (validity, _) = b - .check_batch_prefix( - self.config.as_ref(), - l1_origins, - parent, - &batch_with_inclusion.inclusion_block, - &mut self.fetcher, - ) - .await; - - match validity { - BatchValidity::Accept => self.span = Some(b), - BatchValidity::Drop => { - // Flush the stage. - self.flush(); - - return Err(PipelineError::Eof.temp()); - } - BatchValidity::Past => { - if !self.is_active()? { - error!(target: "batch-stream", "BatchValidity::Past is not allowed pre-holocene"); - return Err(PipelineError::InvalidBatchValidity.crit()); - } - - return Err(PipelineError::Eof.temp()); - } - BatchValidity::Undecided | BatchValidity::Future => { - return Err(PipelineError::NotEnoughData.temp()) - } - } - } - } - } - - // Attempt to pull a SingleBatch out of the SpanBatch. - self.get_single_batch(parent, l1_origins).map(Batch::Single) + async fn next_batch(&mut self) -> PipelineResult { + self.prev.next_batch().await } } #[async_trait] -impl OriginAdvancer for BatchStream +impl

OriginAdvancer for BatchStream

where P: BatchStreamProvider + OriginAdvancer + OriginProvider + SignalReceiver + Send + Debug, - BF: L2ChainProvider + Send + Debug, { async fn advance_origin(&mut self) -> PipelineResult<()> { self.prev.advance_origin().await } } -impl OriginProvider for BatchStream +impl

OriginProvider for BatchStream

where P: BatchStreamProvider + OriginAdvancer + OriginProvider + SignalReceiver + Debug, - BF: L2ChainProvider + Debug, { fn origin(&self) -> Option { self.prev.origin() @@ -204,15 +86,12 @@ where } #[async_trait] -impl SignalReceiver for BatchStream +impl

SignalReceiver for BatchStream

where P: BatchStreamProvider + OriginAdvancer + OriginProvider + SignalReceiver + Debug + Send, - BF: L2ChainProvider + Send + Debug, { async fn signal(&mut self, signal: Signal) -> PipelineResult<()> { self.prev.signal(signal).await?; - self.buffer.clear(); - self.span.take(); Ok(()) } } @@ -225,161 +104,38 @@ mod test { types::ResetSignal, }; use alloc::vec; - use op_alloy_protocol::{SingleBatch, SpanBatchElement}; + use op_alloy_protocol::SingleBatch; use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; - #[tokio::test] - async fn test_batch_stream_flush() { - let config = Arc::new(RollupConfig { holocene_time: Some(0), ..RollupConfig::default() }); - let prev = TestBatchStreamProvider::new(vec![]); - let mut stream = BatchStream::new(prev, config, TestL2ChainProvider::default()); - stream.buffer.push_back(SingleBatch::default()); - stream.span = Some(SpanBatch::default()); - assert!(!stream.buffer.is_empty()); - assert!(stream.span.is_some()); - stream.flush(); - assert!(stream.buffer.is_empty()); - assert!(stream.span.is_none()); - } - #[tokio::test] async fn test_batch_stream_reset() { - let config = Arc::new(RollupConfig { holocene_time: Some(0), ..RollupConfig::default() }); + let config = Arc::new(RollupConfig { ..RollupConfig::default() }); let prev = TestBatchStreamProvider::new(vec![]); - let mut stream = BatchStream::new(prev, config.clone(), TestL2ChainProvider::default()); - stream.buffer.push_back(SingleBatch::default()); - stream.span = Some(SpanBatch::default()); + let mut stream = BatchStream::new(prev); assert!(!stream.prev.reset); stream.signal(ResetSignal::default().signal()).await.unwrap(); assert!(stream.prev.reset); - assert!(stream.buffer.is_empty()); - assert!(stream.span.is_none()); } #[tokio::test] async fn test_batch_stream_flush_channel() { - let config = Arc::new(RollupConfig { holocene_time: Some(0), ..RollupConfig::default() }); + let config = Arc::new(RollupConfig { ..RollupConfig::default() }); let prev = TestBatchStreamProvider::new(vec![]); - let mut stream = BatchStream::new(prev, config.clone(), TestL2ChainProvider::default()); - stream.buffer.push_back(SingleBatch::default()); - stream.span = Some(SpanBatch::default()); + let mut stream = BatchStream::new(prev); assert!(!stream.prev.flushed); stream.signal(Signal::FlushChannel).await.unwrap(); assert!(stream.prev.flushed); - assert!(stream.buffer.is_empty()); - assert!(stream.span.is_none()); - } - - #[tokio::test] - async fn test_batch_stream_inactive() { - let trace_store: TraceStorage = Default::default(); - let layer = CollectingLayer::new(trace_store.clone()); - tracing_subscriber::Registry::default().with(layer).init(); - - let data = vec![Ok(Batch::Single(SingleBatch::default()))]; - let config = Arc::new(RollupConfig { holocene_time: Some(100), ..RollupConfig::default() }); - let prev = TestBatchStreamProvider::new(data); - let mut stream = BatchStream::new(prev, config.clone(), TestL2ChainProvider::default()); - - // The stage should not be active. - assert!(!stream.is_active().unwrap()); - - // The next batch should be passed through to the [BatchQueue] stage. - let batch = stream.next_batch(Default::default(), &[]).await.unwrap(); - assert_eq!(batch, Batch::Single(SingleBatch::default())); - - let logs = trace_store.get_by_level(tracing::Level::TRACE); - assert_eq!(logs.len(), 1); - assert!(logs[0].contains("BatchStream stage is inactive, pass-through.")); - } - - #[tokio::test] - async fn test_span_buffer() { - let mock_batch = SpanBatch { - batches: vec![ - SpanBatchElement { epoch_num: 1, timestamp: 2, ..Default::default() }, - SpanBatchElement { epoch_num: 1, timestamp: 4, ..Default::default() }, - ], - ..Default::default() - }; - let mock_origins = [BlockInfo { number: 1, timestamp: 12, ..Default::default() }]; - - let data = vec![Ok(Batch::Span(mock_batch.clone()))]; - let config = Arc::new(RollupConfig { - delta_time: Some(0), - holocene_time: Some(0), - block_time: 2, - ..RollupConfig::default() - }); - let prev = TestBatchStreamProvider::new(data); - let provider = TestL2ChainProvider::default(); - let mut stream = BatchStream::new(prev, config.clone(), provider); - - // The stage should be active. - assert!(stream.is_active().unwrap()); - - // The next batches should be single batches derived from the span batch. - let batch = stream.next_batch(Default::default(), &mock_origins).await.unwrap(); - if let Batch::Single(single) = batch { - assert_eq!(single.epoch_num, 1); - assert_eq!(single.timestamp, 2); - } else { - panic!("Wrong batch type"); - } - - let batch = stream.next_batch(Default::default(), &mock_origins).await.unwrap(); - if let Batch::Single(single) = batch { - assert_eq!(single.epoch_num, 1); - assert_eq!(single.timestamp, 4); - } else { - panic!("Wrong batch type"); - } - - let err = stream.next_batch(Default::default(), &mock_origins).await.unwrap_err(); - assert_eq!(err, PipelineError::Eof.temp()); - assert_eq!(stream.span_buffer_size(), 0); - assert!(stream.span.is_none()); - - // Add more data into the provider, see if the buffer is re-hydrated. - stream.prev.batches.push(Ok(Batch::Span(mock_batch.clone()))); - - // The next batches should be single batches derived from the span batch. - let batch = stream.next_batch(Default::default(), &mock_origins).await.unwrap(); - if let Batch::Single(single) = batch { - assert_eq!(single.epoch_num, 1); - assert_eq!(single.timestamp, 2); - } else { - panic!("Wrong batch type"); - } - - let batch = stream.next_batch(Default::default(), &mock_origins).await.unwrap(); - if let Batch::Single(single) = batch { - assert_eq!(single.epoch_num, 1); - assert_eq!(single.timestamp, 4); - } else { - panic!("Wrong batch type"); - } - - let err = stream.next_batch(Default::default(), &mock_origins).await.unwrap_err(); - assert_eq!(err, PipelineError::Eof.temp()); - assert_eq!(stream.span_buffer_size(), 0); - assert!(stream.span.is_none()); } #[tokio::test] async fn test_single_batch_pass_through() { let data = vec![Ok(Batch::Single(SingleBatch::default()))]; - let config = Arc::new(RollupConfig { holocene_time: Some(0), ..RollupConfig::default() }); + let config = Arc::new(RollupConfig { ..RollupConfig::default() }); let prev = TestBatchStreamProvider::new(data); - let mut stream = BatchStream::new(prev, config.clone(), TestL2ChainProvider::default()); - - // The stage should be active. - assert!(stream.is_active().unwrap()); + let mut stream = BatchStream::new(prev); // The next batch should be passed through to the [BatchQueue] stage. - let batch = stream.next_batch(Default::default(), &[]).await.unwrap(); + let batch = stream.next_batch().await.unwrap(); assert!(matches!(batch, Batch::Single(_))); - assert_eq!(stream.span_buffer_size(), 0); - assert!(stream.span.is_none()); } } diff --git a/crates/derive/src/stages/batch/batch_validator.rs b/crates/derive/src/stages/batch/batch_validator.rs index 4a5dd6241f..e69de29bb2 100644 --- a/crates/derive/src/stages/batch/batch_validator.rs +++ b/crates/derive/src/stages/batch/batch_validator.rs @@ -1,618 +0,0 @@ -#![allow(clippy::unnecessary_map_or)] -//! Contains the [BatchValidator] stage. - -use super::NextBatchProvider; -use crate::{ - errors::ResetError, - prelude::{OriginProvider, PipelineError, PipelineErrorKind}, - traits::{AttributesProvider, OriginAdvancer, SignalReceiver}, - types::{PipelineResult, ResetSignal, Signal}, -}; -use alloc::{boxed::Box, sync::Arc, vec::Vec}; -use async_trait::async_trait; -use core::fmt::Debug; -use op_alloy_genesis::RollupConfig; -use op_alloy_protocol::{Batch, BatchValidity, BlockInfo, L2BlockInfo, SingleBatch}; - -/// The [BatchValidator] stage is responsible for validating the [SingleBatch]es from -/// the [BatchStream] [AttributesQueue]'s consumption. -/// -/// [BatchStream]: crate::stages::BatchStream -/// [AttributesQueue]: crate::stages::attributes_queue::AttributesQueue -#[derive(Debug)] -pub struct BatchValidator

-where - P: NextBatchProvider + OriginAdvancer + OriginProvider + SignalReceiver + Debug, -{ - /// The rollup configuration. - pub(crate) cfg: Arc, - /// The previous stage of the derivation pipeline. - pub(crate) prev: P, - /// The L1 origin of the batch sequencer. - pub(crate) origin: Option, - /// A consecutive, time-centric window of L1 Blocks. - /// Every L1 origin of unsafe L2 Blocks must be included in this list. - /// If every L2 Block corresponding to a single L1 Block becomes safe, - /// the block is popped from this list. - /// If new L2 Block's L1 origin is not included in this list, fetch and - /// push it to the list. - pub(crate) l1_blocks: Vec, -} - -impl

BatchValidator

-where - P: NextBatchProvider + OriginAdvancer + OriginProvider + SignalReceiver + Debug, -{ - /// Create a new [BatchValidator] stage. - pub const fn new(cfg: Arc, prev: P) -> Self { - Self { cfg, prev, origin: None, l1_blocks: Vec::new() } - } - - /// Returns `true` if the pipeline origin is behind the parent origin. - /// - /// ## Takes - /// - `parent`: The parent block of the current batch. - /// - /// ## Returns - /// - `true` if the origin is behind the parent origin. - fn origin_behind(&self, parent: &L2BlockInfo) -> bool { - self.prev.origin().map_or(true, |origin| origin.number < parent.l1_origin.number) - } - - /// Updates the [BatchValidator]'s view of the L1 origin blocks. - /// - /// ## Takes - /// - `parent`: The parent block of the current batch. - /// - /// ## Returns - /// - `Ok(())` if the update was successful. - /// - `Err(PipelineError)` if the update failed. - pub(crate) fn update_origins(&mut self, parent: &L2BlockInfo) -> PipelineResult<()> { - // NOTE: The origin is used to determine if it's behind. - // It is the future origin that gets saved into the l1 blocks array. - // We always update the origin of this stage if it's not the same so - // after the update code runs, this is consistent. - let origin_behind = self.origin_behind(parent); - - // Advance the origin if needed. - // The entire pipeline has the same origin. - // Batches prior to the l1 origin of the l2 safe head are not accepted. - if self.origin != self.prev.origin() { - self.origin = self.prev.origin(); - if !origin_behind { - let origin = self.origin.as_ref().ok_or(PipelineError::MissingOrigin.crit())?; - self.l1_blocks.push(*origin); - } else { - // This is to handle the special case of startup. - // At startup, the batch validator is reset and includes the - // l1 origin. That is the only time when immediately after - // reset is called, the origin behind is false. - self.l1_blocks.clear(); - } - debug!( - target: "batch-validator", - "Advancing batch validator origin to L1 block #{}.{}", - self.origin.map(|b| b.number).unwrap_or_default(), - origin_behind.then_some(" (origin behind)").unwrap_or_default() - ); - } - - // If the epoch is advanced, update the l1 blocks. - // Advancing epoch must be done after the pipeline successfully applies the entire span - // batch to the chain. - // Because the span batch can be reverted during processing the batch, then we must - // preserve existing l1 blocks to verify the epochs of the next candidate batch. - if !self.l1_blocks.is_empty() && parent.l1_origin.number > self.l1_blocks[0].number { - for (i, block) in self.l1_blocks.iter().enumerate() { - if parent.l1_origin.number == block.number { - self.l1_blocks.drain(0..i); - debug!(target: "batch-validator", "Advancing internal L1 epoch"); - break; - } - } - // If the origin of the parent block is not included, we must advance the origin. - } - - Ok(()) - } - - /// Attempts to derive an empty batch, if the sequencing window is expired. - /// - /// ## Takes - /// - `parent`: The parent block of the current batch. - /// - /// ## Returns - /// - `Ok(SingleBatch)` if an empty batch was derived. - /// - `Err(PipelineError)` if an empty batch could not be derived. - pub(crate) fn try_derive_empty_batch( - &mut self, - parent: &L2BlockInfo, - ) -> PipelineResult { - let epoch = self.l1_blocks[0]; - - // If the current epoch is too old compared to the L1 block we are at, - // i.e. if the sequence window expired, we create empty batches for the current epoch - let stage_origin = self.origin.ok_or(PipelineError::MissingOrigin.crit())?; - let expiry_epoch = epoch.number + self.cfg.seq_window_size; - let force_empty_batches = expiry_epoch <= stage_origin.number; - let first_of_epoch = epoch.number == parent.l1_origin.number + 1; - let next_timestamp = parent.block_info.timestamp + self.cfg.block_time; - - // If the sequencer window did not expire, - // there is still room to receive batches for the current epoch. - // No need to force-create empty batch(es) towards the next epoch yet. - if !force_empty_batches { - return Err(PipelineError::Eof.temp()); - } - - // The next L1 block is needed to proceed towards the next epoch. - if self.l1_blocks.len() < 2 { - return Err(PipelineError::Eof.temp()); - } - - let next_epoch = self.l1_blocks[1]; - - // Fill with empty L2 blocks of the same epoch until we meet the time of the next L1 origin, - // to preserve that L2 time >= L1 time. If this is the first block of the epoch, always - // generate a batch to ensure that we at least have one batch per epoch. - if next_timestamp < next_epoch.timestamp || first_of_epoch { - info!(target: "batch-validator", "Generating empty batch for epoch #{}", epoch.number); - return Ok(SingleBatch { - parent_hash: parent.block_info.hash, - epoch_num: epoch.number, - epoch_hash: epoch.hash, - timestamp: next_timestamp, - transactions: Vec::new(), - }); - } - - // At this point we have auto generated every batch for the current epoch - // that we can, so we can advance to the next epoch. - debug!( - target: "batch-validator", - "Advancing batch validator epoch: {}, timestamp: {}, epoch timestamp: {}", - next_epoch.number, next_timestamp, next_epoch.timestamp - ); - self.l1_blocks.remove(0); - Err(PipelineError::Eof.temp()) - } -} - -#[async_trait] -impl

AttributesProvider for BatchValidator

-where - P: NextBatchProvider + OriginAdvancer + OriginProvider + SignalReceiver + Send + Debug, -{ - async fn next_batch(&mut self, parent: L2BlockInfo) -> PipelineResult { - // Update the L1 origin blocks within the stage. - self.update_origins(&parent)?; - - // If the origin is behind, we must drain previous stages to catch up. - let stage_origin = self.origin.ok_or(PipelineError::MissingOrigin.crit())?; - if self.origin_behind(&parent) || parent.l1_origin.number == stage_origin.number { - self.prev.next_batch(parent, self.l1_blocks.as_ref()).await?; - return Err(PipelineError::NotEnoughData.temp()); - } - - // At least the L1 origin of the safe block and the L1 origin of the following block must - // be included in the l1 blocks. - if self.l1_blocks.len() < 2 { - return Err(PipelineError::MissingOrigin.crit()); - } - - // Note: epoch origin can now be one block ahead of the L2 Safe Head - // This is in the case where we auto generate all batches in an epoch & advance the epoch - // but don't advance the L2 Safe Head's epoch - let epoch = self.l1_blocks[0]; - if parent.l1_origin != epoch.id() && parent.l1_origin.number != epoch.number - 1 { - return Err(PipelineErrorKind::Reset(ResetError::L1OriginMismatch( - parent.l1_origin.number, - epoch.number - 1, - ))); - } - - // Pull the next batch from the previous stage. - let next_batch = match self.prev.next_batch(parent, self.l1_blocks.as_ref()).await { - Ok(batch) => batch, - Err(PipelineErrorKind::Temporary(PipelineError::Eof)) => { - return self.try_derive_empty_batch(&parent); - } - Err(e) => { - return Err(e); - } - }; - - // The batch must be a single batch - this stage does not support span batches. - let Batch::Single(mut next_batch) = next_batch else { - error!( - target: "batch-validator", - "BatchValidator received a batch that is not a SingleBatch" - ); - return Err(PipelineError::InvalidBatchType.crit()); - }; - next_batch.parent_hash = parent.block_info.hash; - - // Check the validity of the single batch before forwarding it. - match next_batch.check_batch( - self.cfg.as_ref(), - self.l1_blocks.as_ref(), - parent, - &stage_origin, - ) { - BatchValidity::Accept => { - info!(target: "batch-validator", "Found next batch (epoch #{})", next_batch.epoch_num); - Ok(next_batch) - } - BatchValidity::Past => { - warn!(target: "batch-validator", "Dropping old batch"); - Err(PipelineError::NotEnoughData.temp()) - } - BatchValidity::Drop => { - warn!(target: "batch-validator", "Invalid singular batch, flushing current channel."); - self.prev.flush(); - Err(PipelineError::NotEnoughData.temp()) - } - BatchValidity::Undecided => Err(PipelineError::NotEnoughData.temp()), - BatchValidity::Future => { - error!(target: "batch-validator", "Future batch detected in BatchValidator."); - Err(PipelineError::InvalidBatchValidity.crit()) - } - } - } - - fn is_last_in_span(&self) -> bool { - self.prev.span_buffer_size() == 0 - } -} - -impl

OriginProvider for BatchValidator

-where - P: NextBatchProvider + OriginAdvancer + OriginProvider + SignalReceiver + Debug, -{ - fn origin(&self) -> Option { - self.prev.origin() - } -} - -#[async_trait] -impl

OriginAdvancer for BatchValidator

-where - P: NextBatchProvider + OriginAdvancer + OriginProvider + SignalReceiver + Send + Debug, -{ - async fn advance_origin(&mut self) -> PipelineResult<()> { - self.prev.advance_origin().await - } -} - -#[async_trait] -impl

SignalReceiver for BatchValidator

-where - P: NextBatchProvider + OriginAdvancer + OriginProvider + SignalReceiver + Send + Debug, -{ - async fn signal(&mut self, signal: Signal) -> PipelineResult<()> { - match signal { - s @ Signal::Reset(ResetSignal { l1_origin, .. }) => { - self.prev.signal(s).await?; - self.origin = Some(l1_origin); - // Include the new origin as an origin to build on. - // This is only for the initialization case. - // During normal resets we will later throw out this block. - self.l1_blocks.clear(); - self.l1_blocks.push(l1_origin); - } - s @ Signal::Activation(_) | s @ Signal::FlushChannel => { - self.prev.signal(s).await?; - } - } - Ok(()) - } -} - -#[cfg(test)] -mod test { - use crate::{ - errors::{PipelineError, PipelineErrorKind, ResetError}, - stages::{BatchValidator, NextBatchProvider}, - test_utils::{CollectingLayer, TestNextBatchProvider, TraceStorage}, - traits::{AttributesProvider, OriginAdvancer, SignalReceiver}, - types::{PipelineResult, ResetSignal, Signal}, - }; - use alloc::{sync::Arc, vec, vec::Vec}; - use alloy_eips::{BlockNumHash, NumHash}; - use alloy_primitives::B256; - use op_alloy_genesis::RollupConfig; - use op_alloy_protocol::{Batch, BlockInfo, L2BlockInfo, SingleBatch, SpanBatch}; - use tracing::Level; - use tracing_subscriber::layer::SubscriberExt; - - #[tokio::test] - async fn test_batch_validator_origin_behind_eof() { - let cfg = Arc::new(RollupConfig::default()); - let mut mock = TestNextBatchProvider::new(vec![]); - mock.origin = Some(BlockInfo::default()); - let mut bv = BatchValidator::new(cfg, mock); - bv.origin = Some(BlockInfo { number: 1, ..Default::default() }); - - let mock_parent = L2BlockInfo { - l1_origin: BlockNumHash { number: 5, ..Default::default() }, - ..Default::default() - }; - assert_eq!(bv.next_batch(mock_parent).await.unwrap_err(), PipelineError::Eof.temp()); - } - - #[tokio::test] - async fn test_batch_validator_origin_behind_startup() { - let cfg = Arc::new(RollupConfig::default()); - let mut mock = TestNextBatchProvider::new(vec![]); - mock.origin = Some(BlockInfo::default()); - let mut bv = BatchValidator::new(cfg, mock); - - // Reset the pipeline to add the L1 origin to the stage. - bv.signal(Signal::Reset(ResetSignal { - l1_origin: BlockInfo { number: 1, ..Default::default() }, - l2_safe_head: L2BlockInfo::new( - BlockInfo::default(), - NumHash::new(1, Default::default()), - 0, - ), - system_config: None, - })) - .await - .unwrap(); - - let mock_parent = L2BlockInfo { - l1_origin: BlockNumHash { number: 2, ..Default::default() }, - ..Default::default() - }; - assert_eq!(bv.l1_blocks.len(), 1); - bv.update_origins(&mock_parent).unwrap(); - assert_eq!(bv.l1_blocks.len(), 0); - } - - #[tokio::test] - async fn test_batch_validator_origin_behind_advance() { - let cfg = Arc::new(RollupConfig::default()); - let mut mock = TestNextBatchProvider::new(vec![]); - mock.origin = Some(BlockInfo { number: 2, ..Default::default() }); - let mut bv = BatchValidator::new(cfg, mock); - - // Reset the pipeline to add the L1 origin to the stage. - bv.signal(Signal::Reset(ResetSignal { - l1_origin: BlockInfo { number: 1, ..Default::default() }, - l2_safe_head: L2BlockInfo::new( - BlockInfo::default(), - NumHash::new(1, Default::default()), - 0, - ), - system_config: None, - })) - .await - .unwrap(); - - let mock_parent = L2BlockInfo { - l1_origin: BlockNumHash { number: 1, ..Default::default() }, - ..Default::default() - }; - assert_eq!(bv.l1_blocks.len(), 1); - bv.update_origins(&mock_parent).unwrap(); - assert_eq!(bv.l1_blocks.len(), 2); - } - - #[tokio::test] - async fn test_batch_validator_advance_epoch() { - let cfg = Arc::new(RollupConfig::default()); - let mut mock = TestNextBatchProvider::new(vec![]); - mock.origin = Some(BlockInfo { number: 2, ..Default::default() }); - let mut bv = BatchValidator::new(cfg, mock); - - // Reset the pipeline to add the L1 origin to the stage. - bv.signal(Signal::Reset(ResetSignal { - l1_origin: BlockInfo { number: 1, ..Default::default() }, - l2_safe_head: L2BlockInfo::new( - BlockInfo::default(), - NumHash::new(1, Default::default()), - 0, - ), - system_config: None, - })) - .await - .unwrap(); - - let mock_parent = L2BlockInfo { - l1_origin: BlockNumHash { number: 2, ..Default::default() }, - ..Default::default() - }; - assert_eq!(bv.l1_blocks.len(), 1); - assert_eq!(bv.l1_blocks[0].number, 1); - assert_eq!(bv.next_batch(mock_parent).await.unwrap_err(), PipelineError::Eof.temp()); - assert_eq!(bv.l1_blocks.len(), 1); - assert_eq!(bv.l1_blocks[0].number, 2); - } - - #[tokio::test] - async fn test_batch_validator_origin_behind_drain_prev() { - let cfg = Arc::new(RollupConfig::default()); - let mut mock = TestNextBatchProvider::new( - (0..5).map(|_| Ok(Batch::Single(SingleBatch::default()))).collect(), - ); - mock.origin = Some(BlockInfo::default()); - let mut bv = BatchValidator::new(cfg, mock); - bv.origin = Some(BlockInfo::default()); - - let mock_parent = L2BlockInfo { - l1_origin: BlockNumHash { number: 5, ..Default::default() }, - ..Default::default() - }; - assert_eq!(bv.prev.span_buffer_size(), 5); - for i in 0..5 { - assert_eq!( - bv.next_batch(mock_parent).await.unwrap_err(), - PipelineError::NotEnoughData.temp() - ); - assert_eq!(bv.prev.span_buffer_size(), 4 - i); - } - assert_eq!(bv.next_batch(mock_parent).await.unwrap_err(), PipelineError::Eof.temp()); - } - - #[tokio::test] - async fn test_batch_validator_l1_origin_mismatch() { - let cfg = Arc::new(RollupConfig::default()); - let mut mock = TestNextBatchProvider::new(vec![Ok(Batch::Single(SingleBatch::default()))]); - mock.origin = Some(BlockInfo { number: 1, ..Default::default() }); - let mut bv = BatchValidator::new(cfg, mock); - bv.origin = Some(BlockInfo::default()); - bv.l1_blocks.push(BlockInfo::default()); - - let mock_parent = L2BlockInfo { - l1_origin: BlockNumHash { number: 0, hash: [0xFF; 32].into() }, - ..Default::default() - }; - - assert!(matches!( - bv.next_batch(mock_parent).await.unwrap_err(), - PipelineErrorKind::Reset(ResetError::L1OriginMismatch(_, _)) - )); - } - - #[tokio::test] - async fn test_batch_validator_received_span_batch() { - let cfg = Arc::new(RollupConfig::default()); - let mut mock = TestNextBatchProvider::new(vec![Ok(Batch::Span(SpanBatch::default()))]); - mock.origin = Some(BlockInfo { number: 1, ..Default::default() }); - let mut bv = BatchValidator::new(cfg, mock); - bv.origin = Some(BlockInfo::default()); - bv.l1_blocks.push(BlockInfo::default()); - - let mock_parent = L2BlockInfo { - l1_origin: BlockNumHash { number: 0, ..Default::default() }, - ..Default::default() - }; - - assert_eq!( - bv.next_batch(mock_parent).await.unwrap_err(), - PipelineError::InvalidBatchType.crit() - ); - assert_eq!(bv.next_batch(mock_parent).await.unwrap_err(), PipelineError::Eof.temp()); - } - - #[tokio::test] - async fn test_batch_validator_next_batch_valid() { - let cfg = Arc::new(RollupConfig { - holocene_time: Some(0), - block_time: 2, - max_sequencer_drift: 700, - ..Default::default() - }); - assert!(cfg.is_holocene_active(0)); - let batch = SingleBatch { - parent_hash: B256::default(), - epoch_num: 2, - epoch_hash: B256::default(), - timestamp: 4, - transactions: Vec::new(), - }; - let parent = L2BlockInfo { - l1_origin: BlockNumHash { number: 0, ..Default::default() }, - block_info: BlockInfo { timestamp: 2, ..Default::default() }, - ..Default::default() - }; - - // Setup batch validator deps - let batch_vec = vec![PipelineResult::Ok(Batch::Single(batch.clone()))]; - let mut mock = TestNextBatchProvider::new(batch_vec); - mock.origin = Some(BlockInfo { number: 1, ..Default::default() }); - - // Configure batch validator - let mut bv = BatchValidator::new(cfg, mock); - - // Reset the pipeline to add the L1 origin to the stage. - bv.signal(Signal::Reset(ResetSignal { - l1_origin: BlockInfo { number: 1, ..Default::default() }, - ..Default::default() - })) - .await - .unwrap(); - bv.l1_blocks.push(BlockInfo { number: 1, ..Default::default() }); - - // Grab the next batch. - let produced_batch = bv.next_batch(parent).await.unwrap(); - assert_eq!(batch, produced_batch); - } - - #[tokio::test] - async fn test_batch_validator_next_batch_sequence_window_expired() { - let trace_store: TraceStorage = Default::default(); - let layer = CollectingLayer::new(trace_store.clone()); - let subscriber = tracing_subscriber::Registry::default().with(layer); - let _guard = tracing::subscriber::set_default(subscriber); - - let cfg = Arc::new(RollupConfig { seq_window_size: 5, ..Default::default() }); - let mut mock = TestNextBatchProvider::new(vec![]); - mock.origin = Some(BlockInfo { number: 1, ..Default::default() }); - let mut bv = BatchValidator::new(cfg, mock); - - // Reset the pipeline to add the L1 origin to the stage. - bv.signal(Signal::Reset(ResetSignal { - l1_origin: BlockInfo { number: 1, ..Default::default() }, - ..Default::default() - })) - .await - .unwrap(); - - // Advance the origin of the previous stage to block #6. - for _ in 0..6 { - bv.advance_origin().await.unwrap(); - } - - // The sequence window is expired, so we should generate an empty batch. - let mock_parent = L2BlockInfo { - l1_origin: BlockNumHash { number: 0, ..Default::default() }, - ..Default::default() - }; - assert!(bv.next_batch(mock_parent).await.unwrap().transactions.is_empty()); - - let trace_lock = trace_store.lock(); - assert_eq!(trace_lock.iter().filter(|(l, _)| matches!(l, &Level::DEBUG)).count(), 1); - assert_eq!(trace_lock.iter().filter(|(l, _)| matches!(l, &Level::INFO)).count(), 1); - assert!(trace_lock[0].1.contains("Advancing batch validator origin")); - assert!(trace_lock[1].1.contains("Generating empty batch for epoch")); - } - - #[tokio::test] - async fn test_batch_validator_next_batch_sequence_window_expired_advance_epoch() { - let trace_store: TraceStorage = Default::default(); - let layer = CollectingLayer::new(trace_store.clone()); - let subscriber = tracing_subscriber::Registry::default().with(layer); - let _guard = tracing::subscriber::set_default(subscriber); - - let cfg = Arc::new(RollupConfig { seq_window_size: 5, ..Default::default() }); - let mut mock = TestNextBatchProvider::new(vec![]); - mock.origin = Some(BlockInfo { number: 1, ..Default::default() }); - let mut bv = BatchValidator::new(cfg, mock); - - // Reset the pipeline to add the L1 origin to the stage. - bv.signal(Signal::Reset(ResetSignal { - l1_origin: BlockInfo { number: 1, ..Default::default() }, - ..Default::default() - })) - .await - .unwrap(); - - // Advance the origin of the previous stage to block #6. - for _ in 0..6 { - bv.advance_origin().await.unwrap(); - } - - // The sequence window is expired, so we should generate an empty batch. - let mock_parent = L2BlockInfo { - l1_origin: BlockNumHash { number: 1, ..Default::default() }, - ..Default::default() - }; - assert_eq!(bv.next_batch(mock_parent).await.unwrap_err(), PipelineError::Eof.temp()); - - let trace_lock = trace_store.lock(); - assert_eq!(trace_lock.iter().filter(|(l, _)| matches!(l, &Level::DEBUG)).count(), 2); - assert!(trace_lock[0].1.contains("Advancing batch validator origin")); - assert!(trace_lock[1].1.contains("Advancing batch validator epoch")); - } -} diff --git a/crates/derive/src/stages/batch/mod.rs b/crates/derive/src/stages/batch/mod.rs index 6f0bac4f24..4406782918 100644 --- a/crates/derive/src/stages/batch/mod.rs +++ b/crates/derive/src/stages/batch/mod.rs @@ -22,9 +22,6 @@ pub use batch_stream::{BatchStream, BatchStreamProvider}; mod batch_queue; pub use batch_queue::BatchQueue; -mod batch_validator; -pub use batch_validator::BatchValidator; - mod batch_provider; pub use batch_provider::BatchProvider; @@ -38,18 +35,7 @@ pub trait NextBatchProvider { /// /// [ChannelReader]: crate::stages::ChannelReader /// [PipelineError::Eof]: crate::errors::PipelineError::Eof - async fn next_batch( - &mut self, - parent: L2BlockInfo, - l1_origins: &[BlockInfo], - ) -> PipelineResult; - - /// Returns the number of [SingleBatch]es that are currently buffered in the [BatchStream] - /// from a [SpanBatch]. - /// - /// [SpanBatch]: op_alloy_protocol::SpanBatch - /// [SingleBatch]: op_alloy_protocol::SingleBatch - fn span_buffer_size(&self) -> usize; + async fn next_batch(&mut self) -> PipelineResult; /// Allows the stage to flush the buffer in the [crate::stages::BatchStream] /// if an invalid single batch is found. Pre-holocene hardfork, this will be a no-op. diff --git a/crates/derive/src/stages/channel/channel_assembler.rs b/crates/derive/src/stages/channel/channel_assembler.rs index bb736083db..9412d68ff4 100644 --- a/crates/derive/src/stages/channel/channel_assembler.rs +++ b/crates/derive/src/stages/channel/channel_assembler.rs @@ -10,9 +10,7 @@ use alloc::{boxed::Box, sync::Arc}; use alloy_primitives::{hex, Bytes}; use async_trait::async_trait; use core::fmt::Debug; -use op_alloy_genesis::{ - RollupConfig, MAX_RLP_BYTES_PER_CHANNEL_BEDROCK, MAX_RLP_BYTES_PER_CHANNEL_FJORD, -}; +use op_alloy_genesis::{RollupConfig, MAX_RLP_BYTES_PER_CHANNEL_BEDROCK}; use op_alloy_protocol::{BlockInfo, Channel}; /// The [ChannelAssembler] stage is responsible for assembling the [Frame]s from the [FrameQueue] @@ -114,11 +112,7 @@ where return Err(PipelineError::NotEnoughData.temp()); } - let max_rlp_bytes_per_channel = if self.cfg.is_fjord_active(origin.timestamp) { - MAX_RLP_BYTES_PER_CHANNEL_FJORD - } else { - MAX_RLP_BYTES_PER_CHANNEL_BEDROCK - }; + let max_rlp_bytes_per_channel = MAX_RLP_BYTES_PER_CHANNEL_BEDROCK; if channel.size() > max_rlp_bytes_per_channel as usize { warn!( target: "channel-assembler", @@ -191,9 +185,7 @@ mod test { test_utils::{CollectingLayer, TestNextFrameProvider, TraceStorage}, }; use alloc::{sync::Arc, vec}; - use op_alloy_genesis::{ - RollupConfig, MAX_RLP_BYTES_PER_CHANNEL_BEDROCK, MAX_RLP_BYTES_PER_CHANNEL_FJORD, - }; + use op_alloy_genesis::{RollupConfig, MAX_RLP_BYTES_PER_CHANNEL_BEDROCK}; use op_alloy_protocol::BlockInfo; use tracing::Level; use tracing_subscriber::layer::SubscriberExt; @@ -346,9 +338,8 @@ mod test { crate::frame!(0xFF, 0, vec![0xDD; 50], false), crate::frame!(0xFF, 1, vec![0xDD; 50], true), ]; - frames[1].data = vec![0; MAX_RLP_BYTES_PER_CHANNEL_FJORD as usize]; let mock = TestNextFrameProvider::new(frames.into_iter().rev().map(Ok).collect()); - let cfg = Arc::new(RollupConfig { fjord_time: Some(0), ..Default::default() }); + let cfg = Arc::new(RollupConfig { ..Default::default() }); let mut assembler = ChannelAssembler::new(cfg, mock); diff --git a/crates/derive/src/stages/channel/channel_bank.rs b/crates/derive/src/stages/channel/channel_bank.rs index 0e63618992..6990bd16d2 100644 --- a/crates/derive/src/stages/channel/channel_bank.rs +++ b/crates/derive/src/stages/channel/channel_bank.rs @@ -13,6 +13,7 @@ use async_trait::async_trait; use core::fmt::Debug; use op_alloy_genesis::RollupConfig; use op_alloy_protocol::{BlockInfo, Channel, ChannelId, Frame}; +use tracing::{info, trace, warn}; /// The maximum size of a channel bank. pub(crate) const MAX_CHANNEL_BANK_SIZE: usize = 100_000_000; @@ -65,11 +66,8 @@ where pub fn prune(&mut self) -> PipelineResult<()> { let mut total_size = self.size(); let origin = self.origin().ok_or(PipelineError::MissingOrigin.crit())?; - let max_channel_bank_size = if self.cfg.is_fjord_active(origin.timestamp) { - FJORD_MAX_CHANNEL_BANK_SIZE - } else { - MAX_CHANNEL_BANK_SIZE - }; + let max_channel_bank_size = MAX_CHANNEL_BANK_SIZE; + while total_size > max_channel_bank_size { let id = self.channel_queue.pop_front().ok_or(PipelineError::ChannelProviderEmpty.crit())?; @@ -95,8 +93,8 @@ where }; // Check if the channel is not timed out. If it has, ignore the frame. - if current_channel.open_block_number() + self.cfg.channel_timeout(origin.timestamp) < - origin.number + if current_channel.open_block_number() + self.cfg.channel_timeout(origin.timestamp) + < origin.number { warn!( target: "channel-bank", @@ -148,13 +146,8 @@ where // If no channel is available, we return `PipelineError::Eof`. // Canyon is activated when the first L1 block whose time >= CanyonTime, not on the L2 // timestamp. - if !self.cfg.is_canyon_active(origin.timestamp) { - return self.try_read_channel_at_index(0).map(Some); - } - let channel_data = - (0..self.channel_queue.len()).find_map(|i| self.try_read_channel_at_index(i).ok()); - channel_data.map_or_else(|| Err(PipelineError::Eof.temp()), |data| Ok(Some(data))) + self.try_read_channel_at_index(0).map(Some) } /// Attempts to read the channel at the specified index. If the channel is not ready or timed @@ -166,8 +159,8 @@ where self.channels.get(&channel_id).ok_or(PipelineError::ChannelProviderEmpty.crit())?; let origin = self.origin().ok_or(PipelineError::MissingOrigin.crit())?; - let timed_out = channel.open_block_number() + self.cfg.channel_timeout(origin.timestamp) < - origin.number; + let timed_out = channel.open_block_number() + self.cfg.channel_timeout(origin.timestamp) + < origin.number; if timed_out || !channel.is_ready() { return Err(PipelineError::Eof.temp()); } @@ -248,6 +241,7 @@ mod tests { types::ResetSignal, }; use alloc::{vec, vec::Vec}; + use op_alloy_genesis::MANTLE_MAINNET_CONFIG; use tracing::Level; use tracing_subscriber::layer::SubscriberExt; @@ -358,7 +352,7 @@ mod tests { #[test] fn test_read_channel_active() { let mock = TestNextFrameProvider::new(vec![]); - let cfg = Arc::new(RollupConfig { canyon_time: Some(0), ..Default::default() }); + let cfg = Arc::new(RollupConfig { ..Default::default() }); let mut channel_bank = ChannelBank::new(cfg, mock); let id: ChannelId = [0xFF; 16]; channel_bank.channel_queue.push_back(id); @@ -467,7 +461,7 @@ mod tests { fn test_ingest_and_prune_channel_bank_fjord() { let mut frames = crate::frames!(0xFF, 0, vec![0xDD; 50], 100000); let mock = TestNextFrameProvider::new(vec![]); - let cfg = Arc::new(RollupConfig { fjord_time: Some(0), ..Default::default() }); + let cfg = Arc::new(RollupConfig { ..Default::default() }); let mut channel_bank = ChannelBank::new(cfg, mock); // Ingest frames until the channel bank is full and it stops increasing in size let mut current_size = 0; @@ -507,12 +501,9 @@ mod tests { let subscriber = tracing_subscriber::Registry::default().with(layer); let _guard = tracing::subscriber::set_default(subscriber); - let configs: [RollupConfig; 2] = [ - op_alloy_registry::ROLLUP_CONFIGS.get(&10).cloned().unwrap(), - op_alloy_registry::ROLLUP_CONFIGS.get(&8453).cloned().unwrap(), - ]; + const ROLLUP_CONFIGS: [RollupConfig; 1] = [MANTLE_MAINNET_CONFIG]; - for cfg in configs { + for cfg in ROLLUP_CONFIGS { let frames = [ crate::frame!(0xFF, 0, vec![0xDD; 50], false), crate::frame!(0xFF, 1, vec![0xDD; 50], true), diff --git a/crates/derive/src/stages/channel/channel_provider.rs b/crates/derive/src/stages/channel/channel_provider.rs index 093e5dcd22..94dcbe6166 100644 --- a/crates/derive/src/stages/channel/channel_provider.rs +++ b/crates/derive/src/stages/channel/channel_provider.rs @@ -12,6 +12,7 @@ use async_trait::async_trait; use core::fmt::Debug; use op_alloy_genesis::RollupConfig; use op_alloy_protocol::BlockInfo; +use tracing::info; /// The [ChannelProvider] stage is a mux between the [ChannelBank] and [ChannelAssembler] stages. /// @@ -57,25 +58,7 @@ where if let Some(prev) = self.prev.take() { // On the first call to `attempt_update`, we need to determine the active stage to // initialize the mux with. - if self.cfg.is_holocene_active(origin.timestamp) { - self.channel_assembler = Some(ChannelAssembler::new(self.cfg.clone(), prev)); - } else { - self.channel_bank = Some(ChannelBank::new(self.cfg.clone(), prev)); - } - } else if self.channel_bank.is_some() && self.cfg.is_holocene_active(origin.timestamp) { - // If the channel bank is active and Holocene is also active, transition to the channel - // assembler. - let channel_bank = self.channel_bank.take().expect("Must have channel bank"); - self.channel_assembler = - Some(ChannelAssembler::new(self.cfg.clone(), channel_bank.prev)); - } else if self.channel_assembler.is_some() && !self.cfg.is_holocene_active(origin.timestamp) - { - // If the channel assembler is active, and Holocene is not active, it indicates an L1 - // reorg around Holocene activation. Transition back to the channel bank - // until Holocene re-activates. - let channel_assembler = - self.channel_assembler.take().expect("Must have channel assembler"); - self.channel_bank = Some(ChannelBank::new(self.cfg.clone(), channel_assembler.prev)); + self.channel_bank = Some(ChannelBank::new(self.cfg.clone(), prev)); } Ok(()) } @@ -169,7 +152,7 @@ mod test { #[test] fn test_channel_provider_assembler_active() { let provider = TestNextFrameProvider::new(vec![]); - let cfg = Arc::new(RollupConfig { holocene_time: Some(0), ..Default::default() }); + let cfg = Arc::new(RollupConfig { ..Default::default() }); let mut channel_provider = ChannelProvider::new(cfg, provider); assert!(channel_provider.attempt_update().is_ok()); @@ -216,7 +199,7 @@ mod test { #[test] fn test_channel_provider_retain_current_assembler() { let provider = TestNextFrameProvider::new(vec![]); - let cfg = Arc::new(RollupConfig { holocene_time: Some(0), ..Default::default() }); + let cfg = Arc::new(RollupConfig { ..Default::default() }); let mut channel_provider = ChannelProvider::new(cfg, provider); // Assert the multiplexer hasn't been initialized. @@ -239,7 +222,7 @@ mod test { #[test] fn test_channel_provider_transition_stage() { let provider = TestNextFrameProvider::new(vec![]); - let cfg = Arc::new(RollupConfig { holocene_time: Some(2), ..Default::default() }); + let cfg = Arc::new(RollupConfig { ..Default::default() }); let mut channel_provider = ChannelProvider::new(cfg, provider); channel_provider.attempt_update().unwrap(); @@ -261,7 +244,7 @@ mod test { #[test] fn test_channel_provider_transition_stage_backwards() { let provider = TestNextFrameProvider::new(vec![]); - let cfg = Arc::new(RollupConfig { holocene_time: Some(2), ..Default::default() }); + let cfg = Arc::new(RollupConfig { ..Default::default() }); let mut channel_provider = ChannelProvider::new(cfg, provider); channel_provider.attempt_update().unwrap(); @@ -326,7 +309,7 @@ mod test { crate::frame!(0xFF, 1, vec![0xDD; 50], true), ]; let provider = TestNextFrameProvider::new(frames.into_iter().rev().map(Ok).collect()); - let cfg = Arc::new(RollupConfig { holocene_time: Some(0), ..Default::default() }); + let cfg = Arc::new(RollupConfig { ..Default::default() }); let mut channel_provider = ChannelProvider::new(cfg.clone(), provider); // Load in the first frame. diff --git a/crates/derive/src/stages/channel/channel_reader.rs b/crates/derive/src/stages/channel/channel_reader.rs index 43e24729fc..05163ed239 100644 --- a/crates/derive/src/stages/channel/channel_reader.rs +++ b/crates/derive/src/stages/channel/channel_reader.rs @@ -6,15 +6,24 @@ use crate::{ traits::{OriginAdvancer, OriginProvider, SignalReceiver}, types::{PipelineResult, Signal}, }; -use alloc::{boxed::Box, sync::Arc}; +use alloc::{boxed::Box, sync::Arc, vec::Vec}; use alloy_primitives::Bytes; +use alloy_rlp::Decodable; use async_trait::async_trait; use core::fmt::Debug; -use op_alloy_genesis::{ - RollupConfig, MAX_RLP_BYTES_PER_CHANNEL_BEDROCK, MAX_RLP_BYTES_PER_CHANNEL_FJORD, -}; -use op_alloy_protocol::{Batch, BatchReader, BlockInfo}; -use tracing::{debug, warn}; +use miniz_oxide::inflate::decompress_to_vec_zlib; +use op_alloy_genesis::{RollupConfig, MAX_RLP_BYTES_PER_CHANNEL_BEDROCK}; +use op_alloy_protocol::{Batch, BlockInfo}; +use tracing::{debug, error, info, warn}; + +/// ZLIB Deflate Compression Method. +pub(crate) const ZLIB_DEFLATE_COMPRESSION_METHOD: u8 = 8; + +/// ZLIB Reserved Compression Info. +pub(crate) const ZLIB_RESERVED_COMPRESSION_METHOD: u8 = 15; + +/// Brotili Compression Channel Version. +pub(crate) const CHANNEL_VERSION_BROTLI: u8 = 1; /// The [ChannelReader] provider trait. #[async_trait] @@ -63,12 +72,7 @@ where let channel = self.prev.next_data().await?.ok_or(PipelineError::ChannelReaderEmpty.temp())?; - let origin = self.prev.origin().ok_or(PipelineError::MissingOrigin.crit())?; - let max_rlp_bytes_per_channel = if self.cfg.is_fjord_active(origin.timestamp) { - MAX_RLP_BYTES_PER_CHANNEL_FJORD - } else { - MAX_RLP_BYTES_PER_CHANNEL_BEDROCK - }; + let max_rlp_bytes_per_channel = MAX_RLP_BYTES_PER_CHANNEL_BEDROCK; self.next_batch = Some(BatchReader::new(&channel[..], max_rlp_bytes_per_channel as usize)); @@ -161,6 +165,80 @@ where } } +/// Batch Reader provides a function that iteratively consumes batches from the reader. +/// The L1Inclusion block is also provided at creation time. +/// Warning: the batch reader can read every batch-type. +/// The caller of the batch-reader should filter the results. +#[derive(Debug)] +pub(crate) struct BatchReader { + /// The raw data to decode. + data: Option>, + /// Decompressed data. + decompressed: Vec, + /// The current cursor in the `decompressed` data. + cursor: usize, + /// The maximum RLP bytes per channel. + max_rlp_bytes_per_channel: usize, +} + +impl BatchReader { + /// Creates a new [BatchReader] from the given data and max decompressed RLP bytes per channel. + pub(crate) fn new(data: T, max_rlp_bytes_per_channel: usize) -> Self + where + T: Into>, + { + Self { + data: Some(data.into()), + decompressed: Vec::new(), + cursor: 0, + max_rlp_bytes_per_channel, + } + } + + /// Pulls out the next batch from the reader. + pub(crate) fn next_batch(&mut self, cfg: &RollupConfig) -> Option { + if let Some(data) = self.data.take() { + // Peek at the data to determine the compression type. + if data.is_empty() { + warn!(target: "batch-reader", "Data is too short to determine compression type, skipping batch"); + return None; + } + + self.decompressed = decompress_to_vec_zlib(&data).ok()?; + + // Check the size of the decompressed channel RLP. + if self.decompressed.len() > self.max_rlp_bytes_per_channel { + return None; + } + } + + // Decompress and RLP decode the batch data, before finally decoding the batch itself. + let decompressed_reader = &mut self.decompressed.as_slice()[self.cursor..].as_ref(); + let bytes = Bytes::decode(decompressed_reader).ok()?; + let result = Batch::decode(&mut bytes.as_ref(), cfg); + match result { + Ok(batch) => { + // Advance the cursor on the reader. + self.cursor = self.decompressed.len() - decompressed_reader.len(); + Some(batch) + } + Err(e) => { + error!(target: "batch-reader", "Failed to decode batch, skipping batch, error: {:?}",e); + None + } + } + + // let Ok(batch) = Batch::decode(&mut bytes.as_ref(), cfg) else { + // error!(target: "batch-reader", "Failed to decode batch, skipping batch"); + // return None; + // }; + // + // // Advance the cursor on the reader. + // self.cursor = self.decompressed.len() - decompressed_reader.len(); + // Some(batch) + } +} + #[cfg(test)] mod test { use super::*; @@ -168,6 +246,7 @@ mod test { errors::PipelineErrorKind, test_utils::TestChannelReaderProvider, types::ResetSignal, }; use alloc::vec; + use op_alloy_protocol::MAX_RLP_BYTES_PER_CHANNEL; fn new_compressed_batch_data() -> Bytes { let file_contents = @@ -181,10 +260,8 @@ mod test { async fn test_flush_channel_reader() { let mock = TestChannelReaderProvider::new(vec![Ok(Some(new_compressed_batch_data()))]); let mut reader = ChannelReader::new(mock, Arc::new(RollupConfig::default())); - reader.next_batch = Some(BatchReader::new( - new_compressed_batch_data(), - MAX_RLP_BYTES_PER_CHANNEL_FJORD as usize, - )); + reader.next_batch = + Some(BatchReader::new(new_compressed_batch_data(), MAX_RLP_BYTES_PER_CHANNEL as usize)); reader.signal(Signal::FlushChannel).await.unwrap(); assert!(reader.next_batch.is_none()); } @@ -193,10 +270,8 @@ mod test { async fn test_reset_channel_reader() { let mock = TestChannelReaderProvider::new(vec![Ok(None)]); let mut reader = ChannelReader::new(mock, Arc::new(RollupConfig::default())); - reader.next_batch = Some(BatchReader::new( - vec![0x00, 0x01, 0x02], - MAX_RLP_BYTES_PER_CHANNEL_FJORD as usize, - )); + reader.next_batch = + Some(BatchReader::new(vec![0x00, 0x01, 0x02], MAX_RLP_BYTES_PER_CHANNEL as usize)); assert!(!reader.prev.reset); reader.signal(ResetSignal::default().signal()).await.unwrap(); assert!(reader.next_batch.is_none()); @@ -238,20 +313,35 @@ mod test { let mock = TestChannelReaderProvider::new(vec![Ok(Some(raw))]); let mut reader = ChannelReader::new(mock, Arc::new(RollupConfig::default())); let res = reader.next_batch().await.unwrap(); - matches!(res, Batch::Span(_)); assert!(reader.next_batch.is_some()); } + #[test] + fn test_batch_reader() { + let raw = new_compressed_batch_data(); + let decompressed_len = decompress_to_vec_zlib(&raw).unwrap().len(); + let mut reader = BatchReader::new(raw, MAX_RLP_BYTES_PER_CHANNEL_BEDROCK as usize); + reader.next_batch(&RollupConfig::default()).unwrap(); + assert_eq!(reader.cursor, decompressed_len); + } + + #[test] + fn test_batch_reader_fjord() { + let raw = new_compressed_batch_data(); + let decompressed_len = decompress_to_vec_zlib(&raw).unwrap().len(); + let mut reader = BatchReader::new(raw, MAX_RLP_BYTES_PER_CHANNEL as usize); + reader.next_batch(&RollupConfig { ..Default::default() }).unwrap(); + assert_eq!(reader.cursor, decompressed_len); + } + #[tokio::test] async fn test_flush_post_holocene() { let raw = new_compressed_batch_data(); - let config = Arc::new(RollupConfig { holocene_time: Some(0), ..RollupConfig::default() }); + let config = Arc::new(RollupConfig { ..RollupConfig::default() }); let mock = TestChannelReaderProvider::new(vec![Ok(Some(raw))]); let mut reader = ChannelReader::new(mock, config); let res = reader.next_batch().await.unwrap(); - matches!(res, Batch::Span(_)); assert!(reader.next_batch.is_some()); - reader.flush(); assert!(reader.next_batch.is_none()); } } diff --git a/crates/derive/src/stages/frame_queue.rs b/crates/derive/src/stages/frame_queue.rs index ca8328ff45..8e7bd4a096 100644 --- a/crates/derive/src/stages/frame_queue.rs +++ b/crates/derive/src/stages/frame_queue.rs @@ -53,60 +53,6 @@ where Self { prev, queue: VecDeque::new(), rollup_config: cfg } } - /// Returns if holocene is active. - pub fn is_holocene_active(&self, origin: BlockInfo) -> bool { - self.rollup_config.is_holocene_active(origin.timestamp) - } - - /// Prunes frames if Holocene is active. - pub fn prune(&mut self, origin: BlockInfo) { - if !self.is_holocene_active(origin) { - return; - } - - let mut i = 0; - while i < self.queue.len() - 1 { - let prev_frame = &self.queue[i]; - let next_frame = &self.queue[i + 1]; - let extends_channel = prev_frame.id == next_frame.id; - - // If the frames are in the same channel, and the frame numbers are not sequential, - // drop the next frame. - if extends_channel && prev_frame.number + 1 != next_frame.number { - self.queue.remove(i + 1); - continue; - } - - // If the frames are in the same channel, and the previous is last, drop the next frame. - if extends_channel && prev_frame.is_last { - self.queue.remove(i + 1); - continue; - } - - // If the frames are in different channels, the next frame must be first. - if !extends_channel && next_frame.number != 0 { - self.queue.remove(i + 1); - continue; - } - - // If the frames are in different channels, and the current channel is not last, walk - // back the channel and drop all prev frames. - if !extends_channel && !prev_frame.is_last && next_frame.number == 0 { - // Find the index of the first frame in the queue with the same channel ID - // as the previous frame. - let first_frame = - self.queue.iter().position(|f| f.id == prev_frame.id).expect("infallible"); - - // Drain all frames from the previous channel. - let drained = self.queue.drain(first_frame..=i); - i = i.saturating_sub(drained.len()); - continue; - } - - i += 1; - } - } - /// Loads more frames into the [FrameQueue]. pub async fn load_frames(&mut self) -> PipelineResult<()> { // Skip loading frames if the queue is not empty. @@ -133,10 +79,6 @@ where // Optimistically extend the queue with the new frames. self.queue.extend(frames); - // Prune frames if Holocene is active. - let origin = self.origin().ok_or(PipelineError::MissingOrigin.crit())?; - self.prune(origin); - Ok(()) } } @@ -212,7 +154,6 @@ pub(crate) mod tests { let mut mock = TestFrameQueueProvider::new(data); mock.set_origin(BlockInfo::default()); let mut frame_queue = FrameQueue::new(mock, Default::default()); - assert!(!frame_queue.is_holocene_active(BlockInfo::default())); let err = frame_queue.next_frame().await.unwrap_err(); assert_eq!(err, PipelineError::NotEnoughData.temp()); } @@ -223,7 +164,6 @@ pub(crate) mod tests { let mut mock = TestFrameQueueProvider::new(data); mock.set_origin(BlockInfo::default()); let mut frame_queue = FrameQueue::new(mock, Default::default()); - assert!(!frame_queue.is_holocene_active(BlockInfo::default())); let err = frame_queue.next_frame().await.unwrap_err(); assert_eq!(err, PipelineError::NotEnoughData.temp()); } @@ -235,7 +175,6 @@ pub(crate) mod tests { .with_raw_frames(Bytes::from(vec![0x01])) .with_expected_err(PipelineError::NotEnoughData.temp()) .build(); - assert.holocene_active(false); assert.next_frames().await; } @@ -246,7 +185,6 @@ pub(crate) mod tests { .with_raw_frames(Bytes::from(vec![0x00, 0x01])) .with_expected_err(PipelineError::NotEnoughData.temp()) .build(); - assert.holocene_active(false); assert.next_frames().await; } @@ -258,7 +196,7 @@ pub(crate) mod tests { .with_origin(BlockInfo::default()) .with_frames(&frames) .build(); - assert.holocene_active(false); + assert.next_frames().await; } @@ -274,7 +212,7 @@ pub(crate) mod tests { .with_origin(BlockInfo::default()) .with_frames(&frames) .build(); - assert.holocene_active(false); + assert.next_frames().await; } @@ -285,7 +223,7 @@ pub(crate) mod tests { .with_expected_frames(&frames) .with_frames(&frames) .build(); - assert.holocene_active(false); + assert.missing_origin().await; } @@ -297,12 +235,12 @@ pub(crate) mod tests { crate::frame!(0xFF, 2, vec![0xDD; 50], true), ]; let assert = crate::test_utils::FrameQueueBuilder::new() - .with_rollup_config(&RollupConfig { holocene_time: Some(0), ..Default::default() }) + .with_rollup_config(&RollupConfig { ..Default::default() }) .with_origin(BlockInfo::default()) .with_expected_frames(&frames) .with_frames(&frames) .build(); - assert.holocene_active(true); + assert.next_frames().await; } @@ -310,12 +248,12 @@ pub(crate) mod tests { async fn test_holocene_single_frame() { let frames = [crate::frame!(0xFF, 1, vec![0xDD; 50], true)]; let assert = crate::test_utils::FrameQueueBuilder::new() - .with_rollup_config(&RollupConfig { holocene_time: Some(0), ..Default::default() }) + .with_rollup_config(&RollupConfig { ..Default::default() }) .with_origin(BlockInfo::default()) .with_expected_frames(&frames) .with_frames(&frames) .build(); - assert.holocene_active(true); + assert.next_frames().await; } @@ -332,12 +270,12 @@ pub(crate) mod tests { crate::frame!(0xFF, 1, vec![0xDD; 50], true), ]; let assert = crate::test_utils::FrameQueueBuilder::new() - .with_rollup_config(&RollupConfig { holocene_time: Some(0), ..Default::default() }) + .with_rollup_config(&RollupConfig { ..Default::default() }) .with_origin(BlockInfo::default()) .with_expected_frames(&[&frames[0..3], &frames[4..]].concat()) .with_frames(&frames) .build(); - assert.holocene_active(true); + assert.next_frames().await; } @@ -351,12 +289,12 @@ pub(crate) mod tests { crate::frame!(0xEE, 4, vec![0xDD; 50], false), // Dropped ]; let assert = crate::test_utils::FrameQueueBuilder::new() - .with_rollup_config(&RollupConfig { holocene_time: Some(0), ..Default::default() }) + .with_rollup_config(&RollupConfig { ..Default::default() }) .with_origin(BlockInfo::default()) .with_expected_frames(&frames[0..2]) .with_frames(&frames) .build(); - assert.holocene_active(true); + assert.next_frames().await; } @@ -373,12 +311,12 @@ pub(crate) mod tests { crate::frame!(0xFF, 1, vec![0xDD; 50], true), ]; let assert = crate::test_utils::FrameQueueBuilder::new() - .with_rollup_config(&RollupConfig { holocene_time: Some(0), ..Default::default() }) + .with_rollup_config(&RollupConfig { ..Default::default() }) .with_origin(BlockInfo::default()) .with_expected_frames(&frames[4..]) .with_frames(&frames) .build(); - assert.holocene_active(true); + assert.next_frames().await; } @@ -398,12 +336,12 @@ pub(crate) mod tests { crate::frame!(0xFF, 1, vec![0xDD; 50], true), ]; let assert = crate::test_utils::FrameQueueBuilder::new() - .with_rollup_config(&RollupConfig { holocene_time: Some(0), ..Default::default() }) + .with_rollup_config(&RollupConfig { ..Default::default() }) .with_origin(BlockInfo::default()) .with_expected_frames(&[&frames[0..4], &frames[6..]].concat()) .with_frames(&frames) .build(); - assert.holocene_active(true); + assert.next_frames().await; } @@ -420,12 +358,12 @@ pub(crate) mod tests { crate::frame!(0xFF, 2, vec![0xDD; 50], true), // Dropped ]; let assert = crate::test_utils::FrameQueueBuilder::new() - .with_rollup_config(&RollupConfig { holocene_time: Some(0), ..Default::default() }) + .with_rollup_config(&RollupConfig { ..Default::default() }) .with_origin(BlockInfo::default()) .with_expected_frames(&frames[0..4]) .with_frames(&frames) .build(); - assert.holocene_active(true); + assert.next_frames().await; } @@ -443,12 +381,12 @@ pub(crate) mod tests { crate::frame!(0xFF, 1, vec![0xDD; 50], true), ]; let assert = crate::test_utils::FrameQueueBuilder::new() - .with_rollup_config(&RollupConfig { holocene_time: Some(0), ..Default::default() }) + .with_rollup_config(&RollupConfig { ..Default::default() }) .with_origin(BlockInfo::default()) .with_expected_frames(&[&frames[0..2], &frames[4..]].concat()) .with_frames(&frames) .build(); - assert.holocene_active(true); + assert.next_frames().await; } @@ -466,12 +404,12 @@ pub(crate) mod tests { crate::frame!(0xFF, 1, vec![0xDD; 50], true), ]; let assert = crate::test_utils::FrameQueueBuilder::new() - .with_rollup_config(&RollupConfig { holocene_time: Some(0), ..Default::default() }) + .with_rollup_config(&RollupConfig { ..Default::default() }) .with_origin(BlockInfo::default()) .with_expected_frames(&frames[4..]) .with_frames(&frames) .build(); - assert.holocene_active(true); + assert.next_frames().await; } @@ -489,12 +427,12 @@ pub(crate) mod tests { crate::frame!(0xFF, 1, vec![0xDD; 50], true), ]; let assert = crate::test_utils::FrameQueueBuilder::new() - .with_rollup_config(&RollupConfig { holocene_time: Some(0), ..Default::default() }) + .with_rollup_config(&RollupConfig { ..Default::default() }) .with_origin(BlockInfo::default()) .with_expected_frames(&[&frames[1..2], &frames[3..]].concat()) .with_frames(&frames) .build(); - assert.holocene_active(true); + assert.next_frames().await; } } diff --git a/crates/derive/src/stages/l1_retrieval.rs b/crates/derive/src/stages/l1_retrieval.rs index 9e68c53958..2619c93752 100644 --- a/crates/derive/src/stages/l1_retrieval.rs +++ b/crates/derive/src/stages/l1_retrieval.rs @@ -124,8 +124,8 @@ where async fn signal(&mut self, signal: Signal) -> PipelineResult<()> { self.prev.signal(signal).await?; match signal { - Signal::Reset(ResetSignal { l1_origin, .. }) | - Signal::Activation(ActivationSignal { l1_origin, .. }) => { + Signal::Reset(ResetSignal { l1_origin, .. }) + | Signal::Activation(ActivationSignal { l1_origin, .. }) => { self.next = Some(l1_origin); } _ => {} diff --git a/crates/derive/src/stages/l1_traversal.rs b/crates/derive/src/stages/l1_traversal.rs index 82b62d4e26..0b82fd6012 100644 --- a/crates/derive/src/stages/l1_traversal.rs +++ b/crates/derive/src/stages/l1_traversal.rs @@ -89,27 +89,17 @@ impl OriginAdvancer for L1Traversal { let receipts = self.data_source.receipts_by_hash(next_l1_origin.hash).await.map_err(Into::into)?; - if let Err(e) = self.system_config.update_with_receipts( - receipts.as_slice(), - self.rollup_config.l1_system_config_address, - self.rollup_config.is_ecotone_active(next_l1_origin.timestamp), - ) { + if let Err(e) = self + .system_config + .update_with_receipts(receipts.as_slice(), self.rollup_config.l1_system_config_address) + { return Err(PipelineError::SystemConfigUpdate(e).crit()); } - let prev_block_holocene = self.rollup_config.is_holocene_active(block.timestamp); - let next_block_holocene = self.rollup_config.is_holocene_active(next_l1_origin.timestamp); - // Update the block origin regardless of if a holocene activation is required. self.block = Some(next_l1_origin); self.done = false; - // If the prev block is not holocene, but the next is, we need to flag this - // so the pipeline driver will reset the pipeline for holocene activation. - if !prev_block_holocene && next_block_holocene { - return Err(ResetError::HoloceneActivation.reset()); - } - Ok(()) } } @@ -124,8 +114,8 @@ impl OriginProvider for L1Traversal { impl SignalReceiver for L1Traversal { async fn signal(&mut self, signal: Signal) -> PipelineResult<()> { match signal { - Signal::Reset(ResetSignal { l1_origin, system_config, .. }) | - Signal::Activation(ActivationSignal { l1_origin, system_config, .. }) => { + Signal::Reset(ResetSignal { l1_origin, system_config, .. }) + | Signal::Activation(ActivationSignal { l1_origin, system_config, .. }) => { self.block = Some(l1_origin); self.done = false; self.system_config = system_config.expect("System config must be provided."); diff --git a/crates/derive/src/stages/mod.rs b/crates/derive/src/stages/mod.rs index f551b318c2..86df3585ec 100644 --- a/crates/derive/src/stages/mod.rs +++ b/crates/derive/src/stages/mod.rs @@ -31,9 +31,7 @@ pub use channel::{ }; mod batch; -pub use batch::{ - BatchProvider, BatchQueue, BatchStream, BatchStreamProvider, BatchValidator, NextBatchProvider, -}; +pub use batch::{BatchProvider, BatchQueue, BatchStream, BatchStreamProvider, NextBatchProvider}; mod attributes_queue; pub use attributes_queue::AttributesQueue; diff --git a/crates/derive/src/test_utils/attributes_queue.rs b/crates/derive/src/test_utils/attributes_queue.rs index 7aa3811352..3f5dfbca27 100644 --- a/crates/derive/src/test_utils/attributes_queue.rs +++ b/crates/derive/src/test_utils/attributes_queue.rs @@ -10,7 +10,8 @@ use crate::{ use alloc::{boxed::Box, string::ToString, vec::Vec}; use alloy_eips::BlockNumHash; use async_trait::async_trait; -use op_alloy_protocol::{BlockInfo, L2BlockInfo, SingleBatch}; +use op_alloy_protocol::SingleBatch; +use op_alloy_protocol::{BlockInfo, L2BlockInfo}; use op_alloy_rpc_types_engine::OpPayloadAttributes; use thiserror::Error; @@ -86,10 +87,6 @@ impl AttributesProvider for TestAttributesProvider { async fn next_batch(&mut self, _parent: L2BlockInfo) -> PipelineResult { self.batches.pop().ok_or(PipelineError::Eof.temp())? } - - fn is_last_in_span(&self) -> bool { - self.batches.is_empty() - } } /// Creates a new [`TestAttributesProvider`] with the given origin and batches. diff --git a/crates/derive/src/test_utils/batch_provider.rs b/crates/derive/src/test_utils/batch_provider.rs index 1ae1329af9..39118e5551 100644 --- a/crates/derive/src/test_utils/batch_provider.rs +++ b/crates/derive/src/test_utils/batch_provider.rs @@ -38,15 +38,7 @@ impl OriginProvider for TestNextBatchProvider { #[async_trait] impl NextBatchProvider for TestNextBatchProvider { - fn flush(&mut self) { - self.flushed = true; - } - - fn span_buffer_size(&self) -> usize { - self.batches.len() - } - - async fn next_batch(&mut self, _: L2BlockInfo, _: &[BlockInfo]) -> PipelineResult { + async fn next_batch(&mut self) -> PipelineResult { self.batches.pop().ok_or(PipelineError::Eof.temp())? } } diff --git a/crates/derive/src/test_utils/batch_stream.rs b/crates/derive/src/test_utils/batch_stream.rs index 7ec1daa947..3fc4fc751f 100644 --- a/crates/derive/src/test_utils/batch_stream.rs +++ b/crates/derive/src/test_utils/batch_stream.rs @@ -21,9 +21,9 @@ pub struct TestBatchStreamProvider { pub origin: Option, /// A list of batches to return. pub batches: Vec>, - /// Wether the reset method was called. + /// Whether the reset method was called. pub reset: bool, - /// Wether the provider was flushed. + /// Whether the provider was flushed. pub flushed: bool, } @@ -42,8 +42,6 @@ impl OriginProvider for TestBatchStreamProvider { #[async_trait] impl BatchStreamProvider for TestBatchStreamProvider { - fn flush(&mut self) {} - async fn next_batch(&mut self) -> PipelineResult { self.batches.pop().ok_or(PipelineError::Eof.temp())? } diff --git a/crates/derive/src/test_utils/eigen_da_provider.rs b/crates/derive/src/test_utils/eigen_da_provider.rs new file mode 100644 index 0000000000..1d3c2165f8 --- /dev/null +++ b/crates/derive/src/test_utils/eigen_da_provider.rs @@ -0,0 +1,35 @@ +use crate::errors::EigenDAProviderError; +use crate::traits::EigenDAProvider; +use alloc::boxed::Box; +use alloc::string::ToString; +use alloc::vec::Vec; +use async_trait::async_trait; + +/// A mock blob provider for testing. +#[derive(Debug, Clone, Default)] +pub struct TestEigenDaProvider { + /// blob data. + pub blob: Vec, + /// whether the blob provider should return an error. + pub should_error: bool, +} + +#[async_trait] +impl EigenDAProvider for TestEigenDaProvider { + type Error = EigenDAProviderError; + + async fn retrieve_blob_with_commitment( + &mut self, + commitment: &[u8], + blob_len: u32, + ) -> Result, Self::Error> { + if self.should_error { + return Err(EigenDAProviderError::Blob("error".to_string())); + } + Ok(self.blob.clone()) + } + + fn da_indexer_enable(&mut self) -> bool { + false + } +} diff --git a/crates/derive/src/test_utils/frame_queue.rs b/crates/derive/src/test_utils/frame_queue.rs index 6f13e9f681..246c069906 100644 --- a/crates/derive/src/test_utils/frame_queue.rs +++ b/crates/derive/src/test_utils/frame_queue.rs @@ -20,7 +20,7 @@ pub struct TestFrameQueueProvider { pub data: Vec>, /// The origin to return. pub origin: Option, - /// Wether the reset method was called. + /// Whether the reset method was called. pub reset: bool, } diff --git a/crates/derive/src/test_utils/frames.rs b/crates/derive/src/test_utils/frames.rs index 9c4a8eb0a3..b89f0e1569 100644 --- a/crates/derive/src/test_utils/frames.rs +++ b/crates/derive/src/test_utils/frames.rs @@ -106,16 +106,6 @@ impl FrameQueueAsserter { Self { inner, expected_frames, expected_err } } - /// Asserts that holocene is active. - pub fn holocene_active(&self, active: bool) { - let holocene = self.inner.is_holocene_active(self.inner.origin().unwrap_or_default()); - if !active { - assert!(!holocene); - } else { - assert!(holocene); - } - } - /// Asserts that the frame queue returns with a missing origin error. pub async fn missing_origin(mut self) { let err = self.inner.next_frame().await.unwrap_err(); diff --git a/crates/derive/src/test_utils/mod.rs b/crates/derive/src/test_utils/mod.rs index b0f28b5a93..ebe2e6c22f 100644 --- a/crates/derive/src/test_utils/mod.rs +++ b/crates/derive/src/test_utils/mod.rs @@ -10,6 +10,9 @@ pub use pipeline::{ mod blob_provider; pub use blob_provider::TestBlobProvider; +mod eigen_da_provider; +pub use eigen_da_provider::TestEigenDaProvider; + mod chain_providers; pub use chain_providers::{TestChainProvider, TestL2ChainProvider, TestProviderError}; diff --git a/crates/derive/src/test_utils/pipeline.rs b/crates/derive/src/test_utils/pipeline.rs index c55e176657..87f5924d83 100644 --- a/crates/derive/src/test_utils/pipeline.rs +++ b/crates/derive/src/test_utils/pipeline.rs @@ -79,10 +79,10 @@ pub type TestChannelProvider = ChannelProvider; pub type TestChannelReader = ChannelReader; /// A [BatchStream] using test providers and sources. -pub type TestBatchStream = BatchStream; +pub type TestBatchStream = BatchStream; /// A [BatchQueue] using test providers and sources. -pub type TestBatchProvider = BatchProvider; +pub type TestBatchProvider = BatchProvider; /// An [AttributesQueue] using test providers and sources. pub type TestAttributesQueue = AttributesQueue; diff --git a/crates/derive/src/traits/attributes.rs b/crates/derive/src/traits/attributes.rs index 42d0b3f23d..be1e601dd6 100644 --- a/crates/derive/src/traits/attributes.rs +++ b/crates/derive/src/traits/attributes.rs @@ -4,7 +4,8 @@ use crate::types::PipelineResult; use alloc::boxed::Box; use alloy_eips::BlockNumHash; use async_trait::async_trait; -use op_alloy_protocol::{L2BlockInfo, SingleBatch}; +use op_alloy_protocol::L2BlockInfo; +use op_alloy_protocol::SingleBatch; use op_alloy_rpc_types_engine::{OpAttributesWithParent, OpPayloadAttributes}; /// [AttributesProvider] is a trait abstraction that generalizes the [BatchQueue] stage. @@ -14,9 +15,6 @@ use op_alloy_rpc_types_engine::{OpAttributesWithParent, OpPayloadAttributes}; pub trait AttributesProvider { /// Returns the next valid batch upon the given safe head. async fn next_batch(&mut self, parent: L2BlockInfo) -> PipelineResult; - - /// Returns whether the current batch is the last in its span. - fn is_last_in_span(&self) -> bool; } /// [NextAttributes] defines the interface for pulling attributes from diff --git a/crates/derive/src/traits/data_sources.rs b/crates/derive/src/traits/data_sources.rs index 18e51bf99e..a9eb69994d 100644 --- a/crates/derive/src/traits/data_sources.rs +++ b/crates/derive/src/traits/data_sources.rs @@ -23,6 +23,23 @@ pub trait BlobProvider { ) -> Result>, Self::Error>; } +/// The EigenDA provider trait specifies the functionality of a data source that can provide EigenDA data +#[async_trait] +pub trait EigenDAProvider { + /// The error type for the [EigenDAProvider] + type Error: Display; + + /// Fetches EigenDA data for a given commitment + async fn retrieve_blob_with_commitment( + &mut self, + commitment: &[u8], + blob_len: u32, + ) -> Result, Self::Error>; + + /// Weather use mantle eigen-da indexer service + fn da_indexer_enable(&mut self) -> bool; +} + /// Describes the functionality of a data source that can provide data availability information. #[async_trait] pub trait DataAvailabilityProvider { diff --git a/crates/derive/src/traits/mod.rs b/crates/derive/src/traits/mod.rs index 91f24c10fd..bf12122977 100644 --- a/crates/derive/src/traits/mod.rs +++ b/crates/derive/src/traits/mod.rs @@ -11,7 +11,7 @@ mod attributes; pub use attributes::{AttributesBuilder, AttributesProvider, NextAttributes}; mod data_sources; -pub use data_sources::{BlobProvider, DataAvailabilityProvider}; +pub use data_sources::{BlobProvider, DataAvailabilityProvider, EigenDAProvider}; mod reset; pub use reset::ResetProvider; diff --git a/crates/driver/CHANGELOG.md b/crates/driver/CHANGELOG.md index 4da62fad12..d282a4b4e3 100644 --- a/crates/driver/CHANGELOG.md +++ b/crates/driver/CHANGELOG.md @@ -7,36 +7,36 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -## [0.2.0](https://github.com/anton-rs/kona/compare/kona-driver-v0.1.0...kona-driver-v0.2.0) - 2024-12-03 +## [0.2.0](https://github.com/op-rs/kona/compare/kona-driver-v0.1.0...kona-driver-v0.2.0) - 2024-12-03 ### Added -- *(driver)* wait for engine ([#851](https://github.com/anton-rs/kona/pull/851)) -- *(driver)* refines the executor interface for the driver ([#850](https://github.com/anton-rs/kona/pull/850)) +- *(driver)* wait for engine ([#851](https://github.com/op-rs/kona/pull/851)) +- *(driver)* refines the executor interface for the driver ([#850](https://github.com/op-rs/kona/pull/850)) ### Fixed -- bump ([#865](https://github.com/anton-rs/kona/pull/865)) +- bump ([#865](https://github.com/op-rs/kona/pull/865)) ### Other -- *(driver)* advance with optional target ([#848](https://github.com/anton-rs/kona/pull/848)) -- *(driver)* visibility ([#834](https://github.com/anton-rs/kona/pull/834)) +- *(driver)* advance with optional target ([#848](https://github.com/op-rs/kona/pull/848)) +- *(driver)* visibility ([#834](https://github.com/op-rs/kona/pull/834)) -## [0.0.1](https://github.com/anton-rs/kona/compare/kona-driver-v0.0.0...kona-driver-v0.0.1) - 2024-11-20 +## [0.0.1](https://github.com/op-rs/kona/compare/kona-driver-v0.0.0...kona-driver-v0.0.1) - 2024-11-20 ### Added -- *(driver,client)* Pipeline Cursor Refactor ([#798](https://github.com/anton-rs/kona/pull/798)) -- *(driver)* Abstract, Default Pipeline ([#796](https://github.com/anton-rs/kona/pull/796)) +- *(driver,client)* Pipeline Cursor Refactor ([#798](https://github.com/op-rs/kona/pull/798)) +- *(driver)* Abstract, Default Pipeline ([#796](https://github.com/op-rs/kona/pull/796)) ### Fixed -- imports ([#829](https://github.com/anton-rs/kona/pull/829)) -- *(client)* SyncStart Refactor ([#797](https://github.com/anton-rs/kona/pull/797)) +- imports ([#829](https://github.com/op-rs/kona/pull/829)) +- *(client)* SyncStart Refactor ([#797](https://github.com/op-rs/kona/pull/797)) ### Other -- *(driver)* use tracing macros ([#823](https://github.com/anton-rs/kona/pull/823)) -- *(driver)* use tracing macros ([#822](https://github.com/anton-rs/kona/pull/822)) -- *(workspace)* Migrate back to `thiserror` v2 ([#811](https://github.com/anton-rs/kona/pull/811)) +- *(driver)* use tracing macros ([#823](https://github.com/op-rs/kona/pull/823)) +- *(driver)* use tracing macros ([#822](https://github.com/op-rs/kona/pull/822)) +- *(workspace)* Migrate back to `thiserror` v2 ([#811](https://github.com/op-rs/kona/pull/811)) diff --git a/crates/driver/Cargo.toml b/crates/driver/Cargo.toml index 84d325d80e..7f4be9fdc9 100644 --- a/crates/driver/Cargo.toml +++ b/crates/driver/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "kona-driver" description = "A no_std derivation pipeline driver" -version = "0.2.0" +version = "0.2.3" edition.workspace = true authors.workspace = true license.workspace = true @@ -14,6 +14,7 @@ workspace = true [dependencies] # Workspace kona-derive.workspace = true +kona-executor.workspace = true # Alloy alloy-rlp.workspace = true @@ -27,6 +28,7 @@ op-alloy-consensus.workspace = true op-alloy-rpc-types-engine.workspace = true # Misc -tracing.workspace = true -thiserror .workspace = true async-trait.workspace = true +spin.workspace = true +thiserror .workspace = true +tracing.workspace = true diff --git a/crates/driver/src/core.rs b/crates/driver/src/core.rs index 7fc73e2e42..d6f3f78fdf 100644 --- a/crates/driver/src/core.rs +++ b/crates/driver/src/core.rs @@ -1,8 +1,9 @@ //! The driver of the kona derivation pipeline. -use alloc::vec::Vec; +use crate::{DriverError, DriverPipeline, DriverResult, Executor, PipelineCursor, TipCursor}; +use alloc::{sync::Arc, vec::Vec}; use alloy_consensus::{BlockBody, Sealable}; -use alloy_primitives::B256; +use alloy_primitives::{Bytes, B256}; use alloy_rlp::Decodable; use core::fmt::Debug; use kona_derive::{ @@ -10,12 +11,13 @@ use kona_derive::{ traits::{Pipeline, SignalReceiver}, types::Signal, }; +use kona_executor::ExecutionArtifacts; + use op_alloy_consensus::{OpBlock, OpTxEnvelope, OpTxType}; use op_alloy_genesis::RollupConfig; use op_alloy_protocol::L2BlockInfo; use op_alloy_rpc_types_engine::OpAttributesWithParent; - -use crate::{DriverError, DriverPipeline, DriverResult, Executor, PipelineCursor, TipCursor}; +use spin::RwLock; /// The Rollup Driver entrypoint. #[derive(Debug)] @@ -25,16 +27,16 @@ where DP: DriverPipeline

+ Send + Sync + Debug, P: Pipeline + SignalReceiver + Send + Sync + Debug, { - /// Marker for the executor. - _marker: core::marker::PhantomData, /// Marker for the pipeline. - _marker2: core::marker::PhantomData

, - /// A pipeline abstraction. - pub pipeline: DP, + _marker: core::marker::PhantomData

, /// Cursor to keep track of the L2 tip - pub cursor: PipelineCursor, + pub cursor: Arc>, /// The Executor. pub executor: E, + /// A pipeline abstraction. + pub pipeline: DP, + /// The safe head's execution artifacts + Transactions + pub safe_head_artifacts: Option<(ExecutionArtifacts, Vec)>, } impl Driver @@ -44,13 +46,13 @@ where P: Pipeline + SignalReceiver + Send + Sync + Debug, { /// Creates a new [Driver]. - pub const fn new(cursor: PipelineCursor, executor: E, pipeline: DP) -> Self { + pub const fn new(cursor: Arc>, executor: E, pipeline: DP) -> Self { Self { _marker: core::marker::PhantomData, - _marker2: core::marker::PhantomData, pipeline, cursor, executor, + safe_head_artifacts: None, } } @@ -73,22 +75,21 @@ where &mut self, cfg: &RollupConfig, mut target: Option, - ) -> DriverResult<(u64, B256), E::Error> { + ) -> DriverResult<(L2BlockInfo, B256), E::Error> { loop { // Check if we have reached the target block number. + let pipeline_cursor = self.cursor.read(); + let tip_cursor = pipeline_cursor.tip(); if let Some(tb) = target { - if self.cursor.l2_safe_head().block_info.number >= tb { + if tip_cursor.l2_safe_head.block_info.number >= tb { info!(target: "client", "Derivation complete, reached L2 safe head."); - return Ok(( - self.cursor.l2_safe_head().block_info.number, - *self.cursor.l2_safe_head_output_root(), - )); + return Ok((tip_cursor.l2_safe_head, tip_cursor.l2_safe_head_output_root)); } } let OpAttributesWithParent { mut attributes, .. } = match self .pipeline - .produce_payload(*self.cursor.l2_safe_head()) + .produce_payload(tip_cursor.l2_safe_head) .await { Ok(attrs) => attrs, @@ -98,7 +99,7 @@ where // Adjust the target block number to the current safe head, as no more blocks // can be produced. if target.is_some() { - target = Some(self.cursor.l2_safe_head().block_info.number); + target = Some(tip_cursor.l2_safe_head.block_info.number); }; continue; } @@ -108,56 +109,25 @@ where } }; - self.executor.update_safe_head(self.cursor.l2_safe_head_header().clone()); - let header = match self.executor.execute_payload(attributes.clone()).await { + self.executor.update_safe_head(tip_cursor.l2_safe_head_header.clone()); + let execution_result = match self.executor.execute_payload(attributes.clone()).await { Ok(header) => header, Err(e) => { error!(target: "client", "Failed to execute L2 block: {}", e); - - if cfg.is_holocene_active(attributes.payload_attributes.timestamp) { - // Retry with a deposit-only block. - warn!(target: "client", "Flushing current channel and retrying deposit only block"); - - // Flush the current batch and channel - if a block was replaced with a - // deposit-only block due to execution failure, the - // batch and channel it is contained in is forwards - // invalidated. - self.pipeline.signal(Signal::FlushChannel).await?; - - // Strip out all transactions that are not deposits. - attributes.transactions = attributes.transactions.map(|txs| { - txs.into_iter() - .filter(|tx| (!tx.is_empty() && tx[0] == OpTxType::Deposit as u8)) - .collect::>() - }); - - // Retry the execution. - self.executor.update_safe_head(self.cursor.l2_safe_head_header().clone()); - match self.executor.execute_payload(attributes.clone()).await { - Ok(header) => header, - Err(e) => { - error!( - target: "client", - "Critical - Failed to execute deposit-only block: {e}", - ); - return Err(DriverError::Executor(e)); - } - } - } else { - // Pre-Holocene, discard the block if execution fails. - continue; - } + // Pre-Holocene, discard the block if execution fails. + continue; } }; // Construct the block. let block = OpBlock { - header: header.clone(), + header: execution_result.block_header.inner().clone(), body: BlockBody { transactions: attributes .transactions - .unwrap_or_default() - .into_iter() + .as_ref() + .unwrap_or(&Vec::new()) + .iter() .map(|tx| OpTxEnvelope::decode(&mut tx.as_ref()).map_err(DriverError::Rlp)) .collect::, E::Error>>()?, ommers: Vec::new(), @@ -165,18 +135,25 @@ where }, }; - // Get the pipeline origin and update the cursor. + // Get the pipeline origin and update the tip cursor. let origin = self.pipeline.origin().ok_or(PipelineError::MissingOrigin.crit())?; let l2_info = L2BlockInfo::from_block_and_genesis( &block, &self.pipeline.rollup_config().genesis, )?; - let cursor = TipCursor::new( + let tip_cursor = TipCursor::new( l2_info, - header.clone().seal_slow(), + execution_result.block_header.clone(), self.executor.compute_output_root().map_err(DriverError::Executor)?, ); - self.cursor.advance(origin, cursor); + + // Advance the derivation pipeline cursor + drop(pipeline_cursor); + self.cursor.write().advance(origin, tip_cursor); + + // Update the latest safe head artifacts. + self.safe_head_artifacts = + Some((execution_result, attributes.transactions.unwrap_or_default())); } } } diff --git a/crates/driver/src/executor.rs b/crates/driver/src/executor.rs index 2e57ca54fd..e65aa796d1 100644 --- a/crates/driver/src/executor.rs +++ b/crates/driver/src/executor.rs @@ -6,6 +6,8 @@ use core::{ fmt::{Debug, Display}, }; +use kona_executor::ExecutionArtifacts; + use alloc::string::ToString; use alloy_consensus::{Header, Sealed}; use alloy_primitives::B256; @@ -30,7 +32,7 @@ pub trait Executor { async fn execute_payload( &mut self, attributes: OpPayloadAttributes, - ) -> Result; + ) -> Result; /// Computes the output root. /// Expected to be called after the payload has been executed. diff --git a/crates/driver/src/lib.rs b/crates/driver/src/lib.rs index bd5bb6ce82..764c163d59 100644 --- a/crates/driver/src/lib.rs +++ b/crates/driver/src/lib.rs @@ -1,7 +1,7 @@ #![doc = include_str!("../README.md")] #![doc( - html_logo_url = "https://raw.githubusercontent.com/anton-rs/kona/main/assets/square.png", - html_favicon_url = "https://raw.githubusercontent.com/anton-rs/kona/main/assets/favicon.ico" + html_logo_url = "https://raw.githubusercontent.com/op-rs/kona/main/assets/square.png", + html_favicon_url = "https://raw.githubusercontent.com/op-rs/kona/main/assets/favicon.ico" )] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] #![cfg_attr(not(test), warn(unused_crate_dependencies))] diff --git a/crates/driver/src/pipeline.rs b/crates/driver/src/pipeline.rs index a949f65a63..fa936a42bc 100644 --- a/crates/driver/src/pipeline.rs +++ b/crates/driver/src/pipeline.rs @@ -40,14 +40,16 @@ where info!(target: "client_derivation_driver", "Advanced origin") } StepResult::OriginAdvanceErr(e) | StepResult::StepFailed(e) => { - warn!(target: "client_derivation_driver", "Failed to step derivation pipeline: {:?}", e); - // Break the loop unless the error signifies that there is not enough data to // complete the current step. In this case, we retry the step to see if other // stages can make progress. match e { - PipelineErrorKind::Temporary(_) => continue, + PipelineErrorKind::Temporary(_) => { + trace!(target: "client_derivation_driver", "Failed to step derivation pipeline temporarily: {:?}", e); + continue; + } PipelineErrorKind::Reset(e) => { + warn!(target: "client_derivation_driver", "Failed to step derivation pipeline due to reset: {:?}", e); let system_config = self .system_config_by_number(l2_safe_head.block_info.number) .await?; @@ -85,7 +87,10 @@ where .await?; } } - PipelineErrorKind::Critical(_) => return Err(e), + PipelineErrorKind::Critical(_) => { + warn!(target: "client_derivation_driver", "Failed to step derivation pipeline: {:?}", e); + return Err(e); + } } } } diff --git a/crates/eigen-da/Cargo.toml b/crates/eigen-da/Cargo.toml new file mode 100644 index 0000000000..11197a968a --- /dev/null +++ b/crates/eigen-da/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "eigen-da" +version = "0.1.0" +edition.workspace = true +license.workspace = true +rust-version.workspace = true +authors.workspace = true +homepage.workspace = true +repository.workspace = true +keywords.workspace = true +categories.workspace = true +exclude.workspace = true + +[dependencies] + +#Alloy +alloy-primitives = { workspace = true, features = ["rlp", "k256", "serde"] } +alloy-rlp = { workspace = true} + +# Workspace +kona-derive = { workspace = true, features = ["serde"] } + +bytes = { workspace = true} +hex = {workspace = true} +tracing.workspace = true + +rust-kzg-bn254-primitives.workspace = true + +[dev-dependencies] +serde_json.workspace = true + +[lints] +workspace = true diff --git a/crates/eigen-da/src/certificate.rs b/crates/eigen-da/src/certificate.rs new file mode 100644 index 0000000000..9a8416af87 --- /dev/null +++ b/crates/eigen-da/src/certificate.rs @@ -0,0 +1,64 @@ +use alloy_primitives::Bytes; +use alloy_rlp::{RlpDecodable, RlpEncodable}; + + +// TODO: use prost to generate struct from proto file +// see seggestion, https://github.com/Layr-Labs/hokulea/pull/17#discussion_r1901102921 + +#[derive(Debug, PartialEq, Clone, RlpEncodable, RlpDecodable)] +pub struct G1Commitment { + pub x: [u8; 32], + pub y: [u8; 32], +} + +#[derive(Debug, PartialEq, Clone, RlpEncodable, RlpDecodable)] +pub struct BlobQuorumParam { + pub quorum_number: u32, + pub adversary_threshold_percentage: u32, + pub confirmation_threshold_percentage: u32, + pub chunk_length: u32, +} + +/// eigenda v1 blob header +#[derive(Debug, PartialEq, Clone, RlpEncodable, RlpDecodable)] +pub struct BlobHeader { + pub commitment: G1Commitment, + pub data_length: u32, + pub blob_quorum_params: Vec, +} + +#[derive(Debug, PartialEq, Clone, RlpEncodable, RlpDecodable)] +pub struct BatchHeader { + pub batch_root: Bytes, + pub quorum_numbers: Bytes, + pub quorum_signed_percentages: Bytes, + pub reference_block_number: u32, +} + +#[derive(Debug, PartialEq, Clone, RlpEncodable, RlpDecodable)] +pub struct BatchMetadata { + pub batch_header: BatchHeader, + pub signatory_record_hash: Bytes, + pub fee: Bytes, + pub confirmation_block_number: u32, + pub batch_header_hash: Bytes, +} + +/// eigenda v1 blob verification proof +#[derive(Debug, PartialEq, Clone, RlpEncodable, RlpDecodable)] +pub struct BlobVerificationProof { + pub batch_id: u32, + pub blob_index: u32, + pub batch_medatada: BatchMetadata, + pub inclusion_proof: Bytes, + pub quorum_indexes: Bytes, +} + +/// eigenda v1 certificate +#[derive(Debug, PartialEq, Clone, RlpEncodable, RlpDecodable)] +pub struct BlobInfo { + /// v1 blob header + pub blob_header: BlobHeader, + /// v1 blob verification proof with merkle tree + pub blob_verification_proof: BlobVerificationProof, +} diff --git a/crates/eigen-da/src/config.rs b/crates/eigen-da/src/config.rs new file mode 100644 index 0000000000..2f67a56e46 --- /dev/null +++ b/crates/eigen-da/src/config.rs @@ -0,0 +1,26 @@ +use core::time::Duration; +use {String, ToString}; + +/// The EigenDa configuration +pub struct EigenDaConfig { + /// The url of EigenDA Proxy service + pub proxy_url: String, + /// EigenDA Disperser RPC URL + pub disperse_url: String, + /// The total amount of time that the batcher will spend waiting for EigenDA to disperse a blob + pub disperse_blob_timeout: Duration, + /// The total amount of time that the batcher will spend waiting for EigenDA to retrieve a blob + pub retrieve_blob_timeout: Duration, +} + +/// Need to manually implement Default +impl Default for EigenDaConfig { + fn default() -> Self { + Self { + proxy_url: "http://127.0.0.1:3100".to_string(), + disperse_url: "".to_string(), + disperse_blob_timeout: Duration::from_secs(120), + retrieve_blob_timeout: Duration::from_secs(120), + } + } +} diff --git a/crates/eigen-da/src/constant.rs b/crates/eigen-da/src/constant.rs new file mode 100644 index 0000000000..2dd116af7f --- /dev/null +++ b/crates/eigen-da/src/constant.rs @@ -0,0 +1,7 @@ +/// This minimal blob encoding contains a 32 byte header = [0x00, version byte, uint32 len of data, 0x00, 0x00,...] +/// followed by the encoded data [0x00, 31 bytes of data, 0x00, 31 bytes of data,...] +pub const BLOB_ENCODING_VERSION_0: u8 = 0x0; +/// TODO: make it part of rollup config +pub const STALE_GAP: u64 = 100; +/// Number of fields for field element on bn254 +pub const BYTES_PER_FIELD_ELEMENT: usize = 32; \ No newline at end of file diff --git a/crates/eigen-da/src/eigenda_data.rs b/crates/eigen-da/src/eigenda_data.rs new file mode 100644 index 0000000000..ef0ef3bf36 --- /dev/null +++ b/crates/eigen-da/src/eigenda_data.rs @@ -0,0 +1,131 @@ +use crate::BYTES_PER_FIELD_ELEMENT; +use alloy_primitives::Bytes; +use bytes::buf::Buf; +use kona_derive::errors::BlobDecodingError; +use rust_kzg_bn254_primitives::helpers; +use tracing::{debug, info}; +use vec; + +pub const BLOB_ENCODING_VERSION_0: u8 = 0x0; + +#[derive(Default, Clone, Debug)] +/// Represents the data structure for EigenDA Blob. +pub struct EigenDABlobData { + /// The calldata + pub blob: Bytes, +} + +impl EigenDABlobData { + pub fn new(blob: Bytes) -> Self { + Self { blob } + } + + /// Decodes the blob into raw byte data. Reverse of the encode function below + /// Returns a [BlobDecodingError] if the blob is invalid. + pub fn decode(&self) -> Result { + let blob = &self.blob; + if blob.len() < 32 { + return Err(BlobDecodingError::InvalidLength); + } + + debug!(target: "eigenda-datasource", "padded_eigenda_blob {:?}", blob); + + // see https://github.com/Layr-Labs/eigenda/blob/f8b0d31d65b29e60172507074922668f4ca89420/api/clients/codecs/default_blob_codec.go#L44 + let content_size = blob.slice(2..6).get_u32(); + debug!(target: "eigenda-datasource", "content_size {:?}", content_size); + + // the first 32 Bytes are reserved as the header field element + let codec_data = blob.slice(32..); + + // rust kzg bn254 impl already + let blob_content = + helpers::remove_empty_byte_from_padded_bytes_unchecked(codec_data.as_ref()); + let blob_content: Bytes = blob_content.into(); + + if blob_content.len() < content_size as usize { + return Err(BlobDecodingError::InvalidLength); + } + Ok(blob_content.slice(..content_size as usize)) + } + + /// The encode function accepts an input of opaque rollup data array into an EigenDABlobData. + /// EigenDABlobData contains a header of 32 bytes and a transformation of input data + /// The 0 index byte of header is always 0, to comply to bn254 field element constraint + /// The 1 index byte of header is proxy encoding version. + /// The 2-4 indices of header are storing the length of the input rollup data in big endien + /// The payload is prepared by padding an empty byte for every 31 bytes from the rollup data + /// This matches exactly the eigenda proxy implementation, whose logic is in + /// + /// + /// The length of (header + payload) by the encode function is always multiple of 32 + /// The eigenda proxy does not take such constraint. + pub fn encode(rollup_data: &[u8]) -> Self { + let rollup_data_size = rollup_data.len() as u32; + + // encode to become raw blob + let codec_rollup_data = helpers::convert_by_padding_empty_byte(rollup_data); + + let blob_payload_size = codec_rollup_data.len(); + + // the first field element contains the header + let blob_size = blob_payload_size + BYTES_PER_FIELD_ELEMENT; + + // round up to the closest multiple of 32 + let blob_size = blob_size.div_ceil(BYTES_PER_FIELD_ELEMENT) * BYTES_PER_FIELD_ELEMENT; + + let mut raw_blob = vec![0u8; blob_size as usize]; + + raw_blob[1] = BLOB_ENCODING_VERSION_0; + raw_blob[2..6].copy_from_slice(&rollup_data_size.to_be_bytes()); + + // encode length as uint32 + raw_blob[BYTES_PER_FIELD_ELEMENT..(BYTES_PER_FIELD_ELEMENT + blob_payload_size as usize)] + .copy_from_slice(&codec_rollup_data); + + Self { blob: Bytes::from(raw_blob) } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use alloy_primitives::Bytes; + use kona_derive::errors::BlobDecodingError; + use vec; + + #[test] + fn test_encode_and_decode_success() { + let rollup_data = vec![0u8; 50000]; + let eigenda_blob = EigenDABlobData::encode(&rollup_data); + let data_len = eigenda_blob.blob.len(); + + assert!(data_len % BYTES_PER_FIELD_ELEMENT == 0); + + let result = eigenda_blob.decode(); + assert!(result.is_ok()); + assert_eq!(result.unwrap(), Bytes::from(rollup_data)); + } + + #[test] + fn test_encode_and_decode_success_empty() { + let rollup_data = vec![]; + let eigenda_blob = EigenDABlobData::encode(&rollup_data); + let data_len = eigenda_blob.blob.len(); + // 32 is eigenda blob header size + assert!(data_len == 32); + + let result = eigenda_blob.decode(); + assert!(result.is_ok()); + assert_eq!(result.unwrap(), Bytes::from(rollup_data)); + } + + #[test] + fn test_encode_and_decode_error_invalid_length() { + let rollup_data = vec![1, 2, 3, 4]; + let mut eigenda_blob = EigenDABlobData::encode(&rollup_data); + eigenda_blob.blob.truncate(33); + let result = eigenda_blob.decode(); + assert!(result.is_err()); + assert_eq!(result.unwrap_err(), BlobDecodingError::InvalidLength); + } +} diff --git a/crates/eigen-da/src/lib.rs b/crates/eigen-da/src/lib.rs new file mode 100644 index 0000000000..b34cd56b1a --- /dev/null +++ b/crates/eigen-da/src/lib.rs @@ -0,0 +1,13 @@ +mod config; +pub use config::*; + +mod certificate; +mod eigenda_data; +mod constant; +pub use constant::BLOB_ENCODING_VERSION_0; +pub use constant::BYTES_PER_FIELD_ELEMENT; +pub use constant::STALE_GAP; + +pub use eigenda_data::EigenDABlobData; + +pub use certificate::BlobInfo; diff --git a/crates/executor/CHANGELOG.md b/crates/executor/CHANGELOG.md index 830ea36cb2..998b48f84b 100644 --- a/crates/executor/CHANGELOG.md +++ b/crates/executor/CHANGELOG.md @@ -6,108 +6,108 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -## [0.2.0](https://github.com/anton-rs/kona/compare/kona-executor-v0.1.0...kona-executor-v0.2.0) - 2024-12-03 +## [0.2.0](https://github.com/op-rs/kona/compare/kona-executor-v0.1.0...kona-executor-v0.2.0) - 2024-12-03 ### Added -- *(driver)* refines the executor interface for the driver ([#850](https://github.com/anton-rs/kona/pull/850)) +- *(driver)* refines the executor interface for the driver ([#850](https://github.com/op-rs/kona/pull/850)) ### Fixed -- bump ([#855](https://github.com/anton-rs/kona/pull/855)) -- use non problematic hashmap fns ([#853](https://github.com/anton-rs/kona/pull/853)) +- bump ([#855](https://github.com/op-rs/kona/pull/855)) +- use non problematic hashmap fns ([#853](https://github.com/op-rs/kona/pull/853)) ### Other -- update deps and clean up misc features ([#864](https://github.com/anton-rs/kona/pull/864)) +- update deps and clean up misc features ([#864](https://github.com/op-rs/kona/pull/864)) -## [0.0.6](https://github.com/anton-rs/kona/compare/kona-executor-v0.0.5...kona-executor-v0.0.6) - 2024-11-20 +## [0.0.6](https://github.com/op-rs/kona/compare/kona-executor-v0.0.5...kona-executor-v0.0.6) - 2024-11-20 ### Added -- *(mpt)* Extend `TrieProvider` in `kona-executor` ([#813](https://github.com/anton-rs/kona/pull/813)) +- *(mpt)* Extend `TrieProvider` in `kona-executor` ([#813](https://github.com/op-rs/kona/pull/813)) ### Other -- *(driver)* use tracing macros ([#823](https://github.com/anton-rs/kona/pull/823)) -- *(workspace)* Migrate back to `thiserror` v2 ([#811](https://github.com/anton-rs/kona/pull/811)) +- *(driver)* use tracing macros ([#823](https://github.com/op-rs/kona/pull/823)) +- *(workspace)* Migrate back to `thiserror` v2 ([#811](https://github.com/op-rs/kona/pull/811)) -## [0.0.5](https://github.com/anton-rs/kona/compare/kona-executor-v0.0.4...kona-executor-v0.0.5) - 2024-11-06 +## [0.0.5](https://github.com/op-rs/kona/compare/kona-executor-v0.0.4...kona-executor-v0.0.5) - 2024-11-06 ### Added -- *(TrieProvider)* Abstract TrieNode retrieval ([#787](https://github.com/anton-rs/kona/pull/787)) +- *(TrieProvider)* Abstract TrieNode retrieval ([#787](https://github.com/op-rs/kona/pull/787)) ### Other -- *(executor)* rm upstream util ([#755](https://github.com/anton-rs/kona/pull/755)) +- *(executor)* rm upstream util ([#755](https://github.com/op-rs/kona/pull/755)) -## [0.0.4](https://github.com/anton-rs/kona/compare/kona-executor-v0.0.3...kona-executor-v0.0.4) - 2024-10-29 +## [0.0.4](https://github.com/op-rs/kona/compare/kona-executor-v0.0.3...kona-executor-v0.0.4) - 2024-10-29 ### Other - update Cargo.toml dependencies -## [0.0.3](https://github.com/anton-rs/kona/compare/kona-executor-v0.0.2...kona-executor-v0.0.3) - 2024-10-25 +## [0.0.3](https://github.com/op-rs/kona/compare/kona-executor-v0.0.2...kona-executor-v0.0.3) - 2024-10-25 ### Added -- remove thiserror ([#735](https://github.com/anton-rs/kona/pull/735)) -- *(executor)* Clean ups ([#719](https://github.com/anton-rs/kona/pull/719)) -- *(executor)* EIP-1559 configurability spec updates ([#716](https://github.com/anton-rs/kona/pull/716)) -- *(executor)* Update EIP-1559 configurability ([#648](https://github.com/anton-rs/kona/pull/648)) -- *(executor)* Use EIP-1559 parameters from payload attributes ([#616](https://github.com/anton-rs/kona/pull/616)) -- *(derive)* bump op-alloy dep ([#605](https://github.com/anton-rs/kona/pull/605)) -- kona-providers ([#596](https://github.com/anton-rs/kona/pull/596)) -- *(executor)* Migrate to `thiserror` ([#544](https://github.com/anton-rs/kona/pull/544)) -- *(mpt)* Migrate to `thiserror` ([#541](https://github.com/anton-rs/kona/pull/541)) -- *(primitives)* Remove Attributes ([#529](https://github.com/anton-rs/kona/pull/529)) -- large dependency update ([#528](https://github.com/anton-rs/kona/pull/528)) +- remove thiserror ([#735](https://github.com/op-rs/kona/pull/735)) +- *(executor)* Clean ups ([#719](https://github.com/op-rs/kona/pull/719)) +- *(executor)* EIP-1559 configurability spec updates ([#716](https://github.com/op-rs/kona/pull/716)) +- *(executor)* Update EIP-1559 configurability ([#648](https://github.com/op-rs/kona/pull/648)) +- *(executor)* Use EIP-1559 parameters from payload attributes ([#616](https://github.com/op-rs/kona/pull/616)) +- *(derive)* bump op-alloy dep ([#605](https://github.com/op-rs/kona/pull/605)) +- kona-providers ([#596](https://github.com/op-rs/kona/pull/596)) +- *(executor)* Migrate to `thiserror` ([#544](https://github.com/op-rs/kona/pull/544)) +- *(mpt)* Migrate to `thiserror` ([#541](https://github.com/op-rs/kona/pull/541)) +- *(primitives)* Remove Attributes ([#529](https://github.com/op-rs/kona/pull/529)) +- large dependency update ([#528](https://github.com/op-rs/kona/pull/528)) ### Fixed -- *(executor)* Holocene EIP-1559 params in Header ([#622](https://github.com/anton-rs/kona/pull/622)) -- *(workspace)* hoist and fix lints ([#577](https://github.com/anton-rs/kona/pull/577)) +- *(executor)* Holocene EIP-1559 params in Header ([#622](https://github.com/op-rs/kona/pull/622)) +- *(workspace)* hoist and fix lints ([#577](https://github.com/op-rs/kona/pull/577)) ### Other -- re-org imports ([#711](https://github.com/anton-rs/kona/pull/711)) -- *(workspace)* Removes Primitives ([#638](https://github.com/anton-rs/kona/pull/638)) -- *(executor)* move todo to issue: ([#680](https://github.com/anton-rs/kona/pull/680)) -- *(executor)* Cover Builder ([#676](https://github.com/anton-rs/kona/pull/676)) -- *(executor)* Use Upstreamed op-alloy Methods ([#651](https://github.com/anton-rs/kona/pull/651)) -- *(executor)* Test Coverage over Executor Utilities ([#650](https://github.com/anton-rs/kona/pull/650)) -- doc logos ([#609](https://github.com/anton-rs/kona/pull/609)) -- *(workspace)* Allow stdlib in `cfg(test)` ([#548](https://github.com/anton-rs/kona/pull/548)) -- Bumps Dependency Versions ([#520](https://github.com/anton-rs/kona/pull/520)) -- *(primitives)* rm RawTransaction ([#505](https://github.com/anton-rs/kona/pull/505)) +- re-org imports ([#711](https://github.com/op-rs/kona/pull/711)) +- *(workspace)* Removes Primitives ([#638](https://github.com/op-rs/kona/pull/638)) +- *(executor)* move todo to issue: ([#680](https://github.com/op-rs/kona/pull/680)) +- *(executor)* Cover Builder ([#676](https://github.com/op-rs/kona/pull/676)) +- *(executor)* Use Upstreamed op-alloy Methods ([#651](https://github.com/op-rs/kona/pull/651)) +- *(executor)* Test Coverage over Executor Utilities ([#650](https://github.com/op-rs/kona/pull/650)) +- doc logos ([#609](https://github.com/op-rs/kona/pull/609)) +- *(workspace)* Allow stdlib in `cfg(test)` ([#548](https://github.com/op-rs/kona/pull/548)) +- Bumps Dependency Versions ([#520](https://github.com/op-rs/kona/pull/520)) +- *(primitives)* rm RawTransaction ([#505](https://github.com/op-rs/kona/pull/505)) -## [0.0.2](https://github.com/anton-rs/kona/compare/kona-executor-v0.0.1...kona-executor-v0.0.2) - 2024-09-04 +## [0.0.2](https://github.com/op-rs/kona/compare/kona-executor-v0.0.1...kona-executor-v0.0.2) - 2024-09-04 ### Added -- *(executor)* Expose full revm Handler ([#475](https://github.com/anton-rs/kona/pull/475)) -- *(workspace)* Workspace Re-exports ([#468](https://github.com/anton-rs/kona/pull/468)) -- *(executor)* `StatelessL2BlockExecutor` benchmarks ([#350](https://github.com/anton-rs/kona/pull/350)) -- *(executor)* Generic precompile overrides ([#340](https://github.com/anton-rs/kona/pull/340)) -- *(executor)* Builder pattern for `StatelessL2BlockExecutor` ([#339](https://github.com/anton-rs/kona/pull/339)) +- *(executor)* Expose full revm Handler ([#475](https://github.com/op-rs/kona/pull/475)) +- *(workspace)* Workspace Re-exports ([#468](https://github.com/op-rs/kona/pull/468)) +- *(executor)* `StatelessL2BlockExecutor` benchmarks ([#350](https://github.com/op-rs/kona/pull/350)) +- *(executor)* Generic precompile overrides ([#340](https://github.com/op-rs/kona/pull/340)) +- *(executor)* Builder pattern for `StatelessL2BlockExecutor` ([#339](https://github.com/op-rs/kona/pull/339)) ### Fixed -- *(workspace)* Use published `revm` version ([#459](https://github.com/anton-rs/kona/pull/459)) -- downgrade for release plz ([#458](https://github.com/anton-rs/kona/pull/458)) -- *(workspace)* Add Unused Dependency Lint ([#453](https://github.com/anton-rs/kona/pull/453)) -- Don't hold onto intermediate execution cache across block boundaries ([#396](https://github.com/anton-rs/kona/pull/396)) +- *(workspace)* Use published `revm` version ([#459](https://github.com/op-rs/kona/pull/459)) +- downgrade for release plz ([#458](https://github.com/op-rs/kona/pull/458)) +- *(workspace)* Add Unused Dependency Lint ([#453](https://github.com/op-rs/kona/pull/453)) +- Don't hold onto intermediate execution cache across block boundaries ([#396](https://github.com/op-rs/kona/pull/396)) ### Other -- *(workspace)* Alloy Version Bumps ([#467](https://github.com/anton-rs/kona/pull/467)) -- *(workspace)* Update for `anton-rs` org transfer ([#474](https://github.com/anton-rs/kona/pull/474)) -- *(workspace)* Hoist Dependencies ([#466](https://github.com/anton-rs/kona/pull/466)) -- refactor types out of kona-derive ([#454](https://github.com/anton-rs/kona/pull/454)) -- *(deps)* Bump revm version to v13 ([#422](https://github.com/anton-rs/kona/pull/422)) +- *(workspace)* Alloy Version Bumps ([#467](https://github.com/op-rs/kona/pull/467)) +- *(workspace)* Update for `op-rs` org transfer ([#474](https://github.com/op-rs/kona/pull/474)) +- *(workspace)* Hoist Dependencies ([#466](https://github.com/op-rs/kona/pull/466)) +- refactor types out of kona-derive ([#454](https://github.com/op-rs/kona/pull/454)) +- *(deps)* Bump revm version to v13 ([#422](https://github.com/op-rs/kona/pull/422)) -## [0.0.1](https://github.com/anton-rs/kona/releases/tag/kona-executor-v0.0.1) - 2024-06-22 +## [0.0.1](https://github.com/op-rs/kona/releases/tag/kona-executor-v0.0.1) - 2024-06-22 ### Other -- *(workspace)* Prep release ([#301](https://github.com/anton-rs/kona/pull/301)) -- version dependencies ([#296](https://github.com/anton-rs/kona/pull/296)) -- *(deps)* fast forward op alloy dep ([#267](https://github.com/anton-rs/kona/pull/267)) -- *(workspace)* `kona-executor` ([#259](https://github.com/anton-rs/kona/pull/259)) +- *(workspace)* Prep release ([#301](https://github.com/op-rs/kona/pull/301)) +- version dependencies ([#296](https://github.com/op-rs/kona/pull/296)) +- *(deps)* fast forward op alloy dep ([#267](https://github.com/op-rs/kona/pull/267)) +- *(workspace)* `kona-executor` ([#259](https://github.com/op-rs/kona/pull/259)) diff --git a/crates/executor/Cargo.toml b/crates/executor/Cargo.toml index d197b9b752..3a0660e201 100644 --- a/crates/executor/Cargo.toml +++ b/crates/executor/Cargo.toml @@ -20,6 +20,7 @@ alloy-consensus = { workspace = true, features = ["k256"] } alloy-primitives = { workspace = true, features = ["rlp"] } alloy-eips.workspace = true alloy-rlp.workspace = true +alloy-trie = { workspace = true, features = ["ethereum"]} # Op Alloy op-alloy-genesis.workspace = true @@ -35,14 +36,17 @@ tracing.workspace = true [dev-dependencies] rand.workspace = true -anyhow.workspace = true alloy-rlp.workspace = true serde_json.workspace = true alloy-rpc-types-engine.workspace = true serde = { workspace = true, features = ["derive"] } criterion = { workspace = true, features = ["html_reports"] } pprof = { workspace = true, features = ["criterion", "flamegraph", "frame-pointer"] } +tokio = { workspace = true, features = ["full"] } +rstest.workspace = true +alloy-provider = { workspace = true, features = ["reqwest"] } +alloy-rpc-client.workspace = true +alloy-transport.workspace = true +alloy-transport-http.workspace = true +kona-host.workspace = true -[[bench]] -name = "execution" -harness = false diff --git a/crates/executor/benches/execution.rs b/crates/executor/benches/execution.rs index 0ced84e0b5..e9d57b2663 100644 --- a/crates/executor/benches/execution.rs +++ b/crates/executor/benches/execution.rs @@ -1,11 +1,11 @@ -#![allow(missing_docs)] //! Benches for the [StatelessL2BlockExecutor] implementation. +#![allow(missing_docs)] + use alloy_consensus::{Header, Sealable}; use alloy_primitives::{address, b256, hex, Bytes, B256}; use alloy_rlp::Decodable; use alloy_rpc_types_engine::PayloadAttributes; -use anyhow::{anyhow, Result}; use criterion::{criterion_group, criterion_main, Bencher, Criterion}; use kona_executor::{StatelessL2BlockExecutor, TrieDBProvider}; use kona_mpt::{NoopTrieHinter, TrieNode, TrieProvider}; @@ -22,6 +22,14 @@ struct TestdataTrieProvider { preimages: HashMap, } +#[derive(Debug, thiserror::Error)] +enum TestdataTrieProviderError { + #[error("RLP error: {0}")] + Rlp(alloy_rlp::Error), + #[error("Preimage not found for key: {0}")] + PreimageNotFound(B256), +} + impl TestdataTrieProvider { /// Constructs a new [TestdataTrieProvider] with the given testdata folder. pub(crate) fn new(testdata_folder: &str) -> Self { @@ -35,35 +43,33 @@ impl TestdataTrieProvider { } impl TrieProvider for TestdataTrieProvider { - type Error = anyhow::Error; + type Error = TestdataTrieProviderError; - fn trie_node_by_hash(&self, key: B256) -> Result { + fn trie_node_by_hash(&self, key: B256) -> Result { TrieNode::decode( &mut self .preimages .get(&key) .cloned() - .ok_or_else(|| anyhow!("Preimage not found for key: {}", key))? + .ok_or(TestdataTrieProviderError::PreimageNotFound(key))? .as_ref(), ) - .map_err(Into::into) + .map_err(TestdataTrieProviderError::Rlp) } } impl TrieDBProvider for TestdataTrieProvider { - fn bytecode_by_hash(&self, code_hash: B256) -> Result { + fn bytecode_by_hash(&self, code_hash: B256) -> Result { self.preimages .get(&code_hash) .cloned() - .ok_or_else(|| anyhow!("Bytecode not found for hash: {}", code_hash)) + .ok_or(TestdataTrieProviderError::PreimageNotFound(code_hash)) } - fn header_by_hash(&self, hash: B256) -> Result

{ - let encoded_header = self - .preimages - .get(&hash) - .ok_or_else(|| anyhow!("Header not found for hash: {}", hash))?; - Header::decode(&mut encoded_header.as_ref()).map_err(|e| anyhow!(e)) + fn header_by_hash(&self, hash: B256) -> Result { + let encoded_header = + self.preimages.get(&hash).ok_or(TestdataTrieProviderError::PreimageNotFound(hash))?; + Header::decode(&mut encoded_header.as_ref()).map_err(TestdataTrieProviderError::Rlp) } } @@ -77,11 +83,7 @@ fn op_mainnet_exec_bench( let rollup_config = RollupConfig { l2_chain_id: 10, regolith_time: Some(0), - canyon_time: Some(0), - delta_time: Some(0), - ecotone_time: Some(0), - base_fee_params: OP_MAINNET_BASE_FEE_PARAMS.as_base_fee_params(), - canyon_base_fee_params: OP_MAINNET_BASE_FEE_PARAMS.as_canyon_base_fee_params(), + shanghai_time: Some(0), ..Default::default() }; @@ -135,7 +137,7 @@ fn execution(c: &mut Criterion) { gas_limit: Some(30_000_000), transactions: Some(raw_txs), no_tx_pool: Some(false), - eip_1559_params: None, + base_fee: None, }; op_mainnet_exec_bench("block_121065789_exec", parent_header, payload_attrs, b) @@ -179,7 +181,7 @@ fn execution(c: &mut Criterion) { gas_limit: Some(30_000_000), transactions: Some(raw_txs), no_tx_pool: Some(false), - eip_1559_params: None, + base_fee: None, }; op_mainnet_exec_bench("block_121135704_exec", parent_header, payload_attrs, b) diff --git a/crates/executor/src/constants.rs b/crates/executor/src/constants.rs index 3a1a71cc6f..efeb00fed4 100644 --- a/crates/executor/src/constants.rs +++ b/crates/executor/src/constants.rs @@ -1,6 +1,6 @@ //! Protocol constants for the executor. -use alloy_primitives::{address, Address}; +use alloy_primitives::{address, b256, Address, B256}; /// The address of the fee recipient. pub(crate) const FEE_RECIPIENT: Address = address!("4200000000000000000000000000000000000011"); @@ -13,3 +13,7 @@ pub(crate) const OUTPUT_ROOT_VERSION: u8 = 0; /// The version byte for the Holocene extra data. pub(crate) const HOLOCENE_EXTRA_DATA_VERSION: u8 = 0x00; + +/// Empty SHA-256 hash. +pub(crate) const SHA256_EMPTY: B256 = + b256!("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"); diff --git a/crates/executor/src/db/account.rs b/crates/executor/src/db/account.rs deleted file mode 100644 index 400e09d003..0000000000 --- a/crates/executor/src/db/account.rs +++ /dev/null @@ -1,82 +0,0 @@ -//! This module contains the [TrieAccount] struct. - -use alloy_primitives::{B256, U256}; -use alloy_rlp::{RlpDecodable, RlpEncodable}; -use revm::primitives::{Account, AccountInfo}; - -/// An Ethereum account as represented in the trie. -#[derive(Clone, Copy, Debug, PartialEq, Eq, Default, RlpEncodable, RlpDecodable)] -pub struct TrieAccount { - /// Account nonce. - pub nonce: u64, - /// Account balance. - pub balance: U256, - /// Account's storage root. - pub storage_root: B256, - /// Hash of the account's bytecode. - pub code_hash: B256, -} - -impl From<(Account, B256)> for TrieAccount { - fn from((account, storage_root): (Account, B256)) -> Self { - Self { - nonce: account.info.nonce, - balance: account.info.balance, - storage_root, - code_hash: account.info.code_hash, - } - } -} - -impl From<(AccountInfo, B256)> for TrieAccount { - fn from((account, storage_root): (AccountInfo, B256)) -> Self { - Self { - nonce: account.nonce, - balance: account.balance, - storage_root, - code_hash: account.code_hash, - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use alloy_primitives::uint; - - #[test] - fn test_trie_account_from_account() { - let account = Account { - info: AccountInfo { - nonce: 1, - balance: uint!(2_U256), - code_hash: B256::default(), - code: Default::default(), - }, - status: Default::default(), - storage: Default::default(), - }; - let storage_root = B256::default(); - let trie_account = TrieAccount::from((account, storage_root)); - assert_eq!(trie_account.nonce, 1); - assert_eq!(trie_account.balance, uint!(2_U256)); - assert_eq!(trie_account.storage_root, B256::default()); - assert_eq!(trie_account.code_hash, B256::default()); - } - - #[test] - fn test_trie_account_from_account_info() { - let account_info = AccountInfo { - nonce: 1, - balance: uint!(2_U256), - code_hash: B256::default(), - code: Default::default(), - }; - let storage_root = B256::default(); - let trie_account = TrieAccount::from((account_info, storage_root)); - assert_eq!(trie_account.nonce, 1); - assert_eq!(trie_account.balance, uint!(2_U256)); - assert_eq!(trie_account.storage_root, B256::default()); - assert_eq!(trie_account.code_hash, B256::default()); - } -} diff --git a/crates/executor/src/db/mod.rs b/crates/executor/src/db/mod.rs index 0076a4becc..4357ac0743 100644 --- a/crates/executor/src/db/mod.rs +++ b/crates/executor/src/db/mod.rs @@ -6,6 +6,7 @@ use alloc::{string::ToString, vec::Vec}; use alloy_consensus::{Header, Sealed, EMPTY_ROOT_HASH}; use alloy_primitives::{keccak256, Address, B256, U256}; use alloy_rlp::{Decodable, Encodable}; +use alloy_trie::TrieAccount; use kona_mpt::{Nibbles, TrieHinter, TrieNode, TrieNodeError}; use revm::{ db::{states::StorageSlot, BundleState}, @@ -13,9 +14,6 @@ use revm::{ Database, }; -mod account; -pub use account::TrieAccount; - mod traits; pub use traits::{NoopTrieDBProvider, TrieDBProvider}; @@ -48,7 +46,6 @@ pub use traits::{NoopTrieDBProvider, TrieDBProvider}; /// ```rust /// use alloy_consensus::{Header, Sealable}; /// use alloy_primitives::{Bytes, B256}; -/// use anyhow::Result; /// use kona_executor::{NoopTrieDBProvider, TrieDB}; /// use kona_mpt::NoopTrieHinter; /// use revm::{db::states::bundle_state::BundleRetention, EvmBuilder, StateBuilder}; @@ -154,16 +151,15 @@ where self.update_accounts(bundle)?; // Recompute the root hash of the trie. - self.root_node.blind(); + let root = self.root_node.blind(); debug!( target: "client_executor", - "Recomputed state root: {commitment:?}", - commitment = self.root_node.blinded_commitment() + "Recomputed state root: {root}", ); // Extract the new state root from the root node. - self.root_node.blinded_commitment().ok_or(TrieDBError::RootNotBlinded) + Ok(root) } /// Fetches the [TrieAccount] of an account from the trie DB. @@ -204,13 +200,19 @@ where /// - `Ok(())` if the accounts were successfully updated. /// - `Err(_)` if the accounts could not be updated. fn update_accounts(&mut self, bundle: &BundleState) -> TrieDBResult<()> { - for (address, bundle_account) in bundle.state() { + // Sort the storage keys prior to applying the changeset, to ensure that the order of + // application is deterministic between runs. + let mut sorted_state = + bundle.state().iter().map(|(k, v)| (k, keccak256(*k), v)).collect::>(); + sorted_state.sort_by_key(|(_, hashed_addr, _)| *hashed_addr); + + for (address, hashed_address, bundle_account) in sorted_state { if bundle_account.status.is_not_modified() { continue; } // Compute the path to the account in the trie. - let account_path = Nibbles::unpack(keccak256(address.as_slice())); + let account_path = Nibbles::unpack(hashed_address.as_slice()); // If the account was destroyed, delete it from the trie. if bundle_account.was_destroyed() { @@ -233,16 +235,29 @@ where .storage_roots .entry(*address) .or_insert_with(|| TrieNode::new_blinded(EMPTY_ROOT_HASH)); - bundle_account.storage.iter().try_for_each(|(index, value)| { - Self::change_storage(acc_storage_root, *index, value, &self.fetcher, &self.hinter) + + // Sort the hashed storage keys prior to applying the changeset, to ensure that the + // order of application is deterministic between runs. + let mut sorted_storage = bundle_account + .storage + .iter() + .map(|(k, v)| (keccak256(k.to_be_bytes::<32>()), v)) + .collect::>(); + sorted_storage.sort_by_key(|(slot, _)| *slot); + + sorted_storage.into_iter().try_for_each(|(hashed_key, value)| { + Self::change_storage( + acc_storage_root, + hashed_key, + value, + &self.fetcher, + &self.hinter, + ) })?; // Recompute the account storage root. - acc_storage_root.blind(); - - let commitment = - acc_storage_root.blinded_commitment().ok_or(TrieDBError::RootNotBlinded)?; - trie_account.storage_root = commitment; + let root = acc_storage_root.blind(); + trie_account.storage_root = root; // RLP encode the trie account for insertion. let mut account_buf = Vec::with_capacity(trie_account.length()); @@ -258,16 +273,18 @@ where /// Modifies a storage slot of an account in the Merkle Patricia Trie. /// /// ## Takes - /// - `address`: The address of the account. - /// - `index`: The index of the storage slot. + /// - `storage_root`: The storage root of the account. + /// - `hashed_key`: The hashed storage slot key. /// - `value`: The new value of the storage slot. + /// - `fetcher`: The trie node fetcher. + /// - `hinter`: The trie hinter. /// /// ## Returns /// - `Ok(())` if the storage slot was successfully modified. /// - `Err(_)` if the storage slot could not be modified. fn change_storage( storage_root: &mut TrieNode, - index: U256, + hashed_key: B256, value: &StorageSlot, fetcher: &F, hinter: &H, @@ -281,7 +298,7 @@ where value.present_value.encode(&mut rlp_buf); // Insert or update the storage slot in the trie. - let hashed_slot_key = Nibbles::unpack(keccak256(index.to_be_bytes::<32>().as_slice())); + let hashed_slot_key = Nibbles::unpack(hashed_key.as_slice()); if value.present_value.is_zero() { // If the storage slot is being set to zero, prune it from the trie. storage_root.delete(&hashed_slot_key, fetcher, hinter)?; @@ -366,8 +383,8 @@ where let mut header = self.parent_block_header.inner().clone(); // Check if the block number is in range. If not, we can fail early. - if block_number > header.number || - header.number.saturating_sub(block_number) > BLOCK_HASH_HISTORY + if block_number > header.number + || header.number.saturating_sub(block_number) > BLOCK_HASH_HISTORY { return Ok(B256::default()); } @@ -404,14 +421,14 @@ mod tests { fn test_trie_db_take_root_node() { let db = new_test_db(); let root_node = db.take_root_node(); - assert_eq!(root_node.blinded_commitment(), Some(B256::default())); + assert_eq!(root_node.blind(), B256::default()); } #[test] fn test_trie_db_root_node_ref() { let db = new_test_db(); let root_node = db.root(); - assert_eq!(root_node.blinded_commitment(), Some(B256::default())); + assert_eq!(root_node.blind(), B256::default()); } #[test] diff --git a/crates/executor/src/executor/env.rs b/crates/executor/src/executor/env.rs index d8e1a61bc4..f68145c31d 100644 --- a/crates/executor/src/executor/env.rs +++ b/crates/executor/src/executor/env.rs @@ -1,17 +1,18 @@ //! Environment preparation for the executor. -use super::{util::decode_holocene_eip_1559_params, StatelessL2BlockExecutor}; +use super::StatelessL2BlockExecutor; use crate::{constants::FEE_RECIPIENT, ExecutorError, ExecutorResult, TrieDBProvider}; use alloy_consensus::Header; use alloy_eips::eip1559::BaseFeeParams; +use alloy_eips::eip7840::BlobParams; use alloy_primitives::{TxKind, U256}; use kona_mpt::TrieHinter; use op_alloy_consensus::OpTxEnvelope; use op_alloy_genesis::RollupConfig; use op_alloy_rpc_types_engine::OpPayloadAttributes; use revm::primitives::{ - BlobExcessGasAndPrice, BlockEnv, CfgEnv, CfgEnvWithHandlerCfg, OptimismFields, SpecId, - TransactTo, TxEnv, + AuthorizationList, BlobExcessGasAndPrice, BlockEnv, CfgEnv, CfgEnvWithHandlerCfg, + OptimismFields, SpecId, TransactTo, TxEnv, }; impl StatelessL2BlockExecutor<'_, P, H> @@ -27,14 +28,8 @@ where /// ## Returns /// The active [SpecId] for the executor. pub(crate) fn revm_spec_id(&self, timestamp: u64) -> SpecId { - if self.config.is_holocene_active(timestamp) { - SpecId::HOLOCENE - } else if self.config.is_fjord_active(timestamp) { - SpecId::FJORD - } else if self.config.is_ecotone_active(timestamp) { - SpecId::ECOTONE - } else if self.config.is_canyon_active(timestamp) { - SpecId::CANYON + if self.config.is_shanghai_active(timestamp) { + SpecId::SHANGHAI } else if self.config.is_regolith_active(timestamp) { SpecId::REGOLITH } else { @@ -68,14 +63,12 @@ where spec_id: SpecId, parent_header: &Header, payload_attrs: &OpPayloadAttributes, - base_fee_params: &BaseFeeParams, ) -> ExecutorResult { let blob_excess_gas_and_price = parent_header - .next_block_excess_blob_gas() + .next_block_excess_blob_gas(BlobParams::cancun()) .or_else(|| spec_id.is_enabled_in(SpecId::ECOTONE).then_some(0)) .map(BlobExcessGasAndPrice::new); - let next_block_base_fee = - parent_header.next_block_base_fee(*base_fee_params).unwrap_or_default(); + let next_block_base_fee = parent_header.base_fee_per_gas.unwrap_or_default(); Ok(BlockEnv { number: U256::from(parent_header.number + 1), @@ -89,40 +82,6 @@ where }) } - /// Returns the active base fee parameters for the given payload attributes. - /// - /// ## Takes - /// - `config`: The rollup config to use for the computation. - /// - `parent_header`: The parent header of the block to be executed. - /// - `payload_attrs`: The payload attributes to use for the computation. - pub(crate) fn active_base_fee_params( - config: &RollupConfig, - parent_header: &Header, - payload_attrs: &OpPayloadAttributes, - ) -> ExecutorResult { - let base_fee_params = - if config.is_holocene_active(payload_attrs.payload_attributes.timestamp) { - // After Holocene activation, the base fee parameters are stored in the - // `extraData` field of the parent header. If Holocene wasn't active in the - // parent block, the default base fee parameters are used. - config - .is_holocene_active(parent_header.timestamp) - .then(|| decode_holocene_eip_1559_params(parent_header)) - .transpose()? - .unwrap_or(config.canyon_base_fee_params) - } else if config.is_canyon_active(payload_attrs.payload_attributes.timestamp) { - // If the payload attribute timestamp is past canyon activation, - // use the canyon base fee params from the rollup config. - config.canyon_base_fee_params - } else { - // If the payload attribute timestamp is prior to canyon activation, - // use the default base fee params from the rollup config. - config.base_fee_params - }; - - Ok(base_fee_params) - } - /// Prepares a [TxEnv] with the given [OpTxEnvelope]. /// /// ## Takes @@ -160,6 +119,8 @@ where mint: None, is_system_transaction: Some(false), enveloped_tx: Some(encoded_transaction.to_vec().into()), + eth_value: None, + eth_tx_value: None, }; Ok(env) } @@ -185,6 +146,8 @@ where mint: None, is_system_transaction: Some(false), enveloped_tx: Some(encoded_transaction.to_vec().into()), + eth_value: None, + eth_tx_value: None, }; Ok(env) } @@ -210,6 +173,34 @@ where mint: None, is_system_transaction: Some(false), enveloped_tx: Some(encoded_transaction.to_vec().into()), + eth_value: None, + eth_tx_value: None, + }; + Ok(env) + } + OpTxEnvelope::Eip7702(signed_tx) => { + let tx = signed_tx.tx(); + env.caller = signed_tx.recover_signer().map_err(ExecutorError::SignatureError)?; + env.gas_limit = tx.gas_limit; + env.gas_price = U256::from(tx.max_fee_per_gas); + env.gas_priority_fee = Some(U256::from(tx.max_priority_fee_per_gas)); + env.transact_to = TransactTo::Call(tx.to); + env.value = tx.value; + env.data = tx.input.clone(); + env.chain_id = Some(tx.chain_id); + env.nonce = Some(tx.nonce); + env.access_list = tx.access_list.to_vec(); + env.blob_hashes.clear(); + env.max_fee_per_blob_gas.take(); + env.authorization_list = + Some(AuthorizationList::Signed(tx.authorization_list.to_vec())); + env.optimism = OptimismFields { + source_hash: None, + mint: None, + is_system_transaction: Some(false), + enveloped_tx: Some(encoded_transaction.to_vec().into()), + eth_value: None, + eth_tx_value: None, }; Ok(env) } @@ -232,6 +223,8 @@ where mint: tx.mint, is_system_transaction: Some(tx.is_system_transaction), enveloped_tx: Some(encoded_transaction.to_vec().into()), + eth_value: tx.eth_value, + eth_tx_value: tx.eth_tx_value, }; Ok(env) } diff --git a/crates/executor/src/executor/mod.rs b/crates/executor/src/executor/mod.rs index 2a92d6dc03..cb44c36cb7 100644 --- a/crates/executor/src/executor/mod.rs +++ b/crates/executor/src/executor/mod.rs @@ -1,14 +1,15 @@ //! A stateless block executor for the OP Stack. use crate::{ - constants::{L2_TO_L1_BRIDGE, OUTPUT_ROOT_VERSION}, + constants::{L2_TO_L1_BRIDGE, OUTPUT_ROOT_VERSION, SHA256_EMPTY}, db::TrieDB, errors::TrieDBError, - syscalls::{ensure_create2_deployer_canyon, pre_block_beacon_root_contract_call}, ExecutorError, ExecutorResult, TrieDBProvider, }; use alloc::vec::Vec; -use alloy_consensus::{Header, Sealable, Transaction, EMPTY_OMMER_ROOT_HASH, EMPTY_ROOT_HASH}; +use alloy_consensus::{ + Header, Sealable, Sealed, Transaction, EMPTY_OMMER_ROOT_HASH, EMPTY_ROOT_HASH, +}; use alloy_eips::eip2718::{Decodable2718, Encodable2718}; use alloy_primitives::{keccak256, logs_bloom, Bytes, Log, B256, U256}; use kona_mpt::{ordered_trie_with_encoder, TrieHinter}; @@ -26,8 +27,15 @@ pub use builder::{KonaHandleRegister, StatelessL2BlockExecutorBuilder}; mod env; -mod util; -use util::encode_holocene_eip_1559_params; +/// The [ExecutionArtifacts] holds the produced block header and receipts from the execution of a +/// block. +#[derive(Default, Debug, Clone, PartialEq, Eq)] +pub struct ExecutionArtifacts { + /// The block header. + pub block_header: Sealed
, + /// The receipts generated during execution. + pub receipts: Vec, +} /// The block executor for the L2 client program. Operates off of a [TrieDB] backed [State], /// allowing for stateless block execution of OP Stack blocks. @@ -75,18 +83,16 @@ where /// 4. Merge all state transitions into the cache state. /// 5. Compute the [state root, transactions root, receipts root, logs bloom] for the processed /// block. - pub fn execute_payload(&mut self, payload: OpPayloadAttributes) -> ExecutorResult<&Header> { + pub fn execute_payload( + &mut self, + payload: OpPayloadAttributes, + ) -> ExecutorResult { // Prepare the `revm` environment. - let base_fee_params = Self::active_base_fee_params( - self.config, - self.trie_db.parent_block_header(), - &payload, - )?; + let initialized_block_env = Self::prepare_block_env( self.revm_spec_id(payload.payload_attributes.timestamp), self.trie_db.parent_block_header(), &payload, - &base_fee_params, )?; let initialized_cfg = self.evm_cfg_env(payload.payload_attributes.timestamp); let block_number = initialized_block_env.number.to::(); @@ -106,23 +112,6 @@ where let mut state = State::builder().with_database(&mut self.trie_db).with_bundle_update().build(); - // Apply the pre-block EIP-4788 contract call. - pre_block_beacon_root_contract_call( - &mut state, - self.config, - block_number, - &initialized_cfg, - &initialized_block_env, - &payload, - )?; - - // Ensure that the create2 contract is deployed upon transition to the Canyon hardfork. - ensure_create2_deployer_canyon( - &mut state, - self.config, - payload.payload_attributes.timestamp, - )?; - let mut cumulative_gas_used = 0u64; let mut receipts: Vec = Vec::with_capacity(transactions.len()); let is_regolith = self.config.is_regolith_active(payload.payload_attributes.timestamp); @@ -146,6 +135,8 @@ where base.build() }; + // let is_isthmus = self.config.is_isthmus_active(payload.payload_attributes.timestamp); + // Execute the transactions in the payload. let decoded_txs = transactions .iter() @@ -159,12 +150,17 @@ where // The sum of the transaction’s gas limit, Tg, and the gas utilized in this block prior, // must be no greater than the block’s gasLimit. let block_available_gas = (gas_limit - cumulative_gas_used) as u128; - if (transaction.gas_limit() as u128) > block_available_gas && - (is_regolith || !transaction.is_system_transaction()) + if (transaction.gas_limit() as u128) > block_available_gas + && (is_regolith || !transaction.is_system_transaction()) { return Err(ExecutorError::BlockGasLimitExceeded); } + // Prevent EIP-7702 transactions pre-isthmus hardfork. + if matches!(transaction, OpTxEnvelope::Eip7702(_)) { + return Err(ExecutorError::UnsupportedTransactionType(transaction.tx_type() as u8)); + } + // Modify the transaction environment with the current transaction. evm = evm .modify() @@ -202,28 +198,22 @@ where // Accumulate the gas used by the transaction. cumulative_gas_used += result.gas_used(); - // Create receipt envelope. let receipt = OpReceiptEnvelope::::from_parts( result.is_success(), - cumulative_gas_used as u128, + cumulative_gas_used, result.logs(), transaction.tx_type(), depositor .as_ref() .map(|depositor| depositor.account_info().unwrap_or_default().nonce), - depositor - .is_some() - .then(|| { - self.config - .is_canyon_active(payload.payload_attributes.timestamp) - .then_some(1) - }) - .flatten(), + None, ); // Ensure the receipt is not an EIP-7702 receipt. if matches!(receipt, OpReceiptEnvelope::Eip7702(_)) { - panic!("EIP-7702 receipts are not supported by the fault proof program"); + panic!( + "EIP-7702 receipts are not supported by the fault proof program before Isthmus" + ); } receipts.push(receipt); } @@ -260,45 +250,15 @@ where // The withdrawals root on OP Stack chains, after Canyon activation, is always the empty // root hash. - let withdrawals_root = self - .config - .is_canyon_active(payload.payload_attributes.timestamp) - .then_some(EMPTY_ROOT_HASH); + // TODO: if Cancun is active, compute the withdrawals root. + // let withdrawals_root = self + // .config + // .is_cancun_active(payload.payload_attributes.timestamp) + // .then_some(EMPTY_ROOT_HASH); // Compute logs bloom filter for the block. let logs_bloom = logs_bloom(receipts.iter().flat_map(|receipt| receipt.logs())); - // Compute Cancun fields, if active. - let (blob_gas_used, excess_blob_gas) = self - .config - .is_ecotone_active(payload.payload_attributes.timestamp) - .then(|| { - let parent_header = state.database.parent_block_header(); - let excess_blob_gas = if self.config.is_ecotone_active(parent_header.timestamp) { - let parent_excess_blob_gas = parent_header.excess_blob_gas.unwrap_or_default(); - let parent_blob_gas_used = parent_header.blob_gas_used.unwrap_or_default(); - calc_excess_blob_gas(parent_excess_blob_gas, parent_blob_gas_used) - } else { - // For the first post-fork block, both blob gas fields are evaluated to 0. - calc_excess_blob_gas(0, 0) - }; - - (Some(0), Some(excess_blob_gas as u128)) - }) - .unwrap_or_default(); - - // At holocene activation, the base fee parameters from the payload are placed - // into the Header's `extra_data` field. - // - // If the payload's `eip_1559_params` are equal to `0`, then the header's `extraData` - // field is set to the encoded canyon base fee parameters. - let encoded_base_fee_params = self - .config - .is_holocene_active(payload.payload_attributes.timestamp) - .then(|| encode_holocene_eip_1559_params(self.config, &payload)) - .transpose()? - .unwrap_or_default(); - // Construct the new header. let header = Header { parent_hash: state.database.parent_block_header().seal(), @@ -307,8 +267,7 @@ where state_root, transactions_root, receipts_root, - withdrawals_root, - requests_hash: None, + withdrawals_root: None, logs_bloom, difficulty: U256::ZERO, number: block_number, @@ -318,11 +277,11 @@ where mix_hash: payload.payload_attributes.prev_randao, nonce: Default::default(), base_fee_per_gas: base_fee.try_into().ok(), - blob_gas_used, - excess_blob_gas: excess_blob_gas.and_then(|x| x.try_into().ok()), + blob_gas_used: None, + excess_blob_gas: None, parent_beacon_block_root: payload.payload_attributes.parent_beacon_block_root, - extra_data: encoded_base_fee_params, - target_blobs_per_block: None, + requests_hash: None, + extra_data: Default::default(), } .seal_slow(); @@ -336,8 +295,8 @@ where ); // Update the parent block hash in the state database. - state.database.set_parent_block_header(header); - Ok(state.database.parent_block_header()) + state.database.set_parent_block_header(header.clone()); + Ok(ExecutionArtifacts { block_header: header, receipts }) } /// Computes the current output root of the executor, based on the parent header and the @@ -355,9 +314,7 @@ where pub fn compute_output_root(&mut self) -> ExecutorResult { // Fetch the L2 to L1 message passer account from the cache or underlying trie. let storage_root = match self.trie_db.storage_roots().get(&L2_TO_L1_BRIDGE) { - Some(storage_root) => { - storage_root.blinded_commitment().ok_or(TrieDBError::RootNotBlinded)? - } + Some(storage_root) => storage_root.blind(), None => { self.trie_db .get_trie_account(&L2_TO_L1_BRIDGE)? @@ -365,7 +322,6 @@ where .storage_root } }; - let parent_header = self.trie_db.parent_block_header(); info!( @@ -412,7 +368,7 @@ where // the receipt root calculation does not inclide the deposit nonce in the // receipt encoding. In the Regolith hardfork, we must strip the deposit nonce // from the receipt encoding to match the receipt root calculation. - if config.is_regolith_active(timestamp) && !config.is_canyon_active(timestamp) { + if config.is_regolith_active(timestamp) { let receipts = receipts .iter() .cloned() @@ -449,486 +405,36 @@ where #[cfg(test)] mod test { - use crate::{constants::FEE_RECIPIENT, db::TrieDBProvider}; - - use super::*; - use alloy_primitives::{b256, hex}; - use alloy_rlp::Decodable; - use alloy_rpc_types_engine::PayloadAttributes; - use anyhow::{anyhow, Result}; - use kona_mpt::{NoopTrieHinter, TrieNode, TrieProvider}; - use op_alloy_genesis::OP_MAINNET_BASE_FEE_PARAMS; - use serde::Deserialize; - use std::collections::HashMap; - - /// A [TrieProvider] implementation that fetches trie nodes and bytecode from the local - /// testdata folder. - #[derive(Deserialize)] - struct TestdataTrieProvider { - preimages: HashMap, - } - - impl TestdataTrieProvider { - /// Constructs a new [TestdataTrieProvider] with the given testdata folder. - pub(crate) fn new(testdata_folder: &str) -> Self { - let file_name = format!("testdata/{}/output.json", testdata_folder); - let preimages = serde_json::from_str::>( - &std::fs::read_to_string(&file_name).unwrap(), - ) - .unwrap(); - Self { preimages } - } - } - - impl TrieProvider for TestdataTrieProvider { - type Error = anyhow::Error; - - fn trie_node_by_hash(&self, key: B256) -> Result { - TrieNode::decode( - &mut self - .preimages - .get(&key) - .cloned() - .ok_or_else(|| anyhow!("Preimage not found for key: {}", key))? - .as_ref(), - ) - .map_err(Into::into) - } - } - - impl TrieDBProvider for TestdataTrieProvider { - fn bytecode_by_hash(&self, code_hash: B256) -> Result { - self.preimages - .get(&code_hash) - .cloned() - .ok_or_else(|| anyhow!("Bytecode not found for hash: {}", code_hash)) - } - - fn header_by_hash(&self, hash: B256) -> Result
{ - let encoded_header = self - .preimages - .get(&hash) - .ok_or_else(|| anyhow!("Header not found for hash: {}", hash))?; - Header::decode(&mut encoded_header.as_ref()).map_err(|e| anyhow!(e)) - } - } - - #[test] - fn test_l2_block_executor_small_block() { - // Static for the execution of block #120794432 on OP mainnet. - // https://optimistic.etherscan.io/block/120794432 - - // Make a mock rollup config, with Ecotone activated at timestamp = 0. - let rollup_config = RollupConfig { - l2_chain_id: 10, - regolith_time: Some(0), - canyon_time: Some(0), - delta_time: Some(0), - ecotone_time: Some(0), - base_fee_params: OP_MAINNET_BASE_FEE_PARAMS.as_base_fee_params(), - canyon_base_fee_params: OP_MAINNET_BASE_FEE_PARAMS.as_canyon_base_fee_params(), - ..Default::default() - }; - - // Decode the headers. - let raw_header = hex!("f90244a0ff7c6abc94edcaddd02c12ec7d85ffbb3ba293f3b76897e4adece57e692bcc39a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347944200000000000000000000000000000000000011a0a0b24abb13d6149947247a8817517971bb8d213de1e23225e2b20d36a5b6427ca0c31e4a2ada52ac698643357ca89ef2740d384076ef0e17b653bcb6ea7dd8902ea09f4fcf34e78afc216240e3faa72c822f8eea4757932eb9e0fd42839d192bb903b901000440000210068007000000940000000220000006000820048404800002000004040100001b2000008800001040000018280000400001200004000101086000000802800080004008010001080000200100a00000204840000118042080000400804001000a0400080200111000000800050000020200064000000012000800048000000000101800200002000000080008001581402002200210341089000080c2d004106000000018000000804285800800000020000180008000020000000000020103410400000000200400008000280400000100020000002002000021000811000920808000010000000200210400000020008000400000000000211008808407332d3f8401c9c3808327c44d84665a343780a0edba75784acf3165bffd96df8b78ffdb3781db91f886f22b4bee0a6f722df93988000000000000000083202ef8a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080a0917693152c4a041efbc196e9d169087093336da96a8bb3af1e55fce447a7b8a9"); - let header = Header::decode(&mut &raw_header[..]).unwrap(); - let raw_expected_header = hex!("f90243a09506905902f5c3613c5441a8697c09e7aafdb64082924d8bd2857f9e34a47a9aa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347944200000000000000000000000000000000000011a0a1e9207c3c68cd4854074f08226a3643debed27e45bf1b22ab528f8de16245eda0121e8765953af84974b845fd9b01f5ff9b0f7d2886a2464535e8e9976a1c8daba092c6a5e34d7296d63d1698258c40539a20080c668fc9d63332363cfbdfa37976b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000808407332d408401c9c38082ab4b84665a343980a0edba75784acf3165bffd96df8b78ffdb3781db91f886f22b4bee0a6f722df93988000000000000000083201f31a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080a0917693152c4a041efbc196e9d169087093336da96a8bb3af1e55fce447a7b8a9"); - let expected_header = Header::decode(&mut &raw_expected_header[..]).unwrap(); - - // Initialize the block executor on block #120794431's post-state. - let mut l2_block_executor = StatelessL2BlockExecutor::builder( - &rollup_config, - TestdataTrieProvider::new("block_120794432_exec"), - NoopTrieHinter, - ) - .with_parent_header(header.seal_slow()) - .build(); - - let raw_tx = hex!("7ef8f8a003b511b9b71520cd62cad3b5fd5b1b8eaebd658447723c31c7f1eba87cfe98c894deaddeaddeaddeaddeaddeaddeaddeaddead00019442000000000000000000000000000000000000158080830f424080b8a4440a5e2000000558000c5fc5000000000000000300000000665a33a70000000001310e960000000000000000000000000000000000000000000000000000000214d2697300000000000000000000000000000000000000000000000000000000000000015346d208a396843018a2e666c8e7832067358433fb87ca421273c6a4e69f78d50000000000000000000000006887246668a3b87f54deb3b94ba47a6f63f32985"); - let payload_attrs = OpPayloadAttributes { - payload_attributes: PayloadAttributes { - timestamp: 0x665a3439, - withdrawals: Default::default(), - parent_beacon_block_root: Some(b256!( - "917693152c4a041efbc196e9d169087093336da96a8bb3af1e55fce447a7b8a9" - )), - prev_randao: b256!( - "edba75784acf3165bffd96df8b78ffdb3781db91f886f22b4bee0a6f722df939" - ), - suggested_fee_recipient: FEE_RECIPIENT, - target_blobs_per_block: None, - max_blobs_per_block: None, - }, - gas_limit: Some(0x1c9c380), - transactions: Some(alloc::vec![raw_tx.into()]), - no_tx_pool: None, - eip_1559_params: None, - }; - let produced_header = l2_block_executor.execute_payload(payload_attrs).unwrap().clone(); - - assert_eq!(produced_header, expected_header); - assert_eq!( - l2_block_executor.trie_db.parent_block_header().seal(), - expected_header.hash_slow() - ); - } - - #[test] - fn test_l2_block_executor_small_block_2() { - // Static for the execution of block #121049889 on OP mainnet. - // https://optimistic.etherscan.io/block/121049889 - - // Make a mock rollup config, with Ecotone activated at timestamp = 0. - let rollup_config = RollupConfig { - l2_chain_id: 10, - regolith_time: Some(0), - canyon_time: Some(0), - delta_time: Some(0), - ecotone_time: Some(0), - base_fee_params: OP_MAINNET_BASE_FEE_PARAMS.as_base_fee_params(), - canyon_base_fee_params: OP_MAINNET_BASE_FEE_PARAMS.as_canyon_base_fee_params(), - ..Default::default() - }; - - // Decode the headers. - let raw_parent_header = hex!("f90245a0311e3aa67dca0d157b8e8a4e117a4fd34cedcebc63f5708976e86581c07824a5a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347944200000000000000000000000000000000000011a0b1772b8cd400c2d2cfee5bd294bcc399e4c8330d856907f95d2305a64ff9c968a0a42b2ec1d1e928f2b63224888d482f72537ee392e98390c760c902ca3f7d75d8a0e993b3cac72163177e7e728c5e4d074551b181a45f49b0026c48e893f7b4768eb901008008140067b0392a00048280488c10a04000180084400038834008020400c960003c9000068083b00000f00cc40088ab48306c402008068f0810881b84342000860104c10500102b209410584214804a40034000080d622018042ca008000204a016089206020412050c1902440158505802207070800900020028facaacc0101e0a08000010a003a15166a231024090841918038500ac4082281880810648221200881000116002c0444044421024c6c401c0008d42280c98408085142c3041542272832790b4154e66c082080a2090100002409548047010c208220588622694900120454200800600104100e01a160214408c4000141890022802209102488084073713208401c9c380831f42d1846661fff980a02ea5360883566f7bf998c6ce46367b64aeb24c0178a6e5752ea796ca9b9f951988000000000000000084038e4654a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080a0025cfb4d23d2384982b73c2669eeb4fb73b29960750554e2380af54add10dbda"); - let parent_header = Header::decode(&mut &raw_parent_header[..]).unwrap(); - let raw_expected_header = hex!("f90245a0925b8e3c7216dd1c62e3fd9911f6cb3f456b9aa685f34239180d1a7ef7653b7fa01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347944200000000000000000000000000000000000011a0ac6f1a9722101300ba71fb58517eadbb4964dc4f4891f8f3e58a292e7c3204f3a032ae1c22601d63eaa26aa5ab30e6b8ae1cdfb7104c0067327d91bc3094461fc9a016c68c81160c03fa72763fdd578c6a5563cca47ded1a54df3610c0412b976b25b90100000004000000000000000000001000000001200000000000000000000040000000001000200000000000000000000000200000000000000001000000000420000200000200002000000000800000000000000000000400000000000000012000000000000200000040008400050009000000000000000000000000000200050000000000000000000000010000000000000050840000000000000000000010000000000400000000000000000000008000000000010000000000000000000804000000000008000001000010000000000000840000080000100000000000600000000000000000002100000000000000001000000000008000000800000000008084073713218401c9c380830505a2846661fffb80a0d91ae18a8b94471ef1b15686ef8a6144a109b837c28488a0f1a2a4e4ad29d5af88000000000000000084038c2024a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080a05e7da14ac6b18e62306c84d9d555387d4b4a6c3d122df22a2af2b68bf219860d"); - let expected_header = Header::decode(&mut &raw_expected_header[..]).unwrap(); - - // Initialize the block executor on block #121049888's post-state. - let mut l2_block_executor = StatelessL2BlockExecutor::builder( - &rollup_config, - TestdataTrieProvider::new("block_121049889_exec"), - NoopTrieHinter, - ) - .with_parent_header(parent_header.seal_slow()) - .build(); - - let raw_txs = alloc::vec![ - hex!("7ef8f8a01e6036fa5dc5d76e0095f42fef2c4aa7d6589b4f496f9c4bea53daef1b4a24c194deaddeaddeaddeaddeaddeaddeaddeaddead00019442000000000000000000000000000000000000158080830f424080b8a4440a5e2000000558000c5fc50000000000000000000000006661ff73000000000131b40700000000000000000000000000000000000000000000000000000005c9ea450a0000000000000000000000000000000000000000000000000000000000000001e885b088376fedbd0490a7991be47854872f6467c476d255eed3151d5f6a95940000000000000000000000006887246668a3b87f54deb3b94ba47a6f63f32985").into(), - hex!("02f9010b0a8301b419835009eb840439574783030fc3940000000000002bdbf1bf3279983603ec279cc6df8702c2ad68fd9000b89666e0daa0001e80001ec0001d0220001e01001e01000bfe1561df392590b0cb3ec093b711066774ca96cd001e01001e20001ee49dbb844d000b3678862f04290e565cca2ef163baeb92bb76790c001e01001e01001ea0000b38873c13509d36077a4638183f4a9a72f8a66b91001e20000bcaaef30cf6e70a0118e59cd3fb88164de6d144b5003a01001802c2ad68fd900000012b817fc001a098c44ee6585f33a4fbc9c999b2469697dd8007b986c79569ae6f3d077de45a1ca035c3ea5e954ae76fdf75f7d7ce215a339ac20a772081b62908d5fcf551693e3a").into(), - hex!("02f904920a828a19834c4b408403dce3e7837a1200944d75a5ce454b264b187bee9e189af1564a68408d80b90424b1dc65a400018958e0d17c70a7bddf525ee0a3bf00f5c8f886a03156c522c0b256cb884d00000000000000000000000000000000000000000000000000000000001814035a6bc28056dae2cfa8a6479f5e50eee95bb3ae2b65be853a4440f15cb60211ba00000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000003400000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000b2c639c533813f4aa9d7837caf62653d097ff85000000000000000000000000000000000000000000000000000000e8d4a510000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000606ecf709c09afd92138cca6ee144be81e1c6ef231d4586a22eb7fc801826e837691e208839c1c58d50a31826c8b47c5218c3898ee6671f734bd9b9584ce210e8b1fb287f374f07a99bbce2ddedc655ee5c94f8fee715db21644ae134638af8c32d18b1d27dbc2e12b205ea25ab6bb4ec447ee7f40dba560e511a20fd8a3775d04ad83bf593e3587be1dd85ab9b2053d1386fae00c5fdea56a68ea147b706e5ced65ab296b8d9248aa943787a5c8aa4fd56ba7133d087e84a625fe1c3d8a390b5000000000000000000000000000000000000000000000000000000000000000666634013473fce9d0696d9f0375be4260a81518a85f2482b3f5336848f8fa3ce1a3f7032124577ee2a755122f916e4fe757fc42eb5561216892ed806d368908b69c4d4d1cd06897a3a2f02c17ffba7a762e4cbbdb086a1181f1111874f88f38f3b86fa03508822346a167de3f6afc9066cc274103cf18d62c7d6a4d93dcd000b7842951fd9a14a647148dac543f446cd9427dedbc3c3ca5ed2b36f5c27ce76de46d4291be6ef3b41679501c8f0341d35cf6afc9f7d91d56ad1a8ae34fc0e708ac001a013f549ca84754e18fae518daa617d19dfbdff6da7bc794bab89e7a17288cb5b5a00c4913669beb11412e9e04bd4311ed5b11443b9e34f7fb25488e58047ddd8820").into() - ]; - let payload_attrs = OpPayloadAttributes { - payload_attributes: PayloadAttributes { - timestamp: 1717698555, - withdrawals: Default::default(), - suggested_fee_recipient: FEE_RECIPIENT, - prev_randao: b256!( - "d91ae18a8b94471ef1b15686ef8a6144a109b837c28488a0f1a2a4e4ad29d5af" - ), - parent_beacon_block_root: Some(b256!( - "5e7da14ac6b18e62306c84d9d555387d4b4a6c3d122df22a2af2b68bf219860d" - )), - target_blobs_per_block: None, - max_blobs_per_block: None, - }, - gas_limit: Some(30000000), - transactions: Some(raw_txs), - no_tx_pool: Some(false), - eip_1559_params: None, - }; - let produced_header = l2_block_executor.execute_payload(payload_attrs).unwrap().clone(); - - assert_eq!(produced_header, expected_header); - assert_eq!( - l2_block_executor.trie_db.parent_block_header().seal(), - expected_header.hash_slow() - ); - } - - #[test] - fn test_l2_block_executor_small_block_3() { - // Static for the execution of block #121003241 on OP mainnet. - // https://optimistic.etherscan.io/block/121003241 - - // Make a mock rollup config, with Ecotone activated at timestamp = 0. - let rollup_config = RollupConfig { - l2_chain_id: 10, - regolith_time: Some(0), - canyon_time: Some(0), - delta_time: Some(0), - ecotone_time: Some(0), - base_fee_params: OP_MAINNET_BASE_FEE_PARAMS.as_base_fee_params(), - canyon_base_fee_params: OP_MAINNET_BASE_FEE_PARAMS.as_canyon_base_fee_params(), - ..Default::default() - }; - - // Decode the headers. - let raw_parent_header = hex!("f90245a01fe9a4a3f3a03b5e9bf26739dc0402016bcd0b4eba84f6daec89cd25ede03785a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347944200000000000000000000000000000000000011a0f0f4294d35c59be9ac60e3c8b10f72f082eb20db04e84b89622eaf36dc288f94a037567276c3663d85aa9c8f6d9fa3a9b02511a5314c08d83648caae01da377f0da0a5cc7888ada10b0cf445632d9239c129cb55b9822edcc6062262660cc9786457b9010007000032410480052001888000000000000200000400200040040000442002000a892000100000020008001100112000000000408000b012000002c200b48080000068040001480885003408000880010044000010241440800428208400004044000880820800800100100000000801820000000000000081000030000800204000000840000000802a0000000100400004000180300000004120104000001922000102000000000060001289c024840010000521800000000022140000208040001203800420620019020200004000209008009000000000004000880070120010220820502000500400202000000000040028000089c00080100000010008808407365ce88401c9c380832415e9846660938980a022e77867678dc60aace7567ee344620f47a66be343eac90a82bf619ea37de357880000000000000000840398f69aa056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080a050f4a35e2f059621cba649e719d23a2a9d030189fd19172a689c76d3adf39fec"); - let parent_header = Header::decode(&mut &raw_parent_header[..]).unwrap(); - let raw_expected_header = hex!("f90245a090957c484fec69a6b308f18d83a320b18a5471ba9566e5b56dfc656abd354744a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347944200000000000000000000000000000000000011a049dfddc9ce6d832c6ab981aea324c3d57b1b1d93823656b43d02608e6b59f3bda0533a1c4f39fa301e354292186123681d97ae64a788cf2af61e6f70e3080c1ac3a0c888d1dfb9590590036630c91d4ff2401a4946524f315bffbbbed795820e3744b90100060000024200002000118880000000008004000104000000000000000400010000080000000000000000040100000000000800c08000200a0000020000200080000000040040000800000008000000000040080004000000804000010002000040802088028c0010000014000200080102001000000800000000001000082000000000002000000000000000000000000044100080200000000100000c00800002000040001100000040100280000400040480000000000000800600000020c040001402008000401001201620020000000000000004000000800200000320000010200200080000400000000000040000000004008080002000000000010000808407365ce98401c9c3808312f8db846660938b80a022e77867678dc60aace7567ee344620f47a66be343eac90a82bf619ea37de3578800000000000000008403970597a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080a050f4a35e2f059621cba649e719d23a2a9d030189fd19172a689c76d3adf39fec"); - let expected_header = Header::decode(&mut &raw_expected_header[..]).unwrap(); - - // Initialize the block executor on block #121003240's post-state. - let mut l2_block_executor = StatelessL2BlockExecutor::builder( - &rollup_config, - TestdataTrieProvider::new("block_121003241_exec"), - NoopTrieHinter, - ) - .with_parent_header(parent_header.seal_slow()) - .build(); - - let raw_txs = alloc::vec![ - hex!("7ef8f8a02c3adbd572915b3ef2fe7c81418461cb32407df8cb1bd4c1f5f4b45e474bfce694deaddeaddeaddeaddeaddeaddeaddeaddead00019442000000000000000000000000000000000000158080830f424080b8a4440a5e2000000558000c5fc5000000000000000400000000666092ff00000000013195d800000000000000000000000000000000000000000000000000000004da0e1101000000000000000000000000000000000000000000000000000000000000000493a1359bf7a89d8b2b2073a153c47f9c399f8f7a864e4f25744d6832cb6fadd80000000000000000000000006887246668a3b87f54deb3b94ba47a6f63f32985").into(), - hex!("f86a03840998d150827b0c9422fb762f614ede47d33ca2de13a5fb16354a7a5b872defc438f220008038a0e83ca5fd673c57230b1ea308752959568a795fc0b2eccc4128bb295673f4f576a04de60eb10a6aa6fcffd5a956523a92451b06cf669cf332139ac2937880e4ee2f").into(), - hex!("f87e8301abd284050d2c55830493e094a43305ce0164d87d7b2368f91a1dcc4ebda751278097c201015dc7073aac5a2702007a6c235e4c4f676660938937a07575b3c2ed04981845adc29fc27bf573ccd17462c2d5789e3844d66d29277a79a005175e178a234d48c7e15bfaa979f1b78636228d550a200d9e34e05169d1b770").into(), - hex!("02f90fb40a83136342840104b33a840836a06e830995ae94087000a300de7200382b55d40045000000e5d60e80b90f4482ad56cb000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000042000000000000000000000000000000000000000000000000000000000000007c00000000000000000000000000000000000000000000000000000000000000b600000000000000000000000008f7dbe4fa3818025d82bb10190f178eaf5992bea0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000003046a761202000000000000000000000000b5fbfeba9848664fd1a49dc2a250d9b5d1294f2a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000104414bf389000000000000000000000000dc6ff44d5d932cbd77b52e5612ba0529dc6226f10000000000000000000000007f5c764cbc14f9669b88837ca1490cca17c3160700000000000000000000000000000000000000000000000000000000000027100000000000000000000000008f7dbe4fa3818025d82bb10190f178eaf5992bea000000000000000000000000000000000000000000000000000000006660a175000000000000000000000000000000000000000000000000de0b6b3a764000000000000000000000000000000000000000000000000000000000000004a71a1f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000419a434a72274666c423432aad2ffb19565424d0c6e2d17fc64934b3e4fec97788446afa2d830e2dd926c04ce882e601cb9fa398149b5d778cbe3ebe6038e8643e1b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a34049de917233a7516aa01fc0bad683a6a8b29d0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000003046a761202000000000000000000000000b5fbfeba9848664fd1a49dc2a250d9b5d1294f2a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000104414bf389000000000000000000000000dc6ff44d5d932cbd77b52e5612ba0529dc6226f10000000000000000000000007f5c764cbc14f9669b88837ca1490cca17c316070000000000000000000000000000000000000000000000000000000000002710000000000000000000000000a34049de917233a7516aa01fc0bad683a6a8b29d000000000000000000000000000000000000000000000000000000006660a17b0000000000000000000000000000000000000000000000002870624346de10000000000000000000000000000000000000000000000000000000000000d8ecb600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000418217f8941b74fc2cd49b297652e34ba54465a905ccc5fd452b48fd40a82502590c4c48e64b2a0f0e8e8793a13addfe6d4937bf78d9875a4d9002266be5ecc0a41b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000fb5049c82e7fa9e7011ddd435b30652b48a1195b0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000003046a761202000000000000000000000000b5fbfeba9848664fd1a49dc2a250d9b5d1294f2a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000104414bf3890000000000000000000000007f5c764cbc14f9669b88837ca1490cca17c31607000000000000000000000000dc6ff44d5d932cbd77b52e5612ba0529dc6226f10000000000000000000000000000000000000000000000000000000000002710000000000000000000000000fb5049c82e7fa9e7011ddd435b30652b48a1195b000000000000000000000000000000000000000000000000000000006660a1890000000000000000000000000000000000000000000000000000000000d019f10000000000000000000000000000000000000000000000002543ff48d0da90eb00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000413698ad34509d153bf3d7287553d81c098983d590f5c9e80c95c361de3c220c745eafd0ca4ef4e78cffe29e7b346ee3d134d20eebd9d98663438646a1ea3801d61c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009ef549707a5d504c24b0627aff2eb845e8ae02d80000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000003046a761202000000000000000000000000b5fbfeba9848664fd1a49dc2a250d9b5d1294f2a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002800000000000000000000000000000000000000000000000000000000000000104414bf38900000000000000000000000068f180fcce6836688e9084f035309e29bf0a20950000000000000000000000007f5c764cbc14f9669b88837ca1490cca17c3160700000000000000000000000000000000000000000000000000000000000001f40000000000000000000000009ef549707a5d504c24b0627aff2eb845e8ae02d8000000000000000000000000000000000000000000000000000000006660a188000000000000000000000000000000000000000000000000000000000000048200000000000000000000000000000000000000000000000000000000000c78cc0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041d561852d56b0baac02af7a38ac72d7f560d4a0956032e051adb598fbdb035661280071192a277daf0d36667dc88155f9b445a465dbbadc3149b3ee6c07ae905d1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c080a0f2c4eec1941db4f698a0fc5b24d708d4231decf19719977bca15af04cbd39cc6a022036042105c9ede61cf13552f6c2d712a3eefbb4f47df3cbe3d3b9b46723398").into(), - hex!("02f8af0a8083989680840578b8db83025dbe94dc6ff44d5d932cbd77b52e5612ba0529dc6226f180b844a9059cbb00000000000000000000000056c38d1b4676c9c2259d0820dcbce069d3321d5f00000000000000000000000000000000000000000000000029563f7ac07ae000c080a0d0b1d61b918d88059cc8dbee2833c2ce78573b76c731e266d110ed330fb72563a05ca02995f5ec74c0bd9b7209785d75369a1f43a5f045189a51f851ea9b9a791b").into(), - hex!("02f8740a832c6a52834c4b4085012a05f200825208948c1e1a0b0f9420139e12fa1379b6a76d381d7c8f870a18f74161700080c001a00b7dcc69c346c674167fdd0cee4b13622838d4d9a1f64ef0270d366e61c49fdaa02d99fcd56b7ef8aec6a04c0204a6fd66dcddb755cd54226527a51e5ba22aacd7").into(), - hex!("f86a808403b23254825208945e809a85aa182a9921edd10a4163745bb3e362848704f7793d6560098038a0c921dce37651444a6c3004e85263d7ef593225d6f5a6ac19265c5a1044f598caa003cbfcc7b3d89a023c7d423496bc0f55c281c501cdd00909e6e09485d90d6500").into(), - hex!("f8aa8207a88403a9e89182cac994dc6ff44d5d932cbd77b52e5612ba0529dc6226f180b844a9059cbb0000000000000000000000002e2927d05851ae228ab68dd04434dece401cf72b00000000000000000000000000000000000000000000000029998b20cdd0c00038a0a3d6514ad022c5b79f8b41cb59b7e48b62ca90d409a5438783f89947009a548ea037de75cc680392eac97820b5884239ca0a0a990e63fc118b0040b631ac73fc52").into(), - hex!("02f905720a820a1e830f42408404606a2c83044bc0940000000071727de22e5e9d8baf0edac6f37da03280b90504765e827f00000000000000000000000000000000000000000000000000000000000000400000000000000000000000004337016838785634c63fce393bfc6222564436c4000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000006a2aad2e20ef62b5b56e4e2b5e342e53ee7fa04f000017719c140000000000000000000000000000000005300000000000000002000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000002265a0000000000000000000000000001d4c00000000000000000000000000000000000000000000000000000000000010a370000000000000000000000000010c8e000000000000000000000000004d4157c00000000000000000000000000000000000000000000000000000000000003200000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001a4e9ae5c530100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000200000000000000000000000006668bc6eea73404b4da5775c774fafc815b66b36000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000044a9059cbb000000000000000000000000efe1bfc13a0f086066fbe23a18c896eb697ca5cc00000000000000000000000000000000000000000000000000000001a13b8600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b59d0021a869f1ed3a661ffe8c9b41ec6244261d9800000000000000000000000000004e8a0000000000000000000000000000000100000000000000000000000000000000000000000000000000000000666095e00000000000000000000000000000000000000000000000000000000000000000dcc3f422395fc31d9308eb3c4805623ddc445433eb04f7d4d7b07a9b4abb16886820d7c9a50f7bb450cff51271a9ff789322e9a72c65cf58da188c6b77093fdb1b00000000000000000000000000000000000000000000000000000000000000000000000000000000000042fff34f0b4b601ea1d21ac1184895b6d6b81662b95d14e59dfb768ef963838ca29f67dcaf0423b47312bd82d9f498976b28765bec3e79153ca76f644f04ef14dc001b000000000000000000000000000000000000000000000000000000000000c001a0ccd6f3e292c0acaea26b3fd6fee4bc1840fd38553b01637e01990ade4b6b26d4a05daf9fa73f7c0c0ae24097e01d04ed2d6548cd9a3668f8aa18abdb5eca623e08").into(), - hex!("02f901920a820112830c5c06840af2724a830473c694a062ae8a9c5e11aaa026fc2670b0d65ccc8b285880b901245a47ddc3000000000000000000000000cb8fa9a76b8e203d8c3797bf438d8fb81ea3326a0000000000000000000000008ae125e8653821e851f12a49f7765db9a9ce73840000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000564edf7ae333278800000000000000000000000000000000000000000000000033f7ab48c542f25d000000000000000000000000000000000000000000000000564ca9d9ed92184200000000000000000000000000000000000000000000000033f656b5d849c5b30000000000000000000000004049d8f3f83365555e55e3594993fbeb30ccdc350000000000000000000000000000000000000000000000000000000066609a8ac080a071ef15fac388b7c5c9b56282610f0c7c5bde00ec3dcb07121fa04c64a0c53ccea0746f4a4cf21cf08f75ae7c078efcf148f910000986add1b7998d81874f5de009").into(), - ]; - let payload_attrs = OpPayloadAttributes { - payload_attributes: PayloadAttributes { - timestamp: 0x6660938b, - withdrawals: Default::default(), - suggested_fee_recipient: FEE_RECIPIENT, - prev_randao: b256!( - "22e77867678dc60aace7567ee344620f47a66be343eac90a82bf619ea37de357" - ), - parent_beacon_block_root: Some(b256!( - "50f4a35e2f059621cba649e719d23a2a9d030189fd19172a689c76d3adf39fec" - )), - target_blobs_per_block: None, - max_blobs_per_block: None, - }, - gas_limit: Some(0x1c9c380), - transactions: Some(raw_txs), - no_tx_pool: Some(false), - eip_1559_params: None, - }; - let produced_header = l2_block_executor.execute_payload(payload_attrs).unwrap().clone(); - - assert_eq!(produced_header, expected_header); - assert_eq!( - l2_block_executor.trie_db.parent_block_header().seal(), - expected_header.hash_slow() - ); - } - - #[test] - fn test_l2_block_executor_med_block_2() { - // Static for the execution of block #121057303 on OP mainnet. - // https://optimistic.etherscan.io/block/121057303/ - - // Make a mock rollup config, with Ecotone activated at timestamp = 0. - let rollup_config = RollupConfig { - l2_chain_id: 10, - regolith_time: Some(0), - canyon_time: Some(0), - delta_time: Some(0), - ecotone_time: Some(0), - base_fee_params: OP_MAINNET_BASE_FEE_PARAMS.as_base_fee_params(), - canyon_base_fee_params: OP_MAINNET_BASE_FEE_PARAMS.as_canyon_base_fee_params(), - ..Default::default() - }; - - // Decode the headers. - let raw_parent_header = hex!("f90245a071101c6ce251190d11965257bf7f3b079d5af139a80ec1d2541110ded5da9bd6a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347944200000000000000000000000000000000000011a0df99471388344de2cff6b0ff98f9c66429c94f055d0aa4b96f5c5064c47e8ac0a0ebbb62603141a37336a38057ec8eca40e5aea904dafdff82a93c72d0ab9671cea05064f082249a9a7b00c8fc287a6e943b38ba6fe8e1fdc4bb0c10c89b9286a938b9010088000000c0120200100410c08048120b528040a00000000808840180040800201484b4c800040300208020c0001a08014040004021c0000028108018a980614100494020b00008004e020048800088004088094100094180406000c006564401001400005a00080006c0040348030a400a02810f08060104002410910001000011509000050a8200004000000820000280145a10a84000821000c080110020000404000000002e100090b0840000ac2214042040002024084081102800100010d1009226090008900820828280002400808d83a20000187001036005294c60085445800b8000410000a00200c1b19470000000049001052600300100020108808084073730168401c9c3808321106784666239e580a0d8ecef54b9a072a935b297c177b54dbbd5ee9e0fd811a2b69de4b1f28656ad16880000000000000000840392cf07a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080a0fa918fbee01a47f475d70995e78b4505bd8714962012720cab27f7e66ec4ea5b"); - let parent_header = Header::decode(&mut &raw_parent_header[..]).unwrap(); - let raw_expected_header = hex!("f90245a0e2608bb1dd6e93302da709acfb82782ee2dcdcbaafdd07fa581958d4d0193560a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347944200000000000000000000000000000000000011a0c8286187544a27fdd14372a0182b366be0c0f0f4c4a0a2ef31ee4538972266f5a08799d21d8d3e65106c57a16ea61b4d5ad8e440753b2788e1b8fdec17d6a88c72a06de5e10918168a54b43414e95a4c965baf0bf84c0c11c0711363f663a76c02b8b901000220004001000000000100000000000000000000000010000004000000000000000000c0008000000020001000000800000000000000200200002040000000000000080010000809000020080000000000040000000000000000000000008000000000000000000004000000020000200000000000000000020100100008002000000000000000000000000000000000000020000020000100000000000000000000001000000000000004000000040000000000000010000000000000100000000000020000040000000000000000000000000000000000000000000000000000000008000000000004000000000000000000000000081000000000000000008084073730178401c9c3808306757184666239e780a0d8ecef54b9a072a935b297c177b54dbbd5ee9e0fd811a2b69de4b1f28656ad16880000000000000000840390bc3da056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080a0fa918fbee01a47f475d70995e78b4505bd8714962012720cab27f7e66ec4ea5b"); - let expected_header = Header::decode(&mut &raw_expected_header[..]).unwrap(); - - // Initialize the block executor on block #121057302's post-state. - let mut l2_block_executor = StatelessL2BlockExecutor::builder( - &rollup_config, - TestdataTrieProvider::new("block_121057303_exec"), - NoopTrieHinter, - ) - .with_parent_header(parent_header.seal_slow()) - .build(); - - let raw_txs = alloc::vec![ - hex!("7ef8f8a01a2c45522a69a90b583aa08a0968847a6fbbdc5480fe6f967b5fcb9384f46e9594deaddeaddeaddeaddeaddeaddeaddeaddead00019442000000000000000000000000000000000000158080830f424080b8a4440a5e2000000558000c5fc500000000000000010000000066623963000000000131b8d700000000000000000000000000000000000000000000000000000003ec02c0240000000000000000000000000000000000000000000000000000000000000001c10a3bb5847ad354f9a70b56f253baaea1c3841647851c4c62e10b22fe4e86940000000000000000000000006887246668a3b87f54deb3b94ba47a6f63f32985").into(), - hex!("02f8b40a8316b3cf8405f5e100850bdfd63e00830249f09494b008aa00579c1307b0ef2c499ad98a8ce58e5880b844a9059cbb0000000000000000000000006713cbd38b831255b60b6c28cbdd15c769baad6d0000000000000000000000000000000000000000000000000000000024a12a1ec001a065ae43157da3a4f80cf3a63f572b408cde608af3f4cd98783d8277414d842b72a070caa5b8fcda2f1e9f40f8b310acbe57b95dbcd8f285775b7e53d783539beb94").into(), - hex!("f9032d8301c3338406244dd88304c7fc941111111254eeb25477b68fb85ed929f73a96058280b902c412aa3caf000000000000000000000000b63aae6c353636d66df13b89ba4425cfe13d10ba000000000000000000000000420000000000000000000000000000000000000600000000000000000000000068f180fcce6836688e9084f035309e29bf0a2095000000000000000000000000b63aae6c353636d66df13b89ba4425cfe13d10ba0000000000000000000000003f343211f0487eb43af2e0e773ba012015e6651a000000000000000000000000000000000000000000000000074a17b261ebbf4000000000000000000000000000000000000000000000000000000000002b13e70000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001120000000000000000000000000000000000000000000000000000000000f400a0c9e75c48000000000000000020120000000000000000000000000000000000000000000000000000c600006302a000000000000000000000000000000000000000000000000000000000000f5b3fee63c1e581e1b9cc9cc17616ce81f0fa5b958d36f789fb2c0042000000000000000000000000000000000000061111111254eeb25477b68fb85ed929f73a96058202a000000000000000000000000000000000000000000000000000000000001b4ccdee63c1e58185c31ffa3706d1cce9d525a00f1c7d4a2911754c42000000000000000000000000000000000000061111111254eeb25477b68fb85ed929f73a960582000000000000000000000000000037a088fb0295e0b68236fa1742c8d1ee86d682e86928ce4b32f27c2010addbdb7020a01310030aba22db3e46766fb7bc3ba666535d25dfd9df5f13d55632ec8638d01b").into(), - hex!("02f901d30a8303cd348316e36084608dcd0e8302cde8945800249621da520adfdca16da20d8a5fc0f814d880b901640ddedd8400000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000002d9f4000000000000000000000000000000000000000000000000005d423c655aa00000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000eb22708b72cc00b04346eee1767c0e147f8db2d00000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000769127d620c000000000000000000000000000000000000000000000000000000000000000016692be0dfa2ce53a3d8c88ebcab639cf00c16197a717bc3ddeab46bbab181bbec001a0bdfb7260ed744771034511f4823380f16bb50427e1888f352c9c94d5d569e66da05cabb47cf62ed550d06af2f9555ff290f4b403fee7e32f67f19d3948db0dc1cb").into() - ]; - let payload_attrs = OpPayloadAttributes { - payload_attributes: PayloadAttributes { - timestamp: 1717713383, - withdrawals: Default::default(), - prev_randao: b256!( - "d8ecef54b9a072a935b297c177b54dbbd5ee9e0fd811a2b69de4b1f28656ad16" - ), - suggested_fee_recipient: FEE_RECIPIENT, - parent_beacon_block_root: Some(b256!( - "fa918fbee01a47f475d70995e78b4505bd8714962012720cab27f7e66ec4ea5b" - )), - target_blobs_per_block: None, - max_blobs_per_block: None, - }, - gas_limit: Some(30_000_000), - transactions: Some(raw_txs), - no_tx_pool: None, - eip_1559_params: None, - }; - let produced_header = l2_block_executor.execute_payload(payload_attrs).unwrap().clone(); - - assert_eq!(produced_header, expected_header); - assert_eq!( - l2_block_executor.trie_db.parent_block_header().seal(), - expected_header.hash_slow() - ); - } - - #[test] - fn test_l2_block_executor_big_block() { - // Static for the execution of block #121065789 on OP mainnet. - // https://optimistic.etherscan.io/block/121065789 - - // Make a mock rollup config, with Ecotone activated at timestamp = 0. - let rollup_config = RollupConfig { - l2_chain_id: 10, - regolith_time: Some(0), - canyon_time: Some(0), - delta_time: Some(0), - ecotone_time: Some(0), - base_fee_params: OP_MAINNET_BASE_FEE_PARAMS.as_base_fee_params(), - canyon_base_fee_params: OP_MAINNET_BASE_FEE_PARAMS.as_canyon_base_fee_params(), - ..Default::default() - }; - - // Decode the headers. - let raw_parent_header = hex!("f90245a00047e5d14e74fa24a08654b49795e57114475fd455689c71c5002f22a39e1be4a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347944200000000000000000000000000000000000011a03a2d37a5619f9cbcb1828a0201e9185b67005131ed6236eac338cf759f0b9ad2a0fcaea4dfdc9c2ab4f0100b5c2fe33fba45c3ebb6a8beb0c156ccbbc901403040a0cde372a52b7bbd47e6fed509c5e43b74bd12a3119bc6a63c311bd00a80d524f5b90100000491006000000040040280000804040000000002010140000400000400004000020000880000200040001000400100000000500200200000102040040000000000000000000008110000080000000000008000004002001000000010004000040500020000000000200000010802000000000000020c010022201004484000000000040000000804800600020000004000000080200008400010010000000000000000000800040000001000000400000000408000000002000020020000007000000200000000000480020036000060002000000000180008008204000080000002082000880000080004000100000004000000080840020000400041040080840737513c8401c9c380830a11a98466627c3180a0c7acc30c856d749a81902d811e879e8dae5de2e022091aaa7eb4b586dcd3d052880000000000000000840395611ba056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080a0a4414c4984ce7285b82bd9b21c642af30f0f648fb6f4929b67753e7345a06bab"); - let parent_header = Header::decode(&mut &raw_parent_header[..]).unwrap(); - let raw_expected_header = hex!("f90246a024c6416b9d3f0546dfa2d536403232d36cf91d5d38236655e2e580c1642fdbaca01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347944200000000000000000000000000000000000011a01477b41c16571887dd0cfacd4972f67d98079cbaa4bf98244eacde4aef8d1ab7a043ab54ba630647289234e3e63861b49d99e839e78852450508d457e524eed43fa042351814b43a1a58a71fdff474360fbb9e510393764863cb04bde6fd4ca0367eb9010008408008c6000010581104c08c41068c8098020012402058d084a18a6408012213000000b02000000000102020800040202162c0424210820040e0405020215810c200800000000001a1000c480044002500011480822041080080c60e001840890a20850016240003012540010060c82006058024020014005480118000040a410c400000260800900000030004486a0820000c884400038060c08981201010322c060008200022100008195004cc082001049028d80000088000000000d402410030020080a102c2e00e1e141000044000208240045804001008018000800041110c1d0a4222056000201500806200190400049851890037500ac089c3000080840737513d8401c9c38084019fe25b8466627c3380a0c7acc30c856d749a81902d811e879e8dae5de2e022091aaa7eb4b586dcd3d05288000000000000000084039231b0a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080a0a4414c4984ce7285b82bd9b21c642af30f0f648fb6f4929b67753e7345a06bab"); - let expected_header = Header::decode(&mut &raw_expected_header[..]).unwrap(); - - // Initialize the block executor on block #121057302's post-state. - let mut l2_block_executor = StatelessL2BlockExecutor::builder( - &rollup_config, - TestdataTrieProvider::new("block_121065789_exec"), - NoopTrieHinter, - ) - .with_parent_header(parent_header.seal_slow()) - .build(); - - let raw_txs = alloc::vec![ - hex!("7ef8f8a0dd829082801fa06ba178080ec514ae92ae90b5fd6799fcedc5a582a54f1358c094deaddeaddeaddeaddeaddeaddeaddeaddead00019442000000000000000000000000000000000000158080830f424080b8a4440a5e2000000558000c5fc500000000000000050000000066627b9f000000000131be5400000000000000000000000000000000000000000000000000000001e05d6a160000000000000000000000000000000000000000000000000000000000000001dc97827f5090fcc3425f1f8a22ac4603b0b176a11997a423006eb61cf64d817a0000000000000000000000006887246668a3b87f54deb3b94ba47a6f63f32985").into(), - hex!("f8ac8301a40e841dcd6500830186a09494b008aa00579c1307b0ef2c499ad98a8ce58e5880b844a9059cbb0000000000000000000000004d2c13fb1201add53b822969231de6d1b0235f1e00000000000000000000000000000000000000000000000000000000049ac5a037a0c66b4526837e93e8d20bf5d378f060c5d4bbf5f6aee41be55598255083c1ff71a02fe196d9fcbd0980017d7d77c2c882c0851c0b06b59753bff54f8726e74870b9").into(), - hex!("02f901720a8203a0839896808407270e00830213d394e592427a0aece92de3edee1f18e0157c0586156480b90104db3e219800000000000000000000000094b008aa00579c1307b0ef2c499ad98a8ce58e580000000000000000000000004b03afc91295ed778320c2824bad5eb5a1d852dd0000000000000000000000000000000000000000000000000000000000000bb8000000000000000000000000fcd04b8f8e8ad520e3c494b6b573f49ad4c9853d0000000000000000000000000000000000000000000000000000000066628a400000000000000000000000000000000000000000000067aa2de076064cbc00000000000000000000000000000000000000000000000000000000000003b20b800000000000000000000000000000000000000000000000000000000000000000c001a04c85fb7e9c041376918b4b3c2e520f0973a564cace5e49929f829236bcf45dcfa01a7d82fe70bf54633ffe3e69f238641695914c4e400c62de8f023b788b29bda0").into(), - hex!("02f9016f0a018312dbe2840ab59b9c826fe99464812f1212f6276068a0726f4695a6637da3e4f880b901045b7d7482000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000004061653166346133333163313166333033623161626232376237393434633435616564326533653137333033366638626237633439353036613135333934393436000000000000000000000000000000000000000000000000000000000000004036616438623264376631333764363166393864613961313830316133353564383237303137666238663263656461343739333062613833353739616636646436c001a068b105ac4576560ec0e938d20b5b4cf001d161729597e7db17205238f4277629a059199bac24b6a7dfc08a3b3ab471d2052a64d367190b078fce60622fed4507b1").into(), - hex!("02f91eb30a83039c68830d59468407381b7c830961bd94087000a300de7200382b55d40045000000e5d60e80b91e4482ad56cb0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000420000000000000000000000000000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000009e00000000000000000000000000000000000000000000000000000000000000cc00000000000000000000000000000000000000000000000000000000000000fa00000000000000000000000000000000000000000000000000000000000001280000000000000000000000000000000000000000000000000000000000000156000000000000000000000000000000000000000000000000000000000000018400000000000000000000000000000000000000000000000000000000000001b20000000000000000000000000f7bd944cd6d51a8b7dab54785608d8bda08f91550000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002446a761202000000000000000000000000dc6ff44d5d932cbd77b52e5612ba0529dc6226f10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000044a9059cbb0000000000000000000000000ed78ae2a0800d6395cf9e311659323bf2822c5600000000000000000000000000000000000000000000000029a74ba63dbfdb780000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000411506c3fea23c087ecd0605c103b3dc00eb380f2d4fa9a0d93c983074f53398ed1e558cd371b8704be8a1ddfd012027853bb1d2fb0599242ea4bd92ebe1b1d3c41c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000314c9258a47fcaf9a59a0eb2e02d8b503dab09840000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002446a7612020000000000000000000000007f5c764cbc14f9669b88837ca1490cca17c316070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000044a9059cbb00000000000000000000000090768aea66779f77f8e11f33ce35f3c0d0814617000000000000000000000000000000000000000000000000000000000366f270000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041ff3a97fcb63be58074d66c191d1a808ea49a1ec6a10f82fdfee5039f8c79425822362696b8a2792140275cd76e4df87c51b84e255390449fb00ac885706d3e4f1c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c7271b6dafb7adfccebc04a1c05160c11cc37860000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002446a7612020000000000000000000000007f5c764cbc14f9669b88837ca1490cca17c316070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000044a9059cbb00000000000000000000000023d640c90786e477226915473fe6fe354ecd24e30000000000000000000000000000000000000000000000000000000000d9a926000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041b555110518c88b56869792d167288b73f0b7a2789f0acc257208973d6f365d84266d67c697245198d433bf8802d56f9147264f8769b5f82f00e66fbb0bf55e701c00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006b3c6afc0a5cff7c98db387d3b9bea85fb2209660000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002446a761202000000000000000000000000dc6ff44d5d932cbd77b52e5612ba0529dc6226f10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000044a9059cbb000000000000000000000000bfde6228d74d163a4bd135395249348719d55b1300000000000000000000000000000000000000000000000029a2241af62c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041dc55a561f8ea7fab8b964c186e44b4d3c71fcfdda44cb37cc8c457ab53e081aa40a10c51841c5e8959525d82f08b115135763d3f2d51f9d6f928f040cec64dcb1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000036db1e5d1a94acd2349a21db1c3c5699995f1110000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002446a761202000000000000000000000000dc6ff44d5d932cbd77b52e5612ba0529dc6226f10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000044a9059cbb0000000000000000000000005dff975994c962195f0d909be53a9c5d13c398c500000000000000000000000000000000000000000000000029a1814e46c1d000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041dbc3b402f947cad5e317951d6ba00ef6d1007f8617ee304dd251262dd949018b64b794f00c0a21af7eb3d769b4fbf6655057105b1a5c157dcaca92596808197c1b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001f764262a8d96239275b6955f1b0c2e490e78dfd0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002446a761202000000000000000000000000dc6ff44d5d932cbd77b52e5612ba0529dc6226f10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000044a9059cbb0000000000000000000000008f0ac647326c6deb5b355fdd49dae8bdd496708e00000000000000000000000000000000000000000000000029a2241af62c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004168c74803581ceeee1233a6aa181da3ef1a015d7518333a9f50fd2d16ca2f1b30192406e7d61899c2533779b472d74cd686a3ff6fb903e60daf1abd7018f68b151b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000cbf74b5e15404cdc8d8391ffdbf2cd48971a20bd0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002446a761202000000000000000000000000dc6ff44d5d932cbd77b52e5612ba0529dc6226f10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000044a9059cbb000000000000000000000000a89182e4e2aacf3de24dc8c2b571714dab6508fd0000000000000000000000000000000000000000000000000001c7a82708500000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004151574458788fe9f96885b496f5621ff074a16b6c5e3de9f306ee2f88cbf163a95eea1bf4f79caf0771120d77b43093166e064edf80aec596909541aabf34cb551b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005fa18acc756d83ce08e0dd8db44b62b904190e30000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002446a761202000000000000000000000000dc6ff44d5d932cbd77b52e5612ba0529dc6226f10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000044a9059cbb0000000000000000000000000ed78ae2a0800d6395cf9e311659323bf2822c5600000000000000000000000000000000000000000000000029a2241af62c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041704047cfdb2bfe65bf969675594f0d2da7eaf951b4d57144af5351f17f8e9b81442eb2d58ac78c29331a1857cb270b5736ac65c7f450c2500ab423fc00d47f5e1c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000090a32be26009dfb0a36b3be2ec9f50a9fa0bf2230000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002446a761202000000000000000000000000dc6ff44d5d932cbd77b52e5612ba0529dc6226f10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000044a9059cbb00000000000000000000000055d8fd11958a4bfb4ea341142eb002f66c6ac6e80000000000000000000000000000000000000000000000000b7d5107b20f30000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000419fa97b385e50a1044ed62550e1e3f4960ca1e5f953c3c07458cef234151f7ec7191bcca4a46ac285fea9cbad1be1d86b4d11ac44584c292b2dfafc4e68d512301b0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000dea125ffc58cbfc448654b9a7697aca7501e5a2d0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000002446a761202000000000000000000000000dc6ff44d5d932cbd77b52e5612ba0529dc6226f10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000000044a9059cbb0000000000000000000000001a466a1a1195d9496f5cff39b881225525769a3300000000000000000000000000000000000000000000000051766de63f8b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004106404715a55eb449609a6b0f8720a68996a0072d894ed6fcfff3ff9d9590bb9561b43c3b1384619d46cbac842dae9309a91e636d03e67e8c6c9046dc00791a351c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c080a001cddc6970b581a8ddde9a548e83b23071bd2a59c3004d14fa513ce9d8b8860ba016e1c19a70c6f988873b62d499e9f4b827cee51874e1b8538be2bedd0b81215d").into(), - hex!("02f8f20a8222468307a12085012a05f20083011170948c7c2c3362a42308bb5c368677ad321d11693b8180b88497998611000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000006168adf58e1ad446bad45c6275bef60ef4ffbab8be412ce3e5a692d0670703e8e56d648a33e80a6d4920166ba42d14ccd4eecda2c001a00e5583d7ac97afd3232bd3deed40c2c3c085b06d73e3ab0d5ceb77892219acc3a0491b2927fcbc3b82165428a5a3d532611792e19506db542d00c90b994782ae8f").into(), - hex!("02f8f20a8215a28307a12085012a05f20083011170948c7c2c3362a42308bb5c368677ad321d11693b8180b88497998611000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000010000000000000000000000006168adf58e1ad446bad45c6275bef60ef4ffbab8be412ce3e5a692d0670703e8e56d648a33e80a6d4920166ba42d14ccd4eecda2c080a0be21db9df84d991bbc0d0b062553ab76be037059aff7fade639d536dfb0c03f1a04585c3272bbdce40e55637cddf1ef8797f07b875bdf7364f23526cbd87bf0872").into(), - hex!("02f920340a83026c9d84039387008403938700834a420894087000a300de7200382b55d40045000000e5d60e80b91fc482ad56cb0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000003e0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000008200000000000000000000000000000000000000000000000000000000000000a400000000000000000000000000000000000000000000000000000000000000c600000000000000000000000000000000000000000000000000000000000000e8000000000000000000000000000000000000000000000000000000000000010a000000000000000000000000000000000000000000000000000000000000012c000000000000000000000000000000000000000000000000000000000000014e0000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000019200000000000000000000000000000000000000000000000000000000000001b400000000000000000000000000000000000000000000000000000000000001d600000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000a9aa45a7df41841e834bd0b1204989d7350aee2b2c539b84e65786fd42064fe72d5ba44e1434f5f3ed3b54cc15a1c1ed3f7d9bc7019c6b6fe6e4e18ffc69958a529c2b591dc978f1f1fac89108ebb460dd64903007706afa5c18f7e101f5757aa975a0bd584a75abf25c55721448a13a1d7280590e308fb0b2029032f838d15d12c0bc116f5f911f3c8a6fb992fa93e45fad91bf19a99eb9cacb5c76526d20f47ed7c6db5e32dd92c0b745ccb9bbc60f268a9ff82c53a0fb1ccb463a855fc6cf2fd322ce37f6aaf65096796b8a29540cf36d478d0e3baba70eac1d51f5518851a537a13978bb25a201790912e54a984562bed7151e6431b5623237b5f5c32cc6b1ed693ae159add9d421339d5db513b70e75d1861fb904a42b34762f03e4a515c63d0c25354f00a0cc89c9ab0d985aa4cf37069424604a41736425729dc3f234370a2ea89d701ec1f76934f566f7d479732e69a1000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000e115109f26205ceb8e28e227bc58a3cf500f8c312c539b84e65786fd42064fe72d5ba44e1434f5f3ed3b54cc15a1c1ed3f7d9bc71e7d290b46718f2eb8d8e47226b21529466aaa10cd18a76484854a78f735141d1e8111cab1c7cd5eb38dfc4aef92dfdb93a64426ddc0222fd5e4a30f989ffaeb0b5217bcb6d582638442705a158d57df4fe0dd4cae0fef3d7ad656d7c8f64aca10c16864fa9cbe4a423afaef0621a00c178e4b4e690472ffe82b76448ff2735d2a255341036d70a0df129fdbae5667947d4807b7e8128c1ce8344f71bb21510a2f63ece569a0d9aa4e77689965b08130141ba88f79e4770db8e6348e8fe03a3210ecced6257dee3d31fbfdde243940ab556f4740a9b5c20edc4125b2b843062f2a1bfe066ac56f7b6de17fb5816deb8c4345ddedf1260b6146d4104d8f3f8f200e9c26ca19f5ac327559d8a3c3ad2366014cd76432b74af62011c00bf564462a000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000999bba23dac348a9a7169664b1149abc0783d67c2c539b84e65786fd42064fe72d5ba44e1434f5f3ed3b54cc15a1c1ed3f7d9bc7177c60556fef8e41a8b3329838e6aba09df2f82fdb1eca33052df7e38516d68d256db0c7796da2b2fc508bcbc5f135afea7588df794a545eaed6e2a8c791b70b04df92e213d8956be5a9164606119114680a471eb091a3f8ba21b997d2b967bf2477689decfc4e8af5a2002725f656e731460120fa9795ec4a01517eb3dc5f8d138d5b1205eb28403be5c2ec1dae214c33b7e9837119da90ff45b858b23971b023148beaff65b4da6384a9354c3462896f10721015e66c28fc14ebb06d21d4af0dc09412a48d63ef25c92e7747d8142f2fa3e5368bee92360baeccfacbb49c9918f8266ca3596d83c00c23ea40db624ab0ee8e1b17e4d4744f5e45f19f18f45e0ce91a2f8105d523c35d89c4be394b0a64fec4a3ea0c5eafcee89e5b10fc9a5f000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb00000000000000000000000000000000000000000000000000000000000000230000000000000000000000005f10f62a0d4bd4bb7c229aab031ae51c6ac31d542c539b84e65786fd42064fe72d5ba44e1434f5f3ed3b54cc15a1c1ed3f7d9bc7278fe9a6b6739901d9f2b36a9f4d9208744200ee37eae1905510be82e4d810a5098b7a0ae27ff42906e48d329011e42fa8f1640a183b6e0cf7467d7e429916c71ac1420326dac3098492a3e0244f381e68abedb76655a76d09f38ccc7bdae56c1bbf7de4b909aa89d6a4e5cb93cc5a201e287364d4d42d183dc278aa73f0e6201344ccaf60ba33412c9267ba2374741fa07d9438f6a30a87a551d71de792269816de70f0e23d5fc7e6f6561d813573ba8500990cadd54665619eb6f115ee1dbc1f9630be6dac5e1b5c37ea14f8082ae57f43fa3b2afbedd445134f15d62320782cbeed48f54ceda94c43de4f0e90e3ad9b37342e7b0a54105b65a045d00841ce2fabb7d092bba29ca228ae95f8ce51af403a152c4871d4dfc27166eb8f35269f000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000a30aa37128a2119ab89652914a30a956eae35f9a2c539b84e65786fd42064fe72d5ba44e1434f5f3ed3b54cc15a1c1ed3f7d9bc70b299790ba04716ba16479689195094d269b626c97827cbeedcbbb8c516efbd40e5c1120d26b239abf8d1db317c8ccf6d99ff9fda34bfab8d077bfbd6497e1fa2e2d657dd11880e5ff8e2fb7bfd3ce3a33b341fc3de41f32c05c87d0e7bab105139becd8882b7d141e1c84c3496287792d7613a544e08d32cd87c8dbd36272c426846de45ccb93788060a164a0cc2a91cfaa73d596b68633a7c8e885c47cd10e1e7c6a9d390f1d2b353e4cd439c464d05c4783d046777db2c35f122e1e1c028d20b9e2a27f1a4a23ac6688c1d31703d25ee805fe5d0df9d201cab8f87868deef149dae6283ba14246b2606dec37d0b6c16cd7bcaca1fed9d9613da85aec75f312a9834a01c99568f050a78c45097ecfb76145cf125cf0d2103f27634786891ca000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb00000000000000000000000000000000000000000000000000000000000000230000000000000000000000007fa4b114d2d14b89dc6515399ae09fe2d7441b762c539b84e65786fd42064fe72d5ba44e1434f5f3ed3b54cc15a1c1ed3f7d9bc72a508522071abf0a3f074ed3ca628e4bcef7a1efe3db7ce2ea732c4f25a9f235293fcd7e88604cac4348079c347a4ec2cb0345660c2c3a7e79729450bb93483c185a64e9bcca1daec006367472d8b8ed5d429afb7c47d0a8d1252c7ea00809e329d02d5c8e4db2911db0693cb4c36a51d7e79f746d7582ba3cb27603c5394ba52e728b48ad38d788966430d1a62addb3faf3613b5e547ed4b71a1da0631b7e102cfaa1b8d91ecd1fab6eb138dd96b16b29b5b45d0a6208e1a9f2197c69f83be92558be565b70dcd0dac3eda3e02431e3a6c03bfd23a5b79efbd2cbd144cdcde129fd53821de617048263ca17984db238f09c0486f092214f10911e00b7a85c2205fff76cb75d2a35ed30daa89384c8b208d486f47ce93fe45f62c594e23971c3000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000a2f059c5e329560a7f4ae4472ee4097f015df1d42c539b84e65786fd42064fe72d5ba44e1434f5f3ed3b54cc15a1c1ed3f7d9bc715cfd4d9061fda04a7ff4c66cec0d2d482201b9f4a1117548d313ef0bf3e189300aec46572ae69d07eaf083cbde723b162622e228bfbbd8eed01d3c791650d3d1feed6991f37c930677e9838458b9ef5e9738a836bffa3c7a86ec6bf9e6f67772741d5cb21d1c97faf6e102f9c0bb15e32db77e82bc51b760c70a1f32979ce8a23f841593456260fa50974347c4d80710157b7577d02e16e771664a0ea8bc19512c5898cc28345b1822234a99f2145b1980e9ccfce18329a494fc596d1697aa7116cc2a22f1bf3db13f0039a69a1d0415671a6140ea4753473ef2c4429e6f39d1ba1bbad2945740fcd828cb427ce598127fe4a740e4a76c090a14b7a86341c4b0e812956c081103d37c667d654b881f1abe74f167c6bdfa656b388d7990ac25b000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb000000000000000000000000000000000000000000000000000000000000002300000000000000000000000074c5d8389e56fc119ebc9e013cc1f7684d5a6b072c539b84e65786fd42064fe72d5ba44e1434f5f3ed3b54cc15a1c1ed3f7d9bc714a09e53d385d673c05228ddb26d7bc3be74f7a103f196567e2968287dab7a8b19aa753e75a75af73cce0bc21eaa8caae77d61af896d0159f6bd9d6c42d1a1251452e4f3b8058a3fe140472133d79b9bfffac66782355a9429255ea98c7a66b62c70a2a680fdce54eafba7e09739dc906327abcfb0199237dbfc28e9499b846216e3242c42fbb9848519d25efd11e8b30e873250186e0b2321d4af000f6e5e372c58d70a568f0d3e034e4aa5c1c8538c5ff07c1deccf3b779f371fde322d468c21d3295fdcadd60fe4ea1267c0792f7276b9f56429776e63c4f38b1ba75cd9c826c9904b4b750cd0a0d133969617fbda3046108e543d227a43d4f11d7662a0cd097a462190a390f639bb3c7df415150a25e7de70a8f58ee40650aa974cf16e3e000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb00000000000000000000000000000000000000000000000000000000000000230000000000000000000000003a1917ef1b997b9ecaadea9fc836c40fc5a158612c539b84e65786fd42064fe72d5ba44e1434f5f3ed3b54cc15a1c1ed3f7d9bc71c711c12d07372deb6db123d4824f3ca1cccc452a89efa11b3fed5058d46263a28bb748862ad7b526192f76868aa2656248114f1fee8fc90b75fbbb0e399c131001f9c1d61b55c1479debc9cc5db22c2eb10a4141b952bf0e8ac51bf348fa0261fd0e8307a84500bf3a3511fcf55a04ad6bbf02e84c1602d1c8eab8269f5ca711819dd95e0eedb673fad82e15193673bd88573e883738c6384d6d7661dc2b3461407f83a9c96a0e61577c5f150ba93cb2309b88c77313db9580dababaf158a45085b16d533ad5b2d9d3f30b40eb653873f5f76e4d951c5a2dffb07b5b1831b22105c3325d94010e6a83488b7593452d8ab85f604b0d5c9349700b869215d4d922a84ffb448ddb0617857497f7a791fffbd68a0ca6536c5e6fe8e9df64e90f651000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000b319c3d1ef0f60c6e03085ce397aea2f2bbed99d2c539b84e65786fd42064fe72d5ba44e1434f5f3ed3b54cc15a1c1ed3f7d9bc7210c111ef03da72d83a899c671cf0d97a47205c0a462f206a5f8012870d75358247af48699c9c38cc36f280beef3e6b877a4ff3ddbb32881bded52bb7108a0df06f4fae4d32d4273f2beee224f1948dfc1730cea292baaa5391fe74f2a9cea702c013d1895ec1e8351f858074bfd57cd5c2bf13333d83df8d984ea144ae1650c2a8172d6f6523db18f407bbde01c23a218dc6280569b50b7b1ecd1ead768f82416bc1eda96770b4542e34e1dcf955ab3433af90036b78dfaf3d4513347301947026626c780884600afe5203fa9e8b15f6e3a72afcd4ebb9c068e57497e64c2920efef1c8b2187d434511572a803a2b8aaa35edd9658f0f10f681a10d251398dc149c1620acf0e50c8479680a199a24e0db6055e5c5227e780b60073eaefcb95c000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000f5da1b574a7675327d1b7339ad9570363c5c34ef2c539b84e65786fd42064fe72d5ba44e1434f5f3ed3b54cc15a1c1ed3f7d9bc728efef1c7cf6964407aa9cd0a21a2618b0b55d4e32e9713d47845be6a155712f164b5b65121455d7f647d5bc8314800fe4ce5179f1d1dfad006418f047020b36007b623ad50378124af98fab6274e64b1312650613ca19eac7eb89376971ec80280faca31d2fe889ae7a9ec4ae12f4fb8e7bc3b6e52110cc696397a4c289de6206bce497ce7b5fb9f23365ebebda365848486ad94136bce4c3e46810622c75b51cc40fc25555def1b8fda690461906dd3659a3e2450335b0af27a30c808158272934cb5d306306fb6b9e35677dacdd71fff28e8cbb85459d2a299b1eef4653ee176c207195dfe7c2660a74cebcbfe901bb9411c60fc50b78ccfb92c8036759851b136cd186aaa78f6f4c21a82f5445660f5175347a26b8a4523d4efb5f5f7fbd000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb00000000000000000000000000000000000000000000000000000000000000230000000000000000000000009b0f286627130086f85f63177421ea1b2cd9f0112c539b84e65786fd42064fe72d5ba44e1434f5f3ed3b54cc15a1c1ed3f7d9bc715c82da09b1c96f513aae1a7f168c2f9fc77553cc19b4e0ec50f315d2f216c5d1fbcc5b43a01f2e4b53f4b6e7634599e9e516cde0f4b2d502893f7d66c843e2b2500e467e437a3265e203c19d92abbfcf1a9609c1b5b736cf249424afdf3f4d71f5d87add3acf628b1b8068b188277bf2d2aa87ddf10c8408079e40fb11468e011ec157bba5ecb886d5e05b05f225a5bc39f09e1e0a0bdbbd758c04ea304d02103ceddb427310d24f2f4e9f416f962e2c3efc58177fb7441150bd292896769b506a99097e337947e5a5019ffabbf2483d2867167111b3570088c1f4f5ba6b77b0798fca770007a70dada02aa9e6eb42d8c547faf5b53e75a8183bca5a40449a2209a2b54939c9ac7fcb528565001890ccf1c8f0d4fe7fe8c513eca3989a75b31000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000b5950dc266f30702248335d8f6bf4f8950b77ca22c539b84e65786fd42064fe72d5ba44e1434f5f3ed3b54cc15a1c1ed3f7d9bc72e937b4950068a3aacffe5a9841739e89c7f72706107b62109da41fc5e6a034113e6495faa3c3c637292220714a0ae733f54257ecaabe7bfa3658cfd10d33353089879446d6f6940e41786eae92d9862537549f1849a0ea652a3245f1e3c16080dfc882056e6e363bb516d39891fd50c297dcbdf20119721f80a77a57d15d51b29e4b31981b4bbeb71619bdd77eb7c74000573d6458a1ef3078ddd174138456e29bdd12d6b0531ee54f8c28d36fa55a17f818deee78441bdf5d2b1224687100a1221687757fe803d8ec441e2eec6a84abace83df3a8751f8b3456587182ac83b21c4730a474697036174b1277d3a1e8f68d424f46f72286c3871b4ed98a283a117d60c47aacd44384fd49ef3cc22d3d076d332783f8fe111f19ca5e5b92f4996000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000920c45b408f6a0c08c4a0481541acc5336e4beca2c539b84e65786fd42064fe72d5ba44e1434f5f3ed3b54cc15a1c1ed3f7d9bc70cfb4bd66c6dc2d7cd7c104893f0a9bf073fb3144f672bb9ed1eb2dee72e39d20bbb1ba1a071f453a92bc1524762e9f7a6d4ffb918d56a059165bc2df45364212fb7c74a2cd0a4acc230c9875eb343747844b8abf20d0e6d5ba61351d73fa7b41de3d6d85f4ca9e199bffec3360f89955df46dd9ba41e23b7c7478cf3d31fe0707dbd1c40a18e480905899ff851dd2a38405c8374b362f64012192a6b2caa3db07611d351c33da2e7b9d5dbc9880a8ed60eaced742390f5d97a1dcd4b87b6ad02d1b929053e54ba0a221038c7ecada4afb36205305a7750fdf978b0ba49904fa0ee6e8fe3627a001814f99e01c80549a424ec106187ac0bf6331065bee11b7641b6f8570d85a3f531205dc5fb5336a1c8bfc708a2cf6b9378e7cc6f8e075e76100000000000000000000000000000000000000000000000000000000c001a0537050b3611333491c79373e0026e1ecf8582a6cf5d82a9318b4ba9b1c82a5b5a053127290f0a4f4a3dcf8cfcbf1a874471b0eefa1ac8cf0e3b4ac97f58f5069bf").into(), - hex!("02f920340a830269c2840393870084039387008349cf0194087000a300de7200382b55d40045000000e5d60e80b91fc482ad56cb0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000003e0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000008200000000000000000000000000000000000000000000000000000000000000a400000000000000000000000000000000000000000000000000000000000000c600000000000000000000000000000000000000000000000000000000000000e8000000000000000000000000000000000000000000000000000000000000010a000000000000000000000000000000000000000000000000000000000000012c000000000000000000000000000000000000000000000000000000000000014e0000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000019200000000000000000000000000000000000000000000000000000000000001b400000000000000000000000000000000000000000000000000000000000001d600000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000ff5b81c06a347cb8268210e970cfb650fa76137528942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae629a1fe61acc415f47fb1df4678c0aafb8977b62aef6325be11f3c26eb36ed5a825acd8d663439a51e60752dd4511d9af15c89ef116130f74c7f10eca596ecbec245b30414b0c4b95e72d6094ce22cfd7ff21ab7de7ec918182b0c1c91ae715fd007ccc9e09775420c6e7f1bc73aa8c88520e37d1428b9f792e546395c853f6d5090e477ddedbe861b0841ae47c1edd5619cc919f03fb26cbe2e09183dfaafa7d24b2318f73d8f1426223e5a1380042f598b2ad19caad855685f696c40bc269df1e7de6b1c189beb2603b86d58392a12e4891b3fe197f318da04453bd335049450f38465dc2a05ea81d5032e670331822eeb3d92960885367ea5c913eab351f7710fb70c8c532d5b2257f13dca19e0eac3d506133738244e5db782a73e22b09c9000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000242ab389dea6b46da7fcfba55d6318c1e2fe7d0628942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae624427bf3c4fb33035faa23446dde42edf4b00f2c76d2284e2d589694ca6896961a078f3488fe8ba820e217d4477912fd96b0ceae34a0608b5db519e302f53c712625caca9ac53703531f7ec7572b9b5f80de7160a5df81029bb29f834de0c3740b15818ff91d30b341b30ec6eed99e4e5bc4aed0101c72e092babbe7ca1aabfb0df5294675220069521b1ea0315edc860450086ea1fab8aeae7bbaa84189b84b21af835d67bbd00b61e7c2fc9b3cddd79f927801d369c275b6be3112583457b42056e57c9f86eaf48c30534ee59bbbff72c77368ed4d3be941f5be3bf9f474df07ebcc794c92f409a4bf625adc56b6076100e4c8a04a98e7b7f8d0ed3e04f13f0e9ba6c313ee27196f25ead7314f56d063e7344e9bcbb69cec65d8c5be59b426000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb000000000000000000000000000000000000000000000000000000000000002300000000000000000000000056c9aee5056ef57250fb974ff9bcab45b121dbdb28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae6284b84661b3e7d8247b71e03458b1560b0590094f5e7c7d6b0c340a7a73d950126b8d6826406705cca25312888531e3595769bcb60c783d4699c2c94fbfb88451d9d8daffa3707389dc7b6d951a9e7a3cd0fca4754b570a834634bede4401c3a1858e38e1a0174d26a4134dd4a9ade06b393269fb96421ed6377282a86e3d25601204f8680e2e112771469071db800cff8738193077cf8f5606402056a8d701d116fd6ce2be79eec293fd6aaee23f7b7ad1b500f01025a5439e0caeec5a4c1941b84a0801f23cb5690a38495a4810d6fadaf2ae74525bb9ee60110ccabe1470816b5b742d4b9757a21846410f848aa6acd2ba7b8ffaafcc459f3f465c9a5e5991f03daf0ef1a0bbf2bb8fa6af00517e4e4ffb0883e51531d25a7a5fbe74797f0000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000e426cebd1060d4bdd9051feec88be9403486cd8028942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae61bc3b3a4f2d260a159b623c703b914ea585c4ed2c73484dc1fb362fe5ca8918a0f2b415093c671280a1a9666a4171305736ba04b4c59979668de99eb6207c1aa0ab3e2931eb4d8128bf58ca6b305adb61b8296f15415d1edec109f8757f8644b09bed0a4184379b56cf64300dbf1b79070e76b62cf6f30f3aafdfd2980abcc1a0830d97b570b40c69d246f6690be9a1636350e4da7de3976ca6db1bf61006beb11e407e1049d700a15a3e10cf0e7e12c374c872b7f8a0772d9b528905fd49f2e08cb7dff6b3c7615409135fea859c455400f2471eef275bdedd852ce81f74be9013d4d176587f44cb22e142cfba09332748617bd8df8512e88c9e67b90b2f1fe154f456dc600560a0b214c09e28e7f7848eca56b40269de0e8b4721249a221c0000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb00000000000000000000000000000000000000000000000000000000000000230000000000000000000000007c86c46c5cdb785dc78ba1837e0225e59450b18128942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae602565c1759ddd04a0819a7aa7a96edc3cd222f119d4e6f550d4bda9997ca45c118468ce7b1c6616208a9f0c5857e2bbb96ac51c73a58e0e1d60e1e2adc9ebaf1160ade7456bc61891c670b5b2b6d40ecabcccb3086f4d79e2147b8d4fe889e56169db8287264aed78a3bcc7f14c97501cefeb5ee0fdd6f199a32daa028b8df8b2b982a923d639cec85d15255ed9b91bd19e26dec3da5fe220677f0ad66bc71a30bd2fe84c4ff72057115eeb8fd51c847682b147d429739025cfdf6e26b7ae86a1d48d009ad19300f056540fdfe08de659ac2f6d4f192e3b1bdf6ffb41576cd2b0753ba92215508561aad8c79aa9c34fa5a3506e7ec7fe7645c810c410c471fd12526160d102ff8a08611cfcfa6dadef243c0513f6739550b9ffc9ce99fdb7297000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000641bed5addd2a358468adf163e6c6ebb80b675da28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae60ae86a5c0f75cec4ec7b453be4fdfc134090e99d66bb9390b908782ad550f426039fde3482e025803dcef8fbe6923b6b6af7a046ec975515430d24443aa15c5c2dd3e8093f9cb080600349e51d7e56b5fc6f0ac083da6d63e03e46003a3a379812c6e738e5d34d372a656dd19e8410b8a00aef4cf3a26bb7076f709953bfbdd202ce2b1ffedeba392f9df3b208b6ed2becc3e6d4b3c5593dc93c5a9d8681d1c42fa7327bc880d13029a9213f88529f089da75c30ca2dd52d0370132a03e378f3006a83b97ed66aa961836459b7d4f6544f1550419d493fd534bfe21266a60bae178d3a497e3e9b0d285015e918a625658ca52d21d6a2aa62667fc4d47039a1900e76a537453b72f8adfaf853e04e68c4f27e34eb84623bdc0b3e1be3648eea2f000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000dbea52199557b8fa35a0fd208d7ca2b964c8955e28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae62600f9363c032d201bd8616f84cabc6010919aecce646109b2f807733be53ba8142a9e34992574b9a4a7ece6de4e9ec8fe60b42fa48cb216c242d9ccb49ed4851704c306d9570788730c05ce290d6b5603d3e51c332a9f60c90fdb8cee47076e1ba1bb35ef430c23f2e6100a541864a83e63e3ca07b054a1ffa1283550fca44700e5456abfa56f15552481280c5239d2f3d3822d1a83abe0a973ac3ea2c9647f25b22b68aefc0243277645d2dbb062595c5b0c26aa18a1449a4d25b5d0e1fcfd26dd9c789797d0941377dc1516dd7d4d1912b74636d7a8ec5fbb183ac34d841f0ccb72ffa06c254085208b3554bacf41f623c7d051bd72d814968379f9f53a982292f9b8a2ec73d2b4f33d009b871003c205d71063ef6bc2b810d0e58906322b000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000339cac126a7b5d6807780f9ebc3b5f0a7cb2626b28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae62f3d9e4e7ca68fbe0889f086d9e238b256d57d515ffbd3cd40bf0aca6b0492ec2dc950c2b7d6c026158d109af1da9c32a47380fc0c7bdcd79d61c43bde7ec5fa099f3b2158ef7935587d1428124be6d2777e283e2dc385eb21c037efc7504d550b98049a7454f9b5d51b96179d8b08d74c65ee27e6efa169f96539abcd448d74150f3d44585790d7af41c0f47025c38f93b3df962d53aba203b2977e0b03a86e13fb21ca28b90c530ff14213e64dbc26c64f4fec89ff0f5e8e70bf32563fd5a1213824e8073aea4908b30f0f2897305725b00fece62de3fc86ae10fcb5158cf42fc550c1d59f63ae72212609bb35db10080ccf9bf4298d993b3fc4da9481d8c12aa75eca7e4c8744599f89ebff87dcc5b6c92786c4831cdb01731ad7492eb2bc000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000898cdb69ab8946814b6b53481d2eeb5dfae589e928942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae628df4363d09f14cc0b180122fb355e58aae4f248a95537baaece2b465bc4b39424d6d520537eafb05785e691f7c8e3a68b00f3e1a71059f763649b0fa1666ca5250cd5c227f0a746063f3dc00fddf2e508f4f005ef02cf0f740addc832f6b71e281b74883a14686f41b30c315c0a7ae5c61ad87c6bcd4c8c2b629878383bbd00278c74f9c3fb9829720af7dc49292b1b74ccb19e4200478551d10de8bf5353ed1dfdbeebfc985888567badf136b727684bceeb41f72138ffd953f9159506f64d0af450ab1db15d160f2907b0c6beef8cb85eed914b58747be81f7ce5267f14f005987b9b30e3a076a21edc79868c2a54075f918b7660435773140c42100b383114ab9a984050afc9dabbd36989204903a234ef647f51501d202267511bc64db3000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000089bf43f6d3014039263b05bb7a01c8646350e6328942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae61b5099c5aaa2aa4fe3ea537c82fc999c56d5e1a0504d48316162fb007247a9351deea520dac62b7a7ad005b3abfd18dcbdf30ee5f9783c58f0ec80cbf67aa526172f62057d065d382ea631782dca3668a56139d25322e8d3128b8ba8989e5e8807e95e4c13049d69ebd673a9b277fea16879eaf3916c0eb384ecb6882f3bfed32a056a0673318cb2dd91fa8cced0076fab50f1a48c9f0cc85564ab58f4280e091018d09d4176019296ec1bead6fe3ec0ae4f653ecd1fc79fa5e76c6444b57a4f114d78fa109f07db217968af2f14c34de42809f4200c7009896107a01edb36ed008d052f0f106b6f446ef5fbe229ad7274519f6bc3208d2c1742d448595061f40f8e73042ce05d9cd4dcc4e753a38b497914719f634abff53e5105b768f6a968000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb00000000000000000000000000000000000000000000000000000000000000230000000000000000000000006c0ba81f432a713774283f812bef31d90d20135328942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae6188e2c1a9a4653e70d1ae03b2750f721a28414019aaa3ca024ca734b2e2d51a7089a71e0d1ca62857286e070825a63ff61c2a5e19b12e62b7c7353ec13c2c8a60d7f667f6bf650bffb6548aacfc54a3c76b2291a2167176c306c5b9933192ad02e9a48800575f56460b02e120de938f514ef627d8b3a6f52e757b3fbc9c7e20f1960c8fc64330e626936c22ad350096fdfd0347652428b8f8815471d3354e31f2ff82e557609b86e761ec1efc4a25dc82961a29400cb728a6d6877394439f7e42fc90e0e1f03b0b56cef81dc69800ca3ae06209cd4340d069234af11e012b28a2dfe3dcc6612173df72ccfdeb30e65b16cd72d9d93abd804f177ec37c0a225321a27158c9162a130048d54fb3ac8a09e9eed1c943f5b030cd7e225a0ef43d436000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000093e8b4942d760c8131989a31ddabe994224fc7328942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae62aa72c25afdc2c65ccac73fa14504c772f86671d5d24ffda4c29c80049b10be603efe26951efc3e66b1cada240b46ba47c193fde7a505eb5f7b90ee821c492871a21e84f29903b895ba690af55a5c6e4eec9c4993f2d6fcb3bdce49c2272cc7d0dd2a2208ec72027f259c47be09ef2a5f91c5f88c8f1004d2f473ab5d591d86308f27e6a91d1a5f4c22d91e5626aac68f4ae8fc70627fa608b37e6008b3ef4362745e5efcfc745c520d13870f9b3ddf41372c76e05c8f8bb818b9fe0b4e7e30e1c8b1ccdec4317ec340fcc5ffe195d2e7adbc6d518d0418159c277887f87ef7512daf179dcba4ebd96b8e46c74c975fb1f74fd2371f13abdeecb82d95397c7d214f6fa20a20fd820e80f89df05fd6eb28bc38af199f97da922116b1b81d5992b000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb00000000000000000000000000000000000000000000000000000000000000230000000000000000000000005694d5bca63987fafbc506499abf1d3df7542f3d28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae62197da3e2e450b7e4295785aa9b2141cbfefa00bd32d01e38bd3ad66cbb4f9bd2ba627efc5a62548611a3b206fecf82937d0681a957bc4b05b69ebeb4b1aad14068983c83a07b558cf74cb7ad93f1e08a10bc1d31938e43948f50478ec0d5adf1c61551b324e6af3d9d04329c7d7150e59099f59c02260243e3ba7fe9bf7a9670ab1bffa724e9e9e13e378c12da3102adce093be3cff880e62c56ba3c2082e4111f51f6ddf705a68987e1d52ef54285e1cc405a3f9e1757a0bacafbb11a13fe90d0e40768ba2e30f81a9b67154c47e0c1724f63bd199962a46c566165abc73c729b6a6181730a69348c8ad17c511756cdbd60a2c9f86f2392282f87fe5b37ae60b252be50c7c03d11da135928a6eeb34feb8c52f23d54994783bb1521a94dc1c000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000d433b30092565fee0f5571c7b4b219808cbd525028942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae60b645f78e9ef37499005d2361154b0ccbbf8ba935d20fa8d90025125262881782c209330e318f86aeb8bec2351bb0d803c445030eca84323234e2cff7c2e30bb12f4886b1789a434d736a17ed9d51f56848ebf962dd0c3c517d68a7eb110fe8111dd1723aa0567a2c1f5fa1cbe681bd82733fc402554d09c55ec7eb1f17ce93117a196deeb54728ef1aeae66250dc819df5e101b22527bed75aadeb3dedc6e0b03473037f988a0498c180c24f03eacd75c83a2ed0f18ea79855d46695e6ea15519ac138f865c649909fafc068e7b3ca65c06af530e3c38b521a2ee2a19e43b121b12033ce74d820c048886b14391417046e03f3686acde01ff8b76cc33d818711dd6811711439bb2bcc43e0a5e43682a1f8870254bb24735bd658d99e4cdbbca00000000000000000000000000000000000000000000000000000000c001a00d851236f0e494fca892608f43aeffee730c92b0c1a9871838a18cd14f80cd47a00f6027f2445ee8452f573d074a0f0879b275eba8c0dcf2c77b0f874c68a1d01e").into(), - hex!("02f920340a830269c3840393870084039387008349cf4394087000a300de7200382b55d40045000000e5d60e80b91fc482ad56cb0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000003e0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000008200000000000000000000000000000000000000000000000000000000000000a400000000000000000000000000000000000000000000000000000000000000c600000000000000000000000000000000000000000000000000000000000000e8000000000000000000000000000000000000000000000000000000000000010a000000000000000000000000000000000000000000000000000000000000012c000000000000000000000000000000000000000000000000000000000000014e0000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000019200000000000000000000000000000000000000000000000000000000000001b400000000000000000000000000000000000000000000000000000000000001d600000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb00000000000000000000000000000000000000000000000000000000000000230000000000000000000000002fc452d648f7e3043f6f3c7e05f79824f07e126528942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae60d070771ea1782f53e75601ec9fdcbfa8165dd10e78facc01734960b460e8bc002d540e4fc9470713a92a102ba6efb53f5195ec39df5fa7c39ded840cac2665e150caf268538195cc7155c61877d76b96f4500268a5b291d0fbec018782434231b0b1b2421890453a77b437398b581794d0e9fcb7665677c1baa6bb4fd32027e1eeed729491ebfacb2d025e3b6fa9a4e9ec09fbfa76eda164907561e7658678115a3cd07f44dc2b38d4a56cefb1b203a78d69c07e4b793aaba302815e282b4550bbb96dae434f7e75c0e9ec7e3c13a7c275a63774c9a1afcf71b5d601d33d0fd150484555347b520362d8ad08e0196ba5ec3a86867e1045fef7c06cd764dab050e2af04a61253746c3b43cb0fb746624ed90bfa5681bd43f461dba788b679367000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb00000000000000000000000000000000000000000000000000000000000000230000000000000000000000004ff1a4ad03dcf3e228712b54a499b6fecb56116528942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae61cb78c9bf2c47a0e409d66d6e535bf475722669c70b0b38b8e6101af2722ee2e02cdeb14b93671e5cf75d02fe89b3581ae8a6754b0b654661181011545a7f8422b5edf9d0e6b47e7024f39de0eaeae3dbf929c8331b7e355a33ccba47abe2f9701dd64e2acf93cea4139b852b2f5705045b4f8dd5048bf6773b07c06cb999b8221680a8796febfc0521bb58645c71e60f51be506241a3245363ac506b023c4fc2847dd48ed1b0e15f9a15c94a96bfa332a39da0199f1ac0ac9608f82bf01ba9628b1af262d218d7e836641ef05c35d09411785f61d9b1fc4ab6f7e673802742813e27335a6e6332a36864ec19142c577acb77e3843cae4c3a753b324227884d81c9260ae6dc694e4176e913c26fc558763cad7f60bf123006d3d72736fcf3ffc000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb000000000000000000000000000000000000000000000000000000000000002300000000000000000000000012d2142a7cbebdcc7ff6cd5b95469abbe4cbf24928942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae615880e10593596d4cb658f00c5562bc58c5a6afc0eb2201f862350792f1edb7512169e7be24ecfce258ae13fb0a4c8de4c8fda790563f7f3ce774220cfe972e1268cc85bf6345d455dd833eb8fe1c980326cea7ed702049d4c86accfe458012b1a0053fbf513220999498d04bc78ae54fce71139e54d9d5746713eeecfe3cba305882c63745df15d918b36cafd8f50cf7216e90b1aa8bc9dc2e3e5429a3bba641b17ac760debdb5700c4c9bad98ee427f265aabf94f2622f90be0ab8fb849ba716477b7071a7d42828716a27e9f6207c49e37bec930d029611c2b98fbd78ec62247bc890c170f59ec6dd157e7975901ed9142563c3d331af055f49a7afd3adca0f8413abe7a9d392410e6ec6193dff28dcde681477d34ea9def60978cd57c7dc000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000e6da5018bd56d59ed86c34bd37e4d3c6eec61c4528942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae62cb04ba4e26d335daf21194aef490805e7c3e3e0410b593f7d7459533908346917b5c793a295e007de396925820eee2c04d47d4027546318716fe4b2b6f323702cf3eb9676205471b0c77116b85d9c5974036a46290df0a80bf86d609287f4a123339d2f5621ccdbed149c2302dd01a3760920a61e8b6bf96f0986b20ef8865224b2c8d18e6d7d92b199564612d8cb33b22423af4c67fc793e2fd504504d51382fff82ab032b15d672bd52ce82c75558fbb1efa9ba7bdd84b295a781a00b04541e312bc1d73e8635d297c7f09448862f568ff6062b5fbe6f48bfb0f4bf3d488f1ef3ade38a1c0f9e21d011193e16f57211ff291da3cb0ce20ef75bb1b426e676267fa0f47ced1401e91a26abf637b88447b2794df9b56fa60a62f51ba414e9af000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000dc5bfc07d7ab9392b706b0ea472bd659dbed8f8f28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae6217cb74019121e68260c8908a6df82d1d728fe3287602b826397b023fc5e43302f245a4ac4b7c1afd8f1fa9deb074b8535cd4e3bd2d275f28a3a66100810b4890ed44be420c6b1409e0e33cacd54bcb47911839f76905b0c6101d9b2b1286b6723fe89341298544f07b77c3b23c16b51114b8f438f9cab043f06122202d2801227cc6e2ac7598adfca6426dcdff07e8c09ef8299cc6d40a7edbad876ba25b4af1eb1ebd3f7cb41dcb78d8972fe5c81bad17a9e98bc27e2f2ea9a6a183002fd362d28cfb0bf8ae7c4536c4e22623f8ed88861561379138247db9d18bb3d683c272962c3f94f3d2c6a4206975d1fb3bf9eb5ce122ec5024fe2f97ef03274350a0e1bdaee3a1550eb966610d56ab224fac4fa3a8d8a2608cda75d2e02c57e2ccb21000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb00000000000000000000000000000000000000000000000000000000000000230000000000000000000000005b4d0d491e04171fa86465244e305591b539af8628942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae60ee7bebe2389775c6f21811d85d1e3debfe450264c80ee39b9d17cf7a7964d73198cd9411360e7d18ba9766bad00b081e874286654ffce04106cd07ab39a80f31fbab5aee54c5f0a51f72b785e8d8be68f4c3ff9b72b7ee06f06fae8257ea005167bff7a7352371616ce294502328d16cb4669bc35f8a6cd3445de9db7beb3fb1a59b7744a0d611e6048e085144682db83231fe279b77ae157193c4f341e1bc32b4be703dd580cb27c297a8682553f9edfba9fde365ad5c5cdabc024b5bb1d6a2845eebf6142cd01024f1dfcc061f25cd668693f0ff709b802c5863363ec08ab1b95f0c7daff4283c94e7629c22514e02442ef02efe22ff99548924f28071ad60379102d4becf6362773c6159a4c3a93a4400d21e1ec39099e6ee9c86fff66ca000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000667c943726579c6b8b3ff2cbb47126e52f59f80f28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae62c940a714aae7708e5a0513ae7fc00273f221598ccdf6a9125a131ab9d8478850047378127753b3cb5fee3a06630428036b23cb039525fecb0de048f6a2eff1e2bb4d3dccafe9dea03935572b49c75342c8f2f4227eb764a76c5eba46da3e08d261edbdea002fbbaae124dfb642481bd3f9c38367c5366d46b860e2dadb3a08103410883fdc095c9866e8a0991556813f661fa4a2c381ce33e17c7e817f0a87d17831194f810d395ba0cf19dc742f1cc37e80348d8450660c00133a6af1703900ad346eb5f46d2b8aa146eb19ccb875a7b1cdcec1718e7111e1343868908bcf003bd5a001b9a8acf992d4aff869e306241ad07f0834dff041cd80e5ad5f842c41a2753564b701f03089b903befd41840d5f3cff2e9c7975bfab8249fd20cab46000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb000000000000000000000000000000000000000000000000000000000000002300000000000000000000000098d88afdfb242127432c715189a775f12bb3390f28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae60efea4f327aefa5e9ead161dd6611ab61df4c9dab9c5988d97612cc479a9f123016930525c1781976da3a14df82768f937f7f70bf96e3cc26bb5dc21dd6cd74f0a47c7bdcc19947fd3ec249b699347c0d78cb35ed6ee393354289f75b924b388227dce1983515cb1368327275a37996e7de1ce67991f773077fb86c352b7695f1d4cae6a343eda07d8b2897b6ba428ee50208001947d75c0d3f6f4730361878a164af0f33cae3197eeb8a07523557a9391a05a0698ad5ac0a50d65dce5caf9ff2bb1c4d9461350a8bc0f778b1a009f42949b7baa3bb2ac472ca3e0f47a541ede14f6abf64d02842c87ad07403aa75bc400b93f94659a6a3e7d5cb45894c0b5662bdb9b7cacf927aa1d2ccbf2307359dfe2dd9853858fbc2309cbd84222ee1c5a000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb000000000000000000000000000000000000000000000000000000000000002300000000000000000000000082fb30bc5c250e9d57cb16e112a7c15a984f94f728942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae613503f6c7ddd1ade21af1b97a7ddb381910c4ccd550bad7eb9d4c773c0d1f41328becb7e3fea7c0af3e8c3bbdb39e2ea67650c0fe58804bb439a70917517e5ff27dba88c9e32b65474be306bdd1ea2b20b4b30d1cf2afd1b63cce6ccdd36aea8089ce6f5703c70ece7ffc1991e6ee367df5b1357d1dd9589ce9838d41972d5f816a37135c21e77f563b25b36932bcb690a61e8d19558b52872e0f2b6de93b686211c9a2aa97c567fd45b927bf3cd9445592d7b0383c16d2d34639556b23e59d5151f0bebe67a27cd7b0aafca46bc5c5dbff099374004d90679a52535a5e2ca7d27fe43171a04b24a499318fe7c030f7985931c7800b5fa5b59687cc52301a7bf2e707160a3e4325baf87bf59e2d8e833668bca2ec7ebf3353b36a0e26ae4587f000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000fc3d84fe66f8f6ce3496fa925f067884c1d11bca28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae620e7d1baa83df3ff39ace24a671d6b3f69bfd8f8e38f9d4c76394e6127113ef61f12276b126303fc35cfc4ea0c935c8d1dee00d9cb654e86b2a2ddbd8b84ebc91169a19887203f9066caecb932178461017d06f66a4ca97dc7919838228fdd080de03a06d07484f6f0840471305fe63e3f60c5682a778b3f180643bc661eff5f15aa8796a3d83ad29685a5743838adc982403daf3bd40c06b7bd525d60c641e30b56e652955d1bc7645537d3b4fd83a780210236ec879b2a5595033c28b5b8ab260deb20e2d5741eab2b68caf50f1192825cba2d2a23ff349b266b5a3cbb93ae1d3b6acfef2820bcd768afb6624ae3a6638b757f447fe0ac3b3a44f060cb92cf2ff522eda5f60551b816e746404aabdadc902cdb01f9c496b7c145c6fcebaecc000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb00000000000000000000000000000000000000000000000000000000000000230000000000000000000000003911c90a4fec5fb6ff39ae0d502dda70c032143228942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae614d76f34519b08809f7d882290658a65b920507b47a4f1931ab4ed831deaac542823eaf1391da29dc538f8ce3fbd4c67f4bfb7b124d8feab2a2ef58d37fb5d72172bbad25a35eaad915bcbc4d9ef1c8caa54694d61524640fff87406f056d890255cbe5c7c56332c1ada63328614d7831c79dfd56784563280da99982420d63301abe49846092d86265d808a363307466e3e15a2aef7e2168e1df212f5b4b7ce27ba044096f19795deb46c94c116327e72e88999aab61150ea629d14bbaa75d922efa2a4ae3c8dd9b7b2306be9f3f04cd660a13c2631d321cdd0098fc88fc6d8070fd6df8a8e2b4cfa9f1a7af64893f2a9759c62498b592d72e36b60b70cd7d21a6c3c5dd10dbb80507845d384e2a0a72c47d82dd9a0eeb7ad8968623c61b40d000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb000000000000000000000000000000000000000000000000000000000000002300000000000000000000000033687810343cee7bdea2cacca78ea6c540c7c3d628942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae61166c0d2307a5ac1c2c7fd55e2263089047b5621a3ea51a6a0a3a861ea096fff1e8085f3ac492c9b35a72ee206e5edb6b1eee04f97198759ea72a902cb1429d1261265b59197fdb6442ad18783cde7daffd682166a58ff620802a244dc224ee619b566dfddcd48572a8eba16b2b0bddf00c812c88dbee6dae0d133004cb757360d94bfba6eed1593868ebe4784ecc3e38808d8771dcb061234fe503ccbae4a1c1dfa73cebcce6e299c431902dea0fecab696c7f2bc74e9b693f724e61c6c68e72c5b6d36705d519d7bdf166e45bfdfdc55728bd7a1e273cb9b7e445e0d6eb7f802b136c3ec82d9e2c31b62669d60dfed1dcb953ea9c53012a2554281dd3a882704e627b208bd0c06874eea409ac1bfe30bb5a3afca1209e4d4d0d9fcba61c864000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000224a08c35cc1ebbfca7d4b4f4c3210b1768c48fb28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae616b0b9916fbd613c79327220b58a6ed1601eb6190ad9984011779d4f26ed0e0b02b9cdf0a697390b1dba01fbf8839aedac9c1d1bed91c2f62790feba4bae20a7227f582865c4e244144caa2de39629356aa3b727db714fa23fa8eef1a0851eaa097aef2ef723bdc57770ef7ba686ebcd49afaad4af272f5b56936ba2f324f5f3143d38c2b9b3d1ca2cb6b2fafad02c3568bef51d41f74056f61698e25ee1dce7048d71b1afbb73453538b6880c65d6a3035c90725491cae13aadf6f7a4c3389c0f8607ffbcbe8681ecfdd75aafab65e190a96fc7084eda9f76a9b824659f60ad0654a033acf4d47c021824138c94d55043f6c062ec30dec32d8392c9fbb7d9110ac815952d896e580ea58c0d1255e9abe5e21c4af2417992eec652ff131bc93a000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000412bd8f25473f2fd93c05013980d2a82d3ecb1a028942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae60792158ffb93c36ee6385bde89e6278d9c81d0695cf7fdb4c161be1d14b9879c00d67c1adbefbfc9cce1eb8a76db8cc0431266d9de688841b796a893cfdf604f1717df5e42292c9036dee88cce2e1f72f123cb38a5087cc69dd3082f72c2b10f278a96ba70aa94dddf347c1147f0746db1e19c2ade2ec6ba03471eabb7569ae62c96515427237b01d7269324b02adc857a7d2a39f25d1210430b7e00b07f05e024c43f76223a90b001631a2c3ed5a904b9106f97374bc39addfc5fec805546b3049966a90b90356e0b949176e1bd76493af2d5646374b9c8864fd1da3c0c8b0008d3e477c6bd287ceef5497bffa552531f6914362ff000409ac01b3125e07f312d035a245808afcee7785031f40587cf25de1dadf7c7255709df7636c7f1f76600000000000000000000000000000000000000000000000000000000c080a0b51e7f43ced124a0110c23d55d5eb2a4b094af4f5d366d955076ef471110ca3aa06c7f8df564f4090b81e8bcaf17637b00ddc6ac0513e8b71522abe47999827380").into(), - hex!("02f920340a8306969a84039387008403938700834af50394087000a300de7200382b55d40045000000e5d60e80b91fc482ad56cb0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000003e0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000008200000000000000000000000000000000000000000000000000000000000000a400000000000000000000000000000000000000000000000000000000000000c600000000000000000000000000000000000000000000000000000000000000e8000000000000000000000000000000000000000000000000000000000000010a000000000000000000000000000000000000000000000000000000000000012c000000000000000000000000000000000000000000000000000000000000014e0000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000019200000000000000000000000000000000000000000000000000000000000001b400000000000000000000000000000000000000000000000000000000000001d600000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000091bf80d5452bd35a48d6f8c86c16973b9fc839528942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae615fd0bcc6b78ca0d068409c82bd6a0560422aa4e76a39747cb3527779b3d10b1109e5e3b7e07ac635de04e45b49baa610d7d58dbb5334a17034fa72e42cf97951dd1f25cdd214841af8c9cd3d7fc7cb6f0a63f896196d8593e0f950b652474c912a16a926ddf0fef1ece209525ebd672fbf331eeac58362355a6929bac7aef89020264f4a382f15cf0e86d637ef7b6525d039c5a26c25217a65144a8fc0e8be91237a63ece99d760b22c098fc06ae96b8221683bf9bd8738e532602c457b0f8206dda8bc97efe551ce4dba6a7bbc3cd0615ea954656fbfaf134aeba1adc149fa2c3415a732bf747cc8b4efe1b7aaa2c9c17d3a6e0d0b8a2732716648bae7b98d2c03d6480453e3234429df386a14b0a5538ee41c2cfe083bf4716516c4d36e77000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000a88c2b0fd676117d9825602c10a26874eb53462728942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae621597357b85ebd21923a956cdadfac2e29949d8445536cb2357a98ce389c9dd00613458c19d646984ad2b63f2e6bc587943f2fda4f96d23391e0d375e6c3cd1b1e08f47cd690bf6bd78aa1098765393f523b55f133faa2e74a39007b761fbcbb07cd568b56e13d97f48d6d05ac6ebd28c387faa09003b931ea11a4a81682a09b2faf9222d7eb5c46b7e268674df2500212ae2fd9882ca73b95ad151cb9edaeeb022bcc9ed786c242f2174c023f027338e70d8da48af8b5ec3118ad7c6044360d1c9e25999717ed8862278f6719c74d64703888cf41248978217bb897f29ccba02259238a185a76990b8e2bce0af5135e7fa53bd18efe3753d5834bb241f81e5b028989a1ca9dfd2cdb1c0161a6c3c360008cc5ec806e04048a222f047508e460000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb000000000000000000000000000000000000000000000000000000000000002300000000000000000000000039bbebaa990e926f859e5bfed1357558c2124a0028942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae607bfc1dbb7cb8f1b249a8e884eda1ebc000a28cf62e95b0df40c7269a2e31c791ef0a7da327c4d71cb5450ea1f3543b6e8da8506e05284440f9959b52a792efb1796d4d1d6909d1c709e4ab5fc06e32f97b0ba3f034ffd11826e009679df5f1e037a93feb52babef495dbc27c7d5b7318075a53b00172545d1e1c27b36ea62a7021b66a1992b26c5c499c31513bc4867f52133f5af31194ccfd4523b2970a05d1697197d982c7d4e95c0c0f6e5616d70c351583909f9b77f10a1bbded80b1aeb1b1adace4e62472954e171bfa434d0adfcadfaf55c3fc416e9063465f2574cf31ad044497a6e3daf933033c136a027751ecf92974038fe19fa95cecc467313ea239ba876a0622d1bb13e885cd9ff2e88bc7c77681801abc32c075b87fd981fea000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb000000000000000000000000000000000000000000000000000000000000002300000000000000000000000081e08338d5231e5b879e2b3fa560efd11026845228942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae6284c21d93a655024f8afd34edc66f6d8d470a1f98a00b4922eb32d1e1b72aa7e0b27c333641719a86364a96c4d9ea44cb2fb35880828694eff5fad4efa64bbd62fdaa0d5996e556f76c0c444c305d3d632e920980968be6d90d819f49534df6e1213ce620eefe0592a99fb3f177ecc4e44fedb71d8273606e6910a765cd68ddb1d7d7942531eee25421628d3df18b6a99d6642a67adc17a837ea6f0377a817a70da666466dda5715aa8ebb905cff09ac31de68829f753dfb6ceaf07c604bc41e076e77c244e2683378c7999b298143e70e02fcce5f2702fa0c3f4ab0c9124ee905f3b92e7b9faf2439eb3b13dcc61f42f94573b26908753cd5e70dbfdce133bb12994979a1f5421f22debf7eb86384b3ea67eb028e5e914f0039f00a8dc8e49e000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000d22666a4ea994185639b9d49e08ff9c181973eba28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae61c0055bc27c4c3824df4fee8de1a033fbc485da86d7dc60a9ff3e28f1af3d27b1e0c1e33bdce9a4506332df34b4a9ccf64a8d77b6a044541a73806ee2d5faad52331294b3992aebe6c164334ed7492afaa15629bcadb9ed6cf8174d12cce52560f5969705fafedc2e3cbd28a597a4e38f3ec9f6b53e98d841ecff6c3cab304c5106d67e8e4bb5256118639b83f9aee7efc605dfaa27f72f73310cdd8fcd7c6e304d834e86b013b3459218b0d8d5cfc9be53c4abe73f90faec9d3495f48a4a54c166a4cb2da9c3c82b5bb54504fb6742522c05038bd766037772b4ba54f14bdaa06dc0477627fe55db05d2be748ecec74752c54e0846a0733e54fc9ed8befdac12725f70d26f43b2059a186b4a801175432478ab9824c37d9c8ac62b28a6b0df9000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb00000000000000000000000000000000000000000000000000000000000000230000000000000000000000006c7a88a3fffc0e32a65efe9dbca7ebef781ff3ac28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae61f8c0ae0efac374c124895a71f82dbe39b17666162ed12523625cc781fce898b050aca11bb96a1c15a8c2c79fdb3d457ee992a0b8f9876dea6a747c052ee6e92104be0981bb2e19f7b49cff94ee4e96276150f5781f23857d6a3c2a328890a7c1022fec3967c9b22a33e6138319057985a9bc1bcb7dc7b52887071343222f0a3205239a8578dca33f4f0ff44605b669eae0f496e7f9532672504ec5b2764e89a163c6fa3d1a339df863a80e4b824e616491d736685b4b68fe008037ae9a0adb914ce67e76aca57400179a7f1a431d55477aa80ca9ce9dc2f1d68a1d5a938a85a2d22933370ea288614c7d3c13960a32240fd76652b8f6bcfb0190941ae8fae86034cacd834618c533e5546a772f9c9f660520c201788b2dd7e3c071c4bb41951000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb00000000000000000000000000000000000000000000000000000000000000230000000000000000000000007e6a5fae2523fa310c0713f7c8cd34f1ee38470d28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae616d4c04c49348fc7844cc251d87fedfd8e810b1e0c2bd61c602a725a861f6910180ccedf030d7678cd567472eabe05e8cbb08ed34163e769644e69e757b2c7f92f2f0109fee8cae60cb587bf3b488903a61e1ca5225359c441fa749166129d6b2afa338de2ef2147f0ca5466679f03bfdef8da5db37b25d29a7ec2fc2648c0611675425fb9a9391caa9b8d7d3f540f02432ef65fbddb3e192a7dec2277bae81225e234f7b0e3364e71db446fec381e09df79ab6dffbfeb8259de6af1ebef1c740a68c98ed119b9e51aa27040fca58f7a00f30972bd21568879ddf0c246f560b822ff7c1650628b584e3a96c61be54b7ecd51bd779b2d4fd6a12a86999ab23515175649c71641fa898fed23379878fbfdccc932e0f4a478bf88af3e79c7653a90000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000dd75e013b66cbb2aa418cb4b2692dcfc9849f40e28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae60d5da2b68f5d410c28aa577cceaf7b894664b06a96a97bc1d2753b53d23377531630c200b3d7643d136e6e9256aaea23676c20b94ef1c7f4888553674ea895941ea660085887d5b65bca0da94260fc4929d259e8f496e938fb276f0bfd055e3a19890b120f10c79a0615e1fb42da8e6deecd079eb31f20bbc50fde260e57cc4918fff935aec59948cd60f431d7aef81d2c5b5a59b046f52f6e2fe6748222c86c2e1135cf95e23fa167432e8b915db34e2efab40d3427dab386b85315981b28bd207751003741525798cc7234a8497890e6b163ee0ac99249eb8b5d43abd2087c2387c914d92d42aca318b7006115d4cfd6529b524ced840a95afc22a953659cf06d7ed44ae5a016eaa41b12a631ba51e8df6c0f4c7e1ce9e5c6902dd4ea6a785000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb00000000000000000000000000000000000000000000000000000000000000230000000000000000000000000f05d6887b0233c339feb5ad2ff23f87bf41be6828942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae61a8fe7eecded8555ec402387be0b88a0c5adc189fd8b71bbf871378a6941218f29da8ad7d1016ee49b9c6288f17277c24b61cdc0355438c73a641141d022605b025a62c611cf353712911d3f61b1fcec2c91ee2ab6192be544e49efb2a4a50510410b0e377e6f059612023201056e36d06b44096ff3c3e147c3c3ab28bf2c3e5281face614b7007cf82c485a522642582f67c08397a37350c3b38b5582af478f0013f1dee2866bd8e1d876135589e29f72aca4080e4a26e6bddacfb3e2fa50fa2ab1d6e70622cb9fae9e6fafcf80f5e0d93635cdf5f7483d6b9df0c34969d00911c0953b7fa85184ad0c2f24121cd8728dd6acf4ea0349ee6364e2e678ebb42627a13d8a8082907ea78ad804f951ca004c8b2573602283ad9fc6f15ff6b9d4f1000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb000000000000000000000000000000000000000000000000000000000000002300000000000000000000000011a7587346dfa931b806ff5f9977109db91efddf28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae625be9d8bcb36aeff220e762650578f29ecd4e99d5210cbfd2498880c6bfdb5e92012a3eb720fd028528bcc103345ae1c4e877db28fff10c435c9cbbe421a0c0f282d3743a3cb2389fe9ef23dd8af75ab5b706c3cf506b77ff6c186ca9d3a63c70a94cce50ec196601cac07e33a5a566a2622eeccb46243930eaf6e0b1e482a651c51057ce621b43e9e2948a352968c612a62765f97b5c4027e81accecc0d028a0771d0572bd4d505c8560513cbccd42f4a255e9f0fdb5023d61014bd1130ed72007102fcd9a1a4eb0f4ea8a1ab4384b02125a84f7a2b1e0115c1d8a8db7ea8061c664ee452f5d5149348f4c2ebc23eccb626ab3b275ea17ae227f440eb7d00f91316b1fae327bf9dd48d422141c56322cf4b0253d249469658e0bae0a31583ed000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb00000000000000000000000000000000000000000000000000000000000000230000000000000000000000007527959b2127f440ad9ab50968fa31acb221f8b428942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae621671e114dfdc998962474a624de9dc385015c89fba8c28bb62396a86fb3df0e17bf2ae07a798b9db4c5d1e73b49ebad41764cc4625f6bd67c30ee38e37a12fe1f84d347a39c94b27189de9a159247542fccd336eee271e696152b7e4197ab3218b64f72ed18a5685d5076610645fda0974379b025fc5b12f5e9ed852ae34bfc01361aa569e6aad7924edb221adb5b3983bb8d9b82bb3b4b742efda83a25c4512c67b28eeefc8dcab34d802c005d1baf023e2068e0500ee1288e41d95ced1b1518bb868523fe25efbb9ebc5928e762e993ba580ddc71f2b6645ce93b0e1ba66b02b33fb53b179483ce8a57f3c0d5903619b76834899295afb4a2e6d9a241d43a14211e2ba038fc5a42893eae0c785a2a02902ff8ac4206e6d8095540fa668191000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000f693bd3ca91bf811367096068c7f23175218a01e28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae62cc2e17e4379c7c2d340a496320adff1a90cb195a9eb89f749cbe61cc301ed0716a7ad4fbf31b32e4d4db65789252bd299b23326b222bf197c94cffbfc97f75b26a7334cb7ee68ab9d8598f72eddb6922e685d77893724e8f13602f7ef539a752eefcbfd427dd9e64e0b53cba20f3c1686956359322cbe24f9343190dccfd7c628c4a19347913eb202533e53d7b3a86b9bcb188f922c8ac4e355d1352e67f7571f9c7c65bb2fbce018f4b9b6eb90f2453d2147d9ce48c153b665b11d2d4a891b0758c29655e377dde22872379459363e6d803dc1448d65506a97bc1c5b221b5a098aa4f9d28cd371668a1dae0bd62ff0700916596830a0580b203fcbffa5d3a119a87b6069429455c0b98105c7dc7666e5851a4d2a5179ab766e6581b912453b000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000e0e0504d9fcf343852a560834c1ccaf8b51f682728942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae6072da586fed751ae8d3effd56ea2a96172b970f2b318c8471b3b2a8a56af968d10219530b160e8541a91a591ccd6ff5b396eafe24c322b9f991ed186c86288e120e49597383d85897069ffb2faa9ab3aea39c8e2bee30632a9d95fe4c632da02111f0096faaaf3572a5ed85b7c400e6e6c3f5f9a7906ec050f1e81184c9105aa292b1da0bd15c6de94f8ea3fa62b07d12f68c516ab0f68457acb6c583f3393651a4cf81688403773aef482427f22089cdf1ccb5df70a588ade26cc603578b50e1c2e473a5c11edd234697a81335a1a3468984728b8a1893a0d5f1f7226fd95a60fbfa60cdaa44d2ba9e1c50eac4026e1695e7c1c8cd9b05a6e67b2823355d3a72478b24e2564d9ada30f91edb4349ca84029a79237442bacb7508eee50ab3c1a000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000bf604969202162d64c0b3fd72c0e550aff8c9f9028942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae61762942ae25b62df89794a14f0547240b5176a501a72f41434c51bd321b2ddd60601d70f80affb5ffd214152f77c69f6948ad44e0032056dcba35063bc336112116efa5196a6ca895df75fabed5706ec3e0822668e3f09c39c5415ee158a3f312c424a82ab819300183f392e946ccf5874cbde3d37bc6a07123e3a0dcba3a4ea14676b893285b2dc382ffbf64c876e9326f936791b36fe03c5e24a688e24379922458260dc9a934304b92642af551f7143973a291b7319c1d3137d253dfcf7df0d63b707edfdad155dae7387bdcbc5b48776c61db44ed51ecb723d25927a37cc2309a9f7a46582666701c40e2dd8c53dd058f0412376c3d4c9bcfb3acf83dc6a05275166c41c2c99a994b2b27686a27f86aac5a08b3a802a4717f6f7ac25709700000000000000000000000000000000000000000000000000000000c001a0d7070e7cd041624764220631f8a65be0e918d2c90107af534b57091c824b9389a02480f4c936f0ef4e9507b208e82baba87021525ee98b5941d08cfc0d7d146547").into(), - hex!("02f920340a8306969b84032a47f984039387008349857a94087000a300de7200382b55d40045000000e5d60e80b91fc482ad56cb0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000003e0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000008200000000000000000000000000000000000000000000000000000000000000a400000000000000000000000000000000000000000000000000000000000000c600000000000000000000000000000000000000000000000000000000000000e8000000000000000000000000000000000000000000000000000000000000010a000000000000000000000000000000000000000000000000000000000000012c000000000000000000000000000000000000000000000000000000000000014e0000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000019200000000000000000000000000000000000000000000000000000000000001b400000000000000000000000000000000000000000000000000000000000001d600000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000cbf61a54ebe5e9152e1f6b81cbffd3027062642928942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae61d460bd138ee32c939dfd8e49c57a95ef4dcef2f88b92e5a1d5e2905f86d787328bb4c7a1e4eb3b8db4d59a38321cd444d510a700551beb6fdfcdc88068c02f70506c41903052ed62b6913f66c9595a218d5726ea3128be80d62f7c69887816a22f613c865b39a6e228b0d90313dad896d11000afe422c2412aa8eef93fb1a1e0cd8be0d3226796e106d56c9f3d6ea5f189f88353aecab6565a256034ee48fd00bafdf7b018aa742f06a35f8ac0442c02d1a4f75186798a33cb57b53f3b2a09507ca58f2e94f1bc503faaabb19812e52adc5446d0d3a2eaa3c37c96cd6b3937014ef84689357e91ccced5dbfda2cbcff66f237923aa145326a831953620b7fc711e8faedc7ef58112a00cf6e13cbc0f005606720fb034d7a57f591ebcf33a66c000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb00000000000000000000000000000000000000000000000000000000000000230000000000000000000000007cdb62cd44f27416d3d80060887b79edbc66eed428942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae627cd53af047b648a62ebbc6b7022738934e337451e6934e285bcb17ed151e9a2156cee556c24689d42cf8d19d308cdaf32215270100cb7de2300b61d6f3805e61fad747173364b42a1fbc54501d3fe6689204bb44e095ca5aca1652d4ce018070bbbad2a1406c2ed33020899c296fb67957c0dafa5e7630c6f15eed2d85ca3921f78322e092ee4289f1f00dbc46793221e1b2439129fb05b1f185cfa857baf812e9ba7fecd26f0671e1fbc3796ab226a8484095d31360f45222167cd7dab33f11a13d59918ab5dbcbd350d47b8d48d3b52e275887e0663b63b9cba34e97377af15def44fb6d6227bc92d17b372a4779d53d4117357d4e372f15ead01502b0cc3006542ebe7436861a0a015643024b8eb364ecc758dc76e38f5cbbf461c18a73b000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb000000000000000000000000000000000000000000000000000000000000002300000000000000000000000060de5ca48792914e8ed36f8294c571cb64cbc86228942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae61c2f5918a5841520443a45ccf49a742a50bcd4548fd8ad248a1b8742aa75b46417c1fc6a32babcf3b5960b1cfb35d98a261641322b811053ace79049d236019205960ca817a496c09847350c58899c0008ab73f124204dacff678139ae80c95c1d7877bf7f5c4b37f570321a76e604b5a140229e1564216e722102a0131c6f442933d8de999cee105ba504babd60abf0d97ff47ccf6395159a8c2a24d24ed918029a1cde683c17c594cad199facdf9928066a73025189be71671e2df5314c0cd00c501e761df7d4b8a0cc152d6870bdf5a3f5f7ad8bdbc2d0f11ce6cdcc829bc1acb667ba2d8c86243659458f23b0c5c46fef1761cc7013ce20c5a55bf9f28481c42002db11bd87e9f501a27ffa16297536ff3bd04d44cf8385c66913b259f94000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb00000000000000000000000000000000000000000000000000000000000000230000000000000000000000004427395e8d53ec91fe009b9f9f7d108a6d046fa328942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae60e8eb84cafb9b1049f380e248ee56e410da056b3ac4fae01e640bf76dfa9b32c089f372414a1aa9c722f3af366ab7f4dbf700d8cfd8376f90c5125df5211c0240c1b68b374253a99342db518fff6ecc0605c35d0abc5cb9fd58d13b554ca1204306006c533a0d4e84cbdc3d1a219f562df9e5afc90dd541b8b2332ba63eba2062b9aeaa5722b7ae0e7d60a977dfc2cc05bf7064b1ed2aa897c306236b1adea8528a850bbec99f23a3c0b9a747c2f285474f266424bf6d336d0c4ec119877f5a9109eafdf5d0f879f6907ecdc9cbd20f41d43dff8d94caf9c4486f017f7d10c511da1f9629b4d2e0232c0bf208a0f9408134b1f6fcf77b33ca549ea32536e43b900f4fbb5c755d3221871fdd7c7118c1fec5559871922b1b462a5f0502b9e14e9000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000ff7fa1fcf8df81ea158cfebdad80d00d49790c1b28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae6142c5c102e9eb810eec6a0fe8cb214c224de98a8ae9e73f46897df36bffe668f15c5b544e21b5c7495900a1bcba9a3b9ff362e192a88c24be1834cecbbebcb172be37dcbd251b8ad00f6a589bf6a296eadba57dbebca0ec879f7c0b101c5a2d12849f2cb39082e9a68623d3793562d40de78acc164ece4ba819b9cd41c60ddb0155ce47cccdd81c62bd4850644937385e494c711b794ea61c3f876cfae88e05805ef8c12ea3890fb78f382fd4757b43fb31e9b711d5eb6179b302bc187b621e806dcecbe346e981b671c871b81d963a58c674ba7b5aaf83203e8b6480104b02006491322421291c323149a72e34c1c9c793b6797eb2a83408faba857a60d810f0f64bf23f7d507c895edfb71d617ccdc2f1f819e16bd07cb467ee77794bfc9b6000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000f34c1f7627c21d08affe689360b68e3b86bddd8e28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae603f4f9d9e44ecdfa78b3f822a00aac0a80fbde1675bed218b4e9daf3018c75c2274fc133f9df6704f4926e8201f000cdb3f5288f5bab86b24f4501734b001faa06b1f228701b430c5f77357668d11abb9aa246ec200026b8835fc8ea038dbc3721978e874ed6e196d0ee6ef1baed881ec1a8fdc818fca586e49adf1a01014d630b247457164a28f47dbef855ff71f85bc3d2d114f450bc209463a532cff56aa9183a29e8599a51c0a5a46435d21e0421a5ee0b31590e2670431f59948523a3840a6914dfcdaa1d8f4acc0999bff181168bc97f59d2e76914b8fe40da7cfd767510fcf9dce7c0aa00f582fcb232b250941dc3acdfb71328c97fb21804ad1abb181f04e30fe89e260a50e3ecff6b402e0796a12625cbb28e218565ca449bfc5d54000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000b6816921690bbb13022ce4279c741e9f10f6d25028942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae60c7d7a2327da7193adb6e7da1a0011071990b12213c823686963a0fba1a43683034744575541f9edc32e3ce969ca106604b4a989340584ddc55b9728c7e2e735074515993dfc63a646b2d8f748414d5dbcd64394118e0f89d165c746caf2434209bb608dd08ab880aad6440c7340c1c684403cb97e2276590bd18963940d98eb1e1a272569a949e07dfe4a665893154eceb132e728555b80e40a51b6134c6a1e0a6fba21519df338be4c257b4a5300e8b8f22fd006f2e9fa8e2d72b60f3818e72de6b2584eda4a90fc2d78b98dc1b5ccbdf1f3c20e733bbff817158df22fbdba1d8e56cd2b62522af6b23891f4f2494e565ded4983941326df46f8895df90b261eddd0dbf8d65704970292fd40ea3c440b4f7004f8a988eaa0124ca04acc2f80000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb000000000000000000000000000000000000000000000000000000000000002300000000000000000000000046cd855658bcbb261645dac5de9bcf3e86338ca528942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae61a678665a7ae5d9945c98f2448bf68e73e80475cbba2f1601c5be074171c21082ad67f4b03530e704fb1b232b3cddf83ed3cc000fcc0cc5137b6f4c3e89d59fe0f02287c98f5c39229b9ea0ecb3b2e927f66c5bd814bcf032c28d3b9227d3cb91154886e38171ac9cb09ad8f8a7898fe624c216c1f2753fdf2126f1e06adbecc0647e62c17a2c83ba39b269533b35a377b069f0b4ef684142f7f38360feb6e832ac89f308bf01ac0fe322a4d106b404f192b2c279299e97be3a5344516ca21ea105a99ffa98dca692c8c3f52addc90eda18cb19336aaa6d085e40463d74d3b8e0f317e0047e3c6f7f9ea5e99a7adf0afc1acffad89ac728808bb2ac3cd57c5aa2b0ccbc0976152d5b67b89e939da3ba4e0490d962b8035782ff36db7f05a23a3000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb00000000000000000000000000000000000000000000000000000000000000230000000000000000000000004ef8a049f19848666c00d958723dda15310a88aa28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae629342c1f6c1e951de321ada9f9dd51886c7da9f435a971f21dcce3e8067d80b20edc4b5a3a2982f4bb2825f7e82dba0143325323491b7810c291cbcbd76e35242f9e523c196e71f608c01dc6fdda1f5a6fa0f60ee6422f0363313332b7f6c4ed2d2daaa8ded8a06a27765e33668632033a783e6a452d32f2d327f629e25106560c6251b41c8d03f2fd7617f7f3c745c899f32353223f8ab32b56f813e430391d0686a6604ba4f73d140c25c0d30a8f7aacc24696207d256f14a2d5f3e217f8a70a9254141d4351a6cfda264150d89b2a35140530990449b767f05689709488f00e227ac767806f1c3dfc1173d3886189057e5a55d147166005840d7ca50f17861700af52ea29cab029a6808d6dc6f82acaf942f9254adea7ac455916f0da4452000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000944618cd80dae4191c7f7f21c58ab13bdf81738a28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae61b7951b069b65c12393920364d045f8d76add6c1d9f29245188781b12600d6be0d5d127d6bd399a6ef83d157093e1f5a7f3e9a1edf67993b678a7f6b2be9b65129827246aee4b32f7d33af5d8363c7edd2b8fa882103655c0e57999d5127aee113a7fe6d4e694ec0e96cca8218f2cac3ea45a958cdb8e7a77e5b0a7f65834f12178510f9a90038299b02ca079f79890aa550ecd77b0b88e6ada0b411255a560c0e214079f6191a523d2f8dac0a1426ddb1b7aaa51f4ab184341392492f727cad29d9439d19f56f626ff8a8482bd148134d5cad497b01d310680537b8e3dbad9705cc9230d48983aee1839334e024c271ea9560ced93bfa54b880901249fc647713b1931335356f6f2c35ac21de1c2a6c3302763a0eea4461c757fb18bf8bdad3000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000f2a05e7c62af3f2f02a24b43c2ae13b08890fd4628942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae622cde3d420dbb6ff32a2b0cae2a9e25945c539ad843317103de9e09595f424b328dada7a73b9e990c662830d82148ef6c90879c37ded18d7f24f9dea6c6cf01504184ca216206879d98b04f4e0eb97f6a6128a309e699e7d160201ed34f76d070c5377a5dc4baa602431b5034dce504c8e8fcb3033e605a7f9d43f5e9e4738c30c9021ba9dde79e0338b9843fbdfa7507174fbf43a28fa11b90f39bd4d0c697c0bc0c8292d6d79489b492324735a57da87a52f3fc56c83706711c86188e4734317b57e8482be2fbddd7b8999c6c403b1649ca77cae53ccb33a7466c0ba2e43670717bb2502de19dd83165e63ac0bdf45f628e77f314131766965730a44a947ab2d37be9216c866637b04e5ee682cb7fc17f92ce5c77cf9113abb1030a1997ab2000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000cbd0a779c26eb779769cc9d3a42f61c97c99602928942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae60396cdbbacab4ca173328793d82669df272d72cbd5f355277324d1cf707995f82b320ecd46b4bc60e11394a891aa160cc8e87ac44ae214a23cddf356c8ef90990d7c8f0c9da0e89ce98f30d4b468df256397afae21430e552c0ab9a4fac037710c7ac7c8858a6d26323a0ef3e40bd3c62fccf473eaa83aebcf6b545a7bc6fd9105811a4341bdab25b827b79253700ac63f5df83cf602db53efa3c93aef66c99d0a5b385aa594eaa55cc8eba9fc5bb179bc1745e4fa1b988e58bd438c1b6a23be0a19671d950886a2c5d8adeb93b36d55c2a6a3fd577fa1f1645edd71a36c37581a5ff14720ee29643e09096dd01785828380c42c9dbe38d2fb89ea391af5deff2ebbaf11c9e1370f4786ae7deb76760ea476ebbbb2bdfce20159706bc2e18fd5000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000377a5093c2531aeaf4f72b4d0b2c48d3d6c8684a28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae62375d5b21debe1c780d2dcf962266b2df4937663d6b6e93bcf22f1d64af660b51760dd6af28c91232ef017518ba734b91d159c4146074d8f8bdf5d0ca47f220f2d03765f35c93d02340b24d19aec48cbdc3f1fc9788ac2aad187ef5b9bc6bca6038a078c76db57cc594712c5c73c31afd34a7a441743799e3543968c33f76634138cd4cb56addade4da332152eee582c4bb8e416e45d3fc7f3f8ed0b7073337e2bcaf837d7d01edb32e38abf2439fa2aa55b077c1c7b60640d4dab03bf59c7f305c8ca9cd7a20b79807a5180f921a14acd7f30aa74882bc531c0b42c6e08d66904d07970d54795b0c30c383228090d4ed088af846c318e4de7c25ae9dc01e5352ed242f8f39a28c8dd178f364beed17820829d319729f3b3fbc85908339f1220000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb000000000000000000000000000000000000000000000000000000000000002300000000000000000000000083b664be1badd9f38133826ed0d1051c473e474e28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae61b96cb848a7076d907b26de483e289c97c2d7a37b74db23961df4cf3b7a77618019266266d91c62ff228e6016a2f9cb3635b8d7431b80a2284ea13e8692a049f0e81c6a92b69cf67abe95986bf1fd34f17bd458cf13668f47e11edc991a4aac313e246126ed023db3b6d19112f7acf890b77efb0300868a91e09d52a966e6d0315c21f20fe7630e06a0e648cd21e430e9cc12c920bb2df8ff89966830faae7243018fe0cb624573d66479c635f8d7ce04fa45292d39aafd96caeea287e08ca6210ee7e000e89bfbc77617a1f1c2c92bc25f4ca5bc4cb9fa8cff4039e27345baa09b9db170f8e1e9655ced30f72be9edefa5257ce44ad8cd3855cc9fcbaaa443923c51df11ed2f8b830c7bf83c18a77600b170ed08e7a0545c690e1357bc9cf4200000000000000000000000000000000000000000000000000000000c080a0b2ba45b0c4cabc8981799c254b90d90c019b757833e05c2742c13f52e82c7bcfa0296885d0ea2c68aa6020ac3881d89a110471efeef6327af2eb295481571c4386").into(), - hex!("02f920340a8306969c84016c2d0e84039387008349cef494087000a300de7200382b55d40045000000e5d60e80b91fc482ad56cb0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000e00000000000000000000000000000000000000000000000000000000000001c000000000000000000000000000000000000000000000000000000000000003e0000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000008200000000000000000000000000000000000000000000000000000000000000a400000000000000000000000000000000000000000000000000000000000000c600000000000000000000000000000000000000000000000000000000000000e8000000000000000000000000000000000000000000000000000000000000010a000000000000000000000000000000000000000000000000000000000000012c000000000000000000000000000000000000000000000000000000000000014e0000000000000000000000000000000000000000000000000000000000000170000000000000000000000000000000000000000000000000000000000000019200000000000000000000000000000000000000000000000000000000000001b400000000000000000000000000000000000000000000000000000000000001d600000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000050a76afb1154d01d6eba284069708d356d9969928942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae6204472fcf9520f9fb2076ff97de783931cff4485b9028f260839f5a3518c0b7c2dedb9ba79cbf3ce5e0eca92a12da266d66f21c58bc107fb961e7fdce9538d4c195256b732f3eae1f49cde40c25294963146d06212e318cfba43ec8ec274d1bf22c8f77a99a5797161aad10de1fb3f3754df5fc20ccede01674a7c7284f7bd690484bc65d8c32f6a062c6e886f8563ce28e02d2e58485273eca71a27aeb19dc70860db898acf6d32b0140c8b90355e8b4b4bcc0d01f2761d44a573421bf4af1c0e6bcc3f1b2cd42af6830438342270b83e244cb2d680021a46c6a0416683e1e10fcb9e36c27546a590b8bfdaab06385ae9c72b22160622aa8acaf404bfafa50c2fd454af5d6f6d7dc38a9fd1dc115b8f1a55b7f9a2fac0e080cc6e7acf472955000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000fd176b56e03a2a4d400c61cade47630196614e6a28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae61f480e5d05a2821f7b6a0da7912130ca375498b472fe02cdd1635bf57e3fc79d0e99986102ae4e27760a6d33cab28b4b77c5fc177b0030d8021b67017f7b4c931a69139b25a75a2023160dd6d6f02a21e95d3005308ce63c45c423de987d8e4b1dbec338be731bba82354b115902c3f4d702178bedea57978eb5b174459fc1b1270ea499e3a908cbda58d2c091f5616d9c2b18687adda6c24017833ce90acec200e87b2cc129df7a4f39d8f6e2c3b2a8d3f3e0905c3d4bff8ede401310ae1d9f276d6239c4c32dc9e627a1dbe6a60ea37e4f7de95512de72696e37de529686d0212ee16598faeb5445f37c581fd9a60bd3d22b1fd965a9cea3dd677df95c9fb3151ba48ffa3b5e7454aa32c6850bbed3457f6cccaac2f5cc9e399a68196b29e4000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000897e11089a878542836ec8e77b825a51ef8829b528942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae600164253f8e62ae2671abad4b06d54a890f9abc01afec02287a15cf1115068951c9bdbc96cb8adaafae3aa83c4110616113c066688bb00fecc39bdeb64a1390a2917725d914fcc89e3c18a87a8ed00d9540700ec7320ab345baafb920b0441ad07c4a7e6b2dc434e9934277572be6f581fff0eb7be0857f48ddfa68c2e66cfce21fe5a394f6fcc4844335bae1029ebb014c6c08c2403aa11fbbf18cf6bffc425060e00ed6a571e020461981b6429019c35ef9f1be8bcbde05745a1c537b9472d03cba89ce21b3cb28eb03f08d7c97f1d94e8c0b55d3fd2586b74da048726ddbc1c8eb5ff64d606c6bacc97d6428a1ff83517a46b8f3d5194714a98957d2f1cd905a46fdce4364f2512312c238f9dc59ee6faffe30ee2d7f5887ab0eecd596b40000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb00000000000000000000000000000000000000000000000000000000000000230000000000000000000000006bc063c2b6c1c94490329f632725e22237456b3f28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae62ad99a00f80269a3a77de4fc3bd9976e9ef2a94954860a99c785b2bf1b63accc26de5151dac27c1c3d92571dfba7a67ca017482bee0be2188fa571875c660e5d221a475b95129123030032cf5243f78a2e6cf478c6c3c549d46fe6811a59c3900578aa1407face18fc14174b56571888ef0c471fd66aa52a53206215429d0f8405511b5377d2e625d010030d49045e1828e2366e8d5df27068e8eb9b89891b170a61b2f39e61d48c97c6117b1f04e5ac104311785063e3acc3cbe7358b13082204a43390431779d8fad127b39c5853f9926e94e6985a0fba609e7453db8a9e7c26d930a97127bc0cb549e5723f4b92f8cc7e5f800368ef108411f31e8c2476b80eac922344044afde8e958a3af9422dda01d35584d76526fc1a2a13ae59dbd0f000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb000000000000000000000000000000000000000000000000000000000000002300000000000000000000000033200fe170f61ed4ac8a09b43e3798e4ac8f195b28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae62d3092e1316ce6abb3acc796d98205e786e22c1345c132b0e61070095b83993b136fae2ec9bb03d161cef5cad8bff5335812f32cea2191dfd42df867f64981542b7fc99748f6833af03f2d7c93ad8d3cfe6b5103a510deebbb029e4005dec5a201326eee2a5598f72b7500f0aedebc83563faef710c75cf0a8f69ee75645ecf0053f00c5847f869a0b27d58d6ca7314f590766b4e4eb305c3c31e64b206df10d02ae3cf650459570d00f74f002fdfa92e68bf056c8b974c07b189a33442281c51748d8cfeb75803b470f289144f38d5648bc6d2def5caf65d0cab9583dc0220f17c983c93039ed5fff9d82b233a207a1069f00bfee072c1ce04211e6571df5c825dc3cacbeb084a77f015460798ebf9a2a5e546013bbd245b57ccb3a3a60579b000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000f1ba6cef8ccb2990ce7de325b7fa407906125bf328942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae620c0644be433481651df7035bc5cc1247d8eb024f08f06646a9f1a81e475902711574aa82220fd71bc6cd5f1e7a2f1c66f6cdec680e04c449fd5f65f0606f84207dac5ae5563747e3e74aca6b92fe8be94a591ba654763f2c376a984ab6bac5a07cf890ae88d46cebfabe94398e2d8aef0a277caa1de32e3a81377e564286b1e02161e7871b40c0a388af9e732df270970cd74b6bb71ec71479a1144789da3ab279ba62160fbc729e5ce188fe5925e3ec9d04988f62adfbb9c8cef7246cd0d5720705aafd2bd6f4735dc9b19b03d606a70aabb86c38e2c3fdf2f53ef92e7eb64207335417ad2b241b88d9ae80418ca07eb457f2c557a5bd4c1eb2ef3c3fcbe3120e195a0a41d0dc2aec8703992711bc3ca34432f04012e6b771841b9862a7447000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000785cb80c25d8d3618ca7962b2dd85e7513b0fda528942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae6291ca2fbeb9e08a732b6937ff647309d7152fb770052fe37d3c7ca22911a6bec11b0f463565e65e5c255bb13afa8fb025bf41cc4aee8f4b8d00d1826c6ab90f813e024024e4c916186ca0ec32ab1688a6a09a156462027b218f39a1f4dd4b964243e8898fc270f9621c0a45380bcb5bc9b14a236680180a042258fac8aae0c9e1dd0ec39787afd536b51527426964ccbc2ddc1ae16b0d6f11d9241d1cb53b94e0e989e1624568bb59dea3cce55fd0b21696e6153034d29e5144b91afaebbc1ca28e9eacaa694821f267617c5cc3b5812f914315097b210e50c31cccc33dcc3310166b0c3a00a800e11be916b0e02875105e99127e4b458784594de119c5be391096f4f245bd3e19ce16a035f8f784a255e4b91bf5af58e6c8b25b0ea151a74c9000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb000000000000000000000000000000000000000000000000000000000000002300000000000000000000000033090fc05f8e16cae75f332ebd31bb92135ee43028942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae61293b778ea3a0add86d973685193aac98de614c89ed36878548b7e2a4abb37bf244289929b41c2ca77197403e44de06d465b59e36f189cbff475f4507f7676d0080338e4831274e7ebb54e58c60ad99e45273c61a7e8928f22a52784987e49d61d915117aeeeeeb6619849969af3e29831e98e5fef5b7ee074710aa86a76bd1c27b1e5fb6cd2e22786fce1f03564cdc8c1ed37a9a7d8f036351132437c16c2bf1edf147d96e5946d37803b5b60606971186736514563b075e15c871aa8072f552659fc082dc7dde5907057306ea98d5c1d82a96fc92a5ccd31fed314579e5ce92e1c0ef05de09ea78c2b62c8b4b51b33235fbea7ec6cd6fb6678ba6a81ecfb0b09b380a270901fe8ecf3b5c8875cfafcefc3ac58e44d7233756d97e0844234f5000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb00000000000000000000000000000000000000000000000000000000000000230000000000000000000000006a63428000c4d1f428c3a7546dbc2b897336304a28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae612cd2880f852b8d726ec68101fa2ee3011c46c3e3c111a39db1356bba256244c2b88c6ff827347a3a00d18c54feff6f30519ac8f95a4851f05c148b15072f8b20aa1e91b77afa9bbd05aef46c2b90b138a1e6117c9d87a73f682e5db6ae890232a5a58a0063bd20022baba8317a33105e3f9ed5ff9786fe114c8bcf9c93d8d092bcda239c922faf406ae57773acab2fadebcf4fde5763153fabdbf198c36146010a39e592415cd62fc4eefe6e6f00c24aee3c626c1d8e4efe0ff664324d172441e993b5f28bb82d89c318f23c0c8b34b8d3d22fa692be9918ecc1e813144be9b014021eb71ccc2649f3a3c0cb7b56eccc633b41daee6f51fc3acca801201a69620784e86e0894942c024878b4b0040040851c2bf0ca42b34381e95fc28e28a28000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000e38fb18ff3738c39b1d9f9352f2468c4426ce4ae28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae61c4102b911ae374a542f5c3c2629332d107f87c9d7f084e58ad6686b8ca032d02e4945598231c20938d0af0ce8567fb69936139c2ba3d6e8e1d9c7d986367a9f29a32ba151998a6732af0747596e22828161d91a3a92ed6664a99b7a0d988c2302b6f9af088ccf5d117a451d93d5b97a4555853aae24178279175905606d3af91c3f6e575377a0504d03e34de54894bc2caec9be3dac382a8d39be54a37069442f58d5cedd52832dddece59733cd2b4a6d370681b5a48b52bc76667902f20c0d1011a2c4396ef44f6003ae3bfb73948a1ecfa6f1855984b0d211ac0f4870a7682cd9ba5ecf6858e550b4fdc10893a899d9bc5327885047c271380499c3c0a7f51be5923b17ea743f23538d8b463fd7d142301174b8b9253f11b7e74310b4c17d000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb00000000000000000000000000000000000000000000000000000000000000230000000000000000000000006d012fe8cdfd1b3db63e95c8d7a06dc9e0b66aef28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae61f92267a1575d60651f0ca0a74d2ab67989f3ccc976b18246b504fca3df8cef31db8c4f95b1afeb35f826a69dca4995c5d2efcf3e9e459bbf99cca255ca1e8ea08c230b042609463c274ed7e6439e545d730c770ff035643c98c03bc419ef0c82eb48d9897932b8f919dc0684164b261d640c0a25e7064de8413beeb515d95121b47662c8e2fc34190f77919fa05e41226a1fa236d464cdd0c46e5d0822fdb4226ab9297b1ac2763b87897e4001bb5fd117ba894621c4f19291b31e074f4614523259e4884d735dbd2f0be3a5e687ccd4824a0a501cc311578f49a13b82beb0e18f3a1aca9688d95856c04b6a6c453397b08301bbb222c83e0a5ef28a116dce41c8ee0133596865178948427ffbfacf1856dbf317bc0d10ecb2ca1aa33dee293000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb000000000000000000000000000000000000000000000000000000000000002300000000000000000000000049c0d6a9e6f273c4494f3568e55d0a313c2edcfc28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae612c4c6415c49c164f8c81c76939fde44b1e6619d1946eb673ac203903dc36a00001c8c09a245beacc76f69f41def1da2219a0cd1ea328134e3aba603e29770fc1ef007c81d6fec56f2f1633d4a5f0b185fad2f719a8b92c624c1441eb2a2f9633020b4b1a0c2a6b16dea1fe908f0d5ab7c2d6f9d7ab50abd9135c25936c317a200f31f339962c0bba6bf3878088ee151d5163df24097350d02cc00f3d5f3a2e316554592f12df06777fc2eeb343641083f6299f66bd6f6f4ae3c125da8cc15680d35cfdfc71d15f59e6e37bae016dfc96da646aea2fbdba7be6fd334c53490ee008c2f1d877ed983a8afe7f98529da6e8186cb1874695070aeb5dc126d4235ad1fd76af0b23372d37b7f5181db3da8d2a46848cf4a473d55ccd23def6db02d46000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000485d8a98bb5dc09f1735aecbc8144ab2db7b545428942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae60543198b027d09bba2e1a841d4d3abd89256be8b84db977f5f651fbadf879efa05b9205ea53264deb3985cd04a071d90646a7f7f598d2caf2d2d005ad498943e15e5e0bbe91d868a0ee665e0651f8ffb6c6d2ac509c43d5bb53d805bc6c15f6d06909f64060d8c1a9519cf2b2c06a4542594ef2c3f03628ab85816700d9e6d4115ae7319fb08e0d7cc7755a766fe2be37a6f41332c900b23330c78cfb42e965b0fb6968782b33ec1dc44e79704c6eab3264b4a1a95caa47f3c1eeba76ab83dea260c18ce79fef579dacdc214b521666a9cb9c5ecd0ef82199e2b045ab073bd0926ccbdd591bacf2f04ce8b13437ec5ee71061c37a3bbd68879e0917ddf157ff5082b9767119e087ee6979a6ba346d99a2f6755aab877b680bd1973b7e6c96563000000000000000000000000000000000000000000000000000000000000000000000000000000007b46ffbc976db2f94c3b3cdd9ebbe4ab50e3d77d000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000184a41e6ceb0000000000000000000000000000000000000000000000000000000000000023000000000000000000000000231a2f44fde5788ee99c2ea163be421714ee47fc28942a4cc38d6ce636ded96f848bf0f3f547664e91b63f3daa080fbebc7d6ae624bd26434331113463b0801bad03295369f09b001551e3039be9a5c86f7c463d0fdd76dae5e472d7738264ac9db2ef6179e1d90a2e2f7931de1b862d24e4cacc171d8f1057095e652a2276423f70ec952dc43abb32bc72ca8080ae10451098b40aca120d5b8822848412087d67b40498eeab7246254d95db1b49b2b77838bee02597c0796b870fe29d3e0fcb8cd2d3148cc5d29ac0e0fe3cc1b42310b6f06cc90f771c1c8425d1e6ee1929cbc01986def1ea012780d606b41cf378682c9a0a2a13e44d09eac7239b532e1c5d99fc76a5b0c0e184edc31aea2b1ded286a8b7b8b1b8c744c3b5b68a413b7710a4106993e0e3aa97c148bbc46e7bd475e4a4a0bf71a64ba3b34be6656b6760ccd4b3c080019735cbf852cd50a5608d56ead05ffe900000000000000000000000000000000000000000000000000000000c080a0f613146bcf55b47f690f88aa4d95f8e188b28065b0ddbd49f689c7776a4049b3a00b4d55033092f80ca9df1123c6437f52372e2548cb8fbeca54722d9fe760e3c2").into() - ]; - let payload_attrs = OpPayloadAttributes { - payload_attributes: PayloadAttributes { - timestamp: 1717730355, - suggested_fee_recipient: FEE_RECIPIENT, - withdrawals: Default::default(), - prev_randao: b256!( - "c7acc30c856d749a81902d811e879e8dae5de2e022091aaa7eb4b586dcd3d052" - ), - parent_beacon_block_root: Some(b256!( - "a4414c4984ce7285b82bd9b21c642af30f0f648fb6f4929b67753e7345a06bab" - )), - target_blobs_per_block: None, - max_blobs_per_block: None, - }, - gas_limit: Some(30_000_000), - transactions: Some(raw_txs), - no_tx_pool: Some(false), - eip_1559_params: None, - }; - let produced_header = l2_block_executor.execute_payload(payload_attrs).unwrap().clone(); - - assert_eq!(produced_header, expected_header); - assert_eq!( - l2_block_executor.trie_db.parent_block_header().seal(), - expected_header.hash_slow() - ); - } - - #[test] - fn test_l2_block_executor_big_block_2() { - // Static for the execution of block #121135704 on OP mainnet. - // https://optimistic.etherscan.io/block/121135704 - - // Make a mock rollup config, with Ecotone activated at timestamp = 0. - let rollup_config = RollupConfig { - l2_chain_id: 10, - regolith_time: Some(0), - canyon_time: Some(0), - delta_time: Some(0), - ecotone_time: Some(0), - base_fee_params: OP_MAINNET_BASE_FEE_PARAMS.as_base_fee_params(), - canyon_base_fee_params: OP_MAINNET_BASE_FEE_PARAMS.as_canyon_base_fee_params(), - ..Default::default() - }; - - // Decode the headers. - let raw_parent_header = hex!("f90245a0e5d5cf15815d34d1f52079c2eade50abb5a4fb076f63276f8040e81116d87e72a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347944200000000000000000000000000000000000011a05605664e786f79b2312e293136d1aa6d5624181a59ad30bd11c91047100d2365a0cab880357793e1e6207e913de30eeaed08f7678c6d7822e8d5d44eec9b0ccd3ba073d6669bdb07a8d3fd21c24289e7176bd2890404acfd1978004c0da9f7ba4a48b90100008000000100200000c01080000000000000080000000020000c08000000000000001000030000010000003000800040000900c000000000040100400024000001000000000080000100000800000004000000000005200008001800800000100001000002000002000010000000082000004000090000000000685000a802000a00000008000000000004000000400000010001002080002000000820000802021000000004280200084200000001000080000000200000200080000000000040020082000000000000080000080000000000000000000000040000000060200090020800000080101000400000021000008400030008c000008000000108408084073862578401c9c3808312003c8466649e6780a023b3d2cb1b7216ef94837fdf94767b6235ce735a19de4f3feee7c1d603f2d10b880000000000000000840393d0c8a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080a08ab0d68c0fc4fe40d31baf01bcf73de45ddf15ab58e66738ca6c60648676f9af"); - let parent_header = Header::decode(&mut &raw_parent_header[..]).unwrap(); - let raw_expected_header = hex!("f90245a0b87093412624e12fb30c80675628005b0c4abaaf3feeccb5b900f0824267a3fca01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347944200000000000000000000000000000000000011a0c8201bf473cbf8adfaf240910aea025ea33573af383777a31407a4a4cf3cbfc7a064a9e23c5c2b545af4351d800e6d78dc4f209dc6253caad14751fdb79e45d0e6a0d95d3aa24da126f4a7ef04585d2f3ab7623e152305c3ba3da5231ab3cd6d3bd1b90100020000000101008180000100100000000000010000000000000c0204042100020291100002000000000002100000080000880000080220400400004000240b400000a00000004000a0801e091020040008000800012400000040000880100040000040210204000000000200010008400040000000100004000009b0000200000000020040000000002000001040110000012481002000001000010000804000820000401480080020480002400008809210006105000000000020001000000824201a1300000080002400000000000000c0000000004008000000004008608000104008ca0000000001000000000000020004200000094400001000000604428084073862588401c9c380831cc6d98466649e6980a023b3d2cb1b7216ef94837fdf94767b6235ce735a19de4f3feee7c1d603f2d10b8800000000000000008403910441a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080a08ab0d68c0fc4fe40d31baf01bcf73de45ddf15ab58e66738ca6c60648676f9af"); - let expected_header = Header::decode(&mut &raw_expected_header[..]).unwrap(); - - // Initialize the block executor on block #121135703's post-state. - let mut l2_block_executor = StatelessL2BlockExecutor::builder( - &rollup_config, - TestdataTrieProvider::new("block_121135704_exec"), - NoopTrieHinter, - ) - .with_parent_header(parent_header.seal_slow()) - .build(); - - let raw_txs = alloc::vec![ - hex!("7ef8f8a0bd8a03d2faac7261a1627e834405975aa1c55c968b072ffa6db6c100d891c9b794deaddeaddeaddeaddeaddeaddeaddeaddead00019442000000000000000000000000000000000000158080830f424080b8a4440a5e2000000558000c5fc500000000000000070000000066649ddb000000000131eb9a000000000000000000000000000000000000000000000000000000023c03238b0000000000000000000000000000000000000000000000000000000000000001427035b1edf748d109f4a751c5e2e33122340b0e22961600d8b76cfde3c7a6b50000000000000000000000006887246668a3b87f54deb3b94ba47a6f63f32985").into(), - hex!("02f8740a83180225840bebc200841dcd6500830249f0944ccc17a0cb35536d479d77adea2f8aa673e9b2d38703e871b540c00080c001a09e25fc89301001dc632d96e4ae9141953689fe57bb5f4925bb52d8ad113cec049f2a5e231b2ecf6a7f541b466d8f87445cb467cd5f632d7ffc2999c7dc580a5b").into(), - hex!("02f8750a83180226840bebc200841dcd6500830249f094212f4275087516892c3ee8a0b68fcf9c13f6edbd8703e871b540c00080c080a0df653a88e57f031682ef1e97ebed3cade860186ce6a2a1e56065929d1f9570aba075e2c34f0abad126a901d7947fdb8640d4b3d0c096b70be77cbd23f963645eb1").into(), - hex!("02f8750a83180227840bebc200841dcd6500830249f0944b178ebb31988b0b7df425e2fa9247113c9a9a8e8703e871b540c00080c001a06cf51a0ce263413929c7219f2696da810b1ac0b24c19417ed124f48f426b28e5a06caab14e2e884b1e6e4940b88a834a92465351db58a3b4abdc638adb2877ed6a").into(), - hex!("02f8750a83180228840bebc200841dcd6500830249f094169e79e9e33763aeba5c1eee6b265eb24a24b0598703e871b540c00080c001a0077aed7927363b13ee91ec719b9cbba48227c50ea80e72829e4c54a492402be7a034ffcf5d50d3821665266e217cb3edaf43aadd99837b14b36dd97054db837eeb").into(), - hex!("02f8750a83180229840bebc200841dcd6500830249f0941677c2a6d05056651bd8eeffb8834037a86b5a598703e871b540c00080c001a03f4c22cec9402f9d04c1f1e92406cc5a53ccccc906430047382ee0c477172990a0141ed5488e7b89eb22484e2f3685ade5933f8e4d6ae03c55722f81c48ce3e6ec").into(), - hex!("02f8750a8318022a840bebc200841dcd6500830249f094613849638013429abca858d60bab0c991da5e3dd8703e871b540c00080c001a0674d1cf0c2ec10ec8cf3ddf1ceb13d334b95e508b05ffb6ea07f3f1018c8886ca01b89992a74e451b929430e516529379abe853615b605669251a162123b6a319c").into(), - hex!("02f8750a8318022b840bebc200841dcd6500830249f094958f564d5a9586deee8cde55676400810796779c8703e871b540c00080c001a0d0dc11affeaa5f379ab4a8995cd00d7324cb7a6875c48f3ac8343c11d47b7ee1a02453699b07195ea21a807f88f39c01a1d809d45654399a2e4c852ca177eaaaed").into(), - hex!("02f904780a0c84068e778084068e77808302df9894ef4fb24ad0916217251f553c0596f8edc630eb668718cfb10af2a4f7b90404b930370100000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000018ff90a61f40000000000000000000000000000000000000000000000000000000000000340000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003600000000000000000000000000000000000000000000000000000000000000380000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000154232662c24f700000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000014c61b1fedfc00000000000000000000000000000000000000000000000000000000000000a4b100000000000000000000000000000000000000000000000000000000000001a000000000000000000000000046eef3e36b4e393922fa3c32e9f43f899b3f712700000000000000000000000000000000000000000000000000000000000001e000000000000000000000000000000000000000000000000000000000000002200000000000000000000000000000000000000000000000000000000000000240000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000000140000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001446eef3e36b4e393922fa3c32e9f43f899b3f7127000000000000000000000000000000000000000000000000000000000000000000000000000000000000001446eef3e36b4e393922fa3c32e9f43f899b3f71270000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000410101010000e60075efbc77000000000000000000000000000000fced1f1bc61400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c080a0bd38744150a6226dd2a4d86fb406292059fb7e9599ad2ff0968815554aaa7127a01857d067cc9495cb8678d42732d1ee2717438ee248fc0c11c4881fd0e573905c").into(), - hex!("02f8ae0a0c83cc52e084062efafe829db294420000000000000000000000000000000000004280b844a9059cbb000000000000000000000000efb3cc77ebb75333112cc61ef19772f9155d2add00000000000000000000000000000000000000000000005150ae84a8cdf00000c080a05ec4c586fbbdee52dfaa903b1151a48bc5df2cd210e2a0d87daf15b433203467a060e3ee29b6d862c6ec0d1f91b241b8e45a142fda4dc69458ff2cac8738dd37b9").into(), - hex!("02f904130a8308267e839896808406538c1d8307a12094903f58ee6d6c3c2ca26427c8f917f6ae515827b180b903a4c9807539000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000002600000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001c000000000000000000000007c2b7b4ac0fcc188b3e7ff5b83f6597f0005ed340209010308020507000406000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000b575892db6100000000000000000000000000000000000000000000000000000b5c6a298fef00000000000000000000000000000000000000000000000000000b5c6a298fef00000000000000000000000000000000000000000000000000000b5c83646d3300000000000000000000000000000000000000000000000000000b5c8538f80000000000000000000000000000000000000000000000000000000b5c8538f80000000000000000000000000000000000000000000000000000000b5c8538f80000000000000000000000000000000000000000000000000000000b5c8baa58fb00000000000000000000000000000000000000000000000000000b5c99feb2d700000000000000000000000000000000000000000000000000000b5c9c9f4a780000000000000000000000000000000000000000000000000000000000000004dc74097b0e5cc36a7cdf0722fb9608cf7e9a5a535475e34b78efbc9a2ef2555cf24b376824df6cfc3fe2db6e24797c1efa2ff2dbb64d34fac96fa7b7fa31a8e1480b1b684b1bc449c33d8f1709efe37cce06183ceae81c69833c48ebcb1a216ce73e8eb98ce8cc7e71d39b5636b91951e671bce12498e604b57be8bff88e448f00000000000000000000000000000000000000000000000000000000000000044a328613d73f44e21da13f28f233958119f314e9e1ebe1f4541eb209436c36c16618e2edf999aa2d263d5a6734f6a341143633023235a81ccda6917bddfa340e5b2f76db20be0dbae19af99a2430e3f0c111880eaa98cd95580b441a1fc2621645e5d7610a6697a0178c67d6fa3812710c179e6a5c7ef0f607b19aedfeedc39cc001a0303b7d9a441823918d302b04cb58ca6b5c834d952af0429709a717ed2316a48da03d9a9af29b52b6d33678b79b6e794eea4e12519b7de717c9ccf495b2d4ee6f13").into(), - hex!("02f8b20a832cfaab834c4b4085012a05f20082cc149494b008aa00579c1307b0ef2c499ad98a8ce58e5880b844a9059cbb0000000000000000000000008bfd47c9c6ff6ae8757f2bbe78e585471348fb72000000000000000000000000000000000000000000000000000000000213c4d0c080a0dead8785821ccedfe19e14a59822a6798766268dc5eca2179e0be9f05f8e2431a053ef2c483ab1eb1d2feea63a2e3f40769f8cbe419853a4213e7bdd147cc64842").into(), - hex!("f869018403b83b4a82561394a061b7f22ba72df1bd64fc8980a66df01a9b21d086026f910a80f28038a0c43718694719ebcc8116e6ae21b1ab64487c43a56b4b3e78ae9a361a7ea57614a056f90d2b9f6e8a1776d61ed6eaf831e6e1c64310ebfd34e5b828bac83557a44d").into(), - hex!("f869018403afd9a6825dd894a061b7f22ba72df1bd64fc8980a66df01a9b21d086021ce0d33aa58037a0b471d2ea71e7d125e64ffd3d141318ce949a40cd0b39cca01625c41e57dead89a073f5fc7c2b79e98053907cd62dac09ed86eae297acd7f22c44ea11ab8a1ca26e").into(), - hex!("02f904da0a83012990830f424084045e2f258305e39c9400000000fc04c910a0b5fea33b03e0447ad0b0aa8702e5763b5ce075b90464a44c9ce700000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000160000000000000000000000000000000000000000000000000000000000000000000000000000000000000000029d7230c7d0257d69880fa5255bcb14863b0e6d100000000000000000000000000000000fcb080a4d6c39a9354da9eb9bc104cd7000000000000000000000000000000000000000000000000000000006664a0bd00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000041fe4bb48f83d1fba43c9f77e98386c43cf86872532b0b047c7c53080bf36e7d823a2206018d9ca46a93c21385de8ea5f2d37d5d9d3980cd4a89807ce1a2a415e51c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000006664a0bd00000000000000000000000000000000000000000000000000000000000002400000000000000000000000000000000000000000000000000000000000000020659a6d1a52778774ecc59ebdd05f205d8713b62ed4160cb76474c091f1cdb5f60000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000023c000000000000000000000000002ef790dd7993a35fd847c053eddae940d0555960000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000006664a0bd000000000000000000000000000000000000000000000000000000000000004139457ec7958ea305974201cf59c768e680ad098fd5b174d4653eb99e2077a9bc270b641cd87b6f4e52eba7d072cf169eb5c1fe995e442f0f7fd82df12bf2416f1c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000415056e9bcf742ba1be88d2fe14568d67f70bdf3c230a425d2152fa8d4097d68ba125c520e1e3a778992f0978913ccf51364799ac9a24a30dc70d156f67eff9a891b00000000000000000000000000000000000000000000000000000000000000c001a04ff321d98b0de90b4149b0e99ba8d291c6208d63d50fad85574e51f6eebbadb4a061590ed8c64190dcb7934c10073c670876c5e62de3eb17d8ffd5b061cf12d922").into(), - hex!("02f906770a81a0830f42408407566a76830927c09400000029e6005863bb2e1686a17c4ae0d17236698694b19b4eb054b9060424856bc300000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000208010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000005af3107a4000000000000000000000000000000000000000000000000000000000000000049400000000000000000000000006d4b5289b981933e34af10817f352061bad6353000000000000000000000000000000000000000000000000000000000000012000000000000000000000000042000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005ae1b619cd6b0000000000000000000000000000000000000000000000000000000000000001800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000410000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000001c00000000000000000000000000000000000000000000000000000000000070e3c000000000000000000000000000000000000000000000000000000000004e56c0000000000000000000000004939d67eeb427312c86d9f889bd7d90cbd1ca2660000000000000000000000000000000000000000000000000000000000a909920000000000000000000000000000000000000000000000000000000008e068db00000000000000000000000000000000000000000000000000000000000151800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004114000000000000000000000000000000000000000000000000000000000000000000000000000000000000000006d4b5289b981933e34af10817f352061bad635300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004114000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000029e6005863bb2e1686a17c4ae0d17236690000000000000000000000000000000000000000000000000000000000000000000029e6005863bb2e1686a17c4ae0d172366900000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000109000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000000400000000000000000000000004939d67eeb427312c86d9f889bd7d90cbd1ca2660000000000000000000000000000000000000000000000000000000000000000000000000000000000000000c001a0412f0c2e72d680c2fedd9c1282ca4935f0646baea439ea372fa28a3febfcf648a0572980c28d5ba9522f592b7f3d39a94b5f5b123a62f6bb136685b12a1d9e7c52").into(), - hex!("02f904da0a83012933830f424084045e2f258305e39c9400000000fc04c910a0b5fea33b03e0447ad0b0aa8702e5763b5ce075b90464a44c9ce7000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000001600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ff5f082dbf2d2f930eb3d2b51bb2f1010a4d5a8900000000000000000000000000000000fcb080a4d6c39a9354da9eb9bc104cd7000000000000000000000000000000000000000000000000000000006664a0bd00000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000041819edf15e18a545cbbabbd24c9f3e136a3dcec10c65f5ce19d6fb903e586e6db5f2e154210d25768487e89cb7d9b62cc611421c3456538c7d9ac39f0fd619e111c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000006664a0bd000000000000000000000000000000000000000000000000000000000000024000000000000000000000000000000000000000000000000000000000000000205183a065a3c67e765796c2969e67b960d2ae041a36070a7ed719b18b5682bdda0000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000023c000000000000000000000000002ef790dd7993a35fd847c053eddae940d0555960000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000006664a0bd0000000000000000000000000000000000000000000000000000000000000041dd6bb97a2c5250e07ba4b0df71715c81ac9adc5ee1111a0f8ff3845321ac7d5262a7cdd80df46391bc4e41b5f1492110a42badfb7b6ebdd8944e2c3c9a9d8e621c000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000041d5ae1701d2a1750e608e1f2b5d10280db952ddb14cc35f819f7334e9eb5133a5072108be5f5134ac6c061fa9e3bcee464ad8c8e13e206cd5c6b632a7294cd34b1c00000000000000000000000000000000000000000000000000000000000000c001a0994107041475defdb265cdbe6da3df610516ec50a81dd9c0a3602c20d1c72b22a04b28a32d391ebdc15e63ffd26dc3a91e6c3c0565538e33e04558a9d1c9d70b3f").into(), - hex!("02f8b50a01830f424084045a3cc98306213f942a5c54c625220cb2166c94dd9329be1f8785977d866e5ceb32785cb844f5c358c60000000000000000000000000000000000000000000000000000000000000504000000000000000000000000000000000000000000000000000000000263b143c001a051a2584f761c7ef2216652d41840cb1e84c0576d076c72f06906777cb043d45aa02bdbb191600306e5f3ff6d65991f61979f8a10d60d0c6ccaaf1f6d5c7515dac2").into() - ]; - let payload_attrs = OpPayloadAttributes { - payload_attributes: PayloadAttributes { - timestamp: 1717870185, - prev_randao: b256!( - "23b3d2cb1b7216ef94837fdf94767b6235ce735a19de4f3feee7c1d603f2d10b" - ), - withdrawals: Default::default(), - suggested_fee_recipient: FEE_RECIPIENT, - parent_beacon_block_root: Some(b256!( - "8ab0d68c0fc4fe40d31baf01bcf73de45ddf15ab58e66738ca6c60648676f9af" - )), - target_blobs_per_block: None, - max_blobs_per_block: None, - }, - gas_limit: Some(30_000_000), - transactions: Some(raw_txs), - no_tx_pool: None, - eip_1559_params: None, - }; - let produced_header = l2_block_executor.execute_payload(payload_attrs).unwrap().clone(); - - assert_eq!(produced_header, expected_header); - assert_eq!( - l2_block_executor.trie_db.parent_block_header().seal(), - expected_header.hash_slow() - ); + use crate::test_utils::run_test_fixture; + use rstest::rstest; + use std::path::PathBuf; + + // To create new test fixtures, uncomment the following test and run it with parameters filled. + // + // #[tokio::test(flavor = "multi_thread")] + // async fn create_fixture() { + // let fixture_creator = crate::test_utils::ExecutorTestFixtureCreator::new( + // "", + // , + // PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("testdata"), + // ); + // fixture_creator.create_static_fixture().await; + // } + + #[rstest] + #[case::small_block(22884230)] + #[case::small_block_2(22884231)] + #[case::small_block_3(22880574)] + #[case::small_block_4(22887258)] + #[case::medium_block(22886464)] + #[case::medium_block_2(22886311)] + #[case::medium_block_3(22880944)] + #[tokio::test] + async fn test_statelessly_execute_block(#[case] block_number: u64) { + let fixture_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")) + .join("testdata") + .join(format!("block-{block_number}.tar.gz")); + + run_test_fixture(fixture_dir).await; } } diff --git a/crates/executor/src/executor/util.rs b/crates/executor/src/executor/util.rs deleted file mode 100644 index f48a1a3ca6..0000000000 --- a/crates/executor/src/executor/util.rs +++ /dev/null @@ -1,204 +0,0 @@ -//! Contains utilities for the L2 executor. - -use crate::{constants::HOLOCENE_EXTRA_DATA_VERSION, ExecutorError, ExecutorResult}; -use alloc::vec::Vec; -use alloy_consensus::Header; -use alloy_eips::eip1559::BaseFeeParams; -use alloy_primitives::{Bytes, B64}; -use op_alloy_genesis::RollupConfig; -use op_alloy_rpc_types_engine::OpPayloadAttributes; - -/// Parse Holocene [Header] extra data. -/// -/// ## Takes -/// - `extra_data`: The extra data field of the [Header]. -/// -/// ## Returns -/// - `Ok(BaseFeeParams)`: The EIP-1559 parameters. -/// - `Err(ExecutorError::InvalidExtraData)`: If the extra data is invalid. -pub(crate) fn decode_holocene_eip_1559_params(header: &Header) -> ExecutorResult { - // Check the extra data length. - if header.extra_data.len() != 1 + 8 { - return Err(ExecutorError::InvalidExtraData); - } - - // Check the extra data version byte. - if header.extra_data[0] != HOLOCENE_EXTRA_DATA_VERSION { - return Err(ExecutorError::InvalidExtraData); - } - - // Parse the EIP-1559 parameters. - let data = &header.extra_data[1..]; - let denominator = - u32::from_be_bytes(data[..4].try_into().map_err(|_| ExecutorError::InvalidExtraData)?) - as u128; - let elasticity = - u32::from_be_bytes(data[4..].try_into().map_err(|_| ExecutorError::InvalidExtraData)?) - as u128; - - // Check for potential division by zero. - if denominator == 0 { - return Err(ExecutorError::InvalidExtraData); - } - - Ok(BaseFeeParams { elasticity_multiplier: elasticity, max_change_denominator: denominator }) -} - -/// Encode Holocene [Header] extra data. -/// -/// ## Takes -/// - `config`: The [RollupConfig] for the chain. -/// - `attributes`: The [OpPayloadAttributes] for the block. -/// -/// ## Returns -/// - `Ok(data)`: The encoded extra data. -/// - `Err(ExecutorError::MissingEIP1559Params)`: If the EIP-1559 parameters are missing. -pub(crate) fn encode_holocene_eip_1559_params( - config: &RollupConfig, - attributes: &OpPayloadAttributes, -) -> ExecutorResult { - let payload_params = attributes.eip_1559_params.ok_or(ExecutorError::MissingEIP1559Params)?; - let params = if payload_params == B64::ZERO { - encode_canyon_base_fee_params(config) - } else { - payload_params - }; - - let mut data = Vec::with_capacity(1 + 8); - data.push(HOLOCENE_EXTRA_DATA_VERSION); - data.extend_from_slice(params.as_ref()); - Ok(data.into()) -} - -/// Encodes the canyon base fee parameters, per Holocene spec. -/// -/// -pub(crate) fn encode_canyon_base_fee_params(config: &RollupConfig) -> B64 { - let params = config.canyon_base_fee_params; - - let mut buf = B64::ZERO; - buf[..4].copy_from_slice(&(params.max_change_denominator as u32).to_be_bytes()); - buf[4..].copy_from_slice(&(params.elasticity_multiplier as u32).to_be_bytes()); - buf -} - -#[cfg(test)] -mod test { - use super::decode_holocene_eip_1559_params; - use crate::executor::util::{encode_canyon_base_fee_params, encode_holocene_eip_1559_params}; - use alloy_consensus::Header; - use alloy_eips::eip1559::BaseFeeParams; - use alloy_primitives::{b64, hex, B64}; - use alloy_rpc_types_engine::PayloadAttributes; - use op_alloy_genesis::RollupConfig; - use op_alloy_rpc_types_engine::OpPayloadAttributes; - - fn mock_payload(eip_1559_params: Option) -> OpPayloadAttributes { - OpPayloadAttributes { - payload_attributes: PayloadAttributes { - timestamp: 0, - prev_randao: Default::default(), - suggested_fee_recipient: Default::default(), - withdrawals: Default::default(), - parent_beacon_block_root: Default::default(), - target_blobs_per_block: None, - max_blobs_per_block: None, - }, - transactions: None, - no_tx_pool: None, - gas_limit: None, - eip_1559_params, - } - } - - #[test] - fn test_decode_holocene_eip_1559_params() { - let params = hex!("00BEEFBABE0BADC0DE"); - let mock_header = Header { extra_data: params.to_vec().into(), ..Default::default() }; - let params = decode_holocene_eip_1559_params(&mock_header).unwrap(); - - assert_eq!(params.elasticity_multiplier, 0x0BAD_C0DE); - assert_eq!(params.max_change_denominator, 0xBEEF_BABE); - } - - #[test] - fn test_decode_holocene_eip_1559_params_invalid_version() { - let params = hex!("01BEEFBABE0BADC0DE"); - let mock_header = Header { extra_data: params.to_vec().into(), ..Default::default() }; - assert!(decode_holocene_eip_1559_params(&mock_header).is_err()); - } - - #[test] - fn test_decode_holocene_eip_1559_params_invalid_denominator() { - let params = hex!("00000000000BADC0DE"); - let mock_header = Header { extra_data: params.to_vec().into(), ..Default::default() }; - assert!(decode_holocene_eip_1559_params(&mock_header).is_err()); - } - - #[test] - fn test_decode_holocene_eip_1559_params_invalid_length() { - let params = hex!("00"); - let mock_header = Header { extra_data: params.to_vec().into(), ..Default::default() }; - assert!(decode_holocene_eip_1559_params(&mock_header).is_err()); - } - - #[test] - fn test_encode_holocene_eip_1559_params_missing() { - let cfg = RollupConfig { - canyon_base_fee_params: BaseFeeParams { - max_change_denominator: 32, - elasticity_multiplier: 64, - }, - ..Default::default() - }; - let attrs = mock_payload(None); - - assert!(encode_holocene_eip_1559_params(&cfg, &attrs).is_err()); - } - - #[test] - fn test_encode_holocene_eip_1559_params_default() { - let cfg = RollupConfig { - canyon_base_fee_params: BaseFeeParams { - max_change_denominator: 32, - elasticity_multiplier: 64, - }, - ..Default::default() - }; - let attrs = mock_payload(Some(B64::ZERO)); - - assert_eq!( - encode_holocene_eip_1559_params(&cfg, &attrs).unwrap(), - hex!("000000002000000040").to_vec() - ); - } - - #[test] - fn test_encode_holocene_eip_1559_params() { - let cfg = RollupConfig { - canyon_base_fee_params: BaseFeeParams { - max_change_denominator: 32, - elasticity_multiplier: 64, - }, - ..Default::default() - }; - let attrs = mock_payload(Some(b64!("0000004000000060"))); - - assert_eq!( - encode_holocene_eip_1559_params(&cfg, &attrs).unwrap(), - hex!("000000004000000060").to_vec() - ); - } - - #[test] - fn test_encode_canyon_1559_params() { - let cfg = RollupConfig { - canyon_base_fee_params: BaseFeeParams { - max_change_denominator: 32, - elasticity_multiplier: 64, - }, - ..Default::default() - }; - assert_eq!(encode_canyon_base_fee_params(&cfg), b64!("0000002000000040")); - } -} diff --git a/crates/executor/src/lib.rs b/crates/executor/src/lib.rs index ed11ebf1e3..49aefc3744 100644 --- a/crates/executor/src/lib.rs +++ b/crates/executor/src/lib.rs @@ -1,7 +1,7 @@ #![doc = include_str!("../README.md")] #![doc( - html_logo_url = "https://raw.githubusercontent.com/anton-rs/kona/main/assets/square.png", - html_favicon_url = "https://raw.githubusercontent.com/anton-rs/kona/main/assets/favicon.ico" + html_logo_url = "https://raw.githubusercontent.com/op-rs/kona/main/assets/square.png", + html_favicon_url = "https://raw.githubusercontent.com/op-rs/kona/main/assets/favicon.ico" )] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] #![cfg_attr(not(test), warn(unused_crate_dependencies))] @@ -16,10 +16,16 @@ mod errors; pub use errors::{ExecutorError, ExecutorResult, TrieDBError, TrieDBResult}; mod executor; -pub use executor::{KonaHandleRegister, StatelessL2BlockExecutor, StatelessL2BlockExecutorBuilder}; +pub use executor::{ + ExecutionArtifacts, KonaHandleRegister, StatelessL2BlockExecutor, + StatelessL2BlockExecutorBuilder, +}; mod db; -pub use db::{NoopTrieDBProvider, TrieAccount, TrieDB, TrieDBProvider}; +pub use db::{NoopTrieDBProvider, TrieDB, TrieDBProvider}; mod constants; mod syscalls; + +#[cfg(test)] +mod test_utils; diff --git a/crates/executor/src/syscalls/canyon.rs b/crates/executor/src/syscalls/canyon.rs deleted file mode 100644 index 14778626fc..0000000000 --- a/crates/executor/src/syscalls/canyon.rs +++ /dev/null @@ -1,57 +0,0 @@ -//! Contains logic specific to Canyon hardfork activation. - -use crate::{db::TrieDB, errors::ExecutorResult, TrieDBProvider}; -use alloy_primitives::{address, b256, hex, Address, Bytes, B256}; -use kona_mpt::TrieHinter; -use op_alloy_genesis::RollupConfig; -use revm::{ - primitives::{Account, Bytecode, HashMap}, - DatabaseCommit, State, -}; - -/// The address of the create2 deployer -const CREATE_2_DEPLOYER_ADDR: Address = address!("13b0D85CcB8bf860b6b79AF3029fCA081AE9beF2"); - -/// The codehash of the create2 deployer contract. -const CREATE_2_DEPLOYER_CODEHASH: B256 = - b256!("b0550b5b431e30d38000efb7107aaa0ade03d48a7198a140edda9d27134468b2"); - -/// The raw bytecode of the create2 deployer contract. -const CREATE_2_DEPLOYER_BYTECODE: [u8; 1584] = hex!("6080604052600436106100435760003560e01c8063076c37b21461004f578063481286e61461007157806356299481146100ba57806366cfa057146100da57600080fd5b3661004a57005b600080fd5b34801561005b57600080fd5b5061006f61006a366004610327565b6100fa565b005b34801561007d57600080fd5b5061009161008c366004610327565b61014a565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200160405180910390f35b3480156100c657600080fd5b506100916100d5366004610349565b61015d565b3480156100e657600080fd5b5061006f6100f53660046103ca565b610172565b61014582826040518060200161010f9061031a565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe082820381018352601f90910116604052610183565b505050565b600061015683836102e7565b9392505050565b600061016a8484846102f0565b949350505050565b61017d838383610183565b50505050565b6000834710156101f4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f437265617465323a20696e73756666696369656e742062616c616e636500000060448201526064015b60405180910390fd5b815160000361025f576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f437265617465323a2062797465636f6465206c656e677468206973207a65726f60448201526064016101eb565b8282516020840186f5905073ffffffffffffffffffffffffffffffffffffffff8116610156576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f437265617465323a204661696c6564206f6e206465706c6f790000000000000060448201526064016101eb565b60006101568383305b6000604051836040820152846020820152828152600b8101905060ff815360559020949350505050565b61014e806104ad83390190565b6000806040838503121561033a57600080fd5b50508035926020909101359150565b60008060006060848603121561035e57600080fd5b8335925060208401359150604084013573ffffffffffffffffffffffffffffffffffffffff8116811461039057600080fd5b809150509250925092565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000806000606084860312156103df57600080fd5b8335925060208401359150604084013567ffffffffffffffff8082111561040557600080fd5b818601915086601f83011261041957600080fd5b81358181111561042b5761042b61039b565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f011681019083821181831017156104715761047161039b565b8160405282815289602084870101111561048a57600080fd5b826020860160208301376000602084830101528095505050505050925092509256fe608060405234801561001057600080fd5b5061012e806100206000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063249cb3fa14602d575b600080fd5b603c603836600460b1565b604e565b60405190815260200160405180910390f35b60008281526020818152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915281205460ff16608857600060aa565b7fa2ef4600d742022d532d4747cb3547474667d6f13804902513b2ec01c848f4b45b9392505050565b6000806040838503121560c357600080fd5b82359150602083013573ffffffffffffffffffffffffffffffffffffffff8116811460ed57600080fd5b80915050925092905056fea26469706673582212205ffd4e6cede7d06a5daf93d48d0541fc68189eeb16608c1999a82063b666eb1164736f6c63430008130033a2646970667358221220fdc4a0fe96e3b21c108ca155438d37c9143fb01278a3c1d274948bad89c564ba64736f6c63430008130033"); - -/// The Canyon hardfork issues an irregular state transition that force-deploys the create2 -/// deployer contract. This is done by directly setting the code of the create2 deployer account -/// prior to executing any transactions on the timestamp activation of the fork. -pub(crate) fn ensure_create2_deployer_canyon( - db: &mut State<&mut TrieDB>, - config: &RollupConfig, - timestamp: u64, -) -> ExecutorResult<()> -where - F: TrieDBProvider, - H: TrieHinter, -{ - // If the canyon hardfork is active at the current timestamp, and it was not active at the - // previous block timestamp, then we need to force-deploy the create2 deployer contract. - if config.is_canyon_active(timestamp) && - !config.is_canyon_active(db.database.parent_block_header().timestamp) - { - // Load the create2 deployer account from the cache. - let acc = db.load_cache_account(CREATE_2_DEPLOYER_ADDR)?; - - // Update the account info with the create2 deployer codehash and bytecode. - let mut acc_info = acc.account_info().unwrap_or_default(); - acc_info.code_hash = CREATE_2_DEPLOYER_CODEHASH; - acc_info.code = Some(Bytecode::new_raw(Bytes::from_static(&CREATE_2_DEPLOYER_BYTECODE))); - - // Convert the cache account back into a revm account and mark it as touched. - let mut revm_acc: Account = acc_info.into(); - revm_acc.mark_touch(); - - // Commit the create2 deployer account to the database. - db.commit(HashMap::from_iter([(CREATE_2_DEPLOYER_ADDR, revm_acc)])); - return Ok(()); - } - - Ok(()) -} diff --git a/crates/executor/src/syscalls/eip2935.rs b/crates/executor/src/syscalls/eip2935.rs new file mode 100644 index 0000000000..584299eb34 --- /dev/null +++ b/crates/executor/src/syscalls/eip2935.rs @@ -0,0 +1,123 @@ +//! Contains the [EIP-2935][eip-2935] syscall. +//! +//! [eip-2935]: https://eips.ethereum.org/EIPS/eip-2935 + +use crate::{ + db::TrieDB, + errors::{ExecutorError, ExecutorResult}, + syscalls::fill_tx_env_for_contract_call, + TrieDBProvider, +}; +use alloc::boxed::Box; +use alloy_primitives::B256; +use kona_mpt::TrieHinter; +use op_alloy_genesis::RollupConfig; +use op_alloy_rpc_types_engine::OpPayloadAttributes; +use revm::{ + db::State, + primitives::{BlockEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg}, + DatabaseCommit, Evm, +}; + +/// Execute the [EIP-2935][EIP-2935] pre-block block hash contract call. +/// +/// If Isthmus is not activated, or the block is the genesis block, then this is a no-op, and no +/// state changes are made. +/// +/// Note: this does not commit the state changes to the database, it only transact the call. +/// +/// Returns `None` if Isthmus is not active or the block is the genesis block, otherwise returns the +/// result of the call. +/// +/// [EIP-2935]: https://eips.ethereum.org/EIPS/eip-2935 +pub(crate) fn pre_block_block_hash_contract_call( + db: &mut State<&mut TrieDB>, + config: &RollupConfig, + block_number: u64, + initialized_cfg: &CfgEnvWithHandlerCfg, + initialized_block_env: &BlockEnv, + parent_block_hash: B256, + payload: &OpPayloadAttributes, +) -> ExecutorResult<()> +where + F: TrieDBProvider, + H: TrieHinter, +{ + // apply pre-block EIP-4788 contract call + let mut evm_pre_block = Evm::builder() + .with_db(db) + .with_env_with_handler_cfg(EnvWithHandlerCfg::new_with_cfg_env( + initialized_cfg.clone(), + initialized_block_env.clone(), + Default::default(), + )) + .build(); + + // initialize a block from the env, because the pre block call needs the block itself + apply_block_hash_contract_call( + config, + payload.payload_attributes.timestamp, + block_number, + parent_block_hash, + &mut evm_pre_block, + ) +} + +/// Apply the EIP-4788 pre-block beacon root contract call to a given EVM instance. +fn apply_block_hash_contract_call( + config: &RollupConfig, + timestamp: u64, + block_number: u64, + parent_block_hash: B256, + evm: &mut Evm<'_, (), &mut State<&mut TrieDB>>, +) -> ExecutorResult<()> +where + F: TrieDBProvider, + H: TrieHinter, +{ + //TODO + // if !config.is_isthmus_active(timestamp) { + // return Ok(()); + // } + return Ok(()); + + // If the block number is zero (genesis block) then no system + // transaction may occur as per EIP-2935. + if block_number == 0 { + return Ok(()); + } + + // Get the previous environment + let previous_env = Box::new(evm.context.evm.env().clone()); + + // modify env for pre block call + fill_tx_env_for_contract_call( + &mut evm.context.evm.env, + alloy_eips::eip4788::SYSTEM_ADDRESS, + alloy_eips::eip2935::HISTORY_STORAGE_ADDRESS, + parent_block_hash.into(), + ); + + let mut state = match evm.transact() { + Ok(res) => res.state, + Err(e) => { + evm.context.evm.env = previous_env; + return Err(ExecutorError::ExecutionError(e)); + } + }; + + // NOTE: Revm currently marks these accounts as "touched" when we do the above transact calls, + // and includes them in the result. + // + // There should be no state changes to these addresses anyways as a result of this system call, + // so we can just remove them from the state returned. + state.remove(&alloy_eips::eip4788::SYSTEM_ADDRESS); + state.remove(&evm.block().coinbase); + + evm.context.evm.db.commit(state); + + // re-set the previous env + evm.context.evm.env = previous_env; + + Ok(()) +} diff --git a/crates/executor/src/syscalls/eip4788.rs b/crates/executor/src/syscalls/eip4788.rs index 2a84848354..b3e7a5e988 100644 --- a/crates/executor/src/syscalls/eip4788.rs +++ b/crates/executor/src/syscalls/eip4788.rs @@ -3,19 +3,17 @@ use crate::{ db::TrieDB, errors::{ExecutorError, ExecutorResult}, + syscalls::fill_tx_env_for_contract_call, TrieDBProvider, }; -use alloc::{boxed::Box, vec::Vec}; -use alloy_eips::eip4788::BEACON_ROOTS_ADDRESS; -use alloy_primitives::{Address, Bytes, B256, U256}; +use alloc::boxed::Box; +use alloy_primitives::B256; use kona_mpt::TrieHinter; use op_alloy_genesis::RollupConfig; use op_alloy_rpc_types_engine::OpPayloadAttributes; use revm::{ db::State, - primitives::{ - BlockEnv, CfgEnvWithHandlerCfg, Env, EnvWithHandlerCfg, OptimismFields, TransactTo, TxEnv, - }, + primitives::{BlockEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg}, DatabaseCommit, Evm, }; @@ -64,9 +62,11 @@ where F: TrieDBProvider, H: TrieHinter, { - if !config.is_ecotone_active(timestamp) { - return Ok(()); - } + //TODO + // if !config.is_ecotone_active(timestamp) { + // return Ok(()); + // } + return Ok(()); let parent_beacon_block_root = parent_beacon_block_root.ok_or(ExecutorError::MissingParentBeaconBlockRoot)?; @@ -84,7 +84,12 @@ where let previous_env = Box::new(evm.context.evm.env().clone()); // modify env for pre block call - fill_tx_env_with_beacon_root_contract_call(&mut evm.context.evm.env, parent_beacon_block_root); + fill_tx_env_for_contract_call( + &mut evm.context.evm.env, + alloy_eips::eip4788::SYSTEM_ADDRESS, + alloy_eips::eip4788::BEACON_ROOTS_ADDRESS, + parent_beacon_block_root.0.into(), + ); let mut state = match evm.transact() { Ok(res) => res.state, @@ -104,75 +109,3 @@ where Ok(()) } - -/// Fill transaction environment with the EIP-4788 system contract message data. -/// -/// This requirements for the beacon root contract call defined by -/// [EIP-4788](https://eips.ethereum.org/EIPS/eip-4788) are: -/// -/// At the start of processing any execution block where `block.timestamp >= FORK_TIMESTAMP` (i.e. -/// before processing any transactions), call [`BEACON_ROOTS_ADDRESS`] as -/// [`SYSTEM_ADDRESS`](alloy_eips::eip4788::SYSTEM_ADDRESS) with the 32-byte input of -/// `header.parent_beacon_block_root`. This will trigger the `set()` routine of the beacon roots -/// contract. -fn fill_tx_env_with_beacon_root_contract_call(env: &mut Env, parent_beacon_block_root: B256) { - fill_tx_env_with_system_contract_call( - env, - alloy_eips::eip4788::SYSTEM_ADDRESS, - BEACON_ROOTS_ADDRESS, - parent_beacon_block_root.0.into(), - ); -} - -/// Fill transaction environment with the system caller and the system contract address and message -/// data. -/// -/// This is a system operation and therefore: -/// * the call must execute to completion -/// * the call does not count against the block’s gas limit -/// * the call does not follow the EIP-1559 burn semantics - no value should be transferred as part -/// of the call -/// * if no code exists at the provided address, the call will fail silently -fn fill_tx_env_with_system_contract_call( - env: &mut Env, - caller: Address, - contract: Address, - data: Bytes, -) { - env.tx = TxEnv { - caller, - transact_to: TransactTo::Call(contract), - // Explicitly set nonce to None so revm does not do any nonce checks - nonce: None, - gas_limit: 30_000_000, - value: U256::ZERO, - data, - // Setting the gas price to zero enforces that no value is transferred as part of the call, - // and that the call will not count against the block's gas limit - gas_price: U256::ZERO, - // The chain ID check is not relevant here and is disabled if set to None - chain_id: None, - // Setting the gas priority fee to None ensures the effective gas price is derived from the - // `gas_price` field, which we need to be zero - gas_priority_fee: None, - access_list: Vec::new(), - authorization_list: None, - // blob fields can be None for this tx - blob_hashes: Vec::new(), - max_fee_per_blob_gas: None, - optimism: OptimismFields { - source_hash: None, - mint: None, - is_system_transaction: Some(false), - // The L1 fee is not charged for the EIP-4788 transaction, submit zero bytes for the - // enveloped tx size. - enveloped_tx: Some(Bytes::default()), - }, - }; - - // ensure the block gas limit is >= the tx - env.block.gas_limit = U256::from(env.tx.gas_limit); - - // disable the base fee check for this call by setting the base fee to zero - env.block.basefee = U256::ZERO; -} diff --git a/crates/executor/src/syscalls/mod.rs b/crates/executor/src/syscalls/mod.rs index 425aca27ca..8826c4230d 100644 --- a/crates/executor/src/syscalls/mod.rs +++ b/crates/executor/src/syscalls/mod.rs @@ -1,7 +1,10 @@ //! Optimism EVM System calls. +mod eip2935; +pub(crate) use eip2935::pre_block_block_hash_contract_call; + mod eip4788; pub(crate) use eip4788::pre_block_beacon_root_contract_call; -mod canyon; -pub(crate) use canyon::ensure_create2_deployer_canyon; +mod tx_env; +pub(crate) use tx_env::fill_tx_env_for_contract_call; diff --git a/crates/executor/src/syscalls/tx_env.rs b/crates/executor/src/syscalls/tx_env.rs new file mode 100644 index 0000000000..9c0b7bfbd3 --- /dev/null +++ b/crates/executor/src/syscalls/tx_env.rs @@ -0,0 +1,60 @@ +//! Contains a helper function to fill the [`TxEnv`] for the given system call. + +use alloc::vec::Vec; +use alloy_primitives::{Address, Bytes, U256}; +use revm::primitives::{Env, OptimismFields, TransactTo, TxEnv}; + +/// Fill transaction environment with the system caller and the system +/// contract address and message data. +/// +/// This is a system operation and therefore: +/// * the call must execute to completion +/// * the call does not count against the block’s gas limit +/// * the call does not follow the EIP-1559 burn semantics - no value should be transferred as part +/// of the call +/// * if no code exists at the provided address, the call will fail silently +pub(crate) fn fill_tx_env_for_contract_call( + env: &mut Env, + caller: Address, + contract: Address, + data: Bytes, +) { + env.tx = TxEnv { + caller, + transact_to: TransactTo::Call(contract), + // Explicitly set nonce to None so revm does not do any nonce checks + nonce: None, + gas_limit: 30_000_000, + value: U256::ZERO, + data, + // Setting the gas price to zero enforces that no value is transferred as part of the call, + // and that the call will not count against the block's gas limit + gas_price: U256::ZERO, + // The chain ID check is not relevant here and is disabled if set to None + chain_id: None, + // Setting the gas priority fee to None ensures the effective gas price is derived from the + // `gas_price` field, which we need to be zero + gas_priority_fee: None, + access_list: Vec::new(), + authorization_list: None, + // blob fields can be None for this tx + blob_hashes: Vec::new(), + max_fee_per_blob_gas: None, + optimism: OptimismFields { + source_hash: None, + mint: None, + is_system_transaction: Some(false), + // The L1 fee is not charged for the EIP-4788 transaction, submit zero bytes for the + // enveloped tx size. + enveloped_tx: Some(Bytes::default()), + eth_value: None, + eth_tx_value: None, + }, + }; + + // ensure the block gas limit is >= the tx + env.block.gas_limit = U256::from(env.tx.gas_limit); + + // disable the base fee check for this call by setting the base fee to zero + env.block.basefee = U256::ZERO; +} diff --git a/crates/executor/src/test_utils.rs b/crates/executor/src/test_utils.rs new file mode 100644 index 0000000000..2ef0fffe77 --- /dev/null +++ b/crates/executor/src/test_utils.rs @@ -0,0 +1,342 @@ +//! Test utilities for the executor. + +#![allow(missing_docs, unused)] + +use crate::{constants::FEE_RECIPIENT, StatelessL2BlockExecutor, TrieDBProvider}; +use alloy_consensus::Header; +use alloy_primitives::{Bytes, Sealable, B256}; +use alloy_provider::{ + network::primitives::{BlockTransactions, BlockTransactionsKind}, + Provider, RootProvider, +}; +use alloy_rlp::Decodable; +use alloy_rpc_client::RpcClient; +use alloy_rpc_types_engine::PayloadAttributes; +use alloy_transport_http::{Client, Http}; +use kona_host::{DiskKeyValueStore, KeyValueStore}; +use kona_mpt::{NoopTrieHinter, TrieNode, TrieProvider}; +use op_alloy_genesis::RollupConfig; +use op_alloy_rpc_types_engine::OpPayloadAttributes; +use serde::{Deserialize, Serialize}; +use std::{env::temp_dir, path::PathBuf, sync::Arc}; +use tokio::{fs, runtime::Handle, sync::Mutex}; + +#[derive(Debug, thiserror::Error)] +pub(crate) enum TestTrieNodeProviderError { + #[error("Preimage not found")] + PreimageNotFound, + #[error("Failed to decode RLP: {0}")] + Rlp(alloy_rlp::Error), + #[error("Failed to write back to key value store")] + KVStore, +} + +#[derive(Debug, Serialize, Deserialize)] +pub(crate) struct ExecutorTestFixture { + /// The rollup configuration for the executing chain. + pub(crate) rollup_config: RollupConfig, + /// The parent block header. + pub(crate) parent_header: Header, + /// The executing payload attributes. + pub(crate) executing_payload: OpPayloadAttributes, + /// The expected block hash + pub(crate) expected_block_hash: B256, +} + +#[derive(Debug)] +pub(crate) struct ExecutorTestFixtureCreator { + /// The RPC provider for the L2 execution layer. + pub(crate) provider: RootProvider, + /// The block number to create the test fixture for. + pub(crate) block_number: u64, + /// The key value store for the test fixture. + pub(crate) kv_store: Arc>, + /// The data directory for the test fixture. + pub(crate) data_dir: PathBuf, +} + +impl ExecutorTestFixtureCreator { + pub(crate) fn new( + provider_url: &str, + block_number: u64, + base_fixture_directory: PathBuf, + ) -> Self { + let base = base_fixture_directory.join(format!("block-{}", block_number)); + + let url = provider_url.parse().expect("Invalid provider URL"); + let http = Http::::new(url); + let provider = RootProvider::new(RpcClient::new(http, false)); + + Self { + provider, + block_number, + kv_store: Arc::new(Mutex::new(DiskKeyValueStore::new(base.join("kv")))), + data_dir: base, + } + } +} + +impl ExecutorTestFixtureCreator { + /// Create a static test fixture with the configuration provided. + pub(crate) async fn create_static_fixture(self) { + let chain_id = self.provider.get_chain_id().await.expect("Failed to get chain ID"); + let rollup_config = ROLLUP_CONFIGS.get(&chain_id).expect("Rollup config not found"); + + let executing_block = self + .provider + .get_block_by_number(self.block_number.into(), BlockTransactionsKind::Hashes) + .await + .expect("Failed to get parent block") + .expect("Block not found"); + let parent_block = self + .provider + .get_block_by_number((self.block_number - 1).into(), BlockTransactionsKind::Hashes) + .await + .expect("Failed to get parent block") + .expect("Block not found"); + + let executing_header = executing_block.header; + let parent_header = parent_block.header.inner.seal_slow(); + + let encoded_executing_transactions = match executing_block.transactions { + BlockTransactions::Hashes(transactions) => { + let mut encoded_transactions = Vec::with_capacity(transactions.len()); + for tx_hash in transactions { + let tx = self + .provider + .client() + .request::<&[B256; 1], Bytes>("debug_getRawTransaction", &[tx_hash]) + .await + .expect("Block not found"); + encoded_transactions.push(tx); + } + encoded_transactions + } + _ => panic!("Only BlockTransactions::Hashes are supported."), + }; + + let payload_attrs = OpPayloadAttributes { + payload_attributes: PayloadAttributes { + timestamp: executing_header.timestamp, + parent_beacon_block_root: parent_header.parent_beacon_block_root, + prev_randao: parent_header.mix_hash, + withdrawals: Default::default(), + suggested_fee_recipient: FEE_RECIPIENT, + }, + gas_limit: Some(executing_header.gas_limit), + transactions: Some(encoded_executing_transactions), + no_tx_pool: None, + base_fee: None, + }; + + let fixture_path = self.data_dir.join("fixture.json"); + let fixture = ExecutorTestFixture { + rollup_config: rollup_config.clone(), + parent_header: parent_header.inner().clone(), + executing_payload: payload_attrs.clone(), + expected_block_hash: executing_header.hash_slow(), + }; + + let mut executor = StatelessL2BlockExecutor::builder(rollup_config, self, NoopTrieHinter) + .with_parent_header(parent_header) + .build(); + let exec_artifacts = + executor.execute_payload(payload_attrs).expect("Failed to execute block").clone(); + + assert_eq!( + exec_artifacts.block_header.inner(), + &executing_header.inner, + "Produced header does not match the expected header" + ); + fs::write(fixture_path.as_path(), serde_json::to_vec(&fixture).unwrap()).await.unwrap(); + + // Tar the fixture. + let data_dir = fixture_path.parent().unwrap(); + tokio::process::Command::new("tar") + .arg("-czf") + .arg(data_dir.with_extension("tar.gz").file_name().unwrap()) + .arg(data_dir.file_name().unwrap()) + .current_dir(data_dir.parent().unwrap()) + .output() + .await + .expect("Failed to tar fixture"); + + // Remove the leftover directory. + fs::remove_dir_all(data_dir).await.expect("Failed to remove temporary directory"); + } +} + +impl TrieProvider for ExecutorTestFixtureCreator { + type Error = TestTrieNodeProviderError; + + fn trie_node_by_hash(&self, key: B256) -> Result { + // Fetch the preimage from the L2 chain provider. + let preimage: Bytes = tokio::task::block_in_place(move || { + Handle::current().block_on(async { + let preimage: Bytes = self + .provider + .client() + .request("debug_dbGet", &[key]) + .await + .map_err(|_| TestTrieNodeProviderError::PreimageNotFound)?; + + self.kv_store + .lock() + .await + .set(key, preimage.clone().into()) + .map_err(|_| TestTrieNodeProviderError::KVStore)?; + + Ok(preimage) + }) + })?; + + // Decode the preimage into a trie node. + TrieNode::decode(&mut preimage.as_ref()).map_err(TestTrieNodeProviderError::Rlp) + } +} + +impl TrieDBProvider for ExecutorTestFixtureCreator { + fn bytecode_by_hash(&self, hash: B256) -> Result { + // geth hashdb scheme code hash key prefix + const CODE_PREFIX: u8 = b'c'; + + // Fetch the preimage from the L2 chain provider. + let preimage: Bytes = tokio::task::block_in_place(move || { + Handle::current().block_on(async { + // Attempt to fetch the code from the L2 chain provider. + let code_hash = [&[CODE_PREFIX], hash.as_slice()].concat(); + let code = self + .provider + .client() + .request::<&[Bytes; 1], Bytes>("debug_dbGet", &[code_hash.into()]) + .await; + + // Check if the first attempt to fetch the code failed. If it did, try fetching the + // code hash preimage without the geth hashdb scheme prefix. + let code = match code { + Ok(code) => code, + Err(_) => self + .provider + .client() + .request::<&[B256; 1], Bytes>("debug_dbGet", &[hash]) + .await + .map_err(|_| TestTrieNodeProviderError::PreimageNotFound)?, + }; + + self.kv_store + .lock() + .await + .set(hash, code.clone().into()) + .map_err(|_| TestTrieNodeProviderError::KVStore)?; + + Ok(code) + }) + })?; + + Ok(preimage) + } + + fn header_by_hash(&self, hash: B256) -> Result { + let encoded_header: Bytes = tokio::task::block_in_place(move || { + Handle::current().block_on(async { + let preimage: Bytes = self + .provider + .client() + .request("debug_getRawHeader", &[hash]) + .await + .map_err(|_| TestTrieNodeProviderError::PreimageNotFound)?; + + self.kv_store + .lock() + .await + .set(hash, preimage.clone().into()) + .map_err(|_| TestTrieNodeProviderError::KVStore)?; + + Ok(preimage) + }) + })?; + + // Decode the Header. + Header::decode(&mut encoded_header.as_ref()).map_err(TestTrieNodeProviderError::Rlp) + } +} + +struct DiskTrieNodeProvider { + kv_store: DiskKeyValueStore, +} + +impl DiskTrieNodeProvider { + pub(crate) const fn new(kv_store: DiskKeyValueStore) -> Self { + Self { kv_store } + } +} + +impl TrieProvider for DiskTrieNodeProvider { + type Error = TestTrieNodeProviderError; + + fn trie_node_by_hash(&self, key: B256) -> Result { + TrieNode::decode( + &mut self + .kv_store + .get(key) + .ok_or(TestTrieNodeProviderError::PreimageNotFound)? + .as_slice(), + ) + .map_err(TestTrieNodeProviderError::Rlp) + } +} + +impl TrieDBProvider for DiskTrieNodeProvider { + fn bytecode_by_hash(&self, code_hash: B256) -> Result { + self.kv_store + .get(code_hash) + .ok_or(TestTrieNodeProviderError::PreimageNotFound) + .map(Bytes::from) + } + + fn header_by_hash(&self, hash: B256) -> Result { + Header::decode( + &mut self + .kv_store + .get(hash) + .ok_or(TestTrieNodeProviderError::PreimageNotFound)? + .as_slice(), + ) + .map_err(TestTrieNodeProviderError::Rlp) + } +} + +/// Executes a [ExecutorTestFixture] stored at the passed `fixture_path` and asserts that the +/// produced block hash matches the expected block hash. +pub(crate) async fn run_test_fixture(fixture_path: PathBuf) { + // First, untar the fixture. + let mut fixture_dir = tempfile::tempdir().expect("Failed to create temporary directory"); + let untar = tokio::process::Command::new("tar") + .arg("-xvf") + .arg(fixture_path.as_path()) + .arg("-C") + .arg(fixture_dir.path()) + .arg("--strip-components=1") + .output() + .await + .expect("Failed to untar fixture"); + + let kv_store = DiskKeyValueStore::new(fixture_dir.path().join("kv")); + let provider = DiskTrieNodeProvider::new(kv_store); + let fixture: ExecutorTestFixture = + serde_json::from_slice(&fs::read(fixture_dir.path().join("fixture.json")).await.unwrap()) + .expect("Failed to deserialize fixture"); + + let mut executor = + StatelessL2BlockExecutor::builder(&fixture.rollup_config, provider, NoopTrieHinter) + .with_parent_header(fixture.parent_header.seal_slow()) + .build(); + + let exec_artifacts = executor.execute_payload(fixture.executing_payload).unwrap(); + + assert_eq!( + exec_artifacts.block_header.hash(), + fixture.expected_block_hash, + "Produced header does not match the expected header" + ); +} diff --git a/crates/mpt/CHANGELOG.md b/crates/mpt/CHANGELOG.md index 20e72abff0..2463794669 100644 --- a/crates/mpt/CHANGELOG.md +++ b/crates/mpt/CHANGELOG.md @@ -6,111 +6,111 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -## [0.1.1](https://github.com/anton-rs/kona/compare/kona-mpt-v0.1.0...kona-mpt-v0.1.1) - 2024-12-03 +## [0.1.1](https://github.com/op-rs/kona/compare/kona-mpt-v0.1.0...kona-mpt-v0.1.1) - 2024-12-03 ### Other -- update deps and clean up misc features ([#864](https://github.com/anton-rs/kona/pull/864)) +- update deps and clean up misc features ([#864](https://github.com/op-rs/kona/pull/864)) -## [0.0.7](https://github.com/anton-rs/kona/compare/kona-mpt-v0.0.6...kona-mpt-v0.0.7) - 2024-11-20 +## [0.0.7](https://github.com/op-rs/kona/compare/kona-mpt-v0.0.6...kona-mpt-v0.0.7) - 2024-11-20 ### Added -- *(mpt)* Extend `TrieProvider` in `kona-executor` ([#813](https://github.com/anton-rs/kona/pull/813)) +- *(mpt)* Extend `TrieProvider` in `kona-executor` ([#813](https://github.com/op-rs/kona/pull/813)) ### Fixed -- *(mpt)* Remove unnused collapse ([#808](https://github.com/anton-rs/kona/pull/808)) +- *(mpt)* Remove unnused collapse ([#808](https://github.com/op-rs/kona/pull/808)) ### Other -- v0.6.6 op-alloy ([#804](https://github.com/anton-rs/kona/pull/804)) -- *(workspace)* Migrate back to `thiserror` v2 ([#811](https://github.com/anton-rs/kona/pull/811)) -- Revert "chore: bump alloy deps ([#788](https://github.com/anton-rs/kona/pull/788))" ([#791](https://github.com/anton-rs/kona/pull/791)) +- v0.6.6 op-alloy ([#804](https://github.com/op-rs/kona/pull/804)) +- *(workspace)* Migrate back to `thiserror` v2 ([#811](https://github.com/op-rs/kona/pull/811)) +- Revert "chore: bump alloy deps ([#788](https://github.com/op-rs/kona/pull/788))" ([#791](https://github.com/op-rs/kona/pull/791)) -## [0.0.6](https://github.com/anton-rs/kona/compare/kona-mpt-v0.0.5...kona-mpt-v0.0.6) - 2024-11-06 +## [0.0.6](https://github.com/op-rs/kona/compare/kona-mpt-v0.0.5...kona-mpt-v0.0.6) - 2024-11-06 ### Added -- *(TrieProvider)* Abstract TrieNode retrieval ([#787](https://github.com/anton-rs/kona/pull/787)) +- *(TrieProvider)* Abstract TrieNode retrieval ([#787](https://github.com/op-rs/kona/pull/787)) ### Other -- bump alloy deps ([#788](https://github.com/anton-rs/kona/pull/788)) +- bump alloy deps ([#788](https://github.com/op-rs/kona/pull/788)) -## [0.0.5](https://github.com/anton-rs/kona/compare/kona-mpt-v0.0.4...kona-mpt-v0.0.5) - 2024-10-29 +## [0.0.5](https://github.com/op-rs/kona/compare/kona-mpt-v0.0.4...kona-mpt-v0.0.5) - 2024-10-29 ### Fixed -- add feature for `alloy-provider`, fix `test_util` ([#738](https://github.com/anton-rs/kona/pull/738)) +- add feature for `alloy-provider`, fix `test_util` ([#738](https://github.com/op-rs/kona/pull/738)) -## [0.0.4](https://github.com/anton-rs/kona/compare/kona-mpt-v0.0.3...kona-mpt-v0.0.4) - 2024-10-25 +## [0.0.4](https://github.com/op-rs/kona/compare/kona-mpt-v0.0.3...kona-mpt-v0.0.4) - 2024-10-25 ### Added -- remove thiserror ([#735](https://github.com/anton-rs/kona/pull/735)) -- *(executor)* Clean ups ([#719](https://github.com/anton-rs/kona/pull/719)) -- use derive more display ([#675](https://github.com/anton-rs/kona/pull/675)) -- kona-providers ([#596](https://github.com/anton-rs/kona/pull/596)) -- *(ci)* Split online/offline tests ([#582](https://github.com/anton-rs/kona/pull/582)) -- *(mpt)* Migrate to `thiserror` ([#541](https://github.com/anton-rs/kona/pull/541)) +- remove thiserror ([#735](https://github.com/op-rs/kona/pull/735)) +- *(executor)* Clean ups ([#719](https://github.com/op-rs/kona/pull/719)) +- use derive more display ([#675](https://github.com/op-rs/kona/pull/675)) +- kona-providers ([#596](https://github.com/op-rs/kona/pull/596)) +- *(ci)* Split online/offline tests ([#582](https://github.com/op-rs/kona/pull/582)) +- *(mpt)* Migrate to `thiserror` ([#541](https://github.com/op-rs/kona/pull/541)) ### Fixed -- *(mpt)* Empty root node case ([#705](https://github.com/anton-rs/kona/pull/705)) -- typos ([#690](https://github.com/anton-rs/kona/pull/690)) -- *(workspace)* hoist and fix lints ([#577](https://github.com/anton-rs/kona/pull/577)) -- *(mpt)* Empty list walker ([#493](https://github.com/anton-rs/kona/pull/493)) +- *(mpt)* Empty root node case ([#705](https://github.com/op-rs/kona/pull/705)) +- typos ([#690](https://github.com/op-rs/kona/pull/690)) +- *(workspace)* hoist and fix lints ([#577](https://github.com/op-rs/kona/pull/577)) +- *(mpt)* Empty list walker ([#493](https://github.com/op-rs/kona/pull/493)) ### Other -- cleans up kona-mpt deps ([#725](https://github.com/anton-rs/kona/pull/725)) -- re-org imports ([#711](https://github.com/anton-rs/kona/pull/711)) -- *(mpt)* codecov ([#655](https://github.com/anton-rs/kona/pull/655)) -- *(mpt)* mpt noop trait impls ([#649](https://github.com/anton-rs/kona/pull/649)) -- *(mpt)* account conversion tests ([#647](https://github.com/anton-rs/kona/pull/647)) -- doc logos ([#609](https://github.com/anton-rs/kona/pull/609)) -- *(workspace)* Allow stdlib in `cfg(test)` ([#548](https://github.com/anton-rs/kona/pull/548)) +- cleans up kona-mpt deps ([#725](https://github.com/op-rs/kona/pull/725)) +- re-org imports ([#711](https://github.com/op-rs/kona/pull/711)) +- *(mpt)* codecov ([#655](https://github.com/op-rs/kona/pull/655)) +- *(mpt)* mpt noop trait impls ([#649](https://github.com/op-rs/kona/pull/649)) +- *(mpt)* account conversion tests ([#647](https://github.com/op-rs/kona/pull/647)) +- doc logos ([#609](https://github.com/op-rs/kona/pull/609)) +- *(workspace)* Allow stdlib in `cfg(test)` ([#548](https://github.com/op-rs/kona/pull/548)) -## [0.0.3](https://github.com/anton-rs/kona/compare/kona-mpt-v0.0.2...kona-mpt-v0.0.3) - 2024-09-04 +## [0.0.3](https://github.com/op-rs/kona/compare/kona-mpt-v0.0.2...kona-mpt-v0.0.3) - 2024-09-04 ### Added -- *(mpt)* `TrieNode` benchmarks ([#351](https://github.com/anton-rs/kona/pull/351)) +- *(mpt)* `TrieNode` benchmarks ([#351](https://github.com/op-rs/kona/pull/351)) ### Fixed -- *(workspace)* Add Unused Dependency Lint ([#453](https://github.com/anton-rs/kona/pull/453)) -- *(deps)* Bump Alloy Dependencies ([#409](https://github.com/anton-rs/kona/pull/409)) +- *(workspace)* Add Unused Dependency Lint ([#453](https://github.com/op-rs/kona/pull/453)) +- *(deps)* Bump Alloy Dependencies ([#409](https://github.com/op-rs/kona/pull/409)) ### Other -- *(workspace)* Alloy Version Bumps ([#467](https://github.com/anton-rs/kona/pull/467)) -- *(workspace)* Update for `anton-rs` org transfer ([#474](https://github.com/anton-rs/kona/pull/474)) -- *(workspace)* Hoist Dependencies ([#466](https://github.com/anton-rs/kona/pull/466)) -- *(bin)* Remove `kt` ([#461](https://github.com/anton-rs/kona/pull/461)) -- *(deps)* Bump revm version to v13 ([#422](https://github.com/anton-rs/kona/pull/422)) +- *(workspace)* Alloy Version Bumps ([#467](https://github.com/op-rs/kona/pull/467)) +- *(workspace)* Update for `op-rs` org transfer ([#474](https://github.com/op-rs/kona/pull/474)) +- *(workspace)* Hoist Dependencies ([#466](https://github.com/op-rs/kona/pull/466)) +- *(bin)* Remove `kt` ([#461](https://github.com/op-rs/kona/pull/461)) +- *(deps)* Bump revm version to v13 ([#422](https://github.com/op-rs/kona/pull/422)) -## [0.0.2](https://github.com/anton-rs/kona/compare/kona-mpt-v0.0.1...kona-mpt-v0.0.2) - 2024-06-22 +## [0.0.2](https://github.com/op-rs/kona/compare/kona-mpt-v0.0.1...kona-mpt-v0.0.2) - 2024-06-22 ### Added -- *(client)* Derivation integration ([#257](https://github.com/anton-rs/kona/pull/257)) -- *(client)* Oracle-backed derive traits ([#252](https://github.com/anton-rs/kona/pull/252)) -- *(client)* Account + Account storage hinting in `TrieDB` ([#228](https://github.com/anton-rs/kona/pull/228)) -- *(client)* Add `current_output_root` to block executor ([#225](https://github.com/anton-rs/kona/pull/225)) -- *(ci)* Dependabot config ([#236](https://github.com/anton-rs/kona/pull/236)) -- *(client)* `StatelessL2BlockExecutor` ([#210](https://github.com/anton-rs/kona/pull/210)) -- *(mpt)* Block hash walkback ([#199](https://github.com/anton-rs/kona/pull/199)) -- *(mpt)* Simplify `TrieDB` ([#198](https://github.com/anton-rs/kona/pull/198)) -- *(mpt)* Trie DB commit ([#196](https://github.com/anton-rs/kona/pull/196)) -- *(mpt)* Trie node insertion ([#195](https://github.com/anton-rs/kona/pull/195)) -- *(host)* Host program scaffold ([#184](https://github.com/anton-rs/kona/pull/184)) -- *(workspace)* Client programs in workspace ([#178](https://github.com/anton-rs/kona/pull/178)) -- *(mpt)* `TrieCacheDB` scaffold ([#174](https://github.com/anton-rs/kona/pull/174)) -- *(mpt)* `TrieNode` retrieval ([#173](https://github.com/anton-rs/kona/pull/173)) -- *(mpt)* Refactor `TrieNode` ([#172](https://github.com/anton-rs/kona/pull/172)) +- *(client)* Derivation integration ([#257](https://github.com/op-rs/kona/pull/257)) +- *(client)* Oracle-backed derive traits ([#252](https://github.com/op-rs/kona/pull/252)) +- *(client)* Account + Account storage hinting in `TrieDB` ([#228](https://github.com/op-rs/kona/pull/228)) +- *(client)* Add `current_output_root` to block executor ([#225](https://github.com/op-rs/kona/pull/225)) +- *(ci)* Dependabot config ([#236](https://github.com/op-rs/kona/pull/236)) +- *(client)* `StatelessL2BlockExecutor` ([#210](https://github.com/op-rs/kona/pull/210)) +- *(mpt)* Block hash walkback ([#199](https://github.com/op-rs/kona/pull/199)) +- *(mpt)* Simplify `TrieDB` ([#198](https://github.com/op-rs/kona/pull/198)) +- *(mpt)* Trie DB commit ([#196](https://github.com/op-rs/kona/pull/196)) +- *(mpt)* Trie node insertion ([#195](https://github.com/op-rs/kona/pull/195)) +- *(host)* Host program scaffold ([#184](https://github.com/op-rs/kona/pull/184)) +- *(workspace)* Client programs in workspace ([#178](https://github.com/op-rs/kona/pull/178)) +- *(mpt)* `TrieCacheDB` scaffold ([#174](https://github.com/op-rs/kona/pull/174)) +- *(mpt)* `TrieNode` retrieval ([#173](https://github.com/op-rs/kona/pull/173)) +- *(mpt)* Refactor `TrieNode` ([#172](https://github.com/op-rs/kona/pull/172)) ### Fixed -- *(mpt)* Fix extension node truncation ([#300](https://github.com/anton-rs/kona/pull/300)) -- *(ci)* Release plz ([#145](https://github.com/anton-rs/kona/pull/145)) +- *(mpt)* Fix extension node truncation ([#300](https://github.com/op-rs/kona/pull/300)) +- *(ci)* Release plz ([#145](https://github.com/op-rs/kona/pull/145)) ### Other -- version dependencies ([#296](https://github.com/anton-rs/kona/pull/296)) -- *(mpt)* Do not expose recursion vars ([#197](https://github.com/anton-rs/kona/pull/197)) +- version dependencies ([#296](https://github.com/op-rs/kona/pull/296)) +- *(mpt)* Do not expose recursion vars ([#197](https://github.com/op-rs/kona/pull/197)) diff --git a/crates/mpt/README.md b/crates/mpt/README.md index 8c63642545..98aa19a2b2 100644 --- a/crates/mpt/README.md +++ b/crates/mpt/README.md @@ -1,9 +1,9 @@ # `kona-mpt` -CI +CI Kona MPT -License -Codecov +License +Codecov A recursive, in-memory implementation of Ethereum's hexary Merkle Patricia Trie (MPT), supporting: - Retrieval diff --git a/crates/mpt/src/lib.rs b/crates/mpt/src/lib.rs index d3e57b140f..cffb2aa3cc 100644 --- a/crates/mpt/src/lib.rs +++ b/crates/mpt/src/lib.rs @@ -1,7 +1,7 @@ #![doc = include_str!("../README.md")] #![doc( - html_logo_url = "https://raw.githubusercontent.com/anton-rs/kona/main/assets/square.png", - html_favicon_url = "https://raw.githubusercontent.com/anton-rs/kona/main/assets/favicon.ico" + html_logo_url = "https://raw.githubusercontent.com/op-rs/kona/main/assets/square.png", + html_favicon_url = "https://raw.githubusercontent.com/op-rs/kona/main/assets/favicon.ico" )] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] #![cfg_attr(not(test), warn(unused_crate_dependencies))] diff --git a/crates/mpt/src/node.rs b/crates/mpt/src/node.rs index d21a6fec57..f4da24a630 100644 --- a/crates/mpt/src/node.rs +++ b/crates/mpt/src/node.rs @@ -104,28 +104,17 @@ impl TrieNode { Self::Blinded { commitment } } - /// Returns the commitment of a [TrieNode::Blinded] node, if `self` is of the - /// [TrieNode::Blinded] or [TrieNode::Empty] variants. - /// - /// ## Returns - /// - `Some(B256)` - The commitment of the blinded node - /// - `None` - `self` is not a [TrieNode::Blinded] node - pub const fn blinded_commitment(&self) -> Option { + /// Blinds the [TrieNode].. Alternatively, if the [TrieNode] is a [TrieNode::Blinded] node + /// already, its commitment is returned directly. + pub fn blind(&self) -> B256 { match self { - Self::Blinded { commitment } => Some(*commitment), - Self::Empty => Some(EMPTY_ROOT_HASH), - _ => None, - } - } - - /// Blinds the [TrieNode] if its encoded length is longer than an encoded [B256] string in - /// length. Alternatively, if the [TrieNode] is a [TrieNode::Blinded] node already, it - /// is left as-is. - pub fn blind(&mut self) { - if self.length() >= B256::ZERO.len() && !matches!(self, Self::Blinded { .. }) { - let mut rlp_buf = Vec::with_capacity(self.length()); - self.encode_in_place(&mut rlp_buf); - *self = Self::Blinded { commitment: keccak256(rlp_buf) } + Self::Blinded { commitment } => *commitment, + Self::Empty => EMPTY_ROOT_HASH, + _ => { + let mut rlp_buf = Vec::with_capacity(self.length()); + self.encode(&mut rlp_buf); + keccak256(rlp_buf) + } } } @@ -360,44 +349,6 @@ impl TrieNode { } } - /// Alternative function to the [Encodable::encode] implementation for this type, that blinds - /// children nodes throughout the encoding process. This function is useful in the case where - /// the trie node cache is no longer required (i.e., during [Self::blind]). - /// - /// ## Takes - /// - `self` - The root trie node - /// - `out` - The buffer to write the encoded trie node to - pub fn encode_in_place(&mut self, out: &mut dyn alloy_rlp::BufMut) { - let payload_length = self.payload_length(); - match self { - Self::Empty => out.put_u8(EMPTY_STRING_CODE), - Self::Blinded { commitment } => commitment.encode(out), - Self::Leaf { prefix, value } => { - // Encode the leaf node's header and key-value pair. - Header { list: true, payload_length }.encode(out); - prefix.encode_path_leaf(true).as_slice().encode(out); - value.encode(out); - } - Self::Extension { prefix, node } => { - // Encode the extension node's header, prefix, and pointer node. - Header { list: true, payload_length }.encode(out); - prefix.encode_path_leaf(false).as_slice().encode(out); - node.blind(); - node.encode_in_place(out); - } - Self::Branch { stack } => { - // In branch nodes, if an element is longer than 32 bytes in length, it is blinded. - // Assuming we have an open trie node, we must re-hash the elements - // that are longer than 32 bytes in length. - Header { list: true, payload_length }.encode(out); - stack.iter_mut().for_each(|node| { - node.blind(); - node.encode_in_place(out); - }); - } - } - } - /// If applicable, collapses `self` into a more compact form. /// /// ## Takes @@ -562,7 +513,7 @@ impl TrieNode { /// than a [B256]. fn blinded_length(&self) -> usize { let encoded_len = self.length(); - if encoded_len >= B256::ZERO.len() && !matches!(self, Self::Blinded { .. }) { + if encoded_len >= B256::ZERO.len() { B256::ZERO.length() } else { encoded_len @@ -572,32 +523,39 @@ impl TrieNode { impl Encodable for TrieNode { fn encode(&self, out: &mut dyn alloy_rlp::BufMut) { + let payload_length = self.payload_length(); match self { Self::Empty => out.put_u8(EMPTY_STRING_CODE), Self::Blinded { commitment } => commitment.encode(out), Self::Leaf { prefix, value } => { // Encode the leaf node's header and key-value pair. - Header { list: true, payload_length: self.payload_length() }.encode(out); - prefix.encode_path_leaf(true).as_slice().encode(out); + Header { list: true, payload_length }.encode(out); + alloy_trie::nodes::encode_path_leaf(prefix, true).as_slice().encode(out); value.encode(out); } Self::Extension { prefix, node } => { // Encode the extension node's header, prefix, and pointer node. - Header { list: true, payload_length: self.payload_length() }.encode(out); - prefix.encode_path_leaf(false).as_slice().encode(out); - let mut blinded = node.clone(); - blinded.blind(); - blinded.encode(out); + Header { list: true, payload_length }.encode(out); + alloy_trie::nodes::encode_path_leaf(prefix, false).as_slice().encode(out); + if node.length() >= B256::ZERO.len() { + let hash = node.blind(); + hash.encode(out); + } else { + node.encode(out); + } } Self::Branch { stack } => { // In branch nodes, if an element is longer than 32 bytes in length, it is blinded. // Assuming we have an open trie node, we must re-hash the elements // that are longer than 32 bytes in length. - Header { list: true, payload_length: self.payload_length() }.encode(out); + Header { list: true, payload_length }.encode(out); stack.iter().for_each(|node| { - let mut blinded = node.clone(); - blinded.blind(); - blinded.encode(out); + if node.length() >= B256::ZERO.len() { + let hash = node.blind(); + hash.encode(out); + } else { + node.encode(out); + } }); } } @@ -674,12 +632,12 @@ mod test { use alloy_primitives::{b256, bytes, hex, keccak256}; use alloy_rlp::{Decodable, Encodable, EMPTY_STRING_CODE}; use alloy_trie::{HashBuilder, Nibbles}; - use rand::prelude::SliceRandom; + use rand::prelude::IteratorRandom; #[test] fn test_empty_blinded() { let trie_node = TrieNode::Empty; - assert_eq!(trie_node.blinded_commitment().unwrap(), EMPTY_ROOT_HASH); + assert_eq!(trie_node.blind(), EMPTY_ROOT_HASH); } #[test] @@ -801,8 +759,7 @@ mod test { assert_eq!(v, encoded_node.as_slice()); } - root_node.blind(); - let commitment = root_node.blinded_commitment().unwrap(); + let commitment = root_node.blind(); assert_eq!(commitment, root); } @@ -856,8 +813,7 @@ mod test { node.insert(&Nibbles::unpack(key), key.into(), &NoopTrieProvider).unwrap(); } - node.blind(); - assert_eq!(node.blinded_commitment().unwrap(), hb.root()); + assert_eq!(node.blind(), hb.root()); } /// Differential test for deleting an arbitrary number of keys from a `TrieNode` / `HashBuilder`. @@ -869,9 +825,9 @@ mod test { let mut hb = HashBuilder::default(); let mut node = TrieNode::Empty; - let mut rng = rand::thread_rng(); + let mut rng = rand::rng(); let deleted_keys = - keys.choose_multiple(&mut rng, 5.min(keys.len())).copied().collect::>(); + keys.clone().into_iter().choose_multiple(&mut rng, 5.min(keys.len())); // Insert the keys into the `HashBuilder` and `TrieNode`. for key in keys { diff --git a/crates/proof-sdk/preimage/CHANGELOG.md b/crates/proof-sdk/preimage/CHANGELOG.md index 5d738b22b4..47ee61d584 100644 --- a/crates/proof-sdk/preimage/CHANGELOG.md +++ b/crates/proof-sdk/preimage/CHANGELOG.md @@ -6,76 +6,76 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -## [0.2.0](https://github.com/anton-rs/kona/compare/kona-preimage-v0.1.0...kona-preimage-v0.2.0) - 2024-12-03 +## [0.2.0](https://github.com/op-rs/kona/compare/kona-preimage-v0.1.0...kona-preimage-v0.2.0) - 2024-12-03 ### Added -- *(workspace)* Isolate FPVM-specific platform code ([#821](https://github.com/anton-rs/kona/pull/821)) +- *(workspace)* Isolate FPVM-specific platform code ([#821](https://github.com/op-rs/kona/pull/821)) -## [0.0.5](https://github.com/anton-rs/kona/compare/kona-preimage-v0.0.4...kona-preimage-v0.0.5) - 2024-11-20 +## [0.0.5](https://github.com/op-rs/kona/compare/kona-preimage-v0.0.4...kona-preimage-v0.0.5) - 2024-11-20 ### Added -- *(preimage)* Decouple from `kona-common` ([#817](https://github.com/anton-rs/kona/pull/817)) +- *(preimage)* Decouple from `kona-common` ([#817](https://github.com/op-rs/kona/pull/817)) ### Other -- *(driver)* use tracing macros ([#823](https://github.com/anton-rs/kona/pull/823)) -- *(workspace)* Reorganize SDK ([#816](https://github.com/anton-rs/kona/pull/816)) +- *(driver)* use tracing macros ([#823](https://github.com/op-rs/kona/pull/823)) +- *(workspace)* Reorganize SDK ([#816](https://github.com/op-rs/kona/pull/816)) -## [0.0.4](https://github.com/anton-rs/kona/compare/kona-preimage-v0.0.3...kona-preimage-v0.0.4) - 2024-10-25 +## [0.0.4](https://github.com/op-rs/kona/compare/kona-preimage-v0.0.3...kona-preimage-v0.0.4) - 2024-10-25 ### Added -- remove thiserror ([#735](https://github.com/anton-rs/kona/pull/735)) -- *(preimage/common)* Migrate to `thiserror` ([#543](https://github.com/anton-rs/kona/pull/543)) +- remove thiserror ([#735](https://github.com/op-rs/kona/pull/735)) +- *(preimage/common)* Migrate to `thiserror` ([#543](https://github.com/op-rs/kona/pull/543)) ### Fixed -- hashmap ([#732](https://github.com/anton-rs/kona/pull/732)) -- *(workspace)* hoist and fix lints ([#577](https://github.com/anton-rs/kona/pull/577)) -- *(preimage)* Improve error differentiation in preimage servers ([#535](https://github.com/anton-rs/kona/pull/535)) +- hashmap ([#732](https://github.com/op-rs/kona/pull/732)) +- *(workspace)* hoist and fix lints ([#577](https://github.com/op-rs/kona/pull/577)) +- *(preimage)* Improve error differentiation in preimage servers ([#535](https://github.com/op-rs/kona/pull/535)) ### Other -- re-org imports ([#711](https://github.com/anton-rs/kona/pull/711)) -- *(preimage)* Test Coverage ([#634](https://github.com/anton-rs/kona/pull/634)) -- doc logos ([#609](https://github.com/anton-rs/kona/pull/609)) -- *(workspace)* Bump dependencies ([#550](https://github.com/anton-rs/kona/pull/550)) -- *(workspace)* Allow stdlib in `cfg(test)` ([#548](https://github.com/anton-rs/kona/pull/548)) +- re-org imports ([#711](https://github.com/op-rs/kona/pull/711)) +- *(preimage)* Test Coverage ([#634](https://github.com/op-rs/kona/pull/634)) +- doc logos ([#609](https://github.com/op-rs/kona/pull/609)) +- *(workspace)* Bump dependencies ([#550](https://github.com/op-rs/kona/pull/550)) +- *(workspace)* Allow stdlib in `cfg(test)` ([#548](https://github.com/op-rs/kona/pull/548)) -## [0.0.3](https://github.com/anton-rs/kona/compare/kona-preimage-v0.0.2...kona-preimage-v0.0.3) - 2024-09-04 +## [0.0.3](https://github.com/op-rs/kona/compare/kona-preimage-v0.0.2...kona-preimage-v0.0.3) - 2024-09-04 ### Added -- *(workspace)* Workspace Re-exports ([#468](https://github.com/anton-rs/kona/pull/468)) -- *(client)* providers generic over oracles ([#336](https://github.com/anton-rs/kona/pull/336)) +- *(workspace)* Workspace Re-exports ([#468](https://github.com/op-rs/kona/pull/468)) +- *(client)* providers generic over oracles ([#336](https://github.com/op-rs/kona/pull/336)) ### Fixed -- *(workspace)* Add Unused Dependency Lint ([#453](https://github.com/anton-rs/kona/pull/453)) +- *(workspace)* Add Unused Dependency Lint ([#453](https://github.com/op-rs/kona/pull/453)) ### Other -- *(workspace)* Update for `anton-rs` org transfer ([#474](https://github.com/anton-rs/kona/pull/474)) -- *(workspace)* Hoist Dependencies ([#466](https://github.com/anton-rs/kona/pull/466)) -- *(common)* Remove need for cursors in `NativeIO` ([#416](https://github.com/anton-rs/kona/pull/416)) -- *(preimage)* Remove dynamic dispatch ([#354](https://github.com/anton-rs/kona/pull/354)) +- *(workspace)* Update for `op-rs` org transfer ([#474](https://github.com/op-rs/kona/pull/474)) +- *(workspace)* Hoist Dependencies ([#466](https://github.com/op-rs/kona/pull/466)) +- *(common)* Remove need for cursors in `NativeIO` ([#416](https://github.com/op-rs/kona/pull/416)) +- *(preimage)* Remove dynamic dispatch ([#354](https://github.com/op-rs/kona/pull/354)) -## [0.0.2](https://github.com/anton-rs/kona/compare/kona-preimage-v0.0.1...kona-preimage-v0.0.2) - 2024-06-22 +## [0.0.2](https://github.com/op-rs/kona/compare/kona-preimage-v0.0.1...kona-preimage-v0.0.2) - 2024-06-22 ### Added -- *(preimage)* add serde feature flag to preimage crate for keys ([#271](https://github.com/anton-rs/kona/pull/271)) -- *(client)* Derivation integration ([#257](https://github.com/anton-rs/kona/pull/257)) -- *(ci)* Dependabot config ([#236](https://github.com/anton-rs/kona/pull/236)) -- *(client)* `StatelessL2BlockExecutor` ([#210](https://github.com/anton-rs/kona/pull/210)) -- *(client)* `BootInfo` ([#205](https://github.com/anton-rs/kona/pull/205)) -- *(preimage)* Async client handles ([#200](https://github.com/anton-rs/kona/pull/200)) -- *(host)* Add local key value store ([#189](https://github.com/anton-rs/kona/pull/189)) -- *(host)* Host program scaffold ([#184](https://github.com/anton-rs/kona/pull/184)) -- *(preimage)* Async server components ([#183](https://github.com/anton-rs/kona/pull/183)) -- *(precompile)* Add `precompile` key type ([#179](https://github.com/anton-rs/kona/pull/179)) -- *(preimage)* `OracleServer` + `HintReader` ([#96](https://github.com/anton-rs/kona/pull/96)) -- *(common)* Move from `RegisterSize` to native ptr size type ([#95](https://github.com/anton-rs/kona/pull/95)) +- *(preimage)* add serde feature flag to preimage crate for keys ([#271](https://github.com/op-rs/kona/pull/271)) +- *(client)* Derivation integration ([#257](https://github.com/op-rs/kona/pull/257)) +- *(ci)* Dependabot config ([#236](https://github.com/op-rs/kona/pull/236)) +- *(client)* `StatelessL2BlockExecutor` ([#210](https://github.com/op-rs/kona/pull/210)) +- *(client)* `BootInfo` ([#205](https://github.com/op-rs/kona/pull/205)) +- *(preimage)* Async client handles ([#200](https://github.com/op-rs/kona/pull/200)) +- *(host)* Add local key value store ([#189](https://github.com/op-rs/kona/pull/189)) +- *(host)* Host program scaffold ([#184](https://github.com/op-rs/kona/pull/184)) +- *(preimage)* Async server components ([#183](https://github.com/op-rs/kona/pull/183)) +- *(precompile)* Add `precompile` key type ([#179](https://github.com/op-rs/kona/pull/179)) +- *(preimage)* `OracleServer` + `HintReader` ([#96](https://github.com/op-rs/kona/pull/96)) +- *(common)* Move from `RegisterSize` to native ptr size type ([#95](https://github.com/op-rs/kona/pull/95)) - *(workspace)* Add `rustfmt.toml` ### Other -- *(workspace)* Move `alloy-primitives` to workspace dependencies ([#103](https://github.com/anton-rs/kona/pull/103)) -- Make versions of packages independent ([#36](https://github.com/anton-rs/kona/pull/36)) +- *(workspace)* Move `alloy-primitives` to workspace dependencies ([#103](https://github.com/op-rs/kona/pull/103)) +- Make versions of packages independent ([#36](https://github.com/op-rs/kona/pull/36)) diff --git a/crates/proof-sdk/preimage/src/key.rs b/crates/proof-sdk/preimage/src/key.rs index f9d76cdf39..d68c348f1c 100644 --- a/crates/proof-sdk/preimage/src/key.rs +++ b/crates/proof-sdk/preimage/src/key.rs @@ -1,7 +1,7 @@ //! Contains the [PreimageKey] type, which is used to identify preimages that may be fetched from //! the preimage oracle. -use alloy_primitives::{B256, U256}; +use alloy_primitives::{Keccak256, B256, U256}; #[cfg(feature = "rkyv")] use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize}; #[cfg(feature = "serde")] @@ -10,9 +10,13 @@ use serde::{Deserialize as SerdeDeserialize, Serialize as SerdeSerialize}; use crate::errors::PreimageOracleError; /// -#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash)] +#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] #[repr(u8)] -#[cfg_attr(feature = "rkyv", derive(Archive, RkyvSerialize, RkyvDeserialize))] +#[cfg_attr( + feature = "rkyv", + derive(Archive, RkyvSerialize, RkyvDeserialize), + rkyv(derive(Eq, PartialEq, Ord, PartialOrd, Hash)) +)] #[cfg_attr(feature = "serde", derive(SerdeSerialize, SerdeDeserialize))] pub enum PreimageKeyType { /// Local key types are local to a given instance of a fault-proof and context dependent. @@ -62,8 +66,12 @@ impl TryFrom for PreimageKeyType { /// |---------|-------------| /// | [0, 1) | Type byte | /// | [1, 32) | Data | -#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash)] -#[cfg_attr(feature = "rkyv", derive(Archive, RkyvSerialize, RkyvDeserialize))] +#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[cfg_attr( + feature = "rkyv", + derive(Archive, RkyvSerialize, RkyvDeserialize), + rkyv(derive(Eq, PartialEq, Ord, PartialOrd, Hash)) +)] #[cfg_attr(feature = "serde", derive(SerdeSerialize, SerdeDeserialize))] pub struct PreimageKey { data: [u8; 31], @@ -87,6 +95,26 @@ impl PreimageKey { Self { data, key_type: PreimageKeyType::Local } } + /// Creates a new keccak256 [PreimageKey] from a 32-byte keccak256 digest. The digest will be + /// truncated to 31 bytes by taking the low-order 31 bytes. + pub fn new_keccak256(digest: [u8; 32]) -> Self { + Self::new(digest, PreimageKeyType::Keccak256) + } + + /// Creates a new precompile [PreimageKey] from a precompile address and input. The key will be + /// constructed as `keccak256(precompile_addr ++ input)`, and then the high-order byte of the + /// digest will be set to the type byte. + pub fn new_precompile(precompile_addr: [u8; 20], input: &[u8]) -> Self { + let mut data = [0u8; 31]; + + let mut hasher = Keccak256::new(); + hasher.update(precompile_addr); + hasher.update(input); + + data.copy_from_slice(&hasher.finalize()[1..]); + Self { data, key_type: PreimageKeyType::Precompile } + } + /// Returns the [PreimageKeyType] for the [PreimageKey]. pub const fn key_type(&self) -> PreimageKeyType { self.key_type diff --git a/crates/proof-sdk/preimage/src/lib.rs b/crates/proof-sdk/preimage/src/lib.rs index 1a2e853eca..25ec7a6283 100644 --- a/crates/proof-sdk/preimage/src/lib.rs +++ b/crates/proof-sdk/preimage/src/lib.rs @@ -1,7 +1,7 @@ #![doc = include_str!("../README.md")] #![doc( - html_logo_url = "https://raw.githubusercontent.com/anton-rs/kona/main/assets/square.png", - html_favicon_url = "https://raw.githubusercontent.com/anton-rs/kona/main/assets/favicon.ico" + html_logo_url = "https://raw.githubusercontent.com/op-rs/kona/main/assets/square.png", + html_favicon_url = "https://raw.githubusercontent.com/op-rs/kona/main/assets/favicon.ico" )] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] #![cfg_attr(not(test), warn(unused_crate_dependencies))] @@ -26,7 +26,7 @@ pub use hint::{HintReader, HintWriter}; mod traits; pub use traits::{ Channel, CommsClient, HintReaderServer, HintRouter, HintWriterClient, PreimageFetcher, - PreimageOracleClient, PreimageOracleServer, + PreimageOracleClient, PreimageOracleServer, PreimageServerBackend, }; #[cfg(any(test, feature = "std"))] diff --git a/crates/proof-sdk/preimage/src/traits.rs b/crates/proof-sdk/preimage/src/traits.rs index 5614b21259..5740210979 100644 --- a/crates/proof-sdk/preimage/src/traits.rs +++ b/crates/proof-sdk/preimage/src/traits.rs @@ -102,6 +102,13 @@ pub trait PreimageFetcher { async fn get_preimage(&self, key: PreimageKey) -> PreimageOracleResult>; } +/// A [PreimageServerBackend] is a trait that combines the [PreimageFetcher] and [HintRouter] +/// traits. +pub trait PreimageServerBackend: PreimageFetcher + HintRouter {} + +// Implement the super trait for any type that satisfies the bounds +impl PreimageServerBackend for T {} + /// A [Channel] is a high-level interface to read and write data to a counterparty. #[async_trait] pub trait Channel { diff --git a/crates/proof-sdk/proof/CHANGELOG.md b/crates/proof-sdk/proof/CHANGELOG.md index 08d41cf45a..5b929d9945 100644 --- a/crates/proof-sdk/proof/CHANGELOG.md +++ b/crates/proof-sdk/proof/CHANGELOG.md @@ -6,85 +6,85 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -## [0.2.0](https://github.com/anton-rs/kona/compare/kona-proof-v0.1.0...kona-proof-v0.2.0) - 2024-12-03 +## [0.2.0](https://github.com/op-rs/kona/compare/kona-proof-v0.1.0...kona-proof-v0.2.0) - 2024-12-03 ### Added -- *(driver)* wait for engine ([#851](https://github.com/anton-rs/kona/pull/851)) -- *(client)* Invalidate impossibly old claims ([#852](https://github.com/anton-rs/kona/pull/852)) -- *(driver)* refines the executor interface for the driver ([#850](https://github.com/anton-rs/kona/pull/850)) -- *(workspace)* Isolate FPVM-specific platform code ([#821](https://github.com/anton-rs/kona/pull/821)) +- *(driver)* wait for engine ([#851](https://github.com/op-rs/kona/pull/851)) +- *(client)* Invalidate impossibly old claims ([#852](https://github.com/op-rs/kona/pull/852)) +- *(driver)* refines the executor interface for the driver ([#850](https://github.com/op-rs/kona/pull/850)) +- *(workspace)* Isolate FPVM-specific platform code ([#821](https://github.com/op-rs/kona/pull/821)) ### Fixed -- bump ([#865](https://github.com/anton-rs/kona/pull/865)) +- bump ([#865](https://github.com/op-rs/kona/pull/865)) ### Other -- update deps and clean up misc features ([#864](https://github.com/anton-rs/kona/pull/864)) -- *(host)* Hint Parsing Cleanup ([#844](https://github.com/anton-rs/kona/pull/844)) -- *(derive)* remove indexed blob hash ([#847](https://github.com/anton-rs/kona/pull/847)) -- L2ExecutePayloadProof Hint Type ([#832](https://github.com/anton-rs/kona/pull/832)) +- update deps and clean up misc features ([#864](https://github.com/op-rs/kona/pull/864)) +- *(host)* Hint Parsing Cleanup ([#844](https://github.com/op-rs/kona/pull/844)) +- *(derive)* remove indexed blob hash ([#847](https://github.com/op-rs/kona/pull/847)) +- L2ExecutePayloadProof Hint Type ([#832](https://github.com/op-rs/kona/pull/832)) -## [0.0.1](https://github.com/anton-rs/kona/releases/tag/kona-proof-v0.0.1) - 2024-11-20 +## [0.0.1](https://github.com/op-rs/kona/releases/tag/kona-proof-v0.0.1) - 2024-11-20 ### Added -- *(workspace)* `kona-proof` ([#818](https://github.com/anton-rs/kona/pull/818)) +- *(workspace)* `kona-proof` ([#818](https://github.com/op-rs/kona/pull/818)) ### Fixed -- imports ([#829](https://github.com/anton-rs/kona/pull/829)) +- imports ([#829](https://github.com/op-rs/kona/pull/829)) ### Other -- op-alloy 0.6.8 ([#830](https://github.com/anton-rs/kona/pull/830)) -- *(driver)* use tracing macros ([#823](https://github.com/anton-rs/kona/pull/823)) +- op-alloy 0.6.8 ([#830](https://github.com/op-rs/kona/pull/830)) +- *(driver)* use tracing macros ([#823](https://github.com/op-rs/kona/pull/823)) -## [0.0.4](https://github.com/anton-rs/kona/compare/kona-common-v0.0.3...kona-common-v0.0.4) - 2024-10-25 +## [0.0.4](https://github.com/op-rs/kona/compare/kona-common-v0.0.3...kona-common-v0.0.4) - 2024-10-25 ### Added -- remove thiserror ([#735](https://github.com/anton-rs/kona/pull/735)) -- *(preimage/common)* Migrate to `thiserror` ([#543](https://github.com/anton-rs/kona/pull/543)) +- remove thiserror ([#735](https://github.com/op-rs/kona/pull/735)) +- *(preimage/common)* Migrate to `thiserror` ([#543](https://github.com/op-rs/kona/pull/543)) ### Fixed -- *(workspace)* hoist and fix lints ([#577](https://github.com/anton-rs/kona/pull/577)) +- *(workspace)* hoist and fix lints ([#577](https://github.com/op-rs/kona/pull/577)) ### Other -- re-org imports ([#711](https://github.com/anton-rs/kona/pull/711)) -- *(preimage)* Test Coverage ([#634](https://github.com/anton-rs/kona/pull/634)) -- test coverage for common ([#629](https://github.com/anton-rs/kona/pull/629)) -- doc logos ([#609](https://github.com/anton-rs/kona/pull/609)) -- *(workspace)* Allow stdlib in `cfg(test)` ([#548](https://github.com/anton-rs/kona/pull/548)) +- re-org imports ([#711](https://github.com/op-rs/kona/pull/711)) +- *(preimage)* Test Coverage ([#634](https://github.com/op-rs/kona/pull/634)) +- test coverage for common ([#629](https://github.com/op-rs/kona/pull/629)) +- doc logos ([#609](https://github.com/op-rs/kona/pull/609)) +- *(workspace)* Allow stdlib in `cfg(test)` ([#548](https://github.com/op-rs/kona/pull/548)) -## [0.0.3](https://github.com/anton-rs/kona/compare/kona-common-v0.0.2...kona-common-v0.0.3) - 2024-09-04 +## [0.0.3](https://github.com/op-rs/kona/compare/kona-common-v0.0.2...kona-common-v0.0.3) - 2024-09-04 ### Added -- add zkvm target for io ([#394](https://github.com/anton-rs/kona/pull/394)) +- add zkvm target for io ([#394](https://github.com/op-rs/kona/pull/394)) ### Other -- *(workspace)* Update for `anton-rs` org transfer ([#474](https://github.com/anton-rs/kona/pull/474)) -- *(workspace)* Hoist Dependencies ([#466](https://github.com/anton-rs/kona/pull/466)) -- *(bin)* Remove `kt` ([#461](https://github.com/anton-rs/kona/pull/461)) -- *(common)* Remove need for cursors in `NativeIO` ([#416](https://github.com/anton-rs/kona/pull/416)) +- *(workspace)* Update for `op-rs` org transfer ([#474](https://github.com/op-rs/kona/pull/474)) +- *(workspace)* Hoist Dependencies ([#466](https://github.com/op-rs/kona/pull/466)) +- *(bin)* Remove `kt` ([#461](https://github.com/op-rs/kona/pull/461)) +- *(common)* Remove need for cursors in `NativeIO` ([#416](https://github.com/op-rs/kona/pull/416)) -## [0.0.2](https://github.com/anton-rs/kona/compare/kona-common-v0.0.1...kona-common-v0.0.2) - 2024-06-22 +## [0.0.2](https://github.com/op-rs/kona/compare/kona-common-v0.0.1...kona-common-v0.0.2) - 2024-06-22 ### Added -- *(client)* Derivation integration ([#257](https://github.com/anton-rs/kona/pull/257)) -- *(client/host)* Oracle-backed Blob fetcher ([#255](https://github.com/anton-rs/kona/pull/255)) -- *(host)* Host program scaffold ([#184](https://github.com/anton-rs/kona/pull/184)) -- *(preimage)* `OracleServer` + `HintReader` ([#96](https://github.com/anton-rs/kona/pull/96)) -- *(common)* Move from `RegisterSize` to native ptr size type ([#95](https://github.com/anton-rs/kona/pull/95)) +- *(client)* Derivation integration ([#257](https://github.com/op-rs/kona/pull/257)) +- *(client/host)* Oracle-backed Blob fetcher ([#255](https://github.com/op-rs/kona/pull/255)) +- *(host)* Host program scaffold ([#184](https://github.com/op-rs/kona/pull/184)) +- *(preimage)* `OracleServer` + `HintReader` ([#96](https://github.com/op-rs/kona/pull/96)) +- *(common)* Move from `RegisterSize` to native ptr size type ([#95](https://github.com/op-rs/kona/pull/95)) - *(workspace)* Add `rustfmt.toml` ### Fixed -- *(common)* Pipe IO support ([#282](https://github.com/anton-rs/kona/pull/282)) +- *(common)* Pipe IO support ([#282](https://github.com/op-rs/kona/pull/282)) ### Other -- *(common)* Use `Box::leak` rather than `mem::forget` ([#180](https://github.com/anton-rs/kona/pull/180)) -- Add simple blocking async executor ([#38](https://github.com/anton-rs/kona/pull/38)) -- Make versions of packages independent ([#36](https://github.com/anton-rs/kona/pull/36)) +- *(common)* Use `Box::leak` rather than `mem::forget` ([#180](https://github.com/op-rs/kona/pull/180)) +- Add simple blocking async executor ([#38](https://github.com/op-rs/kona/pull/38)) +- Make versions of packages independent ([#36](https://github.com/op-rs/kona/pull/36)) diff --git a/crates/proof-sdk/proof/Cargo.toml b/crates/proof-sdk/proof/Cargo.toml index 6b6af22903..d59055f040 100644 --- a/crates/proof-sdk/proof/Cargo.toml +++ b/crates/proof-sdk/proof/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "kona-proof" description = "OP Stack Proof SDK" -version = "0.2.0" +version = "0.2.3" edition.workspace = true authors.workspace = true license.workspace = true @@ -18,6 +18,7 @@ kona-derive.workspace = true kona-driver.workspace = true kona-preimage.workspace = true kona-executor.workspace = true +eigen-da.workspace = true # Alloy alloy-rlp.workspace = true @@ -26,7 +27,6 @@ alloy-consensus.workspace = true alloy-primitives.workspace = true # Op Alloy -op-alloy-registry.workspace = true op-alloy-protocol.workspace = true op-alloy-consensus.workspace = true op-alloy-genesis = { workspace = true, features = ["serde"] } diff --git a/crates/proof-sdk/proof/README.md b/crates/proof-sdk/proof/README.md index 32348f5465..e9aec8c680 100644 --- a/crates/proof-sdk/proof/README.md +++ b/crates/proof-sdk/proof/README.md @@ -1,8 +1,8 @@ # `kona-proof` -CI +CI Kona Proof SDK -License -Codecov +License +Codecov `kona-proof` is an OP Stack state transition proof SDK. diff --git a/crates/proof-sdk/proof/src/boot.rs b/crates/proof-sdk/proof/src/boot.rs index 4417890bb9..7d8388ea94 100644 --- a/crates/proof-sdk/proof/src/boot.rs +++ b/crates/proof-sdk/proof/src/boot.rs @@ -5,7 +5,6 @@ use crate::errors::OracleProviderError; use alloy_primitives::{B256, U256}; use kona_preimage::{PreimageKey, PreimageOracleClient}; use op_alloy_genesis::RollupConfig; -use op_alloy_registry::ROLLUP_CONFIGS; use serde::{Deserialize, Serialize}; /// The local key ident for the L1 head hash. @@ -105,7 +104,7 @@ impl BootInfo { // Attempt to load the rollup config from the chain ID. If there is no config for the chain, // fall back to loading the config from the preimage oracle. - let rollup_config = if let Some(config) = ROLLUP_CONFIGS.get(&chain_id) { + let rollup_config = if let Some(config) = RollupConfig::from_l2_chain_id(chain_id) { config.clone() } else { warn!( diff --git a/crates/proof-sdk/proof/src/errors.rs b/crates/proof-sdk/proof/src/errors.rs index 27bdc4db9c..d68ef15832 100644 --- a/crates/proof-sdk/proof/src/errors.rs +++ b/crates/proof-sdk/proof/src/errors.rs @@ -45,6 +45,12 @@ impl From for PipelineErrorKind { } } +impl From for OracleProviderError { + fn from(val: PreimageOracleError) -> Self { + OracleProviderError::Preimage(val) + } +} + /// Error parsing a hint. #[derive(Error, Debug)] #[error("Hint parsing error: {_0}")] diff --git a/crates/proof-sdk/proof/src/executor.rs b/crates/proof-sdk/proof/src/executor.rs index 3ceaaba0a0..809e3e9ea4 100644 --- a/crates/proof-sdk/proof/src/executor.rs +++ b/crates/proof-sdk/proof/src/executor.rs @@ -5,7 +5,9 @@ use alloy_consensus::{Header, Sealed}; use alloy_primitives::B256; use async_trait::async_trait; use kona_driver::Executor; -use kona_executor::{KonaHandleRegister, StatelessL2BlockExecutor, TrieDBProvider}; +use kona_executor::{ + ExecutionArtifacts, KonaHandleRegister, StatelessL2BlockExecutor, TrieDBProvider, +}; use kona_mpt::TrieHinter; use op_alloy_genesis::RollupConfig; use op_alloy_rpc_types_engine::OpPayloadAttributes; @@ -18,7 +20,7 @@ where H: TrieHinter + Send + Sync + Clone, { /// The rollup config for the executor. - rollup_config: &'a Arc, + rollup_config: &'a RollupConfig, /// The trie provider for the executor. trie_provider: P, /// The trie hinter for the executor. @@ -36,7 +38,7 @@ where { /// Creates a new executor. pub const fn new( - rollup_config: &'a Arc, + rollup_config: &'a RollupConfig, trie_provider: P, trie_hinter: H, handle_register: Option>, @@ -82,14 +84,11 @@ where async fn execute_payload( &mut self, attributes: OpPayloadAttributes, - ) -> Result { - self.inner - .as_mut() - .map_or_else( - || Err(kona_executor::ExecutorError::MissingExecutor), - |e| e.execute_payload(attributes), - ) - .cloned() + ) -> Result { + self.inner.as_mut().map_or_else( + || Err(kona_executor::ExecutorError::MissingExecutor), + |e| e.execute_payload(attributes), + ) } /// Computes the output root. diff --git a/crates/proof-sdk/proof/src/hint.rs b/crates/proof-sdk/proof/src/hint.rs index f77fadc30d..7e1f20c9e4 100644 --- a/crates/proof-sdk/proof/src/hint.rs +++ b/crates/proof-sdk/proof/src/hint.rs @@ -1,48 +1,87 @@ //! This module contains the [HintType] enum. -use crate::errors::HintParsingError; +use crate::errors::{HintParsingError, OracleProviderError}; use alloc::{ string::{String, ToString}, vec::Vec, }; use alloy_primitives::{hex, Bytes}; -use core::fmt::Display; +use core::{fmt::Display, str::FromStr}; +use kona_preimage::HintWriterClient; /// A [Hint] is parsed in the format ` `, where `` is a string that /// represents the type of hint, and `` is the data associated with the hint (bytes /// encoded as hex UTF-8). -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct Hint { +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct Hint { /// The type of hint. - pub hint_type: HintType, + pub ty: HT, /// The data associated with the hint. - pub hint_data: Bytes, + pub data: Bytes, } -impl Hint { - /// Parses a hint from a string. - pub fn parse(s: &str) -> Result { +impl Hint +where + HT: Display, +{ + /// Creates a new [Hint] with the specified type and data. + pub fn new>(ty: HT, data: T) -> Self { + Self { ty, data: data.into() } + } + + /// Splits the [Hint] into its components. + pub fn split(self) -> (HT, Bytes) { + (self.ty, self.data) + } + + /// Appends more data to [Hint::data]. + pub fn with_data>(self, data: T) -> Self { + // No-op if the data is empty. + if data.as_ref().is_empty() { + return self; + } + + let mut hint_data = Vec::with_capacity(self.data.len() + data.as_ref().len()); + hint_data.extend_from_slice(self.data.as_ref()); + hint_data.extend_from_slice(data.as_ref()); + + Self { data: hint_data.into(), ..self } + } + + /// Sends the hint to the passed [HintWriterClient]. + pub async fn send(&self, comms: &T) -> Result<(), OracleProviderError> { + comms.write(&self.encode()).await.map_err(OracleProviderError::Preimage) + } + + /// Encodes the hint as a string. + pub fn encode(&self) -> String { + alloc::format!("{} {}", self.ty, self.data) + } +} + +impl FromStr for Hint +where + HT: FromStr, +{ + type Err = HintParsingError; + + fn from_str(s: &str) -> Result { let mut parts = s.split(' ').collect::>(); if parts.len() != 2 { return Err(HintParsingError(alloc::format!("Invalid hint format: {}", s))); } - let hint_type = HintType::try_from(parts.remove(0))?; + let hint_type = parts.remove(0).parse::()?; let hint_data = hex::decode(parts.remove(0)).map_err(|e| HintParsingError(e.to_string()))?.into(); - Ok(Self { hint_type, hint_data }) - } - - /// Splits the [Hint] into its components. - pub fn split(self) -> (HintType, Bytes) { - (self.hint_type, self.hint_data) + Ok(Self { ty: hint_type, data: hint_data }) } } /// The [HintType] enum is used to specify the type of hint that was received. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum HintType { /// A hint that specifies the block header of a layer 1 block. L1BlockHeader, @@ -72,20 +111,27 @@ pub enum HintType { /// A hint that specifies bulk storage of all the code, state and keys generated by an /// execution witness. L2PayloadWitness, + /// A hint that specifies a blob from eigen da. + EigenDa, } impl HintType { - /// Encodes the hint type as a string. - pub fn encode_with(&self, data: &[&[u8]]) -> String { - let concatenated = hex::encode(data.iter().copied().flatten().copied().collect::>()); - alloc::format!("{} {}", self, concatenated) + /// Creates a new [Hint] from `self` and the specified data. The data passed will be + /// concatenated into a single byte array before being stored in the resulting [Hint]. + pub fn with_data(self, data: &[&[u8]]) -> Hint { + let total_len = data.iter().map(|d| d.len()).sum(); + let hint_data = data.iter().fold(Vec::with_capacity(total_len), |mut acc, d| { + acc.extend_from_slice(d); + acc + }); + Hint::new(self, hint_data) } } -impl TryFrom<&str> for HintType { - type Error = HintParsingError; +impl FromStr for HintType { + type Err = HintParsingError; - fn try_from(value: &str) -> Result { + fn from_str(value: &str) -> Result { match value { "l1-block-header" => Ok(Self::L1BlockHeader), "l1-transactions" => Ok(Self::L1Transactions), @@ -100,6 +146,7 @@ impl TryFrom<&str> for HintType { "l2-account-proof" => Ok(Self::L2AccountProof), "l2-account-storage-proof" => Ok(Self::L2AccountStorageProof), "l2-payload-witness" => Ok(Self::L2PayloadWitness), + "eigen-da" => Ok(Self::EigenDa), _ => Err(HintParsingError(value.to_string())), } } @@ -121,6 +168,7 @@ impl From for &str { HintType::L2AccountProof => "l2-account-proof", HintType::L2AccountStorageProof => "l2-account-storage-proof", HintType::L2PayloadWitness => "l2-payload-witness", + HintType::EigenDa => "eigen-da", } } } diff --git a/crates/proof-sdk/proof/src/l1/blob_provider.rs b/crates/proof-sdk/proof/src/l1/blob_provider.rs index 5d66d7f924..fb5097bc19 100644 --- a/crates/proof-sdk/proof/src/l1/blob_provider.rs +++ b/crates/proof-sdk/proof/src/l1/blob_provider.rs @@ -42,10 +42,7 @@ impl OracleBlobProvider { blob_req_meta[40..48].copy_from_slice(block_ref.timestamp.to_be_bytes().as_ref()); // Send a hint for the blob commitment and field elements. - self.oracle - .write(&HintType::L1Blob.encode_with(&[blob_req_meta.as_ref()])) - .await - .map_err(OracleProviderError::Preimage)?; + HintType::L1Blob.with_data(&[blob_req_meta.as_ref()]).send(self.oracle.as_ref()).await?; // Fetch the blob commitment. let mut commitment = [0u8; 48]; diff --git a/crates/proof-sdk/proof/src/l1/chain_provider.rs b/crates/proof-sdk/proof/src/l1/chain_provider.rs index 9f9cfb8bc6..aa199f4ef4 100644 --- a/crates/proof-sdk/proof/src/l1/chain_provider.rs +++ b/crates/proof-sdk/proof/src/l1/chain_provider.rs @@ -15,16 +15,16 @@ use op_alloy_protocol::BlockInfo; /// The oracle-backed L1 chain provider for the client program. #[derive(Debug, Clone)] pub struct OracleL1ChainProvider { - /// The boot information - boot_info: Arc, + /// The L1 head hash. + pub l1_head: B256, /// The preimage oracle client. pub oracle: Arc, } impl OracleL1ChainProvider { /// Creates a new [OracleL1ChainProvider] with the given boot information and oracle client. - pub const fn new(boot_info: Arc, oracle: Arc) -> Self { - Self { boot_info, oracle } + pub const fn new(l1_head: B256, oracle: Arc) -> Self { + Self { l1_head, oracle } } } @@ -33,26 +33,16 @@ impl ChainProvider for OracleL1ChainProvider { type Error = OracleProviderError; async fn header_by_hash(&mut self, hash: B256) -> Result { - // Send a hint for the block header. - self.oracle - .write(&HintType::L1BlockHeader.encode_with(&[hash.as_ref()])) - .await - .map_err(OracleProviderError::Preimage)?; - // Fetch the header RLP from the oracle. - let header_rlp = self - .oracle - .get(PreimageKey::new(*hash, PreimageKeyType::Keccak256)) - .await - .map_err(OracleProviderError::Preimage)?; - + HintType::L1BlockHeader.with_data(&[hash.as_ref()]).send(self.oracle.as_ref()).await?; + let header_rlp = self.oracle.get(PreimageKey::new_keccak256(*hash)).await?; // Decode the header RLP into a Header. Header::decode(&mut header_rlp.as_slice()).map_err(OracleProviderError::Rlp) } async fn block_info_by_number(&mut self, block_number: u64) -> Result { // Fetch the starting block header. - let mut header = self.header_by_hash(self.boot_info.l1_head).await?; + let mut header = self.header_by_hash(self.l1_head).await?; // Check if the block number is in range. If not, we can fail early. if block_number > header.number { @@ -78,10 +68,7 @@ impl ChainProvider for OracleL1ChainProvider { // Send a hint for the block's receipts, and walk through the receipts trie in the header to // verify them. - self.oracle - .write(&HintType::L1Receipts.encode_with(&[hash.as_ref()])) - .await - .map_err(OracleProviderError::Preimage)?; + HintType::L1Receipts.with_data(&[hash.as_ref()]).send(self.oracle.as_ref()).await?; let trie_walker = OrderedListWalker::try_new_hydrated(header.receipts_root, self) .map_err(OracleProviderError::TrieWalker)?; @@ -113,10 +100,7 @@ impl ChainProvider for OracleL1ChainProvider { // Send a hint for the block's transactions, and walk through the transactions trie in the // header to verify them. - self.oracle - .write(&HintType::L1Transactions.encode_with(&[hash.as_ref()])) - .await - .map_err(OracleProviderError::Preimage)?; + HintType::L1Transactions.with_data(&[hash.as_ref()]).send(self.oracle.as_ref()).await?; let trie_walker = OrderedListWalker::try_new_hydrated(header.transactions_root, self) .map_err(OracleProviderError::TrieWalker)?; diff --git a/crates/proof-sdk/proof/src/l1/eigen_da_provider.rs b/crates/proof-sdk/proof/src/l1/eigen_da_provider.rs new file mode 100644 index 0000000000..883267bd51 --- /dev/null +++ b/crates/proof-sdk/proof/src/l1/eigen_da_provider.rs @@ -0,0 +1,134 @@ +use alloc::boxed::Box; +use alloc::string::ToString; +use alloc::sync::Arc; +use alloc::vec; +use alloc::vec::Vec; +use alloy_primitives::{keccak256, Bytes}; +use alloy_rlp::Decodable; +use async_trait::async_trait; +use eigen_da::{BlobInfo, EigenDABlobData, BYTES_PER_FIELD_ELEMENT}; +// use tokio::io::AsyncReadExt; +use crate::errors::OracleProviderError; +use crate::HintType; +use kona_derive::traits::EigenDAProvider; +use kona_preimage::errors::PreimageOracleError; +use kona_preimage::PreimageKeyType::Precompile; +use kona_preimage::{CommsClient, PreimageKey, PreimageKeyType}; + +#[derive(Debug, Clone)] +pub struct OracleEigenDaProvider { + /// The preimage oracle client. + pub oracle: Arc, +} + +impl OracleEigenDaProvider { + /// Constructs a new `OracleBlobProvider`. + pub fn new(oracle: Arc) -> Self { + Self { oracle } + } + + /// Retrieves a blob from the oracle. + /// + /// ## Takes + /// - `commitment`: The blob commitment. + /// + /// ## Returns + /// - `Ok(blob)`: The blob. + /// - `Err(e)`: The blob could not be retrieved. + async fn get_blob( + &self, + commitment: &[u8], + blob_len: u32, + ) -> Result, OracleProviderError> { + HintType::EigenDa.with_data(&[commitment.as_ref()]).send(self.oracle.as_ref()).await?; + + // the fourth because 0x010000 in the beginning is metadata + // cert should at least contain 32 bytes for header + 3 bytes for commitment type metadata + if commitment.len() <= 32 + 3 { + return Err(OracleProviderError::Preimage(PreimageOracleError::Other( + "does not contain header".into(), + ))); + } + + // the first four bytes are metadata, like cert version, OP generic commitement + // see https://github.com/Layr-Labs/eigenda-proxy/blob/main/commitments/mode.go#L39 + // the first byte my guess is the OP + let cert_blob_info = BlobInfo::decode(&mut &commitment[3..]).unwrap(); + tracing::debug!("cert_blob_info {:?}", cert_blob_info); + + // data_length measurs in field element, multiply to get num bytes + let mut blob: Vec = + vec![0; cert_blob_info.blob_header.data_length as usize * BYTES_PER_FIELD_ELEMENT]; + + // 96 because our g1 commitment has 64 bytes in v1 + // why 96, the original 4844 has bytes length of 80 (it has 48 bytes for commitment) + // even then, it is not that the entire 80 bytes are used. Some bytes are empty + // for solidity optimization, I remember. + // + // TODO: investigate later to decide a right size + let mut blob_key = [0u8; 96]; + + // In eigenDA terminology, length describes the number of field element, size describes + // number of bytes. + let data_length = cert_blob_info.blob_header.data_length as u64; + + tracing::debug!("cert_blob_info.blob_header.data_length {:?}", data_length); + + // the common key + blob_key[..32].copy_from_slice(&cert_blob_info.blob_header.commitment.x); + blob_key[32..64].copy_from_slice(&cert_blob_info.blob_header.commitment.y); + + // + 1 for the proof + for i in 0..data_length { + blob_key[88..].copy_from_slice(i.to_be_bytes().as_ref()); + + let mut field_element = [0u8; 32]; + self.oracle + .get_exact( + PreimageKey::new(*keccak256(blob_key), PreimageKeyType::GlobalGeneric), + &mut field_element, + ) + .await + .map_err(OracleProviderError::Preimage)?; + + // if field element is 0, it means the host has identified that the data + // has breached eigenda invariant, i.e cert is valid + if field_element.is_empty() { + return Err(OracleProviderError::Preimage(PreimageOracleError::Other( + "field elememnt is empty, breached eigenda invariant".into(), + ))); + } + + blob[(i as usize) << 5..(i as usize + 1) << 5].copy_from_slice(field_element.as_ref()); + } + + tracing::debug!(target: "client_oracle", "Retrieved blob from eigen da with commitment {commitment:?} from the oracle."); + let eigenda_blob_data = EigenDABlobData::new(Bytes::copy_from_slice(&blob)); + let blobs = eigenda_blob_data.decode(); + + blobs + .map_err(|err| { + OracleProviderError::Preimage(PreimageOracleError::Other(err.to_string())) + }) + .map(|blob_data| blob_data.to_vec()) + } +} + +#[async_trait] +impl EigenDAProvider for OracleEigenDaProvider { + type Error = OracleProviderError; + + async fn retrieve_blob_with_commitment( + &mut self, + commitment: &[u8], + blob_len: u32, + ) -> Result, Self::Error> { + trace!("Start to get blobs from eigen da with commitment {:?}", commitment); + let out_data: Vec = self.get_blob(commitment, blob_len).await?; + Ok(out_data) + } + + fn da_indexer_enable(&mut self) -> bool { + false + } +} diff --git a/crates/proof-sdk/proof/src/l1/mod.rs b/crates/proof-sdk/proof/src/l1/mod.rs index 9368771684..0282590506 100644 --- a/crates/proof-sdk/proof/src/l1/mod.rs +++ b/crates/proof-sdk/proof/src/l1/mod.rs @@ -10,4 +10,8 @@ mod blob_provider; pub use blob_provider::OracleBlobProvider; mod chain_provider; +mod eigen_da_provider; + pub use chain_provider::OracleL1ChainProvider; + +pub use eigen_da_provider::OracleEigenDaProvider; diff --git a/crates/proof-sdk/proof/src/l1/pipeline.rs b/crates/proof-sdk/proof/src/l1/pipeline.rs index b2e1719b56..00a786d4ca 100644 --- a/crates/proof-sdk/proof/src/l1/pipeline.rs +++ b/crates/proof-sdk/proof/src/l1/pipeline.rs @@ -4,6 +4,8 @@ use crate::{l1::OracleL1ChainProvider, l2::OracleL2ChainProvider, FlushableCache use alloc::{boxed::Box, sync::Arc}; use async_trait::async_trait; use core::fmt::Debug; +use kona_derive::prelude::EigenDaSource; +use kona_derive::traits::EigenDAProvider; use kona_derive::{ attributes::StatefulAttributesBuilder, errors::PipelineErrorKind, @@ -21,15 +23,16 @@ use kona_preimage::CommsClient; use op_alloy_genesis::{RollupConfig, SystemConfig}; use op_alloy_protocol::{BlockInfo, L2BlockInfo}; use op_alloy_rpc_types_engine::OpAttributesWithParent; +use spin::RwLock; /// An oracle-backed derivation pipeline. -pub type OracleDerivationPipeline = DerivationPipeline< - OracleAttributesQueue, O>, +pub type OracleDerivationPipeline = DerivationPipeline< + OracleAttributesQueue, O>, OracleL2ChainProvider, >; /// An oracle-backed Ethereum data source. -pub type OracleDataProvider = EthereumDataSource, B>; +pub type OracleDataProvider = EthereumDataSource, B, E>; /// An oracle-backed payload attributes builder for the `AttributesQueue` stage of the derivation /// pipeline. @@ -45,37 +48,38 @@ pub type OracleAttributesQueue = AttributesQueue< FrameQueue>>>, >, >, - OracleL2ChainProvider, >, - OracleL2ChainProvider, >, OracleAttributesBuilder, >; /// An oracle-backed derivation pipeline. #[derive(Debug)] -pub struct OraclePipeline +pub struct OraclePipeline where O: CommsClient + FlushableCache + Send + Sync + Debug, B: BlobProvider + Send + Sync + Debug + Clone, + E: EigenDAProvider + Send + Sync + Debug + Clone, { /// The internal derivation pipeline. - pub pipeline: OracleDerivationPipeline, + pub pipeline: OracleDerivationPipeline, /// The caching oracle. pub caching_oracle: Arc, } -impl OraclePipeline +impl OraclePipeline where O: CommsClient + FlushableCache + FlushableCache + Send + Sync + Debug, B: BlobProvider + Send + Sync + Debug + Clone, + E: EigenDAProvider + Send + Sync + Debug + Clone, { /// Constructs a new oracle-backed derivation pipeline. pub fn new( cfg: Arc, - sync_start: PipelineCursor, + sync_start: Arc>, caching_oracle: Arc, blob_provider: B, + eigen_da_provider: E, chain_provider: OracleL1ChainProvider, l2_chain_provider: OracleL2ChainProvider, ) -> Self { @@ -84,7 +88,13 @@ where l2_chain_provider.clone(), chain_provider.clone(), ); - let dap = EthereumDataSource::new_from_parts(chain_provider.clone(), blob_provider, &cfg); + + let dap = EthereumDataSource::new_from_parts( + chain_provider.clone(), + blob_provider.clone(), + eigen_da_provider.clone(), + &cfg, + ); let pipeline = PipelineBuilder::new() .rollup_config(cfg) @@ -92,16 +102,17 @@ where .l2_chain_provider(l2_chain_provider) .chain_provider(chain_provider) .builder(attributes) - .origin(sync_start.origin()) + .origin(sync_start.read().origin()) .build(); Self { pipeline, caching_oracle } } } -impl DriverPipeline> for OraclePipeline +impl DriverPipeline> for OraclePipeline where O: CommsClient + FlushableCache + Send + Sync + Debug, B: BlobProvider + Send + Sync + Debug + Clone, + E: EigenDAProvider + Send + Sync + Debug + Clone, { /// Flushes the cache on re-org. fn flush(&mut self) { @@ -110,10 +121,11 @@ where } #[async_trait] -impl SignalReceiver for OraclePipeline +impl SignalReceiver for OraclePipeline where O: CommsClient + FlushableCache + Send + Sync + Debug, B: BlobProvider + Send + Sync + Debug + Clone, + E: EigenDAProvider + Send + Sync + Debug + Clone, { /// Receives a signal from the driver. async fn signal(&mut self, signal: Signal) -> PipelineResult<()> { @@ -121,10 +133,11 @@ where } } -impl OriginProvider for OraclePipeline +impl OriginProvider for OraclePipeline where O: CommsClient + FlushableCache + Send + Sync + Debug, B: BlobProvider + Send + Sync + Debug + Clone, + E: EigenDAProvider + Send + Sync + Debug + Clone, { /// Returns the optional L1 [BlockInfo] origin. fn origin(&self) -> Option { @@ -132,10 +145,11 @@ where } } -impl Iterator for OraclePipeline +impl Iterator for OraclePipeline where O: CommsClient + FlushableCache + Send + Sync + Debug, B: BlobProvider + Send + Sync + Debug + Clone, + E: EigenDAProvider + Send + Sync + Debug + Clone, { type Item = OpAttributesWithParent; @@ -145,10 +159,11 @@ where } #[async_trait] -impl Pipeline for OraclePipeline +impl Pipeline for OraclePipeline where O: CommsClient + FlushableCache + Send + Sync + Debug, B: BlobProvider + Send + Sync + Debug + Clone, + E: EigenDAProvider + Send + Sync + Debug + Clone, { /// Peeks at the next [OpAttributesWithParent] from the pipeline. fn peek(&self) -> Option<&OpAttributesWithParent> { diff --git a/crates/proof-sdk/proof/src/l2/chain_provider.rs b/crates/proof-sdk/proof/src/l2/chain_provider.rs index 224eedba1d..0b022768ea 100644 --- a/crates/proof-sdk/proof/src/l2/chain_provider.rs +++ b/crates/proof-sdk/proof/src/l2/chain_provider.rs @@ -1,6 +1,6 @@ //! Contains the concrete implementation of the [L2ChainProvider] trait for the client program. -use crate::{errors::OracleProviderError, BootInfo, HintType}; +use crate::{errors::OracleProviderError, HintType}; use alloc::{boxed::Box, sync::Arc, vec::Vec}; use alloy_consensus::{BlockBody, Header}; use alloy_eips::eip2718::Decodable2718; @@ -8,26 +8,52 @@ use alloy_primitives::{Address, Bytes, B256}; use alloy_rlp::Decodable; use async_trait::async_trait; use kona_derive::traits::L2ChainProvider; +use kona_driver::PipelineCursor; use kona_executor::TrieDBProvider; use kona_mpt::{OrderedListWalker, TrieHinter, TrieNode, TrieProvider}; use kona_preimage::{CommsClient, PreimageKey, PreimageKeyType}; use op_alloy_consensus::{OpBlock, OpTxEnvelope}; use op_alloy_genesis::{RollupConfig, SystemConfig}; use op_alloy_protocol::{to_system_config, BatchValidationProvider, L2BlockInfo}; +use spin::RwLock; /// The oracle-backed L2 chain provider for the client program. #[derive(Debug, Clone)] pub struct OracleL2ChainProvider { - /// The boot information - boot_info: Arc, + /// The L2 safe head block hash. + l2_head: B256, + /// The rollup configuration. + rollup_config: Arc, /// The preimage oracle client. oracle: Arc, + /// The derivation pipeline cursor + cursor: Option>>, + /// The L2 chain ID to use for the provider's hints. + chain_id: Option, } impl OracleL2ChainProvider { /// Creates a new [OracleL2ChainProvider] with the given boot information and oracle client. - pub const fn new(boot_info: Arc, oracle: Arc) -> Self { - Self { boot_info, oracle } + pub const fn new(l2_head: B256, rollup_config: Arc, oracle: Arc) -> Self { + Self { l2_head, rollup_config, oracle, cursor: None, chain_id: None } + } + + /// Sets the L2 chain ID to use for the provider's hints. + pub fn set_chain_id(&mut self, chain_id: Option) { + self.chain_id = chain_id; + } + + /// Updates the derivation pipeline cursor + pub fn set_cursor(&mut self, cursor: Arc>) { + self.cursor = Some(cursor); + } + + /// Fetches the latest known safe head block hash according to the derivation pipeline cursor + /// or uses the initial l2_head value if no cursor is set. + pub async fn l2_safe_head(&self) -> Result { + self.cursor + .as_ref() + .map_or(Ok(self.l2_head), |cursor| Ok(cursor.read().l2_safe_head().block_info.hash)) } } @@ -35,27 +61,8 @@ impl OracleL2ChainProvider { /// Returns a [Header] corresponding to the given L2 block number, by walking back from the /// L2 safe head. async fn header_by_number(&mut self, block_number: u64) -> Result { - // Fetch the starting L2 output preimage. - self.oracle - .write( - &HintType::StartingL2Output - .encode_with(&[self.boot_info.agreed_l2_output_root.as_ref()]), - ) - .await - .map_err(OracleProviderError::Preimage)?; - let output_preimage = self - .oracle - .get(PreimageKey::new( - *self.boot_info.agreed_l2_output_root, - PreimageKeyType::Keccak256, - )) - .await - .map_err(OracleProviderError::Preimage)?; - // Fetch the starting block header. - let block_hash = - output_preimage[96..128].try_into().map_err(OracleProviderError::SliceConversion)?; - let mut header = self.header_by_hash(block_hash)?; + let mut header = self.header_by_hash(self.l2_safe_head().await?)?; // Check if the block number is in range. If not, we can fail early. if block_number > header.number { @@ -80,7 +87,7 @@ impl BatchValidationProvider for OracleL2ChainProv let block = self.block_by_number(number).await?; // Construct the system config from the payload. - L2BlockInfo::from_block_and_genesis(&block, &self.boot_info.rollup_config.genesis) + L2BlockInfo::from_block_and_genesis(&block, &self.rollup_config.genesis) .map_err(OracleProviderError::BlockInfo) } @@ -91,10 +98,11 @@ impl BatchValidationProvider for OracleL2ChainProv let header_hash = header.hash_slow(); // Fetch the transactions in the block. - self.oracle - .write(&HintType::L2Transactions.encode_with(&[header_hash.as_ref()])) - .await - .map_err(OracleProviderError::Preimage)?; + HintType::L2Transactions + .with_data(&[header_hash.as_ref()]) + .with_data(self.chain_id.map_or_else(Vec::new, |id| id.to_be_bytes().to_vec())) + .send(self.oracle.as_ref()) + .await?; let trie_walker = OrderedListWalker::try_new_hydrated(transactions_root, self) .map_err(OracleProviderError::TrieWalker)?; @@ -110,15 +118,7 @@ impl BatchValidationProvider for OracleL2ChainProv let optimism_block = OpBlock { header, - body: BlockBody { - transactions, - ommers: Vec::new(), - withdrawals: self - .boot_info - .rollup_config - .is_canyon_active(timestamp) - .then(|| alloy_eips::eip4895::Withdrawals::new(Vec::new())), - }, + body: BlockBody { transactions, ommers: Vec::new(), withdrawals: None }, }; Ok(optimism_block) } @@ -166,13 +166,13 @@ impl TrieDBProvider for OracleL2ChainProvider { fn bytecode_by_hash(&self, hash: B256) -> Result { // Fetch the bytecode preimage from the caching oracle. crate::block_on(async move { + HintType::L2Code + .with_data(&[hash.as_slice()]) + .with_data(self.chain_id.map_or_else(Vec::new, |id| id.to_be_bytes().to_vec())) + .send(self.oracle.as_ref()) + .await?; self.oracle - .write(&HintType::L2Code.encode_with(&[hash.as_ref()])) - .await - .map_err(OracleProviderError::Preimage)?; - - self.oracle - .get(PreimageKey::new(*hash, PreimageKeyType::Keccak256)) + .get(PreimageKey::new_keccak256(*hash)) .await .map(Into::into) .map_err(OracleProviderError::Preimage) @@ -182,16 +182,13 @@ impl TrieDBProvider for OracleL2ChainProvider { fn header_by_hash(&self, hash: B256) -> Result { // Fetch the header from the caching oracle. crate::block_on(async move { - self.oracle - .write(&HintType::L2BlockHeader.encode_with(&[hash.as_ref()])) - .await - .map_err(OracleProviderError::Preimage)?; + HintType::L2BlockHeader + .with_data(&[hash.as_slice()]) + .with_data(self.chain_id.map_or_else(Vec::new, |id| id.to_be_bytes().to_vec())) + .send(self.oracle.as_ref()) + .await?; + let header_bytes = self.oracle.get(PreimageKey::new_keccak256(*hash)).await?; - let header_bytes = self - .oracle - .get(PreimageKey::new(*hash, PreimageKeyType::Keccak256)) - .await - .map_err(OracleProviderError::Preimage)?; Header::decode(&mut header_bytes.as_slice()).map_err(OracleProviderError::Rlp) }) } @@ -202,22 +199,21 @@ impl TrieHinter for OracleL2ChainProvider { fn hint_trie_node(&self, hash: B256) -> Result<(), Self::Error> { crate::block_on(async move { - self.oracle - .write(&HintType::L2StateNode.encode_with(&[hash.as_slice()])) + HintType::L2StateNode + .with_data(&[hash.as_slice()]) + .with_data(self.chain_id.map_or_else(Vec::new, |id| id.to_be_bytes().to_vec())) + .send(self.oracle.as_ref()) .await - .map_err(OracleProviderError::Preimage) }) } fn hint_account_proof(&self, address: Address, block_number: u64) -> Result<(), Self::Error> { crate::block_on(async move { - self.oracle - .write( - &HintType::L2AccountProof - .encode_with(&[block_number.to_be_bytes().as_ref(), address.as_slice()]), - ) + HintType::L2AccountProof + .with_data(&[block_number.to_be_bytes().as_ref(), address.as_slice()]) + .with_data(self.chain_id.map_or_else(Vec::new, |id| id.to_be_bytes().to_vec())) + .send(self.oracle.as_ref()) .await - .map_err(OracleProviderError::Preimage) }) } @@ -228,14 +224,15 @@ impl TrieHinter for OracleL2ChainProvider { block_number: u64, ) -> Result<(), Self::Error> { crate::block_on(async move { - self.oracle - .write(&HintType::L2AccountStorageProof.encode_with(&[ + HintType::L2AccountStorageProof + .with_data(&[ block_number.to_be_bytes().as_ref(), address.as_slice(), slot.to_be_bytes::<32>().as_ref(), - ])) + ]) + .with_data(self.chain_id.map_or_else(Vec::new, |id| id.to_be_bytes().to_vec())) + .send(self.oracle.as_ref()) .await - .map_err(OracleProviderError::Preimage) }) } } diff --git a/crates/proof-sdk/proof/src/sync.rs b/crates/proof-sdk/proof/src/sync.rs index 0cb804f05e..1c097081ff 100644 --- a/crates/proof-sdk/proof/src/sync.rs +++ b/crates/proof-sdk/proof/src/sync.rs @@ -1,23 +1,27 @@ //! Sync Start use crate::{ - errors::OracleProviderError, l1::OracleL1ChainProvider, l2::OracleL2ChainProvider, BootInfo, + errors::OracleProviderError, l1::OracleL1ChainProvider, l2::OracleL2ChainProvider, FlushableCache, }; +use alloc::sync::Arc; use alloy_consensus::{Header, Sealed}; +use alloy_primitives::B256; use core::fmt::Debug; use kona_derive::traits::ChainProvider; use kona_driver::{PipelineCursor, TipCursor}; use kona_preimage::CommsClient; +use op_alloy_genesis::RollupConfig; use op_alloy_protocol::BatchValidationProvider; +use spin::RwLock; /// Constructs a [`PipelineCursor`] from the caching oracle, boot info, and providers. pub async fn new_pipeline_cursor( - boot_info: &BootInfo, + rollup_config: &RollupConfig, safe_header: Sealed
, chain_provider: &mut OracleL1ChainProvider, l2_chain_provider: &mut OracleL2ChainProvider, -) -> Result +) -> Result>, OracleProviderError> where O: CommsClient + FlushableCache + FlushableCache + Send + Sync + Debug, { @@ -26,17 +30,18 @@ where // Walk back the starting L1 block by `channel_timeout` to ensure that the full channel is // captured. - let channel_timeout = - boot_info.rollup_config.channel_timeout(safe_head_info.block_info.timestamp); + let channel_timeout = rollup_config.channel_timeout(safe_head_info.block_info.timestamp); let mut l1_origin_number = l1_origin.number.saturating_sub(channel_timeout); - if l1_origin_number < boot_info.rollup_config.genesis.l1.number { - l1_origin_number = boot_info.rollup_config.genesis.l1.number; + if l1_origin_number < rollup_config.genesis.l1.number { + l1_origin_number = rollup_config.genesis.l1.number; } let origin = chain_provider.block_info_by_number(l1_origin_number).await?; // Construct the cursor. let mut cursor = PipelineCursor::new(channel_timeout, origin); - let tip = TipCursor::new(safe_head_info, safe_header, boot_info.agreed_l2_output_root); + let tip = TipCursor::new(safe_head_info, safe_header, B256::ZERO); cursor.advance(origin, tip); - Ok(cursor) + + // Wrap the cursor in a shared read-write lock + Ok(Arc::new(RwLock::new(cursor))) } diff --git a/crates/proof-sdk/std-fpvm-proc/CHANGELOG.md b/crates/proof-sdk/std-fpvm-proc/CHANGELOG.md index 15b8074535..0070fd26c9 100644 --- a/crates/proof-sdk/std-fpvm-proc/CHANGELOG.md +++ b/crates/proof-sdk/std-fpvm-proc/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -## [0.1.1](https://github.com/anton-rs/kona/compare/kona-std-fpvm-proc-v0.1.0...kona-std-fpvm-proc-v0.1.1) - 2024-12-03 +## [0.1.1](https://github.com/op-rs/kona/compare/kona-std-fpvm-proc-v0.1.0...kona-std-fpvm-proc-v0.1.1) - 2024-12-03 ### Other diff --git a/crates/proof-sdk/std-fpvm/CHANGELOG.md b/crates/proof-sdk/std-fpvm/CHANGELOG.md index 06880b1d27..d9fd88e16d 100644 --- a/crates/proof-sdk/std-fpvm/CHANGELOG.md +++ b/crates/proof-sdk/std-fpvm/CHANGELOG.md @@ -7,7 +7,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -## [0.1.1](https://github.com/anton-rs/kona/compare/kona-std-fpvm-v0.1.0...kona-std-fpvm-v0.1.1) - 2024-12-03 +## [0.1.1](https://github.com/op-rs/kona/compare/kona-std-fpvm-v0.1.0...kona-std-fpvm-v0.1.1) - 2024-12-03 ### Other diff --git a/crates/proof-sdk/std-fpvm/README.md b/crates/proof-sdk/std-fpvm/README.md index 2637e592e5..6eb566d9bc 100644 --- a/crates/proof-sdk/std-fpvm/README.md +++ b/crates/proof-sdk/std-fpvm/README.md @@ -1,9 +1,9 @@ # `kona-std-fpvm` -CI +CI Kona Proof SDK -License -Codecov +License +Codecov Platform specific [Fault Proof VM][g-fault-proof-vm] kernel APIs. diff --git a/crates/proof-sdk/std-fpvm/src/lib.rs b/crates/proof-sdk/std-fpvm/src/lib.rs index 5c34de0053..14482e8626 100644 --- a/crates/proof-sdk/std-fpvm/src/lib.rs +++ b/crates/proof-sdk/std-fpvm/src/lib.rs @@ -1,7 +1,7 @@ #![doc = include_str!("../README.md")] #![doc( - html_logo_url = "https://raw.githubusercontent.com/anton-rs/kona/main/assets/square.png", - html_favicon_url = "https://raw.githubusercontent.com/anton-rs/kona/main/assets/favicon.ico" + html_logo_url = "https://raw.githubusercontent.com/op-rs/kona/main/assets/square.png", + html_favicon_url = "https://raw.githubusercontent.com/op-rs/kona/main/assets/favicon.ico" )] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] #![cfg_attr(target_arch = "mips", feature(asm_experimental_arch))] diff --git a/crates/proof-sdk/std-fpvm/src/riscv64/mod.rs b/crates/proof-sdk/std-fpvm/src/riscv64/mod.rs index dd28a94b71..f90970ea7c 100644 --- a/crates/proof-sdk/std-fpvm/src/riscv64/mod.rs +++ b/crates/proof-sdk/std-fpvm/src/riscv64/mod.rs @@ -1,5 +1,5 @@ -//! This module contains raw syscall bindings for the `riscv64gc` target architecture, as well as a -//! high-level implementation of the [crate::BasicKernelInterface] trait for the kernel. +//! This module contains raw syscall bindings for the `riscv64imac` target architecture, as well as +//! a high-level implementation of the [crate::BasicKernelInterface] trait for the kernel. pub(crate) mod io; mod syscall; diff --git a/crates/providers-alloy/Cargo.toml b/crates/providers-alloy/Cargo.toml new file mode 100644 index 0000000000..053fc13af9 --- /dev/null +++ b/crates/providers-alloy/Cargo.toml @@ -0,0 +1,44 @@ +[package] +name = "kona-providers-alloy" +version = "0.1.0" +description = "Alloy-backed providers for hilo" + +edition.workspace = true +authors.workspace = true +license.workspace = true +homepage.workspace = true +keywords.workspace = true +categories.workspace = true +repository.workspace = true +rust-version.workspace = true + +[dependencies] +# Kona +kona-derive.workspace = true +eigen-da.workspace = true + +# Alloy +alloy-rlp.workspace = true +alloy-serde.workspace = true +alloy-eips = { workspace = true, features = ["kzg"] } +alloy-transport.workspace = true +alloy-consensus.workspace = true +alloy-rpc-types-beacon.workspace = true +alloy-provider = { workspace = true, features = ["ipc", "ws", "reqwest"] } +alloy-primitives = { workspace = true, features = ["map"] } + +# Op Alloy +op-alloy-consensus.workspace = true +op-alloy-genesis.workspace = true +op-alloy-protocol.workspace = true + +# Misc +lru.workspace = true +serde.workspace = true +thiserror.workspace = true +async-trait.workspace = true +reqwest = { workspace = true, features = ["json"] } +tokio.workspace = true + +[dev-dependencies] +tokio.workspace = true diff --git a/crates/providers-alloy/README.md b/crates/providers-alloy/README.md new file mode 100644 index 0000000000..7655b4c641 --- /dev/null +++ b/crates/providers-alloy/README.md @@ -0,0 +1,8 @@ +# `kona-providers-alloy` + +CI +Kona MPT +License +Codecov + +Alloy-backed providers for `kona`. diff --git a/crates/providers-alloy/src/beacon_client.rs b/crates/providers-alloy/src/beacon_client.rs new file mode 100644 index 0000000000..bd2af195da --- /dev/null +++ b/crates/providers-alloy/src/beacon_client.rs @@ -0,0 +1,149 @@ +//! Contains an online implementation of the `BeaconClient` trait. + +use alloy_eips::eip4844::IndexedBlobHash; +use alloy_rpc_types_beacon::sidecar::{BeaconBlobBundle, BlobData}; +use async_trait::async_trait; +use reqwest::Client; +use std::{ + boxed::Box, + format, + string::{String, ToString}, + vec::Vec, +}; + +/// The config spec engine api method. +const SPEC_METHOD: &str = "eth/v1/config/spec"; + +/// The beacon genesis engine api method. +const GENESIS_METHOD: &str = "eth/v1/beacon/genesis"; + +/// The blob sidecars engine api method prefix. +const SIDECARS_METHOD_PREFIX: &str = "eth/v1/beacon/blob_sidecars"; + +/// A reduced genesis data. +#[derive(Debug, Default, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub struct ReducedGenesisData { + /// The genesis time. + #[serde(rename = "genesis_time")] + #[serde(with = "alloy_serde::quantity")] + pub genesis_time: u64, +} + +/// An API genesis response. +#[derive(Debug, Default, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub struct APIGenesisResponse { + /// The data. + pub data: ReducedGenesisData, +} + +/// A reduced config data. +#[derive(Debug, Default, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub struct ReducedConfigData { + /// The seconds per slot. + #[serde(rename = "SECONDS_PER_SLOT")] + #[serde(with = "alloy_serde::quantity")] + pub seconds_per_slot: u64, +} + +/// An API config response. +#[derive(Debug, Default, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] +pub struct APIConfigResponse { + /// The data. + pub data: ReducedConfigData, +} + +impl APIConfigResponse { + /// Creates a new API config response. + pub const fn new(seconds_per_slot: u64) -> Self { + Self { data: ReducedConfigData { seconds_per_slot } } + } +} + +impl APIGenesisResponse { + /// Creates a new API genesis response. + pub const fn new(genesis_time: u64) -> Self { + Self { data: ReducedGenesisData { genesis_time } } + } +} + +/// The [BeaconClient] is a thin wrapper around the Beacon API. +#[async_trait] +pub trait BeaconClient { + /// The error type for [BeaconClient] implementations. + type Error: core::fmt::Display + ToString; + + /// Returns the config spec. + async fn config_spec(&self) -> Result; + + /// Returns the beacon genesis. + async fn beacon_genesis(&self) -> Result; + + /// Fetches blob sidecars that were confirmed in the specified L1 block with the given indexed + /// hashes. Order of the returned sidecars is guaranteed to be that of the hashes. Blob data is + /// not checked for validity. + async fn beacon_blob_side_cars( + &self, + slot: u64, + hashes: &[IndexedBlobHash], + ) -> Result, Self::Error>; +} + +/// An online implementation of the [BeaconClient] trait. +#[derive(Debug, Clone)] +pub struct OnlineBeaconClient { + /// The base URL of the beacon API. + pub base: String, + /// The inner reqwest client. + pub inner: Client, +} + +impl OnlineBeaconClient { + /// Creates a new [OnlineBeaconClient] from the provided [reqwest::Url]. + pub fn new_http(mut base: String) -> Self { + // If base ends with a slash, remove it + if base.ends_with("/") { + base.remove(base.len() - 1); + } + Self { base, inner: Client::new() } + } +} + +#[async_trait] +impl BeaconClient for OnlineBeaconClient { + type Error = reqwest::Error; + + async fn config_spec(&self) -> Result { + let first = self.inner.get(format!("{}/{}", self.base, SPEC_METHOD)).send().await?; + first.json::().await + } + + async fn beacon_genesis(&self) -> Result { + let first = self.inner.get(format!("{}/{}", self.base, GENESIS_METHOD)).send().await?; + first.json::().await + } + + async fn beacon_blob_side_cars( + &self, + slot: u64, + hashes: &[IndexedBlobHash], + ) -> Result, Self::Error> { + let raw_response = self + .inner + .get(format!("{}/{}/{}", self.base, SIDECARS_METHOD_PREFIX, slot)) + .send() + .await?; + let raw_response = raw_response.json::().await?; + + // Filter the sidecars by the hashes, in-order. + let mut sidecars = Vec::with_capacity(hashes.len()); + hashes.iter().for_each(|hash| { + if let Some(sidecar) = + raw_response.data.iter().find(|sidecar| sidecar.index == hash.index) + { + sidecars.push(sidecar.clone()); + } + }); + + Ok(sidecars) + } +} diff --git a/bin/host/src/blobs.rs b/crates/providers-alloy/src/blobs.rs similarity index 51% rename from bin/host/src/blobs.rs rename to crates/providers-alloy/src/blobs.rs index 908cb12f52..b98905a74d 100644 --- a/bin/host/src/blobs.rs +++ b/crates/providers-alloy/src/blobs.rs @@ -1,139 +1,47 @@ //! Contains an online implementation of the `BlobProvider` trait. +use crate::BeaconClient; use alloy_eips::eip4844::{Blob, BlobTransactionSidecarItem, IndexedBlobHash}; -use alloy_rpc_types_beacon::sidecar::{BeaconBlobBundle, BlobData}; +use alloy_rpc_types_beacon::sidecar::BlobData; use async_trait::async_trait; use kona_derive::{errors::BlobProviderError, traits::BlobProvider}; use op_alloy_protocol::BlockInfo; -use reqwest::Client; - -/// The config spec engine api method. -const SPEC_METHOD: &str = "eth/v1/config/spec"; - -/// The beacon genesis engine api method. -const GENESIS_METHOD: &str = "eth/v1/beacon/genesis"; - -/// The blob sidecars engine api method prefix. -const SIDECARS_METHOD_PREFIX: &str = "eth/v1/beacon/blob_sidecars"; - -/// A reduced genesis data. -#[derive(Debug, Default, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] -pub struct ReducedGenesisData { - /// The genesis time. - #[serde(rename = "genesis_time")] - #[serde(with = "alloy_serde::quantity")] - pub genesis_time: u64, -} - -/// An API genesis response. -#[derive(Debug, Default, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] -pub struct APIGenesisResponse { - /// The data. - pub data: ReducedGenesisData, -} - -/// A reduced config data. -#[derive(Debug, Default, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] -pub struct ReducedConfigData { - /// The seconds per slot. - #[serde(rename = "SECONDS_PER_SLOT")] - #[serde(with = "alloy_serde::quantity")] - pub seconds_per_slot: u64, -} - -/// An API config response. -#[derive(Debug, Default, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] -pub struct APIConfigResponse { - /// The data. - pub data: ReducedConfigData, -} - -impl APIConfigResponse { - /// Creates a new API config response. - pub const fn new(seconds_per_slot: u64) -> Self { - Self { data: ReducedConfigData { seconds_per_slot } } - } -} - -impl APIGenesisResponse { - /// Creates a new API genesis response. - pub const fn new(genesis_time: u64) -> Self { - Self { data: ReducedGenesisData { genesis_time } } - } -} +use std::{boxed::Box, string::ToString, vec::Vec}; /// An online implementation of the [BlobProvider] trait. #[derive(Debug, Clone)] -pub struct OnlineBlobProvider { - /// The base url. - base: String, - /// The inner reqwest client. - inner: Client, - /// The genesis time. - genesis_time: u64, - /// The slot interval. - slot_interval: u64, +pub struct OnlineBlobProvider { + /// The Beacon API client. + pub beacon_client: B, + /// Beacon Genesis time used for the time to slot conversion. + pub genesis_time: u64, + /// Slot interval used for the time to slot conversion. + pub slot_interval: u64, } -impl OnlineBlobProvider { +impl OnlineBlobProvider { /// Creates a new instance of the [OnlineBlobProvider]. /// /// The `genesis_time` and `slot_interval` arguments are _optional_ and the /// [OnlineBlobProvider] will attempt to load them dynamically at runtime if they are not /// provided. - pub async fn new_http(base: String) -> Result { - let inner = Client::new(); - let genesis = inner - .get(format!("{}/{}", base, GENESIS_METHOD)) - .send() - .await - .map_err(|_| BlobProviderError::Backend("Failed to fetch genesis".to_string()))?; - let genesis_time = genesis - .json::() - .await - .map_err(|e| BlobProviderError::Backend(e.to_string()))? - .data - .genesis_time; - let spec = inner - .get(format!("{}/{}", base, SPEC_METHOD)) - .send() + /// + /// ## Panics + /// Panics if the genesis time or slot interval cannot be loaded from the beacon client. + pub async fn init(beacon_client: B) -> Self { + let genesis_time = beacon_client + .beacon_genesis() .await - .map_err(|_| BlobProviderError::Backend("Failed to fetch config".to_string()))?; - let slot_interval = spec - .json::() + .map(|r| r.data.genesis_time) + .map_err(|e| BlobProviderError::Backend(e.to_string())) + .expect("Failed to load genesis time from beacon client"); + let slot_interval = beacon_client + .config_spec() .await - .map_err(|e| BlobProviderError::Backend(e.to_string()))? - .data - .seconds_per_slot; - Ok(Self { base, inner, genesis_time, slot_interval }) - } - - /// Fetches blob sidecars that were confirmed in the specified L1 block with the given indexed - /// hashes. Order of the returned sidecars is guaranteed to be that of the hashes. Blob data is - /// not checked for validity. - async fn beacon_blob_side_cars( - &self, - slot: u64, - hashes: &[IndexedBlobHash], - ) -> Result, reqwest::Error> { - let raw_response = self - .inner - .get(format!("{}/{}/{}", self.base, SIDECARS_METHOD_PREFIX, slot)) - .send() - .await?; - let raw_response = raw_response.json::().await?; - - // Filter the sidecars by the hashes, in-order. - let mut sidecars = Vec::with_capacity(hashes.len()); - hashes.iter().for_each(|hash| { - if let Some(sidecar) = - raw_response.data.iter().find(|sidecar| sidecar.index == hash.index) - { - sidecars.push(sidecar.clone()); - } - }); - - Ok(sidecars) + .map(|r| r.data.seconds_per_slot) + .map_err(|e| BlobProviderError::Backend(e.to_string())) + .expect("Failed to load slot interval from beacon client"); + Self { beacon_client, genesis_time, slot_interval } } /// Fetches blob sidecars for the given slot and blob hashes. @@ -142,7 +50,8 @@ impl OnlineBlobProvider { slot: u64, hashes: &[IndexedBlobHash], ) -> Result, BlobProviderError> { - self.beacon_blob_side_cars(slot, hashes) + self.beacon_client + .beacon_blob_side_cars(slot, hashes) .await .map_err(|e| BlobProviderError::Backend(e.to_string())) } @@ -184,23 +93,29 @@ impl OnlineBlobProvider { // Validate the correct number of blob sidecars were retrieved. if blob_hashes.len() != filtered.len() { - return Err(BlobProviderError::SidecarLengthMismatch(blob_hashes.len(), filtered.len())); + return Err(BlobProviderError::SidecarLengthMismatch( + blob_hashes.len(), + filtered.len(), + )); } Ok(filtered .into_iter() - .map(|s| BlobTransactionSidecarItem { - index: s.index, - blob: s.blob, - kzg_commitment: s.kzg_commitment, - kzg_proof: s.kzg_proof, + .map(|bs| BlobTransactionSidecarItem { + index: bs.index, + blob: bs.blob, + kzg_commitment: bs.kzg_commitment, + kzg_proof: bs.kzg_proof, }) .collect::>()) } } #[async_trait] -impl BlobProvider for OnlineBlobProvider { +impl BlobProvider for OnlineBlobProvider +where + B: BeaconClient + Send + Sync, +{ type Error = BlobProviderError; /// Fetches blob sidecars that were confirmed in the specified L1 block with the given indexed @@ -222,16 +137,43 @@ impl BlobProvider for OnlineBlobProvider { let hash = blob_hashes .get(i) .ok_or(BlobProviderError::Backend("Missing blob hash".to_string()))?; - match sidecar.verify_blob(&alloy_eips::eip4844::IndexedBlobHash { - hash: hash.hash, - index: hash.index, - }) { - Ok(_) => Ok(sidecar.blob), - Err(e) => Err(BlobProviderError::Backend(e.to_string())), - } + sidecar + .verify_blob(&IndexedBlobHash { hash: hash.hash, index: hash.index }) + .map(|_| sidecar.blob) + .map_err(|e| BlobProviderError::Backend(e.to_string())) }) .collect::>, BlobProviderError>>() .map_err(|e| BlobProviderError::Backend(e.to_string()))?; Ok(blobs) } } + +/// The minimal interface required to fetch sidecars from a remote blob store. +#[async_trait] +pub trait BlobSidecarProvider { + /// Fetches blob sidecars that were confirmed in the specified L1 block with the given indexed + /// hashes. Order of the returned sidecars is guaranteed to be that of the hashes. Blob data is + /// not checked for validity. + /// + /// Consensus specs: + async fn beacon_blob_side_cars( + &self, + slot: u64, + hashes: &[IndexedBlobHash], + ) -> Result, BlobProviderError>; +} + +/// Blanket implementation of the [BlobSidecarProvider] trait for all types that +/// implemend [BeaconClient], which has a superset of the required functionality. +#[async_trait] +impl BlobSidecarProvider for B { + async fn beacon_blob_side_cars( + &self, + slot: u64, + hashes: &[IndexedBlobHash], + ) -> Result, BlobProviderError> { + self.beacon_blob_side_cars(slot, hashes) + .await + .map_err(|e| BlobProviderError::Backend(e.to_string())) + } +} diff --git a/crates/providers-alloy/src/chain_provider.rs b/crates/providers-alloy/src/chain_provider.rs new file mode 100644 index 0000000000..c4a8314fd0 --- /dev/null +++ b/crates/providers-alloy/src/chain_provider.rs @@ -0,0 +1,201 @@ +//! Providers that use alloy provider types on the backend. + +use alloy_consensus::{Block, Header, Receipt, ReceiptWithBloom, TxEnvelope, TxType}; +use alloy_primitives::{Bytes, B256, U64}; +use alloy_provider::{Provider, RootProvider}; +use alloy_rlp::{Buf, Decodable}; +use alloy_transport::{RpcError, TransportErrorKind}; +use async_trait::async_trait; +use kona_derive::{ + errors::{PipelineError, PipelineErrorKind}, + traits::ChainProvider, +}; +use lru::LruCache; +use op_alloy_protocol::BlockInfo; +use std::{boxed::Box, num::NonZeroUsize, vec::Vec}; + +const CACHE_SIZE: usize = 16; + +/// The [AlloyChainProvider] is a concrete implementation of the [ChainProvider] trait, providing +/// data over Ethereum JSON-RPC using an alloy provider as the backend. +/// +/// **Note**: +/// This provider fetches data using the `debug_getRawHeader`, `debug_getRawReceipts`, and +/// `debug_getRawBlock` methods. The RPC must support this namespace. +#[derive(Debug, Clone)] +pub struct AlloyChainProvider { + /// The inner Ethereum JSON-RPC provider. + inner: RootProvider, + /// `header_by_hash` LRU cache. + header_by_hash_cache: LruCache, + /// `receipts_by_hash_cache` LRU cache. + receipts_by_hash_cache: LruCache>, + /// `block_info_and_transactions_by_hash` LRU cache. + block_info_and_transactions_by_hash_cache: LruCache)>, +} + +impl AlloyChainProvider { + /// Creates a new [AlloyChainProvider] with the given alloy provider. + pub fn new(inner: RootProvider) -> Self { + Self { + inner, + header_by_hash_cache: LruCache::new(NonZeroUsize::new(CACHE_SIZE).unwrap()), + receipts_by_hash_cache: LruCache::new(NonZeroUsize::new(CACHE_SIZE).unwrap()), + block_info_and_transactions_by_hash_cache: LruCache::new( + NonZeroUsize::new(CACHE_SIZE).unwrap(), + ), + } + } + + /// Creates a new [AlloyChainProvider] from the provided [reqwest::Url]. + pub fn new_http(url: reqwest::Url) -> Self { + let inner = RootProvider::new_http(url); + Self::new(inner) + } + + /// Returns the latest L2 block number. + pub async fn latest_block_number(&mut self) -> Result> { + self.inner.get_block_number().await + } + + /// Returns the chain ID. + pub async fn chain_id(&mut self) -> Result> { + self.inner.get_chain_id().await + } +} + +/// An error for the [AlloyChainProvider]. +#[allow(clippy::enum_variant_names)] +#[derive(Debug, thiserror::Error)] +pub enum AlloyChainProviderError { + /// Failed to fetch the raw header. + #[error("Failed to fetch raw header for hash {0}")] + RawHeaderFetch(B256), + /// Failed to decode the raw header. + #[error("Failed to decode raw header for hash {0}")] + RawHeaderDecoding(B256), + /// Failed to fetch the raw receipts. + #[error("Failed to fetch raw receipts for hash {0}")] + RawReceiptsFetch(B256), + /// Failed to decode the raw receipts. + #[error("Failed to decode raw receipts for hash {0}")] + RawReceiptsDecoding(B256), +} + +impl From for PipelineErrorKind { + fn from(e: AlloyChainProviderError) -> Self { + match e { + AlloyChainProviderError::RawHeaderFetch(_) => PipelineErrorKind::Temporary( + PipelineError::Provider("Failed to fetch raw header".to_string()), + ), + AlloyChainProviderError::RawHeaderDecoding(_) => PipelineErrorKind::Temporary( + PipelineError::Provider("Failed to decode raw header".to_string()), + ), + AlloyChainProviderError::RawReceiptsFetch(_) => PipelineErrorKind::Temporary( + PipelineError::Provider("Failed to fetch raw receipts".to_string()), + ), + AlloyChainProviderError::RawReceiptsDecoding(_) => PipelineErrorKind::Temporary( + PipelineError::Provider("Failed to decode raw receipts".to_string()), + ), + } + } +} + +#[async_trait] +impl ChainProvider for AlloyChainProvider { + type Error = AlloyChainProviderError; + + async fn header_by_hash(&mut self, hash: B256) -> Result { + if let Some(header) = self.header_by_hash_cache.get(&hash) { + return Ok(header.clone()); + } + + let raw_header: Bytes = self + .inner + .raw_request("debug_getRawHeader".into(), [hash]) + .await + .map_err(|_| AlloyChainProviderError::RawHeaderFetch(hash))?; + + let header = Header::decode(&mut raw_header.as_ref()) + .map_err(|_| AlloyChainProviderError::RawHeaderDecoding(hash))?; + self.header_by_hash_cache.put(hash, header.clone()); + + Ok(header) + } + + async fn block_info_by_number(&mut self, number: u64) -> Result { + let raw_header: Bytes = self + .inner + .raw_request("debug_getRawHeader".into(), [U64::from(number)]) + .await + .map_err(|_| AlloyChainProviderError::RawHeaderFetch(B256::default()))?; + let header = Header::decode(&mut raw_header.as_ref()) + .map_err(|_| AlloyChainProviderError::RawHeaderDecoding(B256::default()))?; + + let block_info = BlockInfo { + hash: header.hash_slow(), + number, + parent_hash: header.parent_hash, + timestamp: header.timestamp, + }; + Ok(block_info) + } + + async fn receipts_by_hash(&mut self, hash: B256) -> Result, Self::Error> { + if let Some(receipts) = self.receipts_by_hash_cache.get(&hash) { + return Ok(receipts.clone()); + } + + let raw_receipts: Vec = self + .inner + .raw_request("debug_getRawReceipts".into(), [hash]) + .await + .map_err(|_| AlloyChainProviderError::RawReceiptsFetch(hash))?; + + let receipts = raw_receipts + .iter() + .map(|r| { + let r = &mut r.as_ref(); + + // Skip the transaction type byte if it exists + if !r.is_empty() && r[0] <= TxType::Eip7702 as u8 { + r.advance(1); + } + + Ok(ReceiptWithBloom::decode(r) + .map_err(|_| AlloyChainProviderError::RawReceiptsDecoding(hash))? + .receipt) + }) + .collect::, Self::Error>>()?; + self.receipts_by_hash_cache.put(hash, receipts.clone()); + Ok(receipts) + } + + async fn block_info_and_transactions_by_hash( + &mut self, + hash: B256, + ) -> Result<(BlockInfo, Vec), Self::Error> { + if let Some(block_info_and_txs) = self.block_info_and_transactions_by_hash_cache.get(&hash) + { + return Ok(block_info_and_txs.clone()); + } + + let raw_block: Bytes = self + .inner + .raw_request("debug_getRawBlock".into(), [hash]) + .await + .map_err(|_| AlloyChainProviderError::RawHeaderFetch(hash))?; + let block: Block = Block::decode(&mut raw_block.as_ref()) + .map_err(|_| AlloyChainProviderError::RawHeaderDecoding(hash))?; + + let block_info = BlockInfo { + hash: block.header.hash_slow(), + number: block.header.number, + parent_hash: block.header.parent_hash, + timestamp: block.header.timestamp, + }; + self.block_info_and_transactions_by_hash_cache + .put(hash, (block_info, block.body.transactions.clone())); + Ok((block_info, block.body.transactions)) + } +} diff --git a/crates/providers-alloy/src/eigen_da_provider.rs b/crates/providers-alloy/src/eigen_da_provider.rs new file mode 100644 index 0000000000..c8c2f3db93 --- /dev/null +++ b/crates/providers-alloy/src/eigen_da_provider.rs @@ -0,0 +1,75 @@ +//! Contains an online implementation of the `EigenDaProvider` trait. + +use async_trait::async_trait; +use kona_derive::da::IEigenDA; +use kona_derive::errors::EigenDAProviderError; +use kona_derive::traits::EigenDAProvider; + +/// An online implementation of the [EigenDaProvider] +#[derive(Debug, Clone)] +pub struct OnlineEigenDaProvider { + /// The EigenDA Proxy client. + eigen_da_proxy_client: E, + /// The Mantle da indexer socket url. + pub mantle_da_indexer_socket: String, + /// Whether you use mantle da indexer. + pub mantle_da_indexer_enable: bool, +} + +impl OnlineEigenDaProvider { + pub const fn new( + eigen_da_proxy_client: E, + mantle_da_indexer_socket: String, + mantle_da_indexer_enable: bool, + ) -> Self { + Self { eigen_da_proxy_client, mantle_da_indexer_socket, mantle_da_indexer_enable } + } + + pub async fn get_blob(&self, commitment: &[u8]) -> Result, EigenDAProviderError> { + self.eigen_da_proxy_client + .retrieve_blob_with_commitment(commitment) + .await + .map_err(|e| EigenDAProviderError::Status(e.to_string())) + } +} + +#[async_trait] +impl EigenDAProvider for OnlineEigenDaProvider +where + E: IEigenDA + Send + Sync, +{ + type Error = EigenDAProviderError; + + async fn retrieve_blob_with_commitment( + &mut self, + commitment: &[u8], + blob_len: u32, + ) -> Result, Self::Error> { + self.eigen_da_proxy_client + .retrieve_blob_with_commitment(commitment) + .await + .map_err(|e| EigenDAProviderError::Status(e.to_string())) + } + + fn da_indexer_enable(&mut self) -> bool { + self.mantle_da_indexer_enable + } +} + +#[cfg(test)] +mod tests { + use super::*; + use alloy_primitives::hex; + use eigen_da::{EigenDaConfig}; + use crate::EigenDaProxy; + + #[tokio::test] + async fn test_get_blob() { + let commitment = hex!("010000f901d8f852f842a00dbbd22149b419a9a751c25065b58745f4216dc3ae4e9ad583306c395387b6a3a02673dfa25dd3095246eeffb639d3e11108a1ba75dd29b86c3a4200ed00210e4e820200cac480213701c401213710f90181830148ae81a5f873eba0c42bcd27bcd22ba55c4189a25d362343838cb75f57979baa0686ec5381a944c3820001826362832a79cba07263089b84cbb2963e4f50a930243c081ab14b01c0c92d57c3029590bd9dfc9200832a7a20a05419bc29ac025512311c14f23d9613e408448e47bb31f71614e1f82b6c63966cb9010074b13a3acaba35d3749063c19806c9a2f2004b318d55edd6cb5129d958807ea7ac09584a2c6ea029ed34c72f849862e4189928e90931e07093209016f5fc70a6c4a8c3237c25c4f236bb25c105fd7dbd6e4a00153c69c0757d8cbf02f966167ccae243412c20de1c3a38a50818dc7f9f3e02dcb3bc4e54800f2224b8c1eaa9955e41792fa0e401f2814ee209331126149c630c34e1b8e2f804955582022676e232d24d7784b496fc997d98db2849b1bfa8443b362723fc603da8de11704a1ef50414e11234496cfac67aebdd2faa24840ffe7f04506652b8a11a534b024a40bc7e99fee042336f425eb16e40e4267593415860204c9069723dbaca8cf2e596dc820001"); + let eigen_config = EigenDaConfig::default(); + let eigen_da_proxy = EigenDaProxy::new(eigen_config); + let eigen_da_provider = OnlineEigenDaProvider::new(eigen_da_proxy, "".to_string(), false); + let out = eigen_da_provider.get_blob(&commitment).await.unwrap(); + assert_eq!(out.len(), 11681) + } +} diff --git a/crates/providers-alloy/src/eigen_da_proxy.rs b/crates/providers-alloy/src/eigen_da_proxy.rs new file mode 100644 index 0000000000..8c4decce97 --- /dev/null +++ b/crates/providers-alloy/src/eigen_da_proxy.rs @@ -0,0 +1,102 @@ +use alloy_primitives::hex; +use alloy_rlp::Decodable; +use async_trait::async_trait; +use core::time::Duration; +use eigen_da::EigenDaConfig; +use kona_derive::da::IEigenDA; +use kona_derive::errors::EigenDAProxyError; +use reqwest::{Client, StatusCode}; +use tokio::time::timeout; +use Box; +use Vec; +use {format, vec}; +use {String, ToString}; + +pub const CERT_V0: u8 = 0; +pub const EIGEN_DA_COMMITMENT_TYPE: u8 = 0; +pub const GENERIC_COMMITMENT_TYPE: u8 = 1; + +pub const BYTES_PER_SYMBOL: usize = 32; + +/// An implementation of the [IEigenDA] trait. +#[derive(Debug, Clone)] +pub struct EigenDaProxy { + /// The url of EigenDA proxy service. + pub proxy_url: String, + /// The url of EigenDA disperser service. + pub disperser_url: String, + /// The http client of EigenDA disperser service. + pub disperse_client: Client, + /// The http client of EigenDA retrieve service. + pub retrieve_client: Client, + /// The timeout for request form retrieve service. + pub retrieve_blob_timeout: Duration, +} + +impl EigenDaProxy { + /// create a new EigenDA Proxy client. + pub fn new(cfg: EigenDaConfig) -> Self { + Self { + proxy_url: cfg.proxy_url, + disperser_url: cfg.disperse_url, + disperse_client: Client::builder() + .timeout(cfg.disperse_blob_timeout) + .build() + .expect("disperse client builder failed"), + retrieve_client: Client::builder() + .timeout(cfg.retrieve_blob_timeout) + .build() + .expect("retrieve client builder failed"), + retrieve_blob_timeout: cfg.retrieve_blob_timeout, + } + } +} + +#[async_trait] +impl IEigenDA for EigenDaProxy { + type Error = EigenDAProxyError; + + async fn retrieve_blob_with_commitment( + &self, + commitment: &[u8], + ) -> Result, Self::Error> { + let request_url = format!("{}/get/0x{}", self.proxy_url, hex::encode(&commitment)); + let req = self.retrieve_client.get(&request_url); + let response = timeout(self.retrieve_blob_timeout, req.send()) + .await + .map_err(|e| EigenDAProxyError::RetrieveBlobWithCommitment(e.to_string()))? + .map_err(|e| EigenDAProxyError::RetrieveBlobWithCommitment(e.to_string()))?; + if response.status() == StatusCode::NOT_FOUND { + return Err(EigenDAProxyError::RetrieveBlobWithCommitment("Blob not found".into())); + } else if response.status() != StatusCode::OK { + return Err(EigenDAProxyError::RetrieveBlobWithCommitment(format!( + "Failed to get preimage, status: {}", + response.status() + ))); + } + + let body = response + .bytes() + .await + .map_err(|e| EigenDAProxyError::RetrieveBlobWithCommitment(e.to_string()))?; + Ok(body.to_vec()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use alloy_primitives::hex; + use eigen_da::BlobInfo; + + #[test] + fn test_decode_blob_info() { + let commitment = hex!("010000f901d8f852f842a00dbbd22149b419a9a751c25065b58745f4216dc3ae4e9ad583306c395387b6a3a02673dfa25dd3095246eeffb639d3e11108a1ba75dd29b86c3a4200ed00210e4e820200cac480213701c401213710f90181830148ae81a5f873eba0c42bcd27bcd22ba55c4189a25d362343838cb75f57979baa0686ec5381a944c3820001826362832a79cba07263089b84cbb2963e4f50a930243c081ab14b01c0c92d57c3029590bd9dfc9200832a7a20a05419bc29ac025512311c14f23d9613e408448e47bb31f71614e1f82b6c63966cb9010074b13a3acaba35d3749063c19806c9a2f2004b318d55edd6cb5129d958807ea7ac09584a2c6ea029ed34c72f849862e4189928e90931e07093209016f5fc70a6c4a8c3237c25c4f236bb25c105fd7dbd6e4a00153c69c0757d8cbf02f966167ccae243412c20de1c3a38a50818dc7f9f3e02dcb3bc4e54800f2224b8c1eaa9955e41792fa0e401f2814ee209331126149c630c34e1b8e2f804955582022676e232d24d7784b496fc997d98db2849b1bfa8443b362723fc603da8de11704a1ef50414e11234496cfac67aebdd2faa24840ffe7f04506652b8a11a534b024a40bc7e99fee042336f425eb16e40e4267593415860204c9069723dbaca8cf2e596dc820001"); + let blob_info = BlobInfo::decode(*commitment).unwrap(); + let blob_header = blob_info.blob_header; + assert_eq!(blob_header.data_length, 512); + let blob_proof = blob_info.blob_verification_proof; + assert_eq!(blob_proof.blob_index, 165); + assert_eq!(blob_proof.batch_id, 84142); + } +} diff --git a/crates/providers-alloy/src/l2_chain_provider.rs b/crates/providers-alloy/src/l2_chain_provider.rs new file mode 100644 index 0000000000..0bea15458c --- /dev/null +++ b/crates/providers-alloy/src/l2_chain_provider.rs @@ -0,0 +1,130 @@ +//! Providers that use alloy provider types on the backend. + +use alloy_primitives::{Bytes, U64}; +use alloy_provider::{Provider, RootProvider}; +use alloy_rlp::Decodable; +use alloy_transport::{RpcError, TransportErrorKind}; +use async_trait::async_trait; +use kona_derive::{ + errors::{PipelineError, PipelineErrorKind}, + traits::L2ChainProvider, +}; +use op_alloy_consensus::OpBlock; +use op_alloy_genesis::{RollupConfig, SystemConfig}; +use op_alloy_protocol::{to_system_config, BatchValidationProvider, L2BlockInfo}; +use std::sync::Arc; + +/// The [AlloyL2ChainProvider] is a concrete implementation of the [L2ChainProvider] trait, +/// providing data over Ethereum JSON-RPC using an alloy provider as the backend. +/// +/// **Note**: +/// This provider fetches data using the `debug_getRawBlock` method. The RPC must support this +/// namespace. +#[derive(Debug, Clone)] +pub struct AlloyL2ChainProvider { + /// The inner Ethereum JSON-RPC provider. + inner: RootProvider, + /// The rollup configuration. + rollup_config: Arc, +} + +impl AlloyL2ChainProvider { + /// Creates a new [AlloyL2ChainProvider] with the given alloy provider and [RollupConfig]. + pub fn new(inner: RootProvider, rollup_config: Arc) -> Self { + Self { inner, rollup_config } + } + + /// Returns the chain ID. + pub async fn chain_id(&mut self) -> Result> { + self.inner.get_chain_id().await + } + + /// Returns the latest L2 block number. + pub async fn latest_block_number(&mut self) -> Result> { + self.inner.get_block_number().await + } + + /// Creates a new [AlloyL2ChainProvider] from the provided [reqwest::Url]. + pub fn new_http(url: reqwest::Url, rollup_config: Arc) -> Self { + let inner = RootProvider::new_http(url); + Self::new(inner, rollup_config) + } +} + +/// An error for the [AlloyL2ChainProvider]. +#[derive(Debug, thiserror::Error)] +pub enum AlloyL2ChainProviderError { + /// Failed to find a block. + #[error("Failed to fetch block {0}")] + BlockNotFound(u64), + /// Failed to construct [L2BlockInfo] from the block and genesis. + #[error("Failed to construct L2BlockInfo from block {0} and genesis")] + L2BlockInfoConstruction(u64), + /// Failed to decode an [OpBlock] from the raw block. + #[error("Failed to decode OpBlock from raw block {0}")] + OpBlockDecode(u64), + /// Failed to convert the block into a [SystemConfig]. + #[error("Failed to convert block {0} into SystemConfig")] + SystemConfigConversion(u64), +} + +impl From for PipelineErrorKind { + fn from(e: AlloyL2ChainProviderError) -> Self { + match e { + AlloyL2ChainProviderError::BlockNotFound(_) => { + PipelineErrorKind::Temporary(PipelineError::Provider("block not found".to_string())) + } + AlloyL2ChainProviderError::L2BlockInfoConstruction(_) => PipelineErrorKind::Temporary( + PipelineError::Provider("l2 block info construction failed".to_string()), + ), + AlloyL2ChainProviderError::OpBlockDecode(_) => PipelineErrorKind::Temporary( + PipelineError::Provider("op block decode failed".to_string()), + ), + AlloyL2ChainProviderError::SystemConfigConversion(_) => PipelineErrorKind::Temporary( + PipelineError::Provider("system config conversion failed".to_string()), + ), + } + } +} + +#[async_trait] +impl BatchValidationProvider for AlloyL2ChainProvider { + type Error = AlloyL2ChainProviderError; + + async fn l2_block_info_by_number(&mut self, number: u64) -> Result { + let block = self + .block_by_number(number) + .await + .map_err(|_| AlloyL2ChainProviderError::BlockNotFound(number))?; + L2BlockInfo::from_block_and_genesis(&block, &self.rollup_config.genesis) + .map_err(|_| AlloyL2ChainProviderError::L2BlockInfoConstruction(number)) + } + + async fn block_by_number(&mut self, number: u64) -> Result { + let raw_block: Bytes = self + .inner + .raw_request("debug_getRawBlock".into(), [U64::from(number)]) + .await + .map_err(|_| AlloyL2ChainProviderError::BlockNotFound(number))?; + OpBlock::decode(&mut raw_block.as_ref()) + .map_err(|_| AlloyL2ChainProviderError::OpBlockDecode(number)) + } +} + +#[async_trait] +impl L2ChainProvider for AlloyL2ChainProvider { + type Error = AlloyL2ChainProviderError; + + async fn system_config_by_number( + &mut self, + number: u64, + rollup_config: Arc, + ) -> Result::Error> { + let block = self + .block_by_number(number) + .await + .map_err(|_| AlloyL2ChainProviderError::BlockNotFound(number))?; + to_system_config(&block, &rollup_config) + .map_err(|_| AlloyL2ChainProviderError::SystemConfigConversion(number)) + } +} diff --git a/crates/providers-alloy/src/lib.rs b/crates/providers-alloy/src/lib.rs new file mode 100644 index 0000000000..8fa1911578 --- /dev/null +++ b/crates/providers-alloy/src/lib.rs @@ -0,0 +1,25 @@ +#![doc = include_str!("../README.md")] +#![doc(issue_tracker_base_url = "https://github.com/op-rs/hilo/issues/")] +#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] +#![cfg_attr(not(test), warn(unused_crate_dependencies))] + +mod beacon_client; +pub use beacon_client::{ + APIConfigResponse, APIGenesisResponse, BeaconClient, OnlineBeaconClient, ReducedConfigData, + ReducedGenesisData, +}; + +mod blobs; +pub use blobs::{BlobSidecarProvider, OnlineBlobProvider}; + +mod chain_provider; +pub use chain_provider::AlloyChainProvider; + +mod l2_chain_provider; + +pub use l2_chain_provider::AlloyL2ChainProvider; +mod eigen_da_provider; +mod eigen_da_proxy; +pub use eigen_da_proxy::EigenDaProxy; + +pub use eigen_da_provider::OnlineEigenDaProvider; diff --git a/justfile b/justfile index 2678f06ab7..a0cd370884 100644 --- a/justfile +++ b/justfile @@ -29,19 +29,18 @@ action-tests test_name='Test_ProgramAction' *args='': just monorepo if [ ! -d "monorepo/.devnet" ]; then - echo "Building devnet allocs for the monorepo" - (cd monorepo && make devnet-allocs) + echo "Building contract artifacts for the monorepo" + (cd monorepo/packages/contracts-bedrock && forge build) fi echo "Building host program for the native target" - just build-native --bin kona-host --release + just build-native --bin kona-host echo "Running action tests for the client program on the native target" - export KONA_HOST_PATH="{{justfile_directory()}}/target/release/kona-host" - export KONA_CLIENT_PATH="{{justfile_directory()}}/target/release-client-lto/kona" + export KONA_HOST_PATH="{{justfile_directory()}}/target/debug/kona-host" cd monorepo/op-e2e/actions/proofs && \ - gotestsum --format=short-verbose -- -run "{{test_name}}" {{args}} -count=1 ./... + gotestsum --format=testname -- -run "{{test_name}}" {{args}} -count=1 ./... # Clean the action tests directory clean-actions: @@ -64,7 +63,7 @@ fmt-native-check: # Lint the workspace lint-native: fmt-native-check lint-docs - cargo +nightly clippy --workspace --all --all-features --all-targets -- -D warnings + cargo clippy --workspace --all --all-features --all-targets -- -D warnings # Lint the workspace (mips arch). Currently, only the `kona-std-fpvm` crate is linted for the `cannon` target, as it is the only crate with architecture-specific code. lint-cannon: @@ -73,7 +72,7 @@ lint-cannon: --platform linux/amd64 \ -v `pwd`/:/workdir \ -w="/workdir" \ - ghcr.io/anton-rs/kona/cannon-builder:main cargo +nightly clippy -p kona-std-fpvm --all-features --target /mips-unknown-none.json -Zbuild-std=core,alloc -- -D warnings + ghcr.io/op-rs/kona/cannon-builder:main cargo clippy -p kona-std-fpvm --all-features -Zbuild-std=core,alloc -- -D warnings # Lint the workspace (risc-v arch). Currently, only the `kona-std-fpvm` crate is linted for the `asterisc` target, as it is the only crate with architecture-specific code. lint-asterisc: @@ -82,7 +81,7 @@ lint-asterisc: --platform linux/amd64 \ -v `pwd`/:/workdir \ -w="/workdir" \ - ghcr.io/anton-rs/kona/asterisc-builder:main cargo +nightly clippy -p kona-std-fpvm --all-features --target riscv64gc-unknown-linux-gnu -Zbuild-std=core,alloc -- -D warnings + ghcr.io/op-rs/kona/asterisc-builder:main cargo clippy -p kona-std-fpvm --all-features -Zbuild-std=core,alloc -- -D warnings # Lint the Rust documentation lint-docs: @@ -106,7 +105,7 @@ build-cannon *args='': --platform linux/amd64 \ -v `pwd`/:/workdir \ -w="/workdir" \ - ghcr.io/anton-rs/kona/cannon-builder:main cargo build --workspace -Zbuild-std=core,alloc $@ --exclude kona-host + ghcr.io/op-rs/kona/cannon-builder:main cargo build --workspace -Zbuild-std=core,alloc $@ --exclude kona-host --exclude kona-providers-alloy # Build for the `asterisc` target. Any crates that require the stdlib are excluded from the build for this target. build-asterisc *args='': @@ -115,38 +114,7 @@ build-asterisc *args='': --platform linux/amd64 \ -v `pwd`/:/workdir \ -w="/workdir" \ - ghcr.io/anton-rs/kona/asterisc-builder:main cargo build --workspace -Zbuild-std=core,alloc $@ --exclude kona-host - -# Build the `kona-client` prestate artifacts for the latest release. -build-client-prestate-asterisc-artifacts kona_tag asterisc_tag out='./prestate-artifacts-asterisc': - #!/bin/bash - PATH_TO_REPRO_BUILDER=./build/asterisc/asterisc-repro.dockerfile - OUTPUT_DIR={{out}} - - echo "Building kona-client prestate artifacts for the asterisc target. 🐚 Kona Tag: {{kona_tag}} | 🎇 Asterisc Tag: {{asterisc_tag}}" - docker build \ - -f $PATH_TO_REPRO_BUILDER \ - --output $OUTPUT_DIR \ - --build-arg CLIENT_TAG={{kona_tag}} \ - --build-arg ASTERISC_TAG={{asterisc_tag}} \ - --platform linux/amd64 \ - . - -# Build the `kona-client` prestate artifacts for the latest release, with an image containing the resulting -# binaries. -build-client-prestate-asterisc-image kona_tag asterisc_tag out='./prestate-artifacts-asterisc': - #!/bin/bash - PATH_TO_REPRO_BUILDER=./build/asterisc/asterisc-repro.dockerfile - OUTPUT_DIR={{out}} - - echo "Building kona-client prestate artifacts for the asterisc target. 🐚 Kona Tag: {{kona_tag}} | 🎇 Asterisc Tag: {{asterisc_tag}}" - docker build \ - -f $PATH_TO_REPRO_BUILDER \ - -t kona-fpp-asterisc:latest \ - --build-arg CLIENT_TAG={{kona_tag}} \ - --build-arg ASTERISC_TAG={{asterisc_tag}} \ - --platform linux/amd64 \ - . + ghcr.io/op-rs/kona/asterisc-builder:main cargo build --workspace -Zbuild-std=core,alloc $@ --exclude kona-host --exclude kona-providers-alloy # Clones and checks out the monorepo at the commit present in `.monorepo` monorepo: diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 0000000000..4cef0b738f --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "1.81"