diff --git a/.github/workflows/build-image.yml b/.github/workflows/build-image.yml index 6ea5796..e52c2fc 100644 --- a/.github/workflows/build-image.yml +++ b/.github/workflows/build-image.yml @@ -21,9 +21,6 @@ jobs: arch: - amd64 - arm64 - image: - - execution-witness-sentry - - zkboost-server include: - arch: amd64 runner: ubuntu-latest @@ -38,7 +35,7 @@ jobs: id: meta uses: docker/metadata-action@v5 with: - images: ghcr.io/${{ github.repository }}/${{ matrix.image }} + images: ghcr.io/${{ github.repository }}/zkboost-server tags: | type=sha,prefix=,format=short,enable=${{ github.ref == 'refs/heads/master' || github.event_name == 'pull_request' }} type=semver,pattern={{version}} @@ -53,16 +50,16 @@ jobs: username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Build ${{ matrix.image }} image + - name: Build zkboost-server image uses: docker/build-push-action@v6 with: context: . - file: docker/Dockerfile.${{ matrix.image }} + file: docker/Dockerfile push: ${{ github.event_name == 'push' }} platforms: linux/${{ matrix.arch }} - tags: ghcr.io/${{ github.repository }}/${{ matrix.image }}:${{ steps.meta.outputs.version }}-${{ matrix.arch }} - cache-from: type=gha,scope=${{ matrix.image }}-${{ matrix.arch }} - cache-to: type=gha,mode=max,scope=${{ matrix.image }}-${{ matrix.arch }} + tags: ghcr.io/${{ github.repository }}/zkboost-server:${{ steps.meta.outputs.version }}-${{ matrix.arch }} + cache-from: type=gha,scope=zkboost-server-${{ matrix.arch }} + cache-to: type=gha,mode=max,scope=zkboost-server-${{ matrix.arch }} merge-manifests: permissions: @@ -71,11 +68,6 @@ jobs: needs: build-images runs-on: ubuntu-latest if: github.event_name == 'push' - strategy: - matrix: - image: - - execution-witness-sentry - - zkboost-server steps: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 @@ -89,12 +81,12 @@ jobs: - name: Create and push multi-arch manifest run: | - docker buildx imagetools create -t ghcr.io/${{ github.repository }}/${{ matrix.image }}:${{ needs.build-images.outputs.version }} \ - ghcr.io/${{ github.repository }}/${{ matrix.image }}:${{ needs.build-images.outputs.version }}-amd64 \ - ghcr.io/${{ github.repository }}/${{ matrix.image }}:${{ needs.build-images.outputs.version }}-arm64 + docker buildx imagetools create -t ghcr.io/${{ github.repository }}/zkboost-server:${{ needs.build-images.outputs.version }} \ + ghcr.io/${{ github.repository }}/zkboost-server:${{ needs.build-images.outputs.version }}-amd64 \ + ghcr.io/${{ github.repository }}/zkboost-server:${{ needs.build-images.outputs.version }}-arm64 - name: Tag latest if: startsWith(github.ref, 'refs/tags/') run: | - docker buildx imagetools create -t ghcr.io/${{ github.repository }}/${{ matrix.image }}:latest \ - ghcr.io/${{ github.repository }}/${{ matrix.image }}:${{ needs.build-images.outputs.version }} + docker buildx imagetools create -t ghcr.io/${{ github.repository }}/zkboost-server:latest \ + ghcr.io/${{ github.repository }}/zkboost-server:${{ needs.build-images.outputs.version }} diff --git a/.github/workflows/integration-test.yml b/.github/workflows/integration-test.yml deleted file mode 100644 index 33774fa..0000000 --- a/.github/workflows/integration-test.yml +++ /dev/null @@ -1,92 +0,0 @@ -name: Integration tests - -on: - push: - branches: ["master"] - pull_request: - branches: ["master"] - -jobs: - build-stateless-validator: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - uses: dtolnay/rust-toolchain@v1 - with: - toolchain: 1.88 - components: clippy - - - name: Cache dependencies - uses: Swatinem/rust-cache@v2 - - - name: clippy - run: cargo clippy --package zkboost-server --test stateless_validator - - - name: Build stateless_validator - run: cargo build --package zkboost-server --test stateless_validator --release - - - name: Build zkboost-server - run: cargo build --package zkboost-server --bin zkboost-server --release - - - name: Find and copy binaries - run: | - BINARY=$(find target/release/deps -name "stateless_validator-*" -type f -executable | head -n 1) - mkdir -p artifacts - cp "$BINARY" artifacts/stateless_validator - cp target/release/zkboost-server artifacts/zkboost-server - - - name: Upload binaries - uses: actions/upload-artifact@v4 - with: - name: binaries - path: artifacts/ - - test-stateless-validator: - runs-on: ubuntu-latest - needs: build-stateless-validator - strategy: - fail-fast: false - matrix: - el: - - ethrex - - reth - zkvm: - - openvm - - pico - - risc0 - - sp1 - - zisk - exclude: - - el: ethrex - zkvm: openvm - - el: ethrex - zkvm: pico - steps: - - uses: actions/checkout@v4 - - - name: Free up disk space - run: bash .github/scripts/free-up-disk-space.sh - - - uses: dtolnay/rust-toolchain@v1 - with: - toolchain: 1.88 - - - name: Download binaries - uses: actions/download-artifact@v4 - with: - name: binaries - path: . - - - name: Run stateless_validator test - env: - RUST_LOG: info - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - chmod +x stateless_validator zkboost-server - ./stateless_validator \ - --zkboost-server-bin ./zkboost-server \ - --el ${{ matrix.el }} \ - --zkvm ${{ matrix.zkvm }} \ - --resource cpu \ - --skip-prove diff --git a/.github/workflows/unit-test.yml b/.github/workflows/unit-test.yml index 3ada843..679abcd 100644 --- a/.github/workflows/unit-test.yml +++ b/.github/workflows/unit-test.yml @@ -12,7 +12,7 @@ jobs: strategy: matrix: os: [ubuntu-latest] - toolchain: [1.88] + toolchain: [1.91] steps: - uses: actions/checkout@v4 diff --git a/Cargo.lock b/Cargo.lock index a4ba939..3146530 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,31 +4,15 @@ version = 4 [[package]] name = "addchain" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2e69442aa5628ea6951fa33e24efe8313f4321a91bd729fc2f75bdfc858570" +checksum = "2e33f6a175ec6a9e0aca777567f9ff7c3deefc255660df887e7fa3585e9801d8" dependencies = [ "num-bigint 0.3.3", "num-integer", "num-traits", ] -[[package]] -name = "adler2" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" - -[[package]] -name = "aead" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" -dependencies = [ - "crypto-common", - "generic-array", -] - [[package]] name = "aes" version = "0.8.4" @@ -40,20 +24,6 @@ dependencies = [ "cpufeatures", ] -[[package]] -name = "aes-gcm" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "831010a0f742e1209b3bcea8fab6a8e149051ba6099432c8cb2cc117dec3ead1" -dependencies = [ - "aead", - "aes", - "cipher", - "ctr", - "ghash", - "subtle", -] - [[package]] name = "ahash" version = "0.8.12" @@ -83,9 +53,9 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "alloy-chains" -version = "0.2.23" +version = "0.2.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35d744058a9daa51a8cf22a3009607498fcf82d3cf4c5444dd8056cdf651f471" +checksum = "90f374d3c6d729268bbe2d0e0ff992bb97898b2df756691a62ee1d5f0506bc39" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -96,36 +66,36 @@ dependencies = [ [[package]] name = "alloy-consensus" -version = "1.1.3" +version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e318e25fb719e747a7e8db1654170fc185024f3ed5b10f86c08d448a912f6e2" +checksum = "b0c0dc44157867da82c469c13186015b86abef209bf0e41625e4b68bac61d728" dependencies = [ "alloy-eips", "alloy-primitives", "alloy-rlp", "alloy-serde", - "alloy-trie 0.9.1", + "alloy-trie 0.9.4", "alloy-tx-macros", "auto_impl", "borsh", "c-kzg", - "derive_more 2.1.0", + "derive_more 2.1.1", "either", "k256", "once_cell", "rand 0.8.5", - "secp256k1 0.30.0", + "secp256k1", "serde", "serde_json", "serde_with", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] name = "alloy-consensus-any" -version = "1.1.3" +version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "364380a845193a317bcb7a5398fc86cdb66c47ebe010771dde05f6869bf9e64a" +checksum = "ba4cdb42df3871cd6b346d6a938ec2ba69a9a0f49d1f82714bc5c48349268434" dependencies = [ "alloy-consensus", "alloy-eips", @@ -145,7 +115,7 @@ dependencies = [ "alloy-rlp", "crc", "serde", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -172,65 +142,72 @@ dependencies = [ "k256", "serde", "serde_with", - "thiserror 2.0.17", + "thiserror 2.0.18", +] + +[[package]] +name = "alloy-eip7928" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8222b1d88f9a6d03be84b0f5e76bb60cd83991b43ad8ab6477f0e4a7809b98d" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "borsh", + "serde", ] [[package]] name = "alloy-eips" -version = "1.1.3" +version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c4d7c5839d9f3a467900c625416b24328450c65702eb3d8caff8813e4d1d33" +checksum = "b9f7ef09f21bd1e9cb8a686f168cb4a206646804567f0889eadb8dcc4c9288c8" dependencies = [ "alloy-eip2124", "alloy-eip2930", "alloy-eip7702", + "alloy-eip7928", "alloy-primitives", "alloy-rlp", "alloy-serde", "auto_impl", "borsh", "c-kzg", - "derive_more 2.1.0", + "derive_more 2.1.1", "either", - "ethereum_ssz", - "ethereum_ssz_derive", "serde", "serde_with", "sha2", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] name = "alloy-evm" -version = "0.24.2" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01be36ba6f5e6e62563b369e03ca529eac46aea50677f84655084b4750816574" +checksum = "7b99ba7b74a87176f31ee1cd26768f7155b0eeff61ed925f59b13085ffe5f891" dependencies = [ "alloy-consensus", "alloy-eips", "alloy-hardforks", "alloy-primitives", - "alloy-rpc-types-engine", - "alloy-rpc-types-eth", "alloy-sol-types", "auto_impl", - "derive_more 2.1.0", - "op-alloy", - "op-revm", + "derive_more 2.1.1", "revm", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] name = "alloy-genesis" -version = "1.1.3" +version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ba4b1be0988c11f0095a2380aa596e35533276b8fa6c9e06961bbfe0aebcac5" +checksum = "7c9cf3b99f46615fbf7dc1add0c96553abb7bf88fc9ec70dfbe7ad0b47ba7fe8" dependencies = [ "alloy-eips", "alloy-primitives", "alloy-serde", - "alloy-trie 0.9.1", + "alloy-trie 0.9.4", "borsh", "serde", "serde_with", @@ -238,9 +215,9 @@ dependencies = [ [[package]] name = "alloy-hardforks" -version = "0.4.5" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d9a33550fc21fd77a3f8b63e99969d17660eec8dcc50a95a80f7c9964f7680b" +checksum = "83ba208044232d14d4adbfa77e57d6329f51bc1acc21f5667bb7db72d88a0831" dependencies = [ "alloy-chains", "alloy-eip2124", @@ -251,9 +228,9 @@ dependencies = [ [[package]] name = "alloy-json-abi" -version = "1.4.1" +version = "1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5513d5e6bd1cba6bdcf5373470f559f320c05c8c59493b6e98912fbe6733943f" +checksum = "e9dbe713da0c737d9e5e387b0ba790eb98b14dd207fe53eef50e19a5a8ec3dac" dependencies = [ "alloy-primitives", "alloy-sol-type-parser", @@ -261,52 +238,11 @@ dependencies = [ "serde_json", ] -[[package]] -name = "alloy-json-rpc" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48562f9b4c4e1514cab54af16feaffc18194a38216bbd0c23004ec4667ad696b" -dependencies = [ - "alloy-primitives", - "alloy-sol-types", - "http 1.4.0", - "serde", - "serde_json", - "thiserror 2.0.17", - "tracing", -] - -[[package]] -name = "alloy-network" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12aeb37b6f2e61b93b1c3d34d01ee720207c76fe447e2a2c217e433ac75b17f5" -dependencies = [ - "alloy-consensus", - "alloy-consensus-any", - "alloy-eips", - "alloy-json-rpc", - "alloy-network-primitives", - "alloy-primitives", - "alloy-rpc-types-any", - "alloy-rpc-types-eth", - "alloy-serde", - "alloy-signer", - "alloy-sol-types", - "async-trait", - "auto_impl", - "derive_more 2.1.0", - "futures-utils-wasm", - "serde", - "serde_json", - "thiserror 2.0.17", -] - [[package]] name = "alloy-network-primitives" -version = "1.1.3" +version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abd29ace62872083e30929cd9b282d82723196d196db589f3ceda67edcc05552" +checksum = "42d6d15e069a8b11f56bef2eccbad2a873c6dd4d4c81d04dda29710f5ea52f04" dependencies = [ "alloy-consensus", "alloy-eips", @@ -317,99 +253,37 @@ dependencies = [ [[package]] name = "alloy-primitives" -version = "1.4.1" +version = "1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "355bf68a433e0fd7f7d33d5a9fc2583fde70bf5c530f63b80845f8da5505cf28" +checksum = "de3b431b4e72cd8bd0ec7a50b4be18e73dab74de0dba180eef171055e5d5926e" dependencies = [ "alloy-rlp", "bytes", "cfg-if 1.0.4", "const-hex", - "derive_more 2.1.0", + "derive_more 2.1.1", "foldhash 0.2.0", + "getrandom 0.4.2", "hashbrown 0.16.1", - "indexmap 2.12.1", + "indexmap 2.13.0", "itoa", "k256", "keccak-asm", "paste", "proptest", "rand 0.9.2", + "rapidhash", "ruint", - "rustc-hash 2.1.1", + "rustc-hash", "serde", "sha3", - "tiny-keccak", -] - -[[package]] -name = "alloy-provider" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b710636d7126e08003b8217e24c09f0cca0b46d62f650a841736891b1ed1fc1" -dependencies = [ - "alloy-chains", - "alloy-consensus", - "alloy-eips", - "alloy-json-rpc", - "alloy-network", - "alloy-network-primitives", - "alloy-primitives", - "alloy-pubsub", - "alloy-rpc-client", - "alloy-rpc-types-eth", - "alloy-signer", - "alloy-sol-types", - "alloy-transport", - "alloy-transport-http", - "alloy-transport-ws", - "async-stream", - "async-trait", - "auto_impl", - "dashmap", - "either", - "futures", - "futures-utils-wasm", - "lru 0.13.0", - "parking_lot", - "pin-project", - "reqwest", - "serde", - "serde_json", - "thiserror 2.0.17", - "tokio", - "tracing", - "url", - "wasmtimer", -] - -[[package]] -name = "alloy-pubsub" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23a0778833917a71a9e0065e0409bfc00cddef55ca962b3453472be38ebe7035" -dependencies = [ - "alloy-json-rpc", - "alloy-primitives", - "alloy-transport", - "auto_impl", - "bimap", - "futures", - "parking_lot", - "serde", - "serde_json", - "tokio", - "tokio-stream", - "tower", - "tracing", - "wasmtimer", ] [[package]] name = "alloy-rlp" -version = "0.3.12" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f70d83b765fdc080dbcd4f4db70d8d23fe4761f2f02ebfa9146b833900634b4" +checksum = "e93e50f64a77ad9c5470bf2ad0ca02f228da70c792a8f06634801e202579f35e" dependencies = [ "alloy-rlp-derive", "arrayvec", @@ -418,77 +292,40 @@ dependencies = [ [[package]] name = "alloy-rlp-derive" -version = "0.3.12" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64b728d511962dda67c1bc7ea7c03736ec275ed2cf4c35d9585298ac9ccf3b73" +checksum = "ce8849c74c9ca0f5a03da1c865e3eb6f768df816e67dd3721a398a8a7e398011" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", -] - -[[package]] -name = "alloy-rpc-client" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b587e63d8c4af437b0a7830dc12d24cb495e956cc8ecbf93e96d62c9cb55b13" -dependencies = [ - "alloy-json-rpc", - "alloy-primitives", - "alloy-pubsub", - "alloy-transport", - "alloy-transport-http", - "alloy-transport-ws", - "futures", - "pin-project", - "reqwest", - "serde", - "serde_json", - "tokio", - "tokio-stream", - "tower", - "tracing", - "url", - "wasmtimer", -] - -[[package]] -name = "alloy-rpc-types-any" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a63fb40ed24e4c92505f488f9dd256e2afaed17faa1b7a221086ebba74f4122" -dependencies = [ - "alloy-consensus-any", - "alloy-rpc-types-eth", - "alloy-serde", + "syn 2.0.117", ] [[package]] name = "alloy-rpc-types-debug" -version = "1.1.3" +version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4936f579d9d10eae01772b2ab3497f9d568684f05f26f8175e12f9a1a2babc33" +checksum = "e1b21e1ad18ff1b31ff1030e046462ab8168cf8894e6778cd805c8bdfe2bd649" dependencies = [ "alloy-primitives", - "derive_more 2.1.0", + "derive_more 2.1.1", "serde", "serde_with", ] [[package]] name = "alloy-rpc-types-engine" -version = "1.1.3" +version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c60bdce3be295924122732b7ecd0b2495ce4790bedc5370ca7019c08ad3f26e" +checksum = "e4ac61f03f1edabccde1c687b5b25fff28f183afee64eaa2e767def3929e4457" dependencies = [ "alloy-consensus", "alloy-eips", "alloy-primitives", "alloy-rlp", "alloy-serde", - "derive_more 2.1.0", - "ethereum_ssz", - "ethereum_ssz_derive", + "derive_more 2.1.1", + "jsonwebtoken", "rand 0.8.5", "serde", "strum", @@ -496,9 +333,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-eth" -version = "1.1.3" +version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9eae0c7c40da20684548cbc8577b6b7447f7bf4ddbac363df95e3da220e41e72" +checksum = "9b2dc411f13092f237d2bf6918caf80977fc2f51485f9b90cb2a2f956912c8c9" dependencies = [ "alloy-consensus", "alloy-consensus-any", @@ -512,72 +349,57 @@ dependencies = [ "serde", "serde_json", "serde_with", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] name = "alloy-serde" -version = "1.1.3" +version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0df1987ed0ff2d0159d76b52e7ddfc4e4fbddacc54d2fbee765e0d14d7c01b5" +checksum = "e2ce1e0dbf7720eee747700e300c99aac01b1a95bb93f493a01e78ee28bb1a37" dependencies = [ "alloy-primitives", "serde", "serde_json", ] -[[package]] -name = "alloy-signer" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "389372d6ae4d62b88c8dca8238e4f7d0a7727b66029eb8a5516a908a03161450" -dependencies = [ - "alloy-primitives", - "async-trait", - "auto_impl", - "either", - "elliptic-curve", - "k256", - "thiserror 2.0.17", -] - [[package]] name = "alloy-sol-macro" -version = "1.4.1" +version = "1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3ce480400051b5217f19d6e9a82d9010cdde20f1ae9c00d53591e4a1afbb312" +checksum = "ab81bab693da9bb79f7a95b64b394718259fdd7e41dceeced4cad57cb71c4f6a" dependencies = [ "alloy-sol-macro-expander", "alloy-sol-macro-input", "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] name = "alloy-sol-macro-expander" -version = "1.4.1" +version = "1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d792e205ed3b72f795a8044c52877d2e6b6e9b1d13f431478121d8d4eaa9028" +checksum = "489f1620bb7e2483fb5819ed01ab6edc1d2f93939dce35a5695085a1afd1d699" dependencies = [ "alloy-sol-macro-input", "const-hex", "heck", - "indexmap 2.12.1", + "indexmap 2.13.0", "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.111", + "sha3", + "syn 2.0.117", "syn-solidity", - "tiny-keccak", ] [[package]] name = "alloy-sol-macro-input" -version = "1.4.1" +version = "1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bd1247a8f90b465ef3f1207627547ec16940c35597875cdc09c49d58b19693c" +checksum = "56cef806ad22d4392c5fc83cf8f2089f988eb99c7067b4e0c6f1971fc1cca318" dependencies = [ "const-hex", "dunce", @@ -585,15 +407,15 @@ dependencies = [ "macro-string", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", "syn-solidity", ] [[package]] name = "alloy-sol-type-parser" -version = "1.5.2" +version = "1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af67a0b0dcebe14244fc92002cd8d96ecbf65db4639d479f5fcd5805755a4c27" +checksum = "a6df77fea9d6a2a75c0ef8d2acbdfd92286cc599983d3175ccdc170d3433d249" dependencies = [ "serde", "winnow", @@ -601,9 +423,9 @@ dependencies = [ [[package]] name = "alloy-sol-types" -version = "1.4.1" +version = "1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70319350969a3af119da6fb3e9bddb1bce66c9ea933600cb297c8b1850ad2a3c" +checksum = "64612d29379782a5dde6f4b6570d9c756d734d760c0c94c254d361e678a6591f" dependencies = [ "alloy-json-abi", "alloy-primitives", @@ -611,61 +433,6 @@ dependencies = [ "serde", ] -[[package]] -name = "alloy-transport" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f01c27edb3c0926919586a231d99e06284f9239da6044b5682033ef781e1cc62" -dependencies = [ - "alloy-json-rpc", - "auto_impl", - "base64 0.22.1", - "derive_more 2.1.0", - "futures", - "futures-utils-wasm", - "parking_lot", - "serde", - "serde_json", - "thiserror 2.0.17", - "tokio", - "tower", - "tracing", - "url", - "wasmtimer", -] - -[[package]] -name = "alloy-transport-http" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2cc57657fd3249fc8324cbbc8edbb7d5114af5fbc7c6c32dff944d6b5922f400" -dependencies = [ - "alloy-json-rpc", - "alloy-transport", - "reqwest", - "serde_json", - "tower", - "tracing", - "url", -] - -[[package]] -name = "alloy-transport-ws" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e81effa6a2db6b2152eefb244b4aa6334b1c42819d0eca8d5a91826ec7a9fdba" -dependencies = [ - "alloy-pubsub", - "alloy-transport", - "futures", - "http 1.4.0", - "serde_json", - "tokio", - "tokio-tungstenite 0.26.2", - "tracing", - "ws_stream_wasm", -] - [[package]] name = "alloy-trie" version = "0.8.1" @@ -675,7 +442,7 @@ dependencies = [ "alloy-primitives", "alloy-rlp", "arrayvec", - "derive_more 2.1.0", + "derive_more 2.1.1", "nybbles 0.3.4", "smallvec", "tracing", @@ -683,30 +450,31 @@ dependencies = [ [[package]] name = "alloy-trie" -version = "0.9.1" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3412d52bb97c6c6cc27ccc28d4e6e8cf605469101193b50b0bd5813b1f990b5" +checksum = "4d7fd448ab0a017de542de1dcca7a58e7019fe0e7a34ed3f9543ebddf6aceffa" dependencies = [ "alloy-primitives", "alloy-rlp", "arrayvec", - "derive_more 2.1.0", - "nybbles 0.4.6", + "derive_more 2.1.1", + "nybbles 0.4.8", "serde", "smallvec", + "thiserror 2.0.18", "tracing", ] [[package]] name = "alloy-tx-macros" -version = "1.1.3" +version = "1.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "333544408503f42d7d3792bfc0f7218b643d968a03d2c0ed383ae558fb4a76d0" +checksum = "6fa0c53e8c1e1ef4d01066b01c737fb62fc9397ab52c6e7bb5669f97d281b9bc" dependencies = [ "darling 0.21.3", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] @@ -770,9 +538,18 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.100" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "archery" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" +checksum = "0a8da9bc4c4053ee067669762bcaeea6e241841295a2b6c948312dad6ef4cc02" +dependencies = [ + "static_assertions", +] [[package]] name = "ark-bls12-381" @@ -794,7 +571,6 @@ checksum = "d69eab57e8d2663efa5c63135b2af4f396d66424f88954c21104125ab6b3e6bc" dependencies = [ "ark-ec", "ark-ff 0.5.0", - "ark-r1cs-std", "ark-std 0.5.0", ] @@ -904,7 +680,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" dependencies = [ "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] @@ -942,7 +718,7 @@ dependencies = [ "num-traits", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] @@ -960,35 +736,6 @@ dependencies = [ "hashbrown 0.15.5", ] -[[package]] -name = "ark-r1cs-std" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "941551ef1df4c7a401de7068758db6503598e6f01850bdb2cfdb614a1f9dbea1" -dependencies = [ - "ark-ec", - "ark-ff 0.5.0", - "ark-relations", - "ark-std 0.5.0", - "educe", - "num-bigint 0.4.6", - "num-integer", - "num-traits", - "tracing", -] - -[[package]] -name = "ark-relations" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec46ddc93e7af44bcab5230937635b06fb5744464dd6a7e7b083e80ebd274384" -dependencies = [ - "ark-ff 0.5.0", - "ark-std 0.5.0", - "tracing", - "tracing-subscriber 0.2.25", -] - [[package]] name = "ark-serialize" version = "0.3.0" @@ -1031,7 +778,7 @@ checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] @@ -1079,20 +826,11 @@ dependencies = [ "serde", ] -[[package]] -name = "ash" -version = "0.38.0+1.3.281" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bb44936d800fea8f016d7f2311c6a4f97aebd5dc86f09906139ec848cf3a46f" -dependencies = [ - "libloading", -] - [[package]] name = "assert_cmd" -version = "2.1.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c5bcfa8749ac45dd12cb11055aeeb6b27a3895560d60d71e3c23bf979e60514" +checksum = "9a686bbee5efb88a82df0621b236e74d925f470e5445d3220a5648b892ec99c9" dependencies = [ "anstyle", "bstr", @@ -1122,7 +860,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] @@ -1133,18 +871,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", -] - -[[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", + "syn 2.0.117", ] [[package]] @@ -1171,7 +898,7 @@ checksum = "ffdcb70bdbc4d478427380519163274ac86e52916e10f0a8889adf0f96d3fee7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] @@ -1182,9 +909,9 @@ checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "aws-lc-rs" -version = "1.13.3" +version = "1.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c953fe1ba023e6b7730c0d4b031d06f267f23a46167dcbd40316644b10a17ba" +checksum = "94bffc006df10ac2a68c83692d734a465f8ee6c5b384d8545a636f81d858f4bf" dependencies = [ "aws-lc-sys", "zeroize", @@ -1192,11 +919,10 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.30.0" +version = "0.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbfd150b5dbdb988bcc8fb1fe787eb6b7ee6180ca24da683b61ea5405f3d43ff" +checksum = "4321e568ed89bb5a7d291a7f37997c2c0df89809d7b6d12062c81ddb54aa782e" dependencies = [ - "bindgen", "cc", "cmake", "dunce", @@ -1205,20 +931,20 @@ dependencies = [ [[package]] name = "axum" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b098575ebe77cb6d14fc7f32749631a6e44edbef6b796f89b020e99ba20d425" +checksum = "8b52af3cb4058c895d37317bb27508dccc8e5f2d39454016b297bf4a400597b8" dependencies = [ "axum-core", "axum-macros", - "base64 0.22.1", + "base64", "bytes", "form_urlencoded", "futures-util", - "http 1.4.0", - "http-body 1.0.1", + "http", + "http-body", "http-body-util", - "hyper 1.8.1", + "hyper", "hyper-util", "itoa", "matchit", @@ -1233,7 +959,7 @@ dependencies = [ "sha1", "sync_wrapper", "tokio", - "tokio-tungstenite 0.28.0", + "tokio-tungstenite", "tower", "tower-layer", "tower-service", @@ -1242,14 +968,14 @@ dependencies = [ [[package]] name = "axum-core" -version = "0.5.5" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59446ce19cd142f8833f856eb31f3eb097812d1479ab224f54d72428ca21ea22" +checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1" dependencies = [ "bytes", "futures-core", - "http 1.4.0", - "http-body 1.0.1", + "http", + "http-body", "http-body-util", "mime", "pin-project-lite", @@ -1270,8 +996,8 @@ dependencies = [ "bytes", "futures-util", "headers", - "http 1.4.0", - "http-body 1.0.1", + "http", + "http-body", "http-body-util", "mime", "pin-project-lite", @@ -1290,27 +1016,15 @@ checksum = "604fde5e028fea851ce1d8570bbdc034bec850d157f7569d10f347d06808c05c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] -[[package]] -name = "az" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be5eb007b7cacc6c660343e96f650fedf4b5a77512399eb952ca6642cf8d13f7" - [[package]] name = "base16ct" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" -[[package]] -name = "base64" -version = "0.21.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" - [[package]] name = "base64" version = "0.22.1" @@ -1319,15 +1033,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e050f626429857a27ddccb31e0aca21356bfa709c04041aefddac081a8f068a" - -[[package]] -name = "bimap" -version = "0.6.3" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "230c5f1ca6a325a32553f8640d31ac9b49f2411e901e427570154868b46da4f7" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" [[package]] name = "bincode" @@ -1349,33 +1057,10 @@ dependencies = [ ] [[package]] -name = "bindgen" -version = "0.69.5" +name = "bit-set" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271383c67ccabffb7381723dea0672a673f292304fcb45c01cc648c7a8d58088" -dependencies = [ - "bitflags", - "cexpr", - "clang-sys", - "itertools 0.12.1", - "lazy_static", - "lazycell", - "log", - "prettyplease", - "proc-macro2", - "quote", - "regex", - "rustc-hash 1.1.0", - "shlex", - "syn 2.0.111", - "which", -] - -[[package]] -name = "bit-set" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" dependencies = [ "bit-vec", ] @@ -1404,9 +1089,9 @@ dependencies = [ [[package]] name = "bitflags" -version = "2.10.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" dependencies = [ "serde_core", ] @@ -1425,23 +1110,38 @@ dependencies = [ ] [[package]] -name = "blake3" -version = "1.8.2" +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "blake2b_simd" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3888aaa89e4b2a40fca9848e400f6a658a5a3978de7be858e209cafa8be9a4a0" +checksum = "b79834656f71332577234b50bfc009996f7449e0c056884e6a02492ded0ca2f3" dependencies = [ "arrayref", "arrayvec", - "cc", - "cfg-if 1.0.4", "constant_time_eq", ] [[package]] -name = "block" -version = "0.1.6" +name = "blake3" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" +checksum = "2468ef7d57b3fb7e16b576e8377cdbde2320c60e1491e961d11da40fc4f02a2d" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if 1.0.4", + "constant_time_eq", + "cpufeatures", +] [[package]] name = "block-buffer" @@ -1452,15 +1152,47 @@ dependencies = [ "generic-array", ] +[[package]] +name = "bls" +version = "0.2.0" +source = "git+https://github.com/sigp/lighthouse?branch=unstable#9c4715c251ea19b2cc4c7688916b5cddfa2b1778" +dependencies = [ + "alloy-primitives", + "blst", + "ethereum_hashing 0.8.0", + "ethereum_serde_utils", + "ethereum_ssz 0.10.1", + "fixed_bytes", + "hex", + "rand 0.9.2", + "safe_arith", + "serde", + "tree_hash 0.12.1", + "zeroize", +] + +[[package]] +name = "bls12_381" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3c196a77437e7cc2fb515ce413a6401291578b5afc8ecb29a3c7ab957f05941" +dependencies = [ + "ff 0.12.1", + "group 0.12.1", + "pairing 0.22.0", + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "bls12_381" version = "0.8.0" source = "git+https://github.com/lambdaclass/bls12_381?branch=expose-fp-struct#219174187bd78154cec35b0809799fc2c991a579" dependencies = [ "digest 0.10.7", - "ff", - "group", - "pairing", + "ff 0.13.1", + "group 0.13.0", + "pairing 0.23.0", "rand_core 0.6.4", "subtle", ] @@ -1477,6 +1209,22 @@ dependencies = [ "zeroize", ] +[[package]] +name = "blstrs" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a8a8ed6fefbeef4a8c7b460e4110e12c5e22a5b7cf32621aae6ad650c4dcf29" +dependencies = [ + "blst", + "byte-slice-cast", + "ff 0.13.1", + "group 0.13.0", + "pairing 0.23.0", + "rand_core 0.6.4", + "serde", + "subtle", +] + [[package]] name = "borsh" version = "1.6.0" @@ -1497,7 +1245,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] @@ -1513,9 +1261,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.19.0" +version = "3.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" [[package]] name = "byte-slice-cast" @@ -1543,28 +1291,14 @@ checksum = "89385e82b5d1821d2219e0b095efa2cc1f246cbf99080f3be46a1a85c0d392d9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] name = "bytemuck" -version = "1.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" -dependencies = [ - "bytemuck_derive", -] - -[[package]] -name = "bytemuck_derive" -version = "1.10.2" +version = "1.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.111", -] +checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" [[package]] name = "byteorder" @@ -1574,18 +1308,18 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" dependencies = [ "serde", ] [[package]] name = "c-kzg" -version = "2.1.5" +version = "2.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e00bf4b112b07b505472dbefd19e37e53307e2bfed5a79e0cc161d58ccd0e687" +checksum = "1a0f582957c24870b7bfd12bf562c40b4734b533cafbaf8ded31d6d85f462c01" dependencies = [ "blst", "cc", @@ -1598,56 +1332,22 @@ dependencies = [ [[package]] name = "camino" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "276a59bf2b2c967788139340c9f0c5b12d7fd6630315c15c217e559de85d2609" -dependencies = [ - "serde_core", -] - -[[package]] -name = "cargo-platform" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo_metadata" -version = "0.19.2" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd5eb614ed4c27c5d706420e4320fbe3216ab31fa1c33cd8246ac36dae4479ba" -dependencies = [ - "camino", - "cargo-platform", - "semver 1.0.27", - "serde", - "serde_json", - "thiserror 2.0.17", -] +checksum = "e629a66d692cb9ff1a1c664e41771b3dcaf961985a9774c0eb0bd1b51cf60a48" [[package]] name = "cc" -version = "1.2.15" +version = "1.2.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c736e259eea577f443d5c86c304f9f4ae0295c43f3ba05c21f1d66b5f06001af" +checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" dependencies = [ + "find-msvc-tools", "jobserver", "libc", "shlex", ] -[[package]] -name = "cexpr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" -dependencies = [ - "nom", -] - [[package]] name = "cfg-if" version = "0.1.10" @@ -1668,14 +1368,14 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chrono" -version = "0.4.42" +version = "0.4.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" +checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" dependencies = [ "iana-time-zone", "num-traits", "serde", - "windows-link 0.2.1", + "windows-link", ] [[package]] @@ -1688,22 +1388,11 @@ dependencies = [ "inout", ] -[[package]] -name = "clang-sys" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" -dependencies = [ - "glob", - "libc", - "libloading", -] - [[package]] name = "clap" -version = "4.5.53" +version = "4.5.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8" +checksum = "2797f34da339ce31042b27d23607e051786132987f595b02ba4f6a6dffb7030a" dependencies = [ "clap_builder", "clap_derive", @@ -1711,9 +1400,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.53" +version = "4.5.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76b5d13eaa18c901fd2f7fca939fefe3a0727a953561fefdf3b2922b8569d00" +checksum = "24a241312cea5059b13574bb9b3861cabf758b879c15190b37b6d6fd63ab6876" dependencies = [ "anstream", "anstyle", @@ -1723,47 +1412,56 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.49" +version = "4.5.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" +checksum = "a92793da1a46a5f2a02a6f4c46c6496b28c43638adea8306fcb0caa1634f24e5" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] name = "clap_lex" -version = "0.7.6" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" +checksum = "3a822ea5bc7590f9d40f1ba12c0dc3c2760f3482c6984db1573ad11031420831" [[package]] name = "cmake" -version = "0.1.54" +version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" +checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d" dependencies = [ "cc", ] [[package]] -name = "codespan-reporting" -version = "0.12.0" +name = "colorchoice" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + +[[package]] +name = "compare_fields" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe6d2e5af09e8c8ad56c969f2157a3d4238cebc7c55f0a517728c38f7b200f81" +checksum = "f6f45d0b4d61b582303179fb7a1a142bc9d647b7583db3b0d5f25a21d286fab9" dependencies = [ - "serde", - "termcolor", - "unicode-width", + "compare_fields_derive", + "itertools 0.14.0", ] [[package]] -name = "colorchoice" -version = "1.0.4" +name = "compare_fields_derive" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" +checksum = "92ff1dbbda10d495b2c92749c002b2025e0be98f42d1741ecc9ff820d2f04dce" +dependencies = [ + "quote", + "syn 2.0.117", +] [[package]] name = "concat-kdf" @@ -1776,9 +1474,9 @@ dependencies = [ [[package]] name = "const-hex" -version = "1.17.0" +version = "1.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bb320cac8a0750d7f25280aa97b09c26edfe161164238ecbbb31092b079e735" +checksum = "531185e432bb31db1ecda541e9e7ab21468d4d844ad7505e0546a49b4945d49b" dependencies = [ "cfg-if 1.0.4", "cpufeatures", @@ -1814,9 +1512,29 @@ dependencies = [ [[package]] name = "constant_time_eq" -version = "0.3.1" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" + +[[package]] +name = "context_deserialize" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" +checksum = "4c523eea4af094b5970c321f4604abc42c5549d3cbae332e98325403fbbdbf70" +dependencies = [ + "context_deserialize_derive", + "serde", +] + +[[package]] +name = "context_deserialize_derive" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b7bf98c48ffa511b14bb3c76202c24a8742cea1efa9570391c5d41373419a09" +dependencies = [ + "quote", + "syn 2.0.117", +] [[package]] name = "convert_case" @@ -1862,17 +1580,6 @@ version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" -[[package]] -name = "core-graphics-types" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d44a101f213f6c4cdc1853d4b78aef6db6bdfa3468798cc1d9912f4735013eb" -dependencies = [ - "bitflags", - "core-foundation 0.10.1", - "libc", -] - [[package]] name = "cpufeatures" version = "0.2.17" @@ -2065,7 +1772,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ "generic-array", - "rand_core 0.6.4", "typenum", ] @@ -2084,33 +1790,6 @@ dependencies = [ "cipher", ] -[[package]] -name = "curve25519-dalek" -version = "4.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" -dependencies = [ - "cfg-if 1.0.4", - "cpufeatures", - "curve25519-dalek-derive", - "digest 0.10.7", - "fiat-crypto", - "rustc_version 0.4.1", - "subtle", - "zeroize", -] - -[[package]] -name = "curve25519-dalek-derive" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.111", -] - [[package]] name = "darling" version = "0.20.11" @@ -2131,6 +1810,16 @@ dependencies = [ "darling_macro 0.21.3", ] +[[package]] +name = "darling" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" +dependencies = [ + "darling_core 0.23.0", + "darling_macro 0.23.0", +] + [[package]] name = "darling_core" version = "0.20.11" @@ -2142,7 +1831,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] @@ -2157,7 +1846,20 @@ dependencies = [ "quote", "serde", "strsim", - "syn 2.0.111", + "syn 2.0.117", +] + +[[package]] +name = "darling_core" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" +dependencies = [ + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.117", ] [[package]] @@ -2168,7 +1870,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core 0.20.11", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] @@ -2179,28 +1881,25 @@ checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" dependencies = [ "darling_core 0.21.3", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] -name = "dashmap" -version = "6.1.0" +name = "darling_macro" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" +checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" dependencies = [ - "cfg-if 1.0.4", - "crossbeam-utils 0.8.21", - "hashbrown 0.14.5", - "lock_api", - "once_cell", - "parking_lot_core", + "darling_core 0.23.0", + "quote", + "syn 2.0.117", ] [[package]] name = "data-encoding" -version = "2.9.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" +checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" [[package]] name = "datatest-stable" @@ -2214,17 +1913,6 @@ dependencies = [ "walkdir", ] -[[package]] -name = "delay_map" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88e365f083a5cb5972d50ce8b1b2c9f125dc5ec0f50c0248cfb568ae59efcf0b" -dependencies = [ - "futures", - "tokio", - "tokio-util", -] - [[package]] name = "der" version = "0.7.10" @@ -2238,9 +1926,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.5.5" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" dependencies = [ "powerfmt", "serde_core", @@ -2265,7 +1953,7 @@ checksum = "ef941ded77d15ca19b40374869ac6000af1c9f2a4c0f3d4c70926287e6364a8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] @@ -2279,11 +1967,11 @@ dependencies = [ [[package]] name = "derive_more" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10b768e943bed7bf2cab53df09f4bc34bfd217cdb57d971e769874c9a6710618" +checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" dependencies = [ - "derive_more-impl 2.1.0", + "derive_more-impl 2.1.1", ] [[package]] @@ -2295,21 +1983,21 @@ dependencies = [ "convert_case 0.6.0", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", "unicode-xid", ] [[package]] name = "derive_more-impl" -version = "2.1.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d286bfdaf75e988b4a78e013ecd79c581e06399ab53fbacd2d916c2f904f30b" +checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" dependencies = [ "convert_case 0.10.0", "proc-macro2", "quote", "rustc_version 0.4.1", - "syn 2.0.111", + "syn 2.0.117", "unicode-xid", ] @@ -2340,37 +2028,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "discv5" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f170f4f6ed0e1df52bf43b403899f0081917ecf1500bfe312505cc3b515a8899" -dependencies = [ - "aes", - "aes-gcm", - "alloy-rlp", - "arrayvec", - "ctr", - "delay_map", - "enr", - "fnv", - "futures", - "hashlink", - "hex", - "hkdf", - "lazy_static", - "lru 0.12.5", - "more-asserts", - "parking_lot", - "rand 0.8.5", - "smallvec", - "socket2 0.5.10", - "tokio", - "tracing", - "uint 0.10.0", - "zeroize", -] - [[package]] name = "displaydoc" version = "0.2.5" @@ -2379,16 +2036,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", -] - -[[package]] -name = "document-features" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" -dependencies = [ - "litrs", + "syn 2.0.117", ] [[package]] @@ -2419,51 +2067,137 @@ dependencies = [ ] [[package]] -name = "ed25519" -version = "2.2.3" +name = "educe" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" dependencies = [ - "pkcs8", - "signature", + "enum-ordinalize", + "proc-macro2", + "quote", + "syn 2.0.117", ] [[package]] -name = "ed25519-dalek" -version = "2.2.0" +name = "eip4844" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" +checksum = "82ab45fc63db6bbe5c3eb7c79303b2aff7ee529c991b2111c46879d1ea38407e" dependencies = [ - "curve25519-dalek", - "ed25519", - "rand_core 0.6.4", + "ekzg-bls12-381", + "ekzg-maybe-rayon", + "ekzg-polynomial", + "ekzg-serialization", + "ekzg-single-open", + "ekzg-trusted-setup", + "hex", + "itertools 0.14.0", "serde", + "serde_json", "sha2", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +dependencies = [ + "serde", +] + +[[package]] +name = "ekzg-bls12-381" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05c599a59deba6188afd9f783507e4d89efc997f0fa340a758f0d0992b322416" +dependencies = [ + "blst", + "blstrs", + "ff 0.13.1", + "group 0.13.0", + "pairing 0.23.0", "subtle", - "zeroize", ] [[package]] -name = "educe" -version = "0.6.0" +name = "ekzg-erasure-codes" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" +checksum = "8474a41a30ddd2b651798b1aa9ce92011207c3667186fe9044184683250109e7" dependencies = [ - "enum-ordinalize", - "proc-macro2", - "quote", - "syn 2.0.111", + "ekzg-bls12-381", + "ekzg-polynomial", ] [[package]] -name = "either" -version = "1.15.0" +name = "ekzg-maybe-rayon" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +checksum = "9cf94d1385185c1f7caef4973be49702c7d9ffdeaf832d126dbb9ed6efe09d40" + +[[package]] +name = "ekzg-multi-open" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d37456a32cf79bdbddd6685a2adec73210e2d60332370bc0e9a502b6d93beb" +dependencies = [ + "ekzg-bls12-381", + "ekzg-maybe-rayon", + "ekzg-polynomial", + "sha2", +] + +[[package]] +name = "ekzg-polynomial" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "704751bac85af4754bb8a14457ef24d820738062d0b6f3763534d0980b1a1e81" +dependencies = [ + "ekzg-bls12-381", + "ekzg-maybe-rayon", +] + +[[package]] +name = "ekzg-serialization" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cb983d9f75b2804c00246def8d52c01cf05f70c22593b8d314fbcf0cf89042b" +dependencies = [ + "ekzg-bls12-381", + "hex", +] + +[[package]] +name = "ekzg-single-open" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799d5806d51e1453fa0f528d6acf4127e2a89e98312c826151ebc24ee3448ec3" +dependencies = [ + "ekzg-bls12-381", + "ekzg-polynomial", + "itertools 0.14.0", +] + +[[package]] +name = "ekzg-trusted-setup" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85314d56718dc2c6dd77c3b3630f1839defcb6f47d9c20195608a0f7976095ab" dependencies = [ + "ekzg-bls12-381", + "ekzg-serialization", + "hex", "serde", + "serde_json", ] +[[package]] +name = "elf" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4445909572dbd556c457c849c4ca58623d84b27c8fff1e74b0b4227d8b90d17b" + [[package]] name = "elliptic-curve" version = "0.13.8" @@ -2473,9 +2207,9 @@ dependencies = [ "base16ct", "crypto-bigint", "digest 0.10.7", - "ff", + "ff 0.13.1", "generic-array", - "group", + "group 0.13.0", "pem-rfc7468", "pkcs8", "rand_core 0.6.4", @@ -2494,25 +2228,6 @@ dependencies = [ "cfg-if 1.0.4", ] -[[package]] -name = "enr" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "851bd664a3d3a3c175cff92b2f0df02df3c541b4895d0ae307611827aae46152" -dependencies = [ - "alloy-rlp", - "base64 0.22.1", - "bytes", - "ed25519-dalek", - "hex", - "k256", - "log", - "rand 0.8.5", - "serde", - "sha3", - "zeroize", -] - [[package]] name = "enum-ordinalize" version = "4.3.2" @@ -2530,7 +2245,7 @@ checksum = "8ca9601fb2d62598ee17836250842873a413586e5d7ed88b356e38ddbb0ec631" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] @@ -2549,43 +2264,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] -name = "ere-build-utils" -version = "0.3.0" -source = "git+https://github.com/eth-act/ere?tag=v0.3.0#ffc0e230cf4387fb22eb755f0fb323b38294520f" -dependencies = [ - "cargo_metadata", -] - -[[package]] -name = "ere-common" -version = "0.3.0" -source = "git+https://github.com/eth-act/ere?tag=v0.3.0#ffc0e230cf4387fb22eb755f0fb323b38294520f" -dependencies = [ - "ere-build-utils", - "serde", - "strum", -] - -[[package]] -name = "ere-dockerized" +name = "ere-io" version = "0.3.0" source = "git+https://github.com/eth-act/ere?tag=v0.3.0#ffc0e230cf4387fb22eb755f0fb323b38294520f" -dependencies = [ - "anyhow", - "ere-common", - "ere-server", - "ere-zkvm-interface 0.3.0", - "serde", - "tempfile", - "thiserror 2.0.17", - "tokio", - "tracing", -] - -[[package]] -name = "ere-io" -version = "0.0.16" -source = "git+https://github.com/eth-act/ere?rev=ec75f8a26657ddbf7efc44cdb3167fff4f55fe27#ec75f8a26657ddbf7efc44cdb3167fff4f55fe27" dependencies = [ "bincode 2.0.1", "rkyv", @@ -2594,8 +2275,8 @@ dependencies = [ [[package]] name = "ere-platform-trait" -version = "0.0.16" -source = "git+https://github.com/eth-act/ere?rev=ec75f8a26657ddbf7efc44cdb3167fff4f55fe27#ec75f8a26657ddbf7efc44cdb3167fff4f55fe27" +version = "0.3.0" +source = "git+https://github.com/eth-act/ere?tag=v0.3.0#ffc0e230cf4387fb22eb755f0fb323b38294520f" dependencies = [ "digest 0.10.7", ] @@ -2607,28 +2288,14 @@ source = "git+https://github.com/eth-act/ere?tag=v0.3.0#ffc0e230cf4387fb22eb755f dependencies = [ "anyhow", "bincode 2.0.1", - "ere-zkvm-interface 0.3.0", + "ere-zkvm-interface", "prost", "serde", - "thiserror 2.0.17", + "thiserror 2.0.18", "tokio", "twirp", ] -[[package]] -name = "ere-zkvm-interface" -version = "0.0.16" -source = "git+https://github.com/eth-act/ere?rev=ec75f8a26657ddbf7efc44cdb3167fff4f55fe27#ec75f8a26657ddbf7efc44cdb3167fff4f55fe27" -dependencies = [ - "anyhow", - "auto_impl", - "bincode 2.0.1", - "indexmap 2.12.1", - "serde", - "strum", - "thiserror 2.0.17", -] - [[package]] name = "ere-zkvm-interface" version = "0.3.0" @@ -2638,10 +2305,10 @@ dependencies = [ "auto_impl", "bincode 2.0.1", "clap", - "indexmap 2.12.1", + "indexmap 2.13.0", "serde", "strum", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -2660,6 +2327,19 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5692dd7b5a1978a5aeb0ce83b7655c58ca8efdcb79d21036ea249da95afec2c6" +[[package]] +name = "eth2_interop_keypairs" +version = "0.2.0" +source = "git+https://github.com/sigp/lighthouse?branch=unstable#9c4715c251ea19b2cc4c7688916b5cddfa2b1778" +dependencies = [ + "bls", + "ethereum_hashing 0.8.0", + "hex", + "num-bigint 0.4.6", + "serde", + "serde_yaml", +] + [[package]] name = "ethbloom" version = "0.14.1" @@ -2698,6 +2378,17 @@ dependencies = [ "sha2", ] +[[package]] +name = "ethereum_hashing" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa93f58bb1eb3d1e556e4f408ef1dac130bad01ac37db4e7ade45de40d1c86a" +dependencies = [ + "cpufeatures", + "ring", + "sha2", +] + [[package]] name = "ethereum_serde_utils" version = "0.8.0" @@ -2726,6 +2417,22 @@ dependencies = [ "typenum", ] +[[package]] +name = "ethereum_ssz" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2128a84f7a3850d54ee343334e3392cca61f9f6aa9441eec481b9394b43c238b" +dependencies = [ + "alloy-primitives", + "context_deserialize", + "ethereum_serde_utils", + "itertools 0.14.0", + "serde", + "serde_derive", + "smallvec", + "typenum", +] + [[package]] name = "ethereum_ssz_derive" version = "0.9.1" @@ -2735,13 +2442,25 @@ dependencies = [ "darling 0.20.11", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", +] + +[[package]] +name = "ethereum_ssz_derive" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd596f91cff004fc8d02be44c21c0f9b93140a04b66027ae052f5f8e05b48eba" +dependencies = [ + "darling 0.23.0", + "proc-macro2", + "quote", + "syn 2.0.117", ] [[package]] name = "ethrex-blockchain" -version = "8.0.0" -source = "git+https://github.com/lambdaclass/ethrex.git?rev=e6d70854d0fe3b0f29ed8961e5cbfc5de7bdd7d1#e6d70854d0fe3b0f29ed8961e5cbfc5de7bdd7d1" +version = "9.0.0" +source = "git+https://github.com/lambdaclass/ethrex.git?tag=v9.0.0#e88175e2d49f1192cc9f2fdeae6fde1392d0759d" dependencies = [ "bytes", "ethrex-common", @@ -2752,8 +2471,8 @@ dependencies = [ "ethrex-trie", "ethrex-vm", "hex", - "rustc-hash 2.1.1", - "thiserror 2.0.17", + "rustc-hash", + "thiserror 2.0.18", "tokio", "tokio-util", "tracing", @@ -2761,8 +2480,8 @@ dependencies = [ [[package]] name = "ethrex-common" -version = "8.0.0" -source = "git+https://github.com/lambdaclass/ethrex.git?rev=e6d70854d0fe3b0f29ed8961e5cbfc5de7bdd7d1#e6d70854d0fe3b0f29ed8961e5cbfc5de7bdd7d1" +version = "9.0.0" +source = "git+https://github.com/lambdaclass/ethrex.git?tag=v9.0.0#e88175e2d49f1192cc9f2fdeae6fde1392d0759d" dependencies = [ "bytes", "crc32fast", @@ -2779,12 +2498,12 @@ dependencies = [ "once_cell", "rayon", "rkyv", - "rustc-hash 2.1.1", + "rustc-hash", "serde", "serde_json", "sha2", "sha3", - "thiserror 2.0.17", + "thiserror 2.0.18", "tinyvec", "tracing", "url", @@ -2792,19 +2511,19 @@ dependencies = [ [[package]] name = "ethrex-crypto" -version = "8.0.0" -source = "git+https://github.com/lambdaclass/ethrex.git?rev=e6d70854d0fe3b0f29ed8961e5cbfc5de7bdd7d1#e6d70854d0fe3b0f29ed8961e5cbfc5de7bdd7d1" +version = "9.0.0" +source = "git+https://github.com/lambdaclass/ethrex.git?tag=v9.0.0#e88175e2d49f1192cc9f2fdeae6fde1392d0759d" dependencies = [ "c-kzg", "kzg-rs", - "thiserror 2.0.17", + "thiserror 2.0.18", "tiny-keccak", ] [[package]] name = "ethrex-l2-common" -version = "8.0.0" -source = "git+https://github.com/lambdaclass/ethrex.git?rev=e6d70854d0fe3b0f29ed8961e5cbfc5de7bdd7d1#e6d70854d0fe3b0f29ed8961e5cbfc5de7bdd7d1" +version = "9.0.0" +source = "git+https://github.com/lambdaclass/ethrex.git?tag=v9.0.0#e88175e2d49f1192cc9f2fdeae6fde1392d0759d" dependencies = [ "bytes", "ethereum-types", @@ -2821,20 +2540,20 @@ dependencies = [ "serde", "serde_with", "sha3", - "thiserror 2.0.17", + "thiserror 2.0.18", "tracing", ] [[package]] name = "ethrex-levm" -version = "8.0.0" -source = "git+https://github.com/lambdaclass/ethrex.git?rev=e6d70854d0fe3b0f29ed8961e5cbfc5de7bdd7d1#e6d70854d0fe3b0f29ed8961e5cbfc5de7bdd7d1" +version = "9.0.0" +source = "git+https://github.com/lambdaclass/ethrex.git?tag=v9.0.0#e88175e2d49f1192cc9f2fdeae6fde1392d0759d" dependencies = [ "ark-bn254", "ark-ec", "ark-ff 0.5.0", "bitvec", - "bls12_381", + "bls12_381 0.8.0", "bytes", "datatest-stable", "derive_more 1.0.0", @@ -2847,36 +2566,36 @@ dependencies = [ "malachite", "p256", "ripemd", - "rustc-hash 2.1.1", + "rustc-hash", "serde", "serde_json", "sha2", "sha3", "strum", - "thiserror 2.0.17", + "thiserror 2.0.18", "walkdir", ] [[package]] name = "ethrex-metrics" -version = "8.0.0" -source = "git+https://github.com/lambdaclass/ethrex.git?rev=e6d70854d0fe3b0f29ed8961e5cbfc5de7bdd7d1#e6d70854d0fe3b0f29ed8961e5cbfc5de7bdd7d1" +version = "9.0.0" +source = "git+https://github.com/lambdaclass/ethrex.git?tag=v9.0.0#e88175e2d49f1192cc9f2fdeae6fde1392d0759d" dependencies = [ "axum", "ethrex-common", "prometheus 0.13.4", "serde", "serde_json", - "thiserror 2.0.17", + "thiserror 2.0.18", "tokio", "tracing", - "tracing-subscriber 0.3.22", + "tracing-subscriber", ] [[package]] name = "ethrex-p2p" -version = "8.0.0" -source = "git+https://github.com/lambdaclass/ethrex.git?rev=e6d70854d0fe3b0f29ed8961e5cbfc5de7bdd7d1#e6d70854d0fe3b0f29ed8961e5cbfc5de7bdd7d1" +version = "9.0.0" +source = "git+https://github.com/lambdaclass/ethrex.git?tag=v9.0.0#e88175e2d49f1192cc9f2fdeae6fde1392d0759d" dependencies = [ "aes", "async-trait", @@ -2895,20 +2614,20 @@ dependencies = [ "futures", "hex", "hmac", - "indexmap 2.12.1", + "indexmap 2.13.0", "lazy_static", "prometheus 0.14.0", "rand 0.8.5", "rayon", - "rustc-hash 2.1.1", - "secp256k1 0.30.0", + "rustc-hash", + "secp256k1", "serde", "serde_json", "sha2", "snap", "spawned-concurrency", "spawned-rt", - "thiserror 2.0.17", + "thiserror 2.0.18", "tokio", "tokio-stream", "tokio-util", @@ -2917,22 +2636,22 @@ dependencies = [ [[package]] name = "ethrex-rlp" -version = "8.0.0" -source = "git+https://github.com/lambdaclass/ethrex.git?rev=e6d70854d0fe3b0f29ed8961e5cbfc5de7bdd7d1#e6d70854d0fe3b0f29ed8961e5cbfc5de7bdd7d1" +version = "9.0.0" +source = "git+https://github.com/lambdaclass/ethrex.git?tag=v9.0.0#e88175e2d49f1192cc9f2fdeae6fde1392d0759d" dependencies = [ "bytes", "ethereum-types", "hex", "lazy_static", "snap", - "thiserror 2.0.17", + "thiserror 2.0.18", "tinyvec", ] [[package]] name = "ethrex-rpc" -version = "8.0.0" -source = "git+https://github.com/lambdaclass/ethrex.git?rev=e6d70854d0fe3b0f29ed8961e5cbfc5de7bdd7d1#e6d70854d0fe3b0f29ed8961e5cbfc5de7bdd7d1" +version = "9.0.0" +source = "git+https://github.com/lambdaclass/ethrex.git?tag=v9.0.0#e88175e2d49f1192cc9f2fdeae6fde1392d0759d" dependencies = [ "axum", "axum-extra", @@ -2953,25 +2672,25 @@ dependencies = [ "jsonwebtoken", "rand 0.8.5", "reqwest", - "secp256k1 0.30.0", + "secp256k1", "serde", "serde_json", "sha2", "spawned-concurrency", "spawned-rt", - "thiserror 2.0.17", + "thiserror 2.0.18", "tokio", "tokio-util", "tower-http", "tracing", - "tracing-subscriber 0.3.22", + "tracing-subscriber", "uuid", ] [[package]] name = "ethrex-storage" -version = "8.0.0" -source = "git+https://github.com/lambdaclass/ethrex.git?rev=e6d70854d0fe3b0f29ed8961e5cbfc5de7bdd7d1#e6d70854d0fe3b0f29ed8961e5cbfc5de7bdd7d1" +version = "9.0.0" +source = "git+https://github.com/lambdaclass/ethrex.git?tag=v9.0.0#e88175e2d49f1192cc9f2fdeae6fde1392d0759d" dependencies = [ "anyhow", "async-trait", @@ -2982,29 +2701,29 @@ dependencies = [ "ethrex-rlp", "ethrex-trie", "hex", - "lru 0.16.2", + "lru 0.16.3", "qfilter", "rayon", - "rustc-hash 2.1.1", + "rustc-hash", "serde", "serde_json", - "thiserror 2.0.17", + "thiserror 2.0.18", "tokio", "tracing", ] [[package]] name = "ethrex-threadpool" -version = "0.1.0" -source = "git+https://github.com/lambdaclass/ethrex.git?rev=e6d70854d0fe3b0f29ed8961e5cbfc5de7bdd7d1#e6d70854d0fe3b0f29ed8961e5cbfc5de7bdd7d1" +version = "9.0.0" +source = "git+https://github.com/lambdaclass/ethrex.git?tag=v9.0.0#e88175e2d49f1192cc9f2fdeae6fde1392d0759d" dependencies = [ "crossbeam 0.8.4", ] [[package]] name = "ethrex-trie" -version = "8.0.0" -source = "git+https://github.com/lambdaclass/ethrex.git?rev=e6d70854d0fe3b0f29ed8961e5cbfc5de7bdd7d1#e6d70854d0fe3b0f29ed8961e5cbfc5de7bdd7d1" +version = "9.0.0" +source = "git+https://github.com/lambdaclass/ethrex.git?tag=v9.0.0#e88175e2d49f1192cc9f2fdeae6fde1392d0759d" dependencies = [ "anyhow", "bytes", @@ -3017,18 +2736,18 @@ dependencies = [ "hex", "lazy_static", "rkyv", - "rustc-hash 2.1.1", + "rustc-hash", "serde", "serde_json", "smallvec", - "thiserror 2.0.17", + "thiserror 2.0.18", "tracing", ] [[package]] name = "ethrex-vm" -version = "8.0.0" -source = "git+https://github.com/lambdaclass/ethrex.git?rev=e6d70854d0fe3b0f29ed8961e5cbfc5de7bdd7d1#e6d70854d0fe3b0f29ed8961e5cbfc5de7bdd7d1" +version = "9.0.0" +source = "git+https://github.com/lambdaclass/ethrex.git?tag=v9.0.0#e88175e2d49f1192cc9f2fdeae6fde1392d0759d" dependencies = [ "bincode 1.3.3", "bytes", @@ -3043,63 +2762,19 @@ dependencies = [ "lazy_static", "rkyv", "serde", - "thiserror 2.0.17", + "thiserror 2.0.18", "tracing", ] [[package]] -name = "eventsource-client" -version = "0.13.0" +name = "eventsource-stream" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43ddc25e1ad2cc0106d5e2d967397b4fb2068a66677ee9b0eea4600e5cfe8fb4" -dependencies = [ - "futures", - "hyper 0.14.32", - "hyper-rustls 0.24.2", - "hyper-timeout", - "log", - "pin-project", - "rand 0.8.5", - "tokio", -] - -[[package]] -name = "execution-witness-sentry" -version = "0.1.0" +checksum = "74fef4569247a5f429d9156b9d0a2599914385dd189c539334c625d8099d90ab" dependencies = [ - "alloy-genesis", - "alloy-primitives", - "alloy-provider", - "alloy-rpc-types-debug", - "alloy-rpc-types-eth", - "anyhow", - "axum", - "clap", - "discv5", - "ere-common", - "ethereum_serde_utils", - "eventsource-client", - "flate2", - "futures", - "lru 0.12.5", - "reqwest", - "reth-chainspec", - "reth-ethereum-primitives", - "reth-stateless", - "serde", - "serde_json", - "thiserror 2.0.17", - "tokio", - "tokio-util", - "toml_edit 0.24.0+spec-1.1.0", - "tower-http", - "tracing", - "tracing-subscriber 0.3.22", - "url", - "zkboost-client", - "zkboost-ethereum-el-input", - "zkboost-ethereum-el-types", - "zkboost-types", + "futures-core", + "nom", + "pin-project-lite", ] [[package]] @@ -3141,6 +2816,17 @@ dependencies = [ "bytes", ] +[[package]] +name = "ff" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160" +dependencies = [ + "bitvec", + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "ff" version = "0.13.1" @@ -3170,22 +2856,10 @@ dependencies = [ ] [[package]] -name = "fiat-crypto" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" - -[[package]] -name = "filetime" -version = "0.2.26" +name = "find-msvc-tools" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc0505cd1b6fa6580283f6bdf70a73fcf4aba1184038c90902b92b3dd0df63ed" -dependencies = [ - "cfg-if 1.0.4", - "libc", - "libredox", - "windows-sys 0.60.2", -] +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" [[package]] name = "fixed-hash" @@ -3200,13 +2874,32 @@ dependencies = [ ] [[package]] -name = "flate2" -version = "1.1.5" +name = "fixed-map" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb" +checksum = "86ed19add84e8cb9e8cc5f7074de0324247149ffef0b851e215fb0edc50c229b" dependencies = [ - "crc32fast", - "miniz_oxide", + "fixed-map-derive", +] + +[[package]] +name = "fixed-map-derive" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dc7a9cb3326bafb80642c5ce99b39a2c0702d4bfa8ee8a3e773791a6cbe2407" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "fixed_bytes" +version = "0.1.0" +source = "git+https://github.com/sigp/lighthouse?branch=unstable#9c4715c251ea19b2cc4c7688916b5cddfa2b1778" +dependencies = [ + "alloy-primitives", + "safe_arith", ] [[package]] @@ -3233,28 +2926,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" dependencies = [ - "foreign-types-shared 0.1.1", -] - -[[package]] -name = "foreign-types" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" -dependencies = [ - "foreign-types-macros", - "foreign-types-shared 0.3.1", -] - -[[package]] -name = "foreign-types-macros" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.111", + "foreign-types-shared", ] [[package]] @@ -3263,12 +2935,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" -[[package]] -name = "foreign-types-shared" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" - [[package]] name = "form_urlencoded" version = "1.2.2" @@ -3292,9 +2958,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" dependencies = [ "futures-channel", "futures-core", @@ -3307,9 +2973,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" dependencies = [ "futures-core", "futures-sink", @@ -3317,15 +2983,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" [[package]] name = "futures-executor" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" dependencies = [ "futures-core", "futures-task", @@ -3334,38 +3000,44 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" [[package]] name = "futures-macro" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] name = "futures-sink" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" [[package]] name = "futures-task" -version = "0.3.31" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-timer" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" [[package]] name = "futures-util" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ "futures-channel", "futures-core", @@ -3375,16 +3047,9 @@ dependencies = [ "futures-task", "memchr", "pin-project-lite", - "pin-utils", "slab", ] -[[package]] -name = "futures-utils-wasm" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42012b0f064e01aa58b545fe3727f90f7dd4020f4a3ea735b50344965f5a57e9" - [[package]] name = "gcd" version = "2.3.0" @@ -3404,9 +3069,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if 1.0.4", "js-sys", @@ -3423,29 +3088,21 @@ checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if 1.0.4", "libc", - "r-efi", + "r-efi 5.3.0", "wasip2", ] [[package]] -name = "ghash" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0d8a4362ccb29cb0b265253fb0a2728f592895ee6854fd9bc13f2ffda266ff1" -dependencies = [ - "opaque-debug", - "polyval", -] - -[[package]] -name = "gl_generator" -version = "0.14.0" +name = "getrandom" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" dependencies = [ - "khronos_api", - "log", - "xml-rs", + "cfg-if 1.0.4", + "libc", + "r-efi 6.0.0", + "wasip2", + "wasip3", ] [[package]] @@ -3455,85 +3112,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" [[package]] -name = "glow" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e5ea60d70410161c8bf5da3fdfeaa1c72ed2c15f8bbb9d19fe3a4fad085f08" -dependencies = [ - "js-sys", - "slotmap", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "glutin_wgl_sys" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c4ee00b289aba7a9e5306d57c2d05499b2e5dc427f84ac708bd2c090212cf3e" -dependencies = [ - "gl_generator", -] - -[[package]] -name = "gmp-mpfr-sys" -version = "1.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60f8970a75c006bb2f8ae79c6768a116dd215fa8346a87aed99bf9d82ca43394" -dependencies = [ - "libc", - "windows-sys 0.60.2", -] - -[[package]] -name = "gpu-alloc" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171" -dependencies = [ - "bitflags", - "gpu-alloc-types", -] - -[[package]] -name = "gpu-alloc-types" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98ff03b468aa837d70984d55f5d3f846f6ec31fe34bbb97c4f85219caeee1ca4" -dependencies = [ - "bitflags", -] - -[[package]] -name = "gpu-allocator" -version = "0.27.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c151a2a5ef800297b4e79efa4f4bec035c5f51d5ae587287c9b952bdf734cacd" -dependencies = [ - "log", - "presser", - "thiserror 1.0.69", - "windows 0.58.0", -] - -[[package]] -name = "gpu-descriptor" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b89c83349105e3732062a895becfc71a8f921bb71ecbbdd8ff99263e3b53a0ca" -dependencies = [ - "bitflags", - "gpu-descriptor-types", - "hashbrown 0.15.5", -] - -[[package]] -name = "gpu-descriptor-types" -version = "0.2.0" +name = "group" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdf242682df893b86f33a73828fb09ca4b2d3bb6cc95249707fc684d27484b91" +checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7" dependencies = [ - "bitflags", + "ff 0.12.1", + "memuse", + "rand_core 0.6.4", + "subtle", ] [[package]] @@ -3542,15 +3129,17 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ - "ff", + "ff 0.13.1", + "rand 0.8.5", "rand_core 0.6.4", + "rand_xorshift 0.3.0", "subtle", ] [[package]] name = "guest" -version = "0.4.0" -source = "git+https://github.com/eth-act/ere-guests?tag=v0.4.0#cc921dcd2978a31ee5e8bb45680396f04549b540" +version = "0.5.0" +source = "git+https://github.com/eth-act/ere-guests?tag=v0.6.0#64c94bb3da631101a6cb2f276c89392cb7c3426f" dependencies = [ "ere-io", "ere-platform-trait", @@ -3572,8 +3161,8 @@ dependencies = [ [[package]] name = "guest_program" -version = "8.0.0" -source = "git+https://github.com/lambdaclass/ethrex.git?rev=e6d70854d0fe3b0f29ed8961e5cbfc5de7bdd7d1#e6d70854d0fe3b0f29ed8961e5cbfc5de7bdd7d1" +version = "9.0.0" +source = "git+https://github.com/lambdaclass/ethrex.git?tag=v9.0.0#e88175e2d49f1192cc9f2fdeae6fde1392d0759d" dependencies = [ "bincode 1.3.3", "bytes", @@ -3590,22 +3179,22 @@ dependencies = [ "serde", "serde_json", "serde_with", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] name = "h2" -version = "0.3.27" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0beca50380b1fc32983fc1cb4587bfa4bb9e78fc259aad4a0032d2080309222d" +checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" dependencies = [ + "atomic-waker", "bytes", "fnv", "futures-core", "futures-sink", - "futures-util", - "http 0.2.12", - "indexmap 2.12.1", + "http", + "indexmap 2.13.0", "slab", "tokio", "tokio-util", @@ -3613,34 +3202,26 @@ dependencies = [ ] [[package]] -name = "h2" -version = "0.4.12" +name = "halo2" +version = "0.1.0-beta.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" +checksum = "2a23c779b38253fe1538102da44ad5bd5378495a61d2c4ee18d64eaa61ae5995" dependencies = [ - "atomic-waker", - "bytes", - "fnv", - "futures-core", - "futures-sink", - "http 1.4.0", - "indexmap 2.12.1", - "slab", - "tokio", - "tokio-util", - "tracing", + "halo2_proofs", ] [[package]] -name = "half" -version = "2.7.1" +name = "halo2_proofs" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" +checksum = "e925780549adee8364c7f2b685c753f6f3df23bde520c67416e93bf615933760" dependencies = [ - "cfg-if 1.0.4", - "crunchy", - "num-traits", - "zerocopy", + "blake2b_simd", + "ff 0.12.1", + "group 0.12.1", + "pasta_curves 0.4.1", + "rand_core 0.6.4", + "rayon", ] [[package]] @@ -3649,15 +3230,6 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" -[[package]] -name = "hashbrown" -version = "0.14.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" -dependencies = [ - "ahash", -] - [[package]] name = "hashbrown" version = "0.15.5" @@ -3682,25 +3254,16 @@ dependencies = [ "serde_core", ] -[[package]] -name = "hashlink" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba4ff7128dee98c7dc9794b6a411377e1404dba1c97deb8d1a55297bd25d8af" -dependencies = [ - "hashbrown 0.14.5", -] - [[package]] name = "headers" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3314d5adb5d94bcdf56771f2e50dbbc80bb4bdf88967526706205ac9eff24eb" dependencies = [ - "base64 0.22.1", + "base64", "bytes", "headers-core", - "http 1.4.0", + "http", "httpdate", "mime", "sha1", @@ -3712,7 +3275,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" dependencies = [ - "http 1.4.0", + "http", ] [[package]] @@ -3748,21 +3311,6 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" -[[package]] -name = "hexf-parse" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" - -[[package]] -name = "hkdf" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" -dependencies = [ - "hmac", -] - [[package]] name = "hmac" version = "0.12.1" @@ -3772,26 +3320,6 @@ dependencies = [ "digest 0.10.7", ] -[[package]] -name = "home" -version = "0.5.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" -dependencies = [ - "windows-sys 0.61.2", -] - -[[package]] -name = "http" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" -dependencies = [ - "bytes", - "fnv", - "itoa", -] - [[package]] name = "http" version = "1.4.0" @@ -3802,17 +3330,6 @@ dependencies = [ "itoa", ] -[[package]] -name = "http-body" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" -dependencies = [ - "bytes", - "http 0.2.12", - "pin-project-lite", -] - [[package]] name = "http-body" version = "1.0.1" @@ -3820,7 +3337,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.4.0", + "http", ] [[package]] @@ -3831,8 +3348,8 @@ checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", "futures-core", - "http 1.4.0", - "http-body 1.0.1", + "http", + "http-body", "pin-project-lite", ] @@ -3848,30 +3365,6 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" -[[package]] -name = "hyper" -version = "0.14.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41dfc780fdec9373c01bae43289ea34c972e40ee3c9f6b3c8801a35f35586ce7" -dependencies = [ - "bytes", - "futures-channel", - "futures-core", - "futures-util", - "h2 0.3.27", - "http 0.2.12", - "http-body 0.4.6", - "httparse", - "httpdate", - "itoa", - "pin-project-lite", - "socket2 0.5.10", - "tokio", - "tower-service", - "tracing", - "want", -] - [[package]] name = "hyper" version = "1.8.1" @@ -3882,9 +3375,9 @@ dependencies = [ "bytes", "futures-channel", "futures-core", - "h2 0.4.12", - "http 1.4.0", - "http-body 1.0.1", + "h2", + "http", + "http-body", "httparse", "httpdate", "itoa", @@ -3895,51 +3388,23 @@ dependencies = [ "want", ] -[[package]] -name = "hyper-rustls" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" -dependencies = [ - "futures-util", - "http 0.2.12", - "hyper 0.14.32", - "log", - "rustls 0.21.12", - "rustls-native-certs 0.6.3", - "tokio", - "tokio-rustls 0.24.1", -] - [[package]] name = "hyper-rustls" version = "0.27.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" dependencies = [ - "http 1.4.0", - "hyper 1.8.1", + "http", + "hyper", "hyper-util", - "rustls 0.23.31", - "rustls-native-certs 0.8.2", + "rustls", + "rustls-native-certs", "rustls-pki-types", "tokio", - "tokio-rustls 0.26.4", + "tokio-rustls", "tower-service", ] -[[package]] -name = "hyper-timeout" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbb958482e8c7be4bc3cf272a766a2b0bf1a6755e7a6ae777f017a31d11b13b1" -dependencies = [ - "hyper 0.14.32", - "pin-project-lite", - "tokio", - "tokio-io-timeout", -] - [[package]] name = "hyper-tls" version = "0.6.0" @@ -3948,7 +3413,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper 1.8.1", + "hyper", "hyper-util", "native-tls", "tokio", @@ -3958,23 +3423,22 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.19" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" dependencies = [ - "base64 0.22.1", + "base64", "bytes", "futures-channel", - "futures-core", "futures-util", - "http 1.4.0", - "http-body 1.0.1", - "hyper 1.8.1", + "http", + "http-body", + "hyper", "ipnet", "libc", "percent-encoding", "pin-project-lite", - "socket2 0.6.1", + "socket2", "system-configuration", "tokio", "tower-service", @@ -3984,9 +3448,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.64" +version = "0.1.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -3994,7 +3458,7 @@ dependencies = [ "js-sys", "log", "wasm-bindgen", - "windows-core 0.61.2", + "windows-core", ] [[package]] @@ -4054,9 +3518,9 @@ checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" [[package]] name = "icu_properties" -version = "2.1.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" dependencies = [ "icu_collections", "icu_locale_core", @@ -4068,9 +3532,9 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "2.1.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" [[package]] name = "icu_provider" @@ -4087,6 +3551,12 @@ dependencies = [ "zerovec", ] +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + [[package]] name = "ident_case" version = "1.0.1" @@ -4158,7 +3628,7 @@ checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] @@ -4174,9 +3644,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.12.1" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" dependencies = [ "equivalent", "hashbrown 0.16.1", @@ -4193,17 +3663,25 @@ dependencies = [ "generic-array", ] +[[package]] +name = "int_to_bytes" +version = "0.2.0" +source = "git+https://github.com/sigp/lighthouse?branch=unstable#9c4715c251ea19b2cc4c7688916b5cddfa2b1778" +dependencies = [ + "bytes", +] + [[package]] name = "ipnet" -version = "2.11.0" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" +checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" [[package]] name = "iri-string" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f867b9d1d896b67beb18518eda36fdb77a32ea590de864f1325b294a6d14397" +checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a" dependencies = [ "memchr", "serde", @@ -4253,15 +3731,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" - -[[package]] -name = "jni-sys" -version = "0.3.0" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" [[package]] name = "jobserver" @@ -4275,9 +3747,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.83" +version = "0.3.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8" +checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c" dependencies = [ "once_cell", "wasm-bindgen", @@ -4289,7 +3761,7 @@ version = "9.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a87cc7a48537badeae96744432de36f4be2b4a34a05a5ef32e9dd8a1c169dde" dependencies = [ - "base64 0.22.1", + "base64", "js-sys", "pem", "ring", @@ -4298,6 +3770,20 @@ dependencies = [ "simple_asn1", ] +[[package]] +name = "jubjub" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a575df5f985fe1cd5b2b05664ff6accfc46559032b954529fd225a2168d27b0f" +dependencies = [ + "bitvec", + "bls12_381 0.7.1", + "ff 0.12.1", + "group 0.12.1", + "rand_core 0.6.4", + "subtle", +] + [[package]] name = "k256" version = "0.13.4" @@ -4315,47 +3801,50 @@ dependencies = [ [[package]] name = "keccak" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +checksum = "cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653" dependencies = [ "cpufeatures", ] [[package]] name = "keccak-asm" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "505d1856a39b200489082f90d897c3f07c455563880bc5952e38eabf731c83b6" +checksum = "b646a74e746cd25045aa0fd42f4f7f78aa6d119380182c7e63a5593c4ab8df6f" dependencies = [ "digest 0.10.7", "sha3-asm", ] [[package]] -name = "khronos-egl" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76" +name = "kzg" +version = "0.1.0" +source = "git+https://github.com/sigp/lighthouse?branch=unstable#9c4715c251ea19b2cc4c7688916b5cddfa2b1778" dependencies = [ - "libc", - "libloading", - "pkg-config", + "c-kzg", + "educe", + "ethereum_hashing 0.8.0", + "ethereum_serde_utils", + "ethereum_ssz 0.10.1", + "ethereum_ssz_derive 0.10.1", + "hex", + "rayon", + "rust_eth_kzg", + "serde", + "serde_json", + "tracing", + "tree_hash 0.12.1", ] -[[package]] -name = "khronos_api" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" - [[package]] name = "kzg-rs" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9201effeea3fcc93b587904ae2df9ce97e433184b9d6d299e9ebc9830a546636" +checksum = "ee8b4f55c3dedcfaa8668de1dfc8469e7a32d441c28edf225ed1f566fb32977d" dependencies = [ - "ff", + "ff 0.13.1", "hex", "serde_arrays", "sha2", @@ -4383,7 +3872,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "018a95aa873eb49896a858dee0d925c33f3978d073c64b08dd4f2c9b35a017c6" dependencies = [ - "getrandom 0.2.16", + "getrandom 0.2.17", "num-bigint 0.4.6", "num-traits", "rand 0.8.5", @@ -4397,45 +3886,27 @@ name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +dependencies = [ + "spin", +] [[package]] -name = "lazycell" -version = "1.3.0" +name = "leb128fmt" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "libc" -version = "0.2.178" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" - -[[package]] -name = "libloading" -version = "0.8.9" +version = "0.2.182" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" -dependencies = [ - "cfg-if 1.0.4", - "windows-link 0.2.1", -] +checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" [[package]] name = "libm" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" - -[[package]] -name = "libredox" -version = "0.1.12" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" -dependencies = [ - "bitflags", - "libc", - "redox_syscall 0.7.0", -] +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "libtest-mimic" @@ -4457,9 +3928,9 @@ checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" [[package]] name = "linux-raw-sys" -version = "0.11.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" [[package]] name = "litemap" @@ -4467,12 +3938,6 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" -[[package]] -name = "litrs" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" - [[package]] name = "lock_api" version = "0.4.14" @@ -4499,18 +3964,9 @@ dependencies = [ [[package]] name = "lru" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "227748d55f2f0ab4735d87fd623798cb6b664512fe979705f829c9f81c934465" -dependencies = [ - "hashbrown 0.15.5", -] - -[[package]] -name = "lru" -version = "0.16.2" +version = "0.16.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96051b46fc183dc9cd4a223960ef37b9af631b55191852a8274bfef064cda20f" +checksum = "a1dc47f592c06f33f8e3aea9591776ec7c9f9e4124778ff8a3c3b87159f7e593" dependencies = [ "hashbrown 0.16.1", ] @@ -4523,7 +3979,7 @@ checksum = "1b27834086c65ec3f9387b096d66e99f221cf081c2b738042aa252bcd41204e3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] @@ -4573,13 +4029,10 @@ dependencies = [ ] [[package]] -name = "malloc_buf" -version = "0.0.6" +name = "maplit" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" -dependencies = [ - "libc", -] +checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" [[package]] name = "matchers" @@ -4604,9 +4057,9 @@ checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" [[package]] name = "memchr" -version = "2.7.6" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "memoffset" @@ -4618,18 +4071,43 @@ dependencies = [ ] [[package]] -name = "metal" -version = "0.32.0" +name = "memuse" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00c15a6f673ff72ddcc22394663290f870fb224c1bfce55734a75c414150e605" +checksum = "3d97bbf43eb4f088f8ca469930cde17fa036207c9a5e02ccc5107c4e8b17c964" + +[[package]] +name = "merkle_proof" +version = "0.2.0" +source = "git+https://github.com/sigp/lighthouse?branch=unstable#9c4715c251ea19b2cc4c7688916b5cddfa2b1778" dependencies = [ - "bitflags", - "block", - "core-graphics-types", - "foreign-types 0.5.0", - "log", - "objc", - "paste", + "alloy-primitives", + "ethereum_hashing 0.8.0", + "fixed_bytes", + "safe_arith", +] + +[[package]] +name = "metastruct" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "969a1be9bd80794bdf93b23ab552c2ec6f3e83b33164824553fd996cdad513b8" +dependencies = [ + "metastruct_macro", +] + +[[package]] +name = "metastruct_macro" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de9164f767d73a507c19205868c84da411dc7795f4bdabf497d3dd93cfef9930" +dependencies = [ + "darling 0.23.0", + "itertools 0.14.0", + "proc-macro2", + "quote", + "smallvec", + "syn 2.0.117", ] [[package]] @@ -4648,12 +4126,12 @@ version = "0.16.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd7399781913e5393588a8d8c6a2867bf85fb38eaf2502fdce465aad2dc6f034" dependencies = [ - "base64 0.22.1", + "base64", "http-body-util", - "hyper 1.8.1", - "hyper-rustls 0.27.7", + "hyper", + "hyper-rustls", "hyper-util", - "indexmap 2.12.1", + "indexmap 2.13.0", "ipnet", "metrics", "metrics-util", @@ -4679,6 +4157,29 @@ dependencies = [ "sketches-ddsketch", ] +[[package]] +name = "milhouse" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "259dd9da2ae5e0278b95da0b7ecef9c18c309d0a2d9e6db57ed33b9e8910c5e7" +dependencies = [ + "alloy-primitives", + "context_deserialize", + "educe", + "ethereum_hashing 0.8.0", + "ethereum_ssz 0.10.1", + "ethereum_ssz_derive 0.10.1", + "itertools 0.13.0", + "parking_lot", + "rayon", + "serde", + "smallvec", + "tree_hash 0.12.1", + "triomphe", + "typenum", + "vec_map", +] + [[package]] name = "mime" version = "0.3.17" @@ -4698,21 +4199,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26541387415a1e829df5d532aad019fb11bc723e2b5bc99edefa4cf5bfad0de7" dependencies = [ "ct-codecs", - "getrandom 0.2.16", + "getrandom 0.2.17", "rpassword", "scrypt", ] -[[package]] -name = "miniz_oxide" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" -dependencies = [ - "adler2", - "simd-adler32", -] - [[package]] name = "mio" version = "1.1.1" @@ -4724,6 +4215,30 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "mock-zkattestor" +version = "0.1.0" +dependencies = [ + "anyhow", + "async-stream", + "clap", + "ethereum_serde_utils", + "futures", + "reqwest", + "reqwest-eventsource", + "serde", + "serde_json", + "sha2", + "ssz_types 0.14.0", + "tokio", + "tracing", + "tracing-subscriber", + "types", + "url", + "zkboost-client", + "zkboost-types", +] + [[package]] name = "modular-bitfield" version = "0.11.2" @@ -4745,16 +4260,10 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "more-asserts" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fafa6961cabd9c63bcd77a45d7e3b7f3b552b70417831fb0f56db717e72407e" - [[package]] name = "mpt" version = "0.1.0" -source = "git+https://github.com/eth-act/zkvm-ethereum-mpt.git?tag=v0.4.0#d4d8f968c183aedc23100c3a5634dee14c320757" +source = "git+https://github.com/eth-act/zkvm-ethereum-mpt.git?rev=a1e44638c49c4e16751a0b915593fce98ab6bdef#a1e44638c49c4e16751a0b915593fce98ab6bdef" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -4779,40 +4288,14 @@ checksum = "4568f25ccbd45ab5d5603dc34318c1ec56b117531781260002151b8530a9f931" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", -] - -[[package]] -name = "naga" -version = "27.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "066cf25f0e8b11ee0df221219010f213ad429855f57c494f995590c861a9a7d8" -dependencies = [ - "arrayvec", - "bit-set", - "bitflags", - "cfg-if 1.0.4", - "cfg_aliases", - "codespan-reporting", - "half", - "hashbrown 0.16.1", - "hexf-parse", - "indexmap 2.12.1", - "libm", - "log", - "num-traits", - "once_cell", - "rustc-hash 1.1.0", - "spirv", - "thiserror 2.0.17", - "unicode-ident", + "syn 2.0.117", ] [[package]] name = "native-tls" -version = "0.2.14" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" +checksum = "465500e14ea162429d264d44189adc38b199b62b1c21eea9f69e4b73cb03bbf2" dependencies = [ "libc", "log", @@ -4820,32 +4303,11 @@ dependencies = [ "openssl-probe", "openssl-sys", "schannel", - "security-framework 2.11.1", + "security-framework", "security-framework-sys", "tempfile", ] -[[package]] -name = "ndk-sys" -version = "0.6.0+11769913" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" -dependencies = [ - "jni-sys", -] - -[[package]] -name = "nix" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" -dependencies = [ - "bitflags", - "cfg-if 1.0.4", - "cfg_aliases", - "libc", -] - [[package]] name = "nom" version = "7.1.3" @@ -4856,15 +4318,6 @@ dependencies = [ "minimal-lexical", ] -[[package]] -name = "ntapi" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4" -dependencies = [ - "winapi", -] - [[package]] name = "nu-ansi-term" version = "0.50.3" @@ -4920,9 +4373,9 @@ dependencies = [ [[package]] name = "num-conv" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" [[package]] name = "num-integer" @@ -4991,10 +4444,9 @@ version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" dependencies = [ - "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] @@ -5009,9 +4461,9 @@ dependencies = [ [[package]] name = "nybbles" -version = "0.4.6" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c4b5ecbd0beec843101bffe848217f770e8b8da81d8355b7d6e226f2199b3dc" +checksum = "0d49ff0c0d00d4a502b39df9af3a525e1efeb14b9dabb5bb83335284c1309210" dependencies = [ "alloy-rlp", "cfg-if 1.0.4", @@ -5021,34 +4473,6 @@ dependencies = [ "smallvec", ] -[[package]] -name = "objc" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" -dependencies = [ - "malloc_buf", -] - -[[package]] -name = "objc2-core-foundation" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" -dependencies = [ - "bitflags", -] - -[[package]] -name = "objc2-io-kit" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33fafba39597d6dc1fb709123dfa8289d39406734be322956a69f0931c73bb15" -dependencies = [ - "libc", - "objc2-core-foundation", -] - [[package]] name = "once_cell" version = "1.21.3" @@ -5065,126 +4489,23 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" -[[package]] -name = "op-alloy" -version = "0.22.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3b13412d297c1f9341f678b763750b120a73ffe998fa54a94d6eda98449e7ca" -dependencies = [ - "op-alloy-consensus", - "op-alloy-network", - "op-alloy-provider", - "op-alloy-rpc-types", - "op-alloy-rpc-types-engine", -] - [[package]] name = "op-alloy-consensus" -version = "0.22.4" +version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "726da827358a547be9f1e37c2a756b9e3729cb0350f43408164794b370cad8ae" +checksum = "736381a95471d23e267263cfcee9e1d96d30b9754a94a2819148f83379de8a86" dependencies = [ "alloy-consensus", "alloy-eips", - "alloy-network", "alloy-primitives", "alloy-rlp", - "alloy-rpc-types-eth", "alloy-serde", - "derive_more 2.1.0", + "derive_more 2.1.1", "serde", "serde_with", - "thiserror 2.0.17", -] - -[[package]] -name = "op-alloy-network" -version = "0.22.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63f27e65be273ec8fcb0b6af0fd850b550979465ab93423705ceb3dfddbd2ab" -dependencies = [ - "alloy-consensus", - "alloy-network", - "alloy-primitives", - "alloy-provider", - "alloy-rpc-types-eth", - "alloy-signer", - "op-alloy-consensus", - "op-alloy-rpc-types", -] - -[[package]] -name = "op-alloy-provider" -version = "0.22.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a71456699aa256dc20119736422ad9a44da8b9585036117afb936778122093b9" -dependencies = [ - "alloy-network", - "alloy-primitives", - "alloy-provider", - "alloy-rpc-types-engine", - "alloy-transport", - "async-trait", - "op-alloy-rpc-types-engine", -] - -[[package]] -name = "op-alloy-rpc-types" -version = "0.22.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "562dd4462562c41f9fdc4d860858c40e14a25df7f983ae82047f15f08fce4d19" -dependencies = [ - "alloy-consensus", - "alloy-eips", - "alloy-network-primitives", - "alloy-primitives", - "alloy-rpc-types-eth", - "alloy-serde", - "derive_more 2.1.0", - "op-alloy-consensus", - "serde", - "serde_json", - "thiserror 2.0.17", -] - -[[package]] -name = "op-alloy-rpc-types-engine" -version = "0.22.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8f24b8cb66e4b33e6c9e508bf46b8ecafc92eadd0b93fedd306c0accb477657" -dependencies = [ - "alloy-consensus", - "alloy-eips", - "alloy-primitives", - "alloy-rlp", - "alloy-rpc-types-engine", - "alloy-serde", - "derive_more 2.1.0", - "ethereum_ssz", - "ethereum_ssz_derive", - "op-alloy-consensus", - "serde", - "snap", - "thiserror 2.0.17", -] - -[[package]] -name = "op-revm" -version = "14.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1475a779c73999fc803778524042319691b31f3d6699d2b560c4ed8be1db802a" -dependencies = [ - "auto_impl", - "revm", - "serde", + "thiserror 2.0.18", ] -[[package]] -name = "opaque-debug" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" - [[package]] name = "openssl" version = "0.10.75" @@ -5193,7 +4514,7 @@ checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" dependencies = [ "bitflags", "cfg-if 1.0.4", - "foreign-types 0.3.2", + "foreign-types", "libc", "once_cell", "openssl-macros", @@ -5208,14 +4529,14 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] name = "openssl-probe" -version = "0.1.6" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" [[package]] name = "openssl-sys" @@ -5229,15 +4550,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "ordered-float" -version = "5.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f4779c6901a562440c3786d08192c6fbda7c1c2060edd10006b05ee35d10f2d" -dependencies = [ - "num-traits", -] - [[package]] name = "p256" version = "0.13.2" @@ -5251,14 +4563,14 @@ dependencies = [ ] [[package]] -name = "p3-baby-bear" -version = "0.2.3-succinct" +name = "p3-bn254-fr" +version = "0.3.2-succinct" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7521838ecab2ddf4f7bc4ceebad06ec02414729598485c1ada516c39900820e8" +checksum = "9abf208fbfe540d6e2a6caaa2a9a345b1c8cb23ffdcdfcc6987244525d4fc821" dependencies = [ + "ff 0.13.1", "num-bigint 0.4.6", "p3-field", - "p3-mds", "p3-poseidon2", "p3-symmetric", "rand 0.8.5", @@ -5266,13 +4578,27 @@ dependencies = [ ] [[package]] -name = "p3-dft" -version = "0.2.3-succinct" +name = "p3-challenger" +version = "0.3.2-succinct" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46414daedd796f1eefcdc1811c0484e4bced5729486b6eaba9521c572c76761a" +checksum = "42b725b453bbb35117a1abf0ddfd900b0676063d6e4231e0fa6bb0d76018d8ad" dependencies = [ "p3-field", - "p3-matrix", + "p3-maybe-rayon", + "p3-symmetric", + "p3-util", + "serde", + "tracing", +] + +[[package]] +name = "p3-dft" +version = "0.3.2-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56a1f81101bff744b7ebba7f4497e917a2c6716d6e62736e4a56e555a2d98cb7" +dependencies = [ + "p3-field", + "p3-matrix", "p3-maybe-rayon", "p3-util", "tracing", @@ -5280,9 +4606,9 @@ dependencies = [ [[package]] name = "p3-field" -version = "0.2.3-succinct" +version = "0.3.2-succinct" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48948a0516b349e9d1cdb95e7236a6ee010c44e68c5cc78b4b92bf1c4022a0d9" +checksum = "36459d4acb03d08097d713f336c7393990bb489ab19920d4f68658c7a5c10968" dependencies = [ "itertools 0.12.1", "num-bigint 0.4.6", @@ -5292,11 +4618,26 @@ dependencies = [ "serde", ] +[[package]] +name = "p3-koala-bear" +version = "0.3.2-succinct" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb1f52bcb6be38bdc8fa6b38b3434d4eedd511f361d4249fd798c6a5ef817b40" +dependencies = [ + "num-bigint 0.4.6", + "p3-field", + "p3-mds", + "p3-poseidon2", + "p3-symmetric", + "rand 0.8.5", + "serde", +] + [[package]] name = "p3-matrix" -version = "0.2.3-succinct" +version = "0.3.2-succinct" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e4de3f373589477cb735ea58e125898ed20935e03664b4614c7fac258b3c42f" +checksum = "5583e9cd136a4095a25c41a9edfdcce2dfae58ef01639317813bdbbd5b55c583" dependencies = [ "itertools 0.12.1", "p3-field", @@ -5309,15 +4650,15 @@ dependencies = [ [[package]] name = "p3-maybe-rayon" -version = "0.2.3-succinct" +version = "0.3.2-succinct" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3968ad1160310296eb04f91a5f4edfa38fe1d6b2b8cd6b5c64e6f9b7370979e" +checksum = "e524d47a49fb4265611303339c4ef970d892817b006cc330dad18afb91e411b1" [[package]] name = "p3-mds" -version = "0.2.3-succinct" +version = "0.3.2-succinct" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2356b1ed0add6d5dfbf7a338ce534a6fde827374394a52cec16a0840af6e97c9" +checksum = "4f6cb8edcb276033d43769a3725570c340d2ed6f35c3cca4cddeee07718fa376" dependencies = [ "itertools 0.12.1", "p3-dft", @@ -5330,9 +4671,9 @@ dependencies = [ [[package]] name = "p3-poseidon2" -version = "0.2.3-succinct" +version = "0.3.2-succinct" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7da1eec7e1b6900581bedd95e76e1ef4975608dd55be9872c9d257a8a9651c3a" +checksum = "5a26197df2097b98ab7038d59a01e1fe1a0f545e7e04aa9436b2454b1836654f" dependencies = [ "gcd", "p3-field", @@ -5344,9 +4685,9 @@ dependencies = [ [[package]] name = "p3-symmetric" -version = "0.2.3-succinct" +version = "0.3.2-succinct" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edb439bea1d822623b41ff4b51e3309e80d13cadf8b86d16ffd5e6efb9fdc360" +checksum = "3a1d3b5202096bca57cde912fbbb9cbaedaf5ac7c42a924c7166b98709d64d21" dependencies = [ "itertools 0.12.1", "p3-field", @@ -5355,20 +4696,29 @@ dependencies = [ [[package]] name = "p3-util" -version = "0.2.3-succinct" +version = "0.3.2-succinct" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6c2c2010678b9332b563eaa38364915b585c1a94b5ca61e2c7541c087ddda5c" +checksum = "ec5f0388aa6d935ca3a17444086120f393f0b2f0816010b5ff95998c1c4095e3" dependencies = [ "serde", ] +[[package]] +name = "pairing" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "135590d8bdba2b31346f9cd1fb2a912329f5135e832a4f422942eb6ead8b6b3b" +dependencies = [ + "group 0.12.1", +] + [[package]] name = "pairing" version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81fec4625e73cf41ef4bb6846cafa6d44736525f442ba45e407c4a000a13996f" dependencies = [ - "group", + "group 0.13.0", ] [[package]] @@ -5396,7 +4746,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] @@ -5417,9 +4767,39 @@ checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if 1.0.4", "libc", - "redox_syscall 0.5.18", + "redox_syscall", "smallvec", - "windows-link 0.2.1", + "windows-link", +] + +[[package]] +name = "pasta_curves" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cc65faf8e7313b4b1fbaa9f7ca917a0eed499a9663be71477f87993604341d8" +dependencies = [ + "blake2b_simd", + "ff 0.12.1", + "group 0.12.1", + "lazy_static", + "rand 0.8.5", + "static_assertions", + "subtle", +] + +[[package]] +name = "pasta_curves" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e57598f73cc7e1b2ac63c79c517b31a0877cd7c402cdcaa311b5208de7a095" +dependencies = [ + "blake2b_simd", + "ff 0.13.1", + "group 0.13.0", + "lazy_static", + "rand 0.8.5", + "static_assertions", + "subtle", ] [[package]] @@ -5444,7 +4824,7 @@ version = "3.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d30c53c26bc5b31a98cd02d20f25a7c8567146caf63ed593a9d87b2775291be" dependencies = [ - "base64 0.22.1", + "base64", "serde_core", ] @@ -5465,24 +4845,14 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pest" -version = "2.8.4" +version = "2.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbcfd20a6d4eeba40179f05735784ad32bdaef05ce8e8af05f180d45bb3e7e22" +checksum = "e0848c601009d37dfa3430c4666e147e49cdcf1b92ecd3e63657d8a5f19da662" dependencies = [ "memchr", "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 = "phf" version = "0.13.1" @@ -5514,7 +4884,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] @@ -5526,31 +4896,11 @@ dependencies = [ "siphasher", ] -[[package]] -name = "pin-project" -version = "1.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.111", -] - [[package]] name = "pin-project-lite" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] name = "pin-utils" @@ -5574,32 +4924,11 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" -[[package]] -name = "polyval" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" -dependencies = [ - "cfg-if 1.0.4", - "cpufeatures", - "opaque-debug", - "universal-hash", -] - [[package]] name = "portable-atomic" -version = "1.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" - -[[package]] -name = "portable-atomic-util" -version = "0.2.4" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" -dependencies = [ - "portable-atomic", -] +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" [[package]] name = "potential_utf" @@ -5627,9 +4956,9 @@ dependencies = [ [[package]] name = "predicates" -version = "3.1.3" +version = "3.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5d19ee57562043d37e82899fade9a22ebab7be9cef5026b07fda9cdd4293573" +checksum = "ada8f2932f28a27ee7b70dd6c1c39ea0675c55a36879ab92f3a715eaa1e63cfe" dependencies = [ "anstyle", "difflib", @@ -5638,26 +4967,20 @@ dependencies = [ [[package]] name = "predicates-core" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "727e462b119fe9c93fd0eb1429a5f7647394014cf3c04ab2c0350eeb09095ffa" +checksum = "cad38746f3166b4031b1a0d39ad9f954dd291e7854fcc0eed52ee41a0b50d144" [[package]] name = "predicates-tree" -version = "1.0.12" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72dd2d6d381dfb73a193c7fca536518d7caee39fc8503f74e7dc0be0531b425c" +checksum = "d0de1b847b39c8131db0467e9df1ff60e6d0562ab8e9a16e568ad0fdb372e2f2" dependencies = [ "predicates-core", "termtree", ] -[[package]] -name = "presser" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8cf8e6a8aa66ce33f63993ffc4ea4271eb5b0530a9002db8455ea6050c77bfa" - [[package]] name = "prettyplease" version = "0.2.37" @@ -5665,7 +4988,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] @@ -5703,11 +5026,11 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "3.4.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" dependencies = [ - "toml_edit 0.23.9", + "toml_edit 0.25.4+spec-1.1.0", ] [[package]] @@ -5729,14 +5052,14 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] name = "proc-macro2" -version = "1.0.103" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] @@ -5764,12 +5087,6 @@ dependencies = [ "hex", ] -[[package]] -name = "profiling" -version = "1.0.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773" - [[package]] name = "prometheus" version = "0.13.4" @@ -5799,14 +5116,14 @@ dependencies = [ "memchr", "parking_lot", "protobuf 3.7.2", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] name = "proptest" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bee689443a2bd0a16ab0348b52ee43e3b2d1b1f931c8aa5c9f8de4c86fbe8c40" +checksum = "37566cb3fdacef14c0737f9546df7cfeadbfbc9fef10991038bf5015d0c80532" dependencies = [ "bit-set", "bit-vec", @@ -5814,7 +5131,7 @@ dependencies = [ "num-traits", "rand 0.9.2", "rand_chacha 0.9.0", - "rand_xorshift", + "rand_xorshift 0.4.0", "regex-syntax", "rusty-fork", "tempfile", @@ -5841,7 +5158,7 @@ dependencies = [ "itertools 0.14.0", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] @@ -5887,7 +5204,7 @@ checksum = "7347867d0a7e1208d93b46767be83e2b8f978c3dad35f775ac8d8847551d6fe1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] @@ -5922,9 +5239,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.42" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" dependencies = [ "proc-macro2", ] @@ -5935,6 +5252,12 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + [[package]] name = "radium" version = "0.7.0" @@ -5969,7 +5292,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ "rand_chacha 0.9.0", - "rand_core 0.9.3", + "rand_core 0.9.5", "serde", ] @@ -5990,7 +5313,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] @@ -5999,26 +5322,35 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.16", + "getrandom 0.2.17", ] [[package]] name = "rand_core" -version = "0.9.3" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" dependencies = [ "getrandom 0.3.4", "serde", ] +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core 0.6.4", +] + [[package]] name = "rand_xorshift" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" dependencies = [ - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] @@ -6027,14 +5359,17 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f703f4665700daf5512dcca5f43afa6af89f09db47fb56be587f80636bda2d41" dependencies = [ - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] -name = "range-alloc" -version = "0.1.4" +name = "rapidhash" +version = "4.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d6831663a5098ea164f89cff59c6284e95f4e3c76ce9848d4529f5ccca9bde" +checksum = "b5e48930979c155e2f33aa36ab3119b5ee81332beb6482199a8ecd6029b80b59" +dependencies = [ + "rustversion", +] [[package]] name = "raw-cpuid" @@ -6045,12 +5380,6 @@ dependencies = [ "bitflags", ] -[[package]] -name = "raw-window-handle" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" - [[package]] name = "rayon" version = "1.11.0" @@ -6080,15 +5409,6 @@ dependencies = [ "bitflags", ] -[[package]] -name = "redox_syscall" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f3fe0889e69e2ae9e41f4d6c4c0181701d00e4697b356fb1f74173a5e0ee27" -dependencies = [ - "bitflags", -] - [[package]] name = "ref-cast" version = "1.0.25" @@ -6106,14 +5426,14 @@ checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] name = "regex" -version = "1.12.2" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" dependencies = [ "aho-corasick", "memchr", @@ -6123,9 +5443,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" dependencies = [ "aho-corasick", "memchr", @@ -6134,9 +5454,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.8" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" [[package]] name = "rend" @@ -6147,28 +5467,23 @@ dependencies = [ "bytecheck", ] -[[package]] -name = "renderdoc-sys" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" - [[package]] name = "reqwest" -version = "0.12.25" +version = "0.12.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6eff9328d40131d43bd911d42d79eb6a47312002a4daefc9e37f17e74a7701a" +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" dependencies = [ - "base64 0.22.1", + "base64", "bytes", "encoding_rs", "futures-core", - "h2 0.4.12", - "http 1.4.0", - "http-body 1.0.1", + "futures-util", + "h2", + "http", + "http-body", "http-body-util", - "hyper 1.8.1", - "hyper-rustls 0.27.7", + "hyper", + "hyper-rustls", "hyper-tls", "hyper-util", "js-sys", @@ -6184,19 +5499,37 @@ dependencies = [ "sync_wrapper", "tokio", "tokio-native-tls", + "tokio-util", "tower", "tower-http", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", + "wasm-streams", "web-sys", ] +[[package]] +name = "reqwest-eventsource" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "632c55746dbb44275691640e7b40c907c16a2dc1a5842aa98aaec90da6ec6bde" +dependencies = [ + "eventsource-stream", + "futures-core", + "futures-timer", + "mime", + "nom", + "pin-project-lite", + "reqwest", + "thiserror 1.0.69", +] + [[package]] name = "reth-chainspec" -version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=cfde951976bfa9100a6d9f806e06fb539ae25241#cfde951976bfa9100a6d9f806e06fb539ae25241" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" dependencies = [ "alloy-chains", "alloy-consensus", @@ -6204,9 +5537,9 @@ dependencies = [ "alloy-evm", "alloy-genesis", "alloy-primitives", - "alloy-trie 0.9.1", + "alloy-trie 0.9.4", "auto_impl", - "derive_more 2.1.0", + "derive_more 2.1.1", "reth-ethereum-forks", "reth-network-peers", "reth-primitives-traits", @@ -6215,14 +5548,14 @@ dependencies = [ [[package]] name = "reth-codecs" -version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=cfde951976bfa9100a6d9f806e06fb539ae25241#cfde951976bfa9100a6d9f806e06fb539ae25241" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" dependencies = [ "alloy-consensus", "alloy-eips", "alloy-genesis", "alloy-primitives", - "alloy-trie 0.9.1", + "alloy-trie 0.9.4", "bytes", "modular-bitfield", "op-alloy-consensus", @@ -6233,31 +5566,31 @@ dependencies = [ [[package]] name = "reth-codecs-derive" -version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=cfde951976bfa9100a6d9f806e06fb539ae25241#cfde951976bfa9100a6d9f806e06fb539ae25241" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] name = "reth-consensus" -version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=cfde951976bfa9100a6d9f806e06fb539ae25241#cfde951976bfa9100a6d9f806e06fb539ae25241" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" dependencies = [ "alloy-consensus", "alloy-primitives", "auto_impl", "reth-execution-types", "reth-primitives-traits", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] name = "reth-consensus-common" -version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=cfde951976bfa9100a6d9f806e06fb539ae25241#cfde951976bfa9100a6d9f806e06fb539ae25241" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" dependencies = [ "alloy-consensus", "alloy-eips", @@ -6268,8 +5601,8 @@ dependencies = [ [[package]] name = "reth-db-models" -version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=cfde951976bfa9100a6d9f806e06fb539ae25241#cfde951976bfa9100a6d9f806e06fb539ae25241" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" dependencies = [ "alloy-eips", "alloy-primitives", @@ -6278,19 +5611,19 @@ dependencies = [ [[package]] name = "reth-errors" -version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=cfde951976bfa9100a6d9f806e06fb539ae25241#cfde951976bfa9100a6d9f806e06fb539ae25241" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" dependencies = [ "reth-consensus", "reth-execution-errors", "reth-storage-errors", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] name = "reth-ethereum-consensus" -version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=cfde951976bfa9100a6d9f806e06fb539ae25241#cfde951976bfa9100a6d9f806e06fb539ae25241" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" dependencies = [ "alloy-consensus", "alloy-eips", @@ -6305,21 +5638,20 @@ dependencies = [ [[package]] name = "reth-ethereum-forks" -version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=cfde951976bfa9100a6d9f806e06fb539ae25241#cfde951976bfa9100a6d9f806e06fb539ae25241" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" dependencies = [ "alloy-eip2124", "alloy-hardforks", "alloy-primitives", "auto_impl", "once_cell", - "rustc-hash 2.1.1", ] [[package]] name = "reth-ethereum-primitives" -version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=cfde951976bfa9100a6d9f806e06fb539ae25241#cfde951976bfa9100a6d9f806e06fb539ae25241" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" dependencies = [ "alloy-consensus", "alloy-eips", @@ -6329,22 +5661,21 @@ dependencies = [ "alloy-serde", "reth-codecs", "reth-primitives-traits", - "reth-zstd-compressors", "serde", "serde_with", ] [[package]] name = "reth-evm" -version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=cfde951976bfa9100a6d9f806e06fb539ae25241#cfde951976bfa9100a6d9f806e06fb539ae25241" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" dependencies = [ "alloy-consensus", "alloy-eips", "alloy-evm", "alloy-primitives", "auto_impl", - "derive_more 2.1.0", + "derive_more 2.1.1", "futures-util", "reth-execution-errors", "reth-execution-types", @@ -6357,8 +5688,8 @@ dependencies = [ [[package]] name = "reth-evm-ethereum" -version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=cfde951976bfa9100a6d9f806e06fb539ae25241#cfde951976bfa9100a6d9f806e06fb539ae25241" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" dependencies = [ "alloy-consensus", "alloy-eips", @@ -6377,27 +5708,27 @@ dependencies = [ [[package]] name = "reth-execution-errors" -version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=cfde951976bfa9100a6d9f806e06fb539ae25241#cfde951976bfa9100a6d9f806e06fb539ae25241" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" dependencies = [ "alloy-evm", "alloy-primitives", "alloy-rlp", - "nybbles 0.4.6", + "nybbles 0.4.8", "reth-storage-errors", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] name = "reth-execution-types" -version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=cfde951976bfa9100a6d9f806e06fb539ae25241#cfde951976bfa9100a6d9f806e06fb539ae25241" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" dependencies = [ "alloy-consensus", "alloy-eips", "alloy-evm", "alloy-primitives", - "derive_more 2.1.0", + "derive_more 2.1.1", "reth-ethereum-primitives", "reth-primitives-traits", "reth-trie-common", @@ -6406,21 +5737,20 @@ dependencies = [ [[package]] name = "reth-network-peers" -version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=cfde951976bfa9100a6d9f806e06fb539ae25241#cfde951976bfa9100a6d9f806e06fb539ae25241" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" dependencies = [ "alloy-primitives", "alloy-rlp", - "secp256k1 0.30.0", "serde_with", - "thiserror 2.0.17", + "thiserror 2.0.18", "url", ] [[package]] name = "reth-payload-validator" -version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=cfde951976bfa9100a6d9f806e06fb539ae25241#cfde951976bfa9100a6d9f806e06fb539ae25241" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" dependencies = [ "alloy-consensus", "alloy-rpc-types-engine", @@ -6429,8 +5759,8 @@ dependencies = [ [[package]] name = "reth-primitives-traits" -version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=cfde951976bfa9100a6d9f806e06fb539ae25241#cfde951976bfa9100a6d9f806e06fb539ae25241" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" dependencies = [ "alloy-consensus", "alloy-eips", @@ -6438,37 +5768,37 @@ dependencies = [ "alloy-primitives", "alloy-rlp", "alloy-rpc-types-eth", - "alloy-trie 0.9.1", + "alloy-trie 0.9.4", "auto_impl", "bytes", - "derive_more 2.1.0", + "derive_more 2.1.1", "once_cell", "op-alloy-consensus", "reth-codecs", "revm-bytecode", "revm-primitives", "revm-state", - "secp256k1 0.30.0", + "secp256k1", "serde", "serde_with", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] name = "reth-prune-types" -version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=cfde951976bfa9100a6d9f806e06fb539ae25241#cfde951976bfa9100a6d9f806e06fb539ae25241" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" dependencies = [ "alloy-primitives", - "derive_more 2.1.0", + "derive_more 2.1.1", "strum", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] name = "reth-revm" -version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=cfde951976bfa9100a6d9f806e06fb539ae25241#cfde951976bfa9100a6d9f806e06fb539ae25241" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" dependencies = [ "alloy-primitives", "reth-primitives-traits", @@ -6479,8 +5809,8 @@ dependencies = [ [[package]] name = "reth-stages-types" -version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=cfde951976bfa9100a6d9f806e06fb539ae25241#cfde951976bfa9100a6d9f806e06fb539ae25241" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" dependencies = [ "alloy-primitives", "reth-trie-common", @@ -6488,15 +5818,15 @@ dependencies = [ [[package]] name = "reth-stateless" -version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=cfde951976bfa9100a6d9f806e06fb539ae25241#cfde951976bfa9100a6d9f806e06fb539ae25241" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" dependencies = [ "alloy-consensus", "alloy-genesis", "alloy-primitives", "alloy-rlp", "alloy-rpc-types-debug", - "alloy-trie 0.9.1", + "alloy-trie 0.9.4", "itertools 0.14.0", "k256", "reth-chainspec", @@ -6511,24 +5841,25 @@ dependencies = [ "reth-trie-sparse", "serde", "serde_with", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] name = "reth-static-file-types" -version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=cfde951976bfa9100a6d9f806e06fb539ae25241#cfde951976bfa9100a6d9f806e06fb539ae25241" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" dependencies = [ "alloy-primitives", - "derive_more 2.1.0", + "derive_more 2.1.1", + "fixed-map", "serde", "strum", ] [[package]] name = "reth-storage-api" -version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=cfde951976bfa9100a6d9f806e06fb539ae25241#cfde951976bfa9100a6d9f806e06fb539ae25241" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" dependencies = [ "alloy-consensus", "alloy-eips", @@ -6549,44 +5880,45 @@ dependencies = [ [[package]] name = "reth-storage-errors" -version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=cfde951976bfa9100a6d9f806e06fb539ae25241#cfde951976bfa9100a6d9f806e06fb539ae25241" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" dependencies = [ "alloy-eips", "alloy-primitives", "alloy-rlp", - "derive_more 2.1.0", + "derive_more 2.1.1", "reth-primitives-traits", "reth-prune-types", "reth-static-file-types", "revm-database-interface", - "thiserror 2.0.17", + "revm-state", + "thiserror 2.0.18", ] [[package]] name = "reth-trie-common" -version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=cfde951976bfa9100a6d9f806e06fb539ae25241#cfde951976bfa9100a6d9f806e06fb539ae25241" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" dependencies = [ "alloy-consensus", "alloy-primitives", "alloy-rlp", - "alloy-trie 0.9.1", - "derive_more 2.1.0", + "alloy-trie 0.9.4", + "derive_more 2.1.1", "itertools 0.14.0", - "nybbles 0.4.6", + "nybbles 0.4.8", "reth-primitives-traits", "revm-database", ] [[package]] name = "reth-trie-sparse" -version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=cfde951976bfa9100a6d9f806e06fb539ae25241#cfde951976bfa9100a6d9f806e06fb539ae25241" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" dependencies = [ "alloy-primitives", "alloy-rlp", - "alloy-trie 0.9.1", + "alloy-trie 0.9.4", "auto_impl", "reth-execution-errors", "reth-primitives-traits", @@ -6597,17 +5929,17 @@ dependencies = [ [[package]] name = "reth-zstd-compressors" -version = "1.9.3" -source = "git+https://github.com/paradigmxyz/reth?rev=cfde951976bfa9100a6d9f806e06fb539ae25241#cfde951976bfa9100a6d9f806e06fb539ae25241" +version = "1.10.2" +source = "git+https://github.com/paradigmxyz/reth?tag=v1.10.2#8e3b5e6a99439561b73c5dd31bd3eced2e994d60" dependencies = [ "zstd", ] [[package]] name = "revm" -version = "33.1.0" +version = "34.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c85ed0028f043f87b3c88d4a4cb6f0a76440085523b6a8afe5ff003cf418054" +checksum = "c2aabdebaa535b3575231a88d72b642897ae8106cf6b0d12eafc6bfdf50abfc7" dependencies = [ "revm-bytecode", "revm-context", @@ -6624,9 +5956,9 @@ dependencies = [ [[package]] name = "revm-bytecode" -version = "7.1.1" +version = "8.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2c6b5e6e8dd1e28a4a60e5f46615d4ef0809111c9e63208e55b5c7058200fb0" +checksum = "74d1e5c1eaa44d39d537f668bc5c3409dc01e5c8be954da6c83370bbdf006457" dependencies = [ "bitvec", "phf", @@ -6636,9 +5968,9 @@ dependencies = [ [[package]] name = "revm-context" -version = "12.1.0" +version = "13.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f038f0c9c723393ac897a5df9140b21cfa98f5753a2cb7d0f28fa430c4118abf" +checksum = "892ff3e6a566cf8d72ffb627fdced3becebbd9ba64089c25975b9b028af326a5" dependencies = [ "bitvec", "cfg-if 1.0.4", @@ -6648,14 +5980,13 @@ dependencies = [ "revm-database-interface", "revm-primitives", "revm-state", - "serde", ] [[package]] name = "revm-context-interface" -version = "13.1.0" +version = "14.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "431c9a14e4ef1be41ae503708fd02d974f80ef1f2b6b23b5e402e8d854d1b225" +checksum = "57f61cc6d23678c4840af895b19f8acfbbd546142ec8028b6526c53cc1c16c98" dependencies = [ "alloy-eip2930", "alloy-eip7702", @@ -6664,41 +5995,38 @@ dependencies = [ "revm-database-interface", "revm-primitives", "revm-state", - "serde", ] [[package]] name = "revm-database" -version = "9.0.6" +version = "10.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "980d8d6bba78c5dd35b83abbb6585b0b902eb25ea4448ed7bfba6283b0337191" +checksum = "529528d0b05fe646be86223032c3e77aa8b05caa2a35447d538c55965956a511" dependencies = [ - "alloy-eips", "revm-bytecode", "revm-database-interface", "revm-primitives", "revm-state", - "serde", ] [[package]] name = "revm-database-interface" -version = "8.0.5" +version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cce03e3780287b07abe58faf4a7f5d8be7e81321f93ccf3343c8f7755602bae" +checksum = "b7bf93ac5b91347c057610c0d96e923db8c62807e03f036762d03e981feddc1d" dependencies = [ "auto_impl", "either", "revm-primitives", "revm-state", - "serde", + "thiserror 2.0.18", ] [[package]] name = "revm-handler" -version = "14.1.0" +version = "15.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d44f8f6dbeec3fecf9fe55f78ef0a758bdd92ea46cd4f1ca6e2a946b32c367f3" +checksum = "0cd0e43e815a85eded249df886c4badec869195e70cdd808a13cfca2794622d2" dependencies = [ "auto_impl", "derive-where", @@ -6710,14 +6038,13 @@ dependencies = [ "revm-precompile", "revm-primitives", "revm-state", - "serde", ] [[package]] name = "revm-inspector" -version = "14.1.0" +version = "15.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5617e49216ce1ca6c8826bcead0386bc84f49359ef67cde6d189961735659f93" +checksum = "4f3ccad59db91ef93696536a0dbaf2f6f17cfe20d4d8843ae118edb7e97947ef" dependencies = [ "auto_impl", "either", @@ -6727,28 +6054,25 @@ dependencies = [ "revm-interpreter", "revm-primitives", "revm-state", - "serde", - "serde_json", ] [[package]] name = "revm-interpreter" -version = "31.1.0" +version = "32.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26ec36405f7477b9dccdc6caa3be19adf5662a7a0dffa6270cdb13a090c077e5" +checksum = "11406408597bc249392d39295831c4b641b3a6f5c471a7c41104a7a1e3564c07" dependencies = [ "revm-bytecode", "revm-context-interface", "revm-primitives", "revm-state", - "serde", ] [[package]] name = "revm-precompile" -version = "31.0.0" +version = "32.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a62958af953cc4043e93b5be9b8497df84cc3bd612b865c49a7a7dfa26a84e2" +checksum = "e2ec11f45deec71e4945e1809736bb20d454285f9167ab53c5159dae1deb603f" dependencies = [ "ark-bls12-381", "ark-bn254", @@ -6757,22 +6081,19 @@ dependencies = [ "ark-serialize 0.5.0", "arrayref", "aurora-engine-modexp", - "c-kzg", "cfg-if 1.0.4", "k256", "p256", "revm-primitives", "ripemd", - "rug", - "secp256k1 0.31.1", "sha2", ] [[package]] name = "revm-primitives" -version = "21.0.2" +version = "22.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29e161db429d465c09ba9cbff0df49e31049fe6b549e28eb0b7bd642fcbd4412" +checksum = "4bcfb5ce6cf18b118932bcdb7da05cd9c250f2cb9f64131396b55f3fe3537c35" dependencies = [ "alloy-primitives", "num_enum", @@ -6782,10 +6103,11 @@ dependencies = [ [[package]] name = "revm-state" -version = "8.1.1" +version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d8be953b7e374dbdea0773cf360debed8df394ea8d82a8b240a6b5da37592fc" +checksum = "311720d4f0f239b041375e7ddafdbd20032a33b7bae718562ea188e188ed9fd3" dependencies = [ + "alloy-eip7928", "bitflags", "revm-bytecode", "revm-primitives", @@ -6810,7 +6132,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if 1.0.4", - "getrandom 0.2.16", + "getrandom 0.2.17", "libc", "untrusted", "windows-sys 0.52.0", @@ -6827,14 +6149,14 @@ dependencies = [ [[package]] name = "rkyv" -version = "0.8.12" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35a640b26f007713818e9a9b65d34da1cf58538207b052916a83d80e43f3ffa4" +checksum = "1a30e631b7f4a03dee9056b8ef6982e8ba371dd5bedb74d3ec86df4499132c70" dependencies = [ "bytecheck", "bytes", - "hashbrown 0.15.5", - "indexmap 2.12.1", + "hashbrown 0.16.1", + "indexmap 2.13.0", "munge", "ptr_meta", "rancor", @@ -6846,13 +6168,13 @@ dependencies = [ [[package]] name = "rkyv_derive" -version = "0.8.12" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd83f5f173ff41e00337d97f6572e416d022ef8a19f371817259ae960324c482" +checksum = "8100bb34c0a1d0f907143db3149e6b4eea3c33b9ee8b189720168e818303986f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] @@ -6887,32 +6209,29 @@ dependencies = [ ] [[package]] -name = "rtoolbox" -version = "0.0.3" +name = "rpds" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7cc970b249fbe527d6e02e0a227762c9108b2f49d81094fe357ffc6d14d7f6f" +checksum = "b4ef5140bcb576bfd6d56cd2de709a7d17851ac1f3805e67fe9d99e42a11821f" dependencies = [ - "libc", - "windows-sys 0.52.0", + "archery", ] [[package]] -name = "rug" -version = "1.28.1" +name = "rtoolbox" +version = "0.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de190ec858987c79cad4da30e19e546139b3339331282832af004d0ea7829639" +checksum = "a7cc970b249fbe527d6e02e0a227762c9108b2f49d81094fe357ffc6d14d7f6f" dependencies = [ - "az", - "gmp-mpfr-sys", "libc", - "libm", + "windows-sys 0.52.0", ] [[package]] name = "ruint" -version = "1.17.0" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a68df0380e5c9d20ce49534f292a36a7514ae21350726efe1865bdb1fa91d278" +checksum = "c141e807189ad38a07276942c6623032d3753c8859c146104ac2e4d68865945a" dependencies = [ "alloy-rlp", "ark-ff 0.3.0", @@ -6943,10 +6262,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" [[package]] -name = "rustc-hash" -version = "1.1.0" +name = "rust_eth_kzg" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +checksum = "1522b7a740cd7f5bc52ea49863618511c8de138dcdf3f8a80b15b3f764942a5b" +dependencies = [ + "eip4844", + "ekzg-bls12-381", + "ekzg-erasure-codes", + "ekzg-multi-open", + "ekzg-serialization", + "ekzg-trusted-setup", + "hex", + "serde", + "serde_json", +] [[package]] name = "rustc-hash" @@ -6993,100 +6323,57 @@ dependencies = [ [[package]] name = "rustix" -version = "1.1.2" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ "bitflags", "errno", "libc", - "linux-raw-sys 0.11.0", + "linux-raw-sys 0.12.1", "windows-sys 0.61.2", ] [[package]] name = "rustls" -version = "0.21.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" -dependencies = [ - "log", - "ring", - "rustls-webpki 0.101.7", - "sct", -] - -[[package]] -name = "rustls" -version = "0.23.31" +version = "0.23.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0ebcbd2f03de0fc1122ad9bb24b127a5a6cd51d72604a3f3c50ac459762b6cc" +checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" dependencies = [ "aws-lc-rs", "once_cell", "rustls-pki-types", - "rustls-webpki 0.103.4", + "rustls-webpki", "subtle", "zeroize", ] [[package]] name = "rustls-native-certs" -version = "0.6.3" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" +checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" dependencies = [ "openssl-probe", - "rustls-pemfile", + "rustls-pki-types", "schannel", - "security-framework 2.11.1", -] - -[[package]] -name = "rustls-native-certs" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9980d917ebb0c0536119ba501e90834767bffc3d60641457fd84a1f3fd337923" -dependencies = [ - "openssl-probe", - "rustls-pki-types", - "schannel", - "security-framework 3.5.1", -] - -[[package]] -name = "rustls-pemfile" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" -dependencies = [ - "base64 0.21.7", + "security-framework", ] [[package]] name = "rustls-pki-types" -version = "1.13.1" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "708c0f9d5f54ba0272468c1d306a52c495b31fa155e91bc25371e6df7996908c" +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" dependencies = [ "zeroize", ] [[package]] name = "rustls-webpki" -version = "0.101.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" -dependencies = [ - "ring", - "untrusted", -] - -[[package]] -name = "rustls-webpki" -version = "0.103.4" +version = "0.103.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc" +checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" dependencies = [ "aws-lc-rs", "ring", @@ -7114,9 +6401,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.20" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" [[package]] name = "safe_arch" @@ -7127,6 +6414,12 @@ dependencies = [ "bytemuck", ] +[[package]] +name = "safe_arith" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b147bb6111014916d3ef9d4c85173124a8e12193a67f6176d67244afd558d6c1" + [[package]] name = "salsa20" version = "0.10.2" @@ -7168,9 +6461,9 @@ dependencies = [ [[package]] name = "schemars" -version = "1.1.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9558e172d4e8533736ba97870c4b2cd63f84b382a3d6eb063da41b91cce17289" +checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc" dependencies = [ "dyn-clone", "ref-cast", @@ -7195,16 +6488,6 @@ dependencies = [ "sha2", ] -[[package]] -name = "sct" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" -dependencies = [ - "ring", - "untrusted", -] - [[package]] name = "sec1" version = "0.7.3" @@ -7228,21 +6511,10 @@ checksum = "b50c5943d326858130af85e049f2661ba3c78b26589b8ab98e65e80ae44a1252" dependencies = [ "bitcoin_hashes", "rand 0.8.5", - "secp256k1-sys 0.10.1", + "secp256k1-sys", "serde", ] -[[package]] -name = "secp256k1" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c3c81b43dc2d8877c216a3fccf76677ee1ebccd429566d3e67447290d0c42b2" -dependencies = [ - "bitcoin_hashes", - "rand 0.9.2", - "secp256k1-sys 0.11.0", -] - [[package]] name = "secp256k1-sys" version = "0.10.1" @@ -7252,33 +6524,11 @@ dependencies = [ "cc", ] -[[package]] -name = "secp256k1-sys" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcb913707158fadaf0d8702c2db0e857de66eb003ccfdda5924b5f5ac98efb38" -dependencies = [ - "cc", -] - -[[package]] -name = "security-framework" -version = "2.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" -dependencies = [ - "bitflags", - "core-foundation 0.9.4", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - [[package]] name = "security-framework" -version = "3.5.1" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" dependencies = [ "bitflags", "core-foundation 0.10.1", @@ -7289,9 +6539,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.15.0" +version = "2.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" dependencies = [ "core-foundation-sys", "libc", @@ -7311,10 +6561,6 @@ name = "semver" version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" -dependencies = [ - "serde", - "serde_core", -] [[package]] name = "semver-parser" @@ -7325,12 +6571,6 @@ 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.228" @@ -7367,21 +6607,20 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] name = "serde_json" -version = "1.0.145" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ - "indexmap 2.12.1", "itoa", "memchr", - "ryu", "serde", "serde_core", + "zmij", ] [[package]] @@ -7418,17 +6657,17 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.16.1" +version = "3.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fa237f2807440d238e0364a218270b98f767a00d3dada77b1c53ae88940e2e7" +checksum = "381b283ce7bc6b476d903296fb59d0d36633652b633b27f64db4fb46dcbfc3b9" dependencies = [ - "base64 0.22.1", + "base64", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.12.1", + "indexmap 2.13.0", "schemars 0.9.0", - "schemars 1.1.0", + "schemars 1.2.1", "serde_core", "serde_json", "serde_with_macros", @@ -7437,14 +6676,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.16.1" +version = "3.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52a8e3ca0ca629121f70ab50f95249e5a6f925cc0f6ffe8256c45b728875706c" +checksum = "a6d4e30573c8cb306ed6ab1dca8423eec9a463ea0e155f45399455e0368b27e0" dependencies = [ "darling 0.21.3", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] @@ -7453,7 +6692,7 @@ version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.12.1", + "indexmap 2.13.0", "itoa", "ryu", "serde", @@ -7504,9 +6743,9 @@ dependencies = [ [[package]] name = "sha3-asm" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28efc5e327c837aa837c59eae585fc250715ef939ac32881bcc11677cd02d46" +checksum = "b31139435f327c93c6038ed350ae4588e2c70a13d50599509fee6349967ba35a" dependencies = [ "cc", "cfg-if 1.0.4", @@ -7529,10 +6768,11 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" -version = "1.4.7" +version = "1.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7664a098b8e616bdfcc2dc0e9ac44eb231eedf41db4e9fe95d8d32ec728dedad" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" dependencies = [ + "errno", "libc", ] @@ -7546,12 +6786,6 @@ dependencies = [ "rand_core 0.6.4", ] -[[package]] -name = "simd-adler32" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" - [[package]] name = "simdutf8" version = "0.1.5" @@ -7560,41 +6794,114 @@ checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e" [[package]] name = "simple_asn1" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "297f631f50729c8c99b84667867963997ec0b50f32b2a7dbcab828ef0541e8bb" +checksum = "0d585997b0ac10be3c5ee635f1bab02d512760d14b7c468801ac8a01d9ae5f1d" dependencies = [ "num-bigint 0.4.6", "num-traits", - "thiserror 2.0.17", + "thiserror 2.0.18", "time", ] [[package]] name = "siphasher" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" +checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" [[package]] name = "sketches-ddsketch" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1e9a774a6c28142ac54bb25d25562e6bcf957493a184f15ad4eebccb23e410a" +checksum = "0c6f73aeb92d671e0cc4dca167e59b2deb6387c375391bc99ee743f326994a2b" [[package]] name = "slab" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] -name = "slotmap" -version = "1.1.1" +name = "slop-algebra" +version = "6.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdd58c3c93c3d278ca835519292445cb4b0d4dc59ccfdf7ceadaab3f8aeb4038" +checksum = "691beea96fd18d4881f9ca1cb4e58194dac6366f24956a2fdae00c8ee382a0c9" dependencies = [ - "version_check", + "itertools 0.14.0", + "p3-field", + "serde", +] + +[[package]] +name = "slop-bn254" +version = "6.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1852499c245f7f3dec23408b4930b3ea7570ae914b9c31f12950ac539d85ee" +dependencies = [ + "ff 0.13.1", + "p3-bn254-fr", + "serde", + "slop-algebra", + "slop-challenger", + "slop-poseidon2", + "slop-symmetric", + "zkhash", +] + +[[package]] +name = "slop-challenger" +version = "6.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4349af93602f3876a3eda948a74d9d16d774c401dfe25f41a45ffd84f230bc1" +dependencies = [ + "futures", + "p3-challenger", + "serde", + "slop-algebra", + "slop-symmetric", +] + +[[package]] +name = "slop-koala-bear" +version = "6.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "574784c044d11cf9d8238dc18bce9b897bc34d0fb1daaceafd75ebb400084016" +dependencies = [ + "lazy_static", + "p3-koala-bear", + "serde", + "slop-algebra", + "slop-challenger", + "slop-poseidon2", + "slop-symmetric", +] + +[[package]] +name = "slop-poseidon2" +version = "6.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5af617970b63e8d7199204bc02996745b6c35c39f2b513a118c62c7b1a0b2f1b" +dependencies = [ + "p3-poseidon2", +] + +[[package]] +name = "slop-primitives" +version = "6.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58d82c53508f3ebff8acdabb5db2584f37686257a2549a17c977cf30cd9e24e6" +dependencies = [ + "slop-algebra", +] + +[[package]] +name = "slop-symmetric" +version = "6.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15acfa7f567ffa4f36de134492632a397c33fa6af2e48894e50978b52eeeb871" +dependencies = [ + "p3-symmetric", ] [[package]] @@ -7614,19 +6921,9 @@ checksum = "1b6b67fb9a61334225b5b790716f609cd58395f895b3fe8b328786812a40bc3b" [[package]] name = "socket2" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e22376abed350d73dd1cd119b57ffccad95b4e585a7cda43e286245ce23c0678" -dependencies = [ - "libc", - "windows-sys 0.52.0", -] - -[[package]] -name = "socket2" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" +checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0" dependencies = [ "libc", "windows-sys 0.60.2", @@ -7634,9 +6931,9 @@ dependencies = [ [[package]] name = "sp1-lib" -version = "5.2.4" +version = "6.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b73b8ff343f2405d5935440e56b7aba5cee6d87303f0051974cbd6f5de502f57" +checksum = "517e820776910468611149dda66791bdb700c1b7d68b96f0ea2e604f00ad8771" dependencies = [ "bincode 1.3.3", "serde", @@ -7645,34 +6942,38 @@ dependencies = [ [[package]] name = "sp1-primitives" -version = "5.2.4" +version = "6.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e69a03098f827102c54c31a5e57280eb45b2c085de433b3f702e4f9e3ec1641" +checksum = "0f395525b4fc46d37136f45be264c81718a67f4409c14c547ff491a263e019e7" dependencies = [ "bincode 1.3.3", "blake3", - "cfg-if 1.0.4", + "elf", "hex", + "itertools 0.14.0", "lazy_static", "num-bigint 0.4.6", - "p3-baby-bear", - "p3-field", - "p3-poseidon2", - "p3-symmetric", "serde", "sha2", + "slop-algebra", + "slop-bn254", + "slop-challenger", + "slop-koala-bear", + "slop-poseidon2", + "slop-primitives", + "slop-symmetric", ] [[package]] name = "sp1_bls12_381" -version = "0.8.0-sp1-5.0.0" +version = "0.8.0-sp1-6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac255e1704ebcdeec5e02f6a0ebc4d2e9e6b802161938330b6810c13a610c583" +checksum = "f23e41cd36168cc2e51e5d3e35ff0c34b204d945769a65591a76286d04b51e43" dependencies = [ "cfg-if 1.0.4", - "ff", - "group", - "pairing", + "ff 0.13.1", + "group 0.13.0", + "pairing 0.23.0", "rand_core 0.6.4", "sp1-lib", "subtle", @@ -7681,11 +6982,11 @@ dependencies = [ [[package]] name = "sparsestate" version = "0.1.0" -source = "git+https://github.com/eth-act/zkvm-ethereum-mpt.git?tag=v0.4.0#d4d8f968c183aedc23100c3a5634dee14c320757" +source = "git+https://github.com/eth-act/zkvm-ethereum-mpt.git?rev=a1e44638c49c4e16751a0b915593fce98ab6bdef#a1e44638c49c4e16751a0b915593fce98ab6bdef" dependencies = [ "alloy-primitives", "alloy-rlp", - "alloy-trie 0.9.1", + "alloy-trie 0.9.4", "mpt", "reth-errors", "reth-revm", @@ -7702,7 +7003,7 @@ dependencies = [ "futures", "pin-project-lite", "spawned-rt", - "thiserror 2.0.17", + "thiserror 2.0.18", "tracing", ] @@ -7717,7 +7018,7 @@ dependencies = [ "tokio-stream", "tokio-util", "tracing", - "tracing-subscriber 0.3.22", + "tracing-subscriber", ] [[package]] @@ -7726,15 +7027,6 @@ version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" -[[package]] -name = "spirv" -version = "0.3.0+sdk-1.3.268.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844" -dependencies = [ - "bitflags", -] - [[package]] name = "spki" version = "0.7.3" @@ -7752,12 +7044,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75b55bedc9a18ed2860a46d6beb4f4082416ee1d60be0cc364cebdcdddc7afd4" dependencies = [ "ethereum_serde_utils", - "ethereum_ssz", + "ethereum_ssz 0.9.1", "itertools 0.13.0", "serde", "serde_derive", "smallvec", - "tree_hash", + "tree_hash 0.10.0", + "typenum", +] + +[[package]] +name = "ssz_types" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fc20a89bab2dabeee65e9c9eb96892dc222c23254b401e1319b85efd852fa31" +dependencies = [ + "context_deserialize", + "educe", + "ethereum_serde_utils", + "ethereum_ssz 0.10.1", + "itertools 0.14.0", + "serde", + "serde_derive", + "smallvec", + "tree_hash 0.12.1", "typenum", ] @@ -7769,28 +7079,28 @@ checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "stateless-validator-common" -version = "0.4.0" -source = "git+https://github.com/eth-act/ere-guests?tag=v0.4.0#cc921dcd2978a31ee5e8bb45680396f04549b540" +version = "0.5.0" +source = "git+https://github.com/eth-act/ere-guests?tag=v0.6.0#64c94bb3da631101a6cb2f276c89392cb7c3426f" dependencies = [ "alloy-eips", "alloy-primitives", "anyhow", - "ethereum_ssz", - "ethereum_ssz_derive", + "ethereum_ssz 0.9.1", + "ethereum_ssz_derive 0.9.1", "rkyv", "serde", "serde_with", "sha2", - "ssz_types", - "tree_hash", - "tree_hash_derive", + "ssz_types 0.11.0", + "tree_hash 0.10.0", + "tree_hash_derive 0.10.0", "typenum", ] [[package]] name = "stateless-validator-ethrex" -version = "0.4.0" -source = "git+https://github.com/eth-act/ere-guests?tag=v0.4.0#cc921dcd2978a31ee5e8bb45680396f04549b540" +version = "0.5.0" +source = "git+https://github.com/eth-act/ere-guests?tag=v0.6.0#64c94bb3da631101a6cb2f276c89392cb7c3426f" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7799,7 +7109,7 @@ dependencies = [ "anyhow", "bytes", "ere-io", - "ere-zkvm-interface 0.0.16", + "ere-zkvm-interface", "ethrex-common", "ethrex-rlp", "ethrex-rpc", @@ -7814,8 +7124,8 @@ dependencies = [ [[package]] name = "stateless-validator-reth" -version = "0.4.0" -source = "git+https://github.com/eth-act/ere-guests?tag=v0.4.0#cc921dcd2978a31ee5e8bb45680396f04549b540" +version = "0.5.0" +source = "git+https://github.com/eth-act/ere-guests?tag=v0.6.0#64c94bb3da631101a6cb2f276c89392cb7c3426f" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7825,8 +7135,8 @@ dependencies = [ "alloy-rpc-types-engine", "anyhow", "ere-io", - "ere-zkvm-interface 0.0.16", - "ethereum_ssz", + "ere-zkvm-interface", + "ethereum_ssz 0.9.1", "guest", "once_cell", "reth-chainspec", @@ -7839,10 +7149,10 @@ dependencies = [ "serde_with", "sha2", "sparsestate", - "ssz_types", + "ssz_types 0.11.0", "stateless-validator-common", - "tree_hash", - "tree_hash_derive", + "tree_hash 0.10.0", + "tree_hash_derive 0.10.0", ] [[package]] @@ -7875,7 +7185,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] @@ -7884,6 +7194,30 @@ version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" +[[package]] +name = "superstruct" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bae4a9ccd7882533c1f210e400763ec6ee64c390fc12248c238276281863719e" +dependencies = [ + "darling 0.23.0", + "itertools 0.14.0", + "proc-macro2", + "quote", + "smallvec", + "syn 2.0.117", +] + +[[package]] +name = "swap_or_not_shuffle" +version = "0.2.0" +source = "git+https://github.com/sigp/lighthouse?branch=unstable#9c4715c251ea19b2cc4c7688916b5cddfa2b1778" +dependencies = [ + "alloy-primitives", + "ethereum_hashing 0.8.0", + "fixed_bytes", +] + [[package]] name = "syn" version = "1.0.109" @@ -7897,9 +7231,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.111" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -7908,14 +7242,14 @@ dependencies = [ [[package]] name = "syn-solidity" -version = "1.4.1" +version = "1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff790eb176cc81bb8936aed0f7b9f14fc4670069a2d371b3e3b0ecce908b2cb3" +checksum = "53f425ae0b12e2f5ae65542e00898d500d4d318b4baf09f40fd0d410454e9947" dependencies = [ "paste", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] @@ -7935,28 +7269,14 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", -] - -[[package]] -name = "sysinfo" -version = "0.37.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16607d5caffd1c07ce073528f9ed972d88db15dd44023fa57142963be3feb11f" -dependencies = [ - "libc", - "memchr", - "ntapi", - "objc2-core-foundation", - "objc2-io-kit", - "windows 0.61.3", + "syn 2.0.117", ] [[package]] name = "system-configuration" -version = "0.6.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" +checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" dependencies = [ "bitflags", "core-foundation 0.9.4", @@ -7979,45 +7299,34 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" -[[package]] -name = "tar" -version = "0.4.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d863878d212c87a19c1a610eb53bb01fe12951c0501cf5a0d65f724914a667a" -dependencies = [ - "filetime", - "libc", - "xattr", -] - [[package]] name = "tempfile" -version = "3.23.0" +version = "3.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" +checksum = "82a72c767771b47409d2345987fda8628641887d5466101319899796367354a0" dependencies = [ "fastrand", - "getrandom 0.3.4", + "getrandom 0.4.2", "once_cell", - "rustix 1.1.2", + "rustix 1.1.4", "windows-sys 0.61.2", ] -[[package]] -name = "termcolor" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" -dependencies = [ - "winapi-util", -] - [[package]] name = "termtree" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f50febec83f5ee1df3015341d8bd429f2d1cc62bcba7ea2076759d315084683" +[[package]] +name = "test_random_derive" +version = "0.2.0" +source = "git+https://github.com/sigp/lighthouse?branch=unstable#9c4715c251ea19b2cc4c7688916b5cddfa2b1778" +dependencies = [ + "quote", + "syn 2.0.117", +] + [[package]] name = "thiserror" version = "1.0.69" @@ -8029,11 +7338,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.17" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" dependencies = [ - "thiserror-impl 2.0.17", + "thiserror-impl 2.0.18", ] [[package]] @@ -8044,18 +7353,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] name = "thiserror-impl" -version = "2.0.17" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] @@ -8078,30 +7387,30 @@ dependencies = [ [[package]] name = "time" -version = "0.3.44" +version = "0.3.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" dependencies = [ "deranged", "itoa", "num-conv", "powerfmt", - "serde", + "serde_core", "time-core", "time-macros", ] [[package]] name = "time-core" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" [[package]] name = "time-macros" -version = "0.2.24" +version = "0.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" +checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" dependencies = [ "num-conv", "time-core", @@ -8143,9 +7452,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.48.0" +version = "1.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" +checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d" dependencies = [ "bytes", "libc", @@ -8153,30 +7462,20 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.6.1", + "socket2", "tokio-macros", "windows-sys 0.61.2", ] -[[package]] -name = "tokio-io-timeout" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bd86198d9ee903fedd2f9a2e72014287c0d9167e4ae43b5853007205dda1b76" -dependencies = [ - "pin-project-lite", - "tokio", -] - [[package]] name = "tokio-macros" -version = "2.6.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" +checksum = "5c55a2eff8b69ce66c84f85e1da1c233edc36ceb85a2058d11b0d6a3c7e7569c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] @@ -8189,31 +7488,21 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-rustls" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" -dependencies = [ - "rustls 0.21.12", - "tokio", -] - [[package]] name = "tokio-rustls" version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ - "rustls 0.23.31", + "rustls", "tokio", ] [[package]] name = "tokio-stream" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" +checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" dependencies = [ "futures-core", "pin-project-lite", @@ -8221,22 +7510,6 @@ 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 0.23.31", - "rustls-pki-types", - "tokio", - "tokio-rustls 0.26.4", - "tungstenite 0.26.2", - "webpki-roots 0.26.11", -] - [[package]] name = "tokio-tungstenite" version = "0.28.0" @@ -8246,21 +7519,20 @@ dependencies = [ "futures-util", "log", "tokio", - "tungstenite 0.28.0", + "tungstenite", ] [[package]] name = "tokio-util" -version = "0.7.17" +version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" dependencies = [ "bytes", "futures-core", "futures-sink", "futures-util", "pin-project-lite", - "slab", "tokio", ] @@ -8274,37 +7546,46 @@ dependencies = [ ] [[package]] -name = "toml_edit" -version = "0.23.9" +name = "toml_datetime" +version = "1.0.0+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d7cbc3b4b49633d57a0509303158ca50de80ae32c265093b24c414705807832" +checksum = "32c2555c699578a4f59f0cc68e5116c8d7cabbd45e1409b989d4be085b53f13e" dependencies = [ - "indexmap 2.12.1", - "toml_datetime", - "toml_parser", - "winnow", + "serde_core", ] [[package]] name = "toml_edit" -version = "0.24.0+spec-1.1.0" +version = "0.24.1+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c740b185920170a6d9191122cafef7010bd6270a3824594bff6784c04d7f09e" +checksum = "01f2eadbbc6b377a847be05f60791ef1058d9f696ecb51d2c07fe911d8569d8e" dependencies = [ - "indexmap 2.12.1", + "indexmap 2.13.0", "serde_core", "serde_spanned", - "toml_datetime", + "toml_datetime 0.7.5+spec-1.1.0", "toml_parser", "toml_writer", "winnow", ] [[package]] -name = "toml_parser" -version = "1.0.6+spec-1.1.0" +name = "toml_edit" +version = "0.25.4+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44" +checksum = "7193cbd0ce53dc966037f54351dbbcf0d5a642c7f0038c382ef9e677ce8c13f2" +dependencies = [ + "indexmap 2.13.0", + "toml_datetime 1.0.0+spec-1.1.0", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.0.9+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "702d4415e08923e7e1ef96cd5727c0dfed80b4d2fa25db9647fe5eb6f7c5a4c4" dependencies = [ "winnow", ] @@ -8317,9 +7598,9 @@ checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607" [[package]] name = "tower" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" dependencies = [ "futures-core", "futures-util", @@ -8340,8 +7621,8 @@ dependencies = [ "bitflags", "bytes", "futures-util", - "http 1.4.0", - "http-body 1.0.1", + "http", + "http-body", "http-body-util", "iri-string", "pin-project-lite", @@ -8365,9 +7646,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.43" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d15d90a0b5c19378952d479dc858407149d7bb45a14de0142f6c534b16fc647" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ "log", "pin-project-lite", @@ -8383,14 +7664,14 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] name = "tracing-core" -version = "0.1.35" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a04e24fab5c89c6a36eb8558c9656f30d81de51dfa4d3b45f26b21d61fa0a6c" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ "once_cell", "valuable", @@ -8407,15 +7688,6 @@ dependencies = [ "tracing-core", ] -[[package]] -name = "tracing-subscriber" -version = "0.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" -dependencies = [ - "tracing-core", -] - [[package]] name = "tracing-subscriber" version = "0.3.22" @@ -8441,8 +7713,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee44f4cef85f88b4dea21c0b1f58320bdf35715cf56d840969487cff00613321" dependencies = [ "alloy-primitives", - "ethereum_hashing", - "ethereum_ssz", + "ethereum_hashing 0.7.0", + "ethereum_ssz 0.9.1", + "smallvec", + "typenum", +] + +[[package]] +name = "tree_hash" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fd51aa83d2eb83b04570808430808b5d24fdbf479a4d5ac5dee4a2e2dd2be4" +dependencies = [ + "alloy-primitives", + "ethereum_hashing 0.8.0", + "ethereum_ssz 0.10.1", "smallvec", "typenum", ] @@ -8456,34 +7741,37 @@ dependencies = [ "darling 0.20.11", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] -name = "try-lock" -version = "0.2.5" +name = "tree_hash_derive" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +checksum = "8840ad4d852e325d3afa7fde8a50b2412f89dce47d7eb291c0cc7f87cd040f38" +dependencies = [ + "darling 0.23.0", + "proc-macro2", + "quote", + "syn 2.0.117", +] [[package]] -name = "tungstenite" -version = "0.26.2" +name = "triomphe" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4793cb5e56680ecbb1d843515b23b6de9a75eb04b66643e256a396d43be33c13" +checksum = "dd69c5aa8f924c7519d6372789a74eac5b94fb0f8fcf0d4a97eb0bfc3e785f39" dependencies = [ - "bytes", - "data-encoding", - "http 1.4.0", - "httparse", - "log", - "rand 0.9.2", - "rustls 0.23.31", - "rustls-pki-types", - "sha1", - "thiserror 2.0.17", - "utf-8", + "serde", + "stable_deref_trait", ] +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + [[package]] name = "tungstenite" version = "0.28.0" @@ -8492,12 +7780,12 @@ checksum = "8628dcc84e5a09eb3d8423d6cb682965dea9133204e8fb3efee74c2a0c259442" dependencies = [ "bytes", "data-encoding", - "http 1.4.0", + "http", "httparse", "log", "rand 0.9.2", "sha1", - "thiserror 2.0.17", + "thiserror 2.0.18", "utf-8", ] @@ -8511,14 +7799,14 @@ dependencies = [ "async-trait", "axum", "futures", - "http 1.4.0", + "http", "http-body-util", - "hyper 1.8.1", + "hyper", "prost", "reqwest", "serde", "serde_json", - "thiserror 2.0.17", + "thiserror 2.0.18", "tokio", "tower", "url", @@ -8530,6 +7818,53 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" +[[package]] +name = "types" +version = "0.2.1" +source = "git+https://github.com/sigp/lighthouse?branch=unstable#9c4715c251ea19b2cc4c7688916b5cddfa2b1778" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "bls", + "compare_fields", + "context_deserialize", + "educe", + "eth2_interop_keypairs", + "ethereum_hashing 0.8.0", + "ethereum_serde_utils", + "ethereum_ssz 0.10.1", + "ethereum_ssz_derive 0.10.1", + "fixed_bytes", + "hex", + "int_to_bytes", + "itertools 0.14.0", + "kzg", + "maplit", + "merkle_proof", + "metastruct", + "milhouse", + "parking_lot", + "rand 0.9.2", + "rand_xorshift 0.4.0", + "rayon", + "regex", + "rpds", + "safe_arith", + "serde", + "serde_json", + "serde_yaml", + "smallvec", + "ssz_types 0.14.0", + "superstruct", + "swap_or_not_shuffle", + "tempfile", + "test_random_derive", + "tracing", + "tree_hash 0.12.1", + "tree_hash_derive 0.12.1", + "typenum", +] + [[package]] name = "ucd-trie" version = "0.1.7" @@ -8568,9 +7903,9 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicode-ident" -version = "1.0.22" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "unicode-segmentation" @@ -8578,28 +7913,12 @@ version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" -[[package]] -name = "unicode-width" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" - [[package]] name = "unicode-xid" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" -[[package]] -name = "universal-hash" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" -dependencies = [ - "crypto-common", - "subtle", -] - [[package]] name = "unsafe-libyaml" version = "0.2.11" @@ -8620,14 +7939,15 @@ checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae" [[package]] name = "url" -version = "2.5.7" +version = "2.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" dependencies = [ "form_urlencoded", "idna", "percent-encoding", "serde", + "serde_derive", ] [[package]] @@ -8650,13 +7970,12 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.19.0" +version = "1.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a" +checksum = "a68d3c8f01c0cfa54a75291d83601161799e4a89a39e0929f4b0354d88757a37" dependencies = [ - "getrandom 0.3.4", + "getrandom 0.4.2", "js-sys", - "serde_core", "wasm-bindgen", ] @@ -8672,6 +7991,12 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + [[package]] name = "version_check" version = "0.9.5" @@ -8714,18 +8039,27 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasip2" -version = "1.0.1+wasi-0.2.4" +version = "1.0.2+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" dependencies = [ "wit-bindgen", ] [[package]] name = "wasm-bindgen" -version = "0.2.106" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd" +checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e" dependencies = [ "cfg-if 1.0.4", "once_cell", @@ -8736,11 +8070,12 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.56" +version = "0.4.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836d9622d604feee9e5de25ac10e3ea5f2d65b41eac0d9ce72eb5deae707ce7c" +checksum = "e9c5522b3a28661442748e09d40924dfb9ca614b21c00d3fd135720e48b67db8" dependencies = [ "cfg-if 1.0.4", + "futures-util", "js-sys", "once_cell", "wasm-bindgen", @@ -8749,9 +8084,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.106" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3" +checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -8759,229 +8094,81 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.106" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40" +checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3" dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.106" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4" +checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16" dependencies = [ "unicode-ident", ] [[package]] -name = "wasmtimer" -version = "0.4.3" +name = "wasm-encoder" +version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c598d6b99ea013e35844697fc4670d08339d5cda15588f193c6beedd12f644b" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" dependencies = [ - "futures", - "js-sys", - "parking_lot", - "pin-utils", - "slab", - "wasm-bindgen", + "leb128fmt", + "wasmparser", ] [[package]] -name = "web-sys" -version = "0.3.83" +name = "wasm-metadata" +version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "webpki-roots" -version = "0.26.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" -dependencies = [ - "webpki-roots 1.0.5", -] - -[[package]] -name = "webpki-roots" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12bed680863276c63889429bfd6cab3b99943659923822de1c8a39c49e4d722c" -dependencies = [ - "rustls-pki-types", + "anyhow", + "indexmap 2.13.0", + "wasm-encoder", + "wasmparser", ] [[package]] -name = "wgpu" -version = "27.0.1" +name = "wasm-streams" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfe68bac7cde125de7a731c3400723cadaaf1703795ad3f4805f187459cd7a77" +checksum = "15053d8d85c7eccdbefef60f06769760a563c7f0a9d6902a13d35c7800b0ad65" dependencies = [ - "arrayvec", - "bitflags", - "cfg-if 1.0.4", - "cfg_aliases", - "document-features", - "hashbrown 0.16.1", + "futures-util", "js-sys", - "log", - "naga", - "parking_lot", - "portable-atomic", - "profiling", - "raw-window-handle", - "smallvec", - "static_assertions", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "wgpu-core", - "wgpu-hal", - "wgpu-types", ] [[package]] -name = "wgpu-core" -version = "27.0.3" +name = "wasmparser" +version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27a75de515543b1897b26119f93731b385a19aea165a1ec5f0e3acecc229cae7" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" dependencies = [ - "arrayvec", - "bit-set", - "bit-vec", "bitflags", - "bytemuck", - "cfg_aliases", - "document-features", - "hashbrown 0.16.1", - "indexmap 2.12.1", - "log", - "naga", - "once_cell", - "parking_lot", - "portable-atomic", - "profiling", - "raw-window-handle", - "rustc-hash 1.1.0", - "smallvec", - "thiserror 2.0.17", - "wgpu-core-deps-apple", - "wgpu-core-deps-emscripten", - "wgpu-core-deps-windows-linux-android", - "wgpu-hal", - "wgpu-types", -] - -[[package]] -name = "wgpu-core-deps-apple" -version = "27.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0772ae958e9be0c729561d5e3fd9a19679bcdfb945b8b1a1969d9bfe8056d233" -dependencies = [ - "wgpu-hal", -] - -[[package]] -name = "wgpu-core-deps-emscripten" -version = "27.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b06ac3444a95b0813ecfd81ddb2774b66220b264b3e2031152a4a29fda4da6b5" -dependencies = [ - "wgpu-hal", -] - -[[package]] -name = "wgpu-core-deps-windows-linux-android" -version = "27.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71197027d61a71748e4120f05a9242b2ad142e3c01f8c1b47707945a879a03c3" -dependencies = [ - "wgpu-hal", + "hashbrown 0.15.5", + "indexmap 2.13.0", + "semver 1.0.27", ] [[package]] -name = "wgpu-hal" -version = "27.0.4" +name = "web-sys" +version = "0.3.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b21cb61c57ee198bc4aff71aeadff4cbb80b927beb912506af9c780d64313ce" +checksum = "854ba17bb104abfb26ba36da9729addc7ce7f06f5c0f90f3c391f8461cca21f9" dependencies = [ - "android_system_properties", - "arrayvec", - "ash", - "bit-set", - "bitflags", - "block", - "bytemuck", - "cfg-if 1.0.4", - "cfg_aliases", - "core-graphics-types", - "glow", - "glutin_wgl_sys", - "gpu-alloc", - "gpu-allocator", - "gpu-descriptor", - "hashbrown 0.16.1", "js-sys", - "khronos-egl", - "libc", - "libloading", - "log", - "metal", - "naga", - "ndk-sys", - "objc", - "once_cell", - "ordered-float", - "parking_lot", - "portable-atomic", - "portable-atomic-util", - "profiling", - "range-alloc", - "raw-window-handle", - "renderdoc-sys", - "smallvec", - "thiserror 2.0.17", "wasm-bindgen", - "web-sys", - "wgpu-types", - "windows 0.58.0", - "windows-core 0.58.0", -] - -[[package]] -name = "wgpu-types" -version = "27.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afdcf84c395990db737f2dd91628706cb31e86d72e53482320d368e52b5da5eb" -dependencies = [ - "bitflags", - "bytemuck", - "js-sys", - "log", - "thiserror 2.0.17", - "web-sys", -] - -[[package]] -name = "which" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" -dependencies = [ - "either", - "home", - "once_cell", - "rustix 0.38.44", ] [[package]] @@ -9025,84 +8212,17 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" -dependencies = [ - "windows-core 0.58.0", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows" -version = "0.61.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893" -dependencies = [ - "windows-collections", - "windows-core 0.61.2", - "windows-future", - "windows-link 0.1.3", - "windows-numerics", -] - -[[package]] -name = "windows-collections" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8" -dependencies = [ - "windows-core 0.61.2", -] - -[[package]] -name = "windows-core" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" -dependencies = [ - "windows-implement 0.58.0", - "windows-interface 0.58.0", - "windows-result 0.2.0", - "windows-strings 0.1.0", - "windows-targets 0.52.6", -] - [[package]] name = "windows-core" -version = "0.61.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" -dependencies = [ - "windows-implement 0.60.2", - "windows-interface 0.59.3", - "windows-link 0.1.3", - "windows-result 0.3.4", - "windows-strings 0.4.2", -] - -[[package]] -name = "windows-future" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e" -dependencies = [ - "windows-core 0.61.2", - "windows-link 0.1.3", - "windows-threading", -] - -[[package]] -name = "windows-implement" -version = "0.58.0" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.111", + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", ] [[package]] @@ -9113,18 +8233,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", -] - -[[package]] -name = "windows-interface" -version = "0.58.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] @@ -9135,58 +8244,24 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] -[[package]] -name = "windows-link" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" - [[package]] name = "windows-link" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" -[[package]] -name = "windows-numerics" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1" -dependencies = [ - "windows-core 0.61.2", - "windows-link 0.1.3", -] - [[package]] name = "windows-registry" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" dependencies = [ - "windows-link 0.2.1", - "windows-result 0.4.1", - "windows-strings 0.5.1", -] - -[[package]] -name = "windows-result" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" -dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-result" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" -dependencies = [ - "windows-link 0.1.3", + "windows-link", + "windows-result", + "windows-strings", ] [[package]] @@ -9195,26 +8270,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ - "windows-link 0.2.1", -] - -[[package]] -name = "windows-strings" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" -dependencies = [ - "windows-result 0.2.0", - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-strings" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" -dependencies = [ - "windows-link 0.1.3", + "windows-link", ] [[package]] @@ -9223,7 +8279,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ - "windows-link 0.2.1", + "windows-link", ] [[package]] @@ -9259,7 +8315,7 @@ version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows-link 0.2.1", + "windows-link", ] [[package]] @@ -9284,7 +8340,7 @@ version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ - "windows-link 0.2.1", + "windows-link", "windows_aarch64_gnullvm 0.53.1", "windows_aarch64_msvc 0.53.1", "windows_i686_gnu 0.53.1", @@ -9295,15 +8351,6 @@ dependencies = [ "windows_x86_64_msvc 0.53.1", ] -[[package]] -name = "windows-threading" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6" -dependencies = [ - "windows-link 0.1.3", -] - [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" @@ -9402,68 +8449,115 @@ checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "winnow" -version = "0.7.14" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" dependencies = [ "memchr", ] [[package]] name = "wit-bindgen" -version = "0.46.0" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] [[package]] -name = "writeable" -version = "0.6.2" +name = "wit-bindgen-core" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] [[package]] -name = "ws_stream_wasm" -version = "0.7.5" +name = "wit-bindgen-rust" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c173014acad22e83f16403ee360115b38846fe754e735c5d9d3803fe70c6abc" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" dependencies = [ - "async_io_stream", - "futures", - "js-sys", - "log", - "pharos", - "rustc_version 0.4.1", - "send_wrapper", - "thiserror 2.0.17", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", + "anyhow", + "heck", + "indexmap 2.13.0", + "prettyplease", + "syn 2.0.117", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", ] [[package]] -name = "wyz" -version = "0.5.1" +name = "wit-bindgen-rust-macro" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" dependencies = [ - "tap", + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn 2.0.117", + "wit-bindgen-core", + "wit-bindgen-rust", ] [[package]] -name = "xattr" -version = "1.6.1" +name = "wit-component" +version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" dependencies = [ - "libc", - "rustix 1.1.2", + "anyhow", + "bitflags", + "indexmap 2.13.0", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", ] [[package]] -name = "xml-rs" -version = "0.8.28" +name = "wit-parser" +version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ae8337f8a065cfc972643663ea4279e04e7256de865aa66fe25cec5fb912d3f" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap 2.13.0", + "log", + "semver 1.0.27", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + +[[package]] +name = "writeable" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] [[package]] name = "xxhash-rust" @@ -9490,28 +8584,28 @@ checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", "synstructure", ] [[package]] name = "zerocopy" -version = "0.8.31" +version = "0.8.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3" +checksum = "a789c6e490b576db9f7e6b6d661bcc9799f7c0ac8352f56ea20193b2681532e5" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.31" +version = "0.8.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a" +checksum = "f65c489a7071a749c849713807783f70672b28094011623e200cb86dcb835953" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] @@ -9531,7 +8625,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", "synstructure", ] @@ -9541,18 +8635,19 @@ version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" dependencies = [ + "serde", "zeroize_derive", ] [[package]] name = "zeroize_derive" -version = "1.4.2" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] @@ -9585,124 +8680,119 @@ checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.111", + "syn 2.0.117", ] [[package]] name = "zkboost-client" version = "0.1.0" dependencies = [ + "async-stream", + "bytes", + "futures", "reqwest", + "reqwest-eventsource", "serde", - "thiserror 2.0.17", + "serde_json", + "thiserror 2.0.18", + "tokio-stream", + "url", "zkboost-types", ] -[[package]] -name = "zkboost-ethereum-el-config" -version = "0.1.0" -dependencies = [ - "anyhow", - "clap", - "ere-common", - "ere-zkvm-interface 0.3.0", - "reqwest", - "serde", - "tokio", - "tracing", - "tracing-subscriber 0.3.22", - "zkboost-ethereum-el-types", - "zkboost-server-config", -] - -[[package]] -name = "zkboost-ethereum-el-input" -version = "0.1.0" -dependencies = [ - "anyhow", - "ere-zkvm-interface 0.3.0", - "reth-stateless", - "sha2", - "stateless-validator-ethrex", - "stateless-validator-reth", - "zkboost-ethereum-el-types", -] - -[[package]] -name = "zkboost-ethereum-el-relayer" -version = "0.1.0" - -[[package]] -name = "zkboost-ethereum-el-types" -version = "0.1.0" -dependencies = [ - "cargo_metadata", - "ere-common", - "serde", - "strum", -] - [[package]] name = "zkboost-server" version = "0.1.0" dependencies = [ + "alloy-eips", + "alloy-genesis", + "alloy-primitives", + "alloy-rpc-types-engine", + "alloy-rpc-types-eth", "anyhow", "axum", + "bincode 1.3.3", + "bytes", "clap", - "ere-dockerized", "ere-server", - "ere-zkvm-interface 0.3.0", - "flate2", + "ere-zkvm-interface", "futures", + "lru 0.12.5", "metrics", "metrics-exporter-prometheus", - "nix", "rand 0.9.2", "reqwest", + "reth-ethereum-primitives", + "reth-stateless", + "serde", "serde_json", - "sysinfo", - "tar", - "tempfile", + "sha2", + "stateless-validator-ethrex", + "stateless-validator-reth", + "strum", + "thiserror 2.0.18", "tokio", - "toml_edit 0.24.0+spec-1.1.0", + "tokio-stream", + "tokio-util", + "toml_edit 0.24.1+spec-1.1.0", + "tower", "tower-http", "tracing", - "tracing-subscriber 0.3.22", - "uuid", - "wgpu", + "tracing-subscriber", + "url", "zkboost-client", - "zkboost-ethereum-el-config", - "zkboost-ethereum-el-input", - "zkboost-ethereum-el-types", - "zkboost-server-config", "zkboost-types", ] [[package]] -name = "zkboost-server-config" +name = "zkboost-types" version = "0.1.0" dependencies = [ - "anyhow", - "ere-dockerized", - "ere-zkvm-interface 0.3.0", - "reqwest", + "ethereum_ssz 0.10.1", + "ethereum_ssz_derive 0.10.1", "serde", - "serde_yaml", - "tokio", - "toml_edit 0.24.0+spec-1.1.0", - "zkboost-types", + "serde_json", + "ssz_types 0.14.0", + "strum", + "superstruct", + "tree_hash 0.12.1", + "tree_hash_derive 0.12.1", + "types", ] [[package]] -name = "zkboost-types" -version = "0.1.0" +name = "zkhash" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4352d1081da6922701401cdd4cbf29a2723feb4cfabb5771f6fee8e9276da1c7" dependencies = [ - "ere-zkvm-interface 0.3.0", - "indexmap 2.12.1", + "ark-ff 0.4.2", + "ark-std 0.4.0", + "bitvec", + "blake2", + "bls12_381 0.7.1", + "byteorder", + "cfg-if 1.0.4", + "group 0.12.1", + "group 0.13.0", + "halo2", + "hex", + "jubjub", + "lazy_static", + "pasta_curves 0.5.1", + "rand 0.8.5", "serde", - "serde_with", + "sha2", + "sha3", + "subtle", ] +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" + [[package]] name = "zstd" version = "0.13.3" diff --git a/Cargo.toml b/Cargo.toml index 36477a0..aa3a649 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,24 +1,17 @@ [workspace] members = [ - # zkboost - "crates/zkboost/client", - "crates/zkboost/server", - "crates/zkboost/server-config", - "crates/zkboost/types", - # zkboost-ethereum - "crates/zkboost-ethereum/el-config", - "crates/zkboost-ethereum/el-input", - "crates/zkboost-ethereum/el-relayer", - "crates/zkboost-ethereum/el-types", - - "crates/execution-witness-sentry", "crates/zkboost/guest-loader", + "crates/client", + "crates/server", + "crates/types", + "crates/mock-zkattestor", + "crates/guest-loader", ] resolver = "2" [workspace.package] version = "0.1.0" edition = "2024" -rust-version = "1.88" +rust-version = "1.91" license = "MIT OR Apache-2.0" [workspace.lints.rust] @@ -38,71 +31,64 @@ result_large_err = "allow" [workspace.dependencies] anyhow = "1.0" +async-stream = "0.3" axum = "0.8" -cargo_metadata = "0.19.0" +bincode = "1.3.3" +bytes = "1" clap = "4.5" -ethereum_serde_utils = "0.8.0" -eventsource-client = "0.13" -flate2 = "1.1.5" futures = "0.3" -indexmap = "2.12" lru = "0.12" -nix = "0.29" +metrics = "0.24" +metrics-exporter-prometheus = "0.16" rand = "0.9.2" reqwest = "0.12" +reqwest-eventsource = "0.6" serde = "1.0" serde_json = "1" -serde_with = "3.16" -serde_yaml = "0.9" sha2 = "0.10.9" strum = "0.27.2" -sysinfo = "0.37" -tar = "0.4.44" -tempfile = "3.20.0" thiserror = "2" tokio = "1.48" +tokio-stream = "0.1" tokio-util = "0.7" toml_edit = "0.24" +tower = "0.5" tower-http = "0.6" tracing = "0.1" tracing-subscriber = "0.3" -uuid = "1.0" -wgpu = "27" -metrics = "0.24" -metrics-exporter-prometheus = "0.16" -discv5 = "0.10" url = "2.5.7" +# lighthouse +ethereum_serde_utils = "0.8.0" +lighthouse_types = { git = "https://github.com/sigp/lighthouse", branch = "unstable", package = "types" } +ssz = { package = "ethereum_ssz", version = "0.10" } +ssz_derive = { package = "ethereum_ssz_derive", version = "0.10" } +ssz_types = "0.14" +superstruct = "0.10" +tree_hash = "0.12" +tree_hash_derive = "0.12" + # alloy +alloy-eips = "1" alloy-genesis = "1" alloy-primitives = "1" -alloy-provider = "1" +alloy-rpc-types-engine = "1" alloy-rpc-types-eth = "1" -alloy-rpc-types-debug = "1" # reth -reth-chainspec = { git = "https://github.com/paradigmxyz/reth", rev = "cfde951976bfa9100a6d9f806e06fb539ae25241" } -reth-ethereum-primitives = { git = "https://github.com/paradigmxyz/reth", rev = "cfde951976bfa9100a6d9f806e06fb539ae25241" } -reth-stateless = { git = "https://github.com/paradigmxyz/reth", rev = "cfde951976bfa9100a6d9f806e06fb539ae25241" } +reth-ethereum-primitives = { git = "https://github.com/paradigmxyz/reth", tag = "v1.10.2", default-features = false } +reth-stateless = { git = "https://github.com/paradigmxyz/reth", tag = "v1.10.2", default-features = false } # ere -ere-common = { git = "https://github.com/eth-act/ere", tag = "v0.3.0" } -ere-dockerized = { git = "https://github.com/eth-act/ere", tag = "v0.3.0" } ere-server = { git = "https://github.com/eth-act/ere", tag = "v0.3.0" } ere-zkvm-interface = { git = "https://github.com/eth-act/ere", tag = "v0.3.0" } # ere-guests -stateless-validator-ethrex = { git = "https://github.com/eth-act/ere-guests", tag = "v0.4.0", features = ["host"] } -stateless-validator-reth = { git = "https://github.com/eth-act/ere-guests", tag = "v0.4.0", features = ["host"] } +stateless-validator-ethrex = { git = "https://github.com/eth-act/ere-guests", tag = "v0.6.0", features = ["host"] } +stateless-validator-reth = { git = "https://github.com/eth-act/ere-guests", tag = "v0.6.0", features = ["host"] } # local -zkboost-client = { path = "crates/zkboost/client" } -zkboost-server = { path = "crates/zkboost/server" } -zkboost-server-config = { path = "crates/zkboost/server-config" } -zkboost-types = { path = "crates/zkboost/types" } -guest-loader = { path = "crates/zkboost/guest-loader" } - -zkboost-ethereum-el-config = { path = "crates/zkboost-ethereum/el-config" } -zkboost-ethereum-el-input = { path = "crates/zkboost-ethereum/el-input" } -zkboost-ethereum-el-relayer = { path = "crates/zkboost-ethereum/el-relayer" } -zkboost-ethereum-el-types = { path = "crates/zkboost-ethereum/el-types" } +zkboost-client = { path = "crates/client" } +zkboost-server = { path = "crates/server" } +zkboost-types = { path = "crates/types" } +zkboost-mock-zkattestor = { path = "crates/mock-zkattestor" } diff --git a/README.md b/README.md index 6045bee..b70dac1 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,8 @@ zkboost is an API wrapper on top of [Ere](https://github.com/eth-act/ere) allowi - [Prerequisites](#prerequisites) - [API](#api) - [Observability](#observability) + - [Docker Compose with Grafana](#docker-compose-with-grafana) + - [Available Metrics](#available-metrics) - [Supported Backends](#supported-backends) - [Contributing](#contributing) - [License](#license) @@ -28,15 +30,11 @@ zkboost is an API wrapper on top of [Ere](https://github.com/eth-act/ere) allowi ## Quick Start -The easiest way to start is by running the `GITHUB_TOKEN= RUST_LOG=info cargo test --package zkboost-server --test stateless_validator -- --zkvm sp1 --resource cpu`. - -> The `GITHUB_TOKEN` is needed to download compiled artifact from repo [`eth-act/zkevm-benchmark-workload`](https://github.com/eth-act/zkevm-benchmark-workload). - ## Manual Build ### Prerequisites -* **Rust** ≥ 1.88 +* **Rust** ≥ 1.91 ```bash # 1. Clone @@ -50,13 +48,14 @@ cargo run --release The following endpoints are available: -| Endpoint | Method | Purpose | -| ---------- | ------ | ---------------------------------------- | -| `/info` | `GET` | Get server and system information | -| `/execute` | `POST` | Run program and get execution metrics | -| `/prove` | `POST` | Generate proof for a program with inputs | -| `/verify` | `POST` | Verify a previously generated proof | -| `/metrics` | `GET` | Prometheus metrics endpoint | +| Method | Endpoint | Purpose | +| ------ | -------------------------------------------------------------- | ------------------------------------------------------------- | +| `POST` | `/v1/execution_proof_requests?proof_types=` | Submit SSZ-encoded `NewPayloadRequest` to request for a proof | +| `GET` | `/v1/execution_proof_requests?new_payload_request_root=` | SSE stream of proof result | +| `GET` | `/v1/execution_proofs/{new_payload_request_root}/{proof_type}` | Fetch a completed proof | +| `POST` | `/v1/execution_proof_verifications` | Verify a proof | +| `GET` | `/health` | Health check | +| `GET` | `/metrics` | Prometheus metrics | ## Observability @@ -67,34 +66,31 @@ zkboost exposes Prometheus-compatible metrics at `/metrics` for monitoring with The Docker Compose setup includes pre-configured Prometheus and Grafana with a zkboost dashboard: ```bash -cd docker && docker-compose up -d +cd docker/example/observability && docker-compose up -d ``` -| Service | URL | Credentials | -| ---------- | ----------------------- | --------------- | -| zkboost | http://localhost:3000 | - | -| Prometheus | http://localhost:9090 | - | -| Grafana | http://localhost:3001 | admin / admin | +| Service | URL | Credentials | +| ---------- | --------------------- | ------------- | +| zkboost | http://localhost:3000 | - | +| Prometheus | http://localhost:9090 | - | +| Grafana | http://localhost:3002 | admin / admin | The zkboost dashboard is auto-provisioned and available at Grafana > Dashboards > zkboost. ### Available Metrics -| Metric | Type | Description | -| ------ | ---- | ----------- | -| `zkboost_http_requests_total` | Counter | Total HTTP requests by endpoint, method, status | -| `zkboost_http_request_duration_seconds` | Histogram | Request latency by endpoint | -| `zkboost_http_requests_in_flight` | Gauge | Currently processing requests | -| `zkboost_prove_total` | Counter | Prove operations by program and status | -| `zkboost_prove_duration_seconds` | Histogram | Proof generation time | -| `zkboost_prove_proof_bytes` | Histogram | Generated proof sizes | -| `zkboost_execute_total` | Counter | Execute operations by program and status | -| `zkboost_execute_duration_seconds` | Histogram | Execution time | -| `zkboost_execute_cycles_total` | Histogram | zkVM cycle counts | -| `zkboost_verify_total` | Counter | Verify operations by program and result | -| `zkboost_verify_duration_seconds` | Histogram | Verification time | -| `zkboost_programs_loaded` | Gauge | Number of loaded zkVM programs | -| `zkboost_build_info` | Gauge | Build version info | +| Metric | Type | Description | +| --------------------------------------- | --------- | ----------------------------------------------- | +| `zkboost_http_requests_total` | Counter | Total HTTP requests by endpoint, method, status | +| `zkboost_http_request_duration_seconds` | Histogram | Request latency by endpoint | +| `zkboost_http_requests_in_flight` | Gauge | Currently processing requests | +| `zkboost_prove_total` | Counter | Prove operations by program and status | +| `zkboost_prove_duration_seconds` | Histogram | Proof generation time | +| `zkboost_prove_proof_bytes` | Histogram | Generated proof sizes | +| `zkboost_verify_total` | Counter | Verify operations by program and result | +| `zkboost_verify_duration_seconds` | Histogram | Verification time | +| `zkboost_programs_loaded` | Gauge | Number of loaded zkVM programs | +| `zkboost_build_info` | Gauge | Build version info | ## Supported Backends diff --git a/crates/zkboost/client/Cargo.toml b/crates/client/Cargo.toml similarity index 56% rename from crates/zkboost/client/Cargo.toml rename to crates/client/Cargo.toml index 869af2e..637b49d 100644 --- a/crates/zkboost/client/Cargo.toml +++ b/crates/client/Cargo.toml @@ -3,13 +3,21 @@ name = "zkboost-client" version.workspace = true edition.workspace = true rust-version.workspace = true +license.workspace = true [lints] workspace = true [dependencies] +async-stream.workspace = true +bytes.workspace = true +futures.workspace = true reqwest = { workspace = true, features = ["json"] } -thiserror.workspace = true +reqwest-eventsource.workspace = true serde.workspace = true +serde_json.workspace = true +thiserror.workspace = true +tokio-stream.workspace = true +url.workspace = true zkboost-types.workspace = true diff --git a/crates/client/src/error.rs b/crates/client/src/error.rs new file mode 100644 index 0000000..2002e47 --- /dev/null +++ b/crates/client/src/error.rs @@ -0,0 +1,47 @@ +//! Error types for the zkboost client. + +/// Errors that can occur when using [`crate::zkBoostClient`]. +#[derive(Debug, thiserror::Error)] +#[allow(non_camel_case_types)] +pub enum Error { + /// An HTTP request failed at the transport level. + #[error("HTTP request failed: {0}")] + Request(#[from] reqwest::Error), + + /// The server returned a non-2xx status code. + #[error("server returned {status}: {body}")] + ServerError { + /// HTTP status code. + status: u16, + /// Response body text. + body: String, + }, + + /// The requested resource was not found (404). + #[error("not found: {0}")] + NotFound(String), + + /// The server returned a 400 Bad Request. + #[error("bad request: {0}")] + BadRequest(String), + + /// A transport error occurred reading the response body. + #[error("transport error reading response body: {0}")] + Transport(reqwest::Error), + + /// An error occurred on the SSE stream. + #[error("SSE error: {0}")] + Sse(String), + + /// Failed to parse a JSON response. + #[error("parse error: {0}")] + Parse(#[from] serde_json::Error), + + /// Failed to parse an SSE event into a [`ProofEvent`](zkboost_types::ProofEvent). + #[error("SSE event parse error: {0}")] + EventParse(#[from] zkboost_types::ProofEventParseError), + + /// Failed to construct a URL. + #[error("URL error: {0}")] + Url(#[from] url::ParseError), +} diff --git a/crates/client/src/lib.rs b/crates/client/src/lib.rs new file mode 100644 index 0000000..0e8ed81 --- /dev/null +++ b/crates/client/src/lib.rs @@ -0,0 +1,204 @@ +//! HTTP client library for the zkboost Proof Node API. +//! +//! Provides [`zkBoostClient`] with methods for all four API operations: +//! +//! - [`request_proof`](zkBoostClient::request_proof) - submit a `NewPayloadRequest` for proving +//! - [`subscribe_proof_events`](zkBoostClient::subscribe_proof_events) - stream SSE proof +//! completion/failure events +//! - [`get_proof`](zkBoostClient::get_proof) - download completed proof bytes +//! - [`verify_proof`](zkBoostClient::verify_proof) - verify a proof against the server +//! +//! # Example +//! +//! ```ignore +//! use zkboost_client::{zkBoostClient, MainnetEthSpec, NewPayloadRequest}; +//! use zkboost_types::ProofType; +//! +//! # async fn example(request: NewPayloadRequest) -> Result<(), Box> { +//! let client = zkBoostClient::new("http://localhost:3000".parse()?); +//! let resp = client.request_proof(&request, &[ProofType::RethSP1]).await?; +//! println!("root: {:?}", resp.new_payload_request_root); +//! # Ok(()) +//! # } +//! ``` + +#![warn(unused_crate_dependencies)] + +pub mod error; + +use bytes::Bytes; +use futures::stream::Stream; +use reqwest_eventsource::{Event, EventSource}; +use tokio_stream::StreamExt; +use url::Url; + +#[rustfmt::skip] +pub use { + error::Error, + zkboost_types::{ + Encode, Hash256, MainnetEthSpec, + NewPayloadRequest, ProofComplete, ProofEvent, ProofFailure, ProofRequestResponse, + ProofStatus, ProofTimeout, ProofType, ProofVerificationResponse, WitnessTimeout, + ProofEventParseError, + }, +}; + +/// HTTP client for the zkboost Proof Node API. +#[derive(Debug, Clone)] +#[allow(non_camel_case_types)] +pub struct zkBoostClient { + endpoint: Url, + http_client: reqwest::Client, +} + +impl zkBoostClient { + /// Creates a new client pointing at the given base URL. + pub fn new(endpoint: Url) -> Self { + Self { + endpoint, + http_client: reqwest::Client::new(), + } + } + + /// Creates a new client with a custom [`reqwest::Client`]. + pub fn with_http_client(endpoint: Url, http_client: reqwest::Client) -> Self { + Self { + endpoint, + http_client, + } + } + + /// Submit a [`NewPayloadRequest`] for proof generation. + /// + /// Sends `POST /v1/execution_proof_requests?proof_types=...` with the SSZ-encoded body. Returns + /// the computed `new_payload_request_root` from the server. + pub async fn request_proof( + &self, + new_payload_request: &NewPayloadRequest, + proof_types: &[ProofType], + ) -> Result { + let mut url = self.endpoint.join("/v1/execution_proof_requests")?; + let proof_types = Vec::from_iter(proof_types.iter().map(ProofType::as_str)).join(","); + url.query_pairs_mut() + .append_pair("proof_types", &proof_types); + + let response = self + .http_client + .post(url) + .header("content-type", "application/octet-stream") + .body(new_payload_request.as_ssz_bytes()) + .send() + .await?; + + handle_json_response(response).await + } + + /// Subscribe to SSE proof events. + /// + /// Opens `GET /v1/execution_proof_requests` as an SSE stream. + /// + /// When `filter_root` is provided, the server only sends events matching that + /// `new_payload_request_root`. + pub fn subscribe_proof_events( + &self, + filter_root: Option, + ) -> impl Stream> + Send + '_ { + async_stream::try_stream! { + let mut url = self.endpoint.join("/v1/execution_proof_requests")?; + if let Some(new_payload_request_root) = filter_root { + url.query_pairs_mut() + .append_pair("new_payload_request_root", &new_payload_request_root.to_string()); + } + + let builder = self.http_client.get(url); + let mut es = EventSource::new(builder) + .map_err(|e| Error::Sse(format!("failed to create event source: {e}")))?; + + while let Some(event) = es.next().await { + match event { + Ok(Event::Open) => {} + Ok(Event::Message(message)) => { + yield ProofEvent::try_from_parts(&message.event, &message.data)?; + } + Err(error) => { + es.close(); + Err(Error::Sse(error.to_string()))?; + } + } + } + } + } + + /// Download a completed execution proof by proof type. + /// + /// Sends `GET /v1/execution_proofs/{root}/{proof_type}` and returns the raw proof bytes, or + /// [`Error::NotFound`] if the proof is not yet available. + pub async fn get_proof( + &self, + new_payload_request_root: Hash256, + proof_type: ProofType, + ) -> Result { + let url = self.endpoint.join(&format!( + "/v1/execution_proofs/{new_payload_request_root}/{proof_type}" + ))?; + + let response = error_for_status(self.http_client.get(url).send().await?).await?; + Ok(response.bytes().await?) + } + + /// Verify a proof against the server. + /// + /// Sends `POST /v1/execution_proof_verifications?new_payload_request_root=...&proof_type=...` + /// with the raw proof bytes as the request body. + pub async fn verify_proof( + &self, + new_payload_request_root: Hash256, + proof_type: ProofType, + proof: &[u8], + ) -> Result { + let mut url = self.endpoint.join("/v1/execution_proof_verifications")?; + url.query_pairs_mut() + .append_pair( + "new_payload_request_root", + &new_payload_request_root.to_string(), + ) + .append_pair("proof_type", proof_type.as_str()); + + let response = self + .http_client + .post(url) + .header("content-type", "application/octet-stream") + .body(proof.to_vec()) + .send() + .await?; + + handle_json_response(response).await + } +} + +async fn error_for_status(response: reqwest::Response) -> Result { + if response.status().is_success() { + return Ok(response); + } + let status = response.status(); + let raw_body = response.text().await.map_err(Error::Transport)?; + let message = serde_json::from_str::(&raw_body) + .ok() + .and_then(|v| v.get("error")?.as_str().map(String::from)) + .unwrap_or(raw_body); + match status { + reqwest::StatusCode::NOT_FOUND => Err(Error::NotFound(message)), + reqwest::StatusCode::BAD_REQUEST => Err(Error::BadRequest(message)), + _ => Err(Error::ServerError { + status: status.as_u16(), + body: message, + }), + } +} + +async fn handle_json_response( + response: reqwest::Response, +) -> Result { + let response = error_for_status(response).await?; + Ok(response.json().await?) +} diff --git a/crates/execution-witness-sentry/Cargo.toml b/crates/execution-witness-sentry/Cargo.toml deleted file mode 100644 index 6024b6a..0000000 --- a/crates/execution-witness-sentry/Cargo.toml +++ /dev/null @@ -1,44 +0,0 @@ -[package] -name = "execution-witness-sentry" -version.workspace = true -edition.workspace = true -rust-version.workspace = true - -[dependencies] -anyhow.workspace = true -axum.workspace = true -clap = { workspace = true, features = ["derive"] } -discv5.workspace = true -ethereum_serde_utils.workspace = true -eventsource-client.workspace = true -flate2.workspace = true -futures.workspace = true -lru.workspace = true -reqwest = { workspace = true, features = ["json"] } -serde = { workspace = true, features = ["derive"] } -serde_json.workspace = true -thiserror.workspace = true -tokio = { workspace = true, features = ["sync", "rt-multi-thread", "macros"] } -tokio-util.workspace = true -toml_edit = { workspace = true, features = ["serde"] } -tower-http = { workspace = true, features = ["trace"] } -tracing.workspace = true -tracing-subscriber = { workspace = true, features = ["env-filter"] } -url.workspace = true - -alloy-genesis.workspace = true -alloy-primitives.workspace = true -alloy-provider = { workspace = true, features = ["ws"] } -alloy-rpc-types-debug.workspace = true -alloy-rpc-types-eth.workspace = true - -reth-chainspec.workspace = true -reth-ethereum-primitives.workspace = true -reth-stateless.workspace = true - -ere-common.workspace = true - -zkboost-client.workspace = true -zkboost-ethereum-el-input.workspace = true -zkboost-ethereum-el-types.workspace = true -zkboost-types.workspace = true diff --git a/crates/execution-witness-sentry/src/cl_subscription.rs b/crates/execution-witness-sentry/src/cl_subscription.rs deleted file mode 100644 index 8fbea58..0000000 --- a/crates/execution-witness-sentry/src/cl_subscription.rs +++ /dev/null @@ -1,135 +0,0 @@ -//! SSE subscription for CL head events. - -use std::{ - pin::Pin, - task::{Context, Poll}, -}; - -use eventsource_client::{Client, SSE}; -use futures::Stream; -use serde::Deserialize; -use url::Url; - -use crate::{ - Hash256, - error::{Error, Result}, -}; - -/// Head event from the CL. -#[derive(Debug, Clone, Deserialize)] -pub struct HeadEvent { - #[serde(with = "serde_utils::quoted_u64")] - pub slot: u64, - pub block: Hash256, - pub state: Hash256, - pub epoch_transition: bool, - pub execution_optimistic: bool, -} - -/// Block event from the CL. -#[derive(Debug, Clone, Deserialize)] -pub struct BlockEvent { - #[serde(with = "serde_utils::quoted_u64")] - pub slot: u64, - pub block: Hash256, - pub execution_optimistic: bool, -} - -/// Unified CL event. -#[derive(Debug, Clone)] -pub enum ClEvent { - Head(HeadEvent), - Block(BlockEvent), -} - -impl ClEvent { - pub fn slot(&self) -> u64 { - match self { - ClEvent::Head(e) => e.slot, - ClEvent::Block(e) => e.slot, - } - } - - pub fn block_root(&self) -> Hash256 { - match self { - ClEvent::Head(e) => e.block, - ClEvent::Block(e) => e.block, - } - } -} - -/// Stream of CL events. -pub struct ClEventStream { - client: Pin> + Send>>, -} - -impl Stream for ClEventStream { - type Item = Result; - - fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - loop { - match self.client.as_mut().poll_next(cx) { - Poll::Ready(Some(Ok(SSE::Event(event)))) => { - let result = match event.event_type.as_str() { - "head" => serde_json::from_str::(&event.data) - .map(ClEvent::Head) - .map_err(Error::Parse), - "block" => serde_json::from_str::(&event.data) - .map(ClEvent::Block) - .map_err(Error::Parse), - _ => continue, - }; - return Poll::Ready(Some(result)); - } - Poll::Ready(Some(Ok(SSE::Comment(_)))) => continue, - Poll::Ready(Some(Ok(SSE::Connected(_)))) => continue, - Poll::Ready(Some(Err(e))) => { - return Poll::Ready(Some(Err(Error::Sse(format!("{e:?}"))))); - } - Poll::Ready(None) => return Poll::Ready(None), - Poll::Pending => return Poll::Pending, - } - } - } -} - -/// Subscribe to CL head events via SSE. -pub fn subscribe_cl_events(base_url: impl AsRef) -> Result { - let url = build_events_url(base_url)?; - - let client = eventsource_client::ClientBuilder::for_url(url.as_str()) - .map_err(|e| Error::Config(format!("Invalid SSE URL: {e}")))? - .build(); - - Ok(ClEventStream { - client: Box::pin(client.stream()), - }) -} - -fn build_events_url(base_url: impl AsRef) -> Result { - let base = Url::parse(base_url.as_ref())?; - Ok(base.join("/eth/v1/events?topics=head,block")?) -} - -#[cfg(test)] -mod tests { - use crate::cl_subscription::build_events_url; - - #[test] - fn build_events_url_adds_path_without_trailing_slash() { - let url = build_events_url("http://localhost:5052").unwrap(); - assert_eq!( - url.as_str(), - "http://localhost:5052/eth/v1/events?topics=head,block" - ); - } - - #[test] - fn build_events_url_adds_path_with_trailing_slash() { - let url = build_events_url("http://localhost:5052/").unwrap(); - assert_eq!( - url.as_str(), - "http://localhost:5052/eth/v1/events?topics=head,block" - ); - } -} diff --git a/crates/execution-witness-sentry/src/config.rs b/crates/execution-witness-sentry/src/config.rs deleted file mode 100644 index ccd1282..0000000 --- a/crates/execution-witness-sentry/src/config.rs +++ /dev/null @@ -1,92 +0,0 @@ -//! Configuration types for the execution witness sentry. - -use std::path::Path; - -use serde::{Deserialize, Serialize}; -use url::Url; -use zkboost_ethereum_el_types::ElProofType; - -use crate::error::{Error, Result}; - -/// Sentry configuration. -#[derive(Debug, Clone, Deserialize, Serialize)] -pub struct Config { - /// Execution layer endpoints to monitor. - #[serde(default)] - pub el_endpoints: Vec, - /// Consensus layer endpoints to submit proofs to. - #[serde(default)] - pub cl_endpoints: Vec, - /// Directory to save block and witness data. - pub output_dir: Option, - /// Chain identifier (used in output path). - pub chain: Option, - /// Number of recent blocks to retain (older blocks are deleted). - pub retain: Option, - /// Number of proofs to submit per block. - pub num_proofs: Option, - /// Endpoint of proof engine. - pub proof_engine: ProofEngineConfig, -} - -/// Execution layer endpoint configuration. -#[derive(Debug, Clone, Deserialize, Serialize)] -pub struct ElEndpoint { - /// Human-readable name for this endpoint. - pub name: String, - /// HTTP JSON-RPC URL. - pub url: Url, - /// WebSocket URL for subscriptions. - pub ws_url: Url, -} - -/// Consensus layer endpoint configuration. -/// -/// When the sentry starts if queries each CL endpoint to check whether its ENR -/// contains the zkVM flag, to determine whether the client requires proof -/// submission or not. -/// -/// The first non-zkVM activated client will be used as the source of the new -/// head SSE subscription. -#[derive(Debug, Clone, Deserialize, Serialize)] -pub struct ClEndpoint { - /// Human-readable name for this endpoint. - pub name: String, - /// HTTP API URL. - pub url: Url, -} - -/// Configuration for the proof engine. -/// -/// The proof engine receives proof requests and asynchronously generates -/// proofs, pushing results back via a webhook. Multiple proof types can -/// be configured to generate different proof variants per block. -#[derive(Debug, Clone, Deserialize, Serialize)] -pub struct ProofEngineConfig { - /// Proof engine URL. - pub url: Url, - /// Proof types the proof engine supports. - pub proof_types: Vec, - /// Port for HTTP server to receive proofs from proof engine. - #[serde(default = "default_proof_engine_webhook_port")] - pub webhook_port: u16, -} - -/// Returns the default webhook port for receiving proofs from the proof engine. -fn default_proof_engine_webhook_port() -> u16 { - 3003 -} - -impl Config { - /// Load configuration from a TOML file. - pub fn load(path: impl AsRef) -> Result { - let content = std::fs::read_to_string(path.as_ref()).map_err(|e| { - Error::Config(format!( - "failed to read config file '{}': {}", - path.as_ref().display(), - e - )) - })?; - Ok(toml_edit::de::from_str(&content)?) - } -} diff --git a/crates/execution-witness-sentry/src/el_subscription.rs b/crates/execution-witness-sentry/src/el_subscription.rs deleted file mode 100644 index 1c3171e..0000000 --- a/crates/execution-witness-sentry/src/el_subscription.rs +++ /dev/null @@ -1,48 +0,0 @@ -//! WebSocket subscription for new block headers. - -use std::{ - pin::Pin, - task::{Context, Poll}, -}; - -use alloy_provider::{Provider, ProviderBuilder, WsConnect}; -use alloy_rpc_types_eth::Header; -use futures::Stream; -use url::Url; - -use crate::error::{Error, Result}; - -/// Subscription stream that keeps the provider alive. -pub struct BlockSubscription

{ - #[allow(dead_code)] - provider: P, - stream: Pin + Send>>, -} - -impl

Unpin for BlockSubscription

{} - -impl Stream for BlockSubscription

{ - type Item = Result

; - - fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { - self.stream.as_mut().poll_next(cx).map(|opt| opt.map(Ok)) - } -} - -/// Subscribe to new block headers via WebSocket. -pub async fn subscribe_blocks(ws_url: &Url) -> Result> + Send> { - let ws = WsConnect::new(ws_url.as_str()); - let provider = ProviderBuilder::new() - .connect_ws(ws) - .await - .map_err(|e| Error::WebSocket(format!("WebSocket connection failed: {e}")))?; - - let subscription = provider - .subscribe_blocks() - .await - .map_err(|e| Error::WebSocket(format!("Block subscription failed: {e}")))?; - - let stream = Box::pin(subscription.into_stream()); - - Ok(BlockSubscription { provider, stream }) -} diff --git a/crates/execution-witness-sentry/src/error.rs b/crates/execution-witness-sentry/src/error.rs deleted file mode 100644 index 06d0af7..0000000 --- a/crates/execution-witness-sentry/src/error.rs +++ /dev/null @@ -1,53 +0,0 @@ -//! Error types for the execution witness sentry. - -use std::io; - -use thiserror::Error; - -/// Errors that can occur in the execution witness sentry. -#[derive(Debug, Error)] -pub enum Error { - /// Failed to load or parse configuration. - #[error("config error: {0}")] - Config(String), - - /// HTTP request failed. - #[error("HTTP error: {0}")] - Http(#[from] reqwest::Error), - - /// JSON-RPC error returned by the node. - #[error("RPC error {code}: {message}")] - Rpc { - /// Error code. - code: i64, - /// Error message. - message: String, - }, - - /// Failed to parse response. - #[error("parse error: {0}")] - Parse(#[from] serde_json::Error), - - /// WebSocket connection or subscription failed. - #[error("WebSocket error: {0}")] - WebSocket(String), - - /// URL parsing failed. - #[error("invalid URL: {0}")] - InvalidUrl(#[from] url::ParseError), - - /// I/O error (file operations, compression). - #[error("I/O error: {0}")] - Io(#[from] io::Error), - - /// TOML parsing error. - #[error("TOML parse error: {0}")] - Toml(#[from] toml_edit::de::Error), - - /// SSE connection error. - #[error("SSE error: {0}")] - Sse(String), -} - -/// Result type alias using our Error type. -pub type Result = std::result::Result; diff --git a/crates/execution-witness-sentry/src/lib.rs b/crates/execution-witness-sentry/src/lib.rs deleted file mode 100644 index 33aaef3..0000000 --- a/crates/execution-witness-sentry/src/lib.rs +++ /dev/null @@ -1,43 +0,0 @@ -//! Execution witness sentry - monitors execution layer nodes for new blocks -//! and fetches their execution witnesses. -//! -//! This crate provides functionality to: -//! - Subscribe to new block headers via WebSocket -//! - Fetch blocks and execution witnesses via JSON-RPC -//! - Store block data and witnesses to disk -//! - Submit execution proofs to consensus layer nodes -//! -//! ## Example -//! -//! ```ignore -//! use execution_witness_sentry::{Config, ElClient, subscribe_blocks}; -//! -//! let config = Config::load("config.toml")?; -//! let client = ElClient::new(url); -//! -//! // Subscribe to new blocks -//! let mut stream = subscribe_blocks(&ws_url).await?; -//! -//! while let Some(header) = stream.next().await { -//! let witness = client.get_execution_witness(header.number).await?; -//! // Process witness... -//! } -//! ``` - -pub mod cl_subscription; -pub mod config; -pub mod el_subscription; -pub mod error; -pub mod rpc; -pub mod service; -pub mod storage; - -// Re-export main types at crate root for convenience. -// Re-export alloy types that appear in our public API. -pub use alloy_rpc_types_eth::{Block, Header}; -pub use cl_subscription::{BlockEvent, ClEvent, ClEventStream, HeadEvent, subscribe_cl_events}; -pub use config::{ClEndpoint, Config, ElEndpoint}; -pub use el_subscription::subscribe_blocks; -pub use error::{Error, Result}; -pub use rpc::{BlockInfo, ClClient, ElClient, ExecutionProof, Hash256, ProofEngineClient}; -pub use storage::{BlockMetadata, BlockStorage, ElBlockWitness, compress_gzip, decompress_gzip}; diff --git a/crates/execution-witness-sentry/src/main.rs b/crates/execution-witness-sentry/src/main.rs deleted file mode 100644 index 49920b8..0000000 --- a/crates/execution-witness-sentry/src/main.rs +++ /dev/null @@ -1,262 +0,0 @@ -//! Execution witness sentry (EWS). -//! -//! EWS orchestrates the complete workflow for generating proofs of execution proof: -//! -//! 1. Listen to new block from CL -//! 2. Fetch execution witness from EL -//! 3. Generate input for EL stateless validator guest program -//! 4. Request Proof Engine (zkboost) for proof -//! 5. Send proof back to CL -//! -//! ## Architecture -//! -//! ```text -//! CL EWS EL Proof Engine -//! | | | | -//! |--new block-->| | | -//! | | | | -//! | |--fetch witness-->| | -//! | |<----witness------| | -//! | | | | -//! | (generate zkVM input) | | -//! | | | | -//! | |--request proof--------------------->| -//! | | | | -//! | | | (generate proof) -//! | | | | -//! | |<------proof-------------------------| -//! | | | | -//! |<----proof----| | | -//! | | | | -//! ``` - -use std::{num::NonZeroUsize, path::PathBuf, sync::Arc, time::Duration}; - -use anyhow::bail; -use clap::Parser; -use execution_witness_sentry::{ - BlockStorage, ClClient, Config, ElBlockWitness, ElClient, Hash256, - service::{ - backfill::BackfillService, - cl_event::ClEventService, - el_data::{ElDataService, ElDataServiceMessage}, - el_event::ElEventService, - proof::{ProofService, ProofServiceMessage}, - }, -}; -use futures::future::select_all; -use lru::LruCache; -use tokio::{ - signal::unix::{SignalKind, signal}, - sync::Mutex, - time::sleep, -}; -use tokio_util::sync::CancellationToken; -use tracing::{info, warn}; - -#[derive(Parser, Debug)] -#[command(name = "execution-witness-sentry")] -#[command(about = "Monitor execution layer nodes and fetch execution witnesses")] -struct Cli { - #[arg(long, short)] - config: PathBuf, -} - -#[tokio::main] -async fn main() -> anyhow::Result<()> { - tracing_subscriber::fmt() - .with_env_filter(tracing_subscriber::EnvFilter::from_default_env()) - .init(); - - let cli = Cli::parse(); - - let config = Arc::new(Config::load(&cli.config)?); - - // TODO: Currently we submit all proofs specified in `config.proof_engine.proof_types` to CLs - // but ideally we only need to submit the required amount of proofs to save bandwidth. - let _num_proofs = config.num_proofs; - - // Initialize EL clients. - - info!( - el_endpoints = config.el_endpoints.len(), - "Loaded configuration" - ); - let el_clients: Vec> = config - .el_endpoints - .iter() - .map(|endpoint| { - info!( - name = %endpoint.name, - url = %endpoint.url, - ws_url = %endpoint.ws_url, - "EL endpoint configured" - ); - - Arc::new(ElClient::new(endpoint.name.clone(), endpoint.url.clone())) - }) - .collect(); - - // Get chain config. - - let chain_config = 'outer: loop { - for el_client in &el_clients { - if let Ok(Some(chain_config)) = el_client.get_chain_config().await { - break 'outer chain_config; - } - warn!( - name = %el_client.name(), - url = %el_client.url(), - "Failed to get chain config", - ) - } - - sleep(Duration::from_secs(2)).await; - }; - - // Initialize CL clients. - - let mut zkvm_enabled_cl_clients: Vec> = Vec::new(); - let mut source_cl_client: Option> = None; - - for endpoint in &config.cl_endpoints { - let client = ClClient::new(endpoint.name.clone(), endpoint.url.clone()); - - match client.is_zkvm_enabled().await { - Ok(true) => { - info!(name = %endpoint.name, "CL endpoint has zkvm enabled (proof target)"); - zkvm_enabled_cl_clients.push(Arc::new(client)); - } - Ok(false) => { - info!(name = %endpoint.name, "CL endpoint does not have zkvm enabled"); - if source_cl_client.is_none() { - info!(name = %endpoint.name, "Using as event source"); - source_cl_client = Some(Arc::new(client)); - } - } - Err(e) => { - warn!(name = %endpoint.name, error = %e, "Failed to check if client has zkVM enabled or not"); - } - } - } - - info!( - zkvm_enabled_cl_clients = zkvm_enabled_cl_clients.len(), - "zkvm-enabled CL endpoints configured" - ); - - let Some(source_cl_client) = source_cl_client else { - bail!("No non-zkvm CL endpoint available for event source"); - }; - info!(name = %source_cl_client.name(), "CL event source configured"); - - let el_data_cache: Arc>> = - Arc::new(Mutex::new(LruCache::new(NonZeroUsize::new(128).unwrap()))); - let storage: Option>> = config.output_dir.as_ref().map(|dir| { - Arc::new(Mutex::new(BlockStorage::new( - dir, - config.chain.as_deref().unwrap_or("unknown"), - config.retain, - ))) - }); - - let (proof_tx, proof_rx) = tokio::sync::mpsc::channel::(1024); - let (el_data_tx, el_data_rx) = tokio::sync::mpsc::channel::(1024); - - let shutdown_token = CancellationToken::new(); - - let mut handles = Vec::new(); - - // Start CL event listening service. - - { - let cl_event_service = Arc::new(ClEventService::new( - source_cl_client.clone(), - storage.clone(), - proof_tx.clone(), - )); - - handles.push(cl_event_service.spawn(shutdown_token.clone())); - } - - // Start EL event listening services. - - for endpoint in &config.el_endpoints { - let el_event_service = Arc::new(ElEventService::new(endpoint.clone(), el_data_tx.clone())); - - handles.push(el_event_service.spawn(shutdown_token.clone())); - } - - // Start EL data service. - - { - let el_data_service = Arc::new(ElDataService::new( - el_clients.clone(), - el_data_cache.clone(), - storage.clone(), - proof_tx.clone(), - )); - - handles.push(el_data_service.spawn(shutdown_token.clone(), el_data_rx)); - } - - // Start proof service. - - { - let proof_service = Arc::new(ProofService::new( - config.proof_engine.clone(), - chain_config, - zkvm_enabled_cl_clients.clone(), - el_data_cache.clone(), - storage.clone(), - )?); - - handles.extend( - proof_service - .spawn(shutdown_token.clone(), proof_rx) - .await?, - ); - } - - // Start backfilling service. - - { - let interval_ms = 2000; - let backfill_service = Arc::new(BackfillService::new( - source_cl_client, - zkvm_enabled_cl_clients, - el_data_cache, - storage, - proof_tx, - el_data_tx, - interval_ms, - )); - - handles.push(backfill_service.spawn(shutdown_token.clone())); - } - - info!("All services started, waiting for shutdown signal"); - - let mut signals: Vec<_> = [SignalKind::interrupt(), SignalKind::terminate()] - .into_iter() - .filter_map(|kind| signal(kind).ok()) - .collect(); - - if signals.is_empty() { - bail!("No shutdown signals could be registered"); - } - - let _ = select_all(signals.iter_mut().map(|s| Box::pin(s.recv()))).await; - - info!("Received shutdown signal, shutting down"); - - shutdown_token.cancel(); - - for handle in handles { - let _ = handle.await; - } - - info!("All services stopped, exiting"); - - Ok(()) -} diff --git a/crates/execution-witness-sentry/src/rpc.rs b/crates/execution-witness-sentry/src/rpc.rs deleted file mode 100644 index 207cbf8..0000000 --- a/crates/execution-witness-sentry/src/rpc.rs +++ /dev/null @@ -1,407 +0,0 @@ -//! JSON-RPC client for execution layer nodes. - -use alloy_genesis::ChainConfig; -use reth_ethereum_primitives::{Block, TransactionSigned}; -use reth_stateless::ExecutionWitness; -use serde::{Deserialize, Serialize, de::DeserializeOwned}; -use url::Url; -use zkboost_client::zkboostClient; -use zkboost_ethereum_el_input::ElInput; -use zkboost_ethereum_el_types::ElProofType; -use zkboost_types::ProofGenId; - -use crate::error::{Error, Result}; - -pub type Hash256 = alloy_primitives::B256; - -/// JSON-RPC request structure. -#[derive(Debug, Clone, Serialize)] -struct JsonRpcRequest { - jsonrpc: &'static str, - method: &'static str, - params: T, - id: u64, -} - -/// JSON-RPC response structure. -#[derive(Debug, Clone, Deserialize)] -pub struct JsonRpcResponse { - pub result: Option, - pub error: Option, -} - -/// JSON-RPC error structure. -#[derive(Debug, Clone, Deserialize)] -pub struct JsonRpcError { - pub code: i64, - pub message: String, -} - -/// Execution layer JSON-RPC client. -pub struct ElClient { - name: String, - url: Url, - http_client: reqwest::Client, -} - -impl ElClient { - /// Create a new EL client. - pub fn new(name: String, url: Url) -> Self { - Self { - name, - url, - http_client: reqwest::Client::new(), - } - } - - /// Return name of the EL client. - pub fn name(&self) -> &str { - &self.name - } - - /// Return url of the EL client. - pub fn url(&self) -> &Url { - &self.url - } - - /// Send a JSON-RPC request to the execution layer node. - /// - /// Serializes the request, sends it to the endpoint, and deserializes the response. - /// Returns `None` if the RPC response has a null `result`. - async fn request( - &self, - method: &'static str, - params: P, - ) -> Result> { - let request = JsonRpcRequest { - jsonrpc: "2.0", - method, - params, - id: 1, - }; - - let response = self - .http_client - .post(self.url.clone()) - .json(&request) - .send() - .await?; - - if !response.status().is_success() { - return Err(Error::Rpc { - code: response.status().as_u16() as i64, - message: response.text().await.unwrap_or_default(), - }); - } - - let rpc_response: JsonRpcResponse = response.json().await?; - - if let Some(error) = rpc_response.error { - return Err(Error::Rpc { - code: error.code, - message: error.message, - }); - } - - match rpc_response.result { - Some(config) => Ok(Some(config)), - None => Ok(None), - } - } - - /// Fetch chain config. - pub async fn get_chain_config(&self) -> Result> { - self.request("debug_chainConfig", ()).await - } - - /// Fetch a block by hash. Returns the block and its gzipped JSON. - pub async fn get_block_by_hash(&self, block_hash: Hash256) -> Result> { - let block: Option> = self - .request("eth_getBlockByHash", (block_hash, false)) - .await?; - Ok(block.map(|block| block.into_consensus())) - } - - /// Fetch execution witness for a block. Returns the witness and its gzipped JSON. - pub async fn get_execution_witness_by_hash( - &self, - block_hash: Hash256, - ) -> Result> { - self.request("debug_executionWitnessByBlockHash", (block_hash,)) - .await - } -} - -/// Execution proof to submit to CL nodes. -#[derive(Debug, Clone, Serialize)] -pub struct ExecutionProof { - pub proof_id: u8, - pub slot: u64, - pub block_hash: Hash256, - pub block_root: Hash256, - pub proof_data: Vec, -} - -/// Consensus layer HTTP API client. -#[derive(Clone)] -pub struct ClClient { - name: String, - url: Url, - http_client: reqwest::Client, -} - -/// Block response with execution payload. -#[derive(Debug, Clone, Deserialize)] -pub struct BlockResponse { - pub data: BlockData, -} - -/// Block data. -#[derive(Debug, Clone, Deserialize)] -pub struct BlockData { - pub message: BlockMessage, -} - -/// Block message. -#[derive(Debug, Clone, Deserialize)] -pub struct BlockMessage { - pub body: BlockBody, -} - -/// Block body. -#[derive(Debug, Clone, Deserialize)] -pub struct BlockBody { - pub execution_payload: Option, -} - -/// Execution payload (minimal fields). -#[derive(Debug, Clone, Deserialize)] -pub struct ExecutionPayload { - pub block_hash: Hash256, -} - -/// Syncing status response. -#[derive(Debug, Clone, Deserialize)] -pub struct SyncingResponse { - pub data: SyncingData, -} - -/// Syncing status data. -#[derive(Debug, Clone, Deserialize)] -pub struct SyncingData { - #[serde(with = "serde_utils::quoted_u64")] - pub head_slot: u64, - pub is_syncing: bool, - pub is_optimistic: Option, -} - -/// Block header response. -#[derive(Debug, Clone, Deserialize)] -pub struct BlockHeaderResponse { - pub data: BlockHeaderData, -} - -/// Block header data. -#[derive(Debug, Clone, Deserialize)] -pub struct BlockHeaderData { - pub root: Hash256, -} - -/// Node identity response. -#[derive(Debug, Clone, Deserialize)] -pub struct IdentityResponse { - pub data: IdentityData, -} - -/// Node identity data. -#[derive(Debug, Clone, Deserialize)] -pub struct IdentityData { - pub enr: String, -} - -impl ClClient { - /// Create a new CL client. - pub fn new(name: String, url: Url) -> Self { - Self { - url, - name, - http_client: reqwest::Client::new(), - } - } - - /// Return name of the CL client. - pub fn name(&self) -> &str { - &self.name - } - - /// Return url of the CL client. - pub fn url(&self) -> &Url { - &self.url - } - - /// Get node syncing status. - pub async fn get_syncing(&self) -> Result { - let url = self.url.join("eth/v1/node/syncing")?; - let response = self.http_client.get(url).send().await?; - Ok(response.json().await?) - } - - /// Get block header for a slot. - pub async fn get_block_header(&self, slot: u64) -> Result> { - let url = self.url.join(&format!("eth/v1/beacon/headers/{slot}"))?; - let response = self.http_client.get(url).send().await?; - - if response.status() == reqwest::StatusCode::NOT_FOUND { - return Ok(None); - } - - Ok(Some(response.json().await?)) - } - - /// Submit an execution proof. - pub async fn submit_execution_proof(&self, proof: &ExecutionProof) -> Result<()> { - let url = self.url.join("eth/v1/beacon/pool/execution_proofs")?; - - let response = self.http_client.post(url).json(proof).send().await?; - - if !response.status().is_success() { - let status = response.status(); - let body = response.text().await.unwrap_or_default(); - return Err(Error::Rpc { - code: status.as_u16() as i64, - message: body, - }); - } - - Ok(()) - } - - /// Get node identity (including ENR). - pub async fn get_identity(&self) -> Result { - let url = self.url.join("eth/v1/node/identity")?; - let response = self.http_client.get(url).send().await?; - Ok(response.json().await?) - } - - /// Check if the node has zkvm enabled by inspecting its ENR. - pub async fn is_zkvm_enabled(&self) -> Result { - let identity = self.get_identity().await?; - Ok(enr_has_zkvm(&identity.data.enr)) - } - - /// Get the execution block hash for a beacon block. - pub async fn get_block_execution_hash(&self, block_root: Hash256) -> Result> { - let url = self - .url - .join(&format!("eth/v2/beacon/blocks/{block_root}"))?; - let response = self.http_client.get(url).send().await?; - - if response.status() == reqwest::StatusCode::NOT_FOUND { - return Ok(None); - } - - let block_response: BlockResponse = response.json().await?; - Ok(block_response - .data - .message - .body - .execution_payload - .map(|p| p.block_hash)) - } - - /// Get the current head slot. - pub async fn get_head_slot(&self) -> Result { - let syncing = self.get_syncing().await?; - Ok(syncing.data.head_slot) - } - - /// Get block info (slot, block_root, execution_block_hash) for a given slot. - /// Returns None if the slot is empty (no block). - pub async fn get_block_info(&self, slot: u64) -> Result> { - let Some(header) = self.get_block_header(slot).await? else { - return Ok(None); - }; - - let block_root = header.data.root; - let execution_block_hash = self.get_block_execution_hash(block_root).await?; - - Ok(Some(BlockInfo { - slot, - block_root, - execution_block_hash, - })) - } -} - -/// Block info for backfill. -#[derive(Debug, Clone)] -pub struct BlockInfo { - pub slot: u64, - pub block_root: Hash256, - pub execution_block_hash: Option, -} - -/// The ENR field specifying whether zkVM execution proofs are enabled. -const ZKVM_ENABLED_ENR_KEY: &str = "zkvm"; - -/// Check if an ENR string contains the zkvm flag. -fn enr_has_zkvm(enr_str: &str) -> bool { - use std::str::FromStr; - - use discv5::enr::{CombinedKey, Enr}; - - match Enr::::from_str(enr_str) { - Ok(enr) => enr - .get_decodable::(ZKVM_ENABLED_ENR_KEY) - .and_then(|result| result.ok()) - .unwrap_or(false), - Err(_) => false, - } -} - -/// Client for communicating with a proof engine. -pub struct ProofEngineClient { - /// URL of the proof engine. - pub url: Url, - /// Proof types supported by this engine. - pub proof_types: Vec, - /// Underlying client for API calls. - client: zkboostClient, -} - -impl ProofEngineClient { - /// Create a new proof engine client. - pub fn new(url: Url, proof_types: Vec) -> anyhow::Result { - let client = zkboostClient::new(url.clone())?; - Ok(Self { - url, - proof_types, - client, - }) - } - - /// Return the proof types supported by this engine. - pub fn proof_types(&self) -> &[ElProofType] { - &self.proof_types - } - - /// Submit a proof generation request to the zkboost server. - /// - /// Converts the execution input to zkVM format and submits it to the - /// configured proof engine. Returns a proof generation ID that can be - /// used to identity webhook callbacks. - pub async fn request_proof( - &self, - proof_type: &ElProofType, - el_input: &ElInput, - ) -> anyhow::Result { - Ok(self - .client - .prove( - proof_type.to_string(), - el_input.to_zkvm_input(proof_type.el(), true)?.stdin, - ) - .await? - .proof_gen_id) - } -} diff --git a/crates/execution-witness-sentry/src/service.rs b/crates/execution-witness-sentry/src/service.rs deleted file mode 100644 index 9dc18d8..0000000 --- a/crates/execution-witness-sentry/src/service.rs +++ /dev/null @@ -1,151 +0,0 @@ -//! Service architecture for the execution-witness-sentry. -//! -//! This module defines the core services that make up the execution-witness-sentry. -//! -//! # Architecture Overview -//! -//! The sentry is composed of services that communicate via channels: -//! -//! ```text -//! ┌────────────────────────────────────────────────────────┐ ┌──────────────────────────────────────────────────────┐ -//! │ CLs │ │ ELs │ -//! └────────────────────────────────────────────────────────┘ └──────────────────────────────────────────────────────┘ -//! ▲ ▲ ▲ ▲ ▲ -//! │ │ │ │ │ -//! │ │ │ │ │ -//! │ Listen heads Get sync status Fetch block and witness Listen heads -//! │ (SSE) │ │ (Websocket) -//! │ │ │ │ │ -//! │ ┌────────┴─────────┐ ┌────────┴─────────┐ ┌────────┴────────┐ ┌────────┴─────────┐ -//! Submit proofs │ CL Event Service │ │ Backfill Service ├──Request data──► │ EL Data Service │◄──Request data──┤ EL Event Service │ -//! │ └────────┬─────────┘ └────────┬─────────┘ └────────┬────────┘ └──────────────────┘ -//! │ │ │ │ -//! │ │ │ │ -//! │ Request proof Request proof EL data ready -//! │ │ │ │ -//! │ │ │ │ -//! │ ▼ ▼ ▼ -//! ┌──────┴──────────────────────────────────────────────────────────────────────────────────────┐ -//! │ Proof Service │ -//! └────────────────────────┬────────────────────────────────────────────────────────────────────┘ -//! ▲ │ -//! │ │ -//! │ Request proof -//! Proof result │ -//! (Webhook) │ -//! │ ▼ -//! ┌──────┴───────────────────────┐ -//! │ Proof Engine │ -//! └──────────────────────────────┘ -//! ``` -//! -//! # Services -//! -//! - [`cl_event::ClEventService`]: Subscribes to CL SSE head events and triggers proof requests -//! - [`el_event::ElEventService`]: Subscribes to EL WebSocket head events and triggers data fetches -//! - [`el_data::ElDataService`]: Fetches block and witness data from EL, caches to memory/disk -//! - [`proof::ProofService`]: Manages proof lifecycle - requesting, receiving, submitting -//! - [`backfill::BackfillService`]: Monitors zkVM CL sync status and backfills missing proofs - -use std::{borrow::Borrow, collections::HashSet, hash::Hash, sync::Arc}; - -use lru::LruCache; -use tokio::sync::Mutex; -use tracing::{debug, warn}; - -use crate::{BlockStorage, ElBlockWitness, Hash256}; - -pub mod backfill; -pub mod cl_event; -pub mod el_data; -pub mod el_event; -pub mod proof; - -/// Represents a target selection that can be either all items or a specific subset. -#[derive(Clone, Debug)] -pub enum Target { - /// Target all items. - All, - /// Target only the specified items. - Specific(HashSet), -} - -impl FromIterator for Target { - fn from_iter>(iter: I) -> Self { - Self::Specific(iter.into_iter().collect()) - } -} - -impl Target { - /// Returns `true` if the target includes the given value. - /// - /// For [`Target::All`], always returns `true`. For [`Target::Specific`], - /// returns `true` only if the value is in the set. - pub fn contains(&self, value: &Q) -> bool - where - T: Borrow, - Q: ?Sized + Hash + Eq, - { - match self { - Self::All => true, - Self::Specific(specific) => specific.contains(value), - } - } - - /// Computes the union of two targets. - /// - /// If either target is [`Target::All`], the result is [`Target::All`]. - /// Otherwise, returns a [`Target::Specific`] containing items from both sets. - pub fn union(&self, other: &Self) -> Self { - match (self, other) { - (Self::All, _) | (_, Self::All) => Self::All, - (Self::Specific(lhs), Self::Specific(rhs)) => { - Self::Specific(lhs.union(rhs).cloned().collect()) - } - } - } -} - -/// Checks if EL block and witness is available for the given block hash. -/// -/// If data is found on disk but not in cache, it is automatically loaded into the cache -/// for faster subsequent access. -/// -/// # Returns -/// -/// `true` if the EL block and witness is available (in cache or loaded from disk), -/// `false` otherwise. -pub(crate) async fn is_el_data_available( - el_data_cache: &Arc>>, - storage: &Option>>, - block_hash: Hash256, -) -> bool { - if el_data_cache.lock().await.contains(&block_hash) { - return true; - } - - let Some(storage) = &storage else { - return false; - }; - - let storage_guard = storage.lock().await; - match storage_guard.load_el_data(block_hash) { - Ok(Some(el_data)) => { - drop(storage_guard); - - let mut cache = el_data_cache.lock().await; - cache.put(block_hash, el_data); - - debug!(block_hash = %block_hash, "Loaded EL data from disk to cache"); - return true; - } - Ok(None) => { - debug!(block_hash = %block_hash, "EL data not found on disk"); - } - Err(e) => { - warn!(block_hash = %block_hash, error = %e, "Failed to load EL data from disk"); - } - } - - false -} diff --git a/crates/execution-witness-sentry/src/service/backfill.rs b/crates/execution-witness-sentry/src/service/backfill.rs deleted file mode 100644 index b831345..0000000 --- a/crates/execution-witness-sentry/src/service/backfill.rs +++ /dev/null @@ -1,284 +0,0 @@ -//! # Backfill Service -//! -//! This module provides [`BackfillService`], which monitors zkVM-enabled CL clients and triggers -//! proof backfill when they fall behind the source CL. -//! -//! ## Purpose -//! -//! The backfill service ensures that zkVM-enabled CL clients stay synchronized with the source CL -//! by periodically checking for gaps and requesting missing proofs. - -use std::{sync::Arc, time::Duration}; - -use alloy_primitives::map::HashMap; -use lru::LruCache; -use tokio::{ - sync::{Mutex, mpsc}, - task::JoinHandle, -}; -use tokio_util::sync::CancellationToken; -use tracing::{debug, error, info, warn}; - -use crate::{ - BlockStorage, ClClient, ElBlockWitness, - rpc::Hash256, - service::{ - Target, el_data::ElDataServiceMessage, is_el_data_available, proof::ProofServiceMessage, - }, -}; - -/// Status of a zkVM-enabled CL client relative to the source CL. -/// -/// Used to determine which clients are behind and need backfilling. -#[derive(Debug, Clone)] -#[allow(non_camel_case_types)] -pub struct zkVMEnabledClStatus { - /// Human-readable name of the zkVM-enabled CL client. - pub name: String, - /// Current head slot of this zkVM-enabled CL client. - pub head_slot: u64, - /// Slot difference from the source CL (negative means behind). - /// - /// Calculated as `zkvm_head - source_head`, so a value of -5 means - /// the zkVM client is 5 slots behind the source. - pub gap: i64, -} - -/// Monitors zkVM-enabled CL clients and triggers proof backfill when they fall behind. -/// -/// The backfill service periodically compares the head slot of each zkVM-enabled CL client -/// against the source CL. When a client falls more than 5 slots behind, it initiates -/// backfill by requesting proofs for missing slots. -/// -/// ## Data Flow -/// -/// When backfilling, for each missing slot: -/// 1. Fetches block info from the source CL -/// 2. Skip if that slot is missing -/// 3. If EL data is not cached, sends [`ElDataServiceMessage::FetchData`] -/// 4. Sends [`ProofServiceMessage::RequestProof`] targeting the specific behind client -pub struct BackfillService { - /// Reference CL client used to determine the canonical head. - source_cl_client: Arc, - /// CL clients that require zkVM proofs for block validation. - zkvm_enabled_cl_clients: HashMap>, - /// Shared LRU cache of execution block data. - el_data_cache: Arc>>, - /// Optional persistent storage for proofs. - storage: Option>>, - /// Channel for sending proof generation requests to [`ProofService`]. - proof_tx: mpsc::Sender, - /// Channel for requesting EL block data from [`ElDataService`]. - el_data_tx: mpsc::Sender, - /// Polling interval in milliseconds between status checks. - interval_ms: u64, -} - -impl BackfillService { - /// Creates a new backfill service. - #[allow(clippy::too_many_arguments)] - pub fn new( - source_cl_client: Arc, - zkvm_enabled_cl_clients: Vec>, - el_data_cache: Arc>>, - storage: Option>>, - proof_tx: mpsc::Sender, - el_data_tx: mpsc::Sender, - interval_ms: u64, - ) -> Self { - let zkvm_enabled_cl_clients = zkvm_enabled_cl_clients - .into_iter() - .map(|client| (client.name().to_string(), client)) - .collect(); - Self { - source_cl_client, - zkvm_enabled_cl_clients, - proof_tx, - el_data_tx, - el_data_cache, - storage, - interval_ms, - } - } - - /// Spawns the backfill service as a background task. - /// - /// The service runs until the shutdown token is cancelled. - pub fn spawn(self: Arc, shutdown_token: CancellationToken) -> JoinHandle<()> { - tokio::spawn(self.run(shutdown_token)) - } - - /// Main event loop that periodically checks client statuses and triggers backfill. - /// - /// Uses a timer-based polling approach with configurable interval. - async fn run(self: Arc, shutdown_token: CancellationToken) { - let mut interval = tokio::time::interval(Duration::from_millis(self.interval_ms)); - interval.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip); - - info!(interval_ms = self.interval_ms, "BackfillService started"); - - loop { - tokio::select! { - biased; - - _ = shutdown_token.cancelled() => { - info!("BackfillService received shutdown signal"); - break; - } - - _ = interval.tick() => { - let statuses = self.get_statuses().await; - - for status in &statuses { - if status.gap < -5 { - warn!( - name = %status.name, - head_slot = status.head_slot, - gap = status.gap, - "zkvm CL is behind, starting backfill" - ); - - if let Some(client) = self.zkvm_enabled_cl_clients.get(&status.name) - - { - self.backfill_proofs(client, 20).await; - } - } else if status.gap < 0 { - debug!( - name = %status.name, - head_slot = status.head_slot, - gap = status.gap, - "zkvm CL slightly behind" - ); - } else { - debug!( - name = %status.name, - head_slot = status.head_slot, - gap = status.gap, - "zkvm CL in sync" - ); - } - } - } - } - } - - info!("BackfillService stopped"); - } - - /// Queries all zkVM-enabled CL clients and computes their gap from the source CL. - /// - /// Returns an empty vector if the source CL head cannot be retrieved. - /// Individual client failures are logged but don't prevent other clients from being checked. - async fn get_statuses(&self) -> Vec { - let source_head = match self.source_cl_client.get_head_slot().await { - Ok(slot) => slot, - Err(e) => { - warn!(error = %e, "Failed to get source CL head"); - return vec![]; - } - }; - - let mut statuses = Vec::new(); - for client in self.zkvm_enabled_cl_clients.values() { - match client.get_head_slot().await { - Ok(head_slot) => { - let gap = head_slot as i64 - source_head as i64; - statuses.push(zkVMEnabledClStatus { - name: client.name().to_string(), - head_slot, - gap, - }); - } - Err(e) => { - warn!(name = %client.name(), error = %e, "Failed to get zkvm CL head"); - } - } - } - - statuses - } - - /// Requests proofs for slots where the given zkVM client is behind. - /// - /// Iterates through slots from the client's current head up to `max_slots` ahead. - /// - /// For each slot, request EL data fetch if it is not available, then submits a proof request. - async fn backfill_proofs(&self, zkvm_enabled_client: &ClClient, max_slots: u64) { - let zkvm_head = match zkvm_enabled_client.get_head_slot().await { - Ok(slot) => slot, - Err(e) => { - warn!(name = %zkvm_enabled_client.name(), error = %e, "Failed to get zkvm CL head for backfill"); - return; - } - }; - - let source_head = match self.source_cl_client.get_head_slot().await { - Ok(slot) => slot, - Err(e) => { - warn!(error = %e, "Failed to get source CL head for backfill"); - return; - } - }; - - if zkvm_head >= source_head { - return; - } - - let gap = source_head - zkvm_head; - let slots_to_check = gap.min(max_slots); - - info!( - name = %zkvm_enabled_client.name(), - zkvm_head = zkvm_head, - source_head = source_head, - gap = gap, - checking = slots_to_check, - "Backfilling proofs" - ); - - // TODO: Track proof that's already backfilled, if it still fall behind, - // it'd probably be other issues instead of missing proofs. - - for slot in (zkvm_head + 1)..=(zkvm_head + slots_to_check) { - let block_info = match self.source_cl_client.get_block_info(slot).await { - Ok(Some(info)) => info, - Ok(None) => { - debug!(slot = slot, "Empty slot, skipping"); - continue; - } - Err(e) => { - debug!(slot = slot, error = %e, "Failed to get block info"); - continue; - } - }; - - let Some(block_hash) = block_info.execution_block_hash else { - debug!(slot = slot, "No execution payload, skipping"); - continue; - }; - - if !is_el_data_available(&self.el_data_cache, &self.storage, block_hash).await { - debug!(slot = slot, block_hash = %block_hash, "EL data not ready for backfill, sending fetch and proof request"); - - let msg = ElDataServiceMessage::FetchData { block_hash }; - if let Err(e) = self.el_data_tx.send(msg).await { - error!(error = %e, "Failed to send block fetch request for backfill"); - } - } - - let msg = ProofServiceMessage::RequestProof { - slot, - block_root: block_info.block_root, - execution_block_hash: block_hash, - target_clients: [zkvm_enabled_client.name().to_string()] - .into_iter() - .collect(), - target_proof_types: Target::All, - }; - if self.proof_tx.send(msg).await.is_err() { - error!("Failed to send backfill proof request"); - } - } - } -} diff --git a/crates/execution-witness-sentry/src/service/cl_event.rs b/crates/execution-witness-sentry/src/service/cl_event.rs deleted file mode 100644 index 3cc1970..0000000 --- a/crates/execution-witness-sentry/src/service/cl_event.rs +++ /dev/null @@ -1,157 +0,0 @@ -//! # CL Event Service -//! -//! This module provides [`ClEventService`], which subscribes to CL head events via Server-Sent -//! Events (SSE) and triggers proof requests. -//! -//! ## Purpose -//! -//! The CL event service is the primary driver for proof generation. It listens for new head events -//! from the source CL client and initiates the proof workflow for each new block. - -use std::{pin::pin, sync::Arc, time::Duration}; - -use futures::StreamExt; -use tokio::{ - sync::{Mutex, mpsc}, - task::JoinHandle, -}; -use tokio_util::sync::CancellationToken; -use tracing::{debug, error, info, warn}; - -use crate::{ - BlockStorage, ClClient, ClEvent, Error, HeadEvent, - service::{Target, proof::ProofServiceMessage}, - subscribe_cl_events, -}; - -/// Subscribes to CL head events via SSE and triggers proof requests. -pub struct ClEventService { - /// The source CL client to subscribe to for head events. - client: Arc, - /// Optional storage for persisting CL block metadata to disk. - storage: Option>>, - /// Channel for sending proof requests to the [`ProofService`](super::proof::ProofService). - proof_tx: mpsc::Sender, -} - -impl ClEventService { - /// Creates a new `ClEventService`. - pub fn new( - client: Arc, - storage: Option>>, - proof_tx: mpsc::Sender, - ) -> Self { - Self { - client, - storage, - proof_tx, - } - } - - /// Processes a head event by fetching block data and requesting proofs. - /// - /// 1. Retrieves the execution block hash from the beacon block - /// 2. Persists CL metadata to storage if configured - /// 3. Sends a proof request for all configured proof types and clients - async fn handle_head(&self, head: HeadEvent) { - debug!(slot = %head.slot, "Received ClEvent"); - - let slot: u64 = head.slot; - let block_root = head.block; - - let execution_block_hash = match self.client.get_block_execution_hash(block_root).await { - Ok(Some(hash)) => hash, - Ok(None) => { - debug!(name = %self.client.name(), slot = slot, "No execution hash for block"); - return; - } - Err(e) => { - debug!(name = %self.client.name(), error = %e, "Failed to get execution hash"); - return; - } - }; - - if let Some(storage) = &self.storage { - let mut storage_guard = storage.lock().await; - if let Err(e) = storage_guard.save_cl_data(execution_block_hash, slot, block_root) { - warn!(block_hash = %execution_block_hash, error = %e, "Failed to save CL block header to disk"); - } else { - debug!( - block_hash = %execution_block_hash, - "Saved CL block header to disk" - ); - } - } - - let message = ProofServiceMessage::RequestProof { - slot, - block_root, - execution_block_hash, - target_clients: Target::All, - target_proof_types: Target::All, - }; - if let Err(error) = self.proof_tx.send(message).await { - error!(slot = %slot, error = %error, "Failed to send proof request"); - } - } - - /// Spawns the service as a background task that processes CL head events. - pub fn spawn(self: Arc, shutdown_token: CancellationToken) -> JoinHandle<()> { - tokio::spawn(self.run(shutdown_token)) - } - - /// Main event loop that subscribes to CL head events and processes them. - async fn run(self: Arc, shutdown_token: CancellationToken) { - const RECONNECT_DELAY: Duration = Duration::from_secs(5); - - loop { - info!(name = %self.client.name(), "Connecting to CL SSE"); - - let stream = match subscribe_cl_events(self.client.url()) { - Ok(s) => s, - Err(e) => { - error!(name = %self.client.name(), url = %self.client.url(), error = %e, "Invalid CL SSE url"); - return; - } - }; - - info!(name = %self.client.name(), "Subscribed to CL head events"); - let mut stream = pin!(stream); - - loop { - tokio::select! { - biased; - - _ = shutdown_token.cancelled() => { - info!(name = %self.client.name(), "ClEventService received shutdown signal"); - return; - } - - result = stream.next() => { - match result { - Some(Ok(ClEvent::Head(head))) => self.handle_head(head).await, - Some(Ok(ClEvent::Block(_))) => {} - Some(Err(e)) => { - if let Error::Sse(e) = &e && e.contains("ConnectionRefused") { - break - } - error!(name = %self.client.name(), error = %e, "CL stream error") - }, - None => break, - } - } - } - } - - warn!(name = %self.client.name(), "CL SSE stream ended, reconnecting in 5 seconds"); - tokio::select! { - _ = shutdown_token.cancelled() => { - info!(name = %self.client.name(), "ClEventService received shutdown signal"); - return; - } - - _ = tokio::time::sleep(RECONNECT_DELAY) => {} - } - } - } -} diff --git a/crates/execution-witness-sentry/src/service/el_data.rs b/crates/execution-witness-sentry/src/service/el_data.rs deleted file mode 100644 index 980a14d..0000000 --- a/crates/execution-witness-sentry/src/service/el_data.rs +++ /dev/null @@ -1,260 +0,0 @@ -//! EL Data Service -//! -//! This module provides [`ElDataService`], which is responsible for fetching block and witness -//! data from EL clients. -//! -//! ## Purpose -//! -//! The EL data is necessary for proof generation, when a new EL block event arrives, or a proof -//! request is processed but the EL data is missing, a [`ElDataServiceMessage::FetchData`] will be -//! sent to this service to fetch the data. It deduplicates the messages with same `block_hash` to -//! prevent duplicate concurrent requests for the same block. - -use std::{ - collections::HashMap, - sync::Arc, - time::{Duration, Instant}, -}; - -use lru::LruCache; -use tokio::{ - sync::{Mutex, mpsc}, - task::{JoinHandle, JoinSet}, -}; -use tokio_util::sync::CancellationToken; -use tracing::{debug, error, info, warn}; - -use crate::{ - BlockStorage, ElBlockWitness, ElClient, Hash256, - service::{is_el_data_available, proof::ProofServiceMessage}, -}; - -/// Timeout for EL data fetch requests (60 seconds). -const IN_FLIGHT_FETCH_TIMEOUT: Duration = Duration::from_secs(60); -/// Interval to cleanup stale in-flight requests (30 seconds). -const CLEANUP_INTERVAL: Duration = Duration::from_secs(30); - -/// Messages handled by [`ElDataService`]. -pub enum ElDataServiceMessage { - /// Request to fetch block and witness data for the given block hash. - /// - /// Sent when a new EL block event arrives or when proof generation - /// requires data that is not yet available. - FetchData { block_hash: Hash256 }, -} - -/// Service responsible for fetching block and witness data from EL clients. -/// -/// When a [`ElDataServiceMessage::FetchData`] message is received, this service -/// fetches the block and execution witness from configured EL endpoints. Successfully -/// fetched data is cached in memory and optionally persisted to disk, then a -/// [`ProofServiceMessage::BlockDataReady`] notification is sent to the proof service. -/// -/// ## Deduplication -/// -/// Concurrent requests for the same block hash are deduplicated via the `in_flight` -/// set to prevent redundant network calls. -pub struct ElDataService { - /// EL clients to fetch block data from, tried in order. - el_clients: Vec>, - /// In-memory LRU cache for recently fetched EL block data. - el_data_cache: Arc>>, - /// Optional disk storage for persisting fetched data. - storage: Option>>, - /// Channel to notify the proof service when data is ready. - proof_tx: mpsc::Sender, - /// Map of block hashes currently being fetched to their request timestamps. - /// Used for deduplication and staleness detection. - in_flight: Arc>>, -} - -impl ElDataService { - /// Creates a new EL data service. - pub fn new( - el_clients: Vec>, - el_data_cache: Arc>>, - storage: Option>>, - proof_tx: mpsc::Sender, - ) -> Self { - Self { - el_clients, - el_data_cache, - storage, - proof_tx, - in_flight: Arc::new(Mutex::new(HashMap::new())), - } - } - - /// Spawns the service as a background task. - pub fn spawn( - self: Arc, - shutdown_token: CancellationToken, - el_data_rx: mpsc::Receiver, - ) -> JoinHandle<()> { - tokio::spawn(self.run(shutdown_token, el_data_rx)) - } - - /// Main event loop that processes incoming messages until shutdown. - async fn run( - self: Arc, - shutdown_token: CancellationToken, - mut el_data_rx: mpsc::Receiver, - ) { - let mut fetch_tasks: JoinSet = JoinSet::new(); - let mut cleanup_interval = tokio::time::interval(CLEANUP_INTERVAL); - - loop { - tokio::select! { - biased; - - _ = shutdown_token.cancelled() => { - info!("ElDataService received shutdown signal"); - fetch_tasks.abort_all(); - break; - } - - _ = cleanup_interval.tick() => { - self.cleanup_stale_requests().await; - } - - Some(result) = fetch_tasks.join_next() => { - match result { - Ok(block_hash) => { - self.in_flight.lock().await.remove(&block_hash); - }, - Err(e) if e.is_panic() => error!(error = ?e, "Fetch task panicked"), - Err(_) => {} - } - } - - Some(message) = el_data_rx.recv() => { - match message { - ElDataServiceMessage::FetchData { block_hash } => { - self.handle_fetch_data(block_hash, &mut fetch_tasks).await; - } - } - } - } - } - } - - /// Handles a fetch data request, spawning a fetch task if not already in flight. - async fn handle_fetch_data( - self: &Arc, - block_hash: Hash256, - fetch_tasks: &mut JoinSet, - ) { - if is_el_data_available(&self.el_data_cache, &self.storage, block_hash).await { - self.send_block_data_ready(block_hash).await; - return; - }; - - { - let mut in_flight = self.in_flight.lock().await; - if let Some(&created_at) = in_flight.get(&block_hash) { - if created_at.elapsed() < IN_FLIGHT_FETCH_TIMEOUT { - debug!(block_hash = %block_hash, "Block fetch already in flight, skipping"); - return; - } - warn!( - block_hash = %block_hash, - elapsed_secs = ?created_at.elapsed().as_secs(), - "Stale in-flight request, retrying fetch" - ); - } - in_flight.insert(block_hash, Instant::now()); - } - - fetch_tasks.spawn(self.clone().fetch_el_data(block_hash)); - } - - /// Removes in-flight entries older than the timeout threshold. - async fn cleanup_stale_requests(&self) { - let mut in_flight = self.in_flight.lock().await; - in_flight.retain(|block_hash, created_at| { - let is_stale = created_at.elapsed() >= IN_FLIGHT_FETCH_TIMEOUT; - if is_stale { - warn!( - block_hash = %block_hash, - elapsed_secs = created_at.elapsed().as_secs(), - "Removing stale in-flight fetch request" - ); - } - !is_stale - }); - } - - /// Fetches EL block and witness, caching and persisting and notifying if success. - async fn fetch_el_data(self: Arc, block_hash: Hash256) -> Hash256 { - for el_client in &self.el_clients { - let block = match el_client.get_block_by_hash(block_hash).await { - Ok(Some(data)) => data, - Ok(None) => { - debug!(block_hash = %block_hash, "Block not found on EL"); - continue; - } - Err(e) => { - warn!(block_hash = %block_hash, error = %e, "Failed to fetch block from EL"); - continue; - } - }; - - let witness = match el_client.get_execution_witness_by_hash(block_hash).await { - Ok(Some(data)) => data, - Ok(None) => { - debug!(block_hash = %block_hash, "Witness not found on EL"); - continue; - } - Err(e) => { - warn!(block_hash = %block_hash, error = %e, "Failed to fetch witness from EL"); - continue; - } - }; - - let block_number = block.header.number; - let el_data = ElBlockWitness { block, witness }; - - info!( - block_number = block_number, - block_hash = %block_hash, - "Fetched block and witness from EL" - ); - - if let Some(storage) = &self.storage { - let mut storage_guard = storage.lock().await; - if let Err(e) = storage_guard.save_el_data(&el_data) { - warn!(block_hash = %block_hash, error = %e, "Failed to save fetched block to disk"); - } else { - debug!( - block_number = block_number, - block_hash = %block_hash, - "Saved fetched block to disk" - ); - } - } - - let mut cache = self.el_data_cache.lock().await; - cache.put(block_hash, el_data); - debug!(block_hash = %block_hash, "Cached fetched block in memory"); - - self.send_block_data_ready(block_hash).await; - - return block_hash; - } - - error!( - block_hash = %block_hash, - "Failed to fetch block and witness from any EL" - ); - - block_hash - } - - /// Notifies the proof service that block data is available. - async fn send_block_data_ready(&self, block_hash: Hash256) { - let msg = ProofServiceMessage::BlockDataReady { block_hash }; - if let Err(e) = self.proof_tx.send(msg).await { - error!(error = %e, "Failed to send block ready notification"); - } - } -} diff --git a/crates/execution-witness-sentry/src/service/el_event.rs b/crates/execution-witness-sentry/src/service/el_event.rs deleted file mode 100644 index f6f00c6..0000000 --- a/crates/execution-witness-sentry/src/service/el_event.rs +++ /dev/null @@ -1,113 +0,0 @@ -//! # EL Event Service -//! -//! This module provides [`ElEventService`], which subscribes to EL head events via WebSocket and -//! triggers block data fetching. -//! -//! ## Purpose -//! -//! The EL event services notifies [`ElDataService`](super::el_data::ElDataService) when a new block -//! arrives, to retrieve the full block data and witness. - -use std::{pin::pin, sync::Arc, time::Duration}; - -use futures::StreamExt; -use tokio::{sync::mpsc, task::JoinHandle}; -use tokio_util::sync::CancellationToken; -use tracing::{error, info, warn}; - -use crate::{ElEndpoint, Header, service::el_data::ElDataServiceMessage, subscribe_blocks}; - -/// Subscribes to EL head events via WebSocket and triggers block data fetching. -/// -/// This service maintains a WebSocket connection to an execution layer node, listening for -/// `newHeads` events. When a new block header arrives, it requests [`ElDataService`] to fetch -/// the full block data and execution witness. -/// -/// [`ElDataService`]: super::el_data::ElDataService -pub struct ElEventService { - /// Configuration for the EL endpoint (name and WebSocket URL). - endpoint: ElEndpoint, - /// Channel to send fetch requests to [`ElDataService`]. - el_data_tx: mpsc::Sender, -} - -impl ElEventService { - /// Creates a new EL event service for the given endpoint. - pub fn new(endpoint: ElEndpoint, el_data_tx: mpsc::Sender) -> Self { - Self { - endpoint, - el_data_tx, - } - } - - /// Processes an incoming block header by sending a fetch request to [`ElDataService`]. - async fn handle_header(&self, header: Header) { - let block_hash = header.hash; - info!( - name = %self.endpoint.name, - number = header.number, - hash = %block_hash, - "EL block header received" - ); - - let message = ElDataServiceMessage::FetchData { block_hash }; - if let Err(error) = self.el_data_tx.send(message).await { - error!(block_hash = %block_hash, error = %error, "Failed to send block fetch request"); - } - } - - /// Spawns the service as a background task. - pub fn spawn(self: Arc, shutdown_token: CancellationToken) -> JoinHandle<()> { - tokio::spawn(self.run(shutdown_token)) - } - - /// Main event loop that processes EL head events until shutdown. - async fn run(self: Arc, shutdown_token: CancellationToken) { - const RECONNECT_DELAY: Duration = Duration::from_secs(2); - - let name = &self.endpoint.name; - let ws_url = &self.endpoint.ws_url; - - loop { - info!(name = %name, "Connecting to EL WebSocket"); - - let stream = match subscribe_blocks(ws_url).await { - Ok(s) => s, - Err(e) => { - warn!(name = %name, error = %e, "Failed to subscribe to EL, retrying in 5 seconds"); - tokio::select! { - _ = shutdown_token.cancelled() => { - info!(name = %name, "ElEventService received shutdown signal"); - break; - } - _ = tokio::time::sleep(RECONNECT_DELAY) => continue, - } - } - }; - - info!(name = %name, "Subscribed to EL newHeads"); - let mut stream = pin!(stream); - - loop { - tokio::select! { - biased; - - _ = shutdown_token.cancelled() => { - info!(name = %name, "ElEventService received shutdown signal"); - return; - } - - result = stream.next() => { - match result { - Some(Ok(header)) => self.handle_header(header).await, - Some(Err(e)) => error!(name = %name, error = %e, "EL stream error"), - None => break, - } - } - } - } - - warn!(name = %name, "EL WebSocket stream ended, reconnecting"); - } - } -} diff --git a/crates/execution-witness-sentry/src/service/proof.rs b/crates/execution-witness-sentry/src/service/proof.rs deleted file mode 100644 index 10a9993..0000000 --- a/crates/execution-witness-sentry/src/service/proof.rs +++ /dev/null @@ -1,809 +0,0 @@ -//! Proof generation and submission service. -//! -//! This module provides [`ProofService`], which is responsible for coordinating proof generation -//! requests and submissions to CL clients.' -//! -//! ## Purpose -//! -//! The services send proof generation request to proof engine, and starts a http server to receive -//! proof result via webhook. -//! -//! Internally it receives messages via [`ProofServiceMessage`]: -//! -//! - [`RequestProof`] - Request proof generation for a block. Sent by [`ClEventService`] on new -//! head events and [`BackfillService`] for gap filling. -//! -//! - [`BlockDataReady`] - Notification that EL block data is now available. Sent by -//! [`ElDataService`] after fetching block and witness data. Triggers processing of any pending -//! requests for that block. -//! -//! [`BackfillService`]: super::backfill::BackfillService -//! [`ClEventService`]: super::cl_event::ClEventService -//! [`ElDataService`]: super::el_data::ElDataService -//! [`RequestProof`]: ProofServiceMessage::RequestProof -//! [`BlockDataReady`]: ProofServiceMessage::BlockDataReady - -use std::{ - collections::{BTreeMap, HashMap, hash_map::Entry}, - net::{Ipv4Addr, SocketAddr}, - num::NonZeroUsize, - sync::Arc, - time::{Duration, Instant}, -}; - -use alloy_genesis::ChainConfig; -use alloy_primitives::B256; -use axum::{ - Json, Router, - extract::State, - http::StatusCode, - routing::{get, post}, -}; -use lru::LruCache; -use reth_stateless::StatelessInput; -use tokio::{ - net::TcpListener, - sync::{Mutex, mpsc}, - task::JoinHandle, -}; -use tokio_util::sync::CancellationToken; -use tower_http::trace::TraceLayer; -use tracing::{debug, error, info, warn}; -use zkboost_ethereum_el_input::ElInput; -use zkboost_ethereum_el_types::ElProofType; -use zkboost_types::{ProofGenId, ProofResult}; - -use crate::{ - BlockStorage, ClClient, ElBlockWitness, ExecutionProof, ProofEngineClient, - config::ProofEngineConfig, - rpc::Hash256, - service::{Target, is_el_data_available}, - storage::Proof, -}; - -/// Timeout of pending proof from proof engine webhook (10 mins). -const IN_FLIGHT_PROOF_TIMEOUT: Duration = Duration::from_secs(600); -/// Timeout of pending request due to unavailable EL data (10 mins). -const PENDING_REQUEST_TIMEOUT: Duration = Duration::from_secs(600); -/// Interval to cleanup timeout objects. -const CLEANUP_INTERVAL: Duration = Duration::from_secs(60); -/// Max retries for proof submission. -const PROOF_SUBMISSION_MAX_RETRIES: u32 = 3; - -/// Identifier for a proof consist of `block_hash` and `proof_type`. -type ProofKey = (B256, ElProofType); - -/// Messages handled by [`ProofService`]. -/// -/// These messages coordinate proof generation and submission workflows. -pub enum ProofServiceMessage { - /// Notification that EL block data is now available in cache. - /// - /// Sent by [`ElDataService`](super::el_data::ElDataService) after fetching - /// block and witness data. Triggers processing of any pending proof requests - /// for this block. - BlockDataReady { - /// The execution block hash for which data is now available. - block_hash: B256, - }, - /// Request proof generation for a specific block. - /// - /// Sent by [`ClEventService`](super::cl_event::ClEventService) on new head - /// events and [`BackfillService`](super::backfill::BackfillService) for gap - /// filling. - RequestProof { - /// Beacon chain slot number. - slot: u64, - /// Beacon block root hash. - block_root: Hash256, - /// Execution layer block hash. - execution_block_hash: B256, - /// CL clients to submit the proof to. - target_clients: Target, - /// Proof types to generate. - target_proof_types: Target, - }, -} - -/// A proof request awaiting EL block data availability. -/// -/// Created when a proof is requested but the block data is not yet cached. -/// Processed when [`ProofServiceMessage::BlockDataReady`] is received for -/// the corresponding block. -#[derive(Clone)] -struct PendingRequest { - /// Beacon chain slot number. - slot: u64, - /// Beacon block root hash. - block_root: Hash256, - /// CL clients to submit the proof to once generated. - target_clients: Target, - /// Timestamp when this request was created, used for staleness cleanup. - created_at: Instant, -} - -/// A proof generation job awaiting completion from the proof engine. -/// -/// Created when a proof request is submitted to the proof engine. Tracked -/// until the proof engine delivers the result via webhook, or the entry -/// times out. -#[derive(Debug, Clone)] -struct InFlightProof { - /// Type of proof being generated. - proof_type: ElProofType, - /// Beacon chain slot number. - slot: u64, - /// Execution block hash being proven. - block_hash: B256, - /// Beacon block root hash. - beacon_block_root: Hash256, - /// CL clients to submit the proof to once generated. - target_clients: Target, - /// Timestamp when this proof was requested, used for timeout detection. - created_at: Instant, - /// Unique identifier returned by the proof engine for tracking. - proof_gen_id: Option, -} - -/// Coordinates proof generation and submission to CL clients. -/// -/// This service manages the full lifecycle of proof generation: -/// -/// 1. Receives proof requests from [`ClEventService`](super::cl_event::ClEventService) and -/// [`BackfillService`](super::backfill::BackfillService) -/// 2. Queues requests if EL block data is not yet available -/// 3. Submits proof jobs to the proof engine -/// 4. Receives completed proofs via webhook -/// 5. Caches and persists proofs for reuse -/// 6. Submits proofs to target CL clients -#[derive(Clone)] -pub struct ProofService { - /// Port for the webhook HTTP server to receive proof results. - webhook_port: u16, - /// Client for communicating with the proof engine. - proof_engine_client: Arc, - /// Chain configuration for constructing stateless inputs. - chain_config: ChainConfig, - /// CL clients to submit proofs to. - zkvm_enabled_cl_clients: Vec>, - /// Shared cache of EL block data (block + witness). - el_data_cache: Arc>>, - /// In-memory cache of generated proofs by block hash and proof type. - proof_cache: Arc>>, - /// Optional persistent storage for proofs. - storage: Option>>, - /// Proof requests waiting for EL data to become available. - pending_requests: Arc>>>, - /// Proof jobs submitted to the engine, awaiting webhook callback. - in_flight_proofs: Arc>>, - /// Mapping from proof engine job IDs to proof key. - proof_gen_ids: Arc>>, -} - -impl ProofService { - /// Creates a new proof service with the given configuration. - pub fn new( - proof_engine_config: ProofEngineConfig, - chain_config: ChainConfig, - zkvm_enabled_cl_clients: Vec>, - el_data_cache: Arc>>, - storage: Option>>, - ) -> anyhow::Result { - let proof_engine_client = Arc::new(ProofEngineClient::new( - proof_engine_config.url.clone(), - proof_engine_config.proof_types.clone(), - )?); - - let proof_cache = Arc::new(Mutex::new(LruCache::new(NonZeroUsize::new(1024).unwrap()))); - let pending_requests = Arc::new(Mutex::new(HashMap::new())); - let in_flight_proofs = Arc::new(Mutex::new(HashMap::new())); - let proof_gen_ids = Arc::new(Mutex::new(HashMap::new())); - - Ok(Self { - webhook_port: proof_engine_config.webhook_port, - proof_engine_client, - chain_config, - zkvm_enabled_cl_clients, - el_data_cache, - proof_cache, - storage, - pending_requests, - in_flight_proofs, - proof_gen_ids, - }) - } - - /// Spawns webhook HTTP server and message processing loop. - pub async fn spawn( - self: Arc, - shutdown_token: CancellationToken, - proof_rx: mpsc::Receiver, - ) -> anyhow::Result>> { - let http_handle = spawn_webhook_server(self.clone(), shutdown_token.clone()).await?; - let service_handle = tokio::spawn(self.run(shutdown_token, proof_rx)); - Ok(vec![http_handle, service_handle]) - } - - /// Main event loop that processes incoming messages until shutdown. - async fn run( - self: Arc, - shutdown_token: CancellationToken, - mut proof_rx: mpsc::Receiver, - ) { - let mut cleanup_interval = tokio::time::interval(CLEANUP_INTERVAL); - - loop { - tokio::select! { - biased; - - _ = shutdown_token.cancelled() => { - info!("ProofService received shutdown signal"); - break; - } - - _ = cleanup_interval.tick() => { - self.cleanup_stale_entries().await; - } - - Some(message) = proof_rx.recv() => { - match message { - ProofServiceMessage::RequestProof { - slot, - block_root, - execution_block_hash, - target_clients, - target_proof_types, - } => { - for &proof_type in self - .proof_engine_client - .proof_types() - .iter() - .filter(|proof_type| target_proof_types.contains(proof_type)) - { - self.handle_request_proof( - slot, - block_root, - execution_block_hash, - target_clients.clone(), - proof_type, - ) - .await; - } - } - ProofServiceMessage::BlockDataReady { block_hash } => { - self.handle_block_data_ready(block_hash).await; - } - } - } - - else => break, - } - } - } - - /// Removes stale pending requests and proof jobs that have timed out. - async fn cleanup_stale_entries(&self) { - let mut pending_requests_guard = self.pending_requests.lock().await; - - for (&block_hash, proof_type_map) in pending_requests_guard.iter_mut() { - proof_type_map.retain(|proof_type, pending_request| { - let is_stale = pending_request.created_at.elapsed() >= PENDING_REQUEST_TIMEOUT; - if is_stale { - warn!( - block_hash = %block_hash, - proof_type = %proof_type, - slot = pending_request.slot, - elapsed_secs = pending_request.created_at.elapsed().as_secs(), - "Removing stale pending request" - ); - } - !is_stale - }); - } - - pending_requests_guard.retain(|_, map| !map.is_empty()); - - drop(pending_requests_guard); - - let mut in_flight_proofs_guard = self.in_flight_proofs.lock().await; - let mut proof_gen_ids_guard = self.proof_gen_ids.lock().await; - - let mut stale_proof_keys = Vec::new(); - for (proof_key, in_flight_proof) in in_flight_proofs_guard.iter() { - if in_flight_proof.created_at.elapsed() >= IN_FLIGHT_PROOF_TIMEOUT { - warn!( - block_hash = %proof_key.0, - proof_type = %proof_key.1, - slot = in_flight_proof.slot, - elapsed_secs = in_flight_proof.created_at.elapsed().as_secs(), - "Removing stale in-flight proof" - ); - stale_proof_keys.push((*proof_key, in_flight_proof.proof_gen_id.clone())); - } - } - for (proof_key, proof_gen_id) in stale_proof_keys { - in_flight_proofs_guard.remove(&proof_key); - if let Some(proof_gen_id) = proof_gen_id { - proof_gen_ids_guard.remove(&proof_gen_id); - } - } - } - - /// Handles a proof request. - /// - /// - If the proof already exists in cache/storage, submits it immediately. - /// - If EL data is available, requests proof generation. - /// - If EL data is not yet available, queues the request as pending. - async fn handle_request_proof( - &self, - slot: u64, - block_root: Hash256, - execution_block_hash: B256, - target_clients: Target, - proof_type: ElProofType, - ) { - debug!( - slot = slot, - block_root = %block_root, - exec_hash = %execution_block_hash, - proof_type = %proof_type, - "Processing proof request" - ); - - if let Some(saved_proof) = self.load_proof(execution_block_hash, proof_type).await { - self.submit_proofs( - &target_clients, - slot, - execution_block_hash, - block_root, - proof_type, - saved_proof.proof_data, - ) - .await; - return; - } - - if is_el_data_available(&self.el_data_cache, &self.storage, execution_block_hash).await { - self.request_proof( - slot, - block_root, - execution_block_hash, - &target_clients, - proof_type, - ) - .await; - } else { - info!(block_hash = %execution_block_hash, proof_type = %proof_type, "EL data not available, inserting pending request"); - - let mut pending_guard = self.pending_requests.lock().await; - let block_requests = pending_guard.entry(execution_block_hash).or_default(); - - block_requests - .entry(proof_type) - .and_modify(|existing| { - existing.target_clients = existing.target_clients.union(&target_clients); - }) - .or_insert_with(|| PendingRequest { - slot, - block_root, - target_clients: target_clients.clone(), - created_at: Instant::now(), - }); - } - } - - /// Processes pending proof requests when EL block data becomes available. - async fn handle_block_data_ready(&self, block_hash: B256) { - debug!(block_hash = %block_hash, "Block ready notification received"); - - let pending_requests = self.pending_requests.lock().await.remove(&block_hash); - let Some(pending_requests) = pending_requests else { - debug!(block_hash = %block_hash, "No pending proof requests for this block"); - return; - }; - - for (proof_type, pending_request) in pending_requests { - if let Some(saved_proof) = self.load_proof(block_hash, proof_type).await { - self.submit_proofs( - &pending_request.target_clients, - pending_request.slot, - block_hash, - pending_request.block_root, - proof_type, - saved_proof.proof_data, - ) - .await; - } else { - self.request_proof( - pending_request.slot, - pending_request.block_root, - block_hash, - &pending_request.target_clients, - proof_type, - ) - .await; - } - } - } - - /// Loads a proof from cache or disk storage. - async fn load_proof(&self, block_hash: B256, proof_type: ElProofType) -> Option { - { - let mut cache = self.proof_cache.lock().await; - if let Some(proof) = cache.get(&(block_hash, proof_type)) { - debug!(block_hash = %block_hash, proof_type = %proof_type, "Load proof from cache"); - return Some(proof.clone()); - } - } - - if let Some(storage) = &self.storage { - let storage_guard = storage.lock().await; - match storage_guard.load_proof(block_hash, proof_type) { - Ok(Some(proof)) => { - debug!(block_hash = %block_hash, proof_type = %proof_type, "Load proof from disk"); - drop(storage_guard); - - let mut cache = self.proof_cache.lock().await; - cache.put((block_hash, proof_type), proof.clone()); - - return Some(proof); - } - Ok(None) => {} - Err(e) => { - warn!(block_hash = %block_hash, proof_type = %proof_type, error = %e, "Failed to load proof from disk"); - } - } - } - - None - } - - /// Submits a proof generation request to the proof engine. - /// - /// Deduplicates requests by checking if a proof job is already in flight - /// for this block and proof type. If a previous request has timed out, - /// allows retry. - async fn request_proof( - &self, - slot: u64, - block_root: Hash256, - block_hash: B256, - target_clients: &Target, - proof_type: ElProofType, - ) { - let (block, witness) = { - let cache = self.el_data_cache.lock().await; - match cache.peek(&block_hash) { - Some(cached) => (cached.block.clone(), cached.witness.clone()), - None => { - warn!( - slot = slot, - block_hash = %block_hash, - "Block data not in cache for proof generation" - ); - return; - } - } - }; - - let stateless_input = StatelessInput { - block, - witness, - chain_config: self.chain_config.clone(), - }; - let el_input = ElInput::new(stateless_input); - - let proof_id = proof_type.proof_id(); - let proof_key = (block_hash, proof_type); - - { - let mut in_flight_proofs_guard = self.in_flight_proofs.lock().await; - let mut proof_gen_ids_guard = self.proof_gen_ids.lock().await; - - match in_flight_proofs_guard.entry(proof_key) { - Entry::Occupied(mut entry) => { - let in_flight_proof = entry.get_mut(); - if in_flight_proof.created_at.elapsed() < IN_FLIGHT_PROOF_TIMEOUT { - debug!( - slot = slot, - block_hash = %block_hash, - proof_id = proof_id, - "Proof already in flight, skipping" - ); - return; - } - warn!( - slot = slot, - block_hash = %block_hash, - proof_id = proof_id, - elapsed_secs = ?in_flight_proof.created_at.elapsed().as_secs(), - "Proof request timed out, retrying" - ); - - in_flight_proof.created_at = Instant::now(); - if let Some(proof_gen_id) = in_flight_proof.proof_gen_id.take() { - proof_gen_ids_guard.remove(&proof_gen_id); - } - } - Entry::Vacant(entry) => { - entry.insert(InFlightProof { - proof_type, - slot, - block_hash, - beacon_block_root: block_root, - target_clients: target_clients.clone(), - created_at: Instant::now(), - proof_gen_id: None, - }); - } - } - } - - match self - .proof_engine_client - .request_proof(&proof_type, &el_input) - .await - { - Ok(proof_gen_id) => { - let mut in_flight_proofs_guard = self.in_flight_proofs.lock().await; - let mut proof_gen_ids_guard = self.proof_gen_ids.lock().await; - - if let Some(in_flight) = in_flight_proofs_guard.get_mut(&proof_key) { - in_flight.proof_gen_id = Some(proof_gen_id.clone()); - proof_gen_ids_guard.insert(proof_gen_id.clone(), proof_key); - }; - - info!( - slot = slot, - block_hash = %block_hash, - proof_id = proof_id, - proof_gen_id = %proof_gen_id, - "Proof job submitted to proof engine" - ); - } - Err(e) => { - self.in_flight_proofs.lock().await.remove(&proof_key); - - error!( - slot = slot, - block_hash = %block_hash, - proof_id = proof_id, - error = %e, - "Failed to submit proof to proof engine" - ); - } - } - } - - /// Spawns tasks to submit a proof to target CL clients. - async fn submit_proofs( - &self, - target_clients: &Target, - slot: u64, - block_hash: B256, - block_root: Hash256, - proof_type: ElProofType, - proof_data: Vec, - ) { - let cl_clients = self - .zkvm_enabled_cl_clients - .iter() - .filter(|cl_client| target_clients.contains(cl_client.name())) - .collect::>(); - - let proof_id = proof_type.proof_id(); - - let mut handles = Vec::new(); - - for client in cl_clients { - let execution_proof = ExecutionProof { - proof_id, - slot, - block_hash, - block_root, - proof_data: proof_data.clone(), - }; - - handles.push(tokio::spawn(submit_proof(client.clone(), execution_proof))); - } - - for handle in handles { - if let Err(e) = handle.await - && e.is_panic() - { - error!(error = ?e, "Proof submission task panicked"); - } - } - } -} - -/// Submit a proof to a single CL client with internal retry loop and exponential backoff. -async fn submit_proof(client: Arc, execution_proof: ExecutionProof) { - let cl_name = client.name().to_string(); - let slot = execution_proof.slot; - let proof_id = execution_proof.proof_id; - - for retry_count in 0..=PROOF_SUBMISSION_MAX_RETRIES { - match client.submit_execution_proof(&execution_proof).await { - Ok(()) => { - if retry_count == 0 { - info!( - cl = %cl_name, - slot = slot, - proof_id = proof_id, - "Proof submitted to CL" - ); - } else { - info!( - cl = %cl_name, - slot = slot, - proof_id = proof_id, - retry_count = retry_count, - "Proof submitted to CL (retry succeeded)" - ); - } - return; - } - Err(e) => { - let msg = e.to_string(); - if msg.contains("already known") { - debug!( - cl = %cl_name, - slot = slot, - proof_id = proof_id, - "Proof already known to CL" - ); - return; - } - - if retry_count >= PROOF_SUBMISSION_MAX_RETRIES { - error!( - cl = %cl_name, - slot = slot, - proof_id = proof_id, - retry_count = retry_count, - error = %e, - "Proof submission to CL failed, max retries exceeded" - ); - return; - } - - let backoff = Duration::from_secs(2u64.pow(retry_count)); - warn!( - cl = %cl_name, - slot = slot, - proof_id = proof_id, - retry_count = retry_count, - next_retry_secs = backoff.as_secs(), - error = %e, - "Proof submission to CL failed, retrying" - ); - tokio::time::sleep(backoff).await; - } - } - } -} - -/// Spawns the HTTP server that receives proof results via webhook. -async fn spawn_webhook_server( - state: Arc, - shutdown_token: CancellationToken, -) -> anyhow::Result> { - let addr = SocketAddr::new(Ipv4Addr::UNSPECIFIED.into(), state.webhook_port); - let listener = TcpListener::bind(&addr).await?; - info!(addr = %addr, "HTTP server listening for proof pushes"); - - Ok(tokio::spawn(async move { - let app = Router::new() - .route("/proofs", post(proof_webhook)) - .route("/health", get(StatusCode::OK)) - .with_state(state) - .layer(TraceLayer::new_for_http()) - // 10MB limit to account for the proof size - .layer(axum::extract::DefaultBodyLimit::max(10 * 1024 * 1024)); - - if let Err(e) = axum::serve(listener, app) - .with_graceful_shutdown(shutdown_token.cancelled_owned()) - .await - { - error!(error = %e, "HTTP server error"); - } - })) -} - -/// Axum handler for receiving proof results from the proof engine. -/// -/// Caches the proof, persists to storage if configured, and submits to -/// target CL clients. -async fn proof_webhook( - State(state): State>, - Json(proof_result): Json, -) -> Result { - info!( - proof_gen_id = %proof_result.proof_gen_id, - "Proof received from proof engine via webhook" - ); - - let Some(proof_key) = state - .proof_gen_ids - .lock() - .await - .remove(&proof_result.proof_gen_id) - else { - error!( - proof_gen_id = %proof_result.proof_gen_id, - "Unknown proof_gen_id" - ); - return Err(( - StatusCode::BAD_REQUEST, - format!("Unknown proof_gen_id {}", proof_result.proof_gen_id), - )); - }; - - let Some(in_flight_proof) = state.in_flight_proofs.lock().await.remove(&proof_key) else { - error!( - proof_gen_id = %proof_result.proof_gen_id, - block_hash = %proof_key.0, - proof_type = %proof_key.1, - "Missing in-flight proof" - ); - return Err(( - StatusCode::INTERNAL_SERVER_ERROR, - "Missing in-flight proof".to_string(), - )); - }; - - if let Some(error) = &proof_result.error { - // TODO: Figure out the proof generatoin retry strategy. - - error!( - proof_gen_id = %proof_result.proof_gen_id, - proof_type = %in_flight_proof.proof_type, - slot = in_flight_proof.slot, - block_hash = %in_flight_proof.block_hash, - error = %error, - "Proof generation failed" - ); - return Ok(StatusCode::OK); - } - - let mut cache = state.proof_cache.lock().await; - cache.put( - (in_flight_proof.block_hash, in_flight_proof.proof_type), - Proof { - proof_type: in_flight_proof.proof_type, - proof_data: proof_result.proof.clone(), - }, - ); - drop(cache); - - if let Some(ref storage) = state.storage { - let mut storage_guard = storage.lock().await; - if let Err(e) = storage_guard.save_proof( - in_flight_proof.block_hash, - in_flight_proof.proof_type, - &proof_result.proof, - ) { - warn!(slot = in_flight_proof.slot, error = %e, "Failed to save proof to disk"); - } else { - debug!( - proof_gen_id = %proof_result.proof_gen_id, - proof_type = %in_flight_proof.proof_type, - slot = in_flight_proof.slot, - "Proof saved" - ); - } - } - state - .submit_proofs( - &in_flight_proof.target_clients, - in_flight_proof.slot, - in_flight_proof.block_hash, - in_flight_proof.beacon_block_root, - in_flight_proof.proof_type, - proof_result.proof.clone(), - ) - .await; - - Ok(StatusCode::OK) -} diff --git a/crates/execution-witness-sentry/src/storage.rs b/crates/execution-witness-sentry/src/storage.rs deleted file mode 100644 index 170f05e..0000000 --- a/crates/execution-witness-sentry/src/storage.rs +++ /dev/null @@ -1,285 +0,0 @@ -//! Block data storage utilities. - -use std::{ - collections::VecDeque, - io::{Read, Write}, - path::PathBuf, -}; - -use flate2::{Compression, read::GzDecoder, write::GzEncoder}; -use reth_ethereum_primitives::Block; -use reth_stateless::ExecutionWitness; -use serde::{Deserialize, Serialize}; -use zkboost_ethereum_el_types::ElProofType; - -use crate::{error::Result, rpc::Hash256}; - -/// Metadata stored alongside block data. -#[derive(Debug, Clone, Default, Serialize, Deserialize)] -pub struct BlockMetadata { - /// EL block hash - pub block_hash: Hash256, - /// EL block number - pub block_number: Option, - /// Gas used in the block - pub gas_used: Option, - /// CL slot number (if known) - #[serde(skip_serializing_if = "Option::is_none")] - pub slot: Option, - /// CL beacon block root (if known) - #[serde(skip_serializing_if = "Option::is_none")] - pub beacon_block_root: Option, -} - -/// EL block and execution witness data. -#[derive(Serialize, Deserialize)] -pub struct ElBlockWitness { - /// EL block. - pub block: Block, - /// Execution witness. - pub witness: ExecutionWitness, -} - -/// A saved proof that can be loaded for backfill. -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct Proof { - /// Proof type - pub proof_type: ElProofType, - /// Proof data - pub proof_data: Vec, -} - -/// Compress data using gzip. -pub fn compress_gzip(data: &[u8]) -> Result> { - let mut encoder = GzEncoder::new(Vec::new(), Compression::default()); - encoder.write_all(data)?; - Ok(encoder.finish()?) -} - -/// Decompress gzip data. -pub fn decompress_gzip(data: &[u8]) -> Result> { - let mut decoder = GzDecoder::new(data); - let mut decompressed = Vec::new(); - decoder.read_to_end(&mut decompressed)?; - Ok(decompressed) -} - -/// Manages EL block data and proof storage on disk. -/// -/// `BlockStorage` organizes data in a directory structure: -/// ```text -/// {output_dir}/{chain}/{block_hash}/ -/// ├── metadata.json # Block metadata (slot, block number, etc.) -/// ├── data.json.gz # Compressed block + witness data -/// └── proof/ -/// └── {proof_type}.json # Compressed proofs by type -/// ``` -/// -/// ## Retention Policy -/// -/// When configured with a retention limit, old block directories are automatically -/// deleted as new blocks are saved, maintaining a sliding window of the most -/// recent blocks. This prevents unbounded disk usage. -pub struct BlockStorage { - /// Root directory for all stored data. - output_dir: PathBuf, - /// Chain identifier used as a subdirectory name (e.g., "mainnet", "holesky"). - chain: String, - /// Queue of block hashes for retention tracking. When full, the oldest - /// entry is removed and its directory deleted. `None` disables retention. - retained: Option>, -} - -impl BlockStorage { - /// Create a new block storage manager. - pub fn new( - output_dir: impl Into, - chain: impl Into, - retain: Option, - ) -> Self { - Self { - output_dir: output_dir.into(), - chain: chain.into(), - retained: retain.map(|retain| VecDeque::with_capacity(retain as usize)), - } - } - - /// Get the chain directory path. - pub fn chain_dir(&self) -> PathBuf { - self.output_dir.join(&self.chain) - } - - /// Get the directory path for a block hash. - pub fn block_dir(&self, block_hash: Hash256) -> PathBuf { - self.chain_dir().join(block_hash.to_string()) - } - - /// Save CL block header data to disk. - pub fn save_cl_data( - &mut self, - block_hash: Hash256, - slot: u64, - beacon_block_root: Hash256, - ) -> Result<()> { - let block_dir = self.block_dir(block_hash); - std::fs::create_dir_all(&block_dir)?; - - // Load existing metadata or create new - let metadata_path = block_dir.join("metadata.json"); - let mut metadata = if metadata_path.exists() { - let content = std::fs::read_to_string(&metadata_path)?; - serde_json::from_str(&content)? - } else { - BlockMetadata { - block_hash, - ..Default::default() - } - }; - - metadata.slot = Some(slot); - metadata.beacon_block_root = Some(beacon_block_root); - - std::fs::write(&metadata_path, serde_json::to_string_pretty(&metadata)?)?; - - Ok(()) - } - - /// Save EL block and witness to disk. - pub fn save_el_data(&mut self, el_data: &ElBlockWitness) -> Result<()> { - let block_number = el_data.block.header.number; - let block_hash = el_data.block.hash_slow(); - let gas_used = el_data.block.header.gas_used; - - let block_dir = self.block_dir(block_hash); - std::fs::create_dir_all(&block_dir)?; - - // Load existing metadata or create new - let metadata_path = block_dir.join("metadata.json"); - let mut metadata = if metadata_path.exists() { - let content = std::fs::read_to_string(&metadata_path)?; - serde_json::from_str(&content)? - } else { - BlockMetadata { - block_hash, - ..Default::default() - } - }; - - // Update with EL info - metadata.block_number = Some(block_number); - metadata.gas_used = Some(gas_used); - - // Save updated metadata - std::fs::write(&metadata_path, serde_json::to_string_pretty(&metadata)?)?; - - // Write combined block + witness data - let data_path = block_dir.join("data.json.gz"); - let compressed = compress_gzip(&serde_json::to_vec(&el_data)?)?; - std::fs::write(data_path, compressed)?; - - if let Some(expired) = self.retained.as_mut().and_then(|retained| { - let expired = (retained.len() == retained.capacity()).then(|| retained.pop_front()); - retained.push_back(block_hash); - expired.flatten() - }) { - self.delete_old_block(expired)?; - } - - Ok(()) - } - - /// Save a execution proof to disk. - /// - /// Proofs are stored in a `proof/` subdirectory under the block's directory, - /// with the filename based on the proof type. - pub fn save_proof( - &mut self, - block_hash: Hash256, - proof_type: ElProofType, - proof_data: &[u8], - ) -> Result<()> { - let proof = Proof { - proof_type, - proof_data: proof_data.to_vec(), - }; - - let block_dir = self.block_dir(block_hash); - std::fs::create_dir_all(&block_dir)?; - - let proof_dir = block_dir.join("proof"); - std::fs::create_dir_all(&proof_dir)?; - - let proof_path = proof_dir.join(format!("{proof_type}.json")); - let compressed = compress_gzip(&serde_json::to_vec(&proof)?)?; - std::fs::write(&proof_path, compressed)?; - - Ok(()) - } - - /// Load metadata for a given block hash. - pub fn load_metadata(&self, block_hash: Hash256) -> Result> { - let block_dir = self.block_dir(block_hash); - let metadata_path = block_dir.join("metadata.json"); - - if !metadata_path.exists() { - return Ok(None); - } - - let content = std::fs::read_to_string(&metadata_path)?; - Ok(Some(serde_json::from_str(&content)?)) - } - - /// Load EL block and witness data from disk. - pub fn load_el_data(&self, block_hash: Hash256) -> Result> { - let block_dir = self.block_dir(block_hash); - let data_path = block_dir.join("data.json.gz"); - - if !data_path.exists() { - return Ok(None); - } - - let compressed = std::fs::read(data_path)?; - let el_data = serde_json::from_slice(&decompress_gzip(&compressed)?)?; - - Ok(Some(el_data)) - } - - /// Load proof from disk. - /// - /// Returns `None` if no proof of the specified type exists for the given block. - pub fn load_proof( - &self, - block_hash: Hash256, - proof_type: ElProofType, - ) -> Result> { - let block_dir = self.block_dir(block_hash); - - if !block_dir.exists() { - return Ok(None); - } - - let proof_dir = block_dir.join("proof"); - if !proof_dir.exists() { - return Ok(None); - } - - let proof_path = proof_dir.join(format!("{proof_type}.json")); - if !proof_path.exists() { - return Ok(None); - } - - let compressed = std::fs::read(proof_path)?; - let proof = serde_json::from_slice(&decompress_gzip(&compressed)?)?; - - Ok(Some(proof)) - } - - /// Delete an old block directory. - fn delete_old_block(&self, block_hash: Hash256) -> Result<()> { - let old_dir = self.block_dir(block_hash); - if old_dir.exists() { - std::fs::remove_dir_all(old_dir)?; - } - Ok(()) - } -} diff --git a/crates/execution-witness-sentry/tests/cl_subscription.rs b/crates/execution-witness-sentry/tests/cl_subscription.rs deleted file mode 100644 index 40d8689..0000000 --- a/crates/execution-witness-sentry/tests/cl_subscription.rs +++ /dev/null @@ -1,11 +0,0 @@ -use execution_witness_sentry::subscribe_cl_events; - -#[test] -fn subscribe_cl_events_accepts_base_url_without_trailing_slash() { - assert!(subscribe_cl_events("http://localhost:5052").is_ok()); -} - -#[test] -fn subscribe_cl_events_accepts_base_url_with_trailing_slash() { - assert!(subscribe_cl_events("http://localhost:5052/").is_ok()); -} diff --git a/crates/zkboost/guest-loader/Cargo.toml b/crates/guest-loader/Cargo.toml similarity index 100% rename from crates/zkboost/guest-loader/Cargo.toml rename to crates/guest-loader/Cargo.toml diff --git a/crates/zkboost/guest-loader/src/lib.rs b/crates/guest-loader/src/lib.rs similarity index 100% rename from crates/zkboost/guest-loader/src/lib.rs rename to crates/guest-loader/src/lib.rs diff --git a/crates/zkboost/guest-loader/src/main.rs b/crates/guest-loader/src/main.rs similarity index 100% rename from crates/zkboost/guest-loader/src/main.rs rename to crates/guest-loader/src/main.rs diff --git a/crates/zkboost/guest-loader/tests/cli.rs b/crates/guest-loader/tests/cli.rs similarity index 100% rename from crates/zkboost/guest-loader/tests/cli.rs rename to crates/guest-loader/tests/cli.rs diff --git a/crates/mock-zkattestor/Cargo.toml b/crates/mock-zkattestor/Cargo.toml new file mode 100644 index 0000000..aa2f626 --- /dev/null +++ b/crates/mock-zkattestor/Cargo.toml @@ -0,0 +1,33 @@ +[package] +name = "mock-zkattestor" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true + +[lints] +workspace = true + +[dependencies] +anyhow.workspace = true +async-stream = "0.3" +clap = { workspace = true, features = ["derive"] } +futures.workspace = true +reqwest = { workspace = true, features = ["json"] } +reqwest-eventsource.workspace = true +serde = { workspace = true, features = ["derive"] } +serde_json.workspace = true +sha2.workspace = true +ssz_types.workspace = true +tokio = { workspace = true, features = ["full"] } +tracing.workspace = true +tracing-subscriber = { workspace = true, features = ["env-filter"] } +url.workspace = true + +# lighthouse +ethereum_serde_utils.workspace = true +lighthouse_types.workspace = true + +# local +zkboost-client.workspace = true +zkboost-types.workspace = true diff --git a/crates/mock-zkattestor/src/cl_client.rs b/crates/mock-zkattestor/src/cl_client.rs new file mode 100644 index 0000000..c020be9 --- /dev/null +++ b/crates/mock-zkattestor/src/cl_client.rs @@ -0,0 +1,150 @@ +use anyhow::{anyhow, bail}; +use futures::{Stream, StreamExt}; +use lighthouse_types::{ + BeaconBlockRef, ForkName, ForkVersionDecode, Hash256, MainnetEthSpec, SignedBeaconBlock, + VersionedHash, +}; +use reqwest_eventsource::{Event as SseEvent, EventSource}; +use serde::Deserialize; +use sha2::{Digest, Sha256}; +use ssz_types::VariableList; +use url::Url; +use zkboost_types::{ + NewPayloadRequest, NewPayloadRequestBellatrix, NewPayloadRequestCapella, + NewPayloadRequestDeneb, NewPayloadRequestElectra, NewPayloadRequestFulu, +}; + +#[derive(Debug, Clone, Deserialize)] +pub(crate) struct Head { + #[serde(with = "serde_utils::quoted_u64")] + pub(crate) slot: u64, + pub(crate) block: Hash256, +} + +#[derive(Clone)] +pub(crate) struct ClClient { + base_url: Url, + http: reqwest::Client, +} + +impl ClClient { + pub(crate) fn new(base_url: Url) -> Self { + Self { + base_url, + http: reqwest::Client::new(), + } + } + + pub(crate) fn subscribe_head_events( + &self, + ) -> impl Stream> + Send + '_ { + async_stream::try_stream! { + let mut url = self.base_url.join("/eth/v1/events")?; + url.query_pairs_mut().append_pair("topics", "head"); + let mut es = EventSource::new(self.http.get(url))?; + while let Some(event) = es.next().await { + match event { + Ok(SseEvent::Open) => {} + Ok(SseEvent::Message(message)) if message.event == "head" => { + let head_event: Head = serde_json::from_str(&message.data)?; + yield head_event + } + Ok(SseEvent::Message(_)) => {} + Err(error) => { + es.close(); + Err(anyhow!("{error}"))?; + } + } + } + } + } + + pub(crate) async fn get_beacon_block( + &self, + slot: u64, + ) -> anyhow::Result> { + let url = self + .base_url + .join(&format!("/eth/v2/beacon/blocks/{slot}"))?; + let resp = self + .http + .get(url) + .header("Accept", "application/octet-stream") + .send() + .await?; + if !resp.status().is_success() { + let status = resp.status(); + let body = resp.text().await.unwrap_or_default(); + bail!("{status}: {body}"); + } + let fork_name: ForkName = resp + .headers() + .get("Eth-Consensus-Version") + .ok_or_else(|| anyhow!("missing Eth-Consensus-Version"))? + .to_str()? + .parse() + .map_err(|error: String| anyhow!("{error}"))?; + let bytes = resp.bytes().await?; + SignedBeaconBlock::from_ssz_bytes_by_fork(&bytes, fork_name).map_err(|e| anyhow!("{e:?}")) + } +} + +pub(crate) fn new_payload_request_from_beacon_block( + block: &SignedBeaconBlock, +) -> anyhow::Result> { + match block.message() { + BeaconBlockRef::Base(_) | BeaconBlockRef::Altair(_) => unreachable!(), + BeaconBlockRef::Bellatrix(b) => { + Ok(NewPayloadRequest::Bellatrix(NewPayloadRequestBellatrix { + execution_payload: b.body.execution_payload.execution_payload.clone(), + })) + } + BeaconBlockRef::Capella(b) => Ok(NewPayloadRequest::Capella(NewPayloadRequestCapella { + execution_payload: b.body.execution_payload.execution_payload.clone(), + })), + BeaconBlockRef::Deneb(b) => Ok(NewPayloadRequest::Deneb(NewPayloadRequestDeneb { + execution_payload: b.body.execution_payload.execution_payload.clone(), + versioned_hashes: VariableList::new( + b.body + .blob_kzg_commitments + .iter() + .map(kzg_commitment_to_versioned_hash) + .collect(), + )?, + parent_beacon_block_root: b.parent_root, + })), + BeaconBlockRef::Electra(b) => Ok(NewPayloadRequest::Electra(NewPayloadRequestElectra { + execution_payload: b.body.execution_payload.execution_payload.clone(), + versioned_hashes: VariableList::new( + b.body + .blob_kzg_commitments + .iter() + .map(kzg_commitment_to_versioned_hash) + .collect(), + )?, + parent_beacon_block_root: b.parent_root, + execution_requests: b.body.execution_requests.clone(), + })), + BeaconBlockRef::Fulu(b) => Ok(NewPayloadRequest::Fulu(NewPayloadRequestFulu { + execution_payload: b.body.execution_payload.execution_payload.clone(), + versioned_hashes: VariableList::new( + b.body + .blob_kzg_commitments + .iter() + .map(kzg_commitment_to_versioned_hash) + .collect(), + )?, + parent_beacon_block_root: b.parent_root, + execution_requests: b.body.execution_requests.clone(), + })), + BeaconBlockRef::Gloas(_) => unimplemented!(), + } +} + +pub(crate) fn kzg_commitment_to_versioned_hash( + commitment: &lighthouse_types::KzgCommitment, +) -> VersionedHash { + let mut hash: [u8; 32] = Sha256::digest(commitment.0).into(); + hash[0] = 0x01; + VersionedHash::from(hash) +} diff --git a/crates/mock-zkattestor/src/main.rs b/crates/mock-zkattestor/src/main.rs new file mode 100644 index 0000000..478ee3a --- /dev/null +++ b/crates/mock-zkattestor/src/main.rs @@ -0,0 +1,139 @@ +//! Mock zkattestor. + +#![warn(unused_crate_dependencies)] + +use std::{collections::HashSet, sync::Arc}; + +use anyhow::bail; +use cl_client::{ClClient, new_payload_request_from_beacon_block}; +use clap::Parser; +use futures::StreamExt; +use lighthouse_types::Hash256; +use tracing::{info, warn}; +use tracing_subscriber::EnvFilter; +use url::Url; +use zkboost_client::zkBoostClient; +use zkboost_types::{ProofEvent, ProofType}; + +mod cl_client; + +#[derive(Parser)] +struct Cli { + #[arg(long)] + cl_endpoint: Url, + #[arg(long)] + zkboost_endpoint: Url, + #[arg(long, value_delimiter = ',')] + proof_types: Vec, +} + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + tracing_subscriber::fmt() + .with_env_filter(EnvFilter::from_default_env()) + .init(); + + let cli = Cli::parse(); + + let mock_attestor = Arc::new(MockAttestor { + cl_client: ClClient::new(cli.cl_endpoint), + zkboost_client: zkBoostClient::new(cli.zkboost_endpoint), + proof_types: cli.proof_types, + }); + + let mut stream = Box::pin(mock_attestor.cl_client.subscribe_head_events()); + while let Some(Ok(head)) = stream.next().await { + info!(slot = head.slot, block = %head.block, "new head"); + let mock_attestor = mock_attestor.clone(); + tokio::spawn(async move { + if let Err(error) = mock_attestor.process_slot(head.slot).await { + warn!(slot = head.slot, error = %error, "slot failed"); + } + }); + } + bail!("head stream ended") +} + +struct MockAttestor { + cl_client: ClClient, + zkboost_client: zkBoostClient, + proof_types: Vec, +} + +impl MockAttestor { + async fn process_slot(&self, slot: u64) -> anyhow::Result<()> { + let beacon_block = self.cl_client.get_beacon_block(slot).await?; + let new_payload_request = new_payload_request_from_beacon_block(&beacon_block)?; + + let block_hash = new_payload_request.block_hash(); + let resp = self + .zkboost_client + .request_proof(&new_payload_request, &self.proof_types) + .await?; + let new_payload_request_root = resp.new_payload_request_root; + info!(%new_payload_request_root, %block_hash, "proof requested"); + + let mut proof_events = Box::pin( + self.zkboost_client + .subscribe_proof_events(Some(new_payload_request_root)), + ); + let mut remaining: HashSet = self.proof_types.iter().copied().collect(); + + while !remaining.is_empty() { + let Some(Ok(proof_event)) = proof_events.next().await else { + bail!("proof stream ended"); + }; + + remaining.remove(&proof_event.proof_type()); + + match proof_event { + ProofEvent::ProofComplete(proof_complete) => { + info!(%new_payload_request_root, proof_type = %proof_complete.proof_type, "proof complete"); + match self + .download_and_verify(new_payload_request_root, proof_complete.proof_type) + .await + { + Ok(()) => { + info!(%new_payload_request_root, proof_type = %proof_complete.proof_type, "proof verified") + } + Err(e) => { + warn!(%new_payload_request_root, proof_type = %proof_complete.proof_type, error = %e, "proof verification failed") + } + } + } + ProofEvent::ProofFailure(proof_failure) => { + warn!(%new_payload_request_root, proof_type = %proof_failure.proof_type, error = %proof_failure.error, "proof failed") + } + ProofEvent::WitnessTimeout(witness_timeout) => { + warn!(%new_payload_request_root, proof_type = %witness_timeout.proof_type, "witness timeout") + } + ProofEvent::ProofTimeout(proof_timeout) => { + warn!(%new_payload_request_root, proof_type = %proof_timeout.proof_type, "proof timeout") + } + } + } + + info!(%new_payload_request_root, "all proofs done"); + + Ok(()) + } + + async fn download_and_verify( + &self, + new_payload_request_root: Hash256, + proof_type: ProofType, + ) -> anyhow::Result<()> { + let proof = self + .zkboost_client + .get_proof(new_payload_request_root, proof_type) + .await?; + let response = self + .zkboost_client + .verify_proof(new_payload_request_root, proof_type, &proof) + .await?; + if !response.status.is_valid() { + anyhow::bail!("invalid proof"); + } + Ok(()) + } +} diff --git a/crates/zkboost/server/Cargo.toml b/crates/server/Cargo.toml similarity index 51% rename from crates/zkboost/server/Cargo.toml rename to crates/server/Cargo.toml index a681da1..9117bb2 100644 --- a/crates/zkboost/server/Cargo.toml +++ b/crates/server/Cargo.toml @@ -11,42 +11,53 @@ workspace = true [dependencies] anyhow.workspace = true axum = { workspace = true, features = ["macros"] } +bincode.workspace = true +bytes.workspace = true clap = { workspace = true, features = ["derive"] } -futures.workspace = true +lru.workspace = true +metrics.workspace = true +metrics-exporter-prometheus.workspace = true rand.workspace = true reqwest = { workspace = true, features = ["json"] } -sysinfo.workspace = true +serde = { workspace = true, features = ["derive"] } +serde_json.workspace = true +sha2.workspace = true +strum = { workspace = true, features = ["derive"] } +thiserror.workspace = true tokio = { workspace = true, features = ["full"] } +tokio-stream = { workspace = true, features = ["sync"] } +tokio-util.workspace = true +toml_edit = { workspace = true, features = ["serde"] } tower-http = { workspace = true, features = ["trace", "limit"] } tracing.workspace = true tracing-subscriber = { workspace = true, features = ["env-filter"] } -uuid = { workspace = true, features = ["v4", "serde"] } -wgpu.workspace = true -metrics.workspace = true -metrics-exporter-prometheus.workspace = true +url.workspace = true -ere-dockerized.workspace = true +# alloy +alloy-eips.workspace = true +alloy-genesis.workspace = true +alloy-primitives.workspace = true +alloy-rpc-types-engine.workspace = true +alloy-rpc-types-eth.workspace = true + +# reth +reth-ethereum-primitives.workspace = true +reth-stateless.workspace = true + +# ere ere-server.workspace = true ere-zkvm-interface.workspace = true -zkboost-server-config.workspace = true +# ere-guests +stateless-validator-ethrex.workspace = true +stateless-validator-reth.workspace = true + +# local zkboost-types.workspace = true [dev-dependencies] -clap = { workspace = true, features = ["derive"] } -flate2.workspace = true -nix = { workspace = true, features = ["signal", "process"] } -serde_json.workspace = true -tar.workspace = true -tempfile.workspace = true -toml_edit.workspace = true +futures.workspace = true +tower = { workspace = true, features = ["util"] } +# local zkboost-client.workspace = true -zkboost-ethereum-el-config.workspace = true -zkboost-ethereum-el-input.workspace = true -zkboost-ethereum-el-types.workspace = true - -[[test]] -name = "stateless_validator" -harness = false -test = false diff --git a/crates/server/src/config.rs b/crates/server/src/config.rs new file mode 100644 index 0000000..407091d --- /dev/null +++ b/crates/server/src/config.rs @@ -0,0 +1,172 @@ +//! Configuration types. + +use std::{ + fs, + path::{Path, PathBuf}, +}; + +use serde::{Deserialize, Serialize}; +use url::Url; +use zkboost_types::ProofType; + +const DEFAULT_PORT: u16 = 3000; +const DEFAULT_WITNESS_TIMEOUT_SECS: u64 = 12; +const DEFAULT_PROOF_TIMEOUT_SECS: u64 = 12; +const DEFAULT_PROOF_CACHE_SIZE: usize = 128; +const DEFAULT_WITNESS_CACHE_SIZE: usize = 128; + +fn default_port() -> u16 { + DEFAULT_PORT +} + +fn default_witness_timeout_secs() -> u64 { + DEFAULT_WITNESS_TIMEOUT_SECS +} + +fn default_proof_timeout_secs() -> u64 { + DEFAULT_PROOF_TIMEOUT_SECS +} + +fn default_proof_cache_size() -> usize { + DEFAULT_PROOF_CACHE_SIZE +} + +fn default_witness_cache_size() -> usize { + DEFAULT_WITNESS_CACHE_SIZE +} + +/// Unified configuration for the zkboost proof node. +#[derive(Debug, Clone, Deserialize, Serialize)] +pub struct Config { + /// HTTP server port. + #[serde(default = "default_port")] + pub port: u16, + /// EL endpoint for witness fetching. + pub el_endpoint: Url, + /// Optional path to a local chain config JSON file. + #[serde(default)] + pub chain_config_path: Option, + /// Timeout in seconds for witness data (both pending-proof and fetch staleness). + #[serde(default = "default_witness_timeout_secs")] + pub witness_timeout_secs: u64, + /// Timeout in seconds for proof generation per zkVM worker. + #[serde(default = "default_proof_timeout_secs")] + pub proof_timeout_secs: u64, + /// Maximum number of completed proofs to keep in the LRU cache. + #[serde(default = "default_proof_cache_size")] + pub proof_cache_size: usize, + /// Maximum number of execution witnesses to keep in the LRU cache. + #[serde(default = "default_witness_cache_size")] + pub witness_cache_size: usize, + /// zkVM backend configurations. + pub zkvm: Vec, +} + +/// zkVM backend configuration, either a remote ere-server or a mock for testing. +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(tag = "kind", rename_all = "lowercase")] +#[allow(non_camel_case_types)] +pub enum zkVMConfig { + /// Remote ere-server backend. + External { + /// HTTP endpoint URL of the ere-server. + endpoint: String, + /// Proof type. + proof_type: ProofType, + }, + /// In-process mock backend for testing. + Mock { + /// Proof type. + proof_type: ProofType, + /// Simulated proving latency in milliseconds. + mock_proving_time_ms: u64, + /// Size of the mock proof in bytes. + mock_proof_size: u64, + /// Whether the mock should always fail proof generation. + #[serde(default)] + mock_failure: bool, + }, +} + +impl zkVMConfig { + /// Returns the proof type identifier for this configuration. + pub fn proof_type(&self) -> ProofType { + match self { + Self::External { proof_type, .. } | Self::Mock { proof_type, .. } => *proof_type, + } + } +} + +impl Config { + /// Load configuration from a TOML file at the given path. + pub fn load(path: impl AsRef) -> anyhow::Result { + let content = fs::read_to_string(path.as_ref())?; + Ok(toml_edit::de::from_str(&content)?) + } +} + +#[cfg(test)] +mod tests { + use zkboost_types::ProofType; + + use crate::config::{Config, zkVMConfig}; + + #[test] + fn test_parse_multiple_zkvms() { + let toml = r#" + el_endpoint = "http://localhost:8545" + + [[zkvm]] + kind = "external" + endpoint = "http://ere-server:3000" + proof_type = "ethrex-zisk" + + [[zkvm]] + kind = "mock" + proof_type = "reth-zisk" + mock_proving_time_ms = 100 + mock_proof_size = 512 + "#; + + let config: Config = toml_edit::de::from_str(toml).unwrap(); + + assert_eq!(config.zkvm.len(), 2); + assert_eq!(config.zkvm[0].proof_type(), ProofType::EthrexZisk); + assert_eq!(config.zkvm[1].proof_type(), ProofType::RethZisk); + + assert!(matches!(&config.zkvm[0], zkVMConfig::External { .. })); + assert!(matches!(&config.zkvm[1], zkVMConfig::Mock { .. })); + } + + #[test] + fn test_cache_size_defaults() { + let toml = r#" + el_endpoint = "http://localhost:8545" + [[zkvm]] + kind = "mock" + proof_type = "reth-sp1" + mock_proving_time_ms = 10 + mock_proof_size = 64 + "#; + let config: Config = toml_edit::de::from_str(toml).unwrap(); + assert_eq!(config.proof_cache_size, 128); + assert_eq!(config.witness_cache_size, 128); + } + + #[test] + fn test_cache_size_overrides() { + let toml = r#" + el_endpoint = "http://localhost:8545" + proof_cache_size = 256 + witness_cache_size = 64 + [[zkvm]] + kind = "mock" + proof_type = "reth-sp1" + mock_proving_time_ms = 10 + mock_proof_size = 64 + "#; + let config: Config = toml_edit::de::from_str(toml).unwrap(); + assert_eq!(config.proof_cache_size, 256); + assert_eq!(config.witness_cache_size, 64); + } +} diff --git a/crates/server/src/el_client.rs b/crates/server/src/el_client.rs new file mode 100644 index 0000000..049bf58 --- /dev/null +++ b/crates/server/src/el_client.rs @@ -0,0 +1,140 @@ +//! EL JSON-RPC client. + +use alloy_genesis::ChainConfig; +use reth_ethereum_primitives::{Block, TransactionSigned}; +use reth_stateless::ExecutionWitness; +use serde::{Deserialize, Serialize, de::DeserializeOwned}; +use url::Url; +use zkboost_types::Hash256; + +/// Execution layer JSON-RPC client. +#[derive(Debug)] +pub struct ElClient { + url: Url, + http_client: reqwest::Client, +} + +impl ElClient { + /// Create a new EL client. + pub fn new(url: Url) -> Self { + Self { + url, + http_client: reqwest::Client::new(), + } + } + + /// Return url of the EL client. + pub fn url(&self) -> &Url { + &self.url + } + + /// Send a JSON-RPC request to the execution layer node. + /// + /// Serializes the request, sends it to the endpoint, and deserializes the response. + /// Returns `None` if the RPC response has a null `result`. + async fn request( + &self, + method: &'static str, + params: P, + ) -> Result, Error> { + let request = JsonRpcRequest { + jsonrpc: "2.0", + method, + params, + id: 1, + }; + + let response = self + .http_client + .post(self.url.clone()) + .json(&request) + .send() + .await?; + + if !response.status().is_success() { + return Err(Error::Rpc { + code: response.status().as_u16() as i64, + message: response.text().await.unwrap_or_default(), + }); + } + + let rpc_response: JsonRpcResponse = response.json().await?; + + if let Some(error) = rpc_response.error { + return Err(Error::Rpc { + code: error.code, + message: error.message, + }); + } + + match rpc_response.result { + Some(value) => Ok(Some(value)), + None => Ok(None), + } + } + + /// Fetch chain config. + pub async fn get_chain_config(&self) -> Result, Error> { + self.request("debug_chainConfig", ()).await + } + + /// Fetch a block by hash. + pub async fn get_block_by_hash(&self, block_hash: Hash256) -> Result, Error> { + let block: Option> = self + .request("eth_getBlockByHash", (block_hash, true)) + .await?; + Ok(block.map(|block| block.into_consensus())) + } + + /// Fetch execution witness for a block. + pub async fn get_execution_witness_by_hash( + &self, + block_hash: Hash256, + ) -> Result, Error> { + self.request("debug_executionWitnessByBlockHash", (block_hash,)) + .await + } +} + +/// JSON-RPC request structure. +#[derive(Debug, Clone, Serialize)] +struct JsonRpcRequest { + jsonrpc: &'static str, + method: &'static str, + params: T, + id: u64, +} + +/// JSON-RPC response structure. +#[derive(Debug, Clone, Deserialize)] +struct JsonRpcResponse { + /// The result payload, if the call succeeded. + result: Option, + /// The error payload, if the call failed. + error: Option, +} + +/// JSON-RPC error structure. +#[derive(Debug, Clone, Deserialize)] +struct JsonRpcError { + /// Error code. + code: i64, + /// Error message. + message: String, +} + +/// Errors that can occur when communicating with an EL JSON-RPC endpoint. +#[derive(Debug, thiserror::Error)] +pub enum Error { + /// HTTP transport error. + #[error("HTTP error: {0}")] + Http(#[from] reqwest::Error), + /// JSON-RPC level error returned by the node. + #[error("RPC error {code}: {message}")] + Rpc { + /// Error code. + code: i64, + /// Error message. + message: String, + }, +} diff --git a/crates/server/src/http.rs b/crates/server/src/http.rs new file mode 100644 index 0000000..2d6e4ed --- /dev/null +++ b/crates/server/src/http.rs @@ -0,0 +1,138 @@ +//! HTTP service: AppState, router, and v1 API handlers. + +use std::{collections::HashMap, sync::Arc}; + +use axum::{ + Router, + extract::{DefaultBodyLimit, State}, + http::StatusCode, + middleware, + routing::{get, post}, +}; +use bytes::Bytes; +use lru::LruCache; +use metrics_exporter_prometheus::PrometheusHandle; +use tokio::sync::{RwLock, broadcast, mpsc}; +use tower_http::trace::TraceLayer; +use zkboost_types::{Hash256, ProofEvent, ProofType}; + +use crate::{ + metrics::http_metrics_middleware, + proof::{ProofServiceMessage, zkvm::zkVMInstance}, +}; + +mod v1; + +/// Shared application state for all HTTP handlers. +pub(crate) struct AppState { + pub(crate) zkvms: Arc>, + pub(crate) completed_proofs: Arc>>, + pub(crate) proof_service_tx: mpsc::Sender, + pub(crate) proof_event_receiver: broadcast::Receiver, + pub(crate) metrics: PrometheusHandle, +} + +impl AppState { + /// Creates shared application state for the HTTP handlers. + pub(crate) fn new( + zkvms: Arc>, + completed_proofs: Arc>>, + proof_service_tx: mpsc::Sender, + proof_event_receiver: broadcast::Receiver, + metrics: PrometheusHandle, + ) -> Self { + Self { + zkvms, + completed_proofs, + proof_service_tx, + proof_event_receiver, + metrics, + } + } +} + +/// Builds the Axum router with all endpoints and middleware. +pub(crate) fn router(state: Arc) -> Router { + Router::new() + .route( + "/v1/execution_proof_requests", + post(v1::post_execution_proof_requests).get(v1::get_execution_proof_requests), + ) + .route( + "/v1/execution_proofs/{new_payload_request_root}/{proof_type}", + get(v1::get_execution_proofs), + ) + .route( + "/v1/execution_proof_verifications", + post(v1::post_execution_proof_verifications), + ) + .route("/health", get(StatusCode::OK)) + .route("/metrics", get(get_metrics)) + .with_state(state) + .layer(middleware::from_fn(http_metrics_middleware)) + .layer(TraceLayer::new_for_http()) + .layer(DefaultBodyLimit::max(1 << 30)) +} + +async fn get_metrics(State(state): State>) -> String { + state.metrics.render() +} + +#[cfg(test)] +pub(crate) mod tests { + use std::{collections::HashMap, num::NonZeroUsize, sync::Arc}; + + use axum::{body::Body, http::Request}; + use lru::LruCache; + use metrics_exporter_prometheus::PrometheusBuilder; + use tokio::sync::{RwLock, broadcast, mpsc}; + use tower::ServiceExt; + use zkboost_types::{ProofEvent, ProofType}; + + use crate::{ + config::zkVMConfig, + http::{AppState, router}, + proof::{ProofServiceMessage, zkvm::zkVMInstance}, + }; + + pub(crate) async fn mock_app_state() -> Arc { + let completed_proofs = + Arc::new(RwLock::new(LruCache::new(NonZeroUsize::new(128).unwrap()))); + let (_, proof_event_receiver) = broadcast::channel::(16); + let (proof_service_tx, _) = mpsc::channel::(16); + + let mock_config = zkVMConfig::Mock { + proof_type: ProofType::RethZisk, + mock_proving_time_ms: 10, + mock_proof_size: 64, + mock_failure: false, + }; + let zkvm = zkVMInstance::new(&mock_config).await.unwrap(); + let zkvms = Arc::new(HashMap::from_iter([(ProofType::RethZisk, zkvm)])); + + let metrics = PrometheusBuilder::new().build_recorder().handle(); + + Arc::new(AppState::new( + zkvms, + completed_proofs, + proof_service_tx, + proof_event_receiver, + metrics, + )) + } + + #[tokio::test] + async fn test_health_endpoint() { + let state = mock_app_state().await; + let response = router(state) + .oneshot( + Request::builder() + .uri("/health") + .body(Body::empty()) + .unwrap(), + ) + .await + .unwrap(); + assert_eq!(response.status(), 200); + } +} diff --git a/crates/server/src/http/v1.rs b/crates/server/src/http/v1.rs new file mode 100644 index 0000000..a92e71b --- /dev/null +++ b/crates/server/src/http/v1.rs @@ -0,0 +1,32 @@ +//! v1 API handlers. + +use axum::{Json, http::StatusCode}; + +mod get_execution_proof_requests; +mod get_execution_proofs; +mod post_execution_proof_requests; +mod post_execution_proof_verifications; + +pub(crate) use get_execution_proof_requests::get_execution_proof_requests; +pub(crate) use get_execution_proofs::get_execution_proofs; +pub(crate) use post_execution_proof_requests::post_execution_proof_requests; +pub(crate) use post_execution_proof_verifications::post_execution_proof_verifications; + +/// JSON error response body returned by API endpoints. +#[derive(Debug, serde::Serialize)] +pub(crate) struct ErrorResponse { + pub(crate) error: String, +} + +/// Constructs an error response tuple for Axum handlers. +pub(crate) fn error_response( + status: StatusCode, + message: impl Into, +) -> (StatusCode, Json) { + ( + status, + Json(ErrorResponse { + error: message.into(), + }), + ) +} diff --git a/crates/server/src/http/v1/get_execution_proof_requests.rs b/crates/server/src/http/v1/get_execution_proof_requests.rs new file mode 100644 index 0000000..8bd2941 --- /dev/null +++ b/crates/server/src/http/v1/get_execution_proof_requests.rs @@ -0,0 +1,92 @@ +//! SSE endpoint handler for `GET /v1/execution_proof_requests`. + +use std::{convert::Infallible, pin::Pin, sync::Arc, time::Duration}; + +use axum::{ + extract::{Query, State}, + response::sse::{Event, KeepAlive, Sse}, +}; +use tokio_stream::{Stream, StreamExt, wrappers::BroadcastStream}; +use zkboost_types::{ProofComplete, ProofEvent, ProofEventQuery}; + +use crate::http::AppState; + +pub(crate) async fn get_execution_proof_requests( + State(state): State>, + Query(params): Query, +) -> Sse>> { + let proof_event_receiver = state.proof_event_receiver.resubscribe(); + + let live_stream = BroadcastStream::new(proof_event_receiver).filter_map(|result| result.ok()); + + let merged: Pin> + Send>> = + if let Some(new_payload_request_root) = params.new_payload_request_root { + let catch_up_events = { + let cache = state.completed_proofs.read().await; + cache + .iter() + .filter(|((cache, _), _)| *cache == new_payload_request_root) + .map(|((new_payload_request_root, proof_type), _)| { + ProofComplete { + new_payload_request_root: *new_payload_request_root, + proof_type: *proof_type, + } + .into() + }) + .collect::>() + }; + let catch_up_stream = tokio_stream::iter(catch_up_events); + let filtered = catch_up_stream + .chain(live_stream.filter(move |proof_event| { + proof_event.new_payload_request_root() == new_payload_request_root + })) + .map(|proof_event| Ok(to_axum_event(proof_event))); + Box::pin(filtered) + } else { + let all = live_stream.map(|proof_event| Ok(to_axum_event(proof_event))); + Box::pin(all) + }; + + Sse::new(merged).keep_alive(KeepAlive::new().interval(Duration::from_secs(15))) +} + +fn to_axum_event(proof_event: ProofEvent) -> Event { + let (name, data) = proof_event.to_parts(); + Event::default().event(name).data(data) +} + +#[cfg(test)] +mod tests { + use axum::{Router, body::Body, http::Request, routing::get}; + use tower::ServiceExt; + + use crate::http::{tests::mock_app_state, v1::get_execution_proof_requests}; + + #[tokio::test] + async fn test_sse_stream_opens() { + let state = mock_app_state().await; + let response = Router::new() + .route( + "/v1/execution_proof_requests", + get(get_execution_proof_requests), + ) + .with_state(state) + .oneshot( + Request::builder() + .uri("/v1/execution_proof_requests") + .body(Body::empty()) + .unwrap(), + ) + .await + .unwrap(); + + assert_eq!(response.status(), 200); + let content_type = response + .headers() + .get("content-type") + .unwrap() + .to_str() + .unwrap(); + assert!(content_type.contains("text/event-stream")); + } +} diff --git a/crates/server/src/http/v1/get_execution_proofs.rs b/crates/server/src/http/v1/get_execution_proofs.rs new file mode 100644 index 0000000..eba50ce --- /dev/null +++ b/crates/server/src/http/v1/get_execution_proofs.rs @@ -0,0 +1,113 @@ +//! Handler for `GET /v1/execution_proofs/{new_payload_request_root}/{proof_type}`. + +use std::sync::Arc; + +use axum::{ + extract::{Path, State}, + http::{StatusCode, header::CONTENT_TYPE}, + response::IntoResponse, +}; +use zkboost_types::{Hash256, ProofType}; + +use crate::http::{AppState, v1::error_response}; + +pub(crate) async fn get_execution_proofs( + State(state): State>, + Path((new_payload_request_root, proof_type)): Path<(Hash256, ProofType)>, +) -> impl IntoResponse { + match state + .completed_proofs + .read() + .await + .peek(&(new_payload_request_root, proof_type)) + { + Some(proof) => ( + StatusCode::OK, + [(CONTENT_TYPE, "application/octet-stream")], + proof.clone(), + ) + .into_response(), + None => error_response( + StatusCode::NOT_FOUND, + format!("proof not found for root {new_payload_request_root} and type {proof_type}"), + ) + .into_response(), + } +} + +#[cfg(test)] +mod tests { + use std::sync::Arc; + + use axum::{ + Router, + body::{Body, to_bytes}, + http::Request, + routing::get, + }; + use bytes::Bytes; + use tower::ServiceExt; + use zkboost_types::{Hash256, ProofType}; + + use crate::http::{AppState, tests::mock_app_state, v1::get_execution_proofs}; + + fn test_router(state: Arc) -> Router { + Router::new() + .route( + "/v1/execution_proofs/{new_payload_request_root}/{proof_type}", + get(get_execution_proofs), + ) + .with_state(state) + } + + #[tokio::test] + async fn test_proof_not_found() { + let state = mock_app_state().await; + let response = test_router(state) + .oneshot( + Request::builder() + .uri(format!( + "/v1/execution_proofs/{}/ethrex-zisk", + Hash256::ZERO + )) + .body(Body::empty()) + .unwrap(), + ) + .await + .unwrap(); + assert_eq!(response.status(), 404); + + let body = to_bytes(response.into_body(), usize::MAX).await.unwrap(); + let json: serde_json::Value = serde_json::from_slice(&body).unwrap(); + assert!(json.get("error").is_some()); + } + + #[tokio::test] + async fn test_proof_found() { + let state = mock_app_state().await; + let new_payload_request_root = Hash256::from_slice(&[1u8; 32]); + let proof_type = ProofType::EthrexZisk; + let proof = Bytes::from(vec![42u8; 64]); + state + .completed_proofs + .write() + .await + .put((new_payload_request_root, proof_type), proof.clone()); + + let response = test_router(state) + .oneshot( + Request::builder() + .uri(format!( + "/v1/execution_proofs/{new_payload_request_root}/ethrex-zisk" + )) + .body(Body::empty()) + .unwrap(), + ) + .await + .unwrap(); + assert_eq!(response.status(), 200); + + let body = to_bytes(response.into_body(), usize::MAX).await.unwrap(); + assert_eq!(body.as_ref(), &[42u8; 64]); + } +} diff --git a/crates/server/src/http/v1/post_execution_proof_requests.rs b/crates/server/src/http/v1/post_execution_proof_requests.rs new file mode 100644 index 0000000..c58e4d0 --- /dev/null +++ b/crates/server/src/http/v1/post_execution_proof_requests.rs @@ -0,0 +1,117 @@ +//! Handler for `POST /v1/execution_proof_requests`. + +use std::sync::Arc; + +use axum::{ + Json, + extract::{Query, State}, + http::StatusCode, +}; +use bytes::Bytes; +use tracing::instrument; +use zkboost_types::{ + Decode, MainnetEthSpec, NewPayloadRequest, ProofRequestQuery, ProofRequestResponse, TreeHash, +}; + +use crate::{ + http::{ + AppState, + v1::{ErrorResponse, error_response}, + }, + proof::ProofServiceMessage, +}; + +#[instrument(skip_all)] +pub(crate) async fn post_execution_proof_requests( + State(state): State>, + Query(params): Query, + body: Bytes, +) -> Result<(StatusCode, Json), (StatusCode, Json)> { + let new_payload_request = NewPayloadRequest::::from_ssz_bytes(&body) + .map_err(|e| error_response(StatusCode::BAD_REQUEST, format!("invalid SSZ body: {e:?}")))?; + + let new_payload_request_root = new_payload_request.tree_hash_root(); + + for proof_type in ¶ms.proof_types { + if !state.zkvms.contains_key(proof_type) { + return Err(error_response( + StatusCode::BAD_REQUEST, + format!("no zkVM configured for proof type '{proof_type}'"), + )); + } + } + + state + .proof_service_tx + .send(ProofServiceMessage::RequestProof { + new_payload_request: Arc::new(new_payload_request), + proof_types: params.proof_types, + }) + .await + .map_err(|e| { + error_response( + StatusCode::INTERNAL_SERVER_ERROR, + format!("failed to enqueue proof: {e}"), + ) + })?; + + Ok(( + StatusCode::OK, + Json(ProofRequestResponse { + new_payload_request_root, + }), + )) +} + +#[cfg(test)] +mod tests { + use std::sync::Arc; + + use axum::{Router, body::Body, http::Request, routing::post}; + use tower::ServiceExt; + + use crate::http::{AppState, tests::mock_app_state, v1::post_execution_proof_requests}; + + fn test_router(state: Arc) -> Router { + Router::new() + .route( + "/v1/execution_proof_requests", + post(post_execution_proof_requests), + ) + .with_state(state) + } + + #[tokio::test] + async fn test_bad_ssz_body() { + let state = mock_app_state().await; + let response = test_router(state) + .oneshot( + Request::builder() + .method("POST") + .uri("/v1/execution_proof_requests?proof_types=ethrex-zisk") + .header("content-type", "application/octet-stream") + .body(Body::from(vec![0u8; 16])) + .unwrap(), + ) + .await + .unwrap(); + assert_eq!(response.status(), 400); + } + + #[tokio::test] + async fn test_unknown_proof_type_returns_bad_request() { + let state = mock_app_state().await; + let response = test_router(state) + .oneshot( + Request::builder() + .method("POST") + .uri("/v1/execution_proof_requests?proof_types=ethrex-zisk") + .header("content-type", "application/octet-stream") + .body(Body::from(vec![0u8; 16])) + .unwrap(), + ) + .await + .unwrap(); + assert_eq!(response.status(), 400); + } +} diff --git a/crates/server/src/http/v1/post_execution_proof_verifications.rs b/crates/server/src/http/v1/post_execution_proof_verifications.rs new file mode 100644 index 0000000..f8d54eb --- /dev/null +++ b/crates/server/src/http/v1/post_execution_proof_verifications.rs @@ -0,0 +1,157 @@ +//! Handler for `POST /v1/execution_proof_verifications`. + +use std::{sync::Arc, time::Instant}; + +use axum::{ + Json, + extract::{Query, State}, + http::StatusCode, +}; +use bytes::Bytes; +use tracing::{instrument, warn}; +use zkboost_types::{ProofStatus, ProofVerificationQuery, ProofVerificationResponse}; + +use crate::{ + http::{ + AppState, + v1::{ErrorResponse, error_response}, + }, + metrics::record_verify, +}; + +#[instrument(skip_all)] +pub(crate) async fn post_execution_proof_verifications( + State(state): State>, + Query(params): Query, + body: Bytes, +) -> Result, (StatusCode, Json)> { + let start = Instant::now(); + let proof_type = params.proof_type; + + let zkvm = state.zkvms.get(&proof_type).ok_or_else(|| { + record_verify(proof_type, false, start.elapsed()); + error_response( + StatusCode::NOT_FOUND, + format!("unknown proof_type: {proof_type}"), + ) + })?; + + let status = match zkvm + .verify(params.new_payload_request_root, body.to_vec()) + .await + { + Ok(()) => ProofStatus::Valid, + Err(e) => { + warn!(proof_type = %proof_type, error = %e, "verification failed"); + ProofStatus::Invalid + } + }; + + record_verify(proof_type, status.is_valid(), start.elapsed()); + + Ok(Json(ProofVerificationResponse { status })) +} + +#[cfg(test)] +mod tests { + use std::sync::Arc; + + use axum::{ + Router, + body::{Body, to_bytes}, + http::Request, + routing::post, + }; + use bytes::Bytes; + use tower::ServiceExt; + use zkboost_types::{ElKind, Hash256, ProofStatus, ProofVerificationResponse}; + + use crate::{ + http::{AppState, tests::mock_app_state, v1::post_execution_proof_verifications}, + proof::zkvm::{MockProof, expected_public_values}, + }; + + fn test_router(state: Arc) -> Router { + Router::new() + .route( + "/v1/execution_proof_verifications", + post(post_execution_proof_verifications), + ) + .with_state(state) + } + + #[tokio::test] + async fn test_unknown_proof_type_returns_not_found() { + let state = mock_app_state().await; + let body = mock_proof(Hash256::ZERO, 64); + let response = test_router(state) + .oneshot( + Request::builder() + .method("POST") + .uri(format!( + "/v1/execution_proof_verifications?proof_type=ethrex-risc0&new_payload_request_root={}", + Hash256::ZERO + )) + .body(Body::from(body)) + .unwrap(), + ) + .await + .unwrap(); + assert_eq!(response.status(), 404); + } + + #[tokio::test] + async fn test_valid_mock_proof() { + let state = mock_app_state().await; + let body = mock_proof(Hash256::ZERO, 64); + let response = test_router(state) + .oneshot( + Request::builder() + .method("POST") + .uri(format!( + "/v1/execution_proof_verifications?proof_type=reth-zisk&new_payload_request_root={}", + Hash256::ZERO + )) + .body(Body::from(body)) + .unwrap(), + ) + .await + .unwrap(); + assert_eq!(response.status(), 200); + + let body = to_bytes(response.into_body(), usize::MAX).await.unwrap(); + let resp: ProofVerificationResponse = serde_json::from_slice(&body).unwrap(); + assert_eq!(resp.status, ProofStatus::Valid); + } + + #[tokio::test] + async fn test_invalid_mock_proof() { + let state = mock_app_state().await; + let body = mock_proof(Hash256::ZERO, 32); + let response = test_router(state) + .oneshot( + Request::builder() + .method("POST") + .uri(format!( + "/v1/execution_proof_verifications?proof_type=reth-zisk&new_payload_request_root={}", + Hash256::ZERO + )) + .body(Body::from(body)) + .unwrap(), + ) + .await + .unwrap(); + assert_eq!(response.status(), 200); + + let body = to_bytes(response.into_body(), usize::MAX).await.unwrap(); + let resp: ProofVerificationResponse = serde_json::from_slice(&body).unwrap(); + assert_eq!(resp.status, ProofStatus::Invalid); + } + + fn mock_proof(new_payload_request_root: Hash256, mock_proof_size: u64) -> Bytes { + let public_values = expected_public_values(new_payload_request_root, ElKind::Reth).unwrap(); + bincode::serialize(&MockProof::new(public_values.to_vec(), mock_proof_size)) + .unwrap() + .into() + } +} diff --git a/crates/server/src/lib.rs b/crates/server/src/lib.rs new file mode 100644 index 0000000..f63602f --- /dev/null +++ b/crates/server/src/lib.rs @@ -0,0 +1,12 @@ +//! zkboost proof node library. +//! +//! Re-exports internal modules so that integration tests and the binary +//! can share the same code. + +pub mod config; +pub mod el_client; +pub mod http; +pub mod metrics; +pub mod proof; +pub mod server; +pub mod witness; diff --git a/crates/server/src/main.rs b/crates/server/src/main.rs new file mode 100644 index 0000000..cb6d644 --- /dev/null +++ b/crates/server/src/main.rs @@ -0,0 +1,63 @@ +//! zkboost proof node. +//! +//! Orchestrates witness fetching, proof generation, and an HTTP API for +//! submitting proof requests and retrieving completed proofs. + +use std::path::PathBuf; + +use clap::Parser; +use tokio::signal::unix::{SignalKind, signal}; +use tokio_util::sync::CancellationToken; +use tracing::{error, info}; +use tracing_subscriber::EnvFilter; +use zkboost_server::{config::Config, metrics::init_metrics, server::zkBoostServer}; + +#[derive(Parser)] +struct Cli { + /// Path to configuration file. + #[arg(long, short)] + config: PathBuf, +} + +#[tokio::main] +async fn main() -> anyhow::Result<()> { + tracing_subscriber::fmt() + .with_env_filter(EnvFilter::from_default_env()) + .init(); + + let cli = Cli::parse(); + + let metrics = init_metrics(); + + let config = Config::load(&cli.config)?; + info!( + port = config.port, + el_endpoint = %config.el_endpoint, + zkvm_count = config.zkvm.len(), + "configuration loaded" + ); + + let shutdown_token = CancellationToken::new(); + + let server = zkBoostServer::new(config, metrics).await?; + let (_addr, handles) = server.run(shutdown_token.clone()).await?; + + let mut sigint = signal(SignalKind::interrupt())?; + let mut sigterm = signal(SignalKind::terminate())?; + tokio::select! { + _ = sigint.recv() => info!("received SIGINT"), + _ = sigterm.recv() => info!("received SIGTERM"), + } + + info!("shutting down"); + shutdown_token.cancel(); + + for handle in handles { + if let Err(error) = handle.await { + error!(error = %error, "service task failed"); + } + } + + info!("all services stopped"); + Ok(()) +} diff --git a/crates/server/src/metrics.rs b/crates/server/src/metrics.rs new file mode 100644 index 0000000..6abcd66 --- /dev/null +++ b/crates/server/src/metrics.rs @@ -0,0 +1,147 @@ +//! Prometheus metrics registration, recording helpers, and HTTP middleware. + +use std::time::{Duration, Instant}; + +use axum::{ + extract::{MatchedPath, Request}, + middleware::Next, + response::Response, +}; +use metrics::{counter, describe_counter, describe_gauge, describe_histogram, gauge, histogram}; +use metrics_exporter_prometheus::{PrometheusBuilder, PrometheusHandle}; +use zkboost_types::ProofType; + +/// Initialize the Prometheus metrics exporter and register metric descriptions. +/// +/// Returns a handle that can be used to render metrics for the `/metrics` endpoint. +pub fn init_metrics() -> PrometheusHandle { + let builder = PrometheusBuilder::new(); + let handle = builder + .install_recorder() + .expect("failed to install Prometheus recorder"); + + // HTTP layer metrics + describe_counter!("zkboost_http_requests_total", "total http requests"); + describe_histogram!( + "zkboost_http_request_duration_seconds", + "http request duration" + ); + describe_gauge!("zkboost_http_requests_in_flight", "http requests in flight"); + + // Prove operation metrics + describe_counter!("zkboost_prove_total", "total prove operations"); + describe_histogram!( + "zkboost_prove_duration_seconds", + "proof generation duration" + ); + describe_histogram!("zkboost_prove_proof_bytes", "proof size"); + + // Verify operation metrics + describe_counter!("zkboost_verify_total", "total verify operations"); + describe_histogram!( + "zkboost_verify_duration_seconds", + "proof verification duration" + ); + + // Application metrics + describe_gauge!("zkboost_programs_loaded", "zkvm programs loaded"); + describe_gauge!("zkboost_build_info", "build info"); + + handle +} + +/// Record an HTTP request start (increment in-flight gauge). +fn record_request_start(endpoint: &str) { + gauge!("zkboost_http_requests_in_flight", "endpoint" => endpoint.to_owned()).increment(1.0); +} + +/// Record an HTTP request completion with status and duration. +fn record_request_end(endpoint: &str, method: &str, status: u16, duration: Duration) { + let endpoint = endpoint.to_owned(); + let method = method.to_owned(); + gauge!("zkboost_http_requests_in_flight", "endpoint" => endpoint.clone()).decrement(1.0); + counter!( + "zkboost_http_requests_total", + "endpoint" => endpoint.clone(), + "method" => method.clone(), + "status" => status.to_string() + ) + .increment(1); + histogram!( + "zkboost_http_request_duration_seconds", + "endpoint" => endpoint, + "method" => method + ) + .record(duration.as_secs_f64()); +} + +/// Record a prove operation result. +pub fn record_prove(proof_type: ProofType, success: bool, duration: Duration, proof_size: usize) { + let status = if success { "success" } else { "error" }; + counter!( + "zkboost_prove_total", + "proof_type" => proof_type.to_string(), + "status" => status + ) + .increment(1); + if success { + histogram!( + "zkboost_prove_duration_seconds", + "proof_type" => proof_type.to_string(), + ) + .record(duration.as_secs_f64()); + histogram!( + "zkboost_prove_proof_bytes", + "proof_type" => proof_type.to_string(), + ) + .record(proof_size as f64); + } +} + +/// Record a verify operation result. +pub fn record_verify(proof_type: ProofType, verified: bool, duration: Duration) { + counter!( + "zkboost_verify_total", + "proof_type" => proof_type.to_string(), + "verified" => verified.to_string() + ) + .increment(1); + histogram!( + "zkboost_verify_duration_seconds", + "proof_type" => proof_type.to_string(), + ) + .record(duration.as_secs_f64()); +} + +/// Set the number of loaded programs gauge. +pub fn set_programs_loaded(count: usize) { + gauge!("zkboost_programs_loaded").set(count as f64); +} + +/// Set the build info gauge with version label. +pub fn set_build_info(version: &str) { + gauge!("zkboost_build_info", "version" => version.to_string()).set(1.0); +} + +/// Axum middleware that records HTTP request metrics. +/// +/// Uses `MatchedPath` (the route template) rather than the raw URI to avoid +/// unbounded metric cardinality from path parameters. +pub(crate) async fn http_metrics_middleware(request: Request, next: Next) -> Response { + let start = Instant::now(); + let method = request.method().to_string(); + let path = request + .extensions() + .get::() + .map(|mp| mp.as_str().to_owned()) + .unwrap_or_else(|| "unmatched".to_owned()); + + record_request_start(&path); + + let response = next.run(request).await; + + let status = response.status().as_u16(); + record_request_end(&path, &method, status, start.elapsed()); + + response +} diff --git a/crates/server/src/proof.rs b/crates/server/src/proof.rs new file mode 100644 index 0000000..6f1e5e7 --- /dev/null +++ b/crates/server/src/proof.rs @@ -0,0 +1,374 @@ +//! Proof generation service. + +pub mod input; +pub mod worker; +pub mod zkvm; + +use std::{ + collections::{HashMap, HashSet}, + sync::Arc, + time::{Duration, Instant}, +}; + +use alloy_genesis::ChainConfig; +use bytes::Bytes; +use input::NewPayloadRequestWithWitness; +use lru::LruCache; +use reth_stateless::ExecutionWitness; +use tokio::{ + sync::{RwLock, broadcast, mpsc, mpsc::error::TrySendError}, + time::interval, +}; +use tokio_util::sync::CancellationToken; +use tracing::{debug, error, info, warn}; +use worker::WorkerInput; +use zkboost_types::{ + Hash256, MainnetEthSpec, NewPayloadRequest, ProofComplete, ProofEvent, ProofFailure, + ProofTimeout, ProofType, TreeHash, WitnessTimeout, +}; + +use crate::{ + proof::worker::{ProofResult, WorkerOutput}, + witness::WitnessServiceMessage, +}; + +const CLEANUP_INTERVAL: Duration = Duration::from_secs(12); + +/// Messages consumed by the proof service event loop. +#[derive(Debug)] +pub(crate) enum ProofServiceMessage { + RequestProof { + new_payload_request: Arc>, + proof_types: Vec, + }, + WitnessAvailable { + block_hash: Hash256, + witness: Arc, + }, +} + +struct PendingRequest { + new_payload_request: Arc>, + new_payload_request_root: Hash256, + proof_type: ProofType, + created_at: Instant, +} + +/// Manages proof lifecycle: pending, enqueued, and completed proof requests. +pub(crate) struct ProofService { + chain_config: Arc, + completed_proofs: Arc>>, + proof_event_tx: broadcast::Sender, + witness_service_tx: mpsc::Sender, + witness_timeout: Duration, + pending: HashMap>, + in_flight: HashSet<(Hash256, ProofType)>, +} + +impl ProofService { + /// Creates a new proof service with the given dependencies. + pub(crate) fn new( + chain_config: Arc, + completed_proofs: Arc>>, + proof_event_tx: broadcast::Sender, + witness_service_tx: mpsc::Sender, + witness_timeout: Duration, + ) -> Self { + Self { + chain_config, + completed_proofs, + proof_event_tx, + witness_service_tx, + witness_timeout, + pending: HashMap::new(), + in_flight: HashSet::new(), + } + } + + /// Runs the proof service event loop until shutdown is signalled. + pub(crate) async fn run( + mut self, + shutdown: CancellationToken, + mut proof_service_rx: mpsc::Receiver, + mut worker_output_rx: mpsc::Receiver, + worker_input_txs: HashMap>, + ) { + let mut cleanup_interval = interval(CLEANUP_INTERVAL); + + info!("proof service started"); + + loop { + tokio::select! { + biased; + + _ = shutdown.cancelled() => { + info!("proof service shutting down"); + drop(worker_input_txs); + break; + } + + _ = cleanup_interval.tick() => self.cleanup_stale_requests(), + + Some(output) = worker_output_rx.recv() => self.handle_worker_output(output).await, + + Some(msg) = proof_service_rx.recv() => self.handle_message(msg, &worker_input_txs).await, + + else => break, + } + } + + info!("proof service stopped"); + } + + fn cleanup_stale_requests(&mut self) { + let witness_timeout = self.witness_timeout; + let in_flight = &mut self.in_flight; + let proof_event_tx = &self.proof_event_tx; + self.pending.retain(|block_hash, entries| { + entries.retain(|request| { + let is_stale = request.created_at.elapsed() >= witness_timeout; + if is_stale { + warn!( + block_hash = %block_hash, + proof_type = %request.proof_type, + elapsed_secs = request.created_at.elapsed().as_secs(), + "pending request timed out" + ); + in_flight.remove(&(request.new_payload_request_root, request.proof_type)); + let _ = proof_event_tx.send( + WitnessTimeout { + new_payload_request_root: request.new_payload_request_root, + proof_type: request.proof_type, + } + .into(), + ); + } + !is_stale + }); + !entries.is_empty() + }); + } + + async fn handle_worker_output(&mut self, output: WorkerOutput) { + let new_payload_request_root = output.new_payload_request_root; + let proof_type = output.proof_type; + self.in_flight + .remove(&(new_payload_request_root, proof_type)); + + match output.proof_result { + ProofResult::Success(proof) => { + self.completed_proofs + .write() + .await + .put((new_payload_request_root, proof_type), proof); + let _ = self.proof_event_tx.send( + ProofComplete { + new_payload_request_root, + proof_type, + } + .into(), + ); + } + ProofResult::Failure(error) => { + let _ = self.proof_event_tx.send( + ProofFailure { + new_payload_request_root, + proof_type, + error, + } + .into(), + ); + } + ProofResult::Timeout => { + let _ = self.proof_event_tx.send( + ProofTimeout { + new_payload_request_root, + proof_type, + } + .into(), + ); + } + } + } + + async fn handle_message( + &mut self, + message: ProofServiceMessage, + worker_input_txs: &HashMap>, + ) { + match message { + ProofServiceMessage::RequestProof { + new_payload_request, + proof_types, + } => { + let block_hash = new_payload_request.block_hash(); + let new_payload_request_root = new_payload_request.tree_hash_root(); + let mut fetch_witness = false; + + for proof_type in proof_types { + { + let cache = self.completed_proofs.read().await; + if cache.contains(&(new_payload_request_root, proof_type)) { + debug!( + %new_payload_request_root, + proof_type = %proof_type, + "proof already completed" + ); + continue; + } + } + + if !self + .in_flight + .insert((new_payload_request_root, proof_type)) + { + debug!( + %new_payload_request_root, + proof_type = %proof_type, + "duplicate proof request" + ); + continue; + } + + debug!( + %new_payload_request_root, + %block_hash, + proof_type = %proof_type, + "new proof request" + ); + + self.pending + .entry(block_hash) + .or_default() + .push(PendingRequest { + new_payload_request: new_payload_request.clone(), + new_payload_request_root, + proof_type, + created_at: Instant::now(), + }); + fetch_witness = true; + } + + if fetch_witness + && let Err(error) = self + .witness_service_tx + .send(WitnessServiceMessage::FetchWitness { block_hash }) + .await + { + error!(error = %error, "witness request send failed"); + if let Some(entries) = self.pending.remove(&block_hash) { + for request in &entries { + self.in_flight + .remove(&(request.new_payload_request_root, request.proof_type)); + let _ = self.proof_event_tx.send( + ProofFailure { + new_payload_request_root: request.new_payload_request_root, + proof_type: request.proof_type, + error: format!("witness service unavailable: {error}"), + } + .into(), + ); + } + } + } + } + ProofServiceMessage::WitnessAvailable { + block_hash, + witness, + } => { + let Some(pending) = self.pending.remove(&block_hash) else { + return; + }; + + info!( + %block_hash, + count = pending.len(), + "dispatching pending requests" + ); + + let input = match NewPayloadRequestWithWitness::new( + &pending[0].new_payload_request, + witness, + self.chain_config.clone(), + ) { + Ok(input) => Arc::new(input), + Err(e) => { + for request in &pending { + self.in_flight + .remove(&(request.new_payload_request_root, request.proof_type)); + let _ = self.proof_event_tx.send( + ProofFailure { + new_payload_request_root: request.new_payload_request_root, + proof_type: request.proof_type, + error: format!("input construction failed: {e}"), + } + .into(), + ); + } + return; + } + }; + + for request in pending { + dispatch_to_worker( + worker_input_txs, + &self.proof_event_tx, + &mut self.in_flight, + request.proof_type, + input.clone(), + ); + } + } + } + } +} + +fn dispatch_to_worker( + worker_input_txs: &HashMap>, + proof_event_tx: &broadcast::Sender, + in_flight: &mut HashSet<(Hash256, ProofType)>, + proof_type: ProofType, + payload: Arc, +) { + let new_payload_request_root = payload.root(); + + let Some(tx) = worker_input_txs.get(&proof_type) else { + in_flight.remove(&(new_payload_request_root, proof_type)); + let _ = proof_event_tx.send( + ProofFailure { + new_payload_request_root, + proof_type, + error: format!("no zkVM worker for proof type '{proof_type}'"), + } + .into(), + ); + return; + }; + + let worker_input = WorkerInput { + payload, + new_payload_request_root, + proof_type, + }; + + match tx.try_send(worker_input) { + Ok(()) => { + debug!(proof_type = %proof_type, "proof dispatched"); + } + Err(error) => { + let reason = match &error { + TrySendError::Full(_) => "worker channel full", + TrySendError::Closed(_) => "worker channel closed", + }; + in_flight.remove(&(new_payload_request_root, proof_type)); + let _ = proof_event_tx.send( + ProofFailure { + new_payload_request_root, + proof_type, + error: format!("dispatch failed: {reason}"), + } + .into(), + ); + } + } +} diff --git a/crates/server/src/proof/input.rs b/crates/server/src/proof/input.rs new file mode 100644 index 0000000..59e8cc6 --- /dev/null +++ b/crates/server/src/proof/input.rs @@ -0,0 +1,241 @@ +//! Execution layer types and proof-type mapping functions. + +use std::sync::Arc; + +use alloy_eips::{eip4895::Withdrawal as AlloyWithdrawal, eip7685::RequestsOrHash}; +use alloy_genesis::ChainConfig; +use alloy_primitives::{B256, Bloom, Bytes}; +use alloy_rpc_types_engine::{ + CancunPayloadFields, ExecutionData, ExecutionPayload as AlloyExecutionPayload, + ExecutionPayloadSidecar, ExecutionPayloadV1 as AlloyExecutionPayloadV1, + ExecutionPayloadV2 as AlloyExecutionPayloadV2, ExecutionPayloadV3 as AlloyExecutionPayloadV3, + PraguePayloadFields, +}; +use ere_zkvm_interface::Input; +use reth_stateless::ExecutionWitness; +use stateless_validator_ethrex::guest::{ + StatelessValidatorEthrexInput, StatelessValidatorEthrexIo, +}; +use stateless_validator_reth::guest::{Io, StatelessValidatorRethInput, StatelessValidatorRethIo}; +use zkboost_types::{ElKind, Hash256, MainnetEthSpec, NewPayloadRequest, TreeHash}; + +#[rustfmt::skip] +pub use reth_stateless::StatelessInput; + +/// Combines a `NewPayloadRequest` with its execution witness and chain config, eagerly computing +/// the `StatelessInput`. +pub(crate) struct NewPayloadRequestWithWitness { + new_payload_request_root: Hash256, + stateless_input: StatelessInput, +} + +impl NewPayloadRequestWithWitness { + /// Constructs a new instance by eagerly computing the `StatelessInput`. + pub(crate) fn new( + new_payload_request: &NewPayloadRequest, + witness: Arc, + chain_config: Arc, + ) -> anyhow::Result { + let new_payload_request_root = new_payload_request.tree_hash_root(); + let execution_data = new_payload_request_to_execution_data(new_payload_request)?; + let block = execution_data + .payload + .try_into_block_with_sidecar(&execution_data.sidecar)?; + let stateless_input = StatelessInput { + block, + witness: Arc::unwrap_or_clone(witness), + chain_config: Arc::unwrap_or_clone(chain_config), + }; + Ok(Self { + new_payload_request_root, + stateless_input, + }) + } + + /// Returns tree hash root of `NewPayloadRequest`. + pub(crate) fn root(&self) -> Hash256 { + self.new_payload_request_root + } + + /// Generates zkVM input for the given EL kind. + pub(crate) fn to_zkvm_input(&self, el_kind: ElKind) -> anyhow::Result { + let stdin = match el_kind { + ElKind::Ethrex => StatelessValidatorEthrexIo::serialize_input( + &StatelessValidatorEthrexInput::new(&self.stateless_input, true)?, + )?, + ElKind::Reth => StatelessValidatorRethIo::serialize_input( + &StatelessValidatorRethInput::new(&self.stateless_input, true)?, + )?, + }; + Ok(Input::new().with_prefixed_stdin(stdin)) + } +} + +macro_rules! convert_payload_to_v1 { + ($payload:expr) => {{ + let payload = $payload; + AlloyExecutionPayloadV1 { + parent_hash: payload.parent_hash.0, + fee_recipient: payload.fee_recipient, + state_root: payload.state_root, + receipts_root: payload.receipts_root, + logs_bloom: Bloom::from_slice(&payload.logs_bloom), + prev_randao: payload.prev_randao, + block_number: payload.block_number, + gas_limit: payload.gas_limit, + gas_used: payload.gas_used, + timestamp: payload.timestamp, + extra_data: Bytes::copy_from_slice(payload.extra_data.as_ref()), + base_fee_per_gas: payload.base_fee_per_gas, + block_hash: payload.block_hash.0, + transactions: payload + .transactions + .iter() + .map(|tx| Bytes::copy_from_slice(tx.as_ref())) + .collect(), + } + }}; +} + +macro_rules! convert_payload_to_v1_with_withdrawals { + ($payload:expr) => {{ + let payload = $payload; + let v1 = convert_payload_to_v1!(payload); + let withdrawals: Vec = + payload.withdrawals.iter().map(convert_withdrawal).collect(); + (v1, withdrawals) + }}; +} + +fn new_payload_request_to_execution_data( + request: &NewPayloadRequest, +) -> anyhow::Result { + match request { + NewPayloadRequest::Bellatrix(inner) => { + let v1 = convert_payload_to_v1!(&inner.execution_payload); + Ok(ExecutionData::new( + AlloyExecutionPayload::V1(v1), + ExecutionPayloadSidecar::none(), + )) + } + NewPayloadRequest::Capella(inner) => { + let (v1, withdrawals) = + convert_payload_to_v1_with_withdrawals!(&inner.execution_payload); + let v2 = AlloyExecutionPayloadV2 { + payload_inner: v1, + withdrawals, + }; + Ok(ExecutionData::new( + AlloyExecutionPayload::V2(v2), + ExecutionPayloadSidecar::none(), + )) + } + NewPayloadRequest::Deneb(inner) => { + let (v1, withdrawals) = + convert_payload_to_v1_with_withdrawals!(&inner.execution_payload); + let v3 = AlloyExecutionPayloadV3 { + payload_inner: AlloyExecutionPayloadV2 { + payload_inner: v1, + withdrawals, + }, + blob_gas_used: inner.execution_payload.blob_gas_used, + excess_blob_gas: inner.execution_payload.excess_blob_gas, + }; + let versioned_hashes: Vec = inner + .versioned_hashes + .iter() + .map(|versioned_hash| B256::from(versioned_hash.0)) + .collect(); + let cancun_fields = + CancunPayloadFields::new(inner.parent_beacon_block_root, versioned_hashes); + Ok(ExecutionData::new( + AlloyExecutionPayload::V3(v3), + ExecutionPayloadSidecar::v3(cancun_fields), + )) + } + NewPayloadRequest::Electra(inner) => { + let (v1, withdrawals) = + convert_payload_to_v1_with_withdrawals!(&inner.execution_payload); + let v3 = AlloyExecutionPayloadV3 { + payload_inner: AlloyExecutionPayloadV2 { + payload_inner: v1, + withdrawals, + }, + blob_gas_used: inner.execution_payload.blob_gas_used, + excess_blob_gas: inner.execution_payload.excess_blob_gas, + }; + let versioned_hashes: Vec = inner + .versioned_hashes + .iter() + .map(|versioned_hash| B256::from(versioned_hash.0)) + .collect(); + let cancun_fields = + CancunPayloadFields::new(inner.parent_beacon_block_root, versioned_hashes); + let requests_hash = inner.execution_requests.requests_hash(); + let prague_fields = PraguePayloadFields::new(RequestsOrHash::Hash(requests_hash)); + Ok(ExecutionData::new( + AlloyExecutionPayload::V3(v3), + ExecutionPayloadSidecar::v4(cancun_fields, prague_fields), + )) + } + NewPayloadRequest::Fulu(inner) => { + let (v1, withdrawals) = + convert_payload_to_v1_with_withdrawals!(&inner.execution_payload); + let v3 = AlloyExecutionPayloadV3 { + payload_inner: AlloyExecutionPayloadV2 { + payload_inner: v1, + withdrawals, + }, + blob_gas_used: inner.execution_payload.blob_gas_used, + excess_blob_gas: inner.execution_payload.excess_blob_gas, + }; + let versioned_hashes: Vec = inner + .versioned_hashes + .iter() + .map(|versioned_hash| B256::from(versioned_hash.0)) + .collect(); + let cancun_fields = + CancunPayloadFields::new(inner.parent_beacon_block_root, versioned_hashes); + let requests_hash = inner.execution_requests.requests_hash(); + let prague_fields = PraguePayloadFields::new(RequestsOrHash::Hash(requests_hash)); + Ok(ExecutionData::new( + AlloyExecutionPayload::V3(v3), + ExecutionPayloadSidecar::v4(cancun_fields, prague_fields), + )) + } + NewPayloadRequest::Gloas(inner) => { + let (v1, withdrawals) = + convert_payload_to_v1_with_withdrawals!(&inner.execution_payload); + let v3 = AlloyExecutionPayloadV3 { + payload_inner: AlloyExecutionPayloadV2 { + payload_inner: v1, + withdrawals, + }, + blob_gas_used: inner.execution_payload.blob_gas_used, + excess_blob_gas: inner.execution_payload.excess_blob_gas, + }; + let versioned_hashes: Vec = inner + .versioned_hashes + .iter() + .map(|versioned_hash| B256::from(versioned_hash.0)) + .collect(); + let cancun_fields = + CancunPayloadFields::new(inner.parent_beacon_block_root, versioned_hashes); + let requests_hash = inner.execution_requests.requests_hash(); + let prague_fields = PraguePayloadFields::new(RequestsOrHash::Hash(requests_hash)); + Ok(ExecutionData::new( + AlloyExecutionPayload::V3(v3), + ExecutionPayloadSidecar::v4(cancun_fields, prague_fields), + )) + } + } +} + +fn convert_withdrawal(withdrawal: &zkboost_types::Withdrawal) -> AlloyWithdrawal { + AlloyWithdrawal { + index: withdrawal.index, + validator_index: withdrawal.validator_index, + address: withdrawal.address, + amount: withdrawal.amount, + } +} diff --git a/crates/server/src/proof/worker.rs b/crates/server/src/proof/worker.rs new file mode 100644 index 0000000..4f2607e --- /dev/null +++ b/crates/server/src/proof/worker.rs @@ -0,0 +1,130 @@ +//! Per-zkVM worker loop. + +use std::{ + sync::Arc, + time::{Duration, Instant}, +}; + +use bytes::Bytes; +use ere_zkvm_interface::Proof; +use tokio::{sync::mpsc, time::timeout}; +use tokio_util::sync::CancellationToken; +use tracing::{error, info}; +use zkboost_types::{Hash256, ProofType}; + +use crate::{ + metrics::record_prove, + proof::{input::NewPayloadRequestWithWitness, zkvm::zkVMInstance}, +}; + +/// Input sent to a per-zkVM worker for proof generation. +pub(crate) struct WorkerInput { + pub(crate) payload: Arc, + pub(crate) new_payload_request_root: Hash256, + pub(crate) proof_type: ProofType, +} + +/// Output returned by a worker after a proof attempt. +pub(crate) struct WorkerOutput { + pub(crate) new_payload_request_root: Hash256, + pub(crate) proof_type: ProofType, + pub(crate) proof_result: ProofResult, +} + +/// Result of a single proof generation attempt. +pub(crate) enum ProofResult { + Success(Bytes), + Failure(String), + Timeout, +} + +/// Runs a per-zkVM worker loop that processes proof requests sequentially. +pub(crate) async fn run_worker( + zkvm: zkVMInstance, + shutdown: CancellationToken, + mut worker_input_rx: mpsc::Receiver, + worker_output_tx: mpsc::Sender, + proof_timeout: Duration, +) { + let proof_type = zkvm.proof_type(); + info!(proof_type = %proof_type, "zkvm worker started"); + + loop { + let input = tokio::select! { + biased; + _ = shutdown.cancelled() => break, + input = worker_input_rx.recv() => match input { + Some(input) => input, + None => break, + }, + }; + + let new_payload_request_root = input.new_payload_request_root; + + info!( + new_payload_request_root = %new_payload_request_root, + proof_type = %proof_type, + "proving" + ); + + let start = Instant::now(); + + let proof_result = tokio::select! { + biased; + + result = timeout(proof_timeout, zkvm.prove(&input.payload)) => { + match result { + Err(_) => ProofResult::Timeout, + Ok(Ok((_, Proof::Compressed(proof), _))) => ProofResult::Success(Bytes::from(proof)), + Ok(Ok((_, proof, _))) => { + ProofResult::Failure(format!("unexpected proof kind: {:?}", proof.kind())) + } + Ok(Err(e)) => ProofResult::Failure(format!("{e}")), + } + } + }; + + let duration = start.elapsed(); + let (success, proof_size) = match &proof_result { + ProofResult::Success(bytes) => (true, bytes.len()), + _ => (false, 0), + }; + record_prove(proof_type, success, duration, proof_size); + + match &proof_result { + ProofResult::Success(proof) => { + info!( + new_payload_request_root = %new_payload_request_root, + proof_type = %proof_type, + proof_size = proof.len(), + "proof generated" + ); + } + ProofResult::Failure(err) => { + error!( + new_payload_request_root = %new_payload_request_root, + proof_type = %proof_type, + error = %err, + "proof generation failed" + ); + } + ProofResult::Timeout => { + error!( + new_payload_request_root = %new_payload_request_root, + proof_type = %proof_type, + "proof generation timed out" + ); + } + } + + let _ = worker_output_tx + .send(WorkerOutput { + new_payload_request_root, + proof_type: input.proof_type, + proof_result, + }) + .await; + } + + info!(proof_type = %proof_type, "zkvm worker stopped"); +} diff --git a/crates/server/src/proof/zkvm.rs b/crates/server/src/proof/zkvm.rs new file mode 100644 index 0000000..98f854a --- /dev/null +++ b/crates/server/src/proof/zkvm.rs @@ -0,0 +1,260 @@ +//! zkVM instance management and initialization. + +use std::{ops::Deref, sync::Arc, time::Duration}; + +use anyhow::Context; +use ere_server::client::zkVMClient; +use ere_zkvm_interface::{Input, ProgramProvingReport, Proof, ProofKind, PublicValues}; +use serde::{Deserialize, Serialize}; +use sha2::{Digest, Sha256}; +use stateless_validator_ethrex::guest::{ + StatelessValidatorEthrexGuest, StatelessValidatorEthrexIo, +}; +use stateless_validator_reth::guest::{ + Guest, Io, Platform, StatelessValidatorOutput, StatelessValidatorRethGuest, + StatelessValidatorRethIo, +}; +use tokio::time::{Instant, sleep, sleep_until}; +use url::Url; +use zkboost_types::{ElKind, Hash256, ProofType}; + +use crate::{config::zkVMConfig, proof::input::NewPayloadRequestWithWitness}; + +#[derive(Debug, thiserror::Error)] +#[allow(non_camel_case_types)] +pub(crate) enum zkVMError { + #[error("proof verification failed: {0}")] + VerificationFailed(String), + #[error("public values mismatch")] + PublicValuesMismatch, +} + +/// zkVM instance, either a remote ere-server or a mock. +#[allow(non_camel_case_types)] +#[derive(Clone)] +pub(crate) enum zkVMInstance { + /// External Ere server that provides zkVM functionalities via HTTP endpoints. + External { + /// Proof type identifier (e.g. `"reth-sp1"`). + proof_type: ProofType, + /// Client of external Ere server. + client: Arc, + }, + /// Mock zkVM for testing. + Mock { + /// Proof type identifier (e.g. `"reth-sp1"`). + proof_type: ProofType, + /// Mock zkVM implementation. + vm: MockzkVM, + }, +} + +impl zkVMInstance { + /// Creates a new zkVM instance from configuration. + pub(crate) async fn new(config: &zkVMConfig) -> anyhow::Result { + match config { + zkVMConfig::External { + endpoint, + proof_type, + } => { + let endpoint_url = Url::parse(endpoint) + .with_context(|| format!("Failed to parse endpoint URL: {endpoint}"))?; + let client = + zkVMClient::from_endpoint(endpoint_url.clone()).with_context(|| { + format!("Failed to create zkVM client for endpoint: {endpoint_url}") + })?; + Ok(Self::External { + proof_type: *proof_type, + client: Arc::new(client), + }) + } + zkVMConfig::Mock { + proof_type, + mock_proving_time_ms, + mock_proof_size, + mock_failure, + } => Ok(Self::Mock { + proof_type: *proof_type, + vm: MockzkVM::new( + proof_type.el_kind(), + *mock_proving_time_ms, + *mock_proof_size, + *mock_failure, + ), + }), + } + } + + /// Generates a compressed proof for the given payload. + pub(crate) async fn prove( + &self, + new_payload_request_with_witness: &NewPayloadRequestWithWitness, + ) -> anyhow::Result<(PublicValues, Proof, ProgramProvingReport)> { + let el_kind = self.proof_type().el_kind(); + let input = new_payload_request_with_witness.to_zkvm_input(el_kind)?; + match self { + Self::External { client, .. } => Ok(client.prove(input, ProofKind::Compressed).await?), + Self::Mock { vm, .. } => vm.prove(&input, ProofKind::Compressed).await, + } + } + + /// Verifies a compressed proof against the expected public values. + pub(crate) async fn verify( + &self, + new_payload_request_root: Hash256, + proof: Vec, + ) -> Result<(), zkVMError> { + let proof = Proof::Compressed(proof); + let public_values = match self { + Self::External { client, .. } => client + .verify(proof) + .await + .map_err(|error| zkVMError::VerificationFailed(error.to_string())), + Self::Mock { vm, .. } => vm + .verify(&proof) + .await + .map_err(|error| zkVMError::VerificationFailed(error.to_string())), + }?; + + let el_kind = self.proof_type().el_kind(); + let expected = expected_public_values(new_payload_request_root, el_kind) + .map_err(|error| zkVMError::VerificationFailed(error.to_string()))?; + + if public_values == expected { + Ok(()) + } else { + Err(zkVMError::PublicValuesMismatch) + } + } + + /// Returns the proof type identifier for this instance. + pub(crate) fn proof_type(&self) -> ProofType { + match self { + Self::External { proof_type, .. } | Self::Mock { proof_type, .. } => *proof_type, + } + } +} + +/// Serializable mock proof used by `MockzkVM` for testing. +#[derive(Serialize, Deserialize)] +pub(crate) struct MockProof { + public_values: PublicValues, + proof: Vec, +} + +impl MockProof { + /// Returns a `MockProof` with random proof bytes. + pub(crate) fn new(public_values: PublicValues, mock_proof_size: u64) -> Self { + let mut proof = vec![0; mock_proof_size as usize]; + rand::fill(proof.as_mut_slice()); + Self { + public_values, + proof, + } + } +} + +/// Mock zkVM for testing. +#[derive(Debug, Clone)] +pub(crate) struct MockzkVM { + el_kind: ElKind, + mock_proving_time: Duration, + mock_proof_size: u64, + failure: bool, +} + +impl MockzkVM { + /// Construct a `MockzkVM`. + pub(crate) fn new( + el_kind: ElKind, + mock_proving_time_ms: u64, + mock_proof_size: u64, + failure: bool, + ) -> Self { + Self { + el_kind, + mock_proving_time: Duration::from_millis(mock_proving_time_ms), + mock_proof_size, + failure, + } + } + + /// Simulate proof generation with configurable delay. + pub(crate) async fn prove( + &self, + input: &Input, + proof_kind: ProofKind, + ) -> anyhow::Result<(PublicValues, Proof, ProgramProvingReport)> { + let start = Instant::now(); + let public_values = execute(self.el_kind, input)?.to_vec(); + sleep_until(start + self.mock_proving_time).await; + if self.failure { + anyhow::bail!("proof generation failure"); + } + Ok(( + public_values.clone(), + Proof::new( + proof_kind, + bincode::serialize(&MockProof::new(public_values, self.mock_proof_size))?, + ), + ProgramProvingReport { + proving_time: self.mock_proving_time, + }, + )) + } + + /// Simulate proof verification by checking proof size. + pub(crate) async fn verify(&self, proof: &Proof) -> anyhow::Result { + let verification_time = Duration::from_millis(10); + sleep(verification_time).await; + let mock_proof: MockProof = bincode::deserialize(proof.as_bytes())?; + if mock_proof.proof.len() == self.mock_proof_size as usize { + Ok(mock_proof.public_values) + } else { + anyhow::bail!("invalid proof") + } + } +} + +fn execute(el_kind: ElKind, input: &Input) -> anyhow::Result<[u8; 32]> { + struct Host; + + impl Platform for Host { + fn read_whole_input() -> impl Deref { + [].as_slice() + } + + fn write_whole_output(_: &[u8]) {} + + fn print(_: &str) {} + } + + fn run(input: &Input) -> anyhow::Result<[u8; 32]> { + let (_, input) = input + .stdin + .split_at_checked(4) + .ok_or_else(|| anyhow::anyhow!("stdin should have length prefixed"))?; + let input = G::Io::deserialize_input(input)?; + let output = G::compute::(input); + let serialized = G::Io::serialize_output(&output)?; + Ok(Sha256::digest(serialized).into()) + } + + match el_kind { + ElKind::Ethrex => run::(input), + ElKind::Reth => run::(input), + } +} + +/// Computes the expected public values hash for a given payload root and EL kind. +pub(crate) fn expected_public_values( + new_payload_request_root: Hash256, + el_kind: ElKind, +) -> anyhow::Result<[u8; 32]> { + let output = StatelessValidatorOutput::new(new_payload_request_root.0, true); + let serialized = match el_kind { + ElKind::Reth => StatelessValidatorRethIo::serialize_output(&output)?, + ElKind::Ethrex => StatelessValidatorEthrexIo::serialize_output(&output)?, + }; + Ok(Sha256::digest(serialized).into()) +} diff --git a/crates/server/src/server.rs b/crates/server/src/server.rs new file mode 100644 index 0000000..f9ff1fb --- /dev/null +++ b/crates/server/src/server.rs @@ -0,0 +1,186 @@ +//! Reusable server initialization and startup. +//! +//! [`zkBoostServer::new`] performs async initialization (EL chain config fetch, zkVM +//! instance creation) and [`zkBoostServer::run`] binds the HTTP listener and spawns +//! all background services. + +use std::{ + collections::HashMap, + fs, + net::{Ipv4Addr, SocketAddr}, + num::NonZeroUsize, + sync::Arc, + time::Duration, +}; + +use alloy_genesis::ChainConfig; +use lru::LruCache; +use metrics_exporter_prometheus::PrometheusHandle; +use tokio::{ + net::TcpListener, + sync::{RwLock, broadcast, mpsc}, + task::JoinHandle, + time::sleep, +}; +use tokio_util::sync::CancellationToken; +use tracing::{error, info, warn}; +use zkboost_types::ProofType; + +use crate::{ + config::Config, + el_client::ElClient, + http::{AppState, router}, + metrics::{set_build_info, set_programs_loaded}, + proof::{ProofService, worker, zkvm::zkVMInstance}, + witness::WitnessService, +}; + +const CHANNEL_CAPACITY: usize = 128; + +/// Configured server ready to run. +#[allow(non_camel_case_types, missing_debug_implementations)] +pub struct zkBoostServer { + el_client: Arc, + chain_config: Arc, + zkvms: Arc>, + config: Config, + metrics: PrometheusHandle, +} + +impl zkBoostServer { + /// Creates a new server by initialising the EL client, fetching chain config, + /// and creating zkVM instances from the given configuration. + pub async fn new(config: Config, metrics: PrometheusHandle) -> anyhow::Result { + info!(url = %config.el_endpoint, "el endpoint configured"); + let el_client = Arc::new(ElClient::new(config.el_endpoint.clone())); + + let chain_config = if let Some(path) = &config.chain_config_path { + let content = fs::read_to_string(path)?; + let chain_config: ChainConfig = serde_json::from_str(&content)?; + info!("chain config loaded from file"); + chain_config + } else { + loop { + match el_client.get_chain_config().await { + Ok(Some(chain_config)) => break chain_config, + Ok(None) => warn!(url = %el_client.url(), "chain config not available"), + Err(e) => { + warn!(url = %el_client.url(), error = %e, "chain config fetch failed") + } + } + info!("retrying chain config fetch"); + sleep(Duration::from_secs(2)).await; + } + }; + let chain_config = Arc::new(chain_config); + info!("chain config loaded"); + + let mut zkvms = HashMap::new(); + for zkvm_config in &config.zkvm { + let instance = zkVMInstance::new(zkvm_config).await?; + info!( + proof_type = %zkvm_config.proof_type(), + "zkvm instance created" + ); + zkvms.insert(zkvm_config.proof_type(), instance); + } + set_programs_loaded(zkvms.len()); + set_build_info(env!("CARGO_PKG_VERSION")); + + Ok(Self { + el_client, + chain_config, + zkvms: Arc::new(zkvms), + config, + metrics, + }) + } + + /// Binds the HTTP listener, spawns background services, and returns the bound + /// address with join handles. + pub async fn run( + self, + shutdown_token: CancellationToken, + ) -> anyhow::Result<(SocketAddr, Vec>)> { + let mut handles = Vec::new(); + + let (proof_service_tx, proof_service_rx) = mpsc::channel(CHANNEL_CAPACITY); + let (witness_service_tx, witness_service_rx) = mpsc::channel(CHANNEL_CAPACITY); + let (worker_output_tx, worker_output_rx) = mpsc::channel(CHANNEL_CAPACITY); + let (proof_event_tx, proof_event_rx) = broadcast::channel(CHANNEL_CAPACITY); + + let witness_timeout = Duration::from_secs(self.config.witness_timeout_secs); + let proof_timeout = Duration::from_secs(self.config.proof_timeout_secs); + + let witness_service = WitnessService::new( + self.el_client, + proof_service_tx.clone(), + witness_timeout, + self.config.witness_cache_size, + ); + handles.push(witness_service.spawn(shutdown_token.clone(), witness_service_rx)); + info!("witness service started"); + + let mut worker_input_txs = HashMap::new(); + for zkvm in self.zkvms.values() { + let (worker_input_tx, worker_input_rx) = mpsc::channel(CHANNEL_CAPACITY); + worker_input_txs.insert(zkvm.proof_type(), worker_input_tx); + handles.push(tokio::spawn(worker::run_worker( + zkvm.clone(), + shutdown_token.clone(), + worker_input_rx, + worker_output_tx.clone(), + proof_timeout, + ))); + } + + let completed_proofs = Arc::new(RwLock::new(LruCache::new( + NonZeroUsize::new(self.config.proof_cache_size) + .expect("proof_cache_size must be non-zero"), + ))); + + let proof_service = ProofService::new( + self.chain_config, + completed_proofs.clone(), + proof_event_tx, + witness_service_tx, + witness_timeout, + ); + let proof_shutdown = shutdown_token.clone(); + handles.push(tokio::spawn(async move { + proof_service + .run( + proof_shutdown, + proof_service_rx, + worker_output_rx, + worker_input_txs, + ) + .await; + })); + info!("proof service started"); + + let app_state = Arc::new(AppState::new( + self.zkvms.clone(), + completed_proofs, + proof_service_tx, + proof_event_rx, + self.metrics, + )); + let listener = TcpListener::bind((Ipv4Addr::UNSPECIFIED, self.config.port)).await?; + let addr = listener.local_addr()?; + info!(port = addr.port(), "http server listening"); + + let shutdown_for_server = shutdown_token.clone(); + let server_handle = tokio::spawn(async move { + if let Err(error) = axum::serve(listener, router(app_state)) + .with_graceful_shutdown(shutdown_for_server.cancelled_owned()) + .await + { + error!(error = %error, "http server error"); + } + }); + handles.push(server_handle); + + Ok((addr, handles)) + } +} diff --git a/crates/server/src/witness.rs b/crates/server/src/witness.rs new file mode 100644 index 0000000..b8887ee --- /dev/null +++ b/crates/server/src/witness.rs @@ -0,0 +1,185 @@ +//! Witness fetching service. +//! +//! This module provides [`WitnessService`], which is responsible for fetching execution witness +//! data from the EL client. It responds to [`WitnessServiceMessage::FetchWitness`] requests from +//! the proof service, retrying failed fetches every second until success or timeout. + +use std::{ + collections::{HashMap, HashSet}, + num::NonZeroUsize, + sync::Arc, + time::{Duration, Instant}, +}; + +use lru::LruCache; +use reth_stateless::ExecutionWitness; +use tokio::{ + sync::mpsc, + task::{JoinHandle, JoinSet}, + time::interval, +}; +use tokio_util::sync::CancellationToken; +use tracing::{debug, error, info, warn}; +use zkboost_types::Hash256; + +use crate::{el_client::ElClient, proof::ProofServiceMessage}; + +const CLEANUP_INTERVAL: Duration = Duration::from_secs(12); +const RETRY_INTERVAL: Duration = Duration::from_secs(1); + +/// Messages consumed by the witness service event loop. +#[derive(Debug)] +pub(crate) enum WitnessServiceMessage { + FetchWitness { block_hash: Hash256 }, +} + +/// Fetches execution witness data from the EL client on demand. +pub(crate) struct WitnessService { + el_client: Arc, + proof_service_tx: mpsc::Sender, + witness_timeout: Duration, + witness_cache_size: usize, +} + +impl WitnessService { + /// Creates a new witness service with the given EL client and proof sender. + pub(crate) fn new( + el_client: Arc, + proof_service_tx: mpsc::Sender, + witness_timeout: Duration, + witness_cache_size: usize, + ) -> Self { + Self { + el_client, + proof_service_tx, + witness_timeout, + witness_cache_size, + } + } + + /// Spawns the witness service event loop as a background task. + pub(crate) fn spawn( + self, + shutdown_token: CancellationToken, + witness_service_rx: mpsc::Receiver, + ) -> JoinHandle<()> { + tokio::spawn(self.run(shutdown_token, witness_service_rx)) + } + + async fn run( + self, + shutdown_token: CancellationToken, + mut witness_service_rx: mpsc::Receiver, + ) { + let mut witness_cache: LruCache> = LruCache::new( + NonZeroUsize::new(self.witness_cache_size) + .expect("witness_cache_size must be non-zero"), + ); + let mut unresolved: HashMap = HashMap::new(); + let mut in_flight: HashSet = HashSet::new(); + let mut tasks: JoinSet<(Hash256, Option)> = JoinSet::new(); + + let mut cleanup_interval = interval(CLEANUP_INTERVAL); + let mut retry_interval = interval(RETRY_INTERVAL); + + loop { + tokio::select! { + biased; + + _ = shutdown_token.cancelled() => { + info!("witness service shutting down"); + tasks.abort_all(); + break; + } + + _ = cleanup_interval.tick() => { + let timeout = self.witness_timeout; + unresolved.retain(|block_hash, created_at| { + let is_stale = created_at.elapsed() >= timeout; + if is_stale { + warn!( + block_hash = %block_hash, + elapsed_secs = created_at.elapsed().as_secs(), + "pending fetch timed out" + ); + } + !is_stale + }); + } + + _ = retry_interval.tick() => { + for &block_hash in unresolved.keys() { + if !in_flight.contains(&block_hash) { + in_flight.insert(block_hash); + let el_client = self.el_client.clone(); + tasks.spawn(fetch_witness_task(el_client, block_hash)); + } + } + } + + Some(result) = tasks.join_next() => { + match result { + Ok((block_hash, Some(witness))) => { + let witness = Arc::new(witness); + witness_cache.put(block_hash, witness.clone()); + unresolved.remove(&block_hash); + in_flight.remove(&block_hash); + info!(block_hash = %block_hash, "witness fetched and cached"); + if let Err(error) = self.proof_service_tx.send(ProofServiceMessage::WitnessAvailable { block_hash, witness }).await { + error!(error = %error, "witness ready send failed"); + } + } + Ok((block_hash, None)) => { + in_flight.remove(&block_hash); + } + Err(error) if error.is_panic() => { + error!(error = ?error, "fetch task panicked"); + } + Err(_) => {} + } + } + + Some(message) = witness_service_rx.recv() => { + match message { + WitnessServiceMessage::FetchWitness { block_hash } => { + if let Some(witness) = witness_cache.peek(&block_hash).cloned() { + debug!(block_hash = %block_hash, "witness cache hit"); + if let Err(error) = self.proof_service_tx.send(ProofServiceMessage::WitnessAvailable { block_hash, witness }).await { + error!(error = %error, "witness ready send failed"); + } + continue; + } + + if in_flight.contains(&block_hash) { + debug!(block_hash = %block_hash, "witness fetch in flight"); + continue; + } + + unresolved.entry(block_hash).or_insert_with(Instant::now); + in_flight.insert(block_hash); + let el_client = self.el_client.clone(); + tasks.spawn(fetch_witness_task(el_client, block_hash)); + } + } + } + } + } + } +} + +async fn fetch_witness_task( + el_client: Arc, + block_hash: Hash256, +) -> (Hash256, Option) { + match el_client.get_execution_witness_by_hash(block_hash).await { + Ok(Some(witness)) => (block_hash, Some(witness)), + Ok(None) => { + debug!(block_hash = %block_hash, "witness not found"); + (block_hash, None) + } + Err(error) => { + warn!(block_hash = %block_hash, error = %error, "witness fetch failed"); + (block_hash, None) + } + } +} diff --git a/crates/server/tests/fixture/chain_config.json b/crates/server/tests/fixture/chain_config.json new file mode 100644 index 0000000..82be0f8 --- /dev/null +++ b/crates/server/tests/fixture/chain_config.json @@ -0,0 +1,45 @@ +{ + "chainId": 3151908, + "homesteadBlock": 0, + "daoForkSupport": false, + "eip150Block": 0, + "eip155Block": 0, + "eip158Block": 0, + "byzantiumBlock": 0, + "constantinopleBlock": 0, + "petersburgBlock": 0, + "istanbulBlock": 0, + "berlinBlock": 0, + "londonBlock": 0, + "mergeNetsplitBlock": 0, + "shanghaiTime": 0, + "cancunTime": 0, + "pragueTime": 0, + "osakaTime": 0, + "bpo1Time": 0, + "terminalTotalDifficulty": 0, + "terminalTotalDifficultyPassed": true, + "depositContractAddress": "0x00000000219ab540356cbb839cbe05303d7705fa", + "blobSchedule": { + "bpo1": { + "baseFeeUpdateFraction": 8346193, + "max": 15, + "target": 10 + }, + "cancun": { + "baseFeeUpdateFraction": 3338477, + "max": 6, + "target": 3 + }, + "osaka": { + "baseFeeUpdateFraction": 5007716, + "max": 9, + "target": 6 + }, + "prague": { + "baseFeeUpdateFraction": 5007716, + "max": 9, + "target": 6 + } + } +} \ No newline at end of file diff --git a/crates/server/tests/fixture/execution_witness.json b/crates/server/tests/fixture/execution_witness.json new file mode 100644 index 0000000..6588706 --- /dev/null +++ b/crates/server/tests/fixture/execution_witness.json @@ -0,0 +1,50 @@ +{ + "state": [ + "0xf90171a046a9f1217c365990825b7d161fc23cae5688cfb6b2307efe4b732c723e03795880a0c0e0b54cb105bad41b4b925883507463ddfae71c619ba2e41d6d57da2a28effea0793c9db0e252f8f5c79a9d872efc5385ab632a9dc31217637b3509fcf6f0b010a077c059a2b360e9c967686a1302a40994cd63a81aa80a841991d8f3d7379b68eb80a0386a1e942dbe86342b17e2e8b28a259d6db65df8e05f944951a089bb9f3d989fa0315b6e4145b520b88ff5fb638b922671ee1ecbcb65b57b9a4be650ab1fce1d39a066e01acc8a9826bc3d5f5286819fc5883dfa30943331f1e7ff2968bfc57ea2d0a00f7041c0b666de2c820d816b27347738f0e8e2d4d7e1e94e2908b88bc3665a338080a012794aea34d39f220863a2977506ebe5555c2b6488a9469fed918b744f67d6d9a0ace6b45485050162428ffe70f5214d2350ed4890b94322bda3ba63a17342983aa0e20d629ffd2bee3848106f86b98c50a9de755283203bb778c19fa269c8ddb2e38080", + "0xe214a0daadd0f2cf85d5b6a644144de38d5eea115a4546c5efc75c3aee9934f46754a0", + "0xf90131a0e9355b99a40b0e92cc489d34c25f68648461fe0dfcefe3c861f1042ae7cbd522a0766a5ea5b9545a72a463a0fc6151efd1ea0e13f7bd151789dcbff75a1e73cd7180a06e27501c46d61120352d54c49863fcf0eaafcfbffdab9e9e09847d62beef79d88080a0731b30b1211ab24c3e719ad1774d6d450379c926217e248edc5c2a6812e0169480a02978c23bea458e7f47cdc57a9938245e2c763f556847e7e320f7f1bd844127628080a047b4dd8c12aa7dec12a56beb24dff26bd425669991ba54e9ec3225fe6293da24a039f39136138de3527d38db1831c98f8897eecd0a75a77129f6386184f28c779ba0fa149b424c332acc1c6967d908eab8e4922f27e00499ed6a1aca3b9975d87ef580a09f297d5e53d34bc2096cce66773c42bf5b177714e3bb9f180521045b34f7127d80", + "0xf90211a0fcf8a530a63eb8575eb9a70c95332fc1047b567be3d1da03a21c9917d92b14a6a006d47616df479b46b302f2a8b7ed03cb537f6cf7c551c15421c65db4e00fa97fa038e34f9e0e4830343ba24f5fcf0eba28d79cb86397adfb16a0169ee7f0180036a004f7ae295715850712c9dc7f1b9f973797b89ef0f46991203ac789210330a517a0dd3420839babaee761e7eaa38ad5f596b1a9b8716e7e9b9261949a964a5a7d61a0eea64374052ac460957bbc34a071cb8b25dcdf44d96785a55b34242914c83f9fa008763a217b516bcfeadc7f6849e812b392643f50a1d25f002ceec6c2ca0adcafa083c6979e463c02818ffeadaeeb8abc9f2f51e767fb9151a7fc89989eb40b57aca0cbcdc1d226a540c50cb1e615e7af99f171d4365b45734940e22d47ec4aa23a14a0be88e4724326382a8b56e2328eeef0ad51f18d5bae0e84296afe14c4028c4af9a018e0f191e57d4186717e0f3c9379d2438cec0babd12d3903a4ad560f017331bfa01796617427e67ed10cdf8a72b02689a700ba71eb93186a1b120c9ad0b0e56eaea0ad0bb86b47186c04223e85a9c33dd1c87dd6e5c17f753f4fd0a56772d8a78399a065fb94808e31ca248fb2d9de329b81735b22f75d109f389678c9965418bf1f16a06a2b50671c3f299bfd4b6cf43d6e5d6aafd4d3677c38a8af52a0cd7680de2b94a037ff00fbe2105bce0e6ed9ea80a1d67b8a476b1ff3d177ac9597a53241e47aa780", + "0xf901b1a027db720cbe694541a361e08b5450894ddce39b11113fe952080ad5f54ada6f4a80a0d2e57f615a47508c6e60935353428b9fc1cc75677a3eb8f5f73d61dd0aaff5f5a0ca976997ddaf06f18992f6207e4f6a05979d07acead96568058789017cc6d06ba04d78166b48044fdc28ed22d2fd39c8df6f8aaa04cb71d3a17286856f6893ff8380a0fc3b71c33e2e6b77c5e494c1db7fdbb447473f003daf378c7a63ba9bf3f0049da0a9c8e462df1860757a204a01fccc87b873837b0a32cbcc645fb663f3eb12a705a07b8e7a21c1178d28074f157b50fca85ee25c12568ff8e9706dcbcdacb77bf854a0973274526811393ea0bf4811ca9077531db00d06b86237a2ecd683f55ba4bcb0a091d9c76bfbc066e84f0b415c737ab8c477498701d920526db41690050cfade99a06aa67101d011d1c22fe739ef83b04b5214a3e2f8e1a2625d8bfdb116b447e86fa0244e4282dfec33c9bb765162ceee4f2e6390033a94b620d50a2fc6943ebd82fca0f3b039a4f32349e85c782d1164c1890e5bf16badc9ee4cf827db6afd2229dde6a0d9240a9d2d5851d05a97ff3305334dfdb0101e1e321fc279d2bb3cad6afa8fc88080", + "0xf90171a06664dd6bcbb08b83f84324db8cbaf2ceb221e49e66971369dd2257e947a3b13d80a0f4ec365c37413b5f9e7d38c3c6409922fa2a593757ef6176b7291ede5ae2b2d780a0614ab7fe84bea831a68e5e39c6e2d339db432b94dcd29ac75de694cfc6641496a036750a0cdda09ef53dc4a7510eb69e87fbafb1739f51d52c60214b7e0d276ddda04eb05cc2337a47e5d315fc9e2972f88b2282caecf7b79cb486ccf4e64ddf54cd80a0044dadb95a10fad8f922e38449d128807ed6c4b3e6af52d0faa865be8cb8847480a0d53e862eebd81f90452eada8434dfdd03a7ef3d06d6db3e68cbc7d05dff81ec0a0eb47388255e7ca68b42fa56180019c61e2dd301bfe20226d6a74d795f6b016a6a0c522d5defc176e5fa5fc0f16d95ad335f25668067c2c9a55db7d901fd8ac04c6a06c457c05a87c557f84f6d98cfb3754a20c1ded0550ef405433d3514f332c77df80a0d5758f21c6c63a45c81d16ecca352c41af637c1729f8866900efcf731dc10db280", + "0xf901518080a0f1a60e8881cfcb2dc50ba58c326ccc9a6da8287c1e5f56d2017563be700058c4a0616362468a3391221e3782da42e2d6fb8ea41da6bdd2d679e20bf0375c06158680a0ed2fba131fadeadeb1082f565fff16ceb008f693056e3140204716c0739cf1e08080a0cfcecd85b5b3b2b03c196589d3d3b9bcd0ddfc01f000cde9fe3cab41dc6a0a16a0b2a5565ce39d8b7fabb242f087f05b7273aef44094f4166046cddd978751c4bea06234ead07239df2c23d50d21d2e045332bb3e2fb0a402aae5780b823e7d5308680a0ebe51b14fea6aaa5c097f2506874e990813c36cd31399ee3d72666de2dde3fcca051eac0e6e8747ed945c8119613a8359cb76220e714610cf783388ce900153208a0e16e6773b65ff27c428b07407a2d2e479712166515a4a43ecc3c4444d77d4f34a0105bafd3bfbb01dd5f28afe06b314ccf6d5f1bddd1e2135dcc010cb3aedd1d4380", + "0xf869a02086c581c7d7b44eecbb92fd9e5867945ec1acdc0ea5bbabda21d17dddf06473b846f8440180a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a00345a365d2f4c5975b9f1599abe0a2ee76b7a3a731bc68781bd04c84e4858f50", + "0xf8518080a0a63eaef203909ce313085e71f47b6855ccd4fffe444fba1ec1efdab787203351808080a079af4179331361fad570767001c2b705c100b691c849c2bda966d070709c4bf880808080808080808080", + "0xf8f18080a0936cc4aad97b5838a8bc0dfa95a5ad0a0fe2c4681ffe209a0228098aad0c619080a0985a93e071c1474beffb3b3feefcf343ea7e4e002d8c6c7675de86cc9ebc27c0a022652c87d9810e05a254c5942729b67343e1069440f4bee452c8c7bb88d193e8a0975e4f968cf4537118047c31c634177fbec68949fd40003601aab2ff822bcc5580a04b66d0874dc47dba19ba179183342befb18cd80e6d4f85516123426f86e0d7afa081ce69bcb065377bda0ac34c8b05086357838440690dbcccba20f3e8cab1b88680808080a0dc281265feb5bcd82bc162628f62f92dc649b77c80a3ac5d14bdf3d367c495238080", + "0xf90211a040da929897ecf8fb0ecdda44d1c6aa37c7b5d19d0a6f1255c3aaac43b77f2d4ca05dbd3e7becc744398948292f4810e753b166b91cc1a763b214b24718e2bc432aa0d8222bc84a44e1d1d03bdae69910ff3b244c815fa99ef1a9aa6bb568cad6b35ca050e569e8e5e77ab130db2842f7598cee50d0b42cc2504a9df287175c307b23c3a01fd4c856668574229bec8b57377eb317351e0695f8c7c8239aa1016a73001b16a0e0cf581054d8c2bab1359dddde660c659c0e5d70ca2c03e667419d1bc9e45f05a0ebe2e281fc5af1d9bc149c1bf210d264f9b283a2c1760abf0ad5f48e08499ac8a08be4370ed1686f92ab5478848e85a1abab751c9c80e7f8d68daa8c3d8232356aa02fb840ef5765a4ceb26d610badea7ea799c28544f3b329b986c400ff272967d2a0e8393cb9738eea3a5031110dd9c2043e360267072374de576cdc9bc4fa015d39a046ff1faf6df6476a5a4d8f6ba32c8f38582b3a7bd4e12893c1712894ea39c017a008afbb10c9064b061ba3a17cfaf8c083b376a402c60704bc0afaa7a55d27f5c9a0582d0c27b5152cb3f3247a8752888739769fb2b6e3f7842298bc26b616773b88a0db4a8cc49ce3a0fefe00143359d4f0fa86026559ea073bb061b7aacd217ac037a0f31e8aa4efb4024c99d873f31485f1c496f484c345b1ec664f4ba723499e03f8a0672f74dceafee2ee98a97fb19f4afdb991ba8c1ee019438f15b809da4b427b5a80", + "0xf90211a04efbc90ce3b15216a559cdb50fb788b0af3916ef1777a585e7093e27cf4bc16da0047b79502e6ba90c8c1b4863e8380b3e6cc23da1c208f8e39c348a936af31ea5a03db8dd4c19ae2b67a736b757995cb7b57ed55ccdd34fb0ebe979a2dee0c66339a0471db2263571236146b863a32d0d1abe6e21a984998b2d7c0376b4243dca42d2a024e8f92fe5bdde58f4954f534b6f91659a8c0f889abdbf7eec9ab77a26478072a0f8afbd19dafaf176fc835595483ea85f554b1b840e8709b3c2a07715411ecb08a034cb0ac81dbce62a5c9855fe0311bd6827fecbb9aa741a7c8e8b7427f73b8716a0a2a9a28a4324e79e625b104a232620f515ff4a3428c78257bbec3621343ec11aa0b030f3e6c8e7b40bc5bea3da238bcf7546c521b7d6b72dbd98e3fbffb0d604ada0de4bf15b56b7a96707c9c6072d1f413322e563f04ec3c3f9fcf7719b073ed285a0c641efacb85f02a412724d2ba1a107c767d66f5258ae33c9c64bd1bcc4a64540a02e14db6c4900768cf91528d8e1b746f9ab032f277077459f5cc79d16b6be0dc3a006c495fb6961358f4bde6c279838bbc557f9927391b42070bd44b30ab824430fa07415c94beb78124e62f7f63ad7a64076cf7b004809565b8a63dedcacc1434ac5a092712479fda69c5e14b2085716b5e5ab229494f395740b941280432b831ed221a0176a9fce68e6fd07098e5bd0e742a828173ba4a7feed5b6455794caad04462a880", + "0xf869a0209d57be05dd69371c4dd2e871bce6e9f4124236825bb612ee18a45e5675be51b846f8440180a0a247228347f628c6463d5f2932202f269bcabe3dbc08a56392c2dc88e7e04249a06e49e66782037c0555897870e29fa5e552daf4719552131a0abce779daec0a5d", + "0xf90211a0e66e395bd17cd8e5cea8b1c1aad2bb861eeb8a2bb096ea6eddeb34422497bdaaa04c03fe869c8cde143d01ab6bfc09226ea42d9ad99a53263f69716a7186c0bf0aa077e46fe2af85fe2ea2de398481c148651e7ee82f27176160eb18b3a802661798a0c52146e012e5094a13d00fc9dbe596a0639c59e2587b7ac55038d3e52d4f4936a044cb808faa3a8e993889588681b030c9a97babe7e15fdb71be950e9a88a7e402a03deea8359c1b0971aa68d701e9cd18016134f5310b0e4a7d9833247db460a1f1a02cedc09ae6f35f5e75e4a65cee5fc753b113311d912b25fc289a872885415a8ca080b9f7d63a5ea0d7b20ace0018da20977a795543c0ab2d4035b60885e5d60828a0b8f2aa8b6816e39e58f9193d23f9573f75e4c0dea753b325da153a6fbdbaabd2a05126fa3c18c632812536718c92ed0747e4a610c245ea1234acbca7533f1506f2a014116df18532e1f44477d3cf371240e82d2cf7c02542d6da6ab56861626a0c24a0ad7eb60b7242bb4abab99f42056bcc64ae2de2b6182550cb6864c404b059fb3fa04e222b8402af16d6151aba0426b59a029db34ba31592f254ba8d6f64e59e07eba0eae43e73dfb5784c88f6424e4da4ac7aae2aa29f09cd528aab89a4003e3a4da7a023fc581b6065c3d34578d7119f3385df16ae9a24aab09a98877d36fd844f2933a0a4cb53144ee264a09401aabbebb43c80264ebfce063a70c28595e1b0c52fdd9c80", + "0xf90211a0f53fd45e8a28bfc7c92543aac0f242249bd15dc550b8d1d43defabfe1ff4622ba072d67f642876a04c9733ce298d4bb2fdc2eb041b6760ed0a3be006785b0705e0a0a86c39e9a32652492ee5240d1715c6a63537351d350754b62952760d8e1f944ba0e79513901b1f313c826300a31dff17f6adf9e2aeb895f730dbb93f0a96a86d9fa031c4646963f14566afb0e50a6c400d69c834c3b1fdb3909677856cbb576db4e5a09cdcc334e9d1c6451e5f5230efdd07ac62f48223d3a71b7082d1c9f3faee6af1a0f5ea37b375d1f04089104149dd9204aa0ff3c90167f7aca7da201905594300e4a076972cc63f4fabea810e87083ec1899b687d8748d26fe16fd4b6a13ae3e303f1a04ff31ed8ee553088b2e578f36bf3ed50d5cbd58611261be37633294dc61acca9a028b05d809456d53fc06c9b102d216cff567a7aca7c9d1cb4cdca67965f0ef4cda01556f03106eeb9fc5a473e8f7f042e57d827b78b76a5f7a8f5b187f8d897515da0f762ae6fe61a92321fb8d528b2f5f4b1b97a94ebf2d5ec0899e8f703fba9790da036affb194c9227b46dece3bc3e1e5ef56403db6c8e34fe1b8bb3ae197158b5d6a0db08702017c418fb841716b9c2454676fa632f607d5b261f55c7434dbc69c4d6a0d4da88e24a26de50f4f0d35a348e12da471480c6e612dacccbc594a61f58d74ca0aaba74a722fd0645b8b7a8886d0e891e04c4e57914480568f5334d7514391f6680", + "0x80", + "0xf8429f37d5f9b51ca71bda3c02250aa5ededabaa712e18e5f1714fde16280d94a4a3a1a0d5848dbf659bcc407318ddcac1ad62fb7b58c53df808ed0a560c8d4a94ac3e6f", + "0xf8689f3aea581b220579a2b99819299dd32c7c28a420018ecb0bde93af007ad89a31b846f8440180a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a078c6cb5202685228bbcbfb992b1c4e116c7ec5ef11e25b8e92716cfc628ddd60", + "0xf869a020d65eaa92c6bc4c13a5ec45527f0c18ea8932588728769ec7aecfe6d9f32e42b846f8440180a0a52d06d7443bb469a8ddfecb744e9750fa7284a237b31f7168562123b84c3547a0f57acd40259872606d76197ef052f3d35588dadf919ee1f0e3cb9b62d3f4b02c", + "0xf90211a065cb9654d83c2c587ff35d995153e55908ccc8d12f99cec6f0fca2174d0d4887a072c2cce9f8770d341a4cb7c7cdc53d75d6308b55e9f991bc8ba67b29434b61dfa0f2b29241a79b4cf67be8c19e0fc49894bbc908bdfaa864f313e640a9656271cca0a4f08ea6851799ebadce763bdb22c8511a37106f2b1f1a2e1da77743588a4751a0e473037e78e7f6b59faf7c818971524734244419165e3b52fd6747e4acbb3235a09f871e9dc9ad7e80a33f12dfb19ec657a944edd24ecd975367a4675d7a2760a0a0f3e41d9e7b89a679eba0c449b24e2f6b074dd4e65abc10fee304b97893689673a0ba956ceecf3546a048edbdb0e93c6bd5f9437ee2bc2eb547d95cad86e16e791ba0be49e1efa56a6325758e40aa25985c3f71f2d20888daa9efd8e2e9cd0d70826ca05d4d0edd678514b0b449d8689f7971252fd7b86378a102395d5ee769d709c2a1a0fcacd3004b2d9f8c601c667041baea5c7ad53bde430303ab3d2f5c765804cd82a0b7195c41d29afbb5b45413885333d6a19b0679d3a92a9f1198ab04689ac0518ca06675b419aca5f5ab938080fd8245ae9c388c144521ad7d4a57e8f36212e218a2a0ddfccdcd7960367614d844e7fca5cb92573ace5ca42ad9381dfc2c69e7f0f890a04651f6d80d233d28e5cda8940d11319698f604ee414041a9374a5ee3d7305b1fa0da847328820b77fcc53e716178f77359797b68b90e53117251c9115ee6fc428880" + ], + "codes": [ + "0x3373fffffffffffffffffffffffffffffffffffffffe1460cb5760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff146101f457600182026001905f5b5f82111560685781019083028483029004916001019190604d565b909390049250505036603814608857366101f457346101f4575f5260205ff35b34106101f457600154600101600155600354806003026004013381556001015f35815560010160203590553360601b5f5260385f601437604c5fa0600101600355005b6003546002548082038060101160df575060105b5f5b8181146101835782810160030260040181604c02815460601b8152601401816001015481526020019060020154807fffffffffffffffffffffffffffffffff00000000000000000000000000000000168252906010019060401c908160381c81600701538160301c81600601538160281c81600501538160201c81600401538160181c81600301538160101c81600201538160081c81600101535360010160e1565b910180921461019557906002556101a0565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff14156101cd57505f5b6001546002828201116101e25750505f6101e8565b01600290035b5f555f600155604c025ff35b5f5ffd", + "0x3373fffffffffffffffffffffffffffffffffffffffe14604d57602036146024575f5ffd5b5f35801560495762001fff810690815414603c575f5ffd5b62001fff01545f5260205ff35b5f5ffd5b62001fff42064281555f359062001fff015500", + "0x3373fffffffffffffffffffffffffffffffffffffffe14604657602036036042575f35600143038111604257611fff81430311604257611fff9006545f5260205ff35b5f5ffd5b5f35611fff60014303065500", + "0x3373fffffffffffffffffffffffffffffffffffffffe1460d35760115f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1461019a57600182026001905f5b5f82111560685781019083028483029004916001019190604d565b9093900492505050366060146088573661019a573461019a575f5260205ff35b341061019a57600154600101600155600354806004026004013381556001015f358155600101602035815560010160403590553360601b5f5260605f60143760745fa0600101600355005b6003546002548082038060021160e7575060025b5f5b8181146101295782810160040260040181607402815460601b815260140181600101548152602001816002015481526020019060030154905260010160e9565b910180921461013b5790600255610146565b90505f6002555f6003555b5f54807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff141561017357505f5b6001546001828201116101885750505f61018e565b01600190035b5f555f6001556074025ff35b5f5ffd" + ], + "keys": [ + "0x000f3df6d732807ef1319fb7b8bb8522d0beac02", + "0x0000000000000000000000000000000000000000000000000000000000003808", + "0x0000000000000000000000000000000000000000000000000000000000001809", + "0x00000961ef480eb55e80d19ad83579a64c007002", + "0x0000000000000000000000000000000000000000000000000000000000000002", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000003", + "0x0000f90827f1c53a10cb7a02335b175320002935", + "0x00000000000000000000000000000000000000000000000000000000000004af", + "0x0000bbddc7ce488642fb579f8b00f3a590007251", + "0x0000000000000000000000000000000000000000000000000000000000000002", + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0000000000000000000000000000000000000000000000000000000000000001", + "0x0000000000000000000000000000000000000000000000000000000000000003" + ], + "headers": [ + "0xf9026fa084a5904e068368b6581e5afa05f96e3912068ab8ceee08ca76bdb9719bd1c090a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948943545177806ed17b9f23f0a21ee5948ecaa776a03bb7c2e1c292bc41a27064b9160eb131723e6c345851ee0c386f09115da5fae6a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b9010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000808204af8402255100808469aeca6d92726574682f76312e31302e312f6c696e7578a0f2940bf2aad7139113b79fcd654cb699530e993a33dc05a31ebfcf017643b55888000000000000000007a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b4218080a037afc7de70547b71e752341e78303f688e6f5b87e47367b747947d5d34af77a0a0e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855" + ] +} \ No newline at end of file diff --git a/crates/server/tests/fixture/new_payload_request.ssz b/crates/server/tests/fixture/new_payload_request.ssz new file mode 100644 index 0000000..6ffe35c Binary files /dev/null and b/crates/server/tests/fixture/new_payload_request.ssz differ diff --git a/crates/server/tests/integration.rs b/crates/server/tests/integration.rs new file mode 100644 index 0000000..a02ae6c --- /dev/null +++ b/crates/server/tests/integration.rs @@ -0,0 +1,349 @@ +//! Integration test for zkboost-server. + +use std::{ + collections::HashMap, + net::Ipv4Addr, + sync::{Arc, OnceLock}, + time::{Duration, Instant}, +}; + +use alloy_genesis::ChainConfig; +use alloy_primitives::B256; +use axum::{Json, extract::State}; +use bytes::Bytes; +use futures::StreamExt; +use metrics_exporter_prometheus::PrometheusBuilder; +use reth_stateless::ExecutionWitness; +use tokio::net::TcpListener; +use zkboost_client::{MainnetEthSpec, zkBoostClient}; +use zkboost_server::{ + config::{Config, zkVMConfig}, + server::zkBoostServer, +}; +use zkboost_types::{ + Decode, Hash256, NewPayloadRequest, ProofEvent, ProofEventKind, ProofStatus, ProofType, + TreeHash, +}; + +struct Fixture { + new_payload_request: NewPayloadRequest, + new_payload_request_root: Hash256, + chain_config: ChainConfig, + witness: ExecutionWitness, +} + +impl Fixture { + fn load() -> Self { + const NEW_PAYLOAD_REQUEST: &[u8] = include_bytes!("fixture/new_payload_request.ssz"); + const CHAIN_CONFIG: &str = include_str!("fixture/chain_config.json"); + const EXECUTION_WITNESS: &str = include_str!("fixture/execution_witness.json"); + let new_payload_request = NewPayloadRequest::from_ssz_bytes(NEW_PAYLOAD_REQUEST).unwrap(); + let new_payload_request_root = new_payload_request.tree_hash_root(); + let chain_config: ChainConfig = serde_json::from_str(CHAIN_CONFIG).unwrap(); + let witness: ExecutionWitness = serde_json::from_str(EXECUTION_WITNESS).unwrap(); + Fixture { + new_payload_request, + new_payload_request_root, + chain_config, + witness, + } + } +} + +async fn start_mock_el(fixture: &Fixture, witness_timeout: bool, witness_delay: bool) -> url::Url { + struct MockElState { + witnesses: HashMap, + chain_config: ChainConfig, + witness_timeout: bool, + witness_delay: bool, + first_query_time: OnceLock, + } + + async fn mock_el_handler( + State(state): State>, + body: Bytes, + ) -> Json { + let request: serde_json::Value = serde_json::from_slice(&body).unwrap(); + let method = request["method"].as_str().unwrap_or(""); + + let result = match method { + "debug_chainConfig" => serde_json::to_value(&state.chain_config).unwrap(), + "debug_executionWitnessByBlockHash" => { + let hash_str = request["params"][0].as_str().unwrap(); + let hash: B256 = hash_str.parse().unwrap(); + + if state.witness_timeout { + serde_json::Value::Null + } else if state.witness_delay { + let first = state.first_query_time.get_or_init(Instant::now); + if first.elapsed() < Duration::from_secs(3) { + serde_json::Value::Null + } else { + state + .witnesses + .get(&hash) + .map(|w| serde_json::to_value(w).unwrap()) + .unwrap_or(serde_json::Value::Null) + } + } else { + state + .witnesses + .get(&hash) + .map(|w| serde_json::to_value(w).unwrap()) + .unwrap_or(serde_json::Value::Null) + } + } + _ => serde_json::Value::Null, + }; + + Json(serde_json::json!({ + "jsonrpc": "2.0", + "result": result, + "id": request["id"], + })) + } + + let block_hash = fixture.new_payload_request.block_hash(); + let witnesses = HashMap::from([(B256::from(block_hash.0), fixture.witness.clone())]); + + let state = Arc::new(MockElState { + witnesses, + chain_config: fixture.chain_config.clone(), + witness_timeout, + witness_delay, + first_query_time: OnceLock::new(), + }); + let app = axum::Router::new() + .route("/", axum::routing::post(mock_el_handler)) + .with_state(state); + + let listener = TcpListener::bind((Ipv4Addr::LOCALHOST, 0)).await.unwrap(); + let port = listener.local_addr().unwrap().port(); + tokio::spawn(async move { axum::serve(listener, app).await }); + + format!("http://127.0.0.1:{port}").parse().unwrap() +} + +async fn start_zkboost_server( + el_endpoint: url::Url, + zkvm_configs: Vec, + witness_timeout_secs: u64, + proof_timeout_secs: u64, +) -> (url::Url, tokio_util::sync::CancellationToken) { + let config = Config { + port: 0, + el_endpoint, + chain_config_path: None, + witness_timeout_secs, + proof_timeout_secs, + proof_cache_size: 128, + witness_cache_size: 128, + zkvm: zkvm_configs, + }; + let metrics = PrometheusBuilder::new().build_recorder().handle(); + let shutdown = tokio_util::sync::CancellationToken::new(); + let server = zkBoostServer::new(config, metrics).await.unwrap(); + let (addr, _) = server.run(shutdown.clone()).await.unwrap(); + let zkboost_endpoint = format!("http://127.0.0.1:{}", addr.port()).parse().unwrap(); + (zkboost_endpoint, shutdown) +} + +#[derive(Default)] +struct Behavior { + witness_delay: bool, + witness_timeout: bool, + proof_timeout: bool, + proof_failure: bool, +} + +struct TestHarness { + fixture: Fixture, + client: zkBoostClient, + proof_type: ProofType, + shutdown: tokio_util::sync::CancellationToken, +} + +impl TestHarness { + async fn new(behavior: Behavior) -> Self { + let fixture = Fixture::load(); + let el_endpoint = + start_mock_el(&fixture, behavior.witness_timeout, behavior.witness_delay).await; + let proof_type = ProofType::EthrexZisk; + let zkvm_config = zkVMConfig::Mock { + proof_type, + mock_proving_time_ms: 3000, + mock_proof_size: 1024, + mock_failure: behavior.proof_failure, + }; + let witness_timeout_secs = if behavior.witness_timeout { 1 } else { 120 }; + let proof_timeout_secs = if behavior.proof_timeout { 1 } else { 120 }; + let (zkboost_endpoint, shutdown) = start_zkboost_server( + el_endpoint, + vec![zkvm_config], + witness_timeout_secs, + proof_timeout_secs, + ) + .await; + let client = zkBoostClient::new(zkboost_endpoint); + Self { + client, + fixture, + proof_type, + shutdown, + } + } + + async fn request_proof(&self) { + let new_payload_request_root = self + .client + .request_proof(&self.fixture.new_payload_request, &[self.proof_type]) + .await + .unwrap() + .new_payload_request_root; + + assert_eq!( + new_payload_request_root, + self.fixture.new_payload_request_root + ); + } + + async fn wait_for_event(&self) -> ProofEvent { + let mut stream = Box::pin( + self.client + .subscribe_proof_events(Some(self.fixture.new_payload_request_root)), + ); + let proof_event = tokio::time::timeout(Duration::from_secs(30), async { + stream.next().await.unwrap().unwrap() + }) + .await + .unwrap(); + + assert_eq!( + proof_event.new_payload_request_root(), + self.fixture.new_payload_request_root + ); + + proof_event + } + + async fn assert_proof_event(&self, proof_event_kind: ProofEventKind) { + let proof_event = self.wait_for_event().await; + + assert_eq!(proof_event.kind(), proof_event_kind); + assert_eq!(proof_event.proof_type(), self.proof_type); + assert_eq!( + proof_event.new_payload_request_root(), + self.fixture.new_payload_request_root + ); + } + + async fn assert_get_proof_is_valid(&self) { + let proof = self + .client + .get_proof(self.fixture.new_payload_request_root, self.proof_type) + .await + .unwrap(); + + let verification = self + .client + .verify_proof( + self.fixture.new_payload_request_root, + self.proof_type, + &proof, + ) + .await + .unwrap(); + + assert_eq!(verification.status, ProofStatus::Valid); + } + + async fn assert_get_proof_not_found(&self) { + assert!(matches!( + self.client + .get_proof(self.fixture.new_payload_request_root, self.proof_type) + .await, + Err(zkboost_client::Error::NotFound(_)) + )); + } +} + +impl Drop for TestHarness { + fn drop(&mut self) { + self.shutdown.cancel(); + } +} + +#[tokio::test] +async fn test_proof_complete() { + let harness = TestHarness::new(Behavior::default()).await; + + harness.request_proof().await; + harness + .assert_proof_event(ProofEventKind::ProofComplete) + .await; + harness.assert_get_proof_is_valid().await; + + harness + .assert_proof_event(ProofEventKind::ProofComplete) + .await; +} + +#[tokio::test] +async fn test_proof_complete_with_witness_delay() { + let behavior = Behavior { + witness_delay: true, + ..Default::default() + }; + let harness = TestHarness::new(behavior).await; + + harness.request_proof().await; + harness + .assert_proof_event(ProofEventKind::ProofComplete) + .await; + harness.assert_get_proof_is_valid().await; +} + +#[tokio::test] +async fn test_proof_failure() { + let behavior = Behavior { + proof_failure: true, + ..Default::default() + }; + let harness = TestHarness::new(behavior).await; + + harness.request_proof().await; + harness + .assert_proof_event(ProofEventKind::ProofFailure) + .await; + harness.assert_get_proof_not_found().await; +} + +#[tokio::test] +async fn test_witness_timeout() { + let behavior = Behavior { + witness_timeout: true, + ..Default::default() + }; + let harness = TestHarness::new(behavior).await; + + harness.request_proof().await; + harness + .assert_proof_event(ProofEventKind::WitnessTimeout) + .await; + harness.assert_get_proof_not_found().await; +} + +#[tokio::test] +async fn test_proof_timeout() { + let behavior = Behavior { + proof_timeout: true, + ..Default::default() + }; + let harness = TestHarness::new(behavior).await; + + harness.request_proof().await; + harness + .assert_proof_event(ProofEventKind::ProofTimeout) + .await; + harness.assert_get_proof_not_found().await; +} diff --git a/crates/types/Cargo.toml b/crates/types/Cargo.toml new file mode 100644 index 0000000..759dd97 --- /dev/null +++ b/crates/types/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "zkboost-types" +version.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true + +[lints] +workspace = true + +[dependencies] +lighthouse_types.workspace = true +serde = { workspace = true, features = ["derive"] } +serde_json.workspace = true +strum = { workspace = true, features = ["derive"] } + +# lighthouse +ssz.workspace = true +ssz_derive.workspace = true +ssz_types.workspace = true +superstruct.workspace = true +tree_hash.workspace = true +tree_hash_derive.workspace = true diff --git a/crates/types/src/lib.rs b/crates/types/src/lib.rs new file mode 100644 index 0000000..6c78561 --- /dev/null +++ b/crates/types/src/lib.rs @@ -0,0 +1,295 @@ +//! Shared request/response types for the zkboost Proof Node API. +//! +//! This crate contains the types used by both the zkboost server and client +//! for REST API communication and SSE event streaming. + +#![warn(unused_crate_dependencies)] + +use std::{ + error::Error, + fmt::{self, Display, Formatter}, +}; + +use serde::{Deserialize, Serialize}; + +mod new_payload_request; +mod proof_type; + +#[rustfmt::skip] +pub use { + lighthouse_types::{Hash256, MainnetEthSpec, Withdrawal}, + ssz::{Decode, Encode}, + tree_hash::TreeHash, + new_payload_request::*, + proof_type::*, +}; + +/// Query params for `POST /v1/execution_proof_requests`. +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] +pub struct ProofRequestQuery { + /// Comma-separated list of proof types to request. + #[serde( + deserialize_with = "comma_separated::deserialize", + serialize_with = "comma_separated::serialize" + )] + pub proof_types: Vec, +} + +/// Response for `POST /v1/execution_proof_requests`. +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] +pub struct ProofRequestResponse { + /// The tree-hash root of the `NewPayloadRequest` used as the identifier. + pub new_payload_request_root: Hash256, +} + +/// Query params for `GET /v1/execution_proof_requests` (SSE). +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] +pub struct ProofEventQuery { + /// Optional filter to get stream events only for this root. + pub new_payload_request_root: Option, +} + +/// Query params for `POST /v1/execution_proof_verifications`. +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] +pub struct ProofVerificationQuery { + /// The root identifying the payload request. + pub new_payload_request_root: Hash256, + /// The proof type to verify. + pub proof_type: ProofType, +} + +/// Response for `POST /v1/execution_proof_verifications`. +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] +pub struct ProofVerificationResponse { + /// The verification result. + pub status: ProofStatus, +} + +/// Verification status returned by the proof verification endpoint. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +pub enum ProofStatus { + /// The proof is valid. + Valid, + /// The proof is invalid. + Invalid, +} + +impl ProofStatus { + /// Returns `true` if proof status is `ProofStatus::Valid`: + pub fn is_valid(&self) -> bool { + *self == Self::Valid + } +} + +/// SSE event types broadcast to HTTP SSE subscribers. +#[derive(Debug, Clone, Eq, PartialEq, strum::EnumDiscriminants)] +#[strum_discriminants(name(ProofEventKind))] +#[strum_discriminants(derive(Hash))] +#[strum_discriminants(doc = "Discriminant enum for [`ProofEvent`] variants.")] +pub enum ProofEvent { + /// A proof completed successfully. + ProofComplete(ProofComplete), + /// A proof failed. + ProofFailure(ProofFailure), + /// Witness fetch timed out. + WitnessTimeout(WitnessTimeout), + /// Proof generation timed out. + ProofTimeout(ProofTimeout), +} + +impl ProofEvent { + /// Returns the discriminant kind for this event. + pub fn kind(&self) -> ProofEventKind { + ProofEventKind::from(self) + } + + /// Returns the `new_payload_request_root` from the event. + pub fn new_payload_request_root(&self) -> Hash256 { + match self { + Self::ProofComplete(inner) => inner.new_payload_request_root, + Self::ProofFailure(inner) => inner.new_payload_request_root, + Self::WitnessTimeout(inner) => inner.new_payload_request_root, + Self::ProofTimeout(inner) => inner.new_payload_request_root, + } + } + + /// Returns the [`ProofType`] from the event. + pub fn proof_type(&self) -> ProofType { + match self { + Self::ProofComplete(inner) => inner.proof_type, + Self::ProofFailure(inner) => inner.proof_type, + Self::WitnessTimeout(inner) => inner.proof_type, + Self::ProofTimeout(inner) => inner.proof_type, + } + } + + /// Returns the canonical SSE event name for this variant. + pub fn event_name(&self) -> &'static str { + match self { + Self::ProofComplete(_) => "proof_complete", + Self::ProofFailure(_) => "proof_failure", + Self::WitnessTimeout(_) => "witness_timeout", + Self::ProofTimeout(_) => "proof_timeout", + } + } + + /// Serializes the inner payload to a JSON string. + pub fn to_parts(&self) -> (&'static str, String) { + let data = match self { + Self::ProofComplete(inner) => serde_json::to_string(inner), + Self::ProofFailure(inner) => serde_json::to_string(inner), + Self::WitnessTimeout(inner) => serde_json::to_string(inner), + Self::ProofTimeout(inner) => serde_json::to_string(inner), + } + .expect("ProofEvent serialization is infallible"); + (self.event_name(), data) + } + + /// Reconstructs a [`ProofEvent`] from an SSE event name and JSON data. + pub fn try_from_parts(name: &str, data: &str) -> Result { + match name { + "proof_complete" => Ok(Self::ProofComplete(serde_json::from_str(data)?)), + "proof_failure" => Ok(Self::ProofFailure(serde_json::from_str(data)?)), + "witness_timeout" => Ok(Self::WitnessTimeout(serde_json::from_str(data)?)), + "proof_timeout" => Ok(Self::ProofTimeout(serde_json::from_str(data)?)), + other => Err(ProofEventParseError::UnknownEvent(other.to_string())), + } + } +} + +impl From for ProofEvent { + fn from(inner: ProofComplete) -> Self { + Self::ProofComplete(inner) + } +} + +impl From for ProofEvent { + fn from(inner: ProofFailure) -> Self { + Self::ProofFailure(inner) + } +} + +impl From for ProofEvent { + fn from(inner: WitnessTimeout) -> Self { + Self::WitnessTimeout(inner) + } +} + +impl From for ProofEvent { + fn from(inner: ProofTimeout) -> Self { + Self::ProofTimeout(inner) + } +} + +/// Error returned when parsing an SSE event into a [`ProofEvent`] fails. +#[derive(Debug)] +pub enum ProofEventParseError { + /// JSON deserialization failed. + Json(serde_json::Error), + /// The event name does not match any known variant. + UnknownEvent(String), +} + +impl Display for ProofEventParseError { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match self { + Self::Json(e) => write!(f, "JSON parse error: {e}"), + Self::UnknownEvent(name) => write!(f, "unknown SSE event type: {name}"), + } + } +} + +impl Error for ProofEventParseError {} + +impl From for ProofEventParseError { + fn from(e: serde_json::Error) -> Self { + Self::Json(e) + } +} + +/// Payload for a successful proof event. +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] +pub struct ProofComplete { + /// Beacon-level identifier for this payload. + pub new_payload_request_root: Hash256, + /// Proof type. + pub proof_type: ProofType, +} + +/// Payload for a failed proof event. +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] +pub struct ProofFailure { + /// Beacon-level identifier for this payload. + pub new_payload_request_root: Hash256, + /// Proof type. + pub proof_type: ProofType, + /// Error message. + pub error: String, +} + +/// Payload for a witness timeout event. +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] +pub struct WitnessTimeout { + /// Beacon-level identifier for this payload. + pub new_payload_request_root: Hash256, + /// Proof type. + pub proof_type: ProofType, +} + +/// Payload for a proof generation timeout event. +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] +pub struct ProofTimeout { + /// Beacon-level identifier for this payload. + pub new_payload_request_root: Hash256, + /// Proof type. + pub proof_type: ProofType, +} + +/// Custom serde for comma-separated `Vec` in query strings. +mod comma_separated { + use serde::{Deserialize, Deserializer, Serializer}; + + use crate::ProofType; + + pub(crate) fn serialize(proof_types: &[ProofType], serializer: S) -> Result + where + S: Serializer, + { + let s: String = proof_types + .iter() + .map(|proof_type| proof_type.as_str()) + .collect::>() + .join(","); + serializer.serialize_str(&s) + } + + pub(crate) fn deserialize<'de, D>(deserializer: D) -> Result, D::Error> + where + D: Deserializer<'de>, + { + let value = String::deserialize(deserializer)?; + if value.is_empty() { + return Ok(Vec::new()); + } + value + .split(',') + .map(|part| { + part.trim() + .parse::() + .map_err(serde::de::Error::custom) + }) + .collect() + } +} + +#[cfg(test)] +mod tests { + use crate::ProofRequestQuery; + + #[test] + fn test_empty_proof_types_deserializes_to_empty_vec() { + let query: ProofRequestQuery = serde_json::from_str(r#"{"proof_types": ""}"#).unwrap(); + assert!(query.proof_types.is_empty()); + } +} diff --git a/crates/types/src/new_payload_request.rs b/crates/types/src/new_payload_request.rs new file mode 100644 index 0000000..d5fed4d --- /dev/null +++ b/crates/types/src/new_payload_request.rs @@ -0,0 +1,72 @@ +//! `NewPayloadRequest` with SSZ `Encode/Decode` and `TreeHash` derived. +//! +//! Copied from [`execution_layer::NewPayloadRequest`]. +//! +//! [`execution_layer::NewPayloadRequest`]: https://github.com/sigp/lighthouse/blob/unstable/beacon_node/execution_layer/src/engine_api/new_payload_request.rs + +#![allow(missing_docs)] + +use lighthouse_types::{ + BeaconStateError, EthSpec, ExecutionPayloadBellatrix, ExecutionPayloadCapella, + ExecutionPayloadDeneb, ExecutionPayloadElectra, ExecutionPayloadFulu, ExecutionRequests, + Hash256, VersionedHash, +}; +use ssz_derive::{Decode, Encode}; +use ssz_types::VariableList; +use superstruct::superstruct; +use tree_hash_derive::TreeHash; + +#[superstruct( + variants(Bellatrix, Capella, Deneb, Electra, Fulu, Gloas), + variant_attributes(derive(Clone, Debug, PartialEq, Encode, Decode, TreeHash)), + map_into(ExecutionPayload), + map_ref_into(ExecutionPayloadRef), + cast_error( + ty = "BeaconStateError", + expr = "BeaconStateError::IncorrectStateVariant" + ), + partial_getter_error( + ty = "BeaconStateError", + expr = "BeaconStateError::IncorrectStateVariant" + ) +)] +#[derive(Clone, Debug, PartialEq, Encode, Decode, TreeHash)] +#[ssz(enum_behaviour = "transparent")] +#[tree_hash(enum_behaviour = "transparent")] +pub struct NewPayloadRequest { + #[superstruct( + only(Bellatrix), + partial_getter(rename = "execution_payload_bellatrix") + )] + pub execution_payload: ExecutionPayloadBellatrix, + #[superstruct(only(Capella), partial_getter(rename = "execution_payload_capella"))] + pub execution_payload: ExecutionPayloadCapella, + #[superstruct(only(Deneb), partial_getter(rename = "execution_payload_deneb"))] + pub execution_payload: ExecutionPayloadDeneb, + #[superstruct(only(Electra), partial_getter(rename = "execution_payload_electra"))] + pub execution_payload: ExecutionPayloadElectra, + #[superstruct(only(Fulu), partial_getter(rename = "execution_payload_fulu"))] + pub execution_payload: ExecutionPayloadFulu, + #[superstruct(only(Gloas), partial_getter(rename = "execution_payload_gloas"))] + pub execution_payload: lighthouse_types::ExecutionPayloadGloas, + #[superstruct(only(Deneb, Electra, Fulu, Gloas))] + pub versioned_hashes: VariableList, + #[superstruct(only(Deneb, Electra, Fulu, Gloas))] + pub parent_beacon_block_root: Hash256, + #[superstruct(only(Electra, Fulu, Gloas))] + pub execution_requests: ExecutionRequests, +} + +impl NewPayloadRequest { + /// Returns the block hash from the execution payload. + pub fn block_hash(&self) -> Hash256 { + match self { + Self::Bellatrix(inner) => inner.execution_payload.block_hash.0, + Self::Capella(inner) => inner.execution_payload.block_hash.0, + Self::Deneb(inner) => inner.execution_payload.block_hash.0, + Self::Electra(inner) => inner.execution_payload.block_hash.0, + Self::Fulu(inner) => inner.execution_payload.block_hash.0, + Self::Gloas(inner) => inner.execution_payload.block_hash.0, + } + } +} diff --git a/crates/types/src/proof_type.rs b/crates/types/src/proof_type.rs new file mode 100644 index 0000000..4a37326 --- /dev/null +++ b/crates/types/src/proof_type.rs @@ -0,0 +1,129 @@ +//! Execution layer proof type. + +use std::{ + error::Error, + fmt::{self, Display, Formatter}, + str::FromStr, +}; + +use serde::{Deserialize, Serialize}; +use strum::IntoEnumIterator; + +/// Execution layer proof type. +#[derive( + Clone, + Copy, + Debug, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Serialize, + Deserialize, + strum::EnumIter, +)] +#[serde(into = "String", try_from = "String")] +pub enum ProofType { + /// Ethrex with RISC Zero backend. + EthrexRisc0, + /// Ethrex with SP1 backend. + EthrexSP1, + /// Ethrex with Zisk backend. + EthrexZisk, + /// Reth with OpenVM backend. + RethOpenVM, + /// Reth with RISC Zero backend. + RethRisc0, + /// Reth with SP1 backend. + RethSP1, + /// Reth with Zisk backend. + RethZisk, +} + +/// Execution layer kind to use for stateless validation. +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum ElKind { + /// Reth + Reth, + /// Ethrex + Ethrex, +} + +impl ProofType { + /// Returns the execution layer kind for this proof type. + pub fn el_kind(&self) -> ElKind { + match self { + Self::EthrexRisc0 | Self::EthrexSP1 | Self::EthrexZisk => ElKind::Ethrex, + Self::RethOpenVM | Self::RethRisc0 | Self::RethSP1 | Self::RethZisk => ElKind::Reth, + } + } + + /// Returns the canonical string representation. + pub fn as_str(&self) -> &'static str { + match self { + Self::EthrexRisc0 => "ethrex-risc0", + Self::EthrexSP1 => "ethrex-sp1", + Self::EthrexZisk => "ethrex-zisk", + Self::RethOpenVM => "reth-openvm", + Self::RethRisc0 => "reth-risc0", + Self::RethSP1 => "reth-sp1", + Self::RethZisk => "reth-zisk", + } + } +} + +impl From for String { + fn from(value: ProofType) -> Self { + value.as_str().to_string() + } +} + +impl FromStr for ProofType { + type Err = ProofTypeParseError; + + fn from_str(s: &str) -> Result { + Ok(match s { + "ethrex-risc0" => Self::EthrexRisc0, + "ethrex-sp1" => Self::EthrexSP1, + "ethrex-zisk" => Self::EthrexZisk, + "reth-openvm" => Self::RethOpenVM, + "reth-risc0" => Self::RethRisc0, + "reth-sp1" => Self::RethSP1, + "reth-zisk" => Self::RethZisk, + _ => return Err(ProofTypeParseError(s.to_string())), + }) + } +} + +impl TryFrom for ProofType { + type Error = ProofTypeParseError; + + fn try_from(s: String) -> Result { + s.parse() + } +} + +impl Display for ProofType { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.as_str()) + } +} + +/// Parse error for invalid proof type values. +#[derive(Debug, Clone, Eq, PartialEq)] +pub struct ProofTypeParseError(String); + +impl Display for ProofTypeParseError { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + let unsupported = &self.0; + let supported = + Vec::from_iter(ProofType::iter().map(|proof_type| proof_type.as_str())).join(", "); + write!( + f, + "Unsupported proof type `{unsupported}`, expect one of [{supported}]", + ) + } +} + +impl Error for ProofTypeParseError {} diff --git a/crates/zkboost-ethereum/el-config/Cargo.toml b/crates/zkboost-ethereum/el-config/Cargo.toml deleted file mode 100644 index be3a21b..0000000 --- a/crates/zkboost-ethereum/el-config/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[package] -name = "zkboost-ethereum-el-config" -version.workspace = true -edition.workspace = true -rust-version.workspace = true - -[lints] -workspace = true - -[dependencies] -anyhow.workspace = true -clap = { workspace = true, features = ["derive", "env"] } -reqwest = { workspace = true, features = ["json"] } -serde = { workspace = true, features = ["derive"] } -tokio = { workspace = true, features = ["full"] } -tracing.workspace = true -tracing-subscriber = { workspace = true, features = ["env-filter"] } - -ere-common.workspace = true -ere-zkvm-interface.workspace = true - -zkboost-ethereum-el-types.workspace = true -zkboost-server-config.workspace = true diff --git a/crates/zkboost-ethereum/el-config/src/lib.rs b/crates/zkboost-ethereum/el-config/src/lib.rs deleted file mode 100644 index d2e6150..0000000 --- a/crates/zkboost-ethereum/el-config/src/lib.rs +++ /dev/null @@ -1,8 +0,0 @@ -//! Configuration file generation for zkboost-server Ethereum Execution Layer -//! support. -//! -//! This crate provides utilities to generate configuration files for -//! zkboost-server, enabling it to serve Ethereum Execution Layer (EL) -//! stateless validator guest programs. - -pub mod program; diff --git a/crates/zkboost-ethereum/el-config/src/main.rs b/crates/zkboost-ethereum/el-config/src/main.rs deleted file mode 100644 index 19d22dc..0000000 --- a/crates/zkboost-ethereum/el-config/src/main.rs +++ /dev/null @@ -1,75 +0,0 @@ -//! Configuration file generator for zkboost-server Ethereum Execution Layer -//! stateless validator. -//! -//! This binary generates configuration files that enable zkboost-server to -//! serve Ethereum Execution Layer stateless validator guest programs. - -use std::path::PathBuf; - -use clap::Parser; -use ere_common::zkVMKind; -use ere_zkvm_interface::ProverResource; -use tokio::fs; -use zkboost_ethereum_el_config::program::download_program; -use zkboost_ethereum_el_types::ElKind; -use zkboost_server_config::{Config, zkVMConfig}; - -#[derive(Parser)] -struct Args { - /// Execution layer client implementation (reth or ethrex) - #[arg(long)] - el: ElKind, - /// zkVM to use - #[arg(long)] - zkvm: zkVMKind, - /// Resource type for proving (cpu or gpu) - #[arg(long, ignore_case = true, default_value = "cpu", value_parser = ["cpu", "gpu"])] - resource: String, - /// Output path to save the `config.toml` and the program. - #[arg(long)] - output_dir: PathBuf, - /// Download the artifact even if a release url is available - #[arg(long)] - download_guest: bool, - /// GitHub token for downloading artifacts from GitHub Actions. - /// Required when `ere-guests` dependency uses a git revision instead of a released tag. - #[arg(env = "GITHUB_TOKEN")] - github_token: Option, -} - -#[tokio::main] -async fn main() -> anyhow::Result<()> { - tracing_subscriber::fmt() - .with_env_filter(tracing_subscriber::EnvFilter::from_default_env()) - .init(); - - let args = Args::parse(); - - let program = download_program( - args.el, - args.zkvm, - args.github_token.as_deref(), - &args.output_dir, - args.download_guest, - ) - .await?; - - let config = Config { - port: 3001, - webhook_url: "http://localhost:3003/proofs".to_string(), - zkvm: vec![zkVMConfig::Docker { - kind: args.zkvm, - resource: match args.resource.to_lowercase().as_str() { - "cpu" => ProverResource::Cpu, - "gpu" => ProverResource::Gpu, - _ => unreachable!(), - }, - program_id: format!("{}-{}", args.el, args.zkvm).into(), - program, - }], - }; - - fs::write(args.output_dir.join("config.toml"), config.to_toml()?).await?; - - Ok(()) -} diff --git a/crates/zkboost-ethereum/el-config/src/program.rs b/crates/zkboost-ethereum/el-config/src/program.rs deleted file mode 100644 index 03cb210..0000000 --- a/crates/zkboost-ethereum/el-config/src/program.rs +++ /dev/null @@ -1,233 +0,0 @@ -//! Program download utilities for zkVM execution layer binaries. - -use std::{path::Path, str::FromStr}; - -use anyhow::{anyhow, bail}; -use ere_common::zkVMKind; -use reqwest::{ - Client, ClientBuilder, - header::{HeaderName, HeaderValue}, -}; -use serde::Deserialize; -use tokio::{fs, process::Command}; -use tracing::info; -use zkboost_ethereum_el_types::{ERE_GUESTS_REPO, ERE_GUESTS_VERSION, ElKind, PackageVersion}; -use zkboost_server_config::{ProgramConfig, UrlConfig}; - -const ACTION_NAME: &str = "Compile and Release Compiled Guests"; - -/// Downloads the compiled zkVM program for a specific EL and zkVM combination. -/// -/// Programs are retrieved from GitHub, either from release artifacts (for -/// tagged versions) or GitHub Actions artifacts (for git revisions). -/// -/// When downloading from Actions artifacts, a GitHub token is required via the -/// `github_token` parameter. -pub async fn download_program( - el: ElKind, - zkvm: zkVMKind, - github_token: Option<&str>, - output_dir: impl AsRef, - download_guest: bool, -) -> anyhow::Result { - let artifact_name = format!("stateless-validator-{el}-{zkvm}"); - download_guest_program( - &artifact_name, - ERE_GUESTS_VERSION, - github_token, - output_dir, - download_guest, - ) - .await -} - -/// Downloads the compiled guest program. -/// -/// Programs are retrieved from GitHub, either from release artifacts (for -/// tagged versions) or GitHub Actions artifacts (for git revisions). -/// -/// When downloading from Actions artifacts, a GitHub token is required via the -/// `github_token` parameter. -pub async fn download_guest_program( - artifact_name: &str, - package_version: PackageVersion, - github_token: Option<&str>, - output_dir: impl AsRef, - download_guest: bool, -) -> anyhow::Result { - let output_dir = output_dir.as_ref(); - fs::create_dir_all(output_dir).await?; - - let artifact_path = output_dir.join(artifact_name); - - match package_version { - // Download from GitHub releases (no authentication needed) - PackageVersion::Tag(tag) => { - if download_guest { - download_release_artifact(tag, artifact_name, &artifact_path).await?; - } else { - return Ok(ProgramConfig::Url(UrlConfig { - url: release_artifact_url(tag, artifact_name), - })); - } - } - // Download from GitHub Actions artifacts (requires `GITHUB_TOKEN`) - PackageVersion::Rev(rev) => { - let github_token = github_token.ok_or_else(|| { - anyhow!( - "`GITHUB_TOKEN` is required when `ere-guests`\ - dependency uses a git revision instead of a released tag.\ - Set it via `GITHUB_TOKEN` environment variable." - ) - })?; - let gh_client = gh_client(github_token)?; - - let action_id = get_release_action_id(&gh_client, rev).await?; - let artifact_url = get_artifact_url(&gh_client, artifact_name, action_id).await?; - download_action_artifact(&gh_client, artifact_name, &artifact_url, &artifact_path) - .await?; - } - } - - Ok(ProgramConfig::Path(artifact_path)) -} - -fn gh_client(github_token: &str) -> anyhow::Result { - Ok(ClientBuilder::new() - .default_headers( - [ - ("Authorization", format!("Bearer {github_token}").as_str()), - ("Accept", "application/vnd.github+json"), - ("X-GitHub-Api-Version", "2022-11-28"), - ("User-Agent", "zkboost-server"), - ] - .into_iter() - .map(|(name, value)| { - ( - HeaderName::from_str(name).unwrap(), - HeaderValue::from_str(value).unwrap(), - ) - }) - .collect(), - ) - .build()?) -} - -async fn get_release_action_id(gh_client: &Client, rev: &str) -> anyhow::Result { - info!("Getting release action id of workload repo at {rev}..."); - - #[derive(Deserialize)] - struct WorkflowRunsResponse { - workflow_runs: Vec, - } - - #[derive(Deserialize)] - struct WorkflowRun { - id: u64, - name: String, - status: String, - conclusion: Option, - } - - let url = format!("https://api.github.com/repos/{ERE_GUESTS_REPO}/actions/runs?head_sha={rev}"); - let res: WorkflowRunsResponse = gh_client.get(&url).send().await?.json().await?; - res.workflow_runs - .into_iter() - .filter(|run| { - run.name == ACTION_NAME - && run.status == "completed" - && run.conclusion.as_deref() == Some("success") - }) - .max_by_key(|run| run.id) - .map(|run| run.id) - .ok_or_else(|| anyhow!("No successful '{ACTION_NAME}' workflow run found for commit {rev}")) -} - -async fn get_artifact_url( - gh_client: &Client, - artifact_name: &str, - action_id: u64, -) -> anyhow::Result { - info!("Getting artifact url of artifact {artifact_name} of action id {action_id}..."); - - #[derive(Deserialize)] - struct ArtifactsResponse { - artifacts: Vec, - } - - #[derive(Deserialize)] - struct Artifact { - name: String, - archive_download_url: String, - } - - let url = format!( - "https://api.github.com/repos/{ERE_GUESTS_REPO}/actions/runs/{action_id}/artifacts" - ); - let res: ArtifactsResponse = gh_client.get(&url).send().await?.json().await?; - res.artifacts - .into_iter() - .find_map(|artifact| { - (artifact.name == artifact_name).then_some(artifact.archive_download_url) - }) - .ok_or_else(|| anyhow!("Artifact '{artifact_name}' not found in action run {action_id}")) -} - -async fn download_action_artifact( - gh_client: &Client, - artifact_name: &str, - artifact_url: &str, - artifact_path: &Path, -) -> anyhow::Result<()> { - info!( - "Downloading artifact {artifact_name} from {artifact_url} into {}...", - artifact_path.display(), - ); - - let artifact_zip_path = artifact_path.with_extension("zip"); - let res = gh_client.get(artifact_url).send().await?; - fs::write(&artifact_zip_path, res.bytes().await?).await?; - - let status = Command::new("unzip") - .arg("-o") - .arg(artifact_zip_path.canonicalize()?) - .current_dir(artifact_path.parent().unwrap().canonicalize()?) - .status() - .await?; - if !status.success() { - bail!("Failed to unzip artifact"); - } - - if !fs::try_exists(artifact_path).await? { - bail!( - "Artifact file not found at '{}' after unzipping", - artifact_path.display(), - ); - } - - fs::remove_file(&artifact_zip_path).await?; - - Ok(()) -} - -fn release_artifact_url(tag: &str, artifact_name: &str) -> String { - format!("https://github.com/{ERE_GUESTS_REPO}/releases/download/{tag}/{artifact_name}") -} - -async fn download_release_artifact( - tag: &str, - artifact_name: &str, - artifact_path: &Path, -) -> anyhow::Result<()> { - let artifact_url = release_artifact_url(tag, artifact_name); - - info!( - "Downloading artifact {artifact_name} from {artifact_url} into {}...", - artifact_path.display(), - ); - - let res = reqwest::get(artifact_url).await?; - fs::write(artifact_path, res.bytes().await?).await?; - - Ok(()) -} diff --git a/crates/zkboost-ethereum/el-input/Cargo.toml b/crates/zkboost-ethereum/el-input/Cargo.toml deleted file mode 100644 index 0635c9d..0000000 --- a/crates/zkboost-ethereum/el-input/Cargo.toml +++ /dev/null @@ -1,25 +0,0 @@ -[package] -name = "zkboost-ethereum-el-input" -version.workspace = true -edition.workspace = true -rust-version.workspace = true - -[lints] -workspace = true - -[dependencies] -anyhow.workspace = true -sha2.workspace = true - -# reth -reth-stateless.workspace = true - -# ere -ere-zkvm-interface.workspace = true - -# ere-guests -stateless-validator-ethrex.workspace = true -stateless-validator-reth.workspace = true - -# local -zkboost-ethereum-el-types.workspace = true diff --git a/crates/zkboost-ethereum/el-input/src/lib.rs b/crates/zkboost-ethereum/el-input/src/lib.rs deleted file mode 100644 index a2932db..0000000 --- a/crates/zkboost-ethereum/el-input/src/lib.rs +++ /dev/null @@ -1,79 +0,0 @@ -//! zkVM input generation for Ethereum Execution Layer stateless validation. - -#![cfg_attr(not(test), warn(unused_crate_dependencies))] - -use ere_zkvm_interface::Input; -use sha2::{Digest, Sha256}; -use stateless_validator_ethrex::guest::{ - Io, StatelessValidatorEthrexInput, StatelessValidatorEthrexIo, -}; -use stateless_validator_reth::guest::{ - StatelessValidatorOutput, StatelessValidatorRethInput, StatelessValidatorRethIo, -}; -use zkboost_ethereum_el_types::ElKind; - -#[rustfmt::skip] -pub use reth_stateless::StatelessInput; - -/// Necessary input for EL guest programs -#[derive(Debug)] -pub struct ElInput { - stateless_input: StatelessInput, -} - -impl ElInput { - /// Constructs a new `ElInput` - pub fn new(stateless_input: StatelessInput) -> Self { - Self { stateless_input } - } - - /// Generates zkVM input for given EL from stateless input. - /// - /// # Arguments - /// - /// * `el` - The execution layer kind (Reth or Ethrex) - /// * `valid_block` - Whether this is expected to be a valid block - /// - /// # Returns - /// - /// [`Input`] for the zkVM methods of the specified EL guest program. - pub fn to_zkvm_input(&self, el: ElKind, valid_block: bool) -> anyhow::Result { - let stdin = match el { - ElKind::Ethrex => StatelessValidatorEthrexIo::serialize_input( - &StatelessValidatorEthrexInput::new(&self.stateless_input, valid_block)?, - )?, - ElKind::Reth => StatelessValidatorRethIo::serialize_input( - &StatelessValidatorRethInput::new(&self.stateless_input, valid_block)?, - )?, - }; - Ok(Input::new().with_prefixed_stdin(stdin)) - } - - /// Returns expected sha256 hash of output given the EL and whether the - /// stateless validation is successful or not. - pub fn expected_public_values( - &self, - el: ElKind, - valid_block: bool, - ) -> anyhow::Result<[u8; 32]> { - let new_payload_request = match el { - ElKind::Ethrex => { - StatelessValidatorEthrexInput::new(&self.stateless_input, valid_block)? - .new_payload_request - } - ElKind::Reth => { - StatelessValidatorRethInput::new(&self.stateless_input, valid_block)? - .new_payload_request - } - }; - let output = StatelessValidatorOutput { - new_payload_request_root: new_payload_request.tree_hash_root(), - successful_block_validation: valid_block, - }; - let serialized_output = match el { - ElKind::Ethrex => StatelessValidatorEthrexIo::serialize_output(&output)?, - ElKind::Reth => StatelessValidatorRethIo::serialize_output(&output)?, - }; - Ok(Sha256::digest(serialized_output).into()) - } -} diff --git a/crates/zkboost-ethereum/el-relayer/Cargo.toml b/crates/zkboost-ethereum/el-relayer/Cargo.toml deleted file mode 100644 index 68fabf4..0000000 --- a/crates/zkboost-ethereum/el-relayer/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "zkboost-ethereum-el-relayer" -version.workspace = true -edition.workspace = true -rust-version.workspace = true -description = "Ethereum relayer bridging Consensus Layer and Execution Layer for zkboost proof generation" -keywords = ["ethereum", "zkboost", "relayer", "consensus-layer", "execution-layer"] -categories = ["cryptography::cryptocurrencies", "network-programming"] - -[lints] -workspace = true - -[dependencies] diff --git a/crates/zkboost-ethereum/el-relayer/src/main.rs b/crates/zkboost-ethereum/el-relayer/src/main.rs deleted file mode 100644 index 2a12315..0000000 --- a/crates/zkboost-ethereum/el-relayer/src/main.rs +++ /dev/null @@ -1,33 +0,0 @@ -//! Ethereum Execution Layer relayer for zkboost proof generation. -//! -//! This relayer orchestrates the complete workflow for generating proofs of -//! EL stateless validation: -//! -//! 1. Listen to new block from EL -//! 2. Fetch execution witness from EL -//! 3. Generate input for EL stateless validator guest program -//! 4. Request zkboost-server for proof -//! 5. Send proof back to CL -//! -//! ## Architecture -//! -//! ```text -//! CL Relayer EL zkboost-server -//! | | | | -//! | |<----new block----| | -//! | | | | -//! | |--fetch witness-->| | -//! | |<----witness------| | -//! | | | | -//! | (generate zkVM input) | | -//! | | | | -//! | |--request proof--------------------->| -//! | |<------proof-------------------------| -//! | | | | -//! |<----proof----| | | -//! | | | | -//! ``` - -#![cfg_attr(not(test), warn(unused_crate_dependencies))] - -fn main() {} diff --git a/crates/zkboost-ethereum/el-types/Cargo.toml b/crates/zkboost-ethereum/el-types/Cargo.toml deleted file mode 100644 index 42ce9f2..0000000 --- a/crates/zkboost-ethereum/el-types/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -name = "zkboost-ethereum-el-types" -version.workspace = true -edition.workspace = true -rust-version.workspace = true - -[lints] -workspace = true - -[dependencies] -serde = { workspace = true, features = ["derive"] } -strum = { workspace = true, features = ["derive"] } -ere-common.workspace = true - -[build-dependencies] -cargo_metadata.workspace = true diff --git a/crates/zkboost-ethereum/el-types/build.rs b/crates/zkboost-ethereum/el-types/build.rs deleted file mode 100644 index 0739dc3..0000000 --- a/crates/zkboost-ethereum/el-types/build.rs +++ /dev/null @@ -1,76 +0,0 @@ -//! Build script that generates `ere-guests` repository and version information. - -use std::{ - env, fs, - path::{Path, PathBuf}, -}; - -fn main() { - generate_ere_guests_info(); - - if let Some(cargo_lock_path) = cargo_lock_path() { - println!("cargo:rerun-if-changed={}", cargo_lock_path.display()); - } -} - -fn generate_ere_guests_info() { - let metadata = cargo_metadata::MetadataCommand::new().exec().unwrap(); - - let url = metadata.packages.iter().find_map(|pkg| { - let url = &pkg.source.as_ref()?.repr; - url.contains("ere-guests").then_some(url) - }); - - // Repo in format of `{org}/{repo}` e.g. `eth-act/ere-guests`. - let repo = url - .and_then(|url| { - let repo = url.strip_prefix("git+https://github.com/")?; - let (repo, _) = repo.split_once('?')?; - Some(format!(r#""{repo}""#)) - }) - .unwrap_or_else(|| panic!("Failed to parse repo from `{url:?}`")); - - let version = url - .and_then(|url| { - let (_, query) = url.split_once('?')?; - - if let Some(query) = query.strip_prefix("tag=") { - let (tag, _) = query.split_once('#')?; - Some(format!(r#"PackageVersion::Tag("{tag}")"#)) - } else { - let (_, rev) = query.split_once('#')?; - Some(format!(r#"PackageVersion::Rev("{rev}")"#)) - } - }) - .unwrap_or_else(|| panic!("Failed to parse version from `{url:?}`")); - - let path = Path::new(&env::var("OUT_DIR").unwrap()).join("workload_info.rs"); - let content = format!( - r#"/// Ere guests repo in format of `{{org}}/{{repo}}` e.g. `eth-act/ere-guests`. -pub const ERE_GUESTS_REPO: &str = {repo}; -/// Ere guests version in tag or revision. -pub const ERE_GUESTS_VERSION: PackageVersion = {version};"# - ); - fs::write(path, content).unwrap(); -} - -/// Returns path to the closest workspace that contains `Cargo.lock` from `CARGO_MANIFEST_DIR`, -/// returns `None` if not found. -pub fn workspace() -> Option { - let mut dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()) - .canonicalize() - .ok()?; - loop { - if dir.join("Cargo.lock").exists() { - return Some(dir); - } - if !dir.pop() { - return None; - } - } -} - -/// Returns path to the closest `Cargo.lock` from `CARGO_MANIFEST_DIR`, returns `None` if not found. -pub fn cargo_lock_path() -> Option { - workspace().map(|workspace| workspace.join("Cargo.lock")) -} diff --git a/crates/zkboost-ethereum/el-types/src/el_kind.rs b/crates/zkboost-ethereum/el-types/src/el_kind.rs deleted file mode 100644 index 52a0d5f..0000000 --- a/crates/zkboost-ethereum/el-types/src/el_kind.rs +++ /dev/null @@ -1,82 +0,0 @@ -//! Ethereum Execution Layer kinds. - -use std::{ - error::Error, - fmt::{self, Display, Formatter}, -}; - -use serde::{Deserialize, Serialize}; -use strum::{Display, EnumIter, EnumString, IntoEnumIterator, IntoStaticStr}; - -/// Execution layer kind to use to do stateless validation. -#[derive( - Clone, - Copy, - Debug, - PartialEq, - Eq, - Hash, - Serialize, - Deserialize, - EnumIter, - EnumString, - IntoStaticStr, - Display, -)] -#[serde(into = "String", try_from = "String")] -#[strum( - ascii_case_insensitive, - serialize_all = "lowercase", - parse_err_fn = ParseError::from, - parse_err_ty = ParseError -)] -pub enum ElKind { - /// Reth - Reth, - /// Ethrex - Ethrex, -} - -impl ElKind { - /// Returns string representation of the execution layer kind. - pub fn as_str(&self) -> &'static str { - self.into() - } -} - -impl From for String { - fn from(value: ElKind) -> Self { - value.as_str().to_string() - } -} - -impl TryFrom for ElKind { - type Error = ParseError; - - fn try_from(s: String) -> Result { - s.parse() - } -} - -/// Parse error for invalid execution layer kind strings. -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct ParseError(String); - -impl From<&str> for ParseError { - fn from(s: &str) -> Self { - Self(s.to_string()) - } -} - -impl Display for ParseError { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - let unsupported = &self.0; - let supported = Vec::from_iter(ElKind::iter().map(|k| k.as_str())).join(", "); - write!( - f, - "Unsupported compiler kind `{unsupported}`, expect one of [{supported}]", - ) - } -} - -impl Error for ParseError {} diff --git a/crates/zkboost-ethereum/el-types/src/el_proof_type.rs b/crates/zkboost-ethereum/el-types/src/el_proof_type.rs deleted file mode 100644 index 7d8a68c..0000000 --- a/crates/zkboost-ethereum/el-types/src/el_proof_type.rs +++ /dev/null @@ -1,143 +0,0 @@ -//! Ethereum Execution Layer proof type. - -use std::{ - error::Error, - fmt::{self, Display, Formatter}, - str::FromStr, -}; - -use ere_common::zkVMKind; -use serde::{Deserialize, Serialize}; -use strum::{EnumIter, IntoEnumIterator}; - -use crate::ElKind; - -/// Execution Layer proof type. -#[derive( - Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize, EnumIter, -)] -#[serde(into = "String", try_from = "String")] -#[repr(u8)] -pub enum ElProofType { - /// EthrexRisc0 - EthrexRisc0, - /// EthrexSP1 - EthrexSP1, - /// EthrexZisk - EthrexZisk, - /// RethOpenVM - RethOpenVM, - /// RethPico - RethPico, - /// RethRisc0 - RethRisc0, - /// RethSP1 - RethSP1, - /// RethZisk - RethZisk, -} - -impl ElProofType { - /// Returns `ElKind`. - pub fn el(&self) -> ElKind { - match self { - Self::EthrexRisc0 | Self::EthrexSP1 | Self::EthrexZisk => ElKind::Ethrex, - Self::RethOpenVM - | Self::RethPico - | Self::RethRisc0 - | Self::RethSP1 - | Self::RethZisk => ElKind::Reth, - } - } - - /// Returns `zkVMKind`. - pub fn zkvm(&self) -> zkVMKind { - match self { - Self::EthrexRisc0 | Self::RethRisc0 => zkVMKind::Risc0, - Self::EthrexSP1 | Self::RethSP1 => zkVMKind::SP1, - Self::EthrexZisk | Self::RethZisk => zkVMKind::Zisk, - Self::RethOpenVM => zkVMKind::OpenVM, - Self::RethPico => zkVMKind::Pico, - } - } - - /// Returns proof ID. - pub fn proof_id(&self) -> u8 { - *self as u8 - } - - /// Returns string representation of the execution layer proof type. - pub fn as_str(&self) -> &'static str { - match self { - Self::EthrexRisc0 => "ethrex-risc0", - Self::EthrexSP1 => "ethrex-sp1", - Self::EthrexZisk => "ethrex-zisk", - Self::RethOpenVM => "reth-openvm", - Self::RethPico => "reth-pico", - Self::RethRisc0 => "reth-risc0", - Self::RethSP1 => "reth-sp1", - Self::RethZisk => "reth-zisk", - } - } -} - -impl From for String { - fn from(value: ElProofType) -> Self { - value.as_str().to_string() - } -} - -impl FromStr for ElProofType { - type Err = ParseError; - - fn from_str(s: &str) -> Result { - Ok(match s { - "ethrex-risc0" => Self::EthrexRisc0, - "ethrex-sp1" => Self::EthrexSP1, - "ethrex-zisk" => Self::EthrexZisk, - "reth-openvm" => Self::RethOpenVM, - "reth-pico" => Self::RethPico, - "reth-risc0" => Self::RethRisc0, - "reth-sp1" => Self::RethSP1, - "reth-zisk" => Self::RethZisk, - _ => return Err(ParseError(s.to_string())), - }) - } -} - -impl TryFrom for ElProofType { - type Error = ParseError; - - fn try_from(s: String) -> Result { - s.parse() - } -} - -impl Display for ElProofType { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.as_str()) - } -} - -/// Parse error for invalid execution layer proof type strings. -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct ParseError(String); - -impl From<&str> for ParseError { - fn from(s: &str) -> Self { - Self(s.to_string()) - } -} - -impl Display for ParseError { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - let unsupported = &self.0; - let supported = Vec::from_iter(ElProofType::iter().map(|k| k.as_str())).join(", "); - write!( - f, - "Unsupported compiler kind `{unsupported}`, expect one of [{supported}]", - ) - } -} - -impl Error for ParseError {} diff --git a/crates/zkboost-ethereum/el-types/src/lib.rs b/crates/zkboost-ethereum/el-types/src/lib.rs deleted file mode 100644 index 111b28b..0000000 --- a/crates/zkboost-ethereum/el-types/src/lib.rs +++ /dev/null @@ -1,29 +0,0 @@ -//! Type definitions for zkBoost Ethereum Execution Layer integration. - -#![cfg_attr(not(test), warn(unused_crate_dependencies))] - -pub use el_kind::ElKind; -pub use el_proof_type::ElProofType; - -pub mod el_kind; -pub mod el_proof_type; - -include!(concat!(env!("OUT_DIR"), "/workload_info.rs")); - -/// Version specification for a package, either as a git revision or release tag. -#[derive(Debug)] -pub enum PackageVersion { - /// Git commit revision (SHA). - Rev(&'static str), - /// Release tag version. - Tag(&'static str), -} - -impl PackageVersion { - /// Returns the version string, whether it's a revision or tag. - pub fn as_str(&self) -> &'static str { - match self { - Self::Rev(s) | Self::Tag(s) => s, - } - } -} diff --git a/crates/zkboost/client/src/client.rs b/crates/zkboost/client/src/client.rs deleted file mode 100644 index 53d7534..0000000 --- a/crates/zkboost/client/src/client.rs +++ /dev/null @@ -1,128 +0,0 @@ -use reqwest::{Client, IntoUrl, RequestBuilder, Response, Url}; -use serde::{Serialize, de::DeserializeOwned}; -use zkboost_types::{ - ExecuteRequest, ExecuteResponse, ProgramID, ProveRequest, ProveResponse, ServerInfoResponse, - VerifyRequest, VerifyResponse, -}; - -use crate::Error; - -/// HTTP client for zkboost servers. -/// -/// Provides methods to execute programs, generate proofs, and verify proofs. -#[allow(non_camel_case_types)] -#[derive(Clone, Debug)] -pub struct zkboostClient { - base_url: Url, - client: Client, -} - -impl zkboostClient { - /// Creates a new client connected to the specified server URL. - pub fn new(base_url: impl IntoUrl) -> Result { - Ok(Self { - base_url: base_url.into_url()?, - client: Client::new(), - }) - } - - /// Creates a new client with a custom [`reqwest::Client`]. - pub fn with_client(base_url: impl IntoUrl, client: Client) -> Result { - Ok(Self { - base_url: base_url.into_url()?, - client, - }) - } - - /// Sends a GET request to the specified path and deserializes the response. - pub async fn get(&self, path: &'static str) -> Result { - let res = send(self.client.get(self.base_url.join(path).unwrap())).await?; - Ok(res.json::().await?) - } - - /// Sends a POST request with a JSON body and deserializes the response. - pub async fn post( - &self, - path: &'static str, - req: Req, - ) -> Result { - let res = send( - self.client - .post(self.base_url.join(path).unwrap()) - .json(&req), - ) - .await?; - Ok(res.json::().await?) - } - - /// Executes a program without generating a proof. - pub async fn execute( - &self, - program_id: impl Into, - input: Vec, - ) -> Result { - self.post( - "execute", - ExecuteRequest { - program_id: program_id.into(), - input, - }, - ) - .await - } - - /// Generates a proof for a program execution. - pub async fn prove( - &self, - program_id: impl Into, - input: Vec, - ) -> Result { - self.post( - "prove", - ProveRequest { - program_id: program_id.into(), - input, - }, - ) - .await - } - - /// Verifies a proof without re-executing the program. - pub async fn verify( - &self, - program_id: impl Into, - proof: Vec, - ) -> Result { - self.post( - "verify", - VerifyRequest { - program_id: program_id.into(), - proof, - }, - ) - .await - } - - /// Retrieves server hardware and system information. - pub async fn info(&self) -> Result { - self.get("info").await - } - - /// Checks if the server is healthy and responsive. - pub async fn health(&self) -> Result<(), Error> { - send(self.client.get(self.base_url.join("health").unwrap())).await?; - Ok(()) - } -} - -/// Sends an HTTP request and handles error status codes. -pub(crate) async fn send(request: RequestBuilder) -> Result { - let res = request.send().await?; - - if let Err(inner) = res.error_for_status_ref() { - let msg = res.text().await.ok(); - return Err(Error::ErrorStatus { inner, msg }); - } - - Ok(res) -} diff --git a/crates/zkboost/client/src/error.rs b/crates/zkboost/client/src/error.rs deleted file mode 100644 index fcfa29e..0000000 --- a/crates/zkboost/client/src/error.rs +++ /dev/null @@ -1,17 +0,0 @@ -use thiserror::Error; - -/// Error type for zkboost client operations. -#[derive(Debug, Error)] -pub enum Error { - /// HTTP request failed or URL conversion failed. - #[error("Request error: {0}")] - Reqwest(#[from] reqwest::Error), - /// Server returned an error response with status code >= 400. - #[error("Requested {} failed with status {} and msg {}", inner.url().unwrap(), inner.status().unwrap(), msg.as_deref().unwrap_or("Unknown"))] - ErrorStatus { - /// The underlying HTTP error containing status code and URL. - inner: reqwest::Error, - /// Error message from the server response body, if available. - msg: Option, - }, -} diff --git a/crates/zkboost/client/src/lib.rs b/crates/zkboost/client/src/lib.rs deleted file mode 100644 index d21f833..0000000 --- a/crates/zkboost/client/src/lib.rs +++ /dev/null @@ -1,38 +0,0 @@ -//! HTTP client for zkboost servers. -//! -//! Provides a high-level Rust client for interacting with zkboost servers to execute zkVM -//! programs, generate proofs, and verify proofs over HTTP. -//! -//! ## Example -//! -//! ```no_run -//! use zkboost_client::{zkboostClient, Error}; -//! -//! # async fn example() -> Result<(), Error> { -//! let client = zkboostClient::new("http://localhost:3001")?; -//! -//! // Execute a program -//! let response = client.execute("my_program", vec![1, 2, 3, 4]).await?; -//! println!("Execution completed in {} cycles", response.total_num_cycles); -//! -//! // Request for proof generation -//! let proof_response = client.prove("my_program", vec![1, 2, 3, 4]).await?; -//! -//! // Wait for proof from webhook -//! let proof = Vec::new(); -//! -//! // Verify the proof -//! let verify_response = client.verify("my_program", proof).await?; -//! assert!(verify_response.verified); -//! # Ok(()) -//! # } -//! ``` - -#![cfg_attr(not(test), warn(unused_crate_dependencies))] - -pub use client::zkboostClient; -pub use error::Error; -pub use zkboost_types as types; - -mod client; -mod error; diff --git a/crates/zkboost/server-config/Cargo.toml b/crates/zkboost/server-config/Cargo.toml deleted file mode 100644 index a4b8d84..0000000 --- a/crates/zkboost/server-config/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -name = "zkboost-server-config" -version.workspace = true -edition.workspace = true -rust-version.workspace = true -license.workspace = true - -[lints] -workspace = true - -[dependencies] -anyhow.workspace = true -reqwest.workspace = true -serde = { workspace = true, features = ["derive"] } -serde_yaml.workspace = true -toml_edit = { workspace = true, features = ["serde"] } - -ere-dockerized.workspace = true -ere-zkvm-interface.workspace = true - -zkboost-types.workspace = true - -[dev-dependencies] -tokio = { workspace = true, features = ["full"] } \ No newline at end of file diff --git a/crates/zkboost/server-config/src/config.rs b/crates/zkboost/server-config/src/config.rs deleted file mode 100644 index 4e2f681..0000000 --- a/crates/zkboost/server-config/src/config.rs +++ /dev/null @@ -1,248 +0,0 @@ -//! Server configuration and TOML/YAML parsing. -//! -//! Defines the configuration structure for loading zkVM programs from TOML/YAML files. - -use std::path::Path; - -use anyhow::Context; -use ere_dockerized::zkVMKind; -use ere_zkvm_interface::ProverResource; -use serde::{Deserialize, Serialize}; -use zkboost_types::ProgramID; - -pub use crate::config::program::{PathConfig, ProgramConfig, UrlConfig}; - -mod program; - -/// Server configuration loaded from a TOML/YAML file. -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -pub struct Config { - /// Port to listen on. - #[serde(default = "default_port")] - pub port: u16, - /// Url for sending proof when generated. - #[serde(default = "default_webhook_url")] - pub webhook_url: String, - /// List of zkVM programs to load on server startup. - #[serde(default)] - pub zkvm: Vec, -} - -fn default_port() -> u16 { - 3001 -} - -fn default_webhook_url() -> String { - "http://localhost:3003/proofs".to_string() -} - -impl Config { - /// Load config from file (auto-detects format from extension). - pub fn load(path: impl AsRef) -> anyhow::Result { - let path = path.as_ref(); - let string = std::fs::read_to_string(path) - .with_context(|| format!("Failed to read config at {path:?}"))?; - - match path.extension().and_then(|s| s.to_str()) { - Some("toml") => Self::from_toml_str(&string), - Some("yaml") => Self::from_yaml_str(&string), - Some(ext) => anyhow::bail!("Unsupported config format: .{ext}"), - None => anyhow::bail!("Config file must have an extension (e.g., .toml)"), - } - } - - /// Parse config from TOML string. - pub fn from_toml_str(s: &str) -> anyhow::Result { - toml_edit::de::from_str(s) - .with_context(|| format!("Failed to deserialize TOML config:\n{s}")) - } - - /// Converts to TOML string. - pub fn to_toml(&self) -> anyhow::Result { - let mut config_toml = toml_edit::ser::to_document(&self)?; - - // Format array into array of tables. - if let Some(item) = config_toml.get_mut("zkvm") - && let toml_edit::Item::Value(toml_edit::Value::Array(array)) = item - { - *item = array - .iter() - .map(|v| toml_edit::Table::from_iter(v.as_inline_table().unwrap())) - .collect::() - .into(); - } - - Ok(config_toml.to_string()) - } - - /// Parse config from YAML string. - pub fn from_yaml_str(s: &str) -> anyhow::Result { - serde_yaml::from_str(s).with_context(|| format!("Failed to deserialize YAML config:\n{s}")) - } -} - -/// Configuration for a single zkVM program. -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -#[serde(untagged)] -#[allow(non_camel_case_types)] -pub enum zkVMConfig { - /// Configuration for `DockerizedzkVM` ran by zkboost. - Docker { - /// The kind of zkVM backend to use. - kind: zkVMKind, - /// The compute resource type for proving (CPU, GPU, or network). - resource: ProverResource, - /// Unique identifier for this program. - program_id: ProgramID, - /// Path to the compiled program binary. - program: ProgramConfig, - }, - /// External Ere zkVM server configuration - External { - /// The endpoint URL of the remote Ere zkVM server. - endpoint: String, - /// Unique identifier for this program. - program_id: ProgramID, - }, - /// Mock zkVM configuration - Mock { - /// Mock time in millisecond for proof generation. - mock_proving_time_ms: u64, - /// Mock size for proof. - mock_proof_size: u64, - /// Unique identifier for this program. - program_id: ProgramID, - }, -} - -impl zkVMConfig { - /// Returns [`ProgramID`]. - pub fn program_id(&self) -> &ProgramID { - match self { - Self::Docker { program_id, .. } => program_id, - Self::External { program_id, .. } => program_id, - Self::Mock { program_id, .. } => program_id, - } - } -} - -#[cfg(test)] -mod test { - use ere_dockerized::zkVMKind; - use ere_zkvm_interface::{ProverResource, RemoteProverConfig}; - - use crate::{Config, PathConfig, ProgramConfig, UrlConfig, zkVMConfig}; - - #[test] - fn test_from_toml_str() { - let toml = r#" - port = 3001 - webhook_url = "http://localhost:3003/proofs" - - [[zkvm]] - kind = "openvm" - resource = { kind = "cpu" } - program_id = "openvm-test" - program = "openvm-test-elf" - - [[zkvm]] - kind = "sp1" - resource = { kind = "network", endpoint = "http://localhost:3000", api_key = "secret" } - program_id = "sp1-test" - program = { path = "sp1-test-elf" } - - [[zkvm]] - kind = "zisk" - resource = { kind = "gpu" } - program_id = "zisk-test" - program = { url = "http://artifact" } - - [[zkvm]] - endpoint = "http://remote:3000" - program_id = "external-test" - - [[zkvm]] - mock_proving_time_ms = 1000 - mock_proof_size = 1024 - program_id = "mock" - "#; - assert_eq!(Config::from_toml_str(toml).unwrap(), sample_config()); - } - - #[test] - fn test_from_yaml_str() { - let yaml = r#" - port: 3001 - webhook_url: "http://localhost:3003/proofs" - zkvm: - - kind: openvm - resource: - kind: cpu - program_id: openvm-test - program: openvm-test-elf - - kind: sp1 - resource: - kind: network - endpoint: http://localhost:3000 - api_key: secret - program_id: sp1-test - program: - path: sp1-test-elf - - kind: zisk - resource: - kind: gpu - program_id: zisk-test - program: - url: http://artifact - - endpoint: "http://remote:3000" - program_id: "external-test" - - mock_proving_time_ms: 1000 - mock_proof_size: 1024 - program_id: "mock" - "#; - assert_eq!(Config::from_yaml_str(yaml).unwrap(), sample_config()); - } - - fn sample_config() -> Config { - Config { - port: 3001, - webhook_url: "http://localhost:3003/proofs".to_string(), - zkvm: vec![ - zkVMConfig::Docker { - kind: zkVMKind::OpenVM, - resource: ProverResource::Cpu, - program_id: "openvm-test".into(), - program: ProgramConfig::Path("openvm-test-elf".into()), - }, - zkVMConfig::Docker { - kind: zkVMKind::SP1, - resource: ProverResource::Network(RemoteProverConfig { - endpoint: "http://localhost:3000".to_string(), - api_key: Some("secret".to_string()), - }), - program_id: "sp1-test".into(), - program: ProgramConfig::ExplicitPath(PathConfig { - path: "sp1-test-elf".into(), - }), - }, - zkVMConfig::Docker { - kind: zkVMKind::Zisk, - resource: ProverResource::Gpu, - program_id: "zisk-test".into(), - program: ProgramConfig::Url(UrlConfig { - url: "http://artifact".to_string(), - }), - }, - zkVMConfig::External { - endpoint: "http://remote:3000".to_string(), - program_id: "external-test".into(), - }, - zkVMConfig::Mock { - mock_proving_time_ms: 1000, - mock_proof_size: 1 << 10, - program_id: "mock".into(), - }, - ], - } - } -} diff --git a/crates/zkboost/server-config/src/config/program.rs b/crates/zkboost/server-config/src/config/program.rs deleted file mode 100644 index 49657fe..0000000 --- a/crates/zkboost/server-config/src/config/program.rs +++ /dev/null @@ -1,128 +0,0 @@ -use std::{fs, path::PathBuf}; - -use anyhow::{Context, bail}; -use ere_dockerized::SerializedProgram; -use serde::{Deserialize, Serialize}; - -/// Configuration for how to load a zkVM program. -/// -/// Supports multiple formats: -/// - Simple string path e.g. `program = "./elf/reth-zisk"` -/// - Explicit path object e.g. `program = { path = "./elf/reth-zisk" }` -/// - URL download e.g. `program = { url = "https://github.com/eth-act/zkevm-benchmark-workload/releases/v0.1.0/reth-zisk" }` -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -#[serde(untagged)] -pub enum ProgramConfig { - /// Simple string path to a local program file. - Path(PathBuf), - - /// Explicit path object with named field. - ExplicitPath(PathConfig), - - /// Remote URL to download the program from. - Url(UrlConfig), -} - -impl ProgramConfig { - /// Load the program from either a local path or remote URL. - pub async fn load(&self) -> anyhow::Result { - let bytes = match self { - ProgramConfig::Path(path) | ProgramConfig::ExplicitPath(PathConfig { path }) => { - fs::read(path).with_context(|| { - format!("Failed to read program from path: {}", path.display()) - })? - } - ProgramConfig::Url(UrlConfig { url }) => { - let response = reqwest::get(url) - .await - .with_context(|| format!("Failed to download program from URL: {url}"))?; - - let status = response.status(); - if !status.is_success() { - bail!("Failed to download program from URL: {url} (HTTP status: {status})"); - } - - response - .bytes() - .await - .with_context(|| format!("Failed to read response bytes from URL: {url}"))? - .to_vec() - } - }; - Ok(SerializedProgram(bytes)) - } -} - -/// Path configuration for explicit path object. -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct PathConfig { - /// Path to the file - pub path: PathBuf, -} - -/// URL configuration for program download. -#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct UrlConfig { - /// Url to the file - pub url: String, -} - -#[cfg(test)] -mod tests { - use serde::Deserialize; - - use crate::{PathConfig, ProgramConfig, UrlConfig}; - - #[derive(Deserialize)] - struct TestConfig { - program: ProgramConfig, - } - - #[test] - fn test_parse_simple_path() { - let toml = r#"program = "./elf/reth-zisk""#; - let config: TestConfig = toml_edit::de::from_str(toml).unwrap(); - assert_eq!( - config.program, - ProgramConfig::Path("./elf/reth-zisk".into()) - ); - } - - #[test] - fn test_parse_explicit_path() { - let toml = r#"program = { path = "./elf/reth-zisk" }"#; - let config: TestConfig = toml_edit::de::from_str(toml).unwrap(); - assert_eq!( - config.program, - ProgramConfig::ExplicitPath(PathConfig { - path: "./elf/reth-zisk".into(), - }) - ); - } - - #[test] - fn test_parse_url() { - let toml = r#"program = { url = "https://example.com/program" }"#; - let config: TestConfig = toml_edit::de::from_str(toml).unwrap(); - assert_eq!( - config.program, - ProgramConfig::Url(UrlConfig { - url: "https://example.com/program".to_string(), - }) - ); - } - - #[test] - fn test_reject_both_path_and_url() { - let toml = r#"program = { path = "./elf/program", url = "https://example.com/program" }"#; - assert!(toml_edit::de::from_str::(toml).is_err()); - } - - #[test] - fn test_reject_neither_path_nor_url() { - let toml = r#"program = {}"#; - assert!(toml_edit::de::from_str::(toml).is_err()); - } -} diff --git a/crates/zkboost/server-config/src/lib.rs b/crates/zkboost/server-config/src/lib.rs deleted file mode 100644 index 467c767..0000000 --- a/crates/zkboost/server-config/src/lib.rs +++ /dev/null @@ -1,9 +0,0 @@ -//! Server configuration and TOML/YAML parsing. -//! -//! Defines the configuration structure for loading zkVM programs from TOML/YAML files. - -#![cfg_attr(not(test), warn(unused_crate_dependencies))] - -mod config; - -pub use config::{Config, PathConfig, ProgramConfig, UrlConfig, zkVMConfig}; diff --git a/crates/zkboost/server/src/app.rs b/crates/zkboost/server/src/app.rs deleted file mode 100644 index a15f459..0000000 --- a/crates/zkboost/server/src/app.rs +++ /dev/null @@ -1,205 +0,0 @@ -//! Application state, initialization, and HTTP endpoints. - -use std::{collections::HashMap, iter::zip, sync::Arc}; - -use anyhow::Context; -use axum::{ - Router, - extract::State, - middleware, - routing::{get, post}, -}; -use ere_dockerized::DockerizedzkVM; -use ere_server::client::zkVMClient; -use ere_zkvm_interface::{ - Input, ProgramExecutionReport, ProgramProvingReport, Proof, ProofKind, PublicValues, -}; -use futures::future::try_join_all; -use metrics_exporter_prometheus::PrometheusHandle; -use reqwest::{Client, StatusCode, Url}; -use tokio::sync::mpsc::Sender; -use tower_http::trace::TraceLayer; -use zkboost_server_config::{Config, zkVMConfig}; -use zkboost_types::ProgramID; - -use crate::{ - app::{ - execute::execute_program, info::get_server_info, prove::prove_program, verify::verify_proof, - }, - metrics::http_metrics_middleware, - mock::MockzkVM, - proof_service::{ProofMessage, ProofService}, -}; - -mod execute; -mod info; -mod prove; -mod verify; - -/// Application state shared across all HTTP handlers. -#[derive(Clone)] -pub(crate) struct AppState { - /// Map of program IDs to their corresponding zkVM instances. - pub(crate) programs: Arc>, - /// Map of program IDs to proof service message sender. - pub(crate) proof_txs: Arc>>, - /// Prometheus metrics handle for rendering metrics. - pub(crate) metrics: PrometheusHandle, -} - -impl AppState { - /// Creates a new application state from configuration. - /// - /// Loads all configured zkVM programs and initializes their instances. - pub(crate) async fn new( - config: &Config, - webhook_url: &str, - metrics: PrometheusHandle, - ) -> anyhow::Result { - let zkvms = try_join_all(config.zkvm.iter().map(init_zkvm)).await?; - let http_client = Client::new(); - let mut proof_txs = HashMap::new(); - let mut programs = HashMap::new(); - for (zkvm_config, zkvm) in zip(&config.zkvm, zkvms) { - let program_id = zkvm_config.program_id().clone(); - let (proof_service, proof_tx) = ProofService::new( - program_id.clone(), - zkvm.clone(), - http_client.clone(), - webhook_url.to_string(), - ); - - proof_service.start_service(); - - proof_txs.insert(program_id.clone(), proof_tx); - programs.insert(program_id, zkvm); - } - - Ok(Self { - programs: Arc::new(programs), - proof_txs: Arc::new(proof_txs), - metrics, - }) - } -} - -/// zkVM instance, either dockerized zkVM or external Ere server. -#[allow(non_camel_case_types)] -#[derive(Clone)] -pub(crate) enum zkVMInstance { - /// Dockerized zkVM managed by zkboost. - Docker { - /// The underlying zkVM implementation. - vm: Arc, - }, - /// External Ere server that provides zkVM functionalities via http endpoints. - External { - /// Client of external Ere server. - client: Arc, - }, - /// Mock zkVM - Mock(MockzkVM), -} - -impl zkVMInstance { - /// Creates a dockerized zkVM instance. - pub(crate) fn docker(vm: DockerizedzkVM) -> Self { - Self::Docker { vm: Arc::new(vm) } - } - - /// Creates an external zkVM instance. - pub(crate) async fn external(endpoint: String) -> anyhow::Result { - let endpoint = Url::parse(&endpoint) - .with_context(|| format!("Failed to parse endpoint URL: {endpoint}"))?; - let client = zkVMClient::from_endpoint(endpoint.clone()) - .with_context(|| format!("Failed to create zkVM client for endpoint: {endpoint}"))?; - Ok(Self::External { - client: Arc::new(client), - }) - } - - /// Creates an mock zkVM instance. - pub(crate) fn mock(mock_proving_time_ms: u64, mock_proof_size: u64) -> Self { - Self::Mock(MockzkVM::new(mock_proving_time_ms, mock_proof_size)) - } - - /// Executes the program with the given input. - pub(crate) async fn execute( - &self, - input: Input, - ) -> anyhow::Result<(PublicValues, ProgramExecutionReport)> { - match self { - Self::Docker { vm } => vm.execute_async(input).await, - Self::External { client } => Ok(client.execute(input).await?), - Self::Mock(vm) => vm.execute(&input).await, - } - } - - /// Creates a proof of the program execution with given input. - pub(crate) async fn prove( - &self, - input: Input, - proof_kind: ProofKind, - ) -> anyhow::Result<(PublicValues, Proof, ProgramProvingReport)> { - match self { - Self::Docker { vm } => vm.prove_async(input, proof_kind).await, - Self::External { client } => Ok(client.prove(input, proof_kind).await?), - Self::Mock(vm) => vm.prove(&input, proof_kind).await, - } - } - - /// Verifies a proof of the program used to create this zkVM instance, then - /// returns the public values extracted from the proof. - pub(crate) async fn verify(&self, proof: Proof) -> anyhow::Result { - match self { - Self::Docker { vm } => vm.verify_async(proof).await, - Self::External { client } => Ok(client.verify(proof).await?), - Self::Mock(vm) => vm.verify(&proof).await, - } - } -} - -/// Builds the Axum router with all endpoints and middleware. -pub(crate) fn app(state: AppState) -> Router { - Router::new() - .route("/execute", post(execute_program)) - .route("/prove", post(prove_program)) - .route("/verify", post(verify_proof)) - .route("/info", get(get_server_info)) - .route("/health", get(StatusCode::OK)) - .route("/metrics", get(get_metrics)) - .with_state(state) - .layer(middleware::from_fn(http_metrics_middleware)) - .layer(TraceLayer::new_for_http()) - // 400MB limit to account for the proof size - // and the possibly large input size - .layer(axum::extract::DefaultBodyLimit::max(400 * 1024 * 1024)) -} - -/// HTTP handler for the `/metrics` endpoint. -async fn get_metrics(State(state): State) -> String { - state.metrics.render() -} - -/// Initializes a single zkVM instance from configuration. -async fn init_zkvm(config: &zkVMConfig) -> anyhow::Result { - match config { - zkVMConfig::Docker { - kind, - resource, - program, - .. - } => { - let serialized_program = program.load().await?; - let zkvm = DockerizedzkVM::new(*kind, serialized_program, resource.clone()) - .with_context(|| format!("Failed to initialize DockerizedzkVM, kind {kind}"))?; - Ok(zkVMInstance::docker(zkvm)) - } - zkVMConfig::External { endpoint, .. } => zkVMInstance::external(endpoint.clone()).await, - zkVMConfig::Mock { - mock_proving_time_ms, - mock_proof_size, - .. - } => Ok(zkVMInstance::mock(*mock_proving_time_ms, *mock_proof_size)), - } -} diff --git a/crates/zkboost/server/src/app/execute.rs b/crates/zkboost/server/src/app/execute.rs deleted file mode 100644 index faa9bfd..0000000 --- a/crates/zkboost/server/src/app/execute.rs +++ /dev/null @@ -1,90 +0,0 @@ -use std::time::Instant; - -use axum::{Json, extract::State, http::StatusCode}; -use ere_zkvm_interface::Input; -use tracing::instrument; -use zkboost_types::{ExecuteRequest, ExecuteResponse}; - -use crate::{app::AppState, metrics::record_execute}; - -/// HTTP handler for the `/execute` endpoint. -/// -/// Executes a zkVM program without generating a proof. -#[instrument(skip_all)] -pub(crate) async fn execute_program( - State(state): State, - Json(req): Json, -) -> Result, (StatusCode, String)> { - let start = Instant::now(); - let program_id = req.program_id.clone(); - - let zkvm = state.programs.get(&program_id).ok_or_else(|| { - record_execute(&program_id.0, false, start.elapsed(), 0); - (StatusCode::NOT_FOUND, "Program not found".to_string()) - })?; - - let input = Input::new().with_stdin(req.input); - - let (public_values, report) = zkvm.execute(input).await.map_err(|e| { - record_execute(&program_id.0, false, start.elapsed(), 0); - ( - StatusCode::INTERNAL_SERVER_ERROR, - format!("Failed to execute program: {e}"), - ) - })?; - - record_execute( - &program_id.0, - true, - start.elapsed(), - report.total_num_cycles, - ); - - Ok(Json(ExecuteResponse { - program_id, - public_values, - total_num_cycles: report.total_num_cycles, - region_cycles: report.region_cycles, - execution_time_ms: report.execution_duration.as_millis(), - })) -} - -#[cfg(test)] -mod tests { - use axum::{Json, extract::State, http::StatusCode}; - use zkboost_types::{ExecuteRequest, ProgramID}; - - use crate::{app::execute::execute_program, mock::tests::mock_app_state}; - - #[tokio::test] - async fn test_execute_success() { - let program_id = ProgramID::from("mock_program_id"); - let state = mock_app_state(Some(&program_id)); - - let request = ExecuteRequest { - program_id: program_id.clone(), - input: Vec::new(), - }; - - let response = execute_program(State(state), Json(request)).await.unwrap(); - - assert_eq!(response.program_id, program_id); - } - - #[tokio::test] - async fn test_execute_program_not_found() { - let state = mock_app_state(None); - - let request = ExecuteRequest { - program_id: ProgramID::from("non_existent"), - input: Vec::new(), - }; - - let result = execute_program(State(state), Json(request)).await; - - assert!(result.is_err()); - let (status, message) = result.unwrap_err(); - assert_eq!(status, StatusCode::NOT_FOUND); - assert_eq!(message, "Program not found"); - } -} diff --git a/crates/zkboost/server/src/app/info.rs b/crates/zkboost/server/src/app/info.rs deleted file mode 100644 index c4a9b8a..0000000 --- a/crates/zkboost/server/src/app/info.rs +++ /dev/null @@ -1,105 +0,0 @@ -//! Collects and caches host hardware / OS data for the "/info" route. - -use axum::Json; -use sysinfo::System; -use tracing::instrument; -use wgpu::{Backends, Instance, InstanceDescriptor}; -use zkboost_types::{CpuInfo, MemoryInfo, OsInfo, ServerInfoResponse}; - -/// HTTP handler for the `/info` endpoint. -/// -/// Returns information about the server's hardware and operating system. -#[instrument] -pub(crate) async fn get_server_info() -> Json { - Json(ServerInfoResponse { - cpu: get_cpu_info(), - memory: get_memory_info(), - os: get_os_info(), - architecture: std::env::consts::ARCH.into(), - gpu: get_gpu_info(), - }) -} - -/// Get information about the CPU. -/// -/// Note: unfortunately this has been unreliable on ARM macs and AWS machines. -fn get_cpu_info() -> CpuInfo { - let sys = System::new_all(); - - // Get info from the CPU cores with maximum frequency as representative - let (frequency, model, vendor) = sys - .cpus() - .iter() - .max_by(|a, b| a.frequency().cmp(&b.frequency())) - .map(|cpu| (cpu.frequency(), cpu.brand(), cpu.vendor_id())) - .unwrap_or((0, "Unknown", "Unknown")); - - CpuInfo { - model: model.to_string(), - cores: System::physical_core_count().unwrap_or(0), - frequency, - vendor: vendor.to_string(), - } -} - -/// Get memory related information about the system. -/// -/// TODO: I think just having total is likely fine. -fn get_memory_info() -> MemoryInfo { - let sys = System::new_all(); - - let total = sys.total_memory(); - let available = sys.available_memory(); - let used = total - available; - - MemoryInfo { - total: format!("{:.2} GB", total as f64 / 1024.0 / 1024.0 / 1024.0), - available: format!("{:.2} GB", available as f64 / 1024.0 / 1024.0 / 1024.0), - used: format!("{:.2} GB", used as f64 / 1024.0 / 1024.0 / 1024.0), - } -} - -/// Get OS specific information. -fn get_os_info() -> OsInfo { - OsInfo { - name: System::name().unwrap_or_else(|| "Unknown".into()), - version: System::os_version().unwrap_or_else(|| "Unknown".into()), - kernel: System::kernel_version().unwrap_or_else(|| "Unknown".into()), - } -} - -/// Get GPU specific information. -fn get_gpu_info() -> String { - let instance_desc = InstanceDescriptor { - backends: Backends::all(), - ..Default::default() - }; - - let instance = Instance::new(&instance_desc); - let names: Vec = instance - .enumerate_adapters(Backends::all()) - .into_iter() - .map(|a| a.get_info().name) - .collect(); - - match names.as_slice() { - [] => "No GPU detected".into(), - [single] => single.clone(), - many => many.join(" · "), - } -} - -#[cfg(test)] -mod tests { - use crate::app::info::get_server_info; - - #[tokio::test] - async fn test_server_info() { - let info = get_server_info().await; - assert!(!info.0.cpu.model.is_empty()); - assert!(!info.0.memory.total.is_empty()); - assert!(!info.0.os.name.is_empty()); - assert!(!info.0.architecture.is_empty()); - assert!(!info.0.gpu.is_empty()); - } -} diff --git a/crates/zkboost/server/src/app/prove.rs b/crates/zkboost/server/src/app/prove.rs deleted file mode 100644 index c131470..0000000 --- a/crates/zkboost/server/src/app/prove.rs +++ /dev/null @@ -1,79 +0,0 @@ -use axum::{Json, extract::State, http::StatusCode}; -use ere_zkvm_interface::Input; -use tracing::instrument; -use uuid::Uuid; -use zkboost_types::{ProofGenId, ProveRequest, ProveResponse}; - -use crate::{app::AppState, proof_service::ProofMessage}; - -/// HTTP handler for the `/prove` endpoint. -/// -/// Queues a proof request and returns immediately with a `ProofGenId`. -#[instrument(skip_all)] -pub(crate) async fn prove_program( - State(state): State, - Json(req): Json, -) -> Result, (StatusCode, String)> { - let program_id = req.program_id.clone(); - - let proof_tx = state - .proof_txs - .get(&program_id) - .ok_or_else(|| (StatusCode::NOT_FOUND, "Program not found".to_string()))?; - - let proof_gen_id = ProofGenId(Uuid::new_v4().to_string()); - - let msg = ProofMessage { - proof_gen_id: proof_gen_id.clone(), - input: Input::new().with_stdin(req.input), - }; - proof_tx.send(msg).await.map_err(|e| { - ( - StatusCode::INTERNAL_SERVER_ERROR, - format!("Failed to send proof: {e}"), - ) - })?; - - Ok(Json(ProveResponse { proof_gen_id })) -} - -#[cfg(test)] -mod tests { - use axum::{Json, extract::State, http::StatusCode}; - use zkboost_types::{ProgramID, ProveRequest}; - - use crate::{app::prove::prove_program, mock::tests::mock_app_state}; - - #[tokio::test] - async fn test_prove_success() { - let program_id = ProgramID::from("mock_program_id"); - let state = mock_app_state(Some(&program_id)); - - let request = ProveRequest { - program_id: program_id.clone(), - input: Vec::new(), - }; - - let response = prove_program(State(state), Json(request)).await.unwrap(); - - // Verify that proof_id is a valid UUID - assert!(uuid::Uuid::parse_str(&response.proof_gen_id.0).is_ok()); - } - - #[tokio::test] - async fn test_prove_program_not_found() { - let state = mock_app_state(None); - - let request = ProveRequest { - program_id: ProgramID::from("non_existent"), - input: Vec::new(), - }; - - let result = prove_program(State(state), Json(request)).await; - - assert!(result.is_err()); - let (status, message) = result.unwrap_err(); - assert_eq!(status, StatusCode::NOT_FOUND); - assert_eq!(message, "Program not found"); - } -} diff --git a/crates/zkboost/server/src/app/verify.rs b/crates/zkboost/server/src/app/verify.rs deleted file mode 100644 index 441cfa3..0000000 --- a/crates/zkboost/server/src/app/verify.rs +++ /dev/null @@ -1,121 +0,0 @@ -use std::time::Instant; - -use axum::{Json, extract::State, http::StatusCode}; -use ere_zkvm_interface::Proof; -use tracing::instrument; -use zkboost_types::{VerifyRequest, VerifyResponse}; - -use crate::{app::AppState, metrics::record_verify}; - -/// HTTP handler for the `/verify` endpoint. -/// -/// Verifies a cryptographic proof without re-executing the program. -#[instrument(skip_all)] -pub(crate) async fn verify_proof( - State(state): State, - Json(req): Json, -) -> Result, (StatusCode, String)> { - let start = Instant::now(); - let program_id = req.program_id.clone(); - - // Check if the program_id is correct - - let zkvm = state.programs.get(&program_id).ok_or_else(|| { - // Record as failed verification for program not found - record_verify(&program_id.0, false, start.elapsed()); - (StatusCode::NOT_FOUND, "Program not found".to_string()) - })?; - - // Verify the proof - let (verified, public_values, failure_reason) = - match zkvm.verify(Proof::Compressed(req.proof)).await { - Ok(public_values) => (true, public_values, String::new()), - Err(err) => { - let failure_reason = match err.downcast_ref::() { - Some(ere_dockerized::zkvm::Error::zkVM(err)) => err.to_string(), - // Connection or RPC errors - Some(err) => return Err((StatusCode::INTERNAL_SERVER_ERROR, err.to_string())), - None => err.to_string(), - }; - (false, Vec::new(), failure_reason) - } - }; - - record_verify(&program_id.0, verified, start.elapsed()); - - Ok(Json(VerifyResponse { - program_id, - verified, - public_values, - failure_reason, - })) -} - -#[cfg(test)] -mod tests { - use axum::{Json, extract::State, http::StatusCode}; - use zkboost_types::{ProgramID, VerifyRequest}; - - use crate::{ - app::{verify::verify_proof, zkVMInstance}, - mock::tests::mock_app_state, - }; - - #[tokio::test] - async fn test_verify_valid_proof() { - let program_id = ProgramID::from("mock_program_id"); - let state = mock_app_state(Some(&program_id)); - - let zkVMInstance::Mock(zkvm) = &state.programs[&program_id] else { - unreachable!() - }; - - // Create a request with the mock proof that MockzkVM accepts - let request = VerifyRequest { - program_id: program_id.clone(), - proof: zkvm.random_proof(), - }; - - // Call the handler - let response = verify_proof(State(state), Json(request)).await.unwrap(); - - // Verify the response - assert_eq!(response.program_id, program_id); - assert!(response.verified); - } - - #[tokio::test] - async fn test_verify_invalid_proof() { - let program_id = ProgramID::from("mock_program_id"); - let state = mock_app_state(Some(&program_id)); - - let request = VerifyRequest { - program_id: program_id.clone(), - proof: b"invalid_proof".to_vec(), - }; - - let result = verify_proof(State(state), Json(request)).await; - // The endpoint returns a result if the verification fails. - // We need to check the proof response to know whether it failed - // verification and for what reason. - assert!(result.is_ok()); - assert!(!result.unwrap().verified); - } - - #[tokio::test] - async fn test_verify_program_not_found() { - let state = mock_app_state(None); - - let request = VerifyRequest { - program_id: ProgramID::from("non_existent"), - proof: b"example_proof".to_vec(), - }; - - let result = verify_proof(State(state), Json(request)).await; - - assert!(result.is_err()); - let (status, message) = result.unwrap_err(); - assert_eq!(status, StatusCode::NOT_FOUND); - assert_eq!(message, "Program not found"); - } -} diff --git a/crates/zkboost/server/src/main.rs b/crates/zkboost/server/src/main.rs deleted file mode 100644 index 74f382d..0000000 --- a/crates/zkboost/server/src/main.rs +++ /dev/null @@ -1,91 +0,0 @@ -//! zkVM execution and proving service. -//! -//! Provides HTTP endpoints for executing zkVM programs, generating proofs, and verifying -//! proofs using various zkVM backends (SP1, OpenVM, Zisk, etc.). -//! -//! ## Endpoints -//! -//! - `POST /execute` - Execute a program without generating a proof -//! - `POST /prove` - Generate a proof for a program execution -//! - `POST /verify` - Verify a proof -//! - `GET /info` - Get server hardware and system information -//! -//! ## Configuration -//! -//! The server is configured via a TOML/YAML file that specifies which zkVM programs to load. -//! See [`config::Config`] for details. -//! -//! ## Usage -//! -//! ```bash -//! zkboost --config config.toml --port 3001 -//! ``` - -#![cfg_attr(not(test), warn(unused_crate_dependencies))] - -use std::{net::SocketAddr, path::PathBuf}; - -use clap::Parser; -use tokio::{ - net::TcpListener, - signal::unix::{SignalKind, signal}, -}; -use tracing::info; -use zkboost_server_config::Config; - -use crate::app::{AppState, app}; - -mod app; -mod metrics; -mod mock; -mod proof_service; - -/// Command-line interface for the zkboost server. -#[derive(Parser, Debug)] -#[command(name = "zkboost")] -#[command(about = "zkVM execution and proving service", long_about = None)] -pub struct Cli { - /// Config file path. - #[arg(long)] - pub config: PathBuf, -} - -#[tokio::main] -async fn main() -> anyhow::Result<()> { - tracing_subscriber::fmt() - .with_env_filter(tracing_subscriber::EnvFilter::from_default_env()) - .init(); - - // Initialize Prometheus metrics exporter - let metrics_handle = metrics::init_metrics(); - - let cli = Cli::parse(); - let config = Config::load(&cli.config)?; - - let state = AppState::new(&config, &config.webhook_url, metrics_handle).await?; - - // Record application metrics - metrics::set_programs_loaded(state.programs.len()); - metrics::set_build_info(env!("CARGO_PKG_VERSION")); - - let router = app(state); - - let addr: SocketAddr = format!("0.0.0.0:{}", config.port).parse()?; - info!("zkboost listening on {addr}"); - - let listener = TcpListener::bind(addr).await?; - axum::serve(listener, router) - .with_graceful_shutdown(shutdown_signal()) - .await?; - Ok(()) -} - -async fn shutdown_signal() { - let mut sigterm = signal(SignalKind::terminate()).expect("failed to install SIGTERM handler"); - let mut sigint = signal(SignalKind::interrupt()).expect("failed to install SIGINT handler"); - - tokio::select! { - _ = sigterm.recv() => info!("Received SIGTERM, starting graceful shutdown"), - _ = sigint.recv() => info!("Received SIGINT (Ctrl-C), starting graceful shutdown"), - } -} diff --git a/crates/zkboost/server/src/metrics.rs b/crates/zkboost/server/src/metrics.rs deleted file mode 100644 index 84179f1..0000000 --- a/crates/zkboost/server/src/metrics.rs +++ /dev/null @@ -1,179 +0,0 @@ -//! Prometheus metrics for the zkboost server. -//! -//! Provides metric initialization and helper functions for recording HTTP and zkVM operation -//! metrics. - -use std::time::{Duration, Instant}; - -use axum::{extract::Request, middleware::Next, response::Response}; -use metrics::{counter, describe_counter, describe_gauge, describe_histogram, gauge, histogram}; -use metrics_exporter_prometheus::{PrometheusBuilder, PrometheusHandle}; - -/// Initialize the Prometheus metrics exporter and register metric descriptions. -/// -/// Returns a handle that can be used to render metrics for the `/metrics` endpoint. -pub(crate) fn init_metrics() -> PrometheusHandle { - let builder = PrometheusBuilder::new(); - let handle = builder - .install_recorder() - .expect("failed to install Prometheus recorder"); - - // HTTP layer metrics - describe_counter!("zkboost_http_requests_total", "Total HTTP requests"); - describe_histogram!( - "zkboost_http_request_duration_seconds", - "HTTP request duration in seconds" - ); - describe_gauge!( - "zkboost_http_requests_in_flight", - "Number of HTTP requests currently being processed" - ); - - // Prove operation metrics - describe_counter!("zkboost_prove_total", "Total prove operations"); - describe_histogram!( - "zkboost_prove_duration_seconds", - "Proof generation time in seconds" - ); - describe_histogram!( - "zkboost_prove_proof_bytes", - "Generated proof sizes in bytes" - ); - - // Execute operation metrics - describe_counter!("zkboost_execute_total", "Total execute operations"); - describe_histogram!( - "zkboost_execute_duration_seconds", - "Program execution time in seconds" - ); - describe_histogram!( - "zkboost_execute_cycles_total", - "Total cycle counts per execution" - ); - - // Verify operation metrics - describe_counter!("zkboost_verify_total", "Total verify operations"); - describe_histogram!( - "zkboost_verify_duration_seconds", - "Proof verification time in seconds" - ); - - // Application metrics - describe_gauge!( - "zkboost_programs_loaded", - "Number of zkVM programs currently loaded" - ); - describe_gauge!("zkboost_build_info", "Build information"); - - handle -} - -/// Record an HTTP request start (increment in-flight gauge). -pub(crate) fn record_request_start(endpoint: &str) { - gauge!("zkboost_http_requests_in_flight", "endpoint" => endpoint.to_string()).increment(1.0); -} - -/// Record an HTTP request completion with status and duration. -pub(crate) fn record_request_end(endpoint: &str, method: &str, status: u16, duration: Duration) { - gauge!("zkboost_http_requests_in_flight", "endpoint" => endpoint.to_string()).decrement(1.0); - counter!( - "zkboost_http_requests_total", - "endpoint" => endpoint.to_string(), - "method" => method.to_string(), - "status" => status.to_string() - ) - .increment(1); - histogram!( - "zkboost_http_request_duration_seconds", - "endpoint" => endpoint.to_string(), - "method" => method.to_string() - ) - .record(duration.as_secs_f64()); -} - -/// Record a prove operation result. -pub(crate) fn record_prove(program_id: &str, success: bool, duration: Duration, proof_size: usize) { - let status = if success { "success" } else { "error" }; - counter!( - "zkboost_prove_total", - "program_id" => program_id.to_string(), - "status" => status - ) - .increment(1); - if success { - histogram!( - "zkboost_prove_duration_seconds", - "program_id" => program_id.to_string() - ) - .record(duration.as_secs_f64()); - histogram!( - "zkboost_prove_proof_bytes", - "program_id" => program_id.to_string() - ) - .record(proof_size as f64); - } -} - -/// Record an execute operation result. -pub(crate) fn record_execute(program_id: &str, success: bool, duration: Duration, cycles: u64) { - let status = if success { "success" } else { "error" }; - counter!( - "zkboost_execute_total", - "program_id" => program_id.to_string(), - "status" => status - ) - .increment(1); - if success { - histogram!( - "zkboost_execute_duration_seconds", - "program_id" => program_id.to_string() - ) - .record(duration.as_secs_f64()); - histogram!( - "zkboost_execute_cycles_total", - "program_id" => program_id.to_string() - ) - .record(cycles as f64); - } -} - -/// Record a verify operation result. -pub(crate) fn record_verify(program_id: &str, verified: bool, duration: Duration) { - counter!( - "zkboost_verify_total", - "program_id" => program_id.to_string(), - "verified" => verified.to_string() - ) - .increment(1); - histogram!( - "zkboost_verify_duration_seconds", - "program_id" => program_id.to_string() - ) - .record(duration.as_secs_f64()); -} - -/// Set the number of loaded programs gauge. -pub(crate) fn set_programs_loaded(count: usize) { - gauge!("zkboost_programs_loaded").set(count as f64); -} - -/// Set the build info gauge with version label. -pub(crate) fn set_build_info(version: &str) { - gauge!("zkboost_build_info", "version" => version.to_string()).set(1.0); -} - -/// Axum middleware that records HTTP request metrics. -pub(crate) async fn http_metrics_middleware(request: Request, next: Next) -> Response { - let start = Instant::now(); - let method = request.method().to_string(); - let path = request.uri().path().to_string(); - - record_request_start(&path); - - let response = next.run(request).await; - - let status = response.status().as_u16(); - record_request_end(&path, &method, status, start.elapsed()); - - response -} diff --git a/crates/zkboost/server/src/mock.rs b/crates/zkboost/server/src/mock.rs deleted file mode 100644 index 488a8f7..0000000 --- a/crates/zkboost/server/src/mock.rs +++ /dev/null @@ -1,120 +0,0 @@ -// A lightweight mock implementation of the zkVM trait that can be used for unit tests. - -use std::time::Duration; - -use ere_zkvm_interface::{ - Input, ProgramExecutionReport, ProgramProvingReport, Proof, ProofKind, PublicValues, -}; - -#[derive(Clone)] -pub(crate) struct MockzkVM { - mock_proving_time: Duration, - mock_proof_size: u64, -} - -impl MockzkVM { - /// Construct a `MockzkVM`. - pub(crate) fn new(mock_proving_time_ms: u64, mock_proof_size: u64) -> Self { - Self { - mock_proving_time: Duration::from_millis(mock_proving_time_ms), - mock_proof_size, - } - } - - // Generate random proof. - pub(crate) fn random_proof(&self) -> Vec { - let mut proof = vec![0; self.mock_proof_size as usize]; - rand::fill(proof.as_mut_slice()); - proof - } - - pub(crate) async fn execute( - &self, - _: &Input, - ) -> anyhow::Result<(PublicValues, ProgramExecutionReport)> { - // Simulate some computation time to avoid 0-ms durations - let execution_duration = Duration::from_millis(10); - tokio::time::sleep(execution_duration).await; - Ok(( - Vec::new(), - ProgramExecutionReport { - total_num_cycles: 100, - region_cycles: Default::default(), - execution_duration, - }, - )) - } - - pub(crate) async fn prove( - &self, - _: &Input, - proof_kind: ProofKind, - ) -> anyhow::Result<(PublicValues, Proof, ProgramProvingReport)> { - // Simulate some computation time to avoid 0-ms durations - tokio::time::sleep(self.mock_proving_time).await; - Ok(( - Vec::new(), - Proof::new(proof_kind, self.random_proof()), - ProgramProvingReport { - proving_time: self.mock_proving_time, - }, - )) - } - - pub(crate) async fn verify(&self, proof: &Proof) -> anyhow::Result { - // Simulate some computation time to avoid 0-ms durations - let verify_time = Duration::from_millis(10); - tokio::time::sleep(verify_time).await; - if proof.as_bytes().len() == self.mock_proof_size as usize { - Ok(Vec::new()) - } else { - anyhow::bail!("invalid proof") - } - } -} - -#[cfg(test)] -pub(crate) mod tests { - use std::{collections::HashMap, sync::Arc}; - - use metrics_exporter_prometheus::PrometheusBuilder; - use reqwest::Client; - use zkboost_types::ProgramID; - - use crate::{ - app::{AppState, zkVMInstance}, - mock::MockzkVM, - proof_service::ProofService, - }; - - /// Create an AppState with an optional mock program for testing. - pub(crate) fn mock_app_state(program_id: Option<&ProgramID>) -> AppState { - let http_client = Client::new(); - let mut proof_txs = HashMap::new(); - let mut programs = HashMap::new(); - - if let Some(program_id) = program_id { - let mock_proving_time_ms = 10; - let mock_proof_size = 32; - let zkvm = zkVMInstance::Mock(MockzkVM::new(mock_proving_time_ms, mock_proof_size)); - let (proof_service, proof_tx) = ProofService::new( - program_id.clone(), - zkvm.clone(), - http_client.clone(), - "http://localhost:3003/proofs".to_string(), - ); - - proof_service.start_service(); - - proof_txs.insert(program_id.clone(), proof_tx); - programs.insert(program_id.clone(), zkvm); - } - - let recorder = PrometheusBuilder::new().build_recorder(); - AppState { - programs: Arc::new(programs), - proof_txs: Arc::new(proof_txs), - metrics: recorder.handle(), - } - } -} diff --git a/crates/zkboost/server/src/proof_service.rs b/crates/zkboost/server/src/proof_service.rs deleted file mode 100644 index a794dce..0000000 --- a/crates/zkboost/server/src/proof_service.rs +++ /dev/null @@ -1,193 +0,0 @@ -//! Background proof generation service with webhook delivery. -//! -//! This module provides asynchronous proof generation that runs in background tasks. -//! When a proof request is received, it is queued and processed asynchronously. -//! Upon completion (success or failure), the result is POSTed to a configured webhook URL. - -use std::time::{Duration, Instant}; - -use ere_zkvm_interface::{Input, Proof, ProofKind}; -use reqwest::Client; -use tokio::sync::mpsc; -use tracing::{error, info, warn}; -use zkboost_types::{ProgramID, ProofGenId, ProofResult}; - -use crate::{app::zkVMInstance, metrics::record_prove}; - -/// Message sent to the proof service to request proof generation. -#[derive(Debug)] -pub(crate) struct ProofMessage { - /// Unique identifier for tracking this proof generation request. - pub proof_gen_id: ProofGenId, - /// Input data for the zkVM program execution. - pub input: Input, -} - -/// Background service that processes proof generation requests asynchronously. -/// -/// Each `ProofService` instance is associated with a specific program and runs -/// as a background task. It receives proof requests via an mpsc channel, -/// generates proofs using the configured zkVM instance, and delivers results -/// to a webhook URL with automatic retry on failure. -pub(crate) struct ProofService { - /// Identifier of the program this service generates proofs for. - program_id: ProgramID, - /// zkVM instance used for proof generation. - zkvm: zkVMInstance, - /// Channel receiver for incoming proof requests. - proof_rx: mpsc::Receiver, - /// HTTP client for webhook delivery. - http_client: Client, - /// URL to POST proof results to upon completion. - webhook_url: String, -} - -impl ProofService { - /// Creates a new proof service and returns the sender for submitting proof requests. - /// - /// The returned `mpsc::Sender` should be used to submit `ProofMessage`s for processing. - /// The channel has a buffer capacity of 128 messages. - pub(crate) fn new( - program_id: ProgramID, - zkvm: zkVMInstance, - http_client: Client, - webhook_url: String, - ) -> (Self, mpsc::Sender) { - let (proof_tx, proof_rx) = mpsc::channel(128); - - ( - Self { - program_id, - zkvm, - proof_rx, - http_client, - webhook_url, - }, - proof_tx, - ) - } - - /// Starts the background proof generation service. - /// - /// This consumes the service and spawns a background task that continuously - /// processes incoming proof requests until the channel is closed. - pub(crate) fn start_service(mut self) { - tokio::spawn(async move { - tracing::info!( - program_id = %self.program_id.0, - "Proof generation service started" - ); - - while let Some(msg) = self.proof_rx.recv().await { - self.process_proof(msg, &self.zkvm).await; - } - - tracing::warn!( - program_id = %self.program_id.0, - "Proof generation service ended" - ); - }); - } - - /// Processes a single proof generation request. - /// - /// Generates a compressed proof using the zkVM instance, records metrics, - /// and delivers the result to the webhook URL. - async fn process_proof(&self, msg: ProofMessage, zkvm: &zkVMInstance) { - let start = Instant::now(); - - let proof_gen_id = msg.proof_gen_id; - let program_id = self.program_id.clone(); - - let (public_values, proof, report, error) = zkvm - .prove(msg.input, ProofKind::Compressed) - .await - .map_err(|error| format!("Failed to generate proof: {error}")) - .and_then(|(public_values, proof, report)| match proof { - Proof::Compressed(proof) => Ok((public_values, proof, report, None)), - _ => Err(format!("Unexpected proof kind {:?}", proof.kind())), - }) - .unwrap_or_else(|error| { - ( - Default::default(), - Default::default(), - Default::default(), - Some(error), - ) - }); - let proving_time_ms = report.proving_time.as_millis(); - - record_prove(&program_id.0, error.is_none(), start.elapsed(), proof.len()); - - self.post_webhook(ProofResult { - proof_gen_id, - public_values, - proof, - proving_time_ms, - error, - }) - .await; - } - - /// Posts the proof result to the configured webhook URL with retry logic. - /// - /// Attempts up to 3 times with exponential backoff (1s, 2s delays between attempts). - /// Stops retrying early on client errors (4xx status codes). - async fn post_webhook(&self, proof_result: ProofResult) { - const MAX_ATTEMPT: u32 = 3; - - for attempt in 1..=MAX_ATTEMPT { - match self - .http_client - .post(&self.webhook_url) - .json(&proof_result) - .timeout(Duration::from_secs(10)) - .send() - .await - { - Ok(resp) if resp.status().is_success() => { - info!( - proof_gen_id = %proof_result.proof_gen_id, - attempt = attempt, - "Successfully pushed proof_result to webhook url" - ); - return; - } - Ok(resp) => { - let status = resp.status(); - let body = resp.text().await.unwrap_or_default(); - error!( - proof_gen_id = %proof_result.proof_gen_id, - attempt = attempt, - status = %status, - body = %body, - "webhook url rejected proof_result push" - ); - - if status.is_client_error() { - return; - } - } - Err(e) => { - warn!( - proof_gen_id = %proof_result.proof_gen_id, - attempt = attempt, - error = %e, - "Failed to push proof_result to webhook url" - ); - } - } - - if attempt < 3 { - let delay = Duration::from_secs(2u64.pow(attempt - 1)); - tokio::time::sleep(delay).await; - } - } - - error!( - proof_gen_id = %proof_result.proof_gen_id, - webhook_url = %self.webhook_url, - "Failed to push proof to webhook url after 3 attempts" - ); - } -} diff --git a/crates/zkboost/server/tests/stateless_validator/main.rs b/crates/zkboost/server/tests/stateless_validator/main.rs deleted file mode 100644 index 6c7f9af..0000000 --- a/crates/zkboost/server/tests/stateless_validator/main.rs +++ /dev/null @@ -1,376 +0,0 @@ -//! Integration tests for the zkboost-server HTTP API with stateless validator -//! program. - -#![allow(unused_crate_dependencies)] - -use std::{ - io, - path::{Path, PathBuf}, - time::{Duration, Instant}, -}; - -use anyhow::bail; -use axum::{Json, Router, extract::State, http::StatusCode, routing::post}; -use clap::Parser; -use ere_dockerized::zkVMKind; -use ere_zkvm_interface::ProverResource; -use nix::sys::{prctl, signal::Signal}; -use tempfile::tempdir; -use tokio::{process::Command, sync::mpsc, time::sleep}; -use tower_http::trace::TraceLayer; -use tracing::info; -use zkboost_client::zkboostClient; -use zkboost_ethereum_el_config::program::download_program; -use zkboost_ethereum_el_input::ElInput; -use zkboost_ethereum_el_types::ElKind; -use zkboost_server_config::{Config, zkVMConfig}; -use zkboost_types::ProofResult; - -use crate::utils::{ClientSession, DockerComposeGuard, ServerResources, fetch_empty_block}; - -mod utils; - -#[derive(Parser)] -struct Args { - /// Path to `zkboost-server` binary. - /// If not provided, `cargo run --release --bin zkboost-server` will be used. - #[arg(long)] - zkboost_server_bin: Option, - /// Execution layer client implementation (reth or ethrex) - #[arg(long, default_value = "reth")] - el: ElKind, - /// zkVM to use - #[arg(long)] - zkvm: zkVMKind, - /// Resource type for proving (cpu or gpu) - #[arg(long, ignore_case = true, default_value = "cpu", value_parser = ["cpu", "gpu"])] - resource: String, - /// RPC URL for generating test fixtures from a live blockchain. - /// If not provided, an empty block fixture will be used. - #[arg(long)] - rpc_url: Option, - /// Comma-separated HTTP headers for RPC requests e.g. `key1:value1,key2:value2` - #[arg(long)] - rpc_headers: Option, - /// Keep the temporary workspace directory for debugging - #[arg(long)] - keep_workspace: bool, - /// Skip proving - #[arg(long)] - skip_prove: bool, - /// Docker registry for Ere images - #[arg(env = "ERE_IMAGE_REGISTRY", default_value = "ghcr.io/eth-act/ere")] - ere_image_registry: String, - /// GitHub token for downloading artifacts from GitHub Actions. - /// Required when `ere-guests` dependency uses a git revision instead of a released tag. - #[arg(env = "GITHUB_TOKEN")] - github_token: Option, - /// Run the server using docker compose - #[arg(long)] - dockerized: bool, -} - -impl Args { - fn program_id(&self) -> String { - format!("{}-{}", self.el.as_str(), self.zkvm) - } -} - -/// Download program and generate config file. -async fn generate_config( - args: &Args, - workspace: &Path, - port: u16, - webhook_url: &str, -) -> anyhow::Result { - info!("Generating config..."); - - let program = download_program( - args.el, - args.zkvm, - args.github_token.as_deref(), - workspace.join("program"), - args.keep_workspace, - ) - .await?; - - let resource = match args.resource.to_lowercase().as_str() { - "cpu" => ProverResource::Cpu, - "gpu" => ProverResource::Gpu, - _ => bail!("Unsupported resource type: {}", args.resource), - }; - - let config = Config { - port, - webhook_url: webhook_url.to_string(), - zkvm: vec![zkVMConfig::Docker { - kind: args.zkvm, - resource, - program_id: args.program_id().into(), - program, - }], - }; - - let config_path = workspace.join("config.toml"); - tokio::fs::write(&config_path, config.to_toml()?).await?; - - info!("Successfully generated config"); - - Ok(config_path.to_string_lossy().to_string()) -} - -/// Start `zkboost-server` with stateless validator program. -async fn start_zkboost_server( - args: &Args, - config_path: &str, - zkboost_server_port: u16, -) -> anyhow::Result { - if args.dockerized { - start_zkboost_server_dockerized(config_path, zkboost_server_port).await - } else { - start_zkboost_server_raw(args, config_path, zkboost_server_port).await - } -} - -/// Start `zkboost-server` using docker compose. -async fn start_zkboost_server_dockerized( - config_path: &str, - zkboost_server_port: u16, -) -> anyhow::Result { - info!("Starting server via docker compose..."); - - let docker_dir = Path::new(env!("CARGO_MANIFEST_DIR")) - .parent() - .unwrap() - .parent() - .unwrap() - .parent() - .unwrap() - .join("docker"); - - let guard = DockerComposeGuard { - docker_dir: docker_dir.clone(), - }; - - let docker_config_path = docker_dir.join("config.toml"); - tokio::fs::copy(config_path, &docker_config_path).await?; - - let status = Command::new("docker") - .args(["compose", "up", "-d", "zkboost"]) - .current_dir(&docker_dir) - .status() - .await?; - - if !status.success() { - bail!("Failed to start docker compose"); - } - - let client = wait_for_server_ready(zkboost_server_port).await?; - Ok(ClientSession { - client, - _resources: ServerResources::Docker(guard), - }) -} - -/// Start `zkboost-server` directly using the binary or cargo. -async fn start_zkboost_server_raw( - args: &Args, - config_path: &str, - zkboost_server_port: u16, -) -> anyhow::Result { - info!("Starting server..."); - - // Start the zkboost server - let mut cmd; - match args.zkboost_server_bin.as_deref() { - Some(bin) => cmd = Command::new(bin), - None => { - cmd = Command::new("cargo"); - cmd.args(["run", "--release", "--bin", "zkboost-server", "--"]); - } - } - - // Set up the child process to receive SIGTERM when parent exits - unsafe { cmd.pre_exec(|| prctl::set_pdeathsig(Signal::SIGTERM).map_err(io::Error::other)) }; - - cmd.env("ERE_IMAGE_REGISTRY", &args.ere_image_registry) - .args(["--config", config_path]) - .spawn()?; - - let client = wait_for_server_ready(zkboost_server_port).await?; - Ok(ClientSession { - client, - _resources: ServerResources::Raw, - }) -} - -/// Wait for the server to be ready by polling the health endpoint. -async fn wait_for_server_ready(port: u16) -> anyhow::Result { - let client = zkboostClient::new(format!("http://localhost:{port}"))?; - let start = Instant::now(); - loop { - match client.health().await { - Ok(_) => break, - Err(_) if start.elapsed().as_secs() >= 300 => { - bail!("Server failed to start after 5 mins") - } - Err(_) => { - info!("Waiting for server to be ready..."); - sleep(Duration::from_secs(10)).await - } - } - } - - info!("Successfully started server"); - - Ok(client) -} - -#[tokio::main] -async fn main() -> anyhow::Result<()> { - tracing_subscriber::fmt() - .with_env_filter(tracing_subscriber::EnvFilter::from_default_env()) - .init(); - - let args = Args::parse(); - - let workspace = tempdir()?; - let workspace = if args.keep_workspace { - let path = workspace.keep(); - info!("Keep server workspace at {}", path.display()); - path - } else { - workspace.path().to_path_buf() - }; - - let zkboost_server_port = 3001; - - // Webhook url to receive proof results - let webhook_port = 3003; - let webhook_url = format!("http://127.0.0.1:{webhook_port}/webhook"); - - let config_path = generate_config(&args, &workspace, zkboost_server_port, &webhook_url).await?; - - let client = start_zkboost_server(&args, &config_path, zkboost_server_port).await?; - - let program_id = args.program_id(); - - let el_input = ElInput::new(fetch_empty_block(&workspace).await?); - let stdin = el_input.to_zkvm_input(args.el, true)?.stdin; - - // Execution - - info!("Requesting execution..."); - - let response = client.execute(&program_id, stdin.clone()).await?; - - assert_eq!(response.program_id.0, program_id); - assert_eq!( - el_input.expected_public_values(args.el, true)?.as_slice(), - response.public_values.as_slice(), - ); - info!( - "Execution time: {:?}", - Duration::from_millis(response.execution_time_ms as u64) - ); - - if args.skip_prove { - info!("Skip proving"); - return Ok(()); - } - - // Proving - - // Create channel for receiving proof results - let (proof_tx, mut proof_rx) = mpsc::channel::(1); - - let webhook_app = Router::new() - .route("/webhook", post(webhook_handler)) - .with_state(proof_tx) - .layer(TraceLayer::new_for_http()); - - let webhook_addr = format!("127.0.0.1:{webhook_port}"); - let listener = tokio::net::TcpListener::bind(&webhook_addr).await?; - info!("Webhook server listening on {webhook_addr}"); - - tokio::spawn(async move { - if let Err(e) = axum::serve(listener, webhook_app).await { - tracing::error!(error = %e, "Webhook server error"); - } - }); - - info!("Requesting proving..."); - - // Submit prove request - let response = client.prove(&program_id, stdin).await?; - let proof_gen_id = response.proof_gen_id.clone(); - - info!("Proof request submitted"); - info!("Waiting for proof {proof_gen_id} via webhook..."); - - // Wait for the webhook to receive the proof result - let (proof, public_values, proving_time_ms) = match proof_rx.recv().await { - Some(proof_result) => { - if proof_result.proof_gen_id == proof_gen_id { - if let Some(error) = &proof_result.error { - bail!("Proof generation failed: {}", error); - } - - info!("Proof completed"); - ( - proof_result.proof, - proof_result.public_values, - proof_result.proving_time_ms, - ) - } else { - bail!("Unexpected proof_gen_id {}", proof_result.proof_gen_id); - } - } - None => { - bail!("Webhook channel closed unexpectedly"); - } - }; - - assert_eq!( - el_input.expected_public_values(args.el, true)?.as_slice(), - public_values.as_slice(), - ); - info!( - "Proving time: {:?}, proof size: {} KiB", - Duration::from_millis(proving_time_ms as u64), - proof.len() as f64 / 1024f64, - ); - - // Verifying (valid proof) - - info!("Requesting verifying a valid proof..."); - - let response = client.verify(&program_id, proof.clone()).await?; - - assert_eq!(response.program_id.0, program_id); - assert!(response.verified); - assert_eq!( - el_input.expected_public_values(args.el, true)?.as_slice(), - response.public_values.as_slice(), - ); - info!("Successfully verified"); - - Ok(()) -} - -async fn webhook_handler( - State(tx): State>, - Json(proof_result): Json, -) -> Result { - info!( - proof_gen_id = %proof_result.proof_gen_id, - "Received proof result via webhook" - ); - - // Send the result through the channel - if tx.send(proof_result).await.is_err() { - tracing::warn!("Failed to send proof result - receiver dropped"); - } - - Ok(StatusCode::OK) -} diff --git a/crates/zkboost/server/tests/stateless_validator/utils.rs b/crates/zkboost/server/tests/stateless_validator/utils.rs deleted file mode 100644 index 367b4b3..0000000 --- a/crates/zkboost/server/tests/stateless_validator/utils.rs +++ /dev/null @@ -1,63 +0,0 @@ -use std::{ - path::{Path, PathBuf}, - process::Command as StdCommand, -}; - -use flate2::read::GzDecoder; -use tar::Archive; -use tokio::fs; -use tracing::info; -use zkboost_client::zkboostClient; -use zkboost_ethereum_el_input::StatelessInput; -use zkboost_ethereum_el_types::{ERE_GUESTS_REPO, ERE_GUESTS_VERSION}; - -pub(crate) struct DockerComposeGuard { - pub docker_dir: PathBuf, -} - -impl Drop for DockerComposeGuard { - fn drop(&mut self) { - info!("Stopping docker compose..."); - let _ = StdCommand::new("docker") - .args(["compose", "down"]) - .current_dir(&self.docker_dir) - .status(); - } -} - -pub(crate) enum ServerResources { - #[allow(dead_code)] - Docker(DockerComposeGuard), - Raw, -} - -pub(crate) struct ClientSession { - pub client: zkboostClient, - pub _resources: ServerResources, -} - -impl std::ops::Deref for ClientSession { - type Target = zkboostClient; - fn deref(&self) -> &Self::Target { - &self.client - } -} - -pub(crate) async fn fetch_empty_block(workspace: &Path) -> anyhow::Result { - let input_dir = workspace.join("input"); - fs::create_dir_all(&input_dir).await?; - - let fixture_url = format!( - "https://raw.githubusercontent.com/{ERE_GUESTS_REPO}/{}/crates/integration-tests/fixtures/block.tar.gz", - ERE_GUESTS_VERSION.as_str(), - ); - let response = reqwest::get(fixture_url).await?; - let content = response.bytes().await?; - let gz = GzDecoder::new(content.as_ref()); - Archive::new(gz).unpack(&input_dir)?; - - let fixture: serde_json::Value = - serde_json::from_slice(&fs::read(input_dir.join("block/empty_block.json")).await?)?; - - Ok(serde_json::from_value(fixture["stateless_input"].clone())?) -} diff --git a/crates/zkboost/types/Cargo.toml b/crates/zkboost/types/Cargo.toml deleted file mode 100644 index a15a67e..0000000 --- a/crates/zkboost/types/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "zkboost-types" -version.workspace = true -edition.workspace = true -rust-version.workspace = true - -[lints] -workspace = true - -[dependencies] -indexmap.workspace = true -serde = { workspace = true, features = ["derive"] } -serde_with = { workspace = true, features = ["base64"] } - -ere-zkvm-interface.workspace = true diff --git a/crates/zkboost/types/src/lib.rs b/crates/zkboost/types/src/lib.rs deleted file mode 100644 index 7a420c8..0000000 --- a/crates/zkboost/types/src/lib.rs +++ /dev/null @@ -1,223 +0,0 @@ -//! Shared type definitions for zkboost. -//! -//! This crate provides the request and response types used by both the zkboost server -//! and client for zkVM execution, proving, and verification operations -//! -//! ## Overview -//! -//! The types are organized around 4 main operations: -//! - Execute - Run zkVM programs without generating proofs -//! - Prove - Generate cryptographic proofs of program execution -//! - Verify - Verify proofs without re-execution -//! - Info - Query server hardware and system information -//! -//! All binary data (inputs, outputs, proofs) is serialized as base64 when transmitted over HTTP. - -#![cfg_attr(not(test), warn(unused_crate_dependencies))] - -use core::fmt::{self, Display}; - -pub use ere_zkvm_interface::PublicValues; -use indexmap::IndexMap; -use serde::{Deserialize, Serialize}; -use serde_with::{base64::Base64, serde_as}; - -/// Unique identifier for a zkVM program. -/// -/// This is a wrapper around a `String` that provides type safety for program identifiers. -/// Programs are identified by their unique ID when making requests to execute, prove, or verify. -#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize, Hash)] -#[serde(transparent)] -pub struct ProgramID(pub String); - -impl From for ProgramID { - fn from(s: String) -> Self { - ProgramID(s) - } -} - -impl From<&String> for ProgramID { - fn from(s: &String) -> Self { - ProgramID(s.to_string()) - } -} - -impl From<&str> for ProgramID { - fn from(s: &str) -> Self { - ProgramID(s.to_string()) - } -} - -impl Display for ProgramID { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.0) - } -} - -/// Unique identifier of the proof generation (UUID). -#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] -pub struct ProofGenId(pub String); - -impl Display for ProofGenId { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.0) - } -} - -/// Request to execute a zkVM program. -/// -/// This initiates program execution without generating a proof. Execution is faster than -/// proving and is useful for testing program logic and obtaining execution metrics. -#[serde_as] -#[derive(Debug, Serialize, Deserialize)] -pub struct ExecuteRequest { - /// The unique identifier of the program to execute. - pub program_id: ProgramID, - /// The input data for the program, encoded as base64 when serialized. - #[serde_as(as = "Base64")] - pub input: Vec, -} - -/// Response from executing a zkVM program. -/// -/// Contains the execution results including public outputs and performance metrics. -#[serde_as] -#[derive(Debug, Serialize, Deserialize)] -pub struct ExecuteResponse { - /// The unique identifier of the executed program. - pub program_id: ProgramID, - /// The public values output by the program, encoded as base64 when serialized. - #[serde_as(as = "Base64")] - pub public_values: PublicValues, - /// Total number of cycles for the entire execution. - pub total_num_cycles: u64, - /// Region-specific cycle counts, mapping region names to their cycle counts. - pub region_cycles: IndexMap, - /// Execution time in milliseconds. - pub execution_time_ms: u128, -} - -/// Request to generate a proof for a zkVM program execution. -/// -/// This runs the program and generates a cryptographic proof that the execution -/// was performed correctly. The proof can later be verified without re-executing the program. -#[serde_as] -#[derive(Debug, Serialize, Deserialize)] -pub struct ProveRequest { - /// The unique identifier of the program to prove. - pub program_id: ProgramID, - /// The input data for the program, encoded as base64 when serialized. - #[serde_as(as = "Base64")] - pub input: Vec, -} - -/// Response from generating a proof for a zkVM program execution. -/// -/// Returns immediately with a proof generation ID that will be attached when -/// posting the proof. -#[derive(Debug, Serialize, Deserialize)] -pub struct ProveResponse { - /// The unique identifier of the proof generation (UUID). - pub proof_gen_id: ProofGenId, -} - -/// Proof result send to webhook URL -#[serde_as] -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct ProofResult { - /// The unique identifier of the proof generation (UUID). - pub proof_gen_id: ProofGenId, - /// The public values output by the program, encoded as base64 when serialized. - #[serde_as(as = "Base64")] - pub public_values: PublicValues, - /// The generated cryptographic proof, encoded as base64 when serialized. - #[serde_as(as = "Base64")] - pub proof: Vec, - /// Proving time in milliseconds. - pub proving_time_ms: u128, - /// Error during proof generation. - pub error: Option, -} - -/// Request to verify a proof. -/// -/// Verifies that a proof is valid for the specified program without re-executing it. -/// Verification is much faster than proof generation. -#[serde_as] -#[derive(Debug, Serialize, Deserialize)] -pub struct VerifyRequest { - /// The unique identifier of the program that generated the proof. - pub program_id: ProgramID, - /// The proof to verify, encoded as base64 when serialized. - #[serde_as(as = "Base64")] - pub proof: Vec, -} - -/// Response from verifying a proof. -/// -/// Contains the verification result and extracted public values if successful. -#[serde_as] -#[derive(Debug, Serialize, Deserialize)] -pub struct VerifyResponse { - /// The unique identifier of the program. - pub program_id: ProgramID, - /// The public values extracted from the proof, encoded as base64 when serialized. - #[serde_as(as = "Base64")] - pub public_values: PublicValues, - /// Whether the proof verification succeeded. - pub verified: bool, - /// Human-readable reason for verification failure. Empty if `verified` is true. - pub failure_reason: String, -} - -/// Information about the server's hardware and operating system. -/// -/// Provides details about the compute environment where zkVM programs are executed. -#[derive(Debug, Serialize, Deserialize)] -pub struct ServerInfoResponse { - /// CPU information. - pub cpu: CpuInfo, - /// Memory information. - pub memory: MemoryInfo, - /// Operating system information. - pub os: OsInfo, - /// CPU architecture (e.g., "x86_64", "aarch64"). - pub architecture: String, - /// GPU information, or "No GPU detected" if none available. - pub gpu: String, -} - -/// CPU information for the server. -#[derive(Debug, Serialize, Deserialize)] -pub struct CpuInfo { - /// CPU model name. - pub model: String, - /// Number of physical CPU cores. - pub cores: usize, - /// CPU frequency in MHz. - pub frequency: u64, - /// CPU vendor (e.g., "GenuineIntel", "AuthenticAMD"). - pub vendor: String, -} - -/// Memory information for the server. -#[derive(Debug, Serialize, Deserialize)] -pub struct MemoryInfo { - /// Total system memory (formatted as human-readable string, e.g., "16.00 GB"). - pub total: String, - /// Available system memory (formatted as human-readable string). - pub available: String, - /// Used system memory (formatted as human-readable string). - pub used: String, -} - -/// Operating system information for the server. -#[derive(Debug, Serialize, Deserialize)] -pub struct OsInfo { - /// Operating system name (e.g., "Linux", "macOS"). - pub name: String, - /// Operating system version. - pub version: String, - /// Kernel version. - pub kernel: String, -} diff --git a/docker/Dockerfile.zkboost-server b/docker/Dockerfile similarity index 65% rename from docker/Dockerfile.zkboost-server rename to docker/Dockerfile index d4ed9f1..e82669e 100644 --- a/docker/Dockerfile.zkboost-server +++ b/docker/Dockerfile @@ -1,4 +1,4 @@ -FROM rust:1.88.0-bookworm AS builder +FROM rust:1.91.0-bookworm AS builder WORKDIR /app @@ -11,8 +11,9 @@ COPY . . RUN --mount=type=cache,sharing=locked,target=/app/target/ \ --mount=type=cache,sharing=locked,target=/usr/local/cargo/git/db \ --mount=type=cache,sharing=locked,target=/usr/local/cargo/registry/ \ - cargo build --release --bin zkboost-server && \ - cp /app/target/release/zkboost-server /app/zkboost-server + cargo build --release --bin zkboost-server --bin mock-zkattestor && \ + cp /app/target/release/zkboost-server /app/zkboost-server && \ + cp /app/target/release/mock-zkattestor /app/mock-zkattestor FROM debian:bookworm-slim @@ -25,10 +26,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ curl \ && apt-get clean && rm -rf /var/lib/apt/lists/* -# Install docker cli (required to create dockerized zkVM server container) -RUN curl -fsSL "https://download.docker.com/linux/static/stable/$(uname -m)/docker-29.1.5.tgz" \ - | tar xz --strip-components=1 -C /usr/local/bin docker/docker - COPY --from=builder /app/zkboost-server /usr/local/bin/zkboost-server +COPY --from=builder /app/mock-zkattestor /usr/local/bin/mock-zkattestor ENTRYPOINT ["/usr/local/bin/zkboost-server"] diff --git a/docker/Dockerfile.execution-witness-sentry b/docker/Dockerfile.execution-witness-sentry deleted file mode 100644 index 108f59e..0000000 --- a/docker/Dockerfile.execution-witness-sentry +++ /dev/null @@ -1,30 +0,0 @@ -FROM rust:1.88.0-bookworm AS builder - -WORKDIR /app - -RUN apt-get update && apt-get install -y --no-install-recommends \ - libclang-dev \ - && apt-get clean && rm -rf /var/lib/apt/lists/* - -COPY . . - -RUN --mount=type=cache,sharing=locked,target=/app/target/ \ - --mount=type=cache,sharing=locked,target=/usr/local/cargo/git/db \ - --mount=type=cache,sharing=locked,target=/usr/local/cargo/registry/ \ - cargo build --release --bin execution-witness-sentry && \ - cp /app/target/release/execution-witness-sentry /app/execution-witness-sentry - -FROM debian:bookworm-slim - -WORKDIR /app - -# Install runtime dependencies -RUN apt-get update && apt-get install -y --no-install-recommends \ - libssl3 \ - ca-certificates \ - curl \ - && apt-get clean && rm -rf /var/lib/apt/lists/* - -COPY --from=builder /app/execution-witness-sentry /usr/local/bin/execution-witness-sentry - -ENTRYPOINT ["/usr/local/bin/execution-witness-sentry"] diff --git a/docker/example/mock-zkattestor/config/zkboost-server.toml b/docker/example/mock-zkattestor/config/zkboost-server.toml new file mode 100644 index 0000000..de44e38 --- /dev/null +++ b/docker/example/mock-zkattestor/config/zkboost-server.toml @@ -0,0 +1,13 @@ +port = 3000 +el_endpoint = "http://host.docker.internal:32003" + +[[zkvm]] +kind = "external" +endpoint = "http://ethrex-zisk:3000" +proof_type = "ethrex-zisk" + +[[zkvm]] +kind = "mock" +mock_proving_time_ms = 5000 +mock_proof_size = 1024 +proof_type = "reth-zisk" diff --git a/docker/example/mock-zkattestor/docker-compose.yml b/docker/example/mock-zkattestor/docker-compose.yml new file mode 100644 index 0000000..0af06fd --- /dev/null +++ b/docker/example/mock-zkattestor/docker-compose.yml @@ -0,0 +1,45 @@ +services: + zkboost-server: + image: zkboost-server:local + build: + context: ../../.. + dockerfile: ./docker/Dockerfile + command: ["--config", "/app/config.toml"] + volumes: + - ./config/zkboost-server.toml:/app/config.toml:ro + networks: + - mock-zkattestor + extra_hosts: + - "host.docker.internal:host-gateway" + environment: + - RUST_LOG=info,zkboost=debug + restart: unless-stopped + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:3000/health"] + start_period: 1s + start_interval: 1s + + mock-zkattestor: + image: zkboost-server:local + entrypoint: ["/usr/local/bin/mock-zkattestor"] + command: + - "--cl-endpoint" + - "http://host.docker.internal:33001" + - "--zkboost-endpoint" + - "http://zkboost-server:3000" + - "--proof-types" + - "ethrex-zisk,reth-zisk" + networks: + - mock-zkattestor + extra_hosts: + - "host.docker.internal:host-gateway" + environment: + - RUST_LOG=info,zkboost=debug + restart: unless-stopped + depends_on: + zkboost-server: + condition: service_healthy + +networks: + mock-zkattestor: + name: mock-zkattestor diff --git a/docker/example/mock-zkattestor/network_params.yaml b/docker/example/mock-zkattestor/network_params.yaml new file mode 100644 index 0000000..c568e00 --- /dev/null +++ b/docker/example/mock-zkattestor/network_params.yaml @@ -0,0 +1,18 @@ +participants: + - el_type: reth + cl_type: lighthouse + count: 3 +network_params: + seconds_per_slot: 12 +global_log_level: debug +snooper_enabled: false +additional_services: + - dora + - prometheus_grafana +port_publisher: + el: + enabled: true + public_port_start: 32000 + cl: + enabled: true + public_port_start: 33000 diff --git a/docker/example/mocknet/config/execution-witness-sentry.toml b/docker/example/mocknet/config/execution-witness-sentry.toml deleted file mode 100644 index 258bb1a..0000000 --- a/docker/example/mocknet/config/execution-witness-sentry.toml +++ /dev/null @@ -1,32 +0,0 @@ -output_dir = "." -chain = "local" -retain = 10 -num_proofs = 2 - -[proof_engine] -url = "http://zkboost-server:3001" -proof_types = ["ethrex-zisk", "reth-zisk"] -webhook_port = 3003 - -[[el_endpoints]] -name = "el-1-reth-lighthouse" -url = "http://host.docker.internal:32003" -ws_url = "ws://host.docker.internal:32004" - -# Non-zkvm CL for head event subscription -[[cl_endpoints]] -name = "cl-1-lighthouse-reth" -url = "http://host.docker.internal:33001/" - -# zkvm-enabled CLs for proof submission -[[cl_endpoints]] -name = "cl-4-lighthouse-geth" -url = "http://host.docker.internal:33022/" - -[[cl_endpoints]] -name = "cl-5-lighthouse-geth" -url = "http://host.docker.internal:33029/" - -[[cl_endpoints]] -name = "cl-6-lighthouse-geth" -url = "http://host.docker.internal:33036/" diff --git a/docker/example/mocknet/config/zkboost-server.toml b/docker/example/mocknet/config/zkboost-server.toml deleted file mode 100644 index 2958efa..0000000 --- a/docker/example/mocknet/config/zkboost-server.toml +++ /dev/null @@ -1,12 +0,0 @@ -port = 3001 -webhook_url = "http://execution-witness-sentry:3003/proofs" - -[[zkvm]] -mock_proving_time_ms = 1000 -mock_proof_size = 1024 -program_id = "ethrex-zisk" - -[[zkvm]] -mock_proving_time_ms = 1000 -mock_proof_size = 1024 -program_id = "reth-zisk" diff --git a/docker/example/mocknet/docker-compose.yml b/docker/example/mocknet/docker-compose.yml deleted file mode 100644 index c8e1024..0000000 --- a/docker/example/mocknet/docker-compose.yml +++ /dev/null @@ -1,40 +0,0 @@ -services: - zkboost-server: - image: zkboost-server:local - build: - context: ../../.. - dockerfile: ./docker/Dockerfile.zkboost-server - command: ["--config", "/app/config.toml"] - volumes: - - ./config/zkboost-server.toml:/app/config.toml:ro - networks: - - mocknet-ews - environment: - - RUST_LOG=info,zkboost=debug - restart: unless-stopped - healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:3001/health"] - - execution-witness-sentry: - image: execution-witness-sentry:local - build: - context: ../../.. - dockerfile: ./docker/Dockerfile.execution-witness-sentry - command: ["--config", "/app/config.toml"] - volumes: - - ./config/execution-witness-sentry.toml:/app/config.toml:ro - networks: - - mocknet-ews - extra_hosts: - - "host.docker.internal:host-gateway" - ports: - - "3003:3003" - environment: - - RUST_LOG=info,execution_witness_sentry=debug - restart: unless-stopped - healthcheck: - test: ["CMD-SHELL", "ps aux | grep -v grep | grep execution-witness-sentry"] - -networks: - mocknet-ews: - name: mocknet-ews diff --git a/docker/example/observability/config.toml b/docker/example/observability/config.toml index bc4cbda..d707fda 100644 --- a/docker/example/observability/config.toml +++ b/docker/example/observability/config.toml @@ -1,9 +1,14 @@ -# zkboost server configuration -# See crates/zkboost/server-config/src/config.rs for schema +port = 3000 +el_endpoint = "http://host.docker.internal:32003" -# Add zkVM programs here. Example: -# [[zkvm]] -# kind = "sp1" -# resource = { kind = "cpu" } -# program_id = "my-program" -# program = "/path/to/elf" +[[zkvm]] +kind = "mock" +mock_proving_time_ms = 5000 +mock_proof_size = 1024 +proof_type = "ethrex-zisk" + +[[zkvm]] +kind = "mock" +mock_proving_time_ms = 5000 +mock_proof_size = 1024 +proof_type = "reth-zisk" diff --git a/docker/example/observability/docker-compose.yml b/docker/example/observability/docker-compose.yml index 0dd724b..c9cac14 100644 --- a/docker/example/observability/docker-compose.yml +++ b/docker/example/observability/docker-compose.yml @@ -6,9 +6,9 @@ services: zkboost: build: context: ../../.. # Context is the project root (one level up) - dockerfile: docker/Dockerfile.zkboost-server # Path to Dockerfile _from_ the context + dockerfile: docker/Dockerfile # Path to Dockerfile _from_ the context ports: - - "3001:3001" + - "3000:3000" networks: - zkboost_network volumes: diff --git a/docker/example/observability/grafana/dashboards/zkboost.json b/docker/example/observability/grafana/dashboards/zkboost.json index 8bb2a3c..0b9ea90 100644 --- a/docker/example/observability/grafana/dashboards/zkboost.json +++ b/docker/example/observability/grafana/dashboards/zkboost.json @@ -445,8 +445,8 @@ "pluginVersion": "10.0.0", "targets": [ { - "expr": "sum(rate(zkboost_prove_total[$__rate_interval])) by (program_id, status)", - "legendFormat": "{{program_id}} ({{status}})", + "expr": "sum(rate(zkboost_prove_total[$__rate_interval])) by (proof_type, status)", + "legendFormat": "{{proof_type}} ({{status}})", "refId": "A" } ], @@ -494,18 +494,18 @@ "pluginVersion": "10.0.0", "targets": [ { - "expr": "histogram_quantile(0.50, sum(rate(zkboost_prove_duration_seconds_bucket[$__rate_interval])) by (le, program_id))", - "legendFormat": "{{program_id}} p50", + "expr": "histogram_quantile(0.50, sum(rate(zkboost_prove_duration_seconds_bucket[$__rate_interval])) by (le, proof_type))", + "legendFormat": "{{proof_type}} p50", "refId": "A" }, { - "expr": "histogram_quantile(0.95, sum(rate(zkboost_prove_duration_seconds_bucket[$__rate_interval])) by (le, program_id))", - "legendFormat": "{{program_id}} p95", + "expr": "histogram_quantile(0.95, sum(rate(zkboost_prove_duration_seconds_bucket[$__rate_interval])) by (le, proof_type))", + "legendFormat": "{{proof_type}} p95", "refId": "B" }, { - "expr": "histogram_quantile(0.99, sum(rate(zkboost_prove_duration_seconds_bucket[$__rate_interval])) by (le, program_id))", - "legendFormat": "{{program_id}} p99", + "expr": "histogram_quantile(0.99, sum(rate(zkboost_prove_duration_seconds_bucket[$__rate_interval])) by (le, proof_type))", + "legendFormat": "{{proof_type}} p99", "refId": "C" } ], @@ -553,13 +553,13 @@ "pluginVersion": "10.0.0", "targets": [ { - "expr": "histogram_quantile(0.50, sum(rate(zkboost_prove_proof_bytes_bucket[$__rate_interval])) by (le, program_id))", - "legendFormat": "{{program_id}} p50", + "expr": "histogram_quantile(0.50, sum(rate(zkboost_prove_proof_bytes_bucket[$__rate_interval])) by (le, proof_type))", + "legendFormat": "{{proof_type}} p50", "refId": "A" }, { - "expr": "histogram_quantile(0.95, sum(rate(zkboost_prove_proof_bytes_bucket[$__rate_interval])) by (le, program_id))", - "legendFormat": "{{program_id}} p95", + "expr": "histogram_quantile(0.95, sum(rate(zkboost_prove_proof_bytes_bucket[$__rate_interval])) by (le, proof_type))", + "legendFormat": "{{proof_type}} p95", "refId": "B" } ], @@ -569,176 +569,6 @@ { "collapsed": false, "gridPos": { "h": 1, "w": 24, "x": 0, "y": 31 }, - "id": 103, - "panels": [], - "title": "Execute Operations", - "type": "row" - }, - { - "datasource": { "type": "prometheus", "uid": "${datasource}" }, - "fieldConfig": { - "defaults": { - "color": { "mode": "palette-classic" }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 10, - "gradientMode": "none", - "hideFrom": { "legend": false, "tooltip": false, "viz": false }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { "type": "linear" }, - "showPoints": "never", - "spanNulls": false, - "stacking": { "group": "A", "mode": "none" }, - "thresholdsStyle": { "mode": "off" } - }, - "mappings": [], - "thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }] }, - "unit": "ops" - }, - "overrides": [] - }, - "gridPos": { "h": 8, "w": 8, "x": 0, "y": 32 }, - "id": 13, - "options": { - "legend": { "calcs": ["sum"], "displayMode": "table", "placement": "bottom", "showLegend": true }, - "tooltip": { "mode": "multi", "sort": "desc" } - }, - "pluginVersion": "10.0.0", - "targets": [ - { - "expr": "sum(rate(zkboost_execute_total[$__rate_interval])) by (program_id, status)", - "legendFormat": "{{program_id}} ({{status}})", - "refId": "A" - } - ], - "title": "Execute Operations Rate", - "type": "timeseries" - }, - { - "datasource": { "type": "prometheus", "uid": "${datasource}" }, - "fieldConfig": { - "defaults": { - "color": { "mode": "palette-classic" }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 10, - "gradientMode": "none", - "hideFrom": { "legend": false, "tooltip": false, "viz": false }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { "type": "linear" }, - "showPoints": "never", - "spanNulls": false, - "stacking": { "group": "A", "mode": "none" }, - "thresholdsStyle": { "mode": "off" } - }, - "mappings": [], - "thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }] }, - "unit": "s" - }, - "overrides": [] - }, - "gridPos": { "h": 8, "w": 8, "x": 8, "y": 32 }, - "id": 14, - "options": { - "legend": { "calcs": ["mean", "max"], "displayMode": "table", "placement": "bottom", "showLegend": true }, - "tooltip": { "mode": "multi", "sort": "desc" } - }, - "pluginVersion": "10.0.0", - "targets": [ - { - "expr": "histogram_quantile(0.50, sum(rate(zkboost_execute_duration_seconds_bucket[$__rate_interval])) by (le, program_id))", - "legendFormat": "{{program_id}} p50", - "refId": "A" - }, - { - "expr": "histogram_quantile(0.95, sum(rate(zkboost_execute_duration_seconds_bucket[$__rate_interval])) by (le, program_id))", - "legendFormat": "{{program_id}} p95", - "refId": "B" - }, - { - "expr": "histogram_quantile(0.99, sum(rate(zkboost_execute_duration_seconds_bucket[$__rate_interval])) by (le, program_id))", - "legendFormat": "{{program_id}} p99", - "refId": "C" - } - ], - "title": "Execute Duration", - "type": "timeseries" - }, - { - "datasource": { "type": "prometheus", "uid": "${datasource}" }, - "fieldConfig": { - "defaults": { - "color": { "mode": "palette-classic" }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "drawStyle": "line", - "fillOpacity": 10, - "gradientMode": "none", - "hideFrom": { "legend": false, "tooltip": false, "viz": false }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { "type": "linear" }, - "showPoints": "never", - "spanNulls": false, - "stacking": { "group": "A", "mode": "none" }, - "thresholdsStyle": { "mode": "off" } - }, - "mappings": [], - "thresholds": { "mode": "absolute", "steps": [{ "color": "green", "value": null }] }, - "unit": "short" - }, - "overrides": [] - }, - "gridPos": { "h": 8, "w": 8, "x": 16, "y": 32 }, - "id": 15, - "options": { - "legend": { "calcs": ["mean", "max"], "displayMode": "table", "placement": "bottom", "showLegend": true }, - "tooltip": { "mode": "multi", "sort": "desc" } - }, - "pluginVersion": "10.0.0", - "targets": [ - { - "expr": "histogram_quantile(0.50, sum(rate(zkboost_execute_cycles_total_bucket[$__rate_interval])) by (le, program_id))", - "legendFormat": "{{program_id}} p50", - "refId": "A" - }, - { - "expr": "histogram_quantile(0.95, sum(rate(zkboost_execute_cycles_total_bucket[$__rate_interval])) by (le, program_id))", - "legendFormat": "{{program_id}} p95", - "refId": "B" - } - ], - "title": "Execution Cycles", - "type": "timeseries" - }, - { - "collapsed": false, - "gridPos": { "h": 1, "w": 24, "x": 0, "y": 40 }, "id": 104, "panels": [], "title": "Verify Operations", @@ -776,7 +606,7 @@ }, "overrides": [] }, - "gridPos": { "h": 8, "w": 12, "x": 0, "y": 41 }, + "gridPos": { "h": 8, "w": 12, "x": 0, "y": 32 }, "id": 16, "options": { "legend": { "calcs": ["sum"], "displayMode": "table", "placement": "bottom", "showLegend": true }, @@ -785,8 +615,8 @@ "pluginVersion": "10.0.0", "targets": [ { - "expr": "sum(rate(zkboost_verify_total[$__rate_interval])) by (program_id, verified)", - "legendFormat": "{{program_id}} (verified={{verified}})", + "expr": "sum(rate(zkboost_verify_total[$__rate_interval])) by (proof_type, verified)", + "legendFormat": "{{proof_type}} (verified={{verified}})", "refId": "A" } ], @@ -825,7 +655,7 @@ }, "overrides": [] }, - "gridPos": { "h": 8, "w": 12, "x": 12, "y": 41 }, + "gridPos": { "h": 8, "w": 12, "x": 12, "y": 32 }, "id": 17, "options": { "legend": { "calcs": ["mean", "max"], "displayMode": "table", "placement": "bottom", "showLegend": true }, @@ -834,18 +664,18 @@ "pluginVersion": "10.0.0", "targets": [ { - "expr": "histogram_quantile(0.50, sum(rate(zkboost_verify_duration_seconds_bucket[$__rate_interval])) by (le, program_id))", - "legendFormat": "{{program_id}} p50", + "expr": "histogram_quantile(0.50, sum(rate(zkboost_verify_duration_seconds_bucket[$__rate_interval])) by (le, proof_type))", + "legendFormat": "{{proof_type}} p50", "refId": "A" }, { - "expr": "histogram_quantile(0.95, sum(rate(zkboost_verify_duration_seconds_bucket[$__rate_interval])) by (le, program_id))", - "legendFormat": "{{program_id}} p95", + "expr": "histogram_quantile(0.95, sum(rate(zkboost_verify_duration_seconds_bucket[$__rate_interval])) by (le, proof_type))", + "legendFormat": "{{proof_type}} p95", "refId": "B" }, { - "expr": "histogram_quantile(0.99, sum(rate(zkboost_verify_duration_seconds_bucket[$__rate_interval])) by (le, program_id))", - "legendFormat": "{{program_id}} p99", + "expr": "histogram_quantile(0.99, sum(rate(zkboost_verify_duration_seconds_bucket[$__rate_interval])) by (le, proof_type))", + "legendFormat": "{{proof_type}} p99", "refId": "C" } ], diff --git a/docker/example/observability/prometheus/prometheus.yml b/docker/example/observability/prometheus/prometheus.yml index c1fc819..41d68bc 100644 --- a/docker/example/observability/prometheus/prometheus.yml +++ b/docker/example/observability/prometheus/prometheus.yml @@ -5,5 +5,5 @@ global: scrape_configs: - job_name: 'zkboost' static_configs: - - targets: ['zkboost:3001'] + - targets: ['zkboost:3000'] metrics_path: '/metrics' diff --git a/docker/example/testnet/config/execution-witness-sentry.toml b/docker/example/testnet/config/execution-witness-sentry.toml deleted file mode 100644 index 258bb1a..0000000 --- a/docker/example/testnet/config/execution-witness-sentry.toml +++ /dev/null @@ -1,32 +0,0 @@ -output_dir = "." -chain = "local" -retain = 10 -num_proofs = 2 - -[proof_engine] -url = "http://zkboost-server:3001" -proof_types = ["ethrex-zisk", "reth-zisk"] -webhook_port = 3003 - -[[el_endpoints]] -name = "el-1-reth-lighthouse" -url = "http://host.docker.internal:32003" -ws_url = "ws://host.docker.internal:32004" - -# Non-zkvm CL for head event subscription -[[cl_endpoints]] -name = "cl-1-lighthouse-reth" -url = "http://host.docker.internal:33001/" - -# zkvm-enabled CLs for proof submission -[[cl_endpoints]] -name = "cl-4-lighthouse-geth" -url = "http://host.docker.internal:33022/" - -[[cl_endpoints]] -name = "cl-5-lighthouse-geth" -url = "http://host.docker.internal:33029/" - -[[cl_endpoints]] -name = "cl-6-lighthouse-geth" -url = "http://host.docker.internal:33036/" diff --git a/docker/example/testnet/config/zkboost-server.toml b/docker/example/testnet/config/zkboost-server.toml index e8c7502..f5eefc4 100644 --- a/docker/example/testnet/config/zkboost-server.toml +++ b/docker/example/testnet/config/zkboost-server.toml @@ -1,10 +1,12 @@ -port = 3001 -webhook_url = "http://execution-witness-sentry:3003/proofs" +port = 3000 +el_endpoint = "http://host.docker.internal:32003" [[zkvm]] +kind = "external" endpoint = "http://ethrex-zisk:3000" -program_id = "ethrex-zisk" +proof_type = "ethrex-zisk" [[zkvm]] +kind = "external" endpoint = "http://reth-zisk:3000" -program_id = "reth-zisk" +proof_type = "reth-zisk" diff --git a/docker/example/testnet/docker-compose.yml b/docker/example/testnet/docker-compose.yml index f7bfa29..555bbd7 100644 --- a/docker/example/testnet/docker-compose.yml +++ b/docker/example/testnet/docker-compose.yml @@ -5,17 +5,16 @@ services: - /bin/sh - -c - | - apk add --no-cache curl - if [ ! -f /programs/stateless-validator-ethrex-zisk ] || [ ! -f /programs/stateless-validator-reth-zisk ]; then - echo "Downloading stateless-validator binaries..." - curl -fsSL "https://github.com/eth-act/ere-guests/releases/download/v0.4.0/stateless-validator-ethrex-zisk" -o /programs/stateless-validator-ethrex-zisk - curl -fsSL "https://github.com/eth-act/ere-guests/releases/download/v0.4.0/stateless-validator-reth-zisk" -o /programs/stateless-validator-reth-zisk - echo "Download complete." - else + if [ -f /programs/stateless-validator-ethrex-zisk ] && [ -f /programs/stateless-validator-reth-zisk ]; then echo "Binaries already exist, skipping download." + exit 0 fi + apk add --no-cache curl minisign bash + bash /scripts/download-ere-guest.sh --tag v0.6.0 --guest stateless-validator-ethrex-zisk --output-dir /programs + bash /scripts/download-ere-guest.sh --tag v0.6.0 --guest stateless-validator-reth-zisk --output-dir /programs volumes: - programs:/programs + - ../../../scripts/download-ere-guest.sh:/scripts/download-ere-guest.sh:ro ethrex-zisk: image: ghcr.io/eth-act/ere/ere-server-zisk:0.3.0-cuda @@ -63,7 +62,7 @@ services: image: zkboost-server:local build: context: ../../.. - dockerfile: ./docker/Dockerfile.zkboost-server + dockerfile: ./docker/Dockerfile command: ["--config", "/app/config.toml"] depends_on: ethrex-zisk: @@ -74,35 +73,19 @@ services: - ./config/zkboost-server.toml:/app/config.toml:ro networks: - testnet-ews - environment: - - RUST_LOG=info,zkboost=debug - restart: unless-stopped - healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:3001/health"] - - execution-witness-sentry: - image: execution-witness-sentry:local - build: - context: ../../.. - dockerfile: ./docker/Dockerfile.execution-witness-sentry - command: ["--config", "/app/config.toml"] - volumes: - - ./config/execution-witness-sentry.toml:/app/config.toml:ro - networks: - - testnet-ews extra_hosts: - "host.docker.internal:host-gateway" - ports: - - "3003:3003" environment: - - RUST_LOG=info,execution_witness_sentry=debug + - RUST_LOG=info,zkboost=debug restart: unless-stopped healthcheck: - test: ["CMD-SHELL", "ps aux | grep -v grep | grep execution-witness-sentry"] + test: ["CMD", "curl", "-f", "http://localhost:3000/health"] + start_period: 1s + start_interval: 1s volumes: programs: - name: programs-v0.4.0 + name: programs-v0.6.0 networks: testnet-ews: diff --git a/scripts/download-ere-guest.sh b/scripts/download-ere-guest.sh new file mode 100755 index 0000000..beec195 --- /dev/null +++ b/scripts/download-ere-guest.sh @@ -0,0 +1,82 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Download and verify a guest program from eth-act/ere-guests releases. +# +# Usage: ./download-ere-guest.sh --tag --guest --output-dir +# Example: ./download-ere-guest.sh --tag v0.6.0 --guest reth-sp1 --output-dir ./programs/ + +PUB_KEY="RWTsNA0kZFhw19A26aujYun4hv4RraCnEYDehrgEG6NnCjmjkr9/+KGy" + +usage() { + echo "Usage: $0 --tag --guest --output-dir " + echo "" + echo "Options:" + echo " --tag Release tag (e.g. v0.6.0)" + echo " --guest Guest program name (e.g. reth-sp1)" + echo " --output-dir Directory to save the downloaded program" + exit 1 +} + +RELEASE_TAG="" +GUEST_NAME="" +OUTPUT_DIR="" + +while [[ $# -gt 0 ]]; do + case "$1" in + --tag) + RELEASE_TAG="$2" + shift 2 + ;; + --guest) + GUEST_NAME="$2" + shift 2 + ;; + --output-dir) + OUTPUT_DIR="$2" + shift 2 + ;; + --help|-h) + usage + ;; + *) + echo "Error: unknown option '$1'" + usage + ;; + esac +done + +if [[ -z "${RELEASE_TAG}" || -z "${GUEST_NAME}" || -z "${OUTPUT_DIR}" ]]; then + echo "Error: all flags are required." + usage +fi + +REPO="eth-act/ere-guests" +BASE_URL="https://github.com/${REPO}/releases/download/${RELEASE_TAG}" +PROGRAM_URL="${BASE_URL}/${GUEST_NAME}" +SIG_URL="${BASE_URL}/${GUEST_NAME}.minisig" + +mkdir -p "${OUTPUT_DIR}" + +PROGRAM_PATH="${OUTPUT_DIR}/${GUEST_NAME}" +SIG_PATH="${OUTPUT_DIR}/${GUEST_NAME}.minisig" + +echo "Downloading ${GUEST_NAME} from ${PROGRAM_URL}..." +curl -fSL -o "${PROGRAM_PATH}" "${PROGRAM_URL}" + +echo "Downloading signature from ${SIG_URL}..." +curl -fSL -o "${SIG_PATH}" "${SIG_URL}" + +echo "Verifying signature..." +if ! command -v minisign &> /dev/null; then + echo "Error: minisign is not installed." + echo "Install: https://jedisct1.github.io/minisign/" + exit 1 +fi + +minisign -Vm "${PROGRAM_PATH}" -x "${SIG_PATH}" -P "${PUB_KEY}" + +echo "Verified OK: ${PROGRAM_PATH}" + +# Clean up signature file +rm -f "${SIG_PATH}"