diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0e592c395..fdb1fc629 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,107 +15,51 @@ concurrency: jobs: build-test: - name: Build and test native + name: Build and test runs-on: ubuntu-latest timeout-minutes: 120 + strategy: + matrix: + VERSIONS: [ + {name: native, toolchain: nightly-2024-04-17}, + {name: sp1, toolchain: nightly-2024-04-17}, + {name: risc0, toolchain: stable}, + {name: sgx, toolchain: stable}, + ] env: - TARGET: native - CI: 1 - MOCK: 1 - steps: - - uses: actions/checkout@v4 - with: - submodules: recursive - - uses: actions-rs/toolchain@v1 - with: - toolchain: nightly-2024-04-17 - profile: minimal - - name: Install cargo-binstall - uses: cargo-bins/cargo-binstall@v1.6.4 - - name: Install native - run: make install - - name: Build native prover - run: make build - - name: Test native prover - run: make test - - name: Build with tracer - run: cargo build --features tracer - - build-test-risc0: - name: Build and test risc0 - runs-on: ubuntu-latest - timeout-minutes: 120 - env: - TARGET: risc0 - CI: 1 - MOCK: 1 - steps: - - uses: actions/checkout@v4 - with: - submodules: recursive - - uses: actions-rs/toolchain@v1 - with: - toolchain: stable - profile: minimal - - name: Install cargo-binstall - uses: cargo-bins/cargo-binstall@v1.6.4 - - uses: risc0/risc0/.github/actions/sccache@release-0.19 - - name: Install risc0 - run: make install - - name: Build risc0 prover - run: make build - - name: Test risc0 prover - run: make test - - build-test-sp1: - name: Build and test sp1 - runs-on: ubuntu-latest - timeout-minutes: 120 - env: - TARGET: sp1 - CI: 1 - MOCK: 1 - steps: - - uses: actions/checkout@v4 - with: - submodules: recursive - - uses: actions-rs/toolchain@v1 - with: - toolchain: nightly-2024-04-17 - profile: minimal - - name: Install cargo-binstall - uses: cargo-bins/cargo-binstall@v1.6.4 - - name: Install sp1 - run: make install - - name: Build sp1 prover - run: make build - - name: Test sp1 prover - run: make test - - build-test-sgx: - name: Build and test sgx - runs-on: ubuntu-latest - timeout-minutes: 120 - env: - TARGET: sgx + TARGET: ${{ matrix.VERSIONS.name }} CI: 1 MOCK: 1 + steps: - uses: actions/checkout@v4 with: submodules: recursive + - uses: actions-rs/toolchain@v1 with: - toolchain: stable + toolchain: ${{ matrix.VERSIONS.toolchain }} profile: minimal + - name: Install cargo-binstall uses: cargo-bins/cargo-binstall@v1.6.4 - - name: Install sgx + + - name: Setup sccache + if: ${{ matrix.VERSIONS.name }} == risc0 + uses: risc0/risc0/.github/actions/sccache@release-0.19 + + - name: Install ${{ matrix.VERSIONS.name }} run: make install - - name: Build sgx prover + + - name: Build ${{ matrix.VERSIONS.name }} prover run: make build - - name: Test sgx prover + + - name: Test ${{ matrix.VERSIONS.name }} prover run: make test + + - name: Build with tracer + if: ${{ matrix.VERSIONS.name }} == native + run: cargo build -F tracer build-test-sgx-hardware: name: Build and test sgx in hardware @@ -125,20 +69,26 @@ jobs: TARGET: sgx CI: 1 EDMM: 0 + steps: - uses: actions/checkout@v4 with: submodules: recursive + - uses: actions-rs/toolchain@v1 with: toolchain: stable profile: minimal + - name: Install cargo-binstall uses: cargo-bins/cargo-binstall@v1.6.4 + - name: Install sgx run: make install + - name: Build sgx prover run: make build + - name: Test sgx prover run: make test @@ -146,6 +96,7 @@ jobs: name: Build and test sgx with Docker runs-on: ubuntu-latest timeout-minutes: 60 + steps: - uses: actions/checkout@v4 - name: Setup and build @@ -158,32 +109,42 @@ jobs: name: Test raiko-lib runs-on: ubuntu-latest timeout-minutes: 60 + steps: - uses: actions/checkout@v4 + - uses: actions-rs/toolchain@v1 with: profile: minimal + - run: cargo test -p raiko-lib --features=std clippy: name: clippy runs-on: ubuntu-latest timeout-minutes: 30 + steps: - - uses: actions/checkout@v4 - - uses: risc0/risc0/.github/actions/rustup@release-0.19 - - uses: risc0/risc0/.github/actions/sccache@release-0.19 - - uses: risc0/clippy-action@main - with: - reporter: 'github-pr-check' - fail_on_error: true - clippy_flags: --workspace --all-targets --all-features -- -Dwarnings + - uses: actions/checkout@v4 + + - uses: risc0/risc0/.github/actions/rustup@release-0.19 + + - uses: risc0/risc0/.github/actions/sccache@release-0.19 + + - uses: risc0/clippy-action@main + with: + reporter: 'github-pr-check' + fail_on_error: true + clippy_flags: --workspace --all-targets --all-features -- -Dwarnings fmt: name: fmt runs-on: ubuntu-latest timeout-minutes: 10 + steps: - - uses: actions/checkout@v4 - - uses: risc0/risc0/.github/actions/rustup@release-0.19 - - run: make fmt + - uses: actions/checkout@v4 + + - uses: risc0/risc0/.github/actions/rustup@release-0.19 + + - run: make fmt diff --git a/.github/workflows/openapi-deploy.yml b/.github/workflows/openapi-deploy.yml new file mode 100644 index 000000000..4c6052f9f --- /dev/null +++ b/.github/workflows/openapi-deploy.yml @@ -0,0 +1,48 @@ +name: OpenAPI + +on: + push: + branches: ["main"] + pull_request: + +permissions: + contents: read + pages: write + id-token: write + +concurrency: + group: "pages" + cancel-in-progress: false + +jobs: + deploy-docs: + name: Generate OpenAPI docs + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Set up Rust + uses: actions-rs/toolchain@v1 + with: + toolchain: nightly-2024-04-17 + profile: minimal + + - name: Run docs generation binary + run: ./script/generate-docs.sh + + - name: Setup Pages + uses: actions/configure-pages@v3 + + - name: Upload artifact + uses: actions/upload-pages-artifact@v2 + with: + path: './openapi' + + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v2 diff --git a/Cargo.lock b/Cargo.lock index 5dec16eb5..a257aadf9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -413,7 +413,7 @@ checksum = "1a047897373be4bbb0224c1afdabca92648dc57a9c9ef6e7b0be3aff7a859c83" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.63", ] [[package]] @@ -606,7 +606,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.63", "syn-solidity", "tiny-keccak", ] @@ -624,7 +624,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.61", + "syn 2.0.63", "syn-solidity", ] @@ -1102,7 +1102,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.63", ] [[package]] @@ -1113,7 +1113,7 @@ checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.63", ] [[package]] @@ -1156,7 +1156,7 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.63", ] [[package]] @@ -1239,7 +1239,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.63", ] [[package]] @@ -1503,7 +1503,7 @@ checksum = "4da9a32f3fed317401fa3c862968128267c3106685286e15d5aaa3d7389c2f60" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.63", ] [[package]] @@ -1687,7 +1687,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.63", ] [[package]] @@ -1923,7 +1923,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.63", ] [[package]] @@ -1993,7 +1993,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.10.0", - "syn 2.0.61", + "syn 2.0.63", ] [[package]] @@ -2004,7 +2004,7 @@ checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f" dependencies = [ "darling_core", "quote", - "syn 2.0.61", + "syn 2.0.63", ] [[package]] @@ -2255,18 +2255,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "enum-as-inner" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ffccbb6966c05b32ef8fbac435df276c4ae4d3dc55a8cd0eb9745e6c12f546a" -dependencies = [ - "heck 0.4.1", - "proc-macro2", - "quote", - "syn 2.0.61", -] - [[package]] name = "enumn" version = "0.1.13" @@ -2275,7 +2263,7 @@ checksum = "6fd000fd6988e73bbe993ea3db9b1aa64906ab88766d654973924340c8cddb42" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.63", ] [[package]] @@ -2408,7 +2396,7 @@ dependencies = [ "regex", "serde", "serde_json", - "syn 2.0.61", + "syn 2.0.63", "toml", "walkdir", ] @@ -2425,7 +2413,7 @@ dependencies = [ "proc-macro2", "quote", "serde_json", - "syn 2.0.61", + "syn 2.0.63", ] [[package]] @@ -2450,7 +2438,7 @@ dependencies = [ "serde", "serde_json", "strum 0.25.0", - "syn 2.0.61", + "syn 2.0.63", "tempfile", "thiserror", "tiny-keccak", @@ -2569,9 +2557,9 @@ dependencies = [ [[package]] name = "fiat-crypto" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38793c55593b33412e3ae40c2c9781ffaa6f438f6f8c10f24e71846fbd7ae01e" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" [[package]] name = "find_cuda_helper" @@ -2643,7 +2631,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.63", ] [[package]] @@ -2729,7 +2717,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.63", ] [[package]] @@ -3055,51 +3043,6 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" -[[package]] -name = "hickory-proto" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07698b8420e2f0d6447a436ba999ec85d8fbf2a398bbd737b82cac4a2e96e512" -dependencies = [ - "async-trait", - "cfg-if", - "data-encoding", - "enum-as-inner", - "futures-channel", - "futures-io", - "futures-util", - "idna 0.4.0", - "ipnet", - "once_cell", - "rand", - "thiserror", - "tinyvec", - "tokio", - "tracing", - "url", -] - -[[package]] -name = "hickory-resolver" -version = "0.24.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28757f23aa75c98f254cf0405e6d8c25b831b32921b050a66692427679b1f243" -dependencies = [ - "cfg-if", - "futures-util", - "hickory-proto", - "ipconfig", - "lru-cache", - "once_cell", - "parking_lot", - "rand", - "resolv-conf", - "smallvec", - "thiserror", - "tokio", - "tracing", -] - [[package]] name = "hmac" version = "0.12.1" @@ -3118,17 +3061,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "hostname" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" -dependencies = [ - "libc", - "match_cfg", - "winapi", -] - [[package]] name = "http" version = "0.2.12" @@ -3269,9 +3201,26 @@ dependencies = [ "futures-util", "http 0.2.12", "hyper 0.14.28", - "rustls", + "rustls 0.21.12", + "tokio", + "tokio-rustls 0.24.1", +] + +[[package]] +name = "hyper-rustls" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0bea761b46ae2b24eb4aef630d8d1c398157b6fc29e6350ecf090a0b70c952c" +dependencies = [ + "futures-util", + "http 1.1.0", + "hyper 1.3.1", + "hyper-util", + "rustls 0.22.4", + "rustls-pki-types", "tokio", - "tokio-rustls", + "tokio-rustls 0.25.0", + "tower-service", ] [[package]] @@ -3352,16 +3301,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" -[[package]] -name = "idna" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" -dependencies = [ - "unicode-bidi", - "unicode-normalization", -] - [[package]] name = "idna" version = "0.5.0" @@ -3466,18 +3405,6 @@ version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f958d3d68f4167080a18141e10381e7634563984a537f2a49a30fd8e53ac5767" -[[package]] -name = "ipconfig" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b58db92f96b720de98181bbbe63c831e87005ab460c1bf306eb2622b4707997f" -dependencies = [ - "socket2", - "widestring", - "windows-sys 0.48.0", - "winreg 0.50.0", -] - [[package]] name = "ipnet" version = "2.9.0" @@ -3623,7 +3550,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.61", + "syn 2.0.63", ] [[package]] @@ -3705,12 +3632,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "linked-hash-map" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" - [[package]] name = "linux-raw-sys" version = "0.4.13" @@ -3742,15 +3663,6 @@ dependencies = [ "hashbrown 0.14.5", ] -[[package]] -name = "lru-cache" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" -dependencies = [ - "linked-hash-map", -] - [[package]] name = "lru_time_cache" version = "0.11.11" @@ -3766,12 +3678,6 @@ dependencies = [ "libc", ] -[[package]] -name = "match_cfg" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" - [[package]] name = "matchers" version = "0.1.0" @@ -3987,7 +3893,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.63", ] [[package]] @@ -4080,7 +3986,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.63", ] [[package]] @@ -4186,7 +4092,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.63", ] [[package]] @@ -4632,7 +4538,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.63", ] [[package]] @@ -4721,7 +4627,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f12335488a2f3b0a83b14edad48dca9879ce89b2edd10e80237e4e852dd645e" dependencies = [ "proc-macro2", - "syn 2.0.61", + "syn 2.0.63", ] [[package]] @@ -4877,7 +4783,7 @@ dependencies = [ "prost", "prost-types", "regex", - "syn 2.0.61", + "syn 2.0.63", "tempfile", ] @@ -4891,7 +4797,7 @@ dependencies = [ "itertools 0.12.1", "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.63", ] [[package]] @@ -4994,6 +4900,7 @@ dependencies = [ "tracing-subscriber 0.3.18", "url", "utoipa", + "utoipa-scalar", "utoipa-swagger-ui", ] @@ -5280,22 +5187,20 @@ dependencies = [ "futures-core", "futures-util", "h2 0.3.26", - "hickory-resolver", "http 0.2.12", "http-body 0.4.6", "hyper 0.14.28", - "hyper-rustls", + "hyper-rustls 0.24.2", "hyper-tls 0.5.0", "ipnet", "js-sys", "log", "mime", - "mime_guess", "native-tls", "once_cell", "percent-encoding", "pin-project-lite", - "rustls", + "rustls 0.21.12", "rustls-pemfile 1.0.4", "serde", "serde_json", @@ -5304,15 +5209,13 @@ dependencies = [ "system-configuration", "tokio", "tokio-native-tls", - "tokio-rustls", - "tokio-util", + "tokio-rustls 0.24.1", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", - "wasm-streams", "web-sys", - "webpki-roots", + "webpki-roots 0.25.4", "winreg 0.50.0", ] @@ -5325,6 +5228,7 @@ dependencies = [ "base64 0.22.1", "bytes", "encoding_rs", + "futures-channel", "futures-core", "futures-util", "h2 0.4.4", @@ -5332,6 +5236,7 @@ dependencies = [ "http-body 1.0.0", "http-body-util", "hyper 1.3.1", + "hyper-rustls 0.26.0", "hyper-tls 0.6.0", "hyper-util", "ipnet", @@ -5342,7 +5247,9 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", + "rustls 0.22.4", "rustls-pemfile 2.1.2", + "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", @@ -5350,37 +5257,31 @@ dependencies = [ "system-configuration", "tokio", "tokio-native-tls", + "tokio-rustls 0.25.0", + "tokio-util", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", + "wasm-streams", "web-sys", + "webpki-roots 0.26.1", "winreg 0.52.0", ] [[package]] name = "reqwest-middleware" -version = "0.2.5" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a735987236a8e238bf0296c7e351b999c188ccc11477f311b82b55c93984216" +checksum = "a45d100244a467870f6cb763c4484d010a6bed6bd610b3676e3825d93fb4cfbd" dependencies = [ "anyhow", "async-trait", - "http 0.2.12", - "reqwest 0.11.27", + "http 1.1.0", + "reqwest 0.12.4", "serde", - "task-local-extensions", "thiserror", -] - -[[package]] -name = "resolv-conf" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00" -dependencies = [ - "hostname", - "quick-error", + "tower-service", ] [[package]] @@ -5824,7 +5725,7 @@ dependencies = [ "regex", "relative-path", "rustc_version 0.4.0", - "syn 2.0.61", + "syn 2.0.63", "unicode-ident", ] @@ -5860,9 +5761,9 @@ checksum = "f86854cf50259291520509879a5c294c3c9a4c334e9ff65071c51e42ef1e2343" [[package]] name = "rust-embed" -version = "8.3.0" +version = "8.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb78f46d0066053d16d4ca7b898e9343bc3530f71c61d5ad84cd404ada068745" +checksum = "19549741604902eb99a7ed0ee177a0663ee1eda51a29f71401f166e47e77806a" dependencies = [ "rust-embed-impl", "rust-embed-utils", @@ -5871,22 +5772,22 @@ dependencies = [ [[package]] name = "rust-embed-impl" -version = "8.3.0" +version = "8.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b91ac2a3c6c0520a3fb3dd89321177c3c692937c4eb21893378219da10c44fc8" +checksum = "cb9f96e283ec64401f30d3df8ee2aaeb2561f34c824381efa24a35f79bf40ee4" dependencies = [ "proc-macro2", "quote", "rust-embed-utils", - "syn 2.0.61", + "syn 2.0.63", "walkdir", ] [[package]] name = "rust-embed-utils" -version = "8.3.0" +version = "8.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86f69089032567ffff4eada41c573fc43ff466c7db7c5688b2e7969584345581" +checksum = "38c74a686185620830701348de757fd36bef4aa9680fd23c49fc539ddcc1af32" dependencies = [ "sha2", "walkdir", @@ -5943,10 +5844,24 @@ checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ "log", "ring 0.17.8", - "rustls-webpki", + "rustls-webpki 0.101.7", "sct", ] +[[package]] +name = "rustls" +version = "0.22.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" +dependencies = [ + "log", + "ring 0.17.8", + "rustls-pki-types", + "rustls-webpki 0.102.3", + "subtle", + "zeroize", +] + [[package]] name = "rustls-pemfile" version = "1.0.4" @@ -5982,6 +5897,17 @@ dependencies = [ "untrusted 0.9.0", ] +[[package]] +name = "rustls-webpki" +version = "0.102.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3bce581c0dd41bce533ce695a1437fa16a7ab5ac3ccfa99fe1a620a7885eabf" +dependencies = [ + "ring 0.17.8", + "rustls-pki-types", + "untrusted 0.9.0", +] + [[package]] name = "rustversion" version = "1.0.16" @@ -6222,7 +6148,7 @@ checksum = "c5e405930b9796f1c00bee880d03fc7e0bb4b9a11afc776885ffe84320da2865" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.63", ] [[package]] @@ -6295,7 +6221,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.63", ] [[package]] @@ -6320,7 +6246,7 @@ checksum = "82fe9db325bcef1fbcde82e078a5cc4efdf787e96b3b9cf45b50b529f2083d67" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.63", ] [[package]] @@ -6501,7 +6427,7 @@ dependencies = [ [[package]] name = "sp1-core" version = "0.1.0" -source = "git+https://github.com/succinctlabs/sp1.git?branch=main#1db2197621011361855ad892b8233e11b0de8ea0" +source = "git+https://github.com/succinctlabs/sp1.git?branch=main#2f57e1e77f7c88396b571bd961d3cbe4b1291c7a" dependencies = [ "anyhow", "arrayref", @@ -6559,7 +6485,7 @@ dependencies = [ [[package]] name = "sp1-derive" version = "0.1.0" -source = "git+https://github.com/succinctlabs/sp1.git?branch=main#1db2197621011361855ad892b8233e11b0de8ea0" +source = "git+https://github.com/succinctlabs/sp1.git?branch=main#2f57e1e77f7c88396b571bd961d3cbe4b1291c7a" dependencies = [ "proc-macro2", "quote", @@ -6588,7 +6514,7 @@ dependencies = [ [[package]] name = "sp1-helper" version = "0.1.0" -source = "git+https://github.com/succinctlabs/sp1.git?branch=main#1db2197621011361855ad892b8233e11b0de8ea0" +source = "git+https://github.com/succinctlabs/sp1.git?branch=main#2f57e1e77f7c88396b571bd961d3cbe4b1291c7a" dependencies = [ "cargo_metadata 0.18.1", "chrono", @@ -6597,7 +6523,7 @@ dependencies = [ [[package]] name = "sp1-primitives" version = "0.1.0" -source = "git+https://github.com/succinctlabs/sp1.git?branch=main#1db2197621011361855ad892b8233e11b0de8ea0" +source = "git+https://github.com/succinctlabs/sp1.git?branch=main#2f57e1e77f7c88396b571bd961d3cbe4b1291c7a" dependencies = [ "itertools 0.12.1", "lazy_static", @@ -6610,7 +6536,7 @@ dependencies = [ [[package]] name = "sp1-prover" version = "0.1.0" -source = "git+https://github.com/succinctlabs/sp1.git?branch=main#1db2197621011361855ad892b8233e11b0de8ea0" +source = "git+https://github.com/succinctlabs/sp1.git?branch=main#2f57e1e77f7c88396b571bd961d3cbe4b1291c7a" dependencies = [ "anyhow", "backtrace", @@ -6627,7 +6553,7 @@ dependencies = [ "p3-commit", "p3-field", "rayon", - "reqwest 0.11.27", + "reqwest 0.12.4", "serde", "serde_json", "serial_test", @@ -6651,7 +6577,7 @@ dependencies = [ [[package]] name = "sp1-recursion-circuit" version = "0.1.0" -source = "git+https://github.com/succinctlabs/sp1.git?branch=main#1db2197621011361855ad892b8233e11b0de8ea0" +source = "git+https://github.com/succinctlabs/sp1.git?branch=main#2f57e1e77f7c88396b571bd961d3cbe4b1291c7a" dependencies = [ "bincode", "itertools 0.12.1", @@ -6674,7 +6600,7 @@ dependencies = [ [[package]] name = "sp1-recursion-compiler" version = "0.1.0" -source = "git+https://github.com/succinctlabs/sp1.git?branch=main#1db2197621011361855ad892b8233e11b0de8ea0" +source = "git+https://github.com/succinctlabs/sp1.git?branch=main#2f57e1e77f7c88396b571bd961d3cbe4b1291c7a" dependencies = [ "backtrace", "itertools 0.12.1", @@ -6700,7 +6626,7 @@ dependencies = [ [[package]] name = "sp1-recursion-core" version = "0.1.0" -source = "git+https://github.com/succinctlabs/sp1.git?branch=main#1db2197621011361855ad892b8233e11b0de8ea0" +source = "git+https://github.com/succinctlabs/sp1.git?branch=main#2f57e1e77f7c88396b571bd961d3cbe4b1291c7a" dependencies = [ "arrayref", "backtrace", @@ -6733,7 +6659,7 @@ dependencies = [ [[package]] name = "sp1-recursion-derive" version = "0.1.0" -source = "git+https://github.com/succinctlabs/sp1.git?branch=main#1db2197621011361855ad892b8233e11b0de8ea0" +source = "git+https://github.com/succinctlabs/sp1.git?branch=main#2f57e1e77f7c88396b571bd961d3cbe4b1291c7a" dependencies = [ "proc-macro2", "quote", @@ -6743,13 +6669,13 @@ dependencies = [ [[package]] name = "sp1-recursion-gnark-ffi" version = "0.1.0" -source = "git+https://github.com/succinctlabs/sp1.git?branch=main#1db2197621011361855ad892b8233e11b0de8ea0" +source = "git+https://github.com/succinctlabs/sp1.git?branch=main#2f57e1e77f7c88396b571bd961d3cbe4b1291c7a" dependencies = [ "crossbeam", "log", "p3-field", "rand", - "reqwest 0.11.27", + "reqwest 0.12.4", "serde", "serde_json", "sp1-recursion-compiler", @@ -6760,7 +6686,7 @@ dependencies = [ [[package]] name = "sp1-recursion-program" version = "0.1.0" -source = "git+https://github.com/succinctlabs/sp1.git?branch=main#1db2197621011361855ad892b8233e11b0de8ea0" +source = "git+https://github.com/succinctlabs/sp1.git?branch=main#2f57e1e77f7c88396b571bd961d3cbe4b1291c7a" dependencies = [ "array-macro", "itertools 0.12.1", @@ -6772,6 +6698,7 @@ dependencies = [ "p3-field", "p3-fri", "p3-matrix", + "p3-maybe-rayon", "p3-merkle-tree", "p3-poseidon2", "p3-symmetric", @@ -6787,7 +6714,7 @@ dependencies = [ [[package]] name = "sp1-sdk" version = "0.1.0" -source = "git+https://github.com/succinctlabs/sp1.git?branch=main#1db2197621011361855ad892b8233e11b0de8ea0" +source = "git+https://github.com/succinctlabs/sp1.git?branch=main#2f57e1e77f7c88396b571bd961d3cbe4b1291c7a" dependencies = [ "alloy", "anyhow", @@ -6805,7 +6732,7 @@ dependencies = [ "p3-matrix", "prost", "prost-types", - "reqwest 0.11.27", + "reqwest 0.12.4", "reqwest-middleware", "serde", "serde_json", @@ -6920,7 +6847,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.61", + "syn 2.0.63", ] [[package]] @@ -6933,7 +6860,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.61", + "syn 2.0.63", ] [[package]] @@ -6977,9 +6904,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.61" +version = "2.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c993ed8ccba56ae856363b1845da7266a7cb78e1d146c8a32d54b45a8b831fc9" +checksum = "bf5be731623ca1a1fb7d8be6f261a3be6d3e2337b8a1f97be944d020c8fcb704" dependencies = [ "proc-macro2", "quote", @@ -6995,7 +6922,7 @@ dependencies = [ "paste", "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.63", ] [[package]] @@ -7031,15 +6958,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" -[[package]] -name = "task-local-extensions" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba323866e5d033818e3240feeb9f7db2c4296674e4d9e16b97b7bf8f490434e8" -dependencies = [ - "pin-utils", -] - [[package]] name = "tempfile" version = "3.10.1" @@ -7084,7 +7002,7 @@ checksum = "e2470041c06ec3ac1ab38d0356a6119054dedaea53e12fbefc0de730a1c08524" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.63", ] [[package]] @@ -7210,7 +7128,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.63", ] [[package]] @@ -7229,7 +7147,18 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "rustls", + "rustls 0.21.12", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" +dependencies = [ + "rustls 0.22.4", + "rustls-pki-types", "tokio", ] @@ -7253,11 +7182,11 @@ checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" dependencies = [ "futures-util", "log", - "rustls", + "rustls 0.21.12", "tokio", - "tokio-rustls", + "tokio-rustls 0.24.1", "tungstenite", - "webpki-roots", + "webpki-roots 0.25.4", ] [[package]] @@ -7414,7 +7343,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.63", ] [[package]] @@ -7520,7 +7449,7 @@ dependencies = [ "httparse", "log", "rand", - "rustls", + "rustls 0.21.12", "sha1", "thiserror", "url", @@ -7530,7 +7459,7 @@ dependencies = [ [[package]] name = "twirp" version = "0.3.0" -source = "git+https://github.com/github/twirp-rs.git?rev=93d4e4b#93d4e4b4a48f9112c943d2925e8dbb1106bd6a18" +source = "git+https://github.com/github/twirp-rs.git?rev=c85f31f9c54957374e7dcb3534fc52cff0aa2dc5#c85f31f9c54957374e7dcb3534fc52cff0aa2dc5" dependencies = [ "async-trait", "axum", @@ -7540,7 +7469,7 @@ dependencies = [ "http-body-util", "hyper 1.3.1", "prost", - "reqwest 0.11.27", + "reqwest 0.12.4", "serde", "serde_json", "thiserror", @@ -7586,7 +7515,7 @@ checksum = "ac73887f47b9312552aa90ef477927ff014d63d1920ca8037c6c1951eab64bb1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.63", ] [[package]] @@ -7680,7 +7609,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", - "idna 0.5.0", + "idna", "percent-encoding", ] @@ -7718,7 +7647,19 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.61", + "syn 2.0.63", +] + +[[package]] +name = "utoipa-scalar" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3ab4b7269d14d93626b0bfedf212f1b0995cb7d13d35daba21d579511e7fae8" +dependencies = [ + "axum", + "serde", + "serde_json", + "utoipa", ] [[package]] @@ -7850,7 +7791,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.63", "wasm-bindgen-shared", ] @@ -7884,7 +7825,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.63", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -7934,6 +7875,15 @@ version = "0.25.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" +[[package]] +name = "webpki-roots" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3de34ae270483955a94f4b21bdaaeb83d508bb84a01435f393818edb0012009" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "which" version = "4.4.2" @@ -7946,12 +7896,6 @@ dependencies = [ "rustix", ] -[[package]] -name = "widestring" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7219d36b6eac893fa81e84ebe06485e7dcbb616177469b142df14f1f4deb1311" - [[package]] name = "winapi" version = "0.3.9" @@ -8214,7 +8158,7 @@ checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.63", ] [[package]] @@ -8234,7 +8178,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.61", + "syn 2.0.63", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index a2774d7d1..9ad34af7d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ members = [ "provers/risc0/driver", "provers/risc0/builder", "provers/sgx/prover", - "provers/sgx/guest", + "provers/sgx/guest", "provers/sgx/setup", "pipeline", ] @@ -106,6 +106,7 @@ axum = { version = "0.7.4", features = ["macros"] } tower-http = { version = "0.5.2", features = ["full"] } tower = { version = "0.4.13", features = ["full"] } utoipa-swagger-ui = { version = "6.0.0", features = ["axum"] } +utoipa-scalar = { version = "0.1.0", features = ["axum"] } utoipa = { version = "4.2.0", features = ["axum_extras"] } structopt = "0.3.24" prometheus = { version = "0.13.3", features = ["process"] } @@ -159,4 +160,4 @@ rand = "0.8.5" rand_core = "0.6.4" base64-serde = "0.7.0" base64 = "0.21.7" -dirs = "5.0.1" \ No newline at end of file +dirs = "5.0.1" diff --git a/README.md b/README.md index 62d78ecd5..f3ad56427 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ After installing dependencies of selected prover, the following command internal ```console $ TARGET=sp1 make build ``` -If you set `DEBUG=1` then the target will be compiled without optimization (not recomended for ZkVM elfs). +If you set `DEBUG=1` then the target will be compiled without optimization (not recommended for ZkVM elfs). ### Running @@ -108,4 +108,8 @@ You can generate an execution trace for the block that is being proven by enabli $ cargo run --features tracer ``` -A `traces` folder will be created inside the root directory. This folder will contain json files with the trace of each valid transaction in the block. \ No newline at end of file +A `traces` folder will be created inside the root directory. This folder will contain json files with the trace of each valid transaction in the block. + +## OpenAPI + +When running any of the features/provers, OpenAPI UIs are available in both Swagger and Scalar flavors on `/swagger-ui` and `/scalar` respectively. diff --git a/docs/README_Docker_and_RA.md b/docs/README_Docker_and_RA.md index 2f8ee6c44..86e163678 100644 --- a/docs/README_Docker_and_RA.md +++ b/docs/README_Docker_and_RA.md @@ -294,7 +294,7 @@ It should look something like this: } ``` -You've now prepared your machine for running Raiko through Docker. Now, you need to perform On-Chain Remote Attestation to recieve TTKOh from moderators and begin proving for Taiko! +You've now prepared your machine for running Raiko through Docker. Now, you need to perform On-Chain Remote Attestation to receive TTKOh from moderators and begin proving for Taiko! > **_NOTE:_** We are no longer automatically distributing TTKOh to people who perform on-chain RA, please reach out to a moderator for TTKOh if you'd like to test SGX proving. diff --git a/host/Cargo.toml b/host/Cargo.toml index be5012892..7635b5803 100644 --- a/host/Cargo.toml +++ b/host/Cargo.toml @@ -32,6 +32,7 @@ axum = { workspace = true } tower-http = { workspace = true } tower = { workspace = true } utoipa-swagger-ui = { workspace = true } +utoipa-scalar = { workspace = true } utoipa = { workspace = true } # misc @@ -83,7 +84,3 @@ path = "src/main.rs" [[bin]] name = "docs" path = "src/docs.rs" - - -[patch.crates-io] -axum = { git = "https://github.com/petarvujovic98/axum", branch = "raiko" } diff --git a/host/src/docs.rs b/host/src/docs.rs index e662ba8bd..26322ea9d 100644 --- a/host/src/docs.rs +++ b/host/src/docs.rs @@ -1,7 +1,6 @@ use raiko_host::server::api::create_docs; +use utoipa_scalar::Scalar; fn main() { - let docs = create_docs(); - let json = docs.to_json().expect("Failed to serialize docs to json"); - println!("{json}"); + println!("{}", Scalar::new(create_docs()).to_html()); } diff --git a/host/src/error.rs b/host/src/error.rs index df72a0824..ddab33739 100644 --- a/host/src/error.rs +++ b/host/src/error.rs @@ -24,6 +24,18 @@ pub enum HostError { #[schema(value_type = Value)] Io(#[from] std::io::Error), + /// For preflight errors. + #[error("There was an error running the preflight: {0}")] + Preflight(String), + + /// For invalid type conversion. + #[error("Invalid conversion: {0}")] + Conversion(String), + + /// For RPC errors. + #[error("There was an error with the RPC provider: {0}")] + RPC(String), + /// For Serde errors. #[error("There was a deserialization error: {0}")] #[schema(value_type = Value)] @@ -35,9 +47,14 @@ pub enum HostError { JoinHandle(#[from] tokio::task::JoinError), /// For errors produced by the guest provers. - #[error("There was a error with a guest prover: {0}")] + #[error("There was an error with a guest prover: {0}")] #[schema(value_type = Value)] - GuestError(#[from] ProverError), + Guest(#[from] ProverError), + + /// For db errors. + #[error("There was an error with the db: {0}")] + #[schema(value_type = Value)] + Db(raiko_lib::mem_db::DbError), /// For requesting a proof of a type that is not supported. #[error("Feature not supported: {0}")] @@ -50,28 +67,28 @@ pub enum HostError { Anyhow(#[from] anyhow::Error), } +impl From for HostError { + fn from(e: raiko_lib::mem_db::DbError) -> Self { + HostError::Db(e) + } +} + impl IntoResponse for HostError { fn into_response(self) -> axum::response::Response { + use HostError::*; match self { - HostError::InvalidProofType(e) - | HostError::InvalidRequestConfig(e) - | HostError::InvalidAddress(e) => { + InvalidProofType(e) | InvalidRequestConfig(e) | InvalidAddress(e) => { (StatusCode::BAD_REQUEST, e.to_string()).into_response() } - HostError::Io(e) => (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()).into_response(), - HostError::Serde(e) => { - (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()).into_response() - } - HostError::Anyhow(e) => { - (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()).into_response() - } - HostError::JoinHandle(e) => { - (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()).into_response() - } - HostError::GuestError(e) => { - (StatusCode::FAILED_DEPENDENCY, e.to_string()).into_response() - } - HostError::FeatureNotSupportedError(e) => { + Conversion(e) | Preflight(e) => (StatusCode::INTERNAL_SERVER_ERROR, e).into_response(), + Io(e) => (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()).into_response(), + Serde(e) => (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()).into_response(), + Anyhow(e) => (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()).into_response(), + JoinHandle(e) => (StatusCode::INTERNAL_SERVER_ERROR, e.to_string()).into_response(), + Guest(e) => (StatusCode::FAILED_DEPENDENCY, e.to_string()).into_response(), + RPC(e) => (StatusCode::FAILED_DEPENDENCY, e.to_string()).into_response(), + Db(e) => (StatusCode::FAILED_DEPENDENCY, e.to_string()).into_response(), + FeatureNotSupportedError(e) => { (StatusCode::METHOD_NOT_ALLOWED, e.to_string()).into_response() } } diff --git a/host/src/lib.rs b/host/src/lib.rs index 587cfb38f..f1d061331 100644 --- a/host/src/lib.rs +++ b/host/src/lib.rs @@ -21,17 +21,17 @@ pub mod request; pub mod rpc_provider; pub mod server; +use std::{alloc, collections::HashMap, path::PathBuf}; + use alloy_primitives::Address; use alloy_rpc_types::EIP1186AccountProofResponse; -use anyhow::{Context, Result}; +use anyhow::Context; use cap::Cap; use clap::Parser; use serde::{Deserialize, Serialize}; use serde_json::Value; -use std::collections::HashMap; -use std::{alloc, fmt::Debug, path::PathBuf}; -use crate::{error::HostError, request::ProofRequestOpt}; +use crate::{error::HostResult, request::ProofRequestOpt}; type MerkleProof = HashMap; @@ -59,8 +59,11 @@ fn default_log_level() -> String { } #[derive(Default, Clone, Serialize, Deserialize, Debug, Parser)] -#[command(name = "raiko")] -#[command(about = "The taiko prover host", long_about = None)] +#[command( + name = "raiko", + about = "The taiko prover host", + long_about = None +)] #[serde(default)] pub struct Cli { #[arg(long, require_equals = true, default_value = "0.0.0.0:8080")] @@ -83,7 +86,7 @@ pub struct Cli { #[arg(long, require_equals = true, default_value = "host/config/config.json")] #[serde(default = "default_config_path")] - /// Path to a config file that includes sufficent json args to request + /// Path to a config file that includes sufficient json args to request /// a proof of specified type. Curl json-rpc overrides its contents config_path: PathBuf, @@ -104,7 +107,7 @@ pub struct Cli { impl Cli { /// Read the options from a file and merge it with the current options. - pub fn merge_from_file(&mut self) -> Result<(), HostError> { + pub fn merge_from_file(&mut self) -> HostResult<()> { let file = std::fs::File::open(&self.config_path)?; let reader = std::io::BufReader::new(file); let mut config: Value = serde_json::from_reader(reader)?; @@ -135,7 +138,7 @@ pub struct ProverState { } impl ProverState { - pub fn init() -> Result { + pub fn init() -> HostResult { // Read the command line arguments; let mut opts = Cli::parse(); // Read the config file. @@ -153,6 +156,8 @@ impl ProverState { } mod memory { + use tracing::info; + use crate::ALLOCATOR; pub(crate) fn reset_stats() { @@ -165,10 +170,10 @@ mod memory { pub(crate) fn print_stats(title: &str) { let max_memory = get_max_allocated(); - println!( + info!( "{title}{}.{:06} MB", - max_memory / 1000000, - max_memory % 1000000 + max_memory / 1_000_000, + max_memory % 1_000_000 ); } } diff --git a/host/src/main.rs b/host/src/main.rs index eb84cb0f2..93e9221e7 100644 --- a/host/src/main.rs +++ b/host/src/main.rs @@ -42,10 +42,10 @@ fn subscribe_log( .max_log_files(max_log) .build(log_path) .expect("initializing rolling file appender failed"); - let (non_blocking, _guard) = tracing_appender::non_blocking(file_appender); + let (non_blocking, guard) = tracing_appender::non_blocking(file_appender); let subscriber = subscriber_builder.json().with_writer(non_blocking).finish(); tracing::subscriber::set_global_default(subscriber).unwrap(); - Some(_guard) + Some(guard) } None => { let subscriber = subscriber_builder.finish(); diff --git a/host/src/metrics.rs b/host/src/metrics.rs index d61dcdc7a..b494bd01a 100644 --- a/host/src/metrics.rs +++ b/host/src/metrics.rs @@ -1,3 +1,5 @@ +use std::time::Duration; + use lazy_static::lazy_static; use prometheus::{ labels, register_histogram_vec, register_int_counter_vec, register_int_gauge, HistogramVec, @@ -123,8 +125,13 @@ pub fn inc_guest_error(guest: &ProofType, block_id: u64) { GUEST_PROOF_ERROR_COUNT.with(&labels).inc(); } +/// Convert a duration to a float with 3 decimal places (seconds,milliseconds). +fn duration_to_f64(d: Duration) -> f64 { + (d.as_secs_f64() * 1_000.0).round() / 1_000.0 +} + /// Observe the time taken for the given guest to generate a proof. -pub fn observe_guest_time(guest: &ProofType, block_id: u64, time: u128, success: bool) { +pub fn observe_guest_time(guest: &ProofType, block_id: u64, time: Duration, success: bool) { let guest = guest.to_string(); let block_id = block_id.to_string(); let success = success.to_string(); @@ -133,27 +140,31 @@ pub fn observe_guest_time(guest: &ProofType, block_id: u64, time: u128, success: "block_id" => &block_id, "success" => &success, }; - GUEST_PROOF_TIME.with(&labels).observe(time as f64); + GUEST_PROOF_TIME + .with(&labels) + .observe(duration_to_f64(time)); } /// Observe the time taken for prepare input. -pub fn observe_prepare_input_time(block_id: u64, time: u128, success: bool) { +pub fn observe_prepare_input_time(block_id: u64, time: Duration, success: bool) { let block_id = block_id.to_string(); let success = success.to_string(); let labels = labels! { "block_id" => block_id.as_str(), "success" => &success, }; - PREPARE_INPUT_TIME.with(&labels).observe(time as f64); + PREPARE_INPUT_TIME + .with(&labels) + .observe(duration_to_f64(time)); } /// Observe the time taken for prepare input. -pub fn observe_total_time(block_id: u64, time: u128, success: bool) { +pub fn observe_total_time(block_id: u64, time: Duration, success: bool) { let block_id = block_id.to_string(); let success = success.to_string(); let labels = labels! { "block_id" => block_id.as_str(), "success" => &success, }; - TOTAL_TIME.with(&labels).observe(time as f64); + TOTAL_TIME.with(&labels).observe(duration_to_f64(time)); } diff --git a/host/src/preflight.rs b/host/src/preflight.rs index 5858d478b..0a98d1e34 100644 --- a/host/src/preflight.rs +++ b/host/src/preflight.rs @@ -5,7 +5,7 @@ pub use alloy_primitives::*; use alloy_provider::{Provider, ReqwestProvider}; use alloy_rpc_types::{Block, BlockTransactions, Filter, Transaction as AlloyRpcTransaction}; use alloy_sol_types::{SolCall, SolEvent}; -use anyhow::{bail, Result}; +use anyhow::{anyhow, bail, Result}; use c_kzg::{Blob, KzgCommitment}; use raiko_lib::{ builder::{ @@ -25,9 +25,13 @@ use raiko_primitives::{ }; use serde::{Deserialize, Serialize}; use std::{collections::HashSet, sync::Arc}; +use tracing::{info, warn}; use crate::{ - provider_db::ProviderDb, raiko::BlockDataProvider, rpc_provider::RpcBlockDataProvider, + error::{HostError, HostResult}, + provider_db::ProviderDb, + raiko::BlockDataProvider, + rpc_provider::RpcBlockDataProvider, }; pub async fn preflight( @@ -37,144 +41,125 @@ pub async fn preflight( prover_data: TaikoProverData, l1_rpc_url: Option, beacon_rpc_url: Option, -) -> Result { - let measurement = Measurement::start("Fetching block data...", true); +) -> HostResult { + let measurement = Measurement::start("Fetching block data...", false); // Get the block and the parent block let blocks = provider .get_blocks(&[(block_number, true), (block_number - 1, false)]) .await?; - let (block, parent_block) = (&blocks[0], &blocks[1]); - - println!("\nblock.hash: {:?}", block.header.hash.unwrap()); - println!("block.parent_hash: {:?}", block.header.parent_hash); - println!("block gas used: {:?}", block.header.gas_used); - println!("block transactions: {:?}", block.transactions.len()); - - let taiko_guest_input = if chain_spec.is_taiko() { - let provider_l1 = RpcBlockDataProvider::new(&l1_rpc_url.clone().unwrap(), block_number); + let (block, parent_block) = ( + blocks.first().ok_or_else(|| { + HostError::Preflight("No block data for the requested block".to_owned()) + })?, + &blocks.get(1).ok_or_else(|| { + HostError::Preflight("No parent block data for the requested block".to_owned()) + })?, + ); - // Decode the anchor tx to find out which L1 blocks we need to fetch - let anchor_tx = match &block.transactions { - BlockTransactions::Full(txs) => txs[0].to_owned(), - _ => unreachable!(), - }; - let anchor_call = decode_anchor(anchor_tx.input.as_ref())?; - // The L1 blocks we need - let l1_state_block_number = anchor_call.l1BlockId; - let l1_inclusion_block_number = l1_state_block_number + 1; - - println!("anchor L1 block id: {:?}", anchor_call.l1BlockId); - println!("anchor L1 state root: {:?}", anchor_call.l1StateRoot); - - // Get the L1 block in which the L2 block was included so we can fetch the DA data. - // Also get the L1 state block header so that we can prove the L1 state root. - let l1_blocks = provider_l1 - .get_blocks(&[ - (l1_inclusion_block_number, false), - (l1_state_block_number, false), - ]) - .await?; - let (l1_inclusion_block, l1_state_block) = (&l1_blocks[0], &l1_blocks[1]); + let hash = block + .header + .hash + .ok_or_else(|| HostError::Preflight("No block hash for the requested block".to_string()))?; - println!( - "l1_state_root_block hash: {:?}", - l1_state_block.header.hash.unwrap() - ); + info!("\nblock.hash: {hash:?}"); + info!("block.parent_hash: {:?}", block.header.parent_hash); + info!("block gas used: {:?}", block.header.gas_used); + info!("block transactions: {:?}", block.transactions.len()); - // Get the block proposal data - let (proposal_tx, proposal_event) = get_block_proposed_event( - provider_l1.provider(), - chain_spec.clone(), - l1_inclusion_block.header.hash.unwrap(), + let taiko_guest_input = if chain_spec.is_taiko() { + prepare_taiko_chain_input( + &chain_spec, block_number, - ) - .await?; - - // Fetch the tx data from either calldata or blobdata - let (tx_data, tx_blob_hash) = if proposal_event.meta.blobUsed { - println!("blob active"); - // Get the blob hashes attached to the propose tx - let blob_hashes = proposal_tx.blob_versioned_hashes.unwrap_or_default(); - assert!(!blob_hashes.is_empty()); - // Currently the protocol enforces the first blob hash to be used - let blob_hash = blob_hashes[0]; - // Get the blob data for this block - let slot_id = block_time_to_block_slot( - l1_inclusion_block.header.timestamp, - chain_spec.genesis_time, - chain_spec.seconds_per_slot, - )?; - // Fetch the blob data - let blob = get_blob_data(&beacon_rpc_url.clone().unwrap(), slot_id, blob_hash).await?; - (blob, Some(blob_hash)) - } else { - // Get the tx list data directly from the propose transaction data - let proposal_call = proposeBlockCall::abi_decode(&proposal_tx.input, false).unwrap(); - (proposal_call.txList.as_ref().to_owned(), None) - }; - - // Create the transactions from the proposed tx list - let transactions = generate_transactions( - proposal_event.meta.blobUsed, - &tx_data, - Some(anchor_tx.clone()), - ); - // Do a sanity check using the transactions returned by the node - assert!( - transactions.len() >= block.transactions.len(), - "unexpected number of transactions" - ); - - // Create the input struct without the block data set - TaikoGuestInput { - l1_header: to_header(&l1_state_block.header), - tx_data, - anchor_tx: serde_json::to_string(&anchor_tx).unwrap(), - tx_blob_hash, - block_proposed: proposal_event, + block, + l1_rpc_url, + beacon_rpc_url, prover_data, - skip_verify_blob: false, - } + ) + .await? } else { // For Ethereum blocks we just convert the block transactions in a tx_list // so that we don't have to supports separate paths. TaikoGuestInput { - tx_data: zlib_compress_data(&alloy_rlp::encode(&get_transactions_from_block(block)))?, + tx_data: zlib_compress_data(&alloy_rlp::encode(&get_transactions_from_block(block)?))?, ..Default::default() } }; measurement.stop(); - let input = GuestInput { - chain_spec: chain_spec.clone(), - block_number, - gas_used: block.header.gas_used.try_into().unwrap(), - block_hash_reference: block.header.hash.unwrap(), - block_header_reference: to_header(&block.header), - beneficiary: block.header.miner, - gas_limit: block.header.gas_limit.try_into().unwrap(), - timestamp: block.header.timestamp.try_into().unwrap(), - extra_data: block.header.extra_data.clone(), - mix_hash: block.header.mix_hash.unwrap(), - withdrawals: block.withdrawals.clone().unwrap_or_default(), - parent_state_trie: Default::default(), - parent_storage: Default::default(), - contracts: Default::default(), - parent_header: to_header(&parent_block.header), - ancestor_headers: Default::default(), - base_fee_per_gas: block.header.base_fee_per_gas.unwrap().try_into().unwrap(), - blob_gas_used: block.header.blob_gas_used.map(|b| b.try_into().unwrap()), - excess_blob_gas: block.header.excess_blob_gas.map(|b| b.try_into().unwrap()), - parent_beacon_block_root: block.header.parent_beacon_block_root, - taiko: taiko_guest_input, - }; + let input = + GuestInput { + chain_spec: chain_spec.clone(), + block_number, + gas_used: block.header.gas_used.try_into().map_err(|_| { + HostError::Conversion("Failed converting gas used to u64".to_string()) + })?, + block_hash_reference: hash, + block_header_reference: to_header(&block.header), + beneficiary: block.header.miner, + gas_limit: block.header.gas_limit.try_into().map_err(|_| { + HostError::Conversion("Failed converting gas limit to u64".to_string()) + })?, + timestamp: block.header.timestamp, + extra_data: block.header.extra_data.clone(), + mix_hash: if let Some(mix_hash) = block.header.mix_hash { + mix_hash + } else { + return Err(HostError::Preflight( + "No mix hash for the requested block".to_owned(), + )); + }, + withdrawals: block.withdrawals.clone().unwrap_or_default(), + parent_state_trie: Default::default(), + parent_storage: Default::default(), + contracts: Default::default(), + parent_header: to_header(&parent_block.header), + ancestor_headers: Default::default(), + base_fee_per_gas: block.header.base_fee_per_gas.map_or_else( + || { + Err(HostError::Preflight( + "No base fee per gas for the requested block".to_owned(), + )) + }, + |base_fee_per_gas| { + base_fee_per_gas.try_into().map_err(|_| { + HostError::Conversion( + "Failed converting base fee per gas to u64".to_owned(), + ) + }) + }, + )?, + blob_gas_used: block.header.blob_gas_used.map_or_else( + || Ok(None), + |b: u128| -> HostResult> { + b.try_into().map(Some).map_err(|_| { + HostError::Conversion("Failed converting blob gas used to u64".to_owned()) + }) + }, + )?, + excess_blob_gas: block.header.excess_blob_gas.map_or_else( + || Ok(None), + |b: u128| -> HostResult> { + b.try_into().map(Some).map_err(|_| { + HostError::Conversion("Failed converting excess blob gas to u64".to_owned()) + }) + }, + )?, + parent_beacon_block_root: block.header.parent_beacon_block_root, + taiko: taiko_guest_input, + }; // Create the block builder, run the transactions and extract the DB let provider_db = ProviderDb::new( provider, chain_spec, - parent_block.header.number.unwrap().try_into().unwrap(), + if let Some(parent_block_number) = parent_block.header.number { + parent_block_number + } else { + return Err(HostError::Preflight( + "No parent block number for the requested block".to_owned(), + )); + }, ) .await?; @@ -188,7 +173,7 @@ pub async fn preflight( let mut done = false; let mut num_iterations = 0; while !done { - println!("Execution iteration {num_iterations}..."); + info!("Execution iteration {num_iterations}..."); builder.mut_db().unwrap().optimistic = num_iterations + 1 < max_iterations; builder = builder.execute_transactions::()?; if builder.mut_db().unwrap().fetch_data().await { @@ -240,16 +225,122 @@ pub async fn preflight( }) } +/// Prepare the input for a Taiko chain +async fn prepare_taiko_chain_input( + chain_spec: &ChainSpec, + block_number: u64, + block: &Block, + l1_rpc_url: Option, + beacon_rpc_url: Option, + prover_data: TaikoProverData, +) -> HostResult { + let l1_rpc_url = l1_rpc_url.ok_or_else(|| { + HostError::Preflight("L1 RPC URL is required for Taiko chains".to_owned()) + })?; + let provider_l1 = RpcBlockDataProvider::new(&l1_rpc_url, block_number)?; + + // Decode the anchor tx to find out which L1 blocks we need to fetch + let anchor_tx = match &block.transactions { + BlockTransactions::Full(txs) => txs[0].clone(), + _ => unreachable!(), + }; + let anchor_call = decode_anchor(anchor_tx.input.as_ref())?; + // The L1 blocks we need + let l1_state_block_number = anchor_call.l1BlockId; + let l1_inclusion_block_number = l1_state_block_number + 1; + + info!("anchor L1 block id: {:?}", anchor_call.l1BlockId); + info!("anchor L1 state root: {:?}", anchor_call.l1StateRoot); + + // Get the L1 block in which the L2 block was included so we can fetch the DA data. + // Also get the L1 state block header so that we can prove the L1 state root. + let l1_blocks = provider_l1 + .get_blocks(&[ + (l1_inclusion_block_number, false), + (l1_state_block_number, false), + ]) + .await?; + let (l1_inclusion_block, l1_state_block) = (&l1_blocks[0], &l1_blocks[1]); + + let l1_state_block_hash = l1_state_block.header.hash.ok_or_else(|| { + HostError::Preflight("No L1 state block hash for the requested block".to_owned()) + })?; + + info!("l1_state_root_block hash: {l1_state_block_hash:?}"); + + let l1_inclusion_block_hash = l1_inclusion_block.header.hash.ok_or_else(|| { + HostError::Preflight("No L1 inclusion block hash for the requested block".to_owned()) + })?; + + // Get the block proposal data + let (proposal_tx, proposal_event) = get_block_proposed_event( + provider_l1.provider(), + chain_spec.clone(), + l1_inclusion_block_hash, + block_number, + ) + .await?; + + // Fetch the tx data from either calldata or blobdata + let (tx_data, tx_blob_hash) = if proposal_event.meta.blobUsed { + info!("blob active"); + // Get the blob hashes attached to the propose tx + let blob_hashes = proposal_tx.blob_versioned_hashes.unwrap_or_default(); + assert!(!blob_hashes.is_empty()); + // Currently the protocol enforces the first blob hash to be used + let blob_hash = blob_hashes[0]; + // Get the blob data for this block + let slot_id = block_time_to_block_slot( + l1_inclusion_block.header.timestamp, + chain_spec.genesis_time, + chain_spec.seconds_per_slot, + )?; + let beacon_rpc_url = beacon_rpc_url.ok_or_else(|| { + HostError::Preflight("Beacon RPC URL is required for Taiko chains".to_owned()) + })?; + let blob = get_blob_data(&beacon_rpc_url, slot_id, blob_hash).await?; + (blob, Some(blob_hash)) + } else { + // Get the tx list data directly from the propose transaction data + let proposal_call = proposeBlockCall::abi_decode(&proposal_tx.input, false) + .map_err(|_| HostError::Preflight("Could not decode proposeBlockCall".to_owned()))?; + (proposal_call.txList.as_ref().to_owned(), None) + }; + + // Create the transactions from the proposed tx list + let transactions = generate_transactions( + proposal_event.meta.blobUsed, + &tx_data, + Some(anchor_tx.clone()), + ); + // Do a sanity check using the transactions returned by the node + assert!( + transactions.len() >= block.transactions.len(), + "unexpected number of transactions" + ); + + // Create the input struct without the block data set + Ok(TaikoGuestInput { + l1_header: to_header(&l1_state_block.header), + tx_data, + anchor_tx: serde_json::to_string(&anchor_tx).map_err(HostError::Serde)?, + tx_blob_hash, + block_proposed: proposal_event, + prover_data, + skip_verify_blob: false, + }) +} + // block_time_to_block_slot returns the slots of the given timestamp. fn block_time_to_block_slot( block_time: u64, genesis_time: u64, block_per_slot: u64, -) -> Result { +) -> HostResult { if block_time < genesis_time { - Err(anyhow::Error::msg( + Err(HostError::Anyhow(anyhow!( "provided block_time precedes genesis time", - )) + ))) } else { Ok((block_time - genesis_time) / block_per_slot) } @@ -263,11 +354,12 @@ fn blob_to_bytes(blob_str: &str) -> Vec { } fn calc_blob_versioned_hash(blob_str: &str) -> [u8; 32] { - let blob_bytes: Vec = - hex::decode(blob_str.to_lowercase().trim_start_matches("0x")).unwrap(); + let blob_bytes: Vec = hex::decode(blob_str.to_lowercase().trim_start_matches("0x")) + .expect("Could not decode blob"); let kzg_settings = Arc::clone(&*MAINNET_KZG_TRUSTED_SETUP); - let blob = Blob::from_bytes(&blob_bytes).unwrap(); - let kzg_commit = KzgCommitment::blob_to_kzg_commitment(&blob, &kzg_settings).unwrap(); + let blob = Blob::from_bytes(&blob_bytes).expect("Could not create blob"); + let kzg_commit = KzgCommitment::blob_to_kzg_commitment(&blob, &kzg_settings) + .expect("Could not create kzg commitment from blob"); let version_hash: [u8; 32] = kzg_to_versioned_hash(kzg_commit).0; version_hash } @@ -333,7 +425,7 @@ async fn get_blob_data_beacon( assert!(tx_blob.is_some()); Ok(blob_to_bytes(&tx_blob.unwrap().blob)) } else { - println!( + warn!( "Request {url} failed with status code: {}", response.status() ); @@ -379,10 +471,14 @@ async fn get_block_proposed_event( block_hash: B256, l2_block_number: u64, ) -> Result<(AlloyRpcTransaction, BlockProposed)> { - // Get the address that emited the event - let l1_address = chain_spec.l1_contract.unwrap(); + // Get the address that emitted the event + let Some(l1_address) = chain_spec.l1_contract else { + bail!("No L1 contract address in the chain spec"); + }; - let network = chain_spec.network().unwrap(); + let Some(network) = chain_spec.network() else { + bail!("No network in the chain spec"); + }; // Get the event signature (value can differ between chains) let event_signature = if network == Network::TaikoA6 { @@ -401,54 +497,43 @@ async fn get_block_proposed_event( // Run over the logs returned to find the matching event for the specified L2 block number // (there can be multiple blocks proposed in the same block and even same tx) for log in logs { - if network == Network::TaikoA6 { - let event = TestnetBlockProposed::decode_log( - &Log::new( - log.address(), - log.topics().to_vec(), - log.data().data.clone(), - ) - .unwrap(), - false, - ) - .unwrap(); - if event.blockId == raiko_primitives::U256::from(l2_block_number) { - let tx = provider - .get_transaction_by_hash(log.transaction_hash.unwrap()) - .await - .expect("could not find the propose tx"); - return Ok((tx, event.data.into())); - } + let Some(log_struct) = Log::new( + log.address(), + log.topics().to_vec(), + log.data().data.clone(), + ) else { + bail!("Could not create log") + }; + let (block_id, data) = if network == Network::TaikoA6 { + let event = TestnetBlockProposed::decode_log(&log_struct, false) + .map_err(|_| HostError::Anyhow(anyhow!("Could not decode tesstnet log")))?; + (event.blockId, event.data.into()) } else { - let event = BlockProposed::decode_log( - &Log::new( - log.address(), - log.topics().to_vec(), - log.data().data.clone(), - ) - .unwrap(), - false, - ) - .unwrap(); - if event.blockId == raiko_primitives::U256::from(l2_block_number) { - let tx = provider - .get_transaction_by_hash(log.transaction_hash.unwrap()) - .await - .expect("could not find the propose tx"); - return Ok((tx, event.data)); - } + let event = BlockProposed::decode_log(&log_struct, false) + .map_err(|_| HostError::Anyhow(anyhow!("Could not decode log")))?; + (event.blockId, event.data) + }; + if block_id == raiko_primitives::U256::from(l2_block_number) { + let Some(log_tx_hash) = log.transaction_hash else { + bail!("No transaction hash in the log") + }; + let tx = provider + .get_transaction_by_hash(log_tx_hash) + .await + .expect("Could not find the propose tx"); + return Ok((tx, data)); } } bail!("No BlockProposed event found for block {l2_block_number}"); } -fn get_transactions_from_block(block: &Block) -> Vec { +fn get_transactions_from_block(block: &Block) -> HostResult> { let mut transactions: Vec = Vec::new(); if !block.transactions.is_empty() { match &block.transactions { BlockTransactions::Full(txs) => { for tx in txs { - transactions.push(from_block_tx(tx)); + transactions.push(from_block_tx(tx)?); } }, _ => unreachable!("Block is too old, please connect to an archive node or use a block that is at most 128 blocks old."), @@ -458,27 +543,27 @@ fn get_transactions_from_block(block: &Block) -> Vec { "unexpected number of transactions" ); } - transactions + Ok(transactions) } -fn from_block_tx(tx: &AlloyRpcTransaction) -> TxEnvelope { - let signature = Signature::from_rs_and_parity( - tx.signature.unwrap().r, - tx.signature.unwrap().s, - tx.signature.unwrap().v.as_limbs()[0], - ) - .unwrap(); - match tx.transaction_type.unwrap_or_default() { +fn from_block_tx(tx: &AlloyRpcTransaction) -> HostResult { + let Some(signature) = tx.signature else { + panic!("Transaction has no signature"); + }; + let signature = + Signature::from_rs_and_parity(signature.r, signature.s, signature.v.as_limbs()[0]) + .map_err(|_| HostError::Anyhow(anyhow!("Could not create signature")))?; + Ok(match tx.transaction_type.unwrap_or_default() { 0 => TxEnvelope::Legacy( TxLegacy { chain_id: tx.chain_id, nonce: tx.nonce, - gas_price: tx.gas_price.unwrap().try_into().unwrap(), - gas_limit: tx.gas.try_into().unwrap(), - to: if tx.to.is_none() { - TxKind::Create + gas_price: tx.gas_price.expect("No gas price for the transaction"), + gas_limit: tx.gas, + to: if let Some(to) = tx.to { + TxKind::Call(to) } else { - TxKind::Call(tx.to.unwrap()) + TxKind::Create }, value: tx.value, input: tx.input.0.clone().into(), @@ -487,14 +572,14 @@ fn from_block_tx(tx: &AlloyRpcTransaction) -> TxEnvelope { ), 1 => TxEnvelope::Eip2930( TxEip2930 { - chain_id: tx.chain_id.unwrap(), + chain_id: tx.chain_id.expect("No chain id for the transaction"), nonce: tx.nonce, - gas_price: tx.gas_price.unwrap().try_into().unwrap(), - gas_limit: tx.gas.try_into().unwrap(), - to: if tx.to.is_none() { - TxKind::Create + gas_price: tx.gas_price.expect("No gas price for the transaction"), + gas_limit: tx.gas, + to: if let Some(to) = tx.to { + TxKind::Call(to) } else { - TxKind::Call(tx.to.unwrap()) + TxKind::Create }, value: tx.value, input: tx.input.clone(), @@ -504,15 +589,19 @@ fn from_block_tx(tx: &AlloyRpcTransaction) -> TxEnvelope { ), 2 => TxEnvelope::Eip1559( TxEip1559 { - chain_id: tx.chain_id.unwrap(), + chain_id: tx.chain_id.expect("No chain id for the transaction"), nonce: tx.nonce, - gas_limit: tx.gas.try_into().unwrap(), - max_fee_per_gas: tx.max_fee_per_gas.unwrap().try_into().unwrap(), - max_priority_fee_per_gas: tx.max_priority_fee_per_gas.unwrap().try_into().unwrap(), - to: if tx.to.is_none() { - TxKind::Create + gas_limit: tx.gas, + max_fee_per_gas: tx + .max_fee_per_gas + .expect("No max fee per gas for the transaction"), + max_priority_fee_per_gas: tx + .max_priority_fee_per_gas + .expect("No max priority fee per gas for the transaction"), + to: if let Some(to) = tx.to { + TxKind::Call(to) } else { - TxKind::Call(tx.to.unwrap()) + TxKind::Create }, value: tx.value, access_list: tx.access_list.clone().unwrap_or_default(), @@ -522,22 +611,28 @@ fn from_block_tx(tx: &AlloyRpcTransaction) -> TxEnvelope { ), 3 => TxEnvelope::Eip4844( TxEip4844Variant::TxEip4844(TxEip4844 { - chain_id: tx.chain_id.unwrap(), + chain_id: tx.chain_id.expect("No chain id for the transaction"), nonce: tx.nonce, - gas_limit: tx.gas.try_into().unwrap(), - max_fee_per_gas: tx.max_fee_per_gas.unwrap().try_into().unwrap(), - max_priority_fee_per_gas: tx.max_priority_fee_per_gas.unwrap().try_into().unwrap(), - to: tx.to.unwrap(), + gas_limit: tx.gas, + max_fee_per_gas: tx + .max_fee_per_gas + .expect("No max fee per gas for the transaction"), + max_priority_fee_per_gas: tx + .max_priority_fee_per_gas + .expect("No max priority fee per gas for the transaction"), + to: tx.to.expect("No to address for the transaction"), value: tx.value, access_list: tx.access_list.clone().unwrap_or_default(), input: tx.input.clone(), blob_versioned_hashes: tx.blob_versioned_hashes.clone().unwrap_or_default(), - max_fee_per_blob_gas: tx.max_fee_per_blob_gas.unwrap().try_into().unwrap(), + max_fee_per_blob_gas: tx + .max_fee_per_blob_gas + .expect("No max fee per blob gas for the transaction"), }) .into_signed(signature), ), _ => unimplemented!(), - } + }) } #[cfg(test)] diff --git a/host/src/provider_db.rs b/host/src/provider_db.rs index 987e028fe..06dd9029a 100644 --- a/host/src/provider_db.rs +++ b/host/src/provider_db.rs @@ -23,7 +23,11 @@ use revm::{ }; use tokio::runtime::Handle; -use crate::{raiko::BlockDataProvider, MerkleProof}; +use crate::{ + error::{HostError, HostResult}, + raiko::BlockDataProvider, + MerkleProof, +}; pub struct ProviderDb { pub provider: BDP, @@ -41,20 +45,17 @@ pub struct ProviderDb { } impl ProviderDb { - pub async fn new( - provider: BDP, - chain_spec: ChainSpec, - block_number: u64, - ) -> Result { + pub async fn new(provider: BDP, chain_spec: ChainSpec, block_number: u64) -> HostResult { let mut provider_db = ProviderDb { provider, block_number, - initial_db: Default::default(), - initial_headers: Default::default(), - current_db: Default::default(), async_executor: tokio::runtime::Handle::current(), + // defaults optimistic: false, staging_db: Default::default(), + initial_db: Default::default(), + initial_headers: Default::default(), + current_db: Default::default(), pending_accounts: HashSet::new(), pending_slots: HashSet::new(), pending_block_hashes: HashSet::new(), @@ -68,8 +69,14 @@ impl ProviderDb { .collect::>(); let initial_history_blocks = provider_db.provider.get_blocks(&block_numbers).await?; for block in initial_history_blocks { - let block_number: u64 = block.header.number.unwrap().try_into().unwrap(); - let block_hash = block.header.hash.unwrap(); + let block_number: u64 = block + .header + .number + .ok_or_else(|| HostError::RPC("No block number".to_owned()))?; + let block_hash = block + .header + .hash + .ok_or_else(|| HostError::RPC("No block hash".to_owned()))?; provider_db .initial_db .insert_block_hash(block_number, block_hash); @@ -81,7 +88,7 @@ impl ProviderDb { Ok(provider_db) } - pub async fn get_proofs(&mut self) -> Result<(MerkleProof, MerkleProof, usize), anyhow::Error> { + pub async fn get_proofs(&mut self) -> HostResult<(MerkleProof, MerkleProof, usize)> { // Latest proof keys let mut storage_keys = self.initial_db.storage_keys(); for (address, mut indices) in self.current_db.storage_keys() { @@ -126,9 +133,7 @@ impl ProviderDb { Ok((initial_proofs, latest_proofs, num_storage_proofs)) } - pub async fn get_ancestor_headers( - &mut self, - ) -> Result, anyhow::Error> { + pub async fn get_ancestor_headers(&mut self) -> HostResult> { let earliest_block = self .initial_db .block_hashes @@ -136,7 +141,10 @@ impl ProviderDb { .min() .unwrap_or(&self.block_number); - let mut headers = Vec::new(); + let mut headers = Vec::with_capacity( + usize::try_from(self.block_number - *earliest_block) + .map_err(|_| HostError::Conversion("Could not convert u64 to usize".to_owned()))?, + ); for block_number in (*earliest_block..self.block_number).rev() { if let std::collections::hash_map::Entry::Vacant(e) = self.initial_headers.entry(block_number) @@ -144,7 +152,12 @@ impl ProviderDb { let block = &self.provider.get_blocks(&[(block_number, false)]).await?[0]; e.insert(to_header(&block.header)); } - headers.push(self.initial_headers[&block_number].clone()); + headers.push( + self.initial_headers + .get(&block_number) + .expect("The header is inserted if it was not present") + .clone(), + ); } Ok(headers) } @@ -157,7 +170,7 @@ impl ProviderDb { } impl Database for ProviderDb { - type Error = anyhow::Error; + type Error = HostError; fn basic(&mut self, address: Address) -> Result, Self::Error> { // Check if the account is in the current database. @@ -193,7 +206,10 @@ impl Database for ProviderDb { let account = &tokio::task::block_in_place(|| { self.async_executor .block_on(self.provider.get_accounts(&[address])) - })?[0]; + })? + .first() + .cloned() + .ok_or(HostError::RPC("No account".to_owned()))?; // Insert the account into the initial database. self.initial_db @@ -231,14 +247,19 @@ impl Database for ProviderDb { let value = tokio::task::block_in_place(|| { self.async_executor .block_on(self.provider.get_storage_values(&[(address, index)])) - })?[0]; + })? + .first() + .copied() + .ok_or(HostError::RPC("No storage value".to_owned()))?; self.initial_db .insert_account_storage(&address, index, value); Ok(value) } fn block_hash(&mut self, number: U256) -> Result { - let block_number = u64::try_from(number).unwrap(); + let block_number: u64 = number + .try_into() + .map_err(|_| HostError::Conversion("Could not convert U256 to u64".to_owned()))?; // Check if the block hash is in the current database. if let Ok(block_hash) = self.initial_db.block_hash(number) { @@ -261,13 +282,14 @@ impl Database for ProviderDb { let block_hash = tokio::task::block_in_place(|| { self.async_executor .block_on(self.provider.get_blocks(&[(block_number, false)])) - }) - .unwrap()[0] - .header - .hash - .unwrap() - .0 - .into(); + })? + .first() + .ok_or(HostError::RPC("No block".to_owned()))? + .header + .hash + .ok_or_else(|| HostError::RPC("No block hash".to_owned()))? + .0 + .into(); self.initial_db.insert_block_hash(block_number, block_hash); Ok(block_hash) } @@ -279,7 +301,7 @@ impl Database for ProviderDb { impl DatabaseCommit for ProviderDb { fn commit(&mut self, changes: HashMap) { - self.current_db.commit(changes) + self.current_db.commit(changes); } } @@ -292,11 +314,13 @@ impl OptimisticDatabase for ProviderDb { // This run was valid when no pending work was scheduled let valid_run = self.is_valid_run(); - let accounts = self + let Ok(accounts) = self .provider - .get_accounts(&self.pending_accounts.iter().cloned().collect::>()) + .get_accounts(&self.pending_accounts.iter().copied().collect::>()) .await - .unwrap(); + else { + return false; + }; for (address, account) in take(&mut self.pending_accounts) .into_iter() .zip(accounts.iter()) @@ -305,29 +329,33 @@ impl OptimisticDatabase for ProviderDb { .insert_account_info(address, account.clone()); } - let slots = self + let Ok(slots) = self .provider - .get_storage_values(&self.pending_slots.iter().cloned().collect::>()) + .get_storage_values(&self.pending_slots.iter().copied().collect::>()) .await - .unwrap(); + else { + return false; + }; for ((address, index), value) in take(&mut self.pending_slots).into_iter().zip(slots.iter()) { self.staging_db .insert_account_storage(&address, index, *value); } - let blocks = self + let Ok(blocks) = self .provider .get_blocks( &self .pending_block_hashes .iter() - .cloned() + .copied() .map(|block_number| (block_number, false)) .collect::>(), ) .await - .unwrap(); + else { + return false; + }; for (block_number, block) in take(&mut self.pending_block_hashes) .into_iter() .zip(blocks.iter()) diff --git a/host/src/raiko.rs b/host/src/raiko.rs index 647ad202c..04917e012 100644 --- a/host/src/raiko.rs +++ b/host/src/raiko.rs @@ -1,40 +1,36 @@ use alloy_primitives::{Address, FixedBytes, B256, U256}; use alloy_rpc_types::Block; -use anyhow::Result; use raiko_lib::builder::{BlockBuilderStrategy, TaikoStrategy}; use raiko_lib::consts::ChainSpec; -use raiko_lib::input::{GuestInput, GuestOutput, TaikoProverData, WrappedHeader}; +use raiko_lib::input::{GuestInput, GuestOutput, TaikoProverData}; use raiko_lib::protocol_instance::{assemble_protocol_instance, ProtocolInstance}; use raiko_lib::prover::{to_proof, Proof, Prover, ProverError, ProverResult}; use raiko_lib::utils::HeaderHasher; use revm::primitives::AccountInfo; use serde::{Deserialize, Serialize}; use std::collections::HashMap; -use tracing::{trace, warn}; +use tracing::{error, info, trace, warn}; -use crate::error::{self, HostError}; +use crate::error::{self, HostError, HostResult}; use crate::preflight::preflight; use crate::request::ProofRequest; use crate::MerkleProof; #[allow(async_fn_in_trait)] pub trait BlockDataProvider { - async fn get_blocks( - &self, - blocks_to_fetch: &[(u64, bool)], - ) -> Result, anyhow::Error>; - async fn get_accounts(&self, accounts: &[Address]) -> Result, anyhow::Error>; - async fn get_storage_values( - &self, - accounts: &[(Address, U256)], - ) -> Result, anyhow::Error>; + async fn get_blocks(&self, blocks_to_fetch: &[(u64, bool)]) -> HostResult>; + + async fn get_accounts(&self, accounts: &[Address]) -> HostResult>; + + async fn get_storage_values(&self, accounts: &[(Address, U256)]) -> HostResult>; + async fn get_merkle_proofs( &self, block_number: u64, accounts: HashMap>, offset: usize, num_storage_proofs: usize, - ) -> Result; + ) -> HostResult; } pub struct Raiko { @@ -53,7 +49,7 @@ impl Raiko { pub async fn generate_input( &self, provider: BDP, - ) -> Result { + ) -> HostResult { preflight( provider, self.request.block_number, @@ -69,12 +65,12 @@ impl Raiko { .map_err(Into::::into) } - pub fn get_output(&self, input: &GuestInput) -> Result { + pub fn get_output(&self, input: &GuestInput) -> HostResult { match TaikoStrategy::build_from(input) { Ok((header, _mpt_node)) => { - println!("Verifying final state using provider data ..."); - println!("Final block hash derived successfully. {}", header.hash()); - println!("Final block header derived successfully. {:?}", header); + info!("Verifying final state using provider data ..."); + info!("Final block hash derived successfully. {}", header.hash()); + info!("Final block header derived successfully. {header:?}"); let pi = self .request .proof_type @@ -82,48 +78,48 @@ impl Raiko { // Check against the expected value of all fields for easy debugability let exp = &input.block_header_reference; - check_eq(exp.parent_hash, header.parent_hash, "base_fee_per_gas"); - check_eq(exp.ommers_hash, header.ommers_hash, "ommers_hash"); - check_eq(exp.beneficiary, header.beneficiary, "beneficiary"); - check_eq(exp.state_root, header.state_root, "state_root"); + check_eq(&exp.parent_hash, &header.parent_hash, "base_fee_per_gas"); + check_eq(&exp.ommers_hash, &header.ommers_hash, "ommers_hash"); + check_eq(&exp.beneficiary, &header.beneficiary, "beneficiary"); + check_eq(&exp.state_root, &header.state_root, "state_root"); check_eq( - exp.transactions_root, - header.transactions_root, + &exp.transactions_root, + &header.transactions_root, "transactions_root", ); - check_eq(exp.receipts_root, header.receipts_root, "receipts_root"); + check_eq(&exp.receipts_root, &header.receipts_root, "receipts_root"); check_eq( - exp.withdrawals_root, - header.withdrawals_root, + &exp.withdrawals_root, + &header.withdrawals_root, "withdrawals_root", ); - check_eq(exp.logs_bloom, header.logs_bloom, "logs_bloom"); - check_eq(exp.difficulty, header.difficulty, "difficulty"); - check_eq(exp.number, header.number, "number"); - check_eq(exp.gas_limit, header.gas_limit, "gas_limit"); - check_eq(exp.gas_used, header.gas_used, "gas_used"); - check_eq(exp.timestamp, header.timestamp, "timestamp"); - check_eq(exp.mix_hash, header.mix_hash, "mix_hash"); - check_eq(exp.nonce, header.nonce, "nonce"); + check_eq(&exp.logs_bloom, &header.logs_bloom, "logs_bloom"); + check_eq(&exp.difficulty, &header.difficulty, "difficulty"); + check_eq(&exp.number, &header.number, "number"); + check_eq(&exp.gas_limit, &header.gas_limit, "gas_limit"); + check_eq(&exp.gas_used, &header.gas_used, "gas_used"); + check_eq(&exp.timestamp, &header.timestamp, "timestamp"); + check_eq(&exp.mix_hash, &header.mix_hash, "mix_hash"); + check_eq(&exp.nonce, &header.nonce, "nonce"); check_eq( - exp.base_fee_per_gas, - header.base_fee_per_gas, + &exp.base_fee_per_gas, + &header.base_fee_per_gas, "base_fee_per_gas", ); - check_eq(exp.blob_gas_used, header.blob_gas_used, "blob_gas_used"); + check_eq(&exp.blob_gas_used, &header.blob_gas_used, "blob_gas_used"); check_eq( - exp.excess_blob_gas, - header.excess_blob_gas, + &exp.excess_blob_gas, + &header.excess_blob_gas, "excess_blob_gas", ); check_eq( - exp.parent_beacon_block_root, - header.parent_beacon_block_root, + &exp.parent_beacon_block_root, + &header.parent_beacon_block_root, "parent_beacon_block_root", ); check_eq( - exp.extra_data.clone(), - header.extra_data.clone(), + &exp.extra_data.clone(), + &header.extra_data.clone(), "extra_data", ); @@ -133,18 +129,13 @@ impl Raiko { input.block_hash_reference, "block hash unexpected" ); - let output = GuestOutput::Success(( - WrappedHeader { - header: header.clone(), - }, - pi, - )); + let output = GuestOutput::Success { header, hash: pi }; Ok(output) } Err(e) => { warn!("Proving bad block construction!"); - Err(HostError::GuestError( + Err(HostError::Guest( raiko_lib::prover::ProverError::GuestError(e.to_string()), )) } @@ -155,7 +146,7 @@ impl Raiko { &self, input: GuestInput, output: &GuestOutput, - ) -> Result { + ) -> HostResult { self.request .proof_type .run_prover( @@ -180,14 +171,14 @@ impl Prover for NativeProver { output: &GuestOutput, _request: &serde_json::Value, ) -> ProverResult { - trace!("Running the native prover for input {:?}", input); - match output.clone() { - GuestOutput::Success((wrapped_header, _)) => { - assemble_protocol_instance(&input, &wrapped_header.header) - .map_err(|e| ProverError::GuestError(e.to_string()))?; - } - _ => return Err(ProverError::GuestError("Unexpected output".to_string())), - } + trace!("Running the native prover for input {input:?}"); + + let GuestOutput::Success { header, .. } = output.clone() else { + return Err(ProverError::GuestError("Unexpected output".to_owned())); + }; + + assemble_protocol_instance(&input, &header) + .map_err(|e| ProverError::GuestError(e.to_string()))?; to_proof(Ok(NativeResponse { output: output.clone(), @@ -199,12 +190,9 @@ impl Prover for NativeProver { } } -fn check_eq(expected: T, actual: T, message: &str) { +fn check_eq(expected: &T, actual: &T, message: &str) { if expected != actual { - println!( - "Assertion failed: {} - Expected: {:?}, Found: {:?}", - message, expected, actual - ); + error!("Assertion failed: {message} - Expected: {expected:?}, Found: {actual:?}"); } } @@ -260,7 +248,8 @@ mod tests { async fn prove_block(chain_spec: ChainSpec, proof_request: ProofRequest) { let provider = - RpcBlockDataProvider::new(&proof_request.rpc.clone(), proof_request.block_number - 1); + RpcBlockDataProvider::new(&proof_request.rpc.clone(), proof_request.block_number - 1) + .expect("Could not create RpcBlockDataProvider"); let raiko = Raiko::new(chain_spec, proof_request.clone()); let mut input = raiko .generate_input(provider) diff --git a/host/src/request.rs b/host/src/request.rs index dcc89496f..257911d64 100644 --- a/host/src/request.rs +++ b/host/src/request.rs @@ -203,30 +203,35 @@ pub struct ProofRequestOpt { #[derive(Default, Clone, Serialize, Deserialize, Debug, ToSchema, Args)] pub struct ProverSpecificOpts { + /// Native prover specific options. pub native: Option, + /// SGX prover specific options. pub sgx: Option, + /// SP1 prover specific options. pub sp1: Option, + /// RISC0 prover specific options. pub risc0: Option, } -impl From for HashMap { +impl From + for HashMap +{ fn from(value: ProverSpecificOpts) -> Self { - HashMap::from_iter( - [ - ("native", value.native.clone()), - ("sgx", value.sgx.clone()), - ("sp1", value.sp1.clone()), - ("risc0", value.risc0.clone()), - ] - .into_iter() - .filter_map(|(name, value)| value.map(|v| (name.to_string(), v))), - ) + [ + ("native", value.native.clone()), + ("sgx", value.sgx.clone()), + ("sp1", value.sp1.clone()), + ("risc0", value.risc0.clone()), + ] + .into_iter() + .filter_map(|(name, value)| value.map(|v| (name.to_string(), v))) + .collect() } } impl ProofRequestOpt { /// Read a partial proof request config from a file. - pub fn from_file(path: T) -> Result + pub fn from_file(path: T) -> HostResult where T: AsRef, { @@ -237,7 +242,7 @@ impl ProofRequestOpt { } /// Merge a partial proof request into current one. - pub fn merge(&mut self, other: &Value) -> Result<(), HostError> { + pub fn merge(&mut self, other: &Value) -> HostResult<()> { let mut this = serde_json::to_value(&self)?; merge(&mut this, other); *self = serde_json::from_value(this)?; diff --git a/host/src/rpc_provider.rs b/host/src/rpc_provider.rs index 336bd2a59..548df4c19 100644 --- a/host/src/rpc_provider.rs +++ b/host/src/rpc_provider.rs @@ -3,13 +3,16 @@ use alloy_provider::{ProviderBuilder, ReqwestProvider, RootProvider}; use alloy_rpc_client::{ClientBuilder, RpcClient}; use alloy_rpc_types::{Block, BlockId, BlockNumberOrTag, EIP1186AccountProofResponse}; use alloy_transport_http::Http; -use anyhow::Result; use raiko_lib::{clear_line, inplace_print}; use reqwest_alloy::Client; use revm::primitives::{AccountInfo, Bytecode}; use std::collections::HashMap; -use crate::{raiko::BlockDataProvider, MerkleProof}; +use crate::{ + error::{HostError, HostResult}, + raiko::BlockDataProvider, + MerkleProof, +}; pub struct RpcBlockDataProvider { pub provider: ReqwestProvider, @@ -18,13 +21,14 @@ pub struct RpcBlockDataProvider { } impl RpcBlockDataProvider { - pub fn new(url: &str, block_number: u64) -> Self { - let url = reqwest::Url::parse(url).expect("invalid rpc url"); - Self { + pub fn new(url: &str, block_number: u64) -> HostResult { + let url = + reqwest::Url::parse(url).map_err(|_| HostError::RPC("Invalid RPC URL".to_owned()))?; + Ok(Self { provider: ProviderBuilder::new().on_provider(RootProvider::new_http(url.clone())), client: ClientBuilder::default().http(url), block_number, - } + }) } pub fn provider(&self) -> &ReqwestProvider { @@ -33,30 +37,42 @@ impl RpcBlockDataProvider { } impl BlockDataProvider for RpcBlockDataProvider { - async fn get_blocks( - &self, - blocks_to_fetch: &[(u64, bool)], - ) -> Result, anyhow::Error> { - let mut all_blocks = Vec::new(); + async fn get_blocks(&self, blocks_to_fetch: &[(u64, bool)]) -> HostResult> { + let mut all_blocks = Vec::with_capacity(blocks_to_fetch.len()); let max_batch_size = 32; for blocks_to_fetch in blocks_to_fetch.chunks(max_batch_size) { let mut batch = self.client.new_batch(); - let mut requests = vec![]; + let mut requests = Vec::with_capacity(max_batch_size); - for (block_number, full) in blocks_to_fetch.iter() { - requests.push(Box::pin(batch.add_call( - "eth_getBlockByNumber", - &(BlockNumberOrTag::from(*block_number), full), - )?)); + for (block_number, full) in blocks_to_fetch { + requests.push(Box::pin( + batch + .add_call( + "eth_getBlockByNumber", + &(BlockNumberOrTag::from(*block_number), full), + ) + .map_err(|_| { + HostError::RPC( + "Failed adding eth_getBlockByNumber call to batch".to_owned(), + ) + })?, + )); } - batch.send().await?; + batch + .send() + .await + .map_err(|_| HostError::RPC("Error sending batch request".to_owned()))?; - let mut blocks = vec![]; + let mut blocks = Vec::with_capacity(max_batch_size); // Collect the data from the batch - for request in requests.into_iter() { - blocks.push(request.await?); + for request in requests { + blocks.push( + request + .await + .map_err(|_| HostError::RPC("Error collecting request data".to_owned()))?, + ); } all_blocks.append(&mut blocks); @@ -65,16 +81,16 @@ impl BlockDataProvider for RpcBlockDataProvider { Ok(all_blocks) } - async fn get_accounts(&self, accounts: &[Address]) -> Result, anyhow::Error> { - let mut all_accounts = Vec::new(); + async fn get_accounts(&self, accounts: &[Address]) -> HostResult> { + let mut all_accounts = Vec::with_capacity(accounts.len()); let max_batch_size = 250; for accounts in accounts.chunks(max_batch_size) { let mut batch = self.client.new_batch(); - let mut nonce_requests = Vec::new(); - let mut balance_requests = Vec::new(); - let mut code_requests = Vec::new(); + let mut nonce_requests = Vec::with_capacity(max_batch_size); + let mut balance_requests = Vec::with_capacity(max_batch_size); + let mut code_requests = Vec::with_capacity(max_batch_size); for address in accounts { nonce_requests.push(Box::pin( @@ -83,7 +99,11 @@ impl BlockDataProvider for RpcBlockDataProvider { "eth_getTransactionCount", &(address, Some(BlockId::from(self.block_number))), ) - .unwrap(), + .map_err(|_| { + HostError::RPC( + "Failed adding eth_getTransactionCount call to batch".to_owned(), + ) + })?, )); balance_requests.push(Box::pin( batch @@ -91,7 +111,9 @@ impl BlockDataProvider for RpcBlockDataProvider { "eth_getBalance", &(address, Some(BlockId::from(self.block_number))), ) - .unwrap(), + .map_err(|_| { + HostError::RPC("Failed adding eth_getBalance call to batch".to_owned()) + })?, )); code_requests.push(Box::pin( batch @@ -99,30 +121,43 @@ impl BlockDataProvider for RpcBlockDataProvider { "eth_getCode", &(address, Some(BlockId::from(self.block_number))), ) - .unwrap(), + .map_err(|_| { + HostError::RPC("Failed adding eth_getCode call to batch".to_owned()) + })?, )); } - batch.send().await?; + batch + .send() + .await + .map_err(|_| HostError::RPC("Error sending batch request".to_owned()))?; let mut accounts = vec![]; // Collect the data from the batch - for (nonce_request, (balance_request, code_request)) in nonce_requests + for ((nonce_request, balance_request), code_request) in nonce_requests .into_iter() - .zip(balance_requests.into_iter().zip(code_requests.into_iter())) + .zip(balance_requests.into_iter()) + .zip(code_requests.into_iter()) { let (nonce, balance, code) = ( - nonce_request.await?, - balance_request.await?, - code_request.await?, + nonce_request.await.map_err(|_| { + HostError::RPC("Failed to collect nonce request".to_owned()) + })?, + balance_request.await.map_err(|_| { + HostError::RPC("Failed to collect balance request".to_owned()) + })?, + code_request + .await + .map_err(|_| HostError::RPC("Failed to collect code request".to_owned()))?, ); - let account_info = AccountInfo::new( - balance, - nonce.try_into().unwrap(), - Bytecode::new_raw(code.clone()).hash_slow(), - Bytecode::new_raw(code), - ); + let nonce = nonce.try_into().map_err(|_| { + HostError::Conversion("Failed to convert nonce to u64".to_owned()) + })?; + + let bytecode = Bytecode::new_raw(code); + + let account_info = AccountInfo::new(balance, nonce, bytecode.hash_slow(), bytecode); accounts.push(account_info); } @@ -133,17 +168,14 @@ impl BlockDataProvider for RpcBlockDataProvider { Ok(all_accounts) } - async fn get_storage_values( - &self, - accounts: &[(Address, U256)], - ) -> Result, anyhow::Error> { - let mut all_values = Vec::new(); + async fn get_storage_values(&self, accounts: &[(Address, U256)]) -> HostResult> { + let mut all_values = Vec::with_capacity(accounts.len()); let max_batch_size = 1000; for accounts in accounts.chunks(max_batch_size) { let mut batch = self.client.new_batch(); - let mut requests = Vec::new(); + let mut requests = Vec::with_capacity(max_batch_size); for (address, key) in accounts { requests.push(Box::pin( @@ -152,16 +184,27 @@ impl BlockDataProvider for RpcBlockDataProvider { "eth_getStorageAt", &(address, key, Some(BlockId::from(self.block_number))), ) - .unwrap(), + .map_err(|_| { + HostError::RPC( + "Failed adding eth_getStorageAt call to batch".to_owned(), + ) + })?, )); } - batch.send().await?; + batch + .send() + .await + .map_err(|_| HostError::RPC("Error sending batch request".to_owned()))?; - let mut values = vec![]; + let mut values = Vec::with_capacity(max_batch_size); // Collect the data from the batch - for request in requests.into_iter() { - values.push(request.await?); + for request in requests { + values.push( + request + .await + .map_err(|_| HostError::RPC("Error collecting request data".to_owned()))?, + ); } all_values.append(&mut values); @@ -176,7 +219,7 @@ impl BlockDataProvider for RpcBlockDataProvider { accounts: HashMap>, offset: usize, num_storage_proofs: usize, - ) -> Result { + ) -> HostResult { let mut storage_proofs: MerkleProof = HashMap::new(); let mut idx = offset; @@ -197,6 +240,7 @@ impl BlockDataProvider for RpcBlockDataProvider { let mut batch_size = 0; while !accounts.is_empty() && batch_size < batch_limit { let mut address_to_remove = None; + if let Some((address, keys)) = accounts.iter_mut().next() { // Calculate how many keys we can still process let num_keys_to_process = if batch_size + keys.len() < batch_limit { @@ -227,7 +271,11 @@ impl BlockDataProvider for RpcBlockDataProvider { BlockId::from(block_number), ), ) - .unwrap(), + .map_err(|_| { + HostError::RPC( + "Failed adding eth_getProof call to batch".to_owned(), + ) + })?, )); // Keep track of how many keys were processed @@ -242,11 +290,16 @@ impl BlockDataProvider for RpcBlockDataProvider { } // Send the batch - batch.send().await?; + batch + .send() + .await + .map_err(|_| HostError::RPC("Error sending batch request".to_owned()))?; // Collect the data from the batch - for request in requests.into_iter() { - let mut proof = request.await?; + for request in requests { + let mut proof = request + .await + .map_err(|_| HostError::RPC("Error collecting request data".to_owned()))?; idx += proof.storage_proof.len(); if let Some(map_proof) = storage_proofs.get_mut(&proof.address) { map_proof.storage_proof.append(&mut proof.storage_proof); diff --git a/host/src/server/api/mod.rs b/host/src/server/api/mod.rs index 9e96e5918..863bd615a 100644 --- a/host/src/server/api/mod.rs +++ b/host/src/server/api/mod.rs @@ -6,6 +6,8 @@ use axum::{ response::Response, Router, }; +use raiko_lib::input::GuestOutput; +use serde::Serialize; use tower::ServiceBuilder; use tower_http::{ compression::CompressionLayer, @@ -13,7 +15,8 @@ use tower_http::{ set_header::SetResponseHeaderLayer, trace::TraceLayer, }; -use utoipa::OpenApi; +use utoipa::{OpenApi, ToSchema}; +use utoipa_scalar::{Scalar, Servable}; use utoipa_swagger_ui::SwaggerUi; use crate::ProverState; @@ -42,10 +45,13 @@ mod proof; schemas( crate::request::ProofRequestOpt, crate::error::HostError, + crate::request::ProverSpecificOpts, + GuestOutputDoc, + ProofResponse, ) ), tags( - (name = "Prooving", description = "Routes that handle prooving requests"), + (name = "Proving", description = "Routes that handle proving requests"), (name = "Health", description = "Routes that report the server health status"), (name = "Metrics", description = "Routes that give detailed insight into the server") ) @@ -53,6 +59,32 @@ mod proof; /// The root API struct which is generated from the `OpenApi` derive macro. pub struct Docs; +#[derive(Debug, Serialize, ToSchema)] +/// The response body of a proof request. +pub struct ProofResponse { + #[schema(value_type = Option)] + /// The output of the prover. + output: Option, + /// The proof. + proof: Option, + /// The quote. + quote: Option, +} + +#[derive(Debug, Serialize, ToSchema)] +pub enum GuestOutputDoc { + #[schema(example = json!({"header": [0, 0, 0, 0], "hash":"0x0...0"}))] + /// The output of the prover when the proof generation was successful. + Success { + /// Header bytes. + header: Vec, + /// Instance hash. + hash: String, + }, + /// The output of the prover when the proof generation failed. + Failure, +} + #[must_use] pub fn create_docs() -> utoipa::openapi::OpenApi { [ @@ -88,6 +120,8 @@ pub fn create_router(concurrency_limit: usize) -> Router { let trace = TraceLayer::new_for_http(); + let docs = create_docs(); + Router::new() // Only add the concurrency limit to the proof route. We want to still be able to call // healthchecks and metrics to have insight into the system. @@ -101,7 +135,8 @@ pub fn create_router(concurrency_limit: usize) -> Router { .layer(middleware) .layer(middleware::from_fn(check_max_body_size)) .layer(trace) - .merge(SwaggerUi::new("/swagger-ui").url("/api-docs/openapi.json", create_docs())) + .merge(SwaggerUi::new("/swagger-ui").url("/api-docs/openapi.json", docs.clone())) + .merge(Scalar::with_url("/scalar", docs)) .fallback(|uri: Uri| async move { (StatusCode::NOT_FOUND, format!("No handler found for {uri}")) }) diff --git a/host/src/server/api/proof.rs b/host/src/server/api/proof.rs index a1e22d5ae..fccf9c6c9 100644 --- a/host/src/server/api/proof.rs +++ b/host/src/server/api/proof.rs @@ -9,6 +9,7 @@ use raiko_lib::{ Measurement, }; use serde_json::Value; +use tracing::{debug, info}; use utoipa::OpenApi; use crate::{ @@ -44,14 +45,14 @@ fn set_cached_input( cache_path: &Option, block_number: u64, network: &str, - input: GuestInput, + input: &GuestInput, ) -> HostResult<()> { if let Some(dir) = cache_path.as_ref() { let path = get_input_path(dir, block_number, network); if !path.exists() { let file = File::create(&path).map_err(>::into)?; - println!("caching input for {path:?}"); - bincode::serialize_into(file, &input).map_err(|e| HostError::Anyhow(e.into()))?; + info!("caching input for {path:?}"); + bincode::serialize_into(file, input).map_err(|e| HostError::Anyhow(e.into()))?; } } Ok(()) @@ -59,8 +60,9 @@ fn set_cached_input( #[utoipa::path(post, path = "/proof", tag = "Proving", + request_body = ProofRequestOpt, responses ( - (status = 200, description = "Successfully created proof for request") + (status = 200, description = "Successfully created proof for request", body = ProofResponse) ) )] #[debug_handler(state = ProverState)] @@ -89,7 +91,7 @@ async fn proof_handler( })?; inc_host_req_count(proof_request.block_number); - println!( + info!( "# Generating proof for block {} on {}", proof_request.block_number, proof_request.network ); @@ -108,16 +110,16 @@ async fn proof_handler( let raiko = Raiko::new(chain_spec, proof_request.clone()); let input = if let Some(cached_input) = cached_input { - println!("Using cached input"); + debug!("Using cached input"); cached_input } else { memory::reset_stats(); let measurement = Measurement::start("Generating input...", false); let provider = - RpcBlockDataProvider::new(&proof_request.rpc.clone(), proof_request.block_number - 1); + RpcBlockDataProvider::new(&proof_request.rpc.clone(), proof_request.block_number - 1)?; let input = raiko.generate_input(provider).await?; let input_time = measurement.stop_with("=> Input generated"); - observe_prepare_input_time(proof_request.block_number, input_time.as_millis(), true); + observe_prepare_input_time(proof_request.block_number, input_time, true); memory::print_stats("Input generation peak memory used: "); input }; @@ -130,11 +132,11 @@ async fn proof_handler( let proof = raiko.prove(input.clone(), &output).await.map_err(|e| { dec_current_req(); let total_time = total_time.stop_with("====> Proof generation failed"); - observe_total_time(proof_request.block_number, total_time.as_millis(), false); + observe_total_time(proof_request.block_number, total_time, false); match e { - HostError::GuestError(e) => { + HostError::Guest(e) => { inc_guest_error(&proof_request.proof_type, proof_request.block_number); - HostError::GuestError(e) + HostError::Guest(e) } e => { inc_host_error(proof_request.block_number); @@ -146,21 +148,21 @@ async fn proof_handler( observe_guest_time( &proof_request.proof_type, proof_request.block_number, - guest_time.as_millis(), + guest_time, true, ); memory::print_stats("Prover peak memory used: "); inc_guest_success(&proof_request.proof_type, proof_request.block_number); let total_time = total_time.stop_with("====> Complete proof generated"); - observe_total_time(proof_request.block_number, total_time.as_millis(), true); + observe_total_time(proof_request.block_number, total_time, true); // Cache the input for future use. set_cached_input( &opts.cache_path, proof_request.block_number, &proof_request.network.to_string(), - input, + &input, ) .map_err(|e| { dec_current_req(); diff --git a/lib/src/input.rs b/lib/src/input.rs index 7c67706e6..0d6d6a980 100644 --- a/lib/src/input.rs +++ b/lib/src/input.rs @@ -19,7 +19,7 @@ use alloy_consensus::Header as AlloyConsensusHeader; use alloy_rpc_types::Withdrawal as AlloyWithdrawal; use alloy_sol_types::{sol, SolCall}; use anyhow::{anyhow, Result}; -use raiko_primitives::{mpt::MptNode, Address, Bytes, FixedBytes, B256, U256}; +use raiko_primitives::{mpt::MptNode, Address, Bytes, B256, U256}; use revm::primitives::HashMap; use serde::{Deserialize, Serialize}; use serde_with::serde_as; @@ -103,19 +103,17 @@ pub struct TaikoProverData { pub graffiti: B256, } +#[serde_as] #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] pub enum GuestOutput { - Success((WrappedHeader, FixedBytes<32>)), + Success { + #[serde_as(as = "RlpBytes")] + header: AlloyConsensusHeader, + hash: B256, + }, Failure, } -#[serde_as] -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -pub struct WrappedHeader { - #[serde_as(as = "RlpBytes")] - pub header: AlloyConsensusHeader, -} - sol! { function anchor( bytes32 l1Hash, diff --git a/lib/src/utils.rs b/lib/src/utils.rs index 23dbf3c2e..b1d3f1d41 100644 --- a/lib/src/utils.rs +++ b/lib/src/utils.rs @@ -41,8 +41,11 @@ pub fn decode_transactions(tx_list: &[u8]) -> Vec { match Vec::::decode(&mut &tx_list.to_owned()[..]) { Ok(transactions) => transactions, Err(e) => { - // a empty vec - println!("decode_transactions error: {:?}, use empty tx_list", e); + // If decoding fails we need to make an empty block + println!( + "decode_transactions not successful: {:?}, use empty tx_list", + e + ); vec![] } } @@ -77,13 +80,9 @@ pub fn generate_transactions( TxEip1559 { chain_id: anchor_tx.chain_id.unwrap(), nonce: anchor_tx.nonce, - gas_limit: anchor_tx.gas.try_into().unwrap(), - max_fee_per_gas: anchor_tx.max_fee_per_gas.unwrap().try_into().unwrap(), - max_priority_fee_per_gas: anchor_tx - .max_priority_fee_per_gas - .unwrap() - .try_into() - .unwrap(), + gas_limit: anchor_tx.gas, + max_fee_per_gas: anchor_tx.max_fee_per_gas.unwrap(), + max_priority_fee_per_gas: anchor_tx.max_priority_fee_per_gas.unwrap(), to: TxKind::Call(anchor_tx.to.unwrap()), value: anchor_tx.value, access_list: Default::default(), @@ -343,23 +342,17 @@ pub fn to_header(header: &AlloyHeader) -> AlloyConsensusHeader { receipts_root: header.receipts_root, logs_bloom: header.logs_bloom, difficulty: header.difficulty, - number: header.number.unwrap().try_into().unwrap(), - gas_limit: header.gas_limit.try_into().unwrap(), - gas_used: header.gas_used.try_into().unwrap(), - timestamp: header.timestamp.try_into().unwrap(), + number: header.number.unwrap(), + gas_limit: header.gas_limit, + gas_used: header.gas_used, + timestamp: header.timestamp, extra_data: header.extra_data.clone(), mix_hash: header.mix_hash.unwrap(), nonce: header.nonce.unwrap(), - base_fee_per_gas: Some( - header - .base_fee_per_gas - .unwrap_or_default() - .try_into() - .unwrap(), - ), + base_fee_per_gas: header.base_fee_per_gas, withdrawals_root: header.withdrawals_root, - blob_gas_used: header.blob_gas_used.map(|x| x.try_into().unwrap()), - excess_blob_gas: header.excess_blob_gas.map(|x| x.try_into().unwrap()), + blob_gas_used: header.blob_gas_used, + excess_blob_gas: header.excess_blob_gas, parent_beacon_block_root: header.parent_beacon_block_root, } } diff --git a/provers/risc0/guest/Cargo.lock b/provers/risc0/guest/Cargo.lock index f38b94ebe..61f9e5b7c 100644 --- a/provers/risc0/guest/Cargo.lock +++ b/provers/risc0/guest/Cargo.lock @@ -1751,6 +1751,7 @@ dependencies = [ "alloy-sol-types", "anyhow", "c-kzg-taiko", + "cfg-if", "chrono", "flate2", "hex", diff --git a/provers/risc0/guest/src/main.rs b/provers/risc0/guest/src/main.rs index 1b83e492a..23a2fc5e4 100644 --- a/provers/risc0/guest/src/main.rs +++ b/provers/risc0/guest/src/main.rs @@ -6,7 +6,7 @@ use raiko_lib::protocol_instance::assemble_protocol_instance; use raiko_lib::protocol_instance::EvidenceType; use raiko_lib::{ builder::{BlockBuilderStrategy, TaikoStrategy}, - input::{GuestInput, GuestOutput, WrappedHeader}, + input::{GuestInput, GuestOutput}, }; use revm_precompile::zk_op::ZkOperation; use zk_op::Risc0Operator; @@ -32,12 +32,10 @@ fn main() { let pi = assemble_protocol_instance(&input, header) .expect("Failed to assemble protocol instance") .instance_hash(EvidenceType::Risc0); - GuestOutput::Success(( - WrappedHeader { - header: header.clone(), - }, - pi, - )) + GuestOutput::Success { + header: header.clone(), + hash: pi, + } } Err(_) => GuestOutput::Failure, }; @@ -45,7 +43,6 @@ fn main() { env::commit(&output); } - harness::zk_suits!( pub mod tests { #[test] diff --git a/provers/sp1/guest/Cargo.lock b/provers/sp1/guest/Cargo.lock index 09659a799..f9b598dbd 100644 --- a/provers/sp1/guest/Cargo.lock +++ b/provers/sp1/guest/Cargo.lock @@ -1579,6 +1579,7 @@ dependencies = [ "alloy-sol-types", "anyhow", "c-kzg-taiko", + "cfg-if", "chrono", "flate2", "hex", diff --git a/provers/sp1/guest/src/main.rs b/provers/sp1/guest/src/main.rs index f1f25d234..5aedb69f9 100644 --- a/provers/sp1/guest/src/main.rs +++ b/provers/sp1/guest/src/main.rs @@ -4,7 +4,7 @@ harness::entrypoint!(main, tests, zk_op::tests); use raiko_lib::{ builder::{BlockBuilderStrategy, TaikoStrategy}, - input::{GuestInput, GuestOutput, WrappedHeader}, + input::{GuestInput, GuestOutput}, protocol_instance::{assemble_protocol_instance, EvidenceType}, }; use revm_precompile::zk_op::ZkOperation; @@ -32,12 +32,10 @@ pub fn main() { let pi = assemble_protocol_instance(&input, header) .expect("Failed to assemble protocol instance") .instance_hash(EvidenceType::Succinct); - GuestOutput::Success(( - WrappedHeader { - header: header.clone(), - }, - pi, - )) + GuestOutput::Success { + header: header.clone(), + hash: pi, + } } Err(_) => GuestOutput::Failure, }; diff --git a/script/generate-docs.sh b/script/generate-docs.sh new file mode 100755 index 000000000..219205ee6 --- /dev/null +++ b/script/generate-docs.sh @@ -0,0 +1,8 @@ +#!/usr/bin/env bash + +DIR="$(cd "$(dirname "$0")" && pwd)" + +cd $DIR + +mkdir ../openapi +cargo run --bin docs >../openapi/index.html