diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 38f96b0fc..dd9880bd6 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -7,6 +7,9 @@ on:
 
 env:
   CARGO_TERM_COLOR: always
+  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+  RISC0_VERSION: 0.19.1
+  RISC0_TOOLCHAIN_VERSION: test-release-2
 
 concurrency:
   group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
@@ -18,36 +21,40 @@ jobs:
     runs-on: ubuntu-latest
     timeout-minutes: 60
     steps:
-      - uses: actions/checkout@v3
-        with:
-          submodules: recursive
-      - uses: risc0/risc0/.github/actions/rustup@release-0.18
-      - uses: risc0/risc0/.github/actions/sccache@release-0.18
-      # - run: cargo install cargo-risczero && cargo risczero install
-      - run: cargo test --workspace --all-targets --all-features --exclude sgx-ra
+    - uses: actions/checkout@v4
+      with:
+        submodules: recursive
+    - uses: risc0/risc0/.github/actions/rustup@release-0.19
+    - uses: risc0/risc0/.github/actions/sccache@release-0.19
+    - uses: risc0/cargo-install@v1
+      with:
+        crate: cargo-binstall
+    - run: cargo binstall -y --force cargo-risczero@${{ env.RISC0_VERSION }}
+    - run: cargo risczero install --version $RISC0_TOOLCHAIN_VERSION
+    - run: cargo test --workspace --all-targets --features taiko
+    - run: cargo test --workspace --all-targets --features "taiko std"
+    - run: cargo test --workspace --all-targets --features optimism
+
 
   clippy:
     name: clippy
     runs-on: ubuntu-latest
     timeout-minutes: 30
     steps:
-      - uses: actions/checkout@v3
-        with:
-          submodules: recursive
-      - uses: risc0/risc0/.github/actions/rustup@release-0.18
-      - uses: risc0/risc0/.github/actions/sccache@release-0.18
-      - uses: risc0/clippy-action@main
-        with:
-          reporter: "github-pr-check"
-          fail_on_error: true
-          github_token: ${{ secrets.GITHUB_TOKEN }}
-          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@v3
-      - uses: risc0/risc0/.github/actions/rustup@release-0.18
-      - run: cargo fmt --all --check
+    - uses: actions/checkout@v4
+    - uses: risc0/risc0/.github/actions/rustup@release-0.19
+    - run: cargo fmt --all --check
diff --git a/.vscode/settings.json b/.vscode/settings.json
index e3c59b6bd..60926f4b7 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,4 +1,6 @@
 {
-  "rust-analyzer.cargo.features": "all",
-  "rust-analyzer.linkedProjects": ["./Cargo.toml"]
+    "rust-analyzer.cargo.features": "all",
+    "rust-analyzer.linkedProjects": [
+        "./Cargo.toml",
+    ]
 }
diff --git a/Cargo.lock b/Cargo.lock
index 80b823c3a..90a41de32 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -17,11 +17,17 @@ version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
 
+[[package]]
+name = "adler32"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234"
+
 [[package]]
 name = "ahash"
-version = "0.8.6"
+version = "0.8.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a"
+checksum = "42cd52102d3df161c77a887b608d7a4897d7cc112886a9537b738a887a03aaff"
 dependencies = [
  "cfg-if",
  "once_cell",
@@ -46,9 +52,9 @@ checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5"
 
 [[package]]
 name = "alloy-dyn-abi"
-version = "0.4.2"
+version = "0.6.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e4e0daba57ddaba12dc9b21f608b843251f3de017f94a431dca4e7f4f72e5ba9"
+checksum = "c7265ac54c88a78604cea8444addfa9dfdad08d3098f153484cb4ee66fc202cc"
 dependencies = [
  "alloy-json-abi",
  "alloy-primitives",
@@ -56,13 +62,14 @@ dependencies = [
  "alloy-sol-types",
  "const-hex",
  "itoa",
+ "winnow",
 ]
 
 [[package]]
 name = "alloy-json-abi"
-version = "0.4.2"
+version = "0.6.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "63c9319ad8b2b623c6a3ac15899f8ffb71479224762dbaedc385c16efbb6cfe3"
+checksum = "a7c5aecfe87e06da0e760840974c6e3cc19d4247be17a3172825fbbe759c8e60"
 dependencies = [
  "alloy-primitives",
  "alloy-sol-type-parser",
@@ -71,9 +78,9 @@ dependencies = [
 
 [[package]]
 name = "alloy-primitives"
-version = "0.4.2"
+version = "0.6.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a0628ec0ba5b98b3370bb6be17b12f23bfce8ee4ad83823325a20546d9b03b78"
+checksum = "f4b6fb2b432ff223d513db7f908937f63c252bee0af9b82bfd25b0a5dd1eb0d8"
 dependencies = [
  "alloy-rlp",
  "bytes",
@@ -82,6 +89,8 @@ dependencies = [
  "derive_more",
  "hex-literal",
  "itoa",
+ "k256",
+ "keccak-asm",
  "proptest",
  "rand",
  "ruint",
@@ -91,21 +100,19 @@ dependencies = [
 
 [[package]]
 name = "alloy-rlp"
-version = "0.3.3"
+version = "0.3.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cc0fac0fc16baf1f63f78b47c3d24718f3619b0714076f6a02957d808d52cbef"
+checksum = "8d58d9f5da7b40e9bfff0b7e7816700be4019db97d4b6359fe7f94a9e22e42ac"
 dependencies = [
- "alloy-rlp-derive",
  "arrayvec",
  "bytes",
- "smol_str",
 ]
 
 [[package]]
 name = "alloy-rlp-derive"
-version = "0.3.3"
+version = "0.3.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0391754c09fab4eae3404d19d0d297aa1c670c1775ab51d8a5312afeca23157"
+checksum = "1a047897373be4bbb0224c1afdabca92648dc57a9c9ef6e7b0be3aff7a859c83"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -114,13 +121,14 @@ dependencies = [
 
 [[package]]
 name = "alloy-sol-macro"
-version = "0.4.2"
+version = "0.6.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a98ad1696a2e17f010ae8e43e9f2a1e930ed176a8e3ff77acfeff6dfb07b42c"
+checksum = "8b0b5ab0cb07c21adf9d72e988b34e8200ce648c2bba8d009183bb1c50fb1216"
 dependencies = [
  "const-hex",
  "dunce",
  "heck 0.4.1",
+ "indexmap 2.2.3",
  "proc-macro-error",
  "proc-macro2",
  "quote",
@@ -131,18 +139,18 @@ dependencies = [
 
 [[package]]
 name = "alloy-sol-type-parser"
-version = "0.4.2"
+version = "0.6.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "81c61ccc29e7c58bf16a2f780898852348183f58b127bde03ced6d07ad544787"
+checksum = "4dd124ec0a456ec5e9dcca5b6e8b011bc723cc410d4d9a66bf032770feaeef4b"
 dependencies = [
  "winnow",
 ]
 
 [[package]]
 name = "alloy-sol-types"
-version = "0.4.2"
+version = "0.6.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "98d7107bed88e8f09f0ddcc3335622d87bfb6821f3e0c7473329fb1cfad5e015"
+checksum = "6c08f62ded7ce03513bfb60ef5cad4fff5d4f67eac6feb4df80426b7b9ffb06e"
 dependencies = [
  "alloy-primitives",
  "alloy-sol-macro",
@@ -176,9 +184,9 @@ dependencies = [
 
 [[package]]
 name = "anstream"
-version = "0.6.4"
+version = "0.6.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44"
+checksum = "6e2e1ebcb11de5c03c67de28a7df593d32191b44939c482e97702baaaa6ab6a5"
 dependencies = [
  "anstyle",
  "anstyle-parse",
@@ -190,43 +198,43 @@ dependencies = [
 
 [[package]]
 name = "anstyle"
-version = "1.0.4"
+version = "1.0.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7079075b41f533b8c61d2a4d073c4676e1f8b249ff94a393b0595db304e0dd87"
+checksum = "8901269c6307e8d93993578286ac0edf7f195079ffff5ebdeea6a59ffb7e36bc"
 
 [[package]]
 name = "anstyle-parse"
-version = "0.2.2"
+version = "0.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "317b9a89c1868f5ea6ff1d9539a69f45dffc21ce321ac1fd1160dfa48c8e2140"
+checksum = "c75ac65da39e5fe5ab759307499ddad880d724eed2f6ce5b5e8a26f4f387928c"
 dependencies = [
  "utf8parse",
 ]
 
 [[package]]
 name = "anstyle-query"
-version = "1.0.0"
+version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
+checksum = "e28923312444cdd728e4738b3f9c9cac739500909bb3d3c94b43551b16517648"
 dependencies = [
- "windows-sys 0.48.0",
+ "windows-sys 0.52.0",
 ]
 
 [[package]]
 name = "anstyle-wincon"
-version = "3.0.1"
+version = "3.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f0699d10d2f4d628a98ee7b57b289abbc98ff3bad977cb3152709d4bf2330628"
+checksum = "1cd54b81ec8d6180e24654d0b371ad22fc3dd083b6ff8ba325b72e00c87660a7"
 dependencies = [
  "anstyle",
- "windows-sys 0.48.0",
+ "windows-sys 0.52.0",
 ]
 
 [[package]]
 name = "anyhow"
-version = "1.0.75"
+version = "1.0.79"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6"
+checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca"
 
 [[package]]
 name = "ark-ff"
@@ -258,7 +266,7 @@ dependencies = [
  "ark-std 0.4.0",
  "derivative",
  "digest 0.10.7",
- "itertools 0.10.5",
+ "itertools",
  "num-bigint 0.4.4",
  "num-traits",
  "paste",
@@ -360,9 +368,9 @@ checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
 
 [[package]]
 name = "assert_cmd"
-version = "2.0.12"
+version = "2.0.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "88903cb14723e4d4003335bb7f8a14f27691649105346a0f0957466c096adfe6"
+checksum = "00ad3f3a942eee60335ab4342358c161ee296829e0d16ff42fc1d6cb07815467"
 dependencies = [
  "anstyle",
  "bstr",
@@ -375,9 +383,9 @@ dependencies = [
 
 [[package]]
 name = "async-trait"
-version = "0.1.74"
+version = "0.1.77"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a66537f1bb974b254c98ed142ff995236e81b9d0fe4db0575f46612cb15eb0f9"
+checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -395,15 +403,6 @@ dependencies = [
  "rustc_version 0.4.0",
 ]
 
-[[package]]
-name = "atomic-polyfill"
-version = "1.0.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4"
-dependencies = [
- "critical-section",
-]
-
 [[package]]
 name = "atty"
 version = "0.2.14"
@@ -415,16 +414,25 @@ dependencies = [
  "winapi",
 ]
 
+[[package]]
+name = "aurora-engine-modexp"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bfacad86e9e138fca0670949eb8ed4ffdf73a55bded8887efe0863cd1a3a6f70"
+dependencies = [
+ "hex 0.4.3",
+ "num",
+]
+
 [[package]]
 name = "auto_impl"
-version = "1.1.0"
+version = "1.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fee3da8ef1276b0bee5dd1c7258010d8fffd31801447323115a25560e1327b89"
+checksum = "823b8bb275161044e2ac7a25879cb3e2480cb403e3943022c7c769c599b756aa"
 dependencies = [
- "proc-macro-error",
  "proc-macro2",
  "quote",
- "syn 1.0.109",
+ "syn 2.0.48",
 ]
 
 [[package]]
@@ -514,29 +522,6 @@ dependencies = [
  "which",
 ]
 
-[[package]]
-name = "bindgen"
-version = "0.66.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f2b84e06fc203107bfbad243f4aba2af864eb7db3b1cf46ea0a023b0b433d2a7"
-dependencies = [
- "bitflags 2.4.1",
- "cexpr",
- "clang-sys",
- "lazy_static",
- "lazycell",
- "log",
- "peeking_take_while",
- "prettyplease",
- "proc-macro2",
- "quote",
- "regex",
- "rustc-hash",
- "shlex",
- "syn 2.0.48",
- "which",
-]
-
 [[package]]
 name = "bit-set"
 version = "0.5.3"
@@ -566,9 +551,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 
 [[package]]
 name = "bitflags"
-version = "2.4.1"
+version = "2.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07"
+checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
 dependencies = [
  "serde",
 ]
@@ -618,9 +603,9 @@ dependencies = [
 
 [[package]]
 name = "bonsai-sdk"
-version = "0.4.0"
+version = "0.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "94478e373742b9d1de02e13399633348e5b230dfe6364f65e80056c7df7438c5"
+checksum = "441d1092e11977985946b6564251df91d80ae36982128e53be52a32548ad8762"
 dependencies = [
  "reqwest",
  "serde",
@@ -629,12 +614,12 @@ dependencies = [
 
 [[package]]
 name = "bstr"
-version = "1.7.0"
+version = "1.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c79ad7fb2dd38f3dabd76b09c6a5a20c038fc0213ef1e9afd30eb777f120f019"
+checksum = "c48f0051a4b4c5e0b6d365cd04af53aeaa209e3cc15ec2cdb69e73cc87fbd0dc"
 dependencies = [
  "memchr",
- "regex-automata 0.4.3",
+ "regex-automata 0.4.5",
  "serde",
 ]
 
@@ -658,9 +643,9 @@ checksum = "e1e5f035d16fc623ae5f74981db80a439803888314e3a555fd6f04acd51a3205"
 
 [[package]]
 name = "bytemuck"
-version = "1.14.0"
+version = "1.14.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6"
+checksum = "a2ef034f05691a48569bd920a96c81b9d91bbad1ab5ac7c4616c1f6ef36cb79f"
 dependencies = [
  "bytemuck_derive",
 ]
@@ -693,11 +678,10 @@ dependencies = [
 
 [[package]]
 name = "c-kzg"
-version = "0.1.1"
+version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac926d808fb72fe09ebf471a091d6d72918876ccf0b4989766093d2d0d24a0ef"
+checksum = "b9d8c306be83ec04bf5f73710badd8edf56dea23f2f0d8b7f9fe4644d371c758"
 dependencies = [
- "bindgen 0.66.1",
  "blst",
  "cc",
  "glob",
@@ -717,9 +701,9 @@ dependencies = [
 
 [[package]]
 name = "cargo-platform"
-version = "0.1.6"
+version = "0.1.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ceed8ef69d8518a5dda55c07425450b58a4e1946f4951eab6d7191ee86c2443d"
+checksum = "694c8807f2ae16faecc43dc17d74b3eb042482789fd0eb64b39a2e04e087053f"
 dependencies = [
  "serde",
 ]
@@ -732,7 +716,7 @@ checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa"
 dependencies = [
  "camino",
  "cargo-platform",
- "semver 1.0.20",
+ "semver 1.0.21",
  "serde",
  "serde_json",
 ]
@@ -763,9 +747,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "chrono"
-version = "0.4.31"
+version = "0.4.34"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38"
+checksum = "5bc015644b92d5890fab7489e49d21f879d5c990186827d42ec511919404f38b"
 dependencies = [
  "android-tzdata",
  "iana-time-zone",
@@ -773,14 +757,14 @@ dependencies = [
  "num-traits",
  "serde",
  "wasm-bindgen",
- "windows-targets 0.48.5",
+ "windows-targets 0.52.0",
 ]
 
 [[package]]
 name = "clang-sys"
-version = "1.6.1"
+version = "1.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f"
+checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1"
 dependencies = [
  "glob",
  "libc",
@@ -804,9 +788,9 @@ dependencies = [
 
 [[package]]
 name = "clap"
-version = "4.4.7"
+version = "4.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac495e00dcec98c83465d5ad66c5c4fabd652fd6686e7c6269b117e729a6f17b"
+checksum = "80c21025abd42669a92efc996ef13cfb2c5c627858421ea58d5c3b331a6c134f"
 dependencies = [
  "clap_builder",
  "clap_derive",
@@ -814,21 +798,21 @@ dependencies = [
 
 [[package]]
 name = "clap_builder"
-version = "4.4.7"
+version = "4.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c77ed9a32a62e6ca27175d00d29d05ca32e396ea1eb5fb01d8256b669cec7663"
+checksum = "458bf1f341769dfcf849846f65dffdf9146daa56bcd2a47cb4e1de9915567c99"
 dependencies = [
  "anstream",
  "anstyle",
  "clap_lex",
- "strsim 0.10.0",
+ "strsim 0.11.0",
 ]
 
 [[package]]
 name = "clap_derive"
-version = "4.4.7"
+version = "4.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442"
+checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47"
 dependencies = [
  "heck 0.4.1",
  "proc-macro2",
@@ -838,9 +822,9 @@ dependencies = [
 
 [[package]]
 name = "clap_lex"
-version = "0.6.0"
+version = "0.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1"
+checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce"
 
 [[package]]
 name = "cmake"
@@ -859,9 +843,9 @@ checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
 
 [[package]]
 name = "const-hex"
-version = "1.10.0"
+version = "1.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a5104de16b218eddf8e34ffe2f86f74bfa4e61e95a1b89732fccf6325efd0557"
+checksum = "18d59688ad0945eaf6b84cb44fedbe93484c81b48970e98f09db8a22832d7961"
 dependencies = [
  "cfg-if",
  "cpufeatures",
@@ -872,9 +856,9 @@ dependencies = [
 
 [[package]]
 name = "const-oid"
-version = "0.9.5"
+version = "0.9.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f"
+checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
 
 [[package]]
 name = "convert_case"
@@ -884,9 +868,9 @@ checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
 
 [[package]]
 name = "core-foundation"
-version = "0.9.3"
+version = "0.9.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
+checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
 dependencies = [
  "core-foundation-sys",
  "libc",
@@ -894,24 +878,33 @@ dependencies = [
 
 [[package]]
 name = "core-foundation-sys"
-version = "0.8.4"
+version = "0.8.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
+checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
+
+[[package]]
+name = "core2"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505"
+dependencies = [
+ "memchr",
+]
 
 [[package]]
 name = "cpufeatures"
-version = "0.2.11"
+version = "0.2.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce420fe07aecd3e67c5f910618fe65e94158f6dcc0adf44e00d69ce2bdfe0fd0"
+checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504"
 dependencies = [
  "libc",
 ]
 
 [[package]]
 name = "crc32fast"
-version = "1.3.2"
+version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
+checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa"
 dependencies = [
  "cfg-if",
 ]
@@ -924,22 +917,18 @@ checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216"
 
 [[package]]
 name = "crossbeam-channel"
-version = "0.5.8"
+version = "0.5.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200"
+checksum = "176dc175b78f56c0f321911d9c8eb2b77a78a4860b9c19db83835fea1a46649b"
 dependencies = [
- "cfg-if",
  "crossbeam-utils",
 ]
 
 [[package]]
 name = "crossbeam-utils"
-version = "0.8.16"
+version = "0.8.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294"
-dependencies = [
- "cfg-if",
-]
+checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345"
 
 [[package]]
 name = "crunchy"
@@ -949,9 +938,9 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
 
 [[package]]
 name = "crypto-bigint"
-version = "0.5.3"
+version = "0.5.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "740fe28e594155f10cfc383984cbefd529d7396050557148f79cb0f621204124"
+checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76"
 dependencies = [
  "generic-array",
  "rand_core",
@@ -971,9 +960,9 @@ dependencies = [
 
 [[package]]
 name = "darling"
-version = "0.20.3"
+version = "0.20.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e"
+checksum = "c376d08ea6aa96aafe61237c7200d1241cb177b7d3a542d791f2d118e9cbb955"
 dependencies = [
  "darling_core",
  "darling_macro",
@@ -981,9 +970,9 @@ dependencies = [
 
 [[package]]
 name = "darling_core"
-version = "0.20.3"
+version = "0.20.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621"
+checksum = "33043dcd19068b8192064c704b3f83eb464f91f1ff527b44a4e2b08d9cdb8855"
 dependencies = [
  "fnv",
  "ident_case",
@@ -995,20 +984,26 @@ dependencies = [
 
 [[package]]
 name = "darling_macro"
-version = "0.20.3"
+version = "0.20.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5"
+checksum = "c5a91391accf613803c2a9bf9abccdbaa07c54b4244a5b64883f9c3c137c86be"
 dependencies = [
  "darling_core",
  "quote",
  "syn 2.0.48",
 ]
 
+[[package]]
+name = "dary_heap"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7762d17f1241643615821a8455a0b2c3e803784b058693d990b11f2dce25a0ca"
+
 [[package]]
 name = "data-encoding"
-version = "2.4.0"
+version = "2.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308"
+checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5"
 
 [[package]]
 name = "der"
@@ -1022,9 +1017,9 @@ dependencies = [
 
 [[package]]
 name = "deranged"
-version = "0.3.9"
+version = "0.3.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f32d04922c60427da6f9fef14d042d9edddef64cb9d4ce0d64d0685fbeb1fd3"
+checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
 dependencies = [
  "powerfmt",
  "serde",
@@ -1116,9 +1111,9 @@ checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b"
 
 [[package]]
 name = "ecdsa"
-version = "0.16.8"
+version = "0.16.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4b1e0c257a9e9f25f90ff76d7a68360ed497ee519c8e428d1825ef0000799d4"
+checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca"
 dependencies = [
  "der",
  "digest 0.10.7",
@@ -1130,21 +1125,21 @@ dependencies = [
 
 [[package]]
 name = "either"
-version = "1.9.0"
+version = "1.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
+checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a"
 
 [[package]]
 name = "elf"
-version = "0.7.3"
+version = "0.7.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7f6e7d85896690fe195447717af8eceae0593ac2196fd42fe88c184e904406ce"
+checksum = "4445909572dbd556c457c849c4ca58623d84b27c8fff1e74b0b4227d8b90d17b"
 
 [[package]]
 name = "elliptic-curve"
-version = "0.13.6"
+version = "0.13.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d97ca172ae9dc9f9b779a6e3a65d308f2af74e5b8c921299075bdb4a0370e914"
+checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47"
 dependencies = [
  "base16ct",
  "crypto-bigint",
@@ -1188,9 +1183,9 @@ dependencies = [
 
 [[package]]
 name = "enumn"
-version = "0.1.12"
+version = "0.1.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c2ad8cef1d801a4686bfd8919f0b30eac4c8e48968c437a6405ded4fb5272d2b"
+checksum = "6fd000fd6988e73bbe993ea3db9b1aa64906ab88766d654973924340c8cddb42"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1218,12 +1213,12 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
 
 [[package]]
 name = "errno"
-version = "0.3.5"
+version = "0.3.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860"
+checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
 dependencies = [
  "libc",
- "windows-sys 0.48.0",
+ "windows-sys 0.52.0",
 ]
 
 [[package]]
@@ -1285,9 +1280,9 @@ dependencies = [
 
 [[package]]
 name = "ethers-core"
-version = "2.0.10"
+version = "2.0.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0a17f0708692024db9956b31d7a20163607d2745953f5ae8125ab368ba280ad"
+checksum = "aab3cef6cc1c9fd7f787043c81ad3052eff2b96a3878ef1526aa446311bdbfc9"
 dependencies = [
  "arrayvec",
  "bytes",
@@ -1312,9 +1307,9 @@ dependencies = [
 
 [[package]]
 name = "ethers-providers"
-version = "2.0.10"
+version = "2.0.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6838fa110e57d572336178b7c79e94ff88ef976306852d8cb87d9e5b1fc7c0b5"
+checksum = "fb6b15393996e3b8a78ef1332d6483c11d839042c17be58decc92fa8b1c3508a"
 dependencies = [
  "async-trait",
  "auto_impl",
@@ -1420,9 +1415,9 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
 
 [[package]]
 name = "form_urlencoded"
-version = "1.2.0"
+version = "1.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652"
+checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
 dependencies = [
  "percent-encoding",
 ]
@@ -1435,9 +1430,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
 
 [[package]]
 name = "futures"
-version = "0.3.29"
+version = "0.3.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335"
+checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0"
 dependencies = [
  "futures-channel",
  "futures-core",
@@ -1450,9 +1445,9 @@ dependencies = [
 
 [[package]]
 name = "futures-channel"
-version = "0.3.29"
+version = "0.3.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb"
+checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
 dependencies = [
  "futures-core",
  "futures-sink",
@@ -1460,15 +1455,15 @@ dependencies = [
 
 [[package]]
 name = "futures-core"
-version = "0.3.29"
+version = "0.3.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c"
+checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
 
 [[package]]
 name = "futures-executor"
-version = "0.3.29"
+version = "0.3.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc"
+checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d"
 dependencies = [
  "futures-core",
  "futures-task",
@@ -1477,15 +1472,15 @@ dependencies = [
 
 [[package]]
 name = "futures-io"
-version = "0.3.29"
+version = "0.3.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa"
+checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
 
 [[package]]
 name = "futures-macro"
-version = "0.3.29"
+version = "0.3.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb"
+checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1494,15 +1489,15 @@ dependencies = [
 
 [[package]]
 name = "futures-sink"
-version = "0.3.29"
+version = "0.3.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817"
+checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
 
 [[package]]
 name = "futures-task"
-version = "0.3.29"
+version = "0.3.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2"
+checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
 
 [[package]]
 name = "futures-timer"
@@ -1516,9 +1511,9 @@ dependencies = [
 
 [[package]]
 name = "futures-util"
-version = "0.3.29"
+version = "0.3.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104"
+checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
 dependencies = [
  "futures-channel",
  "futures-core",
@@ -1554,9 +1549,9 @@ dependencies = [
 
 [[package]]
 name = "getrandom"
-version = "0.2.10"
+version = "0.2.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
+checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5"
 dependencies = [
  "cfg-if",
  "libc",
@@ -1565,9 +1560,9 @@ dependencies = [
 
 [[package]]
 name = "gimli"
-version = "0.28.0"
+version = "0.28.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6fb8d784f27acf97159b40fc4db5ecd8aa23b9ad5ef69cdd136d3bc80665f0c0"
+checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
 
 [[package]]
 name = "glob"
@@ -1609,9 +1604,9 @@ dependencies = [
 
 [[package]]
 name = "h2"
-version = "0.3.21"
+version = "0.3.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "91fc23aa11be92976ef4729127f1a74adf36d8436f7816b185d18df956790833"
+checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9"
 dependencies = [
  "bytes",
  "fnv",
@@ -1619,7 +1614,7 @@ dependencies = [
  "futures-sink",
  "futures-util",
  "http",
- "indexmap 1.9.3",
+ "indexmap 2.2.3",
  "slab",
  "tokio",
  "tokio-util",
@@ -1634,9 +1629,18 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
 
 [[package]]
 name = "hashbrown"
-version = "0.14.2"
+version = "0.13.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f93e7192158dbcda357bdec5fb5788eebf8bbac027f3f33e719d29135ae84156"
+checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
+dependencies = [
+ "ahash",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.14.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
 dependencies = [
  "ahash",
  "allocator-api2",
@@ -1688,9 +1692,9 @@ dependencies = [
 
 [[package]]
 name = "hermit-abi"
-version = "0.3.3"
+version = "0.3.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d77f7ec81a6d05a3abb01ab6eb7590f6083d08449fe5a1c8b1e620283546ccb7"
+checksum = "bd5256b483761cd23699d0da46cc6fd2ee3be420bbe6d020ae4a091e70b7e9fd"
 
 [[package]]
 name = "hex"
@@ -1724,18 +1728,18 @@ dependencies = [
 
 [[package]]
 name = "home"
-version = "0.5.5"
+version = "0.5.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb"
+checksum = "e3d1354bf6b7235cb4a0576c2619fd4ed18183f689b12b006a0ee7329eeff9a5"
 dependencies = [
- "windows-sys 0.48.0",
+ "windows-sys 0.52.0",
 ]
 
 [[package]]
 name = "http"
-version = "0.2.9"
+version = "0.2.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482"
+checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb"
 dependencies = [
  "bytes",
  "fnv",
@@ -1744,9 +1748,9 @@ dependencies = [
 
 [[package]]
 name = "http-body"
-version = "0.4.5"
+version = "0.4.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1"
+checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2"
 dependencies = [
  "bytes",
  "http",
@@ -1773,9 +1777,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
 
 [[package]]
 name = "hyper"
-version = "0.14.27"
+version = "0.14.28"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468"
+checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80"
 dependencies = [
  "bytes",
  "futures-channel",
@@ -1788,7 +1792,7 @@ dependencies = [
  "httpdate",
  "itoa",
  "pin-project-lite",
- "socket2 0.4.10",
+ "socket2",
  "tokio",
  "tower-service",
  "tracing",
@@ -1824,9 +1828,9 @@ dependencies = [
 
 [[package]]
 name = "iana-time-zone"
-version = "0.1.58"
+version = "0.1.60"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8326b86b6cff230b97d0d312a6c40a60726df3332e721f72a1b035f451663b20"
+checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141"
 dependencies = [
  "android_system_properties",
  "core-foundation-sys",
@@ -1853,9 +1857,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
 
 [[package]]
 name = "idna"
-version = "0.4.0"
+version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c"
+checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
 dependencies = [
  "unicode-bidi",
  "unicode-normalization",
@@ -1912,12 +1916,12 @@ dependencies = [
 
 [[package]]
 name = "indexmap"
-version = "2.0.2"
+version = "2.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897"
+checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177"
 dependencies = [
  "equivalent",
- "hashbrown 0.14.2",
+ "hashbrown 0.14.3",
  "serde",
 ]
 
@@ -1938,12 +1942,12 @@ checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3"
 
 [[package]]
 name = "is-terminal"
-version = "0.4.10"
+version = "0.4.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0bad00257d07be169d870ab665980b06cdb366d792ad690bf2e76876dc503455"
+checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b"
 dependencies = [
- "hermit-abi 0.3.3",
- "rustix",
+ "hermit-abi 0.3.6",
+ "libc",
  "windows-sys 0.52.0",
 ]
 
@@ -1956,26 +1960,17 @@ dependencies = [
  "either",
 ]
 
-[[package]]
-name = "itertools"
-version = "0.11.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57"
-dependencies = [
- "either",
-]
-
 [[package]]
 name = "itoa"
-version = "1.0.9"
+version = "1.0.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
+checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
 
 [[package]]
 name = "js-sys"
-version = "0.3.64"
+version = "0.3.68"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a"
+checksum = "406cda4b368d531c842222cf9d2600a9a4acce8d29423695379c6868a143a9ee"
 dependencies = [
  "wasm-bindgen",
 ]
@@ -1996,9 +1991,9 @@ dependencies = [
 
 [[package]]
 name = "k256"
-version = "0.13.1"
+version = "0.13.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cadb76004ed8e97623117f3df85b17aaa6626ab0b0831e6573f104df16cd1bcc"
+checksum = "956ff9b67e26e1a6a866cb758f12c6f8746208489e3e4a4b5580802f2f0a587b"
 dependencies = [
  "cfg-if",
  "ecdsa",
@@ -2010,13 +2005,23 @@ dependencies = [
 
 [[package]]
 name = "keccak"
-version = "0.1.4"
+version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940"
+checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654"
 dependencies = [
  "cpufeatures",
 ]
 
+[[package]]
+name = "keccak-asm"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bb8515fff80ed850aea4a1595f2e519c003e2a00a82fe168ebf5269196caf444"
+dependencies = [
+ "digest 0.10.7",
+ "sha3-asm",
+]
+
 [[package]]
 name = "lazy_static"
 version = "1.4.0"
@@ -2034,18 +2039,42 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
 
 [[package]]
 name = "libc"
-version = "0.2.149"
+version = "0.2.153"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b"
+checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
+
+[[package]]
+name = "libflate"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f7d5654ae1795afc7ff76f4365c2c8791b0feb18e8996a96adad8ffd7c3b2bf"
+dependencies = [
+ "adler32",
+ "core2",
+ "crc32fast",
+ "dary_heap",
+ "libflate_lz77",
+]
+
+[[package]]
+name = "libflate_lz77"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "be5f52fb8c451576ec6b79d3f4deb327398bc05bbdbd99021a6e77a4c855d524"
+dependencies = [
+ "core2",
+ "hashbrown 0.13.2",
+ "rle-decode-fast",
+]
 
 [[package]]
 name = "libloading"
-version = "0.7.4"
+version = "0.8.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
+checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161"
 dependencies = [
  "cfg-if",
- "winapi",
+ "windows-sys 0.48.0",
 ]
 
 [[package]]
@@ -2060,16 +2089,16 @@ version = "0.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "85c833ca1e66078851dba29046874e38f08b2c883700aa29a03ddd3b23814ee8"
 dependencies = [
- "bitflags 2.4.1",
+ "bitflags 2.4.2",
  "libc",
- "redox_syscall 0.4.1",
+ "redox_syscall",
 ]
 
 [[package]]
 name = "linux-raw-sys"
-version = "0.4.10"
+version = "0.4.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f"
+checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
 
 [[package]]
 name = "lock_api"
@@ -2104,8 +2133,8 @@ dependencies = [
 
 [[package]]
 name = "mbedtls"
-version = "0.12.1"
-source = "git+https://github.com/fortanix/rust-mbedtls.git#51429f1db35d986ddb3f43bbefc078df74be62ff"
+version = "0.12.3"
+source = "git+https://github.com/fortanix/rust-mbedtls.git#55eac05326dfef3d754af00f35d11413250e0c65"
 dependencies = [
  "bitflags 1.3.2",
  "byteorder",
@@ -2122,7 +2151,7 @@ dependencies = [
 [[package]]
 name = "mbedtls-platform-support"
 version = "0.1.1"
-source = "git+https://github.com/fortanix/rust-mbedtls.git#51429f1db35d986ddb3f43bbefc078df74be62ff"
+source = "git+https://github.com/fortanix/rust-mbedtls.git#55eac05326dfef3d754af00f35d11413250e0c65"
 dependencies = [
  "cc",
  "cfg-if",
@@ -2132,10 +2161,10 @@ dependencies = [
 
 [[package]]
 name = "mbedtls-sys-auto"
-version = "2.28.4+mbedtls-2.28.3"
-source = "git+https://github.com/fortanix/rust-mbedtls.git#51429f1db35d986ddb3f43bbefc078df74be62ff"
+version = "2.28.7"
+source = "git+https://github.com/fortanix/rust-mbedtls.git#55eac05326dfef3d754af00f35d11413250e0c65"
 dependencies = [
- "bindgen 0.65.1",
+ "bindgen",
  "cc",
  "cfg-if",
  "cmake",
@@ -2147,9 +2176,9 @@ dependencies = [
 
 [[package]]
 name = "memchr"
-version = "2.6.4"
+version = "2.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
+checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
 
 [[package]]
 name = "mime"
@@ -2165,18 +2194,18 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
 
 [[package]]
 name = "miniz_oxide"
-version = "0.7.1"
+version = "0.7.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
+checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7"
 dependencies = [
  "adler",
 ]
 
 [[package]]
 name = "mio"
-version = "0.8.9"
+version = "0.8.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3dce281c5e46beae905d4de1870d8b1509a9142b62eedf18b443b011ca8343d0"
+checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09"
 dependencies = [
  "libc",
  "wasi",
@@ -2259,18 +2288,24 @@ dependencies = [
 
 [[package]]
 name = "num-complex"
-version = "0.4.4"
+version = "0.4.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214"
+checksum = "23c6602fda94a57c990fe0df199a035d83576b496aa29f4e634a8ac6004e68a6"
 dependencies = [
  "num-traits",
 ]
 
+[[package]]
+name = "num-conv"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
+
 [[package]]
 name = "num-derive"
-version = "0.4.1"
+version = "0.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cfb77679af88f8b125209d354a202862602672222e7f2313fdd6dc349bad4712"
+checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -2279,19 +2314,18 @@ dependencies = [
 
 [[package]]
 name = "num-integer"
-version = "0.1.45"
+version = "0.1.46"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
+checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
 dependencies = [
- "autocfg",
  "num-traits",
 ]
 
 [[package]]
 name = "num-iter"
-version = "0.1.43"
+version = "0.1.44"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252"
+checksum = "d869c01cc0c455284163fd0092f1f93835385ccab5a98a0dcc497b2f8bf055a9"
 dependencies = [
  "autocfg",
  "num-integer",
@@ -2312,9 +2346,9 @@ dependencies = [
 
 [[package]]
 name = "num-traits"
-version = "0.2.17"
+version = "0.2.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
+checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a"
 dependencies = [
  "autocfg",
  "libm",
@@ -2326,26 +2360,26 @@ version = "1.16.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43"
 dependencies = [
- "hermit-abi 0.3.3",
+ "hermit-abi 0.3.6",
  "libc",
 ]
 
 [[package]]
 name = "num_enum"
-version = "0.7.0"
+version = "0.7.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70bf6736f74634d299d00086f02986875b3c2d924781a6a2cb6c201e73da0ceb"
+checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845"
 dependencies = [
  "num_enum_derive",
 ]
 
 [[package]]
 name = "num_enum_derive"
-version = "0.7.0"
+version = "0.7.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "56ea360eafe1022f7cc56cd7b869ed57330fb2453d0c7831d99b74c65d2f5597"
+checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b"
 dependencies = [
- "proc-macro-crate",
+ "proc-macro-crate 3.1.0",
  "proc-macro2",
  "quote",
  "syn 2.0.48",
@@ -2353,21 +2387,21 @@ dependencies = [
 
 [[package]]
 name = "object"
-version = "0.32.1"
+version = "0.32.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9cf5f9dd3933bd50a9e1f149ec995f39ae2c496d31fd772c1fd45ebc27e902b0"
+checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441"
 dependencies = [
  "memchr",
 ]
 
 [[package]]
 name = "once_cell"
-version = "1.18.0"
+version = "1.19.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
+checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
 dependencies = [
- "atomic-polyfill",
  "critical-section",
+ "portable-atomic",
 ]
 
 [[package]]
@@ -2397,11 +2431,11 @@ dependencies = [
 
 [[package]]
 name = "openssl"
-version = "0.10.57"
+version = "0.10.63"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c"
+checksum = "15c9d69dd87a29568d4d017cfe8ec518706046a05184e5aea92d0af890b803c8"
 dependencies = [
- "bitflags 2.4.1",
+ "bitflags 2.4.2",
  "cfg-if",
  "foreign-types",
  "libc",
@@ -2429,9 +2463,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
 
 [[package]]
 name = "openssl-sys"
-version = "0.9.93"
+version = "0.9.99"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "db4d56a4c0478783083cfafcc42493dd4a981d41669da64b4572a2a089b51b1d"
+checksum = "22e1bf214306098e4832460f797824c05d25aacdf896f64a985fb0fd992454ae"
 dependencies = [
  "cc",
  "libc",
@@ -2453,9 +2487,9 @@ checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
 
 [[package]]
 name = "parity-scale-codec"
-version = "3.6.5"
+version = "3.6.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0dec8a8073036902368c2cdc0387e85ff9a37054d7e7c98e592145e0c92cd4fb"
+checksum = "881331e34fa842a2fb61cc2db9643a8fedc615e47cfcc52597d1af0db9a7e8fe"
 dependencies = [
  "arrayvec",
  "bitvec",
@@ -2467,11 +2501,11 @@ dependencies = [
 
 [[package]]
 name = "parity-scale-codec-derive"
-version = "3.6.5"
+version = "3.6.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "312270ee71e1cd70289dacf597cab7b207aa107d2f28191c2ae45b2ece18a260"
+checksum = "be30eaf4b0a9fba5336683b38de57bb86d179a35862ba6bfcf57625d006bde5b"
 dependencies = [
- "proc-macro-crate",
+ "proc-macro-crate 2.0.0",
  "proc-macro2",
  "quote",
  "syn 1.0.109",
@@ -2495,7 +2529,7 @@ checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e"
 dependencies = [
  "cfg-if",
  "libc",
- "redox_syscall 0.4.1",
+ "redox_syscall",
  "smallvec",
  "windows-targets 0.48.5",
 ]
@@ -2523,15 +2557,15 @@ dependencies = [
 
 [[package]]
 name = "percent-encoding"
-version = "2.3.0"
+version = "2.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94"
+checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
 
 [[package]]
 name = "pest"
-version = "2.7.6"
+version = "2.7.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1f200d8d83c44a45b21764d1916299752ca035d15ecd46faca3e9a2a2bf6ad06"
+checksum = "219c0dcc30b6a27553f9cc242972b67f75b60eb0db71f0b5462f38b058c41546"
 dependencies = [
  "memchr",
  "thiserror",
@@ -2550,18 +2584,18 @@ dependencies = [
 
 [[package]]
 name = "pin-project"
-version = "1.1.3"
+version = "1.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422"
+checksum = "0302c4a0442c456bd56f841aee5c3bfd17967563f6fadc9ceb9f9c23cf3807e0"
 dependencies = [
  "pin-project-internal",
 ]
 
 [[package]]
 name = "pin-project-internal"
-version = "1.1.3"
+version = "1.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405"
+checksum = "266c042b60c9c76b8d53061e52b2e0d1116abc57cefc8c5cd671619a56ac3690"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -2592,9 +2626,15 @@ dependencies = [
 
 [[package]]
 name = "pkg-config"
-version = "0.3.27"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec"
+
+[[package]]
+name = "portable-atomic"
+version = "1.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
+checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0"
 
 [[package]]
 name = "powerfmt"
@@ -2610,13 +2650,12 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
 
 [[package]]
 name = "predicates"
-version = "3.0.4"
+version = "3.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6dfc28575c2e3f19cb3c73b93af36460ae898d426eba6fc15b9bd2a5220758a0"
+checksum = "68b87bfd4605926cdfefc1c3b5f8fe560e3feca9d5552cf68c466d3d8236c7e8"
 dependencies = [
  "anstyle",
  "difflib",
- "itertools 0.11.0",
  "predicates-core",
 ]
 
@@ -2638,9 +2677,9 @@ dependencies = [
 
 [[package]]
 name = "prettyplease"
-version = "0.2.15"
+version = "0.2.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d"
+checksum = "a41cf62165e97c7f814d2221421dbb9afcbcdb0a88068e5ea206e19951c2cbb5"
 dependencies = [
  "proc-macro2",
  "syn 2.0.48",
@@ -2667,7 +2706,25 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919"
 dependencies = [
  "once_cell",
- "toml_edit",
+ "toml_edit 0.19.15",
+]
+
+[[package]]
+name = "proc-macro-crate"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8"
+dependencies = [
+ "toml_edit 0.20.7",
+]
+
+[[package]]
+name = "proc-macro-crate"
+version = "3.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284"
+dependencies = [
+ "toml_edit 0.21.1",
 ]
 
 [[package]]
@@ -2696,9 +2753,9 @@ dependencies = [
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.76"
+version = "1.0.78"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c"
+checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
 dependencies = [
  "unicode-ident",
 ]
@@ -2720,19 +2777,19 @@ dependencies = [
 
 [[package]]
 name = "proptest"
-version = "1.3.1"
+version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7c003ac8c77cb07bb74f5f198bce836a689bcd5a42574612bf14d17bfd08c20e"
+checksum = "31b476131c3c86cb68032fdc5cb6d5a1045e3e42d96b69fa599fd77701e1f5bf"
 dependencies = [
  "bit-set",
  "bit-vec 0.6.3",
- "bitflags 2.4.1",
+ "bitflags 2.4.2",
  "lazy_static",
  "num-traits",
  "rand",
  "rand_chacha",
  "rand_xorshift",
- "regex-syntax 0.7.5",
+ "regex-syntax 0.8.2",
  "rusty-fork",
  "tempfile",
  "unarray",
@@ -2746,11 +2803,11 @@ checksum = "106dd99e98437432fed6519dedecfade6a06a73bb7b2a1e019fdd2bee5778d94"
 
 [[package]]
 name = "pulldown-cmark"
-version = "0.9.3"
+version = "0.9.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77a1a2f1f0a7ecff9c31abbe177637be0e97a0aef46cf8738ece09327985d998"
+checksum = "57206b407293d2bcd3af849ce869d52068623f19e1b5ff8e8778e3309439682b"
 dependencies = [
- "bitflags 1.3.2",
+ "bitflags 2.4.2",
  "memchr",
  "unicase",
 ]
@@ -2783,7 +2840,7 @@ dependencies = [
  "anyhow",
  "base64 0.21.7",
  "base64-serde",
- "clap 4.4.7",
+ "clap 4.5.0",
  "dirs",
  "ethers-core",
  "hex 0.4.3",
@@ -2791,7 +2848,7 @@ dependencies = [
  "rand",
  "rand_core",
  "risc0-zkvm",
- "secp256k1",
+ "secp256k1 0.27.0",
  "serde",
  "serde_json",
  "sgx-ra",
@@ -2812,11 +2869,11 @@ dependencies = [
  "bincode",
  "bonsai-sdk",
  "bytemuck",
- "clap 4.4.7",
+ "clap 4.5.0",
  "ethers-core",
  "ethers-providers",
  "flate2",
- "hashbrown 0.14.2",
+ "hashbrown 0.14.3",
  "hex 0.4.3",
  "hyper",
  "lazy_static",
@@ -2880,15 +2937,6 @@ dependencies = [
  "rand_core",
 ]
 
-[[package]]
-name = "redox_syscall"
-version = "0.3.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
-dependencies = [
- "bitflags 1.3.2",
-]
-
 [[package]]
 name = "redox_syscall"
 version = "0.4.1"
@@ -2911,13 +2959,13 @@ dependencies = [
 
 [[package]]
 name = "regex"
-version = "1.10.2"
+version = "1.10.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343"
+checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15"
 dependencies = [
  "aho-corasick",
  "memchr",
- "regex-automata 0.4.3",
+ "regex-automata 0.4.5",
  "regex-syntax 0.8.2",
 ]
 
@@ -2932,9 +2980,9 @@ dependencies = [
 
 [[package]]
 name = "regex-automata"
-version = "0.4.3"
+version = "0.4.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f"
+checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd"
 dependencies = [
  "aho-corasick",
  "memchr",
@@ -2947,12 +2995,6 @@ version = "0.6.29"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
 
-[[package]]
-name = "regex-syntax"
-version = "0.7.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da"
-
 [[package]]
 name = "regex-syntax"
 version = "0.8.2"
@@ -2961,15 +3003,15 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
 
 [[package]]
 name = "relative-path"
-version = "1.9.0"
+version = "1.9.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c707298afce11da2efef2f600116fa93ffa7a032b5d7b628aa17711ec81383ca"
+checksum = "e898588f33fdd5b9420719948f9f2a32c922a246964576f71ba7f24f80610fbc"
 
 [[package]]
 name = "reqwest"
-version = "0.11.22"
+version = "0.11.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b"
+checksum = "c6920094eb85afde5e4a138be3f2de8bbdf28000f0029e72c45025a56b042251"
 dependencies = [
  "base64 0.21.7",
  "bytes",
@@ -2995,6 +3037,7 @@ dependencies = [
  "serde",
  "serde_json",
  "serde_urlencoded",
+ "sync_wrapper",
  "system-configuration",
  "tokio",
  "tokio-native-tls",
@@ -3011,7 +3054,7 @@ dependencies = [
 [[package]]
 name = "revm"
 version = "3.5.0"
-source = "git+https://github.com/johntaiko/revm?branch=feat/taiko#327dc05411c59db6520ba3782a4d1cdab992f479"
+source = "git+https://github.com/ceciliaz030/revm.git?branch=sync-taiko-v3.5#0ebc1e0f5e2ab731bd583c4113440d6226dea58c"
 dependencies = [
  "auto_impl",
  "revm-interpreter",
@@ -3023,7 +3066,7 @@ dependencies = [
 [[package]]
 name = "revm-interpreter"
 version = "1.3.0"
-source = "git+https://github.com/johntaiko/revm?branch=feat/taiko#327dc05411c59db6520ba3782a4d1cdab992f479"
+source = "git+https://github.com/ceciliaz030/revm.git?branch=sync-taiko-v3.5#0ebc1e0f5e2ab731bd583c4113440d6226dea58c"
 dependencies = [
  "revm-primitives",
  "serde",
@@ -3032,15 +3075,15 @@ dependencies = [
 [[package]]
 name = "revm-precompile"
 version = "2.2.0"
-source = "git+https://github.com/johntaiko/revm?branch=feat/taiko#327dc05411c59db6520ba3782a4d1cdab992f479"
+source = "git+https://github.com/ceciliaz030/revm.git?branch=sync-taiko-v3.5#0ebc1e0f5e2ab731bd583c4113440d6226dea58c"
 dependencies = [
+ "aurora-engine-modexp",
  "c-kzg",
  "k256",
- "num",
  "once_cell",
  "revm-primitives",
  "ripemd",
- "secp256k1",
+ "secp256k1 0.28.2",
  "sha2",
  "substrate-bn",
 ]
@@ -3048,16 +3091,15 @@ dependencies = [
 [[package]]
 name = "revm-primitives"
 version = "1.3.0"
-source = "git+https://github.com/johntaiko/revm?branch=feat/taiko#327dc05411c59db6520ba3782a4d1cdab992f479"
+source = "git+https://github.com/ceciliaz030/revm.git?branch=sync-taiko-v3.5#0ebc1e0f5e2ab731bd583c4113440d6226dea58c"
 dependencies = [
  "alloy-primitives",
- "alloy-rlp",
  "auto_impl",
- "bitflags 2.4.1",
+ "bitflags 2.4.2",
  "bitvec",
  "c-kzg",
  "enumn",
- "hashbrown 0.14.2",
+ "hashbrown 0.14.3",
  "hex 0.4.3",
  "serde",
 ]
@@ -3089,9 +3131,9 @@ dependencies = [
 
 [[package]]
 name = "ring"
-version = "0.17.5"
+version = "0.17.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fb0205304757e5d899b9c2e448b867ffd03ae7f988002e47cd24954391394d0b"
+checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74"
 dependencies = [
  "cc",
  "getrandom",
@@ -3200,6 +3242,12 @@ version = "0.18.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8524b46783b58b00e9b2a4712e837093c975b23cf25bfaf99e1cf69e9011bf6b"
 
+[[package]]
+name = "rle-decode-fast"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3582f63211428f83597b51b2ddb88e2a91a9d52d12831f9d08f5e624e8977422"
+
 [[package]]
 name = "rlp"
 version = "0.5.2"
@@ -3324,39 +3372,39 @@ version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
 dependencies = [
- "semver 1.0.20",
+ "semver 1.0.21",
 ]
 
 [[package]]
 name = "rustix"
-version = "0.38.20"
+version = "0.38.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "67ce50cb2e16c2903e30d1cbccfd8387a74b9d4c938b6a4c5ec6cc7556f7a8a0"
+checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949"
 dependencies = [
- "bitflags 2.4.1",
+ "bitflags 2.4.2",
  "errno",
  "libc",
  "linux-raw-sys",
- "windows-sys 0.48.0",
+ "windows-sys 0.52.0",
 ]
 
 [[package]]
 name = "rustls"
-version = "0.21.8"
+version = "0.21.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "446e14c5cda4f3f30fe71863c34ec70f5ac79d6087097ad0bb433e1be5edf04c"
+checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba"
 dependencies = [
  "log",
- "ring 0.17.5",
+ "ring 0.17.7",
  "rustls-webpki",
  "sct",
 ]
 
 [[package]]
 name = "rustls-pemfile"
-version = "1.0.3"
+version = "1.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2"
+checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c"
 dependencies = [
  "base64 0.21.7",
 ]
@@ -3367,7 +3415,7 @@ version = "0.101.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765"
 dependencies = [
- "ring 0.17.5",
+ "ring 0.17.7",
  "untrusted 0.9.0",
 ]
 
@@ -3391,9 +3439,9 @@ dependencies = [
 
 [[package]]
 name = "ryu"
-version = "1.0.15"
+version = "1.0.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
+checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c"
 
 [[package]]
 name = "same-file"
@@ -3422,7 +3470,7 @@ version = "2.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "abf2c68b89cafb3b8d918dd07b42be0da66ff202cf1155c5739a4e0c1ea0dc19"
 dependencies = [
- "proc-macro-crate",
+ "proc-macro-crate 1.3.1",
  "proc-macro2",
  "quote",
  "syn 1.0.109",
@@ -3430,11 +3478,11 @@ dependencies = [
 
 [[package]]
 name = "schannel"
-version = "0.1.22"
+version = "0.1.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88"
+checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534"
 dependencies = [
- "windows-sys 0.48.0",
+ "windows-sys 0.52.0",
 ]
 
 [[package]]
@@ -3449,7 +3497,7 @@ version = "0.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414"
 dependencies = [
- "ring 0.17.5",
+ "ring 0.17.7",
  "untrusted 0.9.0",
 ]
 
@@ -3474,7 +3522,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "25996b82292a7a57ed3508f052cfff8640d38d32018784acd714758b43da9c8f"
 dependencies = [
  "rand",
- "secp256k1-sys",
+ "secp256k1-sys 0.8.1",
+]
+
+[[package]]
+name = "secp256k1"
+version = "0.28.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d24b59d129cdadea20aea4fb2352fa053712e5d713eee47d700cd4b2bc002f10"
+dependencies = [
+ "secp256k1-sys 0.9.2",
 ]
 
 [[package]]
@@ -3486,6 +3543,15 @@ dependencies = [
  "cc",
 ]
 
+[[package]]
+name = "secp256k1-sys"
+version = "0.9.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5d1746aae42c19d583c3c1a8c646bfad910498e2051c551a7f2e3c0c9fbb7eb"
+dependencies = [
+ "cc",
+]
+
 [[package]]
 name = "security-framework"
 version = "2.9.2"
@@ -3520,9 +3586,9 @@ dependencies = [
 
 [[package]]
 name = "semver"
-version = "1.0.20"
+version = "1.0.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090"
+checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0"
 dependencies = [
  "serde",
 ]
@@ -3550,18 +3616,18 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73"
 
 [[package]]
 name = "serde"
-version = "1.0.195"
+version = "1.0.196"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02"
+checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.195"
+version = "1.0.196"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c"
+checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -3570,11 +3636,11 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.107"
+version = "1.0.113"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65"
+checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79"
 dependencies = [
- "indexmap 2.0.2",
+ "indexmap 2.2.3",
  "itoa",
  "ryu",
  "serde",
@@ -3594,16 +3660,17 @@ dependencies = [
 
 [[package]]
 name = "serde_with"
-version = "3.4.0"
+version = "3.6.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "64cd236ccc1b7a29e7e2739f27c0b2dd199804abc4290e32f59f3b68d6405c23"
+checksum = "15d167997bd841ec232f5b2b8e0e26606df2e7caa4c31b95ea9ca52b200bd270"
 dependencies = [
  "base64 0.21.7",
  "chrono",
  "hex 0.4.3",
  "indexmap 1.9.3",
- "indexmap 2.0.2",
+ "indexmap 2.2.3",
  "serde",
+ "serde_derive",
  "serde_json",
  "serde_with_macros",
  "time",
@@ -3611,9 +3678,9 @@ dependencies = [
 
 [[package]]
 name = "serde_with_macros"
-version = "3.4.0"
+version = "3.6.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "93634eb5f75a2323b16de4748022ac4297f9e76b6dced2be287a099f41b5e788"
+checksum = "865f9743393e638991566a8b7a479043c2c8da94a33e0a31f18214c9cae0a64d"
 dependencies = [
  "darling",
  "proc-macro2",
@@ -3661,6 +3728,16 @@ dependencies = [
  "keccak",
 ]
 
+[[package]]
+name = "sha3-asm"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bac61da6b35ad76b195eb4771210f947734321a8d81d7738e1580d953bc7a15e"
+dependencies = [
+ "cc",
+ "cfg-if",
+]
+
 [[package]]
 name = "sharded-slab"
 version = "0.1.7"
@@ -3672,9 +3749,9 @@ dependencies = [
 
 [[package]]
 name = "shlex"
-version = "1.2.0"
+version = "1.3.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a7cee0529a6d40f580e7a5e6c495c8fbfe21b7b52795ed4bb5e62cdf92bc6380"
+checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
 
 [[package]]
 name = "signal-hook-registry"
@@ -3687,9 +3764,9 @@ dependencies = [
 
 [[package]]
 name = "signature"
-version = "2.1.0"
+version = "2.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500"
+checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
 dependencies = [
  "digest 0.10.7",
  "rand_core",
@@ -3733,28 +3810,9 @@ dependencies = [
 
 [[package]]
 name = "smallvec"
-version = "1.11.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a"
-
-[[package]]
-name = "smol_str"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "74212e6bbe9a4352329b2f68ba3130c15a3f26fe88ff22dbdc6cdd58fa85e99c"
-dependencies = [
- "serde",
-]
-
-[[package]]
-name = "socket2"
-version = "0.4.10"
+version = "1.13.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9f7916fc008ca5542385b89a3d3ce689953c143e9304a9bf8beec1de48994c0d"
-dependencies = [
- "libc",
- "winapi",
-]
+checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7"
 
 [[package]]
 name = "socket2"
@@ -3780,9 +3838,9 @@ checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
 
 [[package]]
 name = "spki"
-version = "0.7.2"
+version = "0.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a"
+checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d"
 dependencies = [
  "base64ct",
  "der",
@@ -3806,6 +3864,12 @@ version = "0.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
 
+[[package]]
+name = "strsim"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01"
+
 [[package]]
 name = "structopt"
 version = "0.3.26"
@@ -3923,9 +3987,9 @@ dependencies = [
 
 [[package]]
 name = "syn-solidity"
-version = "0.4.2"
+version = "0.6.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86b837ef12ab88835251726eb12237655e61ec8dc8a280085d1961cdc3dfd047"
+checksum = "63bef2e2c735acbc06874eca3a8506f02a3c4700e6e748afc92cc2e4220e8a03"
 dependencies = [
  "paste",
  "proc-macro2",
@@ -3933,6 +3997,12 @@ dependencies = [
  "syn 2.0.48",
 ]
 
+[[package]]
+name = "sync_wrapper"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
+
 [[package]]
 name = "system-configuration"
 version = "0.5.1"
@@ -3962,15 +4032,14 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
 
 [[package]]
 name = "tempfile"
-version = "3.8.0"
+version = "3.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef"
+checksum = "a365e8cd18e44762ef95d87f284f4b5cd04107fec2ff3052bd6a3e6069669e67"
 dependencies = [
  "cfg-if",
  "fastrand",
- "redox_syscall 0.3.5",
  "rustix",
- "windows-sys 0.48.0",
+ "windows-sys 0.52.0",
 ]
 
 [[package]]
@@ -4012,18 +4081,18 @@ dependencies = [
 
 [[package]]
 name = "thiserror"
-version = "1.0.50"
+version = "1.0.57"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2"
+checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.50"
+version = "1.0.57"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8"
+checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -4071,12 +4140,13 @@ dependencies = [
 
 [[package]]
 name = "time"
-version = "0.3.30"
+version = "0.3.34"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5"
+checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749"
 dependencies = [
  "deranged",
  "itoa",
+ "num-conv",
  "powerfmt",
  "serde",
  "time-core",
@@ -4091,10 +4161,11 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
 
 [[package]]
 name = "time-macros"
-version = "0.2.15"
+version = "0.2.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20"
+checksum = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774"
 dependencies = [
+ "num-conv",
  "time-core",
 ]
 
@@ -4124,9 +4195,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
 
 [[package]]
 name = "tokio"
-version = "1.33.0"
+version = "1.36.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4f38200e3ef7995e5ef13baec2f432a6da0aa9ac495b2c0e8f3b7eec2c92d653"
+checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931"
 dependencies = [
  "backtrace",
  "bytes",
@@ -4136,16 +4207,16 @@ dependencies = [
  "parking_lot",
  "pin-project-lite",
  "signal-hook-registry",
- "socket2 0.5.5",
+ "socket2",
  "tokio-macros",
  "windows-sys 0.48.0",
 ]
 
 [[package]]
 name = "tokio-macros"
-version = "2.1.0"
+version = "2.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e"
+checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -4222,7 +4293,29 @@ version = "0.19.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
 dependencies = [
- "indexmap 2.0.2",
+ "indexmap 2.2.3",
+ "toml_datetime",
+ "winnow",
+]
+
+[[package]]
+name = "toml_edit"
+version = "0.20.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81"
+dependencies = [
+ "indexmap 2.2.3",
+ "toml_datetime",
+ "winnow",
+]
+
+[[package]]
+name = "toml_edit"
+version = "0.21.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1"
+dependencies = [
+ "indexmap 2.2.3",
  "toml_datetime",
  "winnow",
 ]
@@ -4359,9 +4452,9 @@ dependencies = [
 
 [[package]]
 name = "try-lock"
-version = "0.2.4"
+version = "0.2.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
+checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
 
 [[package]]
 name = "tungstenite"
@@ -4424,9 +4517,9 @@ dependencies = [
 
 [[package]]
 name = "unicode-bidi"
-version = "0.3.13"
+version = "0.3.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
+checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75"
 
 [[package]]
 name = "unicode-ident"
@@ -4445,9 +4538,9 @@ dependencies = [
 
 [[package]]
 name = "unicode-segmentation"
-version = "1.10.1"
+version = "1.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
+checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202"
 
 [[package]]
 name = "unicode-width"
@@ -4475,9 +4568,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
 
 [[package]]
 name = "url"
-version = "2.4.1"
+version = "2.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5"
+checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633"
 dependencies = [
  "form_urlencoded",
  "idna",
@@ -4556,9 +4649,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
 [[package]]
 name = "wasm-bindgen"
-version = "0.2.87"
+version = "0.2.91"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342"
+checksum = "c1e124130aee3fb58c5bdd6b639a0509486b0338acaaae0c84a5124b0f588b7f"
 dependencies = [
  "cfg-if",
  "wasm-bindgen-macro",
@@ -4566,9 +4659,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-backend"
-version = "0.2.87"
+version = "0.2.91"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd"
+checksum = "c9e7e1900c352b609c8488ad12639a311045f40a35491fb69ba8c12f758af70b"
 dependencies = [
  "bumpalo",
  "log",
@@ -4581,9 +4674,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-futures"
-version = "0.4.37"
+version = "0.4.41"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03"
+checksum = "877b9c3f61ceea0e56331985743b13f3d25c406a7098d45180fb5f09bc19ed97"
 dependencies = [
  "cfg-if",
  "js-sys",
@@ -4593,9 +4686,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro"
-version = "0.2.87"
+version = "0.2.91"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d"
+checksum = "b30af9e2d358182b5c7449424f017eba305ed32a7010509ede96cdc4696c46ed"
 dependencies = [
  "quote",
  "wasm-bindgen-macro-support",
@@ -4603,9 +4696,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro-support"
-version = "0.2.87"
+version = "0.2.91"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
+checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -4616,15 +4709,15 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-shared"
-version = "0.2.87"
+version = "0.2.91"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1"
+checksum = "4f186bd2dcf04330886ce82d6f33dd75a7bfcf69ecf5763b89fcde53b6ac9838"
 
 [[package]]
 name = "web-sys"
-version = "0.3.64"
+version = "0.3.68"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b"
+checksum = "96565907687f7aceb35bc5fc03770a8a0471d82e479f25832f54a0e3f4b28446"
 dependencies = [
  "js-sys",
  "wasm-bindgen",
@@ -4632,9 +4725,9 @@ dependencies = [
 
 [[package]]
 name = "webpki-roots"
-version = "0.25.2"
+version = "0.25.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14247bb57be4f377dfb94c72830b8ce8fc6beac03cf4bf7b9732eadd414123fc"
+checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1"
 
 [[package]]
 name = "which"
@@ -4681,11 +4774,11 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 
 [[package]]
 name = "windows-core"
-version = "0.51.1"
+version = "0.52.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f1f8cf84f35d2db49a46868f947758c7a1138116f7fac3bc844f43ade1292e64"
+checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
 dependencies = [
- "windows-targets 0.48.5",
+ "windows-targets 0.52.0",
 ]
 
 [[package]]
@@ -4822,9 +4915,9 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
 
 [[package]]
 name = "winnow"
-version = "0.5.17"
+version = "0.5.40"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a3b801d0e0a6726477cc207f60162da452f3a95adb368399bef20a946e06f65c"
+checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876"
 dependencies = [
  "memchr",
 ]
@@ -4879,18 +4972,18 @@ dependencies = [
 
 [[package]]
 name = "zerocopy"
-version = "0.7.15"
+version = "0.7.32"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "81ba595b9f2772fbee2312de30eeb80ec773b4cb2f1e8098db024afadda6c06f"
+checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be"
 dependencies = [
  "zerocopy-derive",
 ]
 
 [[package]]
 name = "zerocopy-derive"
-version = "0.7.15"
+version = "0.7.32"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "772666c41fb6dceaf520b564b962d738a8e1a83b41bd48945f50837aed78bb1d"
+checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -4899,9 +4992,9 @@ dependencies = [
 
 [[package]]
 name = "zeroize"
-version = "1.6.0"
+version = "1.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9"
+checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d"
 dependencies = [
  "zeroize_derive",
 ]
@@ -4921,15 +5014,18 @@ dependencies = [
 name = "zeth-lib"
 version = "0.1.0"
 dependencies = [
+ "alloy-primitives",
  "alloy-sol-types",
  "anyhow",
  "bincode",
+ "bytes",
  "chrono",
  "ethers-core",
  "ethers-providers",
  "flate2",
- "hashbrown 0.14.2",
+ "hashbrown 0.14.3",
  "hex 0.4.3",
+ "libflate",
  "log",
  "once_cell",
  "revm",
diff --git a/Cargo.toml b/Cargo.toml
index e09c1ef0d..542399042 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -23,24 +23,15 @@ lto = true
 [profile.release.build-override]
 opt-level = 3
 
-[patch.crates-io]
-# use optimized risc0 circuit
-revm = { git = "https://github.com/johntaiko/revm", branch = "feat/taiko" }
-revm-primitives = { git = "https://github.com/johntaiko/revm", branch = "feat/taiko" }
 
 
 [workspace.dependencies]
-bonsai-sdk = "0.4"
+bonsai-sdk = "0.5"
 hashbrown = { version = "0.14", features = ["inline-more"] }
-risc0-build = "0.18"
-risc0-zkvm = { version = "0.18", default-features = false }
-revm = { version = "3.5", default-features = false, features = [
+risc0-build = "0.19"
+risc0-zkvm = { version = "0.19", default-features = false }
+revm-primitives = { git = "https://github.com/ceciliaz030/revm.git", branch = "sync-taiko-v3.5", default_features = false }
+revm = { git = "https://github.com/ceciliaz030/revm.git", branch = "sync-taiko-v3.5", default-features = false, features = [
     "std",
     "serde",
-    "taiko",
-    "optional_no_base_fee",
-    "optional_balance_check",
-] }
-revm-primitives = { version = "1.3", default_features = false, features = [
-    "taiko",
 ] }
diff --git a/lib/Cargo.toml b/lib/Cargo.toml
index 82a1058dd..904005f57 100644
--- a/lib/Cargo.toml
+++ b/lib/Cargo.toml
@@ -5,11 +5,17 @@ edition = "2021"
 
 [dependencies]
 anyhow = { version = "1.0", default-features = false }
-alloy-sol-types = { version = "0.4", default-features = false, optional = true }
+alloy-sol-types = { version = "0.6", default-features = false }
+alloy-primitives = { version = "0.6", default-features = false, features = [
+  "rlp",
+  "serde",
+] }
+bytes = "1.5"
 ethers-core = { version = "2.0", features = ["optimism"] }
 hashbrown = { workspace = true }
+libflate = "2.0.0"
 once_cell = { version = "1.18", default-features = false }
-revm = { workspace = true }
+revm = { workspace = true, default-features = false }
 ruint = { version = "1.10", default-features = false }
 serde = { version = "1.0", default-features = false, features = ["alloc"] }
 thiserror-no-std = "2.0.2"
@@ -35,14 +41,13 @@ bincode = "1.3"
 serde_with = "3.1"
 
 [features]
-default = ["taiko"]
+# default = ["taiko", "std"]
 std = []
 taiko = [
     "zeth-primitives/taiko", 
-    "dep:alloy-sol-types",
+    "revm/taiko",
     "dep:hex",
     "dep:rlp",
     "dep:tracing"
     ]
-pos = []
-server = []
+optimism = ["std", "revm/optimism"]
\ No newline at end of file
diff --git a/lib/src/block_builder.rs b/lib/src/block_builder.rs
deleted file mode 100644
index c090b2d56..000000000
--- a/lib/src/block_builder.rs
+++ /dev/null
@@ -1,201 +0,0 @@
-// Copyright 2023 RISC Zero, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-use anyhow::Result;
-use revm::{Database, DatabaseCommit};
-use zeth_primitives::{
-    block::Header,
-    transactions::{ethereum::EthereumTxEssence, optimism::OptimismTxEssence, TxEssence},
-};
-
-use crate::{
-    consts::ChainSpec,
-    execution::{ethereum::EthTxExecStrategy, optimism::OpTxExecStrategy, TxExecStrategy},
-    finalization::{BlockBuildStrategy, BuildFromMemDbStrategy},
-    initialization::{DbInitStrategy, MemDbInitStrategy},
-    input::Input,
-    mem_db::MemDb,
-    preparation::{EthHeaderPrepStrategy, HeaderPrepStrategy},
-};
-
-#[derive(Clone, Debug)]
-pub struct BlockBuilder<'a, D, E: TxEssence> {
-    pub(crate) chain_spec: &'a ChainSpec,
-    pub(crate) input: Input<E>,
-    pub(crate) db: Option<D>,
-    pub(crate) header: Option<Header>,
-}
-
-impl<D, E> BlockBuilder<'_, D, E>
-where
-    D: Database + DatabaseCommit,
-    <D as Database>::Error: core::fmt::Debug,
-    E: TxEssence,
-{
-    /// Creates a new block builder.
-    pub fn new(chain_spec: &ChainSpec, input: Input<E>) -> BlockBuilder<'_, D, E> {
-        BlockBuilder {
-            chain_spec,
-            db: None,
-            header: None,
-            input,
-        }
-    }
-
-    /// Sets the database.
-    pub fn with_db(mut self, db: D) -> Self {
-        self.db = Some(db);
-        self
-    }
-
-    /// Initializes the database from the input tries.
-    pub fn initialize_database<T: DbInitStrategy<E, Database = D>>(self) -> Result<Self> {
-        T::initialize_database(self)
-    }
-
-    /// Initializes the header. This must be called before executing transactions.
-    pub fn prepare_header<T: HeaderPrepStrategy>(self) -> Result<Self> {
-        T::prepare_header(self)
-    }
-
-    /// Executes the transactions.
-    pub fn execute_transactions<T: TxExecStrategy<E>>(self) -> Result<Self> {
-        T::execute_transactions(self)
-    }
-
-    /// Builds the block and returns the header.
-    pub fn build<T: BlockBuildStrategy<E, Database = D>>(self) -> Result<T::Output> {
-        T::build(self)
-    }
-
-    /// Returns a reference to the database.
-    pub fn db(&self) -> Option<&D> {
-        self.db.as_ref()
-    }
-
-    /// Returns a mutable reference to the database.
-    pub fn mut_db(&mut self) -> Option<&mut D> {
-        self.db.as_mut()
-    }
-}
-
-pub trait NetworkStrategyBundle {
-    type Database: Database + DatabaseCommit;
-    type TxEssence: TxEssence;
-
-    type DbInitStrategy: DbInitStrategy<Self::TxEssence, Database = Self::Database>;
-    type HeaderPrepStrategy: HeaderPrepStrategy;
-    type TxExecStrategy: TxExecStrategy<Self::TxEssence>;
-    type BlockBuildStrategy: BlockBuildStrategy<Self::TxEssence, Database = Self::Database>;
-}
-
-pub struct ConfiguredBlockBuilder<'a, N: NetworkStrategyBundle>(
-    BlockBuilder<'a, N::Database, N::TxEssence>,
-)
-where
-    N::TxEssence: TxEssence;
-
-impl<N: NetworkStrategyBundle> ConfiguredBlockBuilder<'_, N>
-where
-    <N::Database as Database>::Error: core::fmt::Debug,
-{
-    pub fn build_from(
-        chain_spec: &ChainSpec,
-        input: Input<N::TxEssence>,
-    ) -> Result<<N::BlockBuildStrategy as BlockBuildStrategy<N::TxEssence>>::Output> {
-        Self::new(chain_spec, input)
-            .initialize_database()?
-            .prepare_header()?
-            .execute_transactions()?
-            .build()
-    }
-
-    /// Creates a new block builder.
-    pub fn new(
-        chain_spec: &ChainSpec,
-        input: Input<N::TxEssence>,
-    ) -> ConfiguredBlockBuilder<'_, N> {
-        ConfiguredBlockBuilder(BlockBuilder::new(chain_spec, input))
-    }
-
-    /// Sets the database.
-    pub fn with_db(mut self, db: N::Database) -> Self {
-        self.0.db = Some(db);
-        self
-    }
-
-    /// Initializes the database from the input tries.
-    pub fn initialize_database(self) -> Result<Self> {
-        Ok(ConfiguredBlockBuilder(
-            N::DbInitStrategy::initialize_database(self.0)?,
-        ))
-    }
-
-    /// Initializes the header. This must be called before executing transactions.
-    pub fn prepare_header(self) -> Result<Self> {
-        Ok(ConfiguredBlockBuilder(
-            N::HeaderPrepStrategy::prepare_header(self.0)?,
-        ))
-    }
-
-    /// Executes the transactions.
-    pub fn execute_transactions(self) -> Result<Self> {
-        Ok(ConfiguredBlockBuilder(
-            N::TxExecStrategy::execute_transactions(self.0)?,
-        ))
-    }
-
-    /// Builds the block and returns the header.
-    pub fn build(
-        self,
-    ) -> Result<<N::BlockBuildStrategy as BlockBuildStrategy<N::TxEssence>>::Output> {
-        N::BlockBuildStrategy::build(self.0)
-    }
-
-    /// Returns a reference to the database.
-    pub fn db(&self) -> Option<&N::Database> {
-        self.0.db.as_ref()
-    }
-
-    /// Returns a mutable reference to the database.
-    pub fn mut_db(&mut self) -> Option<&mut N::Database> {
-        self.0.db.as_mut()
-    }
-}
-
-pub struct EthereumStrategyBundle {}
-
-impl NetworkStrategyBundle for EthereumStrategyBundle {
-    type Database = MemDb;
-    type TxEssence = EthereumTxEssence;
-    type DbInitStrategy = MemDbInitStrategy;
-    type HeaderPrepStrategy = EthHeaderPrepStrategy;
-    type TxExecStrategy = EthTxExecStrategy;
-    type BlockBuildStrategy = BuildFromMemDbStrategy;
-}
-
-pub type EthereumBlockBuilder<'a> = ConfiguredBlockBuilder<'a, EthereumStrategyBundle>;
-
-pub struct OptimismStrategyBundle {}
-
-impl NetworkStrategyBundle for OptimismStrategyBundle {
-    type Database = MemDb;
-    type TxEssence = OptimismTxEssence;
-    type DbInitStrategy = MemDbInitStrategy;
-    type HeaderPrepStrategy = EthHeaderPrepStrategy;
-    type TxExecStrategy = OpTxExecStrategy;
-    type BlockBuildStrategy = BuildFromMemDbStrategy;
-}
-
-pub type OptimismBlockBuilder<'a> = ConfiguredBlockBuilder<'a, OptimismStrategyBundle>;
diff --git a/lib/src/execution/ethereum.rs b/lib/src/builder/execute/ethereum.rs
similarity index 78%
rename from lib/src/execution/ethereum.rs
rename to lib/src/builder/execute/ethereum.rs
index 6ca6e71d7..d1a486fc8 100644
--- a/lib/src/execution/ethereum.rs
+++ b/lib/src/builder/execute/ethereum.rs
@@ -1,4 +1,4 @@
-// Copyright 2023 RISC Zero, Inc.
+// Copyright 2024 RISC Zero, Inc.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -18,8 +18,9 @@ use anyhow::{anyhow, bail, Context};
 #[cfg(not(target_os = "zkvm"))]
 use log::debug;
 use revm::{
+    interpreter::Host,
     primitives::{Account, Address, ResultAndState, SpecId, TransactTo, TxEnv},
-    Database, DatabaseCommit, EVM,
+    Database, DatabaseCommit, Evm,
 };
 use ruint::aliases::U256;
 use zeth_primitives::{
@@ -32,13 +33,11 @@ use zeth_primitives::{
     Bloom, RlpBytes,
 };
 
-use crate::{
-    block_builder::BlockBuilder,
-    consts,
-    consts::{GWEI_TO_WEI, MIN_SPEC_ID},
-    execution::TxExecStrategy,
-    guest_mem_forget,
-};
+use super::TxExecStrategy;
+use crate::{builder::BlockBuilder, consts, guest_mem_forget};
+
+/// Minimum supported protocol version: Paris (Block no. 15537394).
+const MIN_SPEC_ID: SpecId = SpecId::MERGE;
 
 pub struct EthTxExecStrategy {}
 
@@ -57,11 +56,7 @@ impl TxExecStrategy<EthereumTxEssence> for EthTxExecStrategy {
         // Compute the spec id
         let spec_id = block_builder.chain_spec.spec_id(header.number);
         if !SpecId::enabled(spec_id, MIN_SPEC_ID) {
-            bail!(
-                "Invalid protocol version: expected >= {:?}, got {:?}",
-                MIN_SPEC_ID,
-                spec_id,
-            )
+            bail!("Invalid protocol version: expected >= {MIN_SPEC_ID:?}, got {spec_id:?}");
         }
 
         #[cfg(not(target_os = "zkvm"))]
@@ -69,12 +64,19 @@ impl TxExecStrategy<EthereumTxEssence> for EthTxExecStrategy {
             use chrono::{TimeZone, Utc};
             use log::info;
             let dt = Utc
-                .timestamp_opt(block_builder.input.timestamp.try_into().unwrap(), 0)
+                .timestamp_opt(
+                    block_builder
+                        .input
+                        .timestamp
+                        .try_into()
+                        .expect("Timestamp could not fit into i64"),
+                    0,
+                )
                 .unwrap();
 
             info!("Block no. {}", header.number);
-            info!("  EVM spec ID: {:?}", spec_id);
-            info!("  Timestamp: {}", dt);
+            info!("  EVM spec ID: {spec_id:?}");
+            info!("  Timestamp: {dt}");
             info!("  Transactions: {}", block_builder.input.transactions.len());
             info!("  Withdrawals: {}", block_builder.input.withdrawals.len());
             info!("  Fee Recipient: {:?}", block_builder.input.beneficiary);
@@ -83,23 +85,26 @@ impl TxExecStrategy<EthereumTxEssence> for EthTxExecStrategy {
             info!("  Extra data: {:?}", block_builder.input.extra_data);
         }
 
-        // initialize the EVM
-        let mut evm = EVM::new();
-
-        // set the EVM configuration
-        evm.env.cfg.chain_id = block_builder.chain_spec.chain_id();
-        evm.env.cfg.spec_id = spec_id;
-
-        // set the EVM block environment
-        evm.env.block.number = header.number.try_into().unwrap();
-        evm.env.block.coinbase = block_builder.input.beneficiary;
-        evm.env.block.timestamp = header.timestamp;
-        evm.env.block.difficulty = U256::ZERO;
-        evm.env.block.prevrandao = Some(header.mix_hash);
-        evm.env.block.basefee = header.base_fee_per_gas;
-        evm.env.block.gas_limit = block_builder.input.gas_limit;
-
-        evm.database(block_builder.db.take().unwrap());
+        // initialize the Evm
+        let mut evm = Evm::builder()
+            .spec_id(spec_id)
+            .modify_cfg_env(|cfg_env| {
+                // set the EVM configuration
+                cfg_env.chain_id = block_builder.chain_spec.chain_id();
+                // cfg_env.optimism = false;
+            })
+            .modify_block_env(|blk_env| {
+                // set the EVM block environment
+                blk_env.number = U256::from(header.number);
+                blk_env.coinbase = block_builder.input.beneficiary;
+                blk_env.timestamp = header.timestamp;
+                blk_env.difficulty = U256::ZERO;
+                blk_env.prevrandao = Some(header.mix_hash);
+                blk_env.basefee = header.base_fee_per_gas;
+                blk_env.gas_limit = block_builder.input.gas_limit;
+            })
+            .with_db(block_builder.db.take().expect("No database"))
+            .build();
 
         // bloom filter over all transaction logs
         let mut logs_bloom = Bloom::default();
@@ -116,34 +121,34 @@ impl TxExecStrategy<EthereumTxEssence> for EthTxExecStrategy {
             // verify the transaction signature
             let tx_from = tx
                 .recover_from()
-                .with_context(|| format!("Error recovering address for transaction {}", tx_no))?;
+                .with_context(|| format!("Error recovering address for transaction {tx_no}"))?;
 
             #[cfg(not(target_os = "zkvm"))]
             {
                 let tx_hash = tx.hash();
-                debug!("Tx no. {} (hash: {})", tx_no, tx_hash);
+                debug!("Tx no. {tx_no} (hash: {tx_hash})");
                 debug!("  Type: {}", tx.essence.tx_type());
-                debug!("  Fr: {:?}", tx_from);
+                debug!("  Fr: {tx_from:?}");
                 debug!("  To: {:?}", tx.essence.to().unwrap_or_default());
             }
 
             // verify transaction gas
             let block_available_gas = block_builder.input.gas_limit - cumulative_gas_used;
             if block_available_gas < tx.essence.gas_limit() {
-                bail!("Error at transaction {}: gas exceeds block limit", tx_no);
+                bail!("Error at transaction {tx_no}: gas exceeds block limit");
             }
 
             // process the transaction
-            fill_eth_tx_env(&mut evm.env.tx, &tx.essence, tx_from);
+            fill_eth_tx_env(&mut evm.env().tx, &tx.essence, tx_from);
             let ResultAndState { result, state } = evm
                 .transact()
-                .map_err(|evm_err| anyhow!("Error at transaction {}: {:?}", tx_no, evm_err))?;
+                .map_err(|evm_err| anyhow!("Error at transaction {tx_no}: {evm_err:?}"))?;
 
             let gas_used = result.gas_used().try_into().unwrap();
             cumulative_gas_used = cumulative_gas_used.checked_add(gas_used).unwrap();
 
             #[cfg(not(target_os = "zkvm"))]
-            debug!("  Ok: {:?}", result);
+            debug!("  Ok: {result:?}");
 
             // create the receipt from the EVM result
             let receipt = Receipt::new(
@@ -173,8 +178,7 @@ impl TxExecStrategy<EthereumTxEssence> for EthTxExecStrategy {
                 if account.is_touched() {
                     // log account
                     debug!(
-                        "  State {:?} (is_selfdestructed={}, is_loaded_as_not_existing={}, is_created={}, is_empty={})",
-                        address,
+                        "  State {address:?} (is_selfdestructed={}, is_loaded_as_not_existing={}, is_created={}, is_empty={})",
                         account.is_selfdestructed(),
                         account.is_loaded_as_not_existing(),
                         account.is_created(),
@@ -189,7 +193,7 @@ impl TxExecStrategy<EthereumTxEssence> for EthTxExecStrategy {
                     // log state changes
                     for (addr, slot) in &account.storage {
                         if slot.is_changed() {
-                            debug!("    Storage address: {:?}", addr);
+                            debug!("    Storage address: {addr:?}");
                             debug!("      Before: {:?}", slot.original_value());
                             debug!("       After: {:?}", slot.present_value());
                         }
@@ -197,11 +201,9 @@ impl TxExecStrategy<EthereumTxEssence> for EthTxExecStrategy {
                 }
             }
 
-            evm.db().unwrap().commit(state);
+            evm.context.evm.db.commit(state);
         }
 
-        let mut db = evm.take_db();
-
         // process withdrawals unconditionally after any transactions
         let mut withdrawals_trie = MptNode::default();
         for (i, withdrawal) in take(&mut block_builder.input.withdrawals)
@@ -209,7 +211,7 @@ impl TxExecStrategy<EthereumTxEssence> for EthTxExecStrategy {
             .enumerate()
         {
             // the withdrawal amount is given in Gwei
-            let amount_wei = GWEI_TO_WEI
+            let amount_wei = consts::GWEI_TO_WEI
                 .checked_mul(withdrawal.amount.try_into().unwrap())
                 .unwrap();
 
@@ -217,10 +219,10 @@ impl TxExecStrategy<EthereumTxEssence> for EthTxExecStrategy {
             {
                 debug!("Withdrawal no. {}", withdrawal.index);
                 debug!("  Recipient: {:?}", withdrawal.address);
-                debug!("  Value: {}", amount_wei);
+                debug!("  Value: {amount_wei}");
             }
             // Credit withdrawal amount
-            increase_account_balance(&mut db, withdrawal.address, amount_wei)?;
+            increase_account_balance(&mut evm.context.evm.db, withdrawal.address, amount_wei)?;
             // Add withdrawal to trie
             withdrawals_trie
                 .insert_rlp(&i.to_rlp(), withdrawal)
@@ -233,16 +235,12 @@ impl TxExecStrategy<EthereumTxEssence> for EthTxExecStrategy {
         header.receipts_root = receipt_trie.hash();
         header.logs_bloom = logs_bloom;
         header.gas_used = cumulative_gas_used;
-        header.withdrawals_root = if spec_id < SpecId::SHANGHAI {
-            None
-        } else {
-            Some(withdrawals_trie.hash())
-        };
+        header.withdrawals_root = (spec_id < SpecId::SHANGHAI).then_some(withdrawals_trie.hash());
 
         // Leak memory, save cycles
         guest_mem_forget([tx_trie, receipt_trie, withdrawals_trie]);
         // Return block builder with updated database
-        Ok(block_builder.with_db(db))
+        Ok(block_builder.with_db(evm.context.evm.db))
     }
 }
 
@@ -311,13 +309,7 @@ where
     // Read account from database
     let mut account: Account = db
         .basic(address)
-        .map_err(|db_err| {
-            anyhow!(
-                "Error increasing account balance for {}: {:?}",
-                address,
-                db_err
-            )
-        })?
+        .map_err(|db_err| anyhow!("Error increasing account balance for {address}: {db_err:?}"))?
         .unwrap_or_default()
         .into();
     // Credit withdrawal amount
diff --git a/lib/src/execution/mod.rs b/lib/src/builder/execute/mod.rs
similarity index 86%
rename from lib/src/execution/mod.rs
rename to lib/src/builder/execute/mod.rs
index f1a88cb84..a02e2d2be 100644
--- a/lib/src/execution/mod.rs
+++ b/lib/src/builder/execute/mod.rs
@@ -18,10 +18,13 @@ use anyhow::Result;
 use revm::{Database, DatabaseCommit};
 use zeth_primitives::transactions::TxEssence;
 
-use crate::block_builder::BlockBuilder;
+use super::BlockBuilder;
 
-pub mod ethereum;
-pub mod optimism;
+pub(super) mod ethereum;
+#[cfg(feature = "optimism")]
+pub(super) mod optimism;
+#[cfg(feature = "taiko")]
+pub(super) mod taiko;
 
 pub trait TxExecStrategy<E: TxEssence> {
     fn execute_transactions<D>(block_builder: BlockBuilder<D, E>) -> Result<BlockBuilder<D, E>>
diff --git a/lib/src/builder/execute/optimism.rs b/lib/src/builder/execute/optimism.rs
new file mode 100644
index 000000000..ee52e19b2
--- /dev/null
+++ b/lib/src/builder/execute/optimism.rs
@@ -0,0 +1,269 @@
+// Copyright 2024 RISC Zero, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+use alloc::{format, vec, vec::Vec};
+use core::{fmt::Debug, mem::take, str::FromStr};
+
+use anyhow::{anyhow, bail, Context, Result};
+#[cfg(not(target_os = "zkvm"))]
+use log::debug;
+use revm::{
+    interpreter::Host,
+    optimism,
+    primitives::{Address, ResultAndState, SpecId, TransactTo, TxEnv},
+    Database, DatabaseCommit, Evm,
+};
+use ruint::aliases::U256;
+use zeth_primitives::{
+    receipt::Receipt,
+    transactions::{
+        ethereum::{EthereumTxEssence, TransactionKind},
+        optimism::{OptimismTxEssence, TxEssenceOptimismDeposited},
+        TxEssence,
+    },
+    trie::MptNode,
+    Bloom, Bytes, RlpBytes,
+};
+
+use super::{ethereum, TxExecStrategy};
+use crate::{builder::BlockBuilder, consts, guest_mem_forget};
+
+/// Minimum supported protocol version: Bedrock (Block no. 105235063).
+const MIN_SPEC_ID: SpecId = SpecId::BEDROCK;
+
+pub struct OpTxExecStrategy {}
+
+impl TxExecStrategy<OptimismTxEssence> for OpTxExecStrategy {
+    fn execute_transactions<D>(
+        mut block_builder: BlockBuilder<D, OptimismTxEssence>,
+    ) -> Result<BlockBuilder<D, OptimismTxEssence>>
+    where
+        D: Database + DatabaseCommit,
+        <D as Database>::Error: Debug,
+    {
+        let header = block_builder
+            .header
+            .as_mut()
+            .expect("Header is not initialized");
+        // Compute the spec id
+        let spec_id = block_builder.chain_spec.spec_id(header.number);
+        if !SpecId::enabled(spec_id, MIN_SPEC_ID) {
+            bail!("Invalid protocol version: expected >= {MIN_SPEC_ID:?}, got {spec_id:?}")
+        }
+        let chain_id = block_builder.chain_spec.chain_id();
+
+        #[cfg(not(target_os = "zkvm"))]
+        {
+            use chrono::{TimeZone, Utc};
+            use log::info;
+            let dt = Utc
+                .timestamp_opt(
+                    block_builder
+                        .input
+                        .timestamp
+                        .try_into()
+                        .expect("Timestamp could not fit into i64"),
+                    0,
+                )
+                .unwrap();
+
+            info!("Block no. {}", header.number);
+            info!("  EVM spec ID: {spec_id:?}");
+            info!("  Timestamp: {dt}");
+            info!("  Transactions: {}", block_builder.input.transactions.len());
+            info!("  Fee Recipient: {:?}", block_builder.input.beneficiary);
+            info!("  Gas limit: {}", block_builder.input.gas_limit);
+            info!("  Base fee per gas: {}", header.base_fee_per_gas);
+            info!("  Extra data: {:?}", block_builder.input.extra_data);
+        }
+
+        let mut evm = Evm::builder()
+            .spec_id(spec_id)
+            .modify_cfg_env(|cfg_env| {
+                // set the EVM configuration
+                cfg_env.chain_id = chain_id;
+                cfg_env.optimism = true;
+            })
+            .modify_block_env(|blk_env| {
+                // set the EVM block environment
+                blk_env.number = U256::from(header.number);
+                blk_env.coinbase = block_builder.input.beneficiary;
+                blk_env.timestamp = header.timestamp;
+                blk_env.difficulty = U256::ZERO;
+                blk_env.prevrandao = Some(header.mix_hash);
+                blk_env.basefee = header.base_fee_per_gas;
+                blk_env.gas_limit = block_builder.input.gas_limit;
+            })
+            .with_db(block_builder.db.take().unwrap())
+            .append_handler_register(optimism::optimism_handle_register)
+            .build();
+
+        // bloom filter over all transaction logs
+        let mut logs_bloom = Bloom::default();
+        // keep track of the gas used over all transactions
+        let mut cumulative_gas_used = consts::ZERO;
+
+        // process all the transactions
+        let mut tx_trie = MptNode::default();
+        let mut receipt_trie = MptNode::default();
+        for (tx_no, tx) in take(&mut block_builder.input.transactions)
+            .into_iter()
+            .enumerate()
+        {
+            // verify the transaction signature
+            let tx_from = tx
+                .recover_from()
+                .with_context(|| format!("Error recovering address for transaction {tx_no}"))?;
+
+            #[cfg(not(target_os = "zkvm"))]
+            {
+                let tx_hash = tx.hash();
+                debug!("Tx no. {tx_no} (hash: {tx_hash})");
+                debug!("  Type: {}", tx.essence.tx_type());
+                debug!("  Fr: {tx_from:?}");
+                debug!("  To: {:?}", tx.essence.to().unwrap_or_default());
+            }
+
+            // verify transaction gas
+            let block_available_gas = block_builder.input.gas_limit - cumulative_gas_used;
+            if block_available_gas < tx.essence.gas_limit() {
+                bail!("Error at transaction {tx_no}: gas exceeds block limit");
+            }
+
+            match &tx.essence {
+                OptimismTxEssence::OptimismDeposited(deposit) => {
+                    #[cfg(not(target_os = "zkvm"))]
+                    {
+                        debug!("  Source: {:?}", &deposit.source_hash);
+                        debug!("  Mint: {:?}", &deposit.mint);
+                        debug!("  System Tx: {:?}", deposit.is_system_tx);
+                    }
+
+                    // Initialize tx environment
+                    fill_deposit_tx_env(&mut evm.env().tx, deposit, tx_from);
+                }
+                OptimismTxEssence::Ethereum(essence) => {
+                    fill_eth_tx_env(&mut evm.env().tx, tx.to_rlp(), essence, tx_from);
+                }
+            };
+
+            // process the transaction
+            let ResultAndState { result, state } = evm
+                .transact()
+                .map_err(|evm_err| anyhow!("Error at transaction {tx_no}: {evm_err:?}"))?;
+
+            let gas_used = result.gas_used().try_into().unwrap();
+            cumulative_gas_used = cumulative_gas_used.checked_add(gas_used).unwrap();
+
+            #[cfg(not(target_os = "zkvm"))]
+            debug!("  Ok: {result:?}");
+
+            // create the receipt from the EVM result
+            let receipt = Receipt::new(
+                tx.essence.tx_type(),
+                result.is_success(),
+                cumulative_gas_used,
+                result.logs().into_iter().map(|log| log.into()).collect(),
+            );
+
+            // update account states
+            #[cfg(not(target_os = "zkvm"))]
+            for (address, account) in &state {
+                if account.is_touched() {
+                    // log account
+                    debug!(
+                        "  State {address:?} (is_selfdestructed={}, is_loaded_as_not_existing={}, is_created={})",
+                        account.is_selfdestructed(),
+                        account.is_loaded_as_not_existing(),
+                        account.is_created()
+                    );
+                    // log balance changes
+                    debug!(
+                        "     After balance: {} (Nonce: {})",
+                        account.info.balance, account.info.nonce
+                    );
+
+                    // log state changes
+                    for (addr, slot) in &account.storage {
+                        if slot.is_changed() {
+                            debug!("    Storage address: {addr:?}");
+                            debug!("      Before: {:?}", slot.original_value());
+                            debug!("       After: {:?}", slot.present_value());
+                        }
+                    }
+                }
+            }
+
+            evm.context.evm.db.commit(state);
+
+            // accumulate logs to the block bloom filter
+            logs_bloom.accrue_bloom(&receipt.payload.logs_bloom);
+
+            // Add receipt and tx to tries
+            let trie_key = tx_no.to_rlp();
+            tx_trie
+                .insert_rlp(&trie_key, tx)
+                .map_err(Into::<anyhow::Error>::into)
+                .context("failed to insert transaction")?;
+            receipt_trie
+                .insert_rlp(&trie_key, receipt)
+                .map_err(Into::<anyhow::Error>::into)
+                .context("failed to insert receipt")?;
+        }
+
+        // Update result header with computed values
+        header.transactions_root = tx_trie.hash();
+        header.receipts_root = receipt_trie.hash();
+        header.logs_bloom = logs_bloom;
+        header.gas_used = cumulative_gas_used;
+        header.withdrawals_root = None;
+
+        // Leak memory, save cycles
+        guest_mem_forget([tx_trie, receipt_trie]);
+        // Return block builder with updated database
+        Ok(block_builder.with_db(evm.context.evm.db))
+    }
+}
+
+fn fill_deposit_tx_env(tx_env: &mut TxEnv, essence: &TxEssenceOptimismDeposited, caller: Address) {
+    // initialize additional optimism tx fields
+    tx_env.optimism.source_hash = Some(essence.source_hash);
+    tx_env.optimism.mint = Some(essence.mint.try_into().unwrap());
+    tx_env.optimism.is_system_transaction = Some(essence.is_system_tx);
+    tx_env.optimism.enveloped_tx = None; // only used for non-deposit txs
+
+    tx_env.caller = caller; // previously overridden to tx.from
+    tx_env.gas_limit = essence.gas_limit.try_into().unwrap();
+    tx_env.gas_price = U256::ZERO;
+    tx_env.gas_priority_fee = None;
+    tx_env.transact_to = if let TransactionKind::Call(to_addr) = essence.to {
+        TransactTo::Call(to_addr)
+    } else {
+        TransactTo::create()
+    };
+    tx_env.value = essence.value;
+    tx_env.data = essence.data.clone();
+    tx_env.chain_id = None;
+    tx_env.nonce = None;
+    tx_env.access_list.clear();
+}
+
+fn fill_eth_tx_env(tx_env: &mut TxEnv, tx: Vec<u8>, essence: &EthereumTxEssence, caller: Address) {
+    // initialize additional optimism tx fields
+    tx_env.optimism.source_hash = None;
+    tx_env.optimism.mint = None;
+    tx_env.optimism.is_system_transaction = Some(false);
+    tx_env.optimism.enveloped_tx = Some(Bytes::from(tx));
+
+    ethereum::fill_eth_tx_env(tx_env, essence, caller);
+}
diff --git a/lib/src/builder/execute/taiko.rs b/lib/src/builder/execute/taiko.rs
new file mode 100644
index 000000000..1cfa6df27
--- /dev/null
+++ b/lib/src/builder/execute/taiko.rs
@@ -0,0 +1,249 @@
+// Copyright 2024 RISC Zero, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use core::{fmt::Debug, mem::take, str::from_utf8};
+
+use anyhow::{anyhow, bail, Context, Result};
+#[cfg(not(target_os = "zkvm"))]
+use log::debug;
+use revm::{
+    interpreter::Host,
+    primitives::{Address, ResultAndState, SpecId, TxEnv},
+    taiko, Database, DatabaseCommit, Evm,
+};
+use ruint::aliases::U256;
+use zeth_primitives::{
+    receipt::Receipt,
+    transactions::{ethereum::EthereumTxEssence, TxEssence},
+    trie::MptNode,
+    Bloom, RlpBytes,
+};
+
+use super::{ethereum, TxExecStrategy};
+use crate::{
+    builder::BlockBuilder,
+    consts::{self, ChainSpec},
+    guest_mem_forget,
+};
+
+/// Minimum supported protocol version: Bedrock (Block no. 105235063).
+const MIN_SPEC_ID: SpecId = SpecId::SHANGHAI /*change*/;
+
+pub struct TkoTxExecStrategy {}
+
+impl TxExecStrategy<EthereumTxEssence> for TkoTxExecStrategy {
+    fn execute_transactions<D>(
+        mut block_builder: BlockBuilder<D, EthereumTxEssence>,
+    ) -> Result<BlockBuilder<D, EthereumTxEssence>>
+    where
+        D: Database + DatabaseCommit,
+        <D as Database>::Error: Debug,
+    {
+        let header = block_builder
+            .header
+            .as_mut()
+            .expect("Header is not initialized");
+        // Compute the spec id
+        let spec_id = block_builder.chain_spec.spec_id(header.number);
+        if !SpecId::enabled(spec_id, MIN_SPEC_ID) {
+            bail!("Invalid protocol version: expected >= {MIN_SPEC_ID:?}, got {spec_id:?}")
+        }
+        let chain_id = block_builder.chain_spec.chain_id();
+
+        #[cfg(not(target_os = "zkvm"))]
+        {
+            use chrono::{TimeZone, Utc};
+            use log::info;
+            let dt = Utc
+                .timestamp_opt(
+                    block_builder
+                        .input
+                        .timestamp
+                        .try_into()
+                        .expect("Timestamp could not fit into i64"),
+                    0,
+                )
+                .unwrap();
+
+            info!("Block no. {}", header.number);
+            info!("  EVM spec ID: {spec_id:?}");
+            info!("  Timestamp: {dt}");
+            info!("  Transactions: {}", block_builder.input.transactions.len());
+            info!("  Fee Recipient: {:?}", block_builder.input.beneficiary);
+            info!("  Gas limit: {}", block_builder.input.gas_limit);
+            info!("  Base fee per gas: {}", header.base_fee_per_gas);
+            info!("  Extra data: {:?}", block_builder.input.extra_data);
+        }
+
+        let mut evm = Evm::builder()
+            .spec_id(spec_id)
+            .modify_cfg_env(|cfg_env| {
+                // set the EVM configuration
+                cfg_env.chain_id = chain_id;
+                cfg_env.taiko = true;
+            })
+            .modify_block_env(|blk_env| {
+                // set the EVM block environment
+                blk_env.number = U256::from(header.number);
+                blk_env.coinbase = block_builder.input.beneficiary;
+                blk_env.timestamp = header.timestamp;
+                blk_env.difficulty = U256::ZERO;
+                blk_env.prevrandao = Some(header.mix_hash);
+                blk_env.basefee = header.base_fee_per_gas;
+                blk_env.gas_limit = block_builder.input.gas_limit;
+            })
+            .with_db(block_builder.db.take().unwrap())
+            .append_handler_register(taiko::handler_register::taiko_handle_register)
+            .build();
+
+        // bloom filter over all transaction logs
+        let mut logs_bloom = Bloom::default();
+        // keep track of the gas used over all transactions
+        let mut cumulative_gas_used = consts::ZERO;
+
+        // process all the transactions
+        let mut tx_trie = MptNode::default();
+        let mut receipt_trie = MptNode::default();
+        #[allow(unused_variables)]
+        let mut actual_tx_no = 0usize;
+
+        for (tx_no, tx) in take(&mut block_builder.input.transactions)
+            .into_iter()
+            .enumerate()
+        {
+            // anchor transaction must be executed successfully
+            let is_anchor = tx_no == 0;
+            // verify the transaction signature
+            let tx_from = tx
+                .recover_from()
+                .with_context(|| anyhow!("Error recovering address for transaction {tx_no}"))?;
+
+            #[cfg(not(target_os = "zkvm"))]
+            {
+                let tx_hash = tx.hash();
+                debug!("Tx no. {tx_no} (hash: {tx_hash})");
+                debug!("  Type: {}", tx.essence.tx_type());
+                debug!("  Fr: {tx_from:?}");
+                debug!("  To: {:?}", tx.essence.to().unwrap_or_default());
+            }
+
+            // verify transaction gas
+            let block_available_gas = block_builder.input.gas_limit - cumulative_gas_used;
+            if block_available_gas < tx.essence.gas_limit() {
+                bail!("Error at transaction {tx_no}: gas exceeds block limit");
+            }
+
+            fill_eth_tx_env(
+                block_builder.chain_spec,
+                &mut evm.env().tx,
+                &tx.essence,
+                tx_from,
+                is_anchor,
+            );
+
+            // process the transaction
+            let ResultAndState { result, state } = evm
+                .transact()
+                .map_err(|evm_err| anyhow!("Error at transaction {tx_no}: {evm_err:?}"))?;
+
+            if is_anchor && !result.is_success() {
+                bail!(
+                    "Error at transaction {tx_no}: execute anchor failed {result:?}, output {:?}",
+                    result.output().map(|o| from_utf8(o).unwrap_or_default())
+                );
+            }
+
+            let gas_used = result.gas_used().try_into().unwrap();
+            cumulative_gas_used = cumulative_gas_used.checked_add(gas_used).unwrap();
+
+            #[cfg(not(target_os = "zkvm"))]
+            debug!("  Ok: {result:?}");
+
+            // create the receipt from the EVM result
+            let receipt = Receipt::new(
+                tx.essence.tx_type(),
+                result.is_success(),
+                cumulative_gas_used,
+                result.logs().into_iter().map(|log| log.into()).collect(),
+            );
+
+            // update account states
+            #[cfg(not(target_os = "zkvm"))]
+            for (address, account) in &state {
+                if account.is_touched() {
+                    // log account
+                    debug!(
+                        "  State {address:?} (is_selfdestructed={}, is_loaded_as_not_existing={}, is_created={})",
+                        account.is_selfdestructed(),
+                        account.is_loaded_as_not_existing(),
+                        account.is_created()
+                    );
+                    // log balance changes
+                    debug!(
+                        "     After balance: {} (Nonce: {})",
+                        account.info.balance, account.info.nonce
+                    );
+
+                    // log state changes
+                    for (addr, slot) in &account.storage {
+                        if slot.is_changed() {
+                            debug!("    Storage address: {addr:?}");
+                            debug!("      Before: {:?}", slot.original_value());
+                            debug!("       After: {:?}", slot.present_value());
+                        }
+                    }
+                }
+            }
+
+            actual_tx_no += 1;
+
+            evm.context.evm.db.commit(state);
+
+            // accumulate logs to the block bloom filter
+            logs_bloom.accrue_bloom(&receipt.payload.logs_bloom);
+
+            // Add receipt and tx to tries
+            let trie_key = tx_no.to_rlp();
+            tx_trie.insert_rlp(&trie_key, tx)?;
+            receipt_trie.insert_rlp(&trie_key, receipt)?;
+        }
+
+        // Update result header with computed values
+        header.transactions_root = tx_trie.hash();
+        header.receipts_root = receipt_trie.hash();
+        header.logs_bloom = logs_bloom;
+        header.gas_used = cumulative_gas_used;
+        header.withdrawals_root = None;
+
+        // Leak memory, save cycles
+        guest_mem_forget([tx_trie, receipt_trie]);
+        // Return block builder with updated database
+        Ok(block_builder.with_db(evm.context.evm.db))
+    }
+}
+
+pub fn fill_eth_tx_env(
+    _l2_chain_spec: &ChainSpec,
+    tx_env: &mut TxEnv,
+    essence: &EthereumTxEssence,
+    caller: Address,
+    is_anchor: bool,
+) {
+    // claim the anchor
+    tx_env.taiko.is_anchor = is_anchor;
+    // set the treasury address
+    tx_env.taiko.treasury = *crate::taiko::consts::testnet::L2_CONTRACT;
+
+    ethereum::fill_eth_tx_env(tx_env, essence, caller);
+}
diff --git a/lib/src/finalization.rs b/lib/src/builder/finalize.rs
similarity index 56%
rename from lib/src/finalization.rs
rename to lib/src/builder/finalize.rs
index 91972aa30..9cf1c3ddb 100644
--- a/lib/src/finalization.rs
+++ b/lib/src/builder/finalize.rs
@@ -12,54 +12,46 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+use core::mem;
+
 use anyhow::Result;
-use hashbrown::HashMap;
-use revm::primitives::Address;
+use revm::{Database, DatabaseCommit};
 use zeth_primitives::{
     block::Header,
     keccak::keccak,
     transactions::TxEssence,
     trie::{MptNode, StateAccount},
-    U256,
 };
 
 use crate::{
-    block_builder::BlockBuilder,
+    builder::BlockBuilder,
     guest_mem_forget,
     mem_db::{AccountState, MemDb},
 };
 
-pub trait BlockBuildStrategy<E: TxEssence> {
-    type Database;
-    type Output;
-
-    fn build(block_builder: BlockBuilder<Self::Database, E>) -> Result<Self::Output>;
+pub trait BlockFinalizeStrategy<D>
+where
+    D: Database + DatabaseCommit,
+    <D as Database>::Error: core::fmt::Debug,
+{
+    fn finalize<E>(block_builder: BlockBuilder<D, E>) -> Result<(Header, MptNode)>
+    where
+        E: TxEssence;
 }
 
-pub struct BuildFromMemDbStrategy {}
+pub struct MemDbBlockFinalizeStrategy {}
 
-impl BuildFromMemDbStrategy {
-    pub fn build_header<E: TxEssence>(
-        debug_storage_tries: &mut Option<HashMap<Address, MptNode>>,
+impl BlockFinalizeStrategy<MemDb> for MemDbBlockFinalizeStrategy {
+    fn finalize<E: TxEssence>(
         mut block_builder: BlockBuilder<MemDb, E>,
-    ) -> Result<Header> {
-        let db = block_builder.db.as_ref().unwrap();
+    ) -> Result<(Header, MptNode)> {
+        let db = block_builder.db.take().expect("DB not initialized");
 
         // apply state updates
-        let state_trie = &mut block_builder.input.parent_state_trie;
+        let mut state_trie = mem::take(&mut block_builder.input.parent_state_trie);
         for (address, account) in &db.accounts {
             // if the account has not been touched, it can be ignored
             if account.state == AccountState::None {
-                if let Some(map) = debug_storage_tries {
-                    let storage_root = block_builder
-                        .input
-                        .parent_storage
-                        .get(address)
-                        .unwrap()
-                        .0
-                        .clone();
-                    map.insert(*address, storage_root);
-                }
                 continue;
             }
 
@@ -77,8 +69,11 @@ impl BuildFromMemDbStrategy {
             let storage_root = {
                 // getting a mutable reference is more efficient than calling remove
                 // every account must have an entry, even newly created accounts
-                let (storage_trie, _) =
-                    block_builder.input.parent_storage.get_mut(address).unwrap();
+                let (storage_trie, _) = block_builder
+                    .input
+                    .parent_storage
+                    .get_mut(address)
+                    .expect("Address not found in storage");
                 // for cleared accounts always start from the empty trie
                 if account.state == AccountState::StorageCleared {
                     storage_trie.clear();
@@ -87,18 +82,13 @@ impl BuildFromMemDbStrategy {
                 // apply all new storage entries for the current account (address)
                 for (key, value) in state_storage {
                     let storage_trie_index = keccak(key.to_be_bytes::<32>());
-                    if value == &U256::ZERO {
+                    if value.is_zero() {
                         storage_trie.delete(&storage_trie_index)?;
                     } else {
                         storage_trie.insert_rlp(&storage_trie_index, *value)?;
                     }
                 }
 
-                // insert the storage trie for host debugging
-                if let Some(map) = debug_storage_tries {
-                    map.insert(*address, storage_trie.clone());
-                }
-
                 storage_trie.hash()
             };
 
@@ -112,38 +102,12 @@ impl BuildFromMemDbStrategy {
         }
 
         // update result header with the new state root
-        let mut header = block_builder
-            .header
-            .take()
-            .expect("Header was not initialized");
+        let mut header = block_builder.header.take().expect("Header not initialized");
         header.state_root = state_trie.hash();
 
         // Leak memory, save cycles
         guest_mem_forget(block_builder);
 
-        Ok(header)
-    }
-}
-
-impl<E: TxEssence> BlockBuildStrategy<E> for BuildFromMemDbStrategy {
-    type Database = MemDb;
-    type Output = Header;
-
-    #[inline(always)]
-    fn build(block_builder: BlockBuilder<Self::Database, E>) -> Result<Self::Output> {
-        BuildFromMemDbStrategy::build_header(&mut None, block_builder)
-    }
-}
-
-pub struct DebugBuildFromMemDbStrategy {}
-
-impl<E: TxEssence> BlockBuildStrategy<E> for DebugBuildFromMemDbStrategy {
-    type Database = MemDb;
-    type Output = (Header, HashMap<Address, MptNode>);
-
-    fn build(block_builder: BlockBuilder<Self::Database, E>) -> Result<Self::Output> {
-        let mut storage_trace = Some(Default::default());
-        let header = BuildFromMemDbStrategy::build_header(&mut storage_trace, block_builder)?;
-        Ok((header, storage_trace.unwrap()))
+        Ok((header, state_trie))
     }
 }
diff --git a/lib/src/initialization.rs b/lib/src/builder/initialize.rs
similarity index 84%
rename from lib/src/initialization.rs
rename to lib/src/builder/initialize.rs
index 057c5af14..2d8290785 100644
--- a/lib/src/initialization.rs
+++ b/lib/src/builder/initialize.rs
@@ -16,7 +16,10 @@ use core::mem;
 
 use anyhow::{bail, Result};
 use hashbrown::HashMap;
-use revm::primitives::{AccountInfo, Bytecode, B256};
+use revm::{
+    primitives::{AccountInfo, Bytecode, B256},
+    Database, DatabaseCommit,
+};
 use zeth_primitives::{
     keccak::{keccak, KECCAK_EMPTY},
     transactions::TxEssence,
@@ -25,28 +28,28 @@ use zeth_primitives::{
 };
 
 use crate::{
-    block_builder::BlockBuilder,
+    builder::BlockBuilder,
     consts::MAX_BLOCK_HASH_AGE,
     guest_mem_forget,
     mem_db::{AccountState, DbAccount, MemDb},
 };
 
-pub trait DbInitStrategy<E: TxEssence> {
-    type Database;
-
-    fn initialize_database(
-        block_builder: BlockBuilder<Self::Database, E>,
-    ) -> Result<BlockBuilder<Self::Database, E>>;
+pub trait DbInitStrategy<D>
+where
+    D: Database + DatabaseCommit,
+    <D as Database>::Error: core::fmt::Debug,
+{
+    fn initialize_database<E>(block_builder: BlockBuilder<D, E>) -> Result<BlockBuilder<D, E>>
+    where
+        E: TxEssence;
 }
 
 pub struct MemDbInitStrategy {}
 
-impl<E: TxEssence> DbInitStrategy<E> for MemDbInitStrategy {
-    type Database = MemDb;
-
-    fn initialize_database(
-        mut block_builder: BlockBuilder<Self::Database, E>,
-    ) -> Result<BlockBuilder<Self::Database, E>> {
+impl DbInitStrategy<MemDb> for MemDbInitStrategy {
+    fn initialize_database<E: TxEssence>(
+        mut block_builder: BlockBuilder<MemDb, E>,
+    ) -> Result<BlockBuilder<MemDb, E>> {
         // Verify state trie root
         if block_builder.input.parent_state_trie.hash()
             != block_builder.input.parent_header.state_root
@@ -79,8 +82,7 @@ impl<E: TxEssence> DbInitStrategy<E> for MemDbInitStrategy {
             // Verify storage trie root
             if storage_trie.hash() != state_account.storage_root {
                 bail!(
-                    "Invalid storage trie for {:?}: expected {}, got {}",
-                    address,
+                    "Invalid storage trie for {address:?}: expected {}, got {}",
                     state_account.storage_root,
                     storage_trie.hash()
                 );
@@ -91,7 +93,10 @@ impl<E: TxEssence> DbInitStrategy<E> for MemDbInitStrategy {
             let bytecode = if code_hash.0 == KECCAK_EMPTY.0 {
                 Bytecode::new()
             } else {
-                let bytes = contracts.get(&code_hash).unwrap().clone();
+                let bytes = contracts
+                    .get(&code_hash)
+                    .expect("Contract not found")
+                    .clone();
                 Bytecode::new_raw(bytes)
             };
 
@@ -140,9 +145,8 @@ impl<E: TxEssence> DbInitStrategy<E> for MemDbInitStrategy {
                 || block_builder.input.parent_header.number - current.number >= MAX_BLOCK_HASH_AGE
             {
                 bail!(
-                    "Invalid chain: {} is not one of the {} most recent blocks",
+                    "Invalid chain: {} is not one of the {MAX_BLOCK_HASH_AGE} most recent blocks",
                     current.number,
-                    MAX_BLOCK_HASH_AGE,
                 );
             }
             block_hashes.insert(current.number, current_hash);
diff --git a/lib/src/builder/mod.rs b/lib/src/builder/mod.rs
new file mode 100644
index 000000000..e2321a22d
--- /dev/null
+++ b/lib/src/builder/mod.rs
@@ -0,0 +1,163 @@
+// Copyright 2023 RISC Zero, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use anyhow::Result;
+use revm::{Database, DatabaseCommit};
+use zeth_primitives::{
+    block::Header,
+    transactions::{ethereum::EthereumTxEssence, TxEssence},
+    trie::MptNode,
+};
+
+#[cfg(feature = "optimism")]
+pub use self::execute::optimism::OpTxExecStrategy;
+#[cfg(feature = "optimism")]
+use crate::OptimismTxEssence;
+#[cfg(feature = "taiko")]
+pub use self::execute::taiko::TkoTxExecStrategy;
+use crate::{
+    builder::{
+        execute::{ethereum::EthTxExecStrategy, TxExecStrategy},
+        finalize::{BlockFinalizeStrategy, MemDbBlockFinalizeStrategy},
+        initialize::{DbInitStrategy, MemDbInitStrategy},
+        prepare::{EthHeaderPrepStrategy, HeaderPrepStrategy},
+    },
+    consts::ChainSpec,
+    input::Input,
+    mem_db::MemDb,
+};
+
+mod execute;
+mod finalize;
+mod initialize;
+pub mod prepare;
+
+/// A generic builder for building a block.
+#[derive(Clone, Debug)]
+pub struct BlockBuilder<'a, D, E: TxEssence> {
+    pub(crate) chain_spec: &'a ChainSpec,
+    pub(crate) input: Input<E>,
+    pub(crate) db: Option<D>,
+    pub(crate) header: Option<Header>,
+}
+
+impl<D, E> BlockBuilder<'_, D, E>
+where
+    D: Database + DatabaseCommit,
+    <D as Database>::Error: core::fmt::Debug,
+    E: TxEssence,
+{
+    /// Creates a new block builder.
+    pub fn new(chain_spec: &ChainSpec, input: Input<E>) -> BlockBuilder<'_, D, E> {
+        BlockBuilder {
+            chain_spec,
+            db: None,
+            header: None,
+            input,
+        }
+    }
+
+    /// Sets the database instead of initializing it from the input.
+    pub fn with_db(mut self, db: D) -> Self {
+        self.db = Some(db);
+        self
+    }
+
+    /// Initializes the database from the input.
+    pub fn initialize_database<T: DbInitStrategy<D>>(self) -> Result<Self> {
+        T::initialize_database(self)
+    }
+
+    /// Initializes the header. This must be called before executing transactions.
+    pub fn prepare_header<T: HeaderPrepStrategy>(self) -> Result<Self> {
+        T::prepare_header(self)
+    }
+
+    /// Executes all input transactions.
+    pub fn execute_transactions<T: TxExecStrategy<E>>(self) -> Result<Self> {
+        T::execute_transactions(self)
+    }
+
+    /// Finalizes the block building and returns the header and the state trie.
+    pub fn finalize<T: BlockFinalizeStrategy<D>>(self) -> Result<(Header, MptNode)> {
+        T::finalize(self)
+    }
+
+    /// Returns a reference to the database.
+    pub fn db(&self) -> Option<&D> {
+        self.db.as_ref()
+    }
+
+    /// Returns a mutable reference to the database.
+    pub fn mut_db(&mut self) -> Option<&mut D> {
+        self.db.as_mut()
+    }
+}
+
+/// A bundle of strategies for building a block using [BlockBuilder].
+pub trait BlockBuilderStrategy {
+    type TxEssence: TxEssence;
+
+    type DbInitStrategy: DbInitStrategy<MemDb>;
+    type HeaderPrepStrategy: HeaderPrepStrategy;
+    type TxExecStrategy: TxExecStrategy<Self::TxEssence>;
+    type BlockFinalizeStrategy: BlockFinalizeStrategy<MemDb>;
+
+    /// Builds a block from the given input.
+    fn build_from(
+        chain_spec: &ChainSpec,
+        input: Input<Self::TxEssence>,
+    ) -> Result<(Header, MptNode)> {
+        BlockBuilder::<MemDb, Self::TxEssence>::new(chain_spec, input)
+            .initialize_database::<Self::DbInitStrategy>()?
+            .prepare_header::<Self::HeaderPrepStrategy>()?
+            .execute_transactions::<Self::TxExecStrategy>()?
+            .finalize::<Self::BlockFinalizeStrategy>()
+    }
+}
+
+/// The [BlockBuilderStrategy] for building an Ethereum block.
+pub struct EthereumStrategy {}
+
+impl BlockBuilderStrategy for EthereumStrategy {
+    type TxEssence = EthereumTxEssence;
+    type DbInitStrategy = MemDbInitStrategy;
+    type HeaderPrepStrategy = EthHeaderPrepStrategy;
+    type TxExecStrategy = EthTxExecStrategy;
+    type BlockFinalizeStrategy = MemDbBlockFinalizeStrategy;
+}
+
+/// The [BlockBuilderStrategy] for building an Optimism block.
+#[cfg(feature = "optimism")]
+pub struct OptimismStrategy {}
+#[cfg(feature = "optimism")]
+impl BlockBuilderStrategy for OptimismStrategy {
+    type TxEssence = OptimismTxEssence;
+    type DbInitStrategy = MemDbInitStrategy;
+    type HeaderPrepStrategy = EthHeaderPrepStrategy;
+    type TxExecStrategy = OpTxExecStrategy;
+    type BlockFinalizeStrategy = MemDbBlockFinalizeStrategy;
+}
+
+/// The [BlockBuilderStrategy] for building an Optimism block.
+#[cfg(feature = "taiko")]
+pub struct TaikoStrategy {}
+#[cfg(feature = "taiko")]
+impl BlockBuilderStrategy for TaikoStrategy {
+    type TxEssence = EthereumTxEssence;
+    type DbInitStrategy = MemDbInitStrategy;
+    type HeaderPrepStrategy = EthHeaderPrepStrategy;
+    type TxExecStrategy = TkoTxExecStrategy;
+    type BlockFinalizeStrategy = MemDbBlockFinalizeStrategy;
+}
diff --git a/lib/src/preparation.rs b/lib/src/builder/prepare.rs
similarity index 90%
rename from lib/src/preparation.rs
rename to lib/src/builder/prepare.rs
index 81c5c4e36..f2613ca07 100644
--- a/lib/src/preparation.rs
+++ b/lib/src/builder/prepare.rs
@@ -19,7 +19,7 @@ use revm::{Database, DatabaseCommit};
 use zeth_primitives::{block::Header, transactions::TxEssence, U256};
 
 use crate::{
-    block_builder::BlockBuilder,
+    builder::BlockBuilder,
     consts::{Eip1559Constants, GAS_LIMIT_BOUND_DIVISOR, MAX_EXTRA_DATA_BYTES, MIN_GAS_LIMIT, ONE},
 };
 
@@ -27,7 +27,7 @@ pub trait HeaderPrepStrategy {
     fn prepare_header<D, E>(block_builder: BlockBuilder<D, E>) -> Result<BlockBuilder<D, E>>
     where
         D: Database + DatabaseCommit,
-        <D as Database>::Error: Debug,
+        <D as Database>::Error: core::fmt::Debug,
         E: TxEssence;
 }
 
@@ -49,16 +49,14 @@ impl HeaderPrepStrategy for EthHeaderPrepStrategy {
         let limit = block_builder.input.parent_header.gas_limit / GAS_LIMIT_BOUND_DIVISOR;
         if diff >= limit {
             bail!(
-                "Invalid gas limit: expected {} +- {}, got {}",
+                "Invalid gas limit: expected {} +- {limit}, got {}",
                 block_builder.input.parent_header.gas_limit,
-                limit,
                 block_builder.input.gas_limit,
             );
         }
         if block_builder.input.gas_limit < MIN_GAS_LIMIT {
             bail!(
-                "Invalid gas limit: expected >= {}, got {}",
-                MIN_GAS_LIMIT,
+                "Invalid gas limit: expected >= {MIN_GAS_LIMIT}, got {}",
                 block_builder.input.gas_limit,
             );
         }
@@ -73,11 +71,7 @@ impl HeaderPrepStrategy for EthHeaderPrepStrategy {
         // Validate extra data
         let extra_data_bytes = block_builder.input.extra_data.len();
         if extra_data_bytes > MAX_EXTRA_DATA_BYTES {
-            bail!(
-                "Invalid extra data: expected <= {}, got {}",
-                MAX_EXTRA_DATA_BYTES,
-                extra_data_bytes,
-            )
+            bail!("Invalid extra data: expected <= {MAX_EXTRA_DATA_BYTES}, got {extra_data_bytes}");
         }
         // Derive header
         block_builder.header = Some(Header {
@@ -107,8 +101,7 @@ impl HeaderPrepStrategy for EthHeaderPrepStrategy {
 }
 
 /// Base fee for next block. [EIP-1559](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1559.md) spec
-#[inline(always)]
-pub fn derive_base_fee(parent: &Header, eip_1559_constants: &Eip1559Constants) -> Result<U256> {
+fn derive_base_fee(parent: &Header, eip_1559_constants: &Eip1559Constants) -> Result<U256> {
     let parent_gas_target = parent.gas_limit / eip_1559_constants.elasticity_multiplier;
 
     match parent.gas_used.cmp(&parent_gas_target) {
diff --git a/lib/src/consts.rs b/lib/src/consts.rs
index 5c7d1e3c1..69c49b158 100644
--- a/lib/src/consts.rs
+++ b/lib/src/consts.rs
@@ -13,6 +13,7 @@
 // limitations under the License.
 
 //! Constants for the Ethereum protocol.
+extern crate alloc;
 
 use alloc::{
     collections::BTreeMap,
@@ -24,7 +25,7 @@ use anyhow::bail;
 use once_cell::sync::Lazy;
 use revm::primitives::SpecId;
 use serde::{Deserialize, Serialize};
-use zeth_primitives::{uint, Address, BlockNumber, ChainId, U256};
+use zeth_primitives::{uint, BlockNumber, ChainId, U256};
 
 /// U256 representation of 0.
 pub const ZERO: U256 = U256::ZERO;
@@ -45,9 +46,6 @@ pub const MAX_BLOCK_HASH_AGE: u64 = 256;
 /// Multiplier for converting gwei to wei.
 pub const GWEI_TO_WEI: U256 = uint!(1_000_000_000_U256);
 
-/// Minimum supported protocol version: Paris (Block no. 15537394).
-pub const MIN_SPEC_ID: SpecId = SpecId::MERGE;
-
 /// The Ethereum mainnet specification.
 pub static ETH_MAINNET_CHAIN_SPEC: Lazy<ChainSpec> = Lazy::new(|| {
     ChainSpec {
@@ -65,66 +63,49 @@ pub static ETH_MAINNET_CHAIN_SPEC: Lazy<ChainSpec> = Lazy::new(|| {
             base_fee_max_decrease_denominator: uint!(8_U256),
             elasticity_multiplier: uint!(2_U256),
         },
-        l1_contract: None,
-        l1_signal_service: None,
-        l2_contract: None,
-        l2_signal_service: None,
     }
 });
 
+/// The Taiko mainnet specification.
 #[cfg(feature = "taiko")]
-macro_rules! taiko_chain_spec {
-    ($a:ident, $b:ident ) => {
-        pub static $a: Lazy<ChainSpec> = Lazy::new(|| {
-            use zeth_primitives::taiko::$b::*;
-            ChainSpec {
-                chain_id: CHAIN_ID,
-                hard_forks: BTreeMap::from([
-                    (SpecId::SHANGHAI, ForkCondition::Block(0)),
-                    (SpecId::CANCUN, ForkCondition::TBD),
-                ]),
-                eip_1559_constants: Eip1559Constants {
-                    base_fee_change_denominator: uint!(8_U256),
-                    base_fee_max_increase_denominator: uint!(8_U256),
-                    base_fee_max_decrease_denominator: uint!(8_U256),
-                    elasticity_multiplier: uint!(2_U256),
-                },
-                l1_contract: Some(*L1_CONTRACT),
-                l1_signal_service: Some(*L1_SIGNAL_SERVICE),
-                l2_contract: Some(*L2_CONTRACT),
-                l2_signal_service: Some(*L2_SIGNAL_SERVICE),
-            }
-        });
-    };
-}
-
-taiko_chain_spec!(TAIKO_TESTNET_CHAIN_SPEC, testnet);
-taiko_chain_spec!(TAIKO_INTERNAL_DEVNET_A_CHAIN_SPEC, internal_devnet_a);
-taiko_chain_spec!(TAIKO_INTERNAL_DEVNET_B_CHAIN_SPEC, internal_devnet_b);
-
-pub fn get_taiko_chain_spec(chain: &str) -> ChainSpec {
-    match chain {
-        "testnet" => TAIKO_TESTNET_CHAIN_SPEC.clone(),
-        "internal_devnet_a" => TAIKO_INTERNAL_DEVNET_A_CHAIN_SPEC.clone(),
-        "internal_devnet_b" => TAIKO_INTERNAL_DEVNET_B_CHAIN_SPEC.clone(),
-        _ => panic!("unknown chain"),
+pub static TKO_MAINNET_CHAIN_SPEC: Lazy<ChainSpec> = Lazy::new(|| {
+    ChainSpec {
+        chain_id: 1,
+        hard_forks: BTreeMap::from([
+            (SpecId::SHANGHAI, ForkCondition::Block(0)),
+            (SpecId::SHANGHAI /* change */, ForkCondition::Block(0)),
+            // previous versions not supported
+            (SpecId::CANCUN, ForkCondition::TBD),
+        ]),
+        eip_1559_constants: Eip1559Constants {
+            base_fee_change_denominator: uint!(8_U256),
+            base_fee_max_increase_denominator: uint!(8_U256),
+            base_fee_max_decrease_denominator: uint!(8_U256),
+            elasticity_multiplier: uint!(2_U256),
+        },
     }
-}
+});
+
+#[cfg(feature = "taiko")]
+pub use crate::taiko::consts::testnet::*;
 
-/// The optimism mainnet specification.
+/// The Optimism mainnet specification.
+#[cfg(feature = "optimism")]
 pub static OP_MAINNET_CHAIN_SPEC: Lazy<ChainSpec> = Lazy::new(|| ChainSpec {
     chain_id: 10,
-    hard_forks: BTreeMap::from([(SpecId::MERGE, ForkCondition::Block(0))]),
+    hard_forks: BTreeMap::from([
+        (SpecId::FRONTIER, ForkCondition::Block(0)),
+        // previous versions not supported
+        (SpecId::BEDROCK, ForkCondition::Block(105235063)),
+        // Regolith is activated from day 1 of Bedrock on mainnet
+        (SpecId::REGOLITH, ForkCondition::Block(105235063)),
+    ]),
     eip_1559_constants: Eip1559Constants {
         base_fee_change_denominator: uint!(50_U256),
         base_fee_max_increase_denominator: uint!(10_U256),
         base_fee_max_decrease_denominator: uint!(50_U256),
         elasticity_multiplier: uint!(6_U256),
     },
-    l1_contract: None,
-    l1_signal_service: None,
-    l2_contract: None,
-    l2_signal_service: None,
 });
 
 /// The condition at which a fork is activated.
@@ -170,13 +151,9 @@ impl Default for Eip1559Constants {
 /// Specification of a specific chain.
 #[derive(Debug, Clone, Default, Serialize, Deserialize)]
 pub struct ChainSpec {
-    chain_id: ChainId,
-    hard_forks: BTreeMap<SpecId, ForkCondition>,
-    eip_1559_constants: Eip1559Constants,
-    pub l1_contract: Option<Address>,
-    pub l1_signal_service: Option<Address>,
-    pub l2_contract: Option<Address>,
-    pub l2_signal_service: Option<Address>,
+    pub chain_id: ChainId,
+    pub hard_forks: BTreeMap<SpecId, ForkCondition>,
+    pub eip_1559_constants: Eip1559Constants,
 }
 
 impl ChainSpec {
@@ -190,10 +167,6 @@ impl ChainSpec {
             chain_id,
             hard_forks: BTreeMap::from([(spec_id, ForkCondition::Block(0))]),
             eip_1559_constants,
-            l1_contract: None,
-            l1_signal_service: None,
-            l2_contract: None,
-            l2_signal_service: None,
         }
     }
     /// Returns the network chain ID.
@@ -231,6 +204,7 @@ impl FromStr for Network {
         match s.to_lowercase().as_str() {
             "ethereum" => Ok(Network::Ethereum),
             "optimism" => Ok(Network::Optimism),
+            #[allow(clippy::needless_return)]
             _ => bail!("Unknown network"),
         }
     }
diff --git a/lib/src/execution/optimism.rs b/lib/src/execution/optimism.rs
deleted file mode 100644
index e164ddafb..000000000
--- a/lib/src/execution/optimism.rs
+++ /dev/null
@@ -1,472 +0,0 @@
-// Copyright 2023 RISC Zero, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-use alloc::{format, vec, vec::Vec};
-use core::{fmt::Debug, mem::take, str::FromStr};
-
-use anyhow::{anyhow, bail, Context, Result};
-#[cfg(not(target_os = "zkvm"))]
-use log::debug;
-use revm::{
-    primitives::{Account, Address, ResultAndState, SpecId, TransactTo, TxEnv},
-    Database, DatabaseCommit, EVM,
-};
-use ruint::aliases::U256;
-use zeth_primitives::{
-    receipt::Receipt,
-    transactions::{
-        ethereum::{EthereumTxEssence, TransactionKind},
-        optimism::{OptimismTxEssence, TxEssenceOptimismDeposited},
-        TxEssence,
-    },
-    trie::MptNode,
-    Bloom, RlpBytes,
-};
-
-use crate::{
-    block_builder::BlockBuilder,
-    consts,
-    consts::{GWEI_TO_WEI, MIN_SPEC_ID},
-    execution::{
-        ethereum::{fill_eth_tx_env, increase_account_balance},
-        TxExecStrategy,
-    },
-    guest_mem_forget,
-};
-
-pub struct OpTxExecStrategy {}
-
-impl TxExecStrategy<OptimismTxEssence> for OpTxExecStrategy {
-    fn execute_transactions<D>(
-        mut block_builder: BlockBuilder<D, OptimismTxEssence>,
-    ) -> Result<BlockBuilder<D, OptimismTxEssence>>
-    where
-        D: Database + DatabaseCommit,
-        <D as Database>::Error: Debug,
-    {
-        let header = block_builder
-            .header
-            .as_mut()
-            .expect("Header is not initialized");
-        // Compute the spec id
-        let spec_id = block_builder.chain_spec.spec_id(header.number);
-        if !SpecId::enabled(spec_id, MIN_SPEC_ID) {
-            bail!(
-                "Invalid protocol version: expected >= {:?}, got {:?}",
-                MIN_SPEC_ID,
-                spec_id,
-            )
-        }
-        let chain_id = block_builder.chain_spec.chain_id();
-
-        #[cfg(not(target_os = "zkvm"))]
-        {
-            use chrono::{TimeZone, Utc};
-            use log::info;
-            let dt = Utc
-                .timestamp_opt(block_builder.input.timestamp.try_into().unwrap(), 0)
-                .unwrap();
-
-            info!("Block no. {}", header.number);
-            info!("  EVM spec ID: {:?}", spec_id);
-            info!("  Timestamp: {}", dt);
-            info!("  Transactions: {}", block_builder.input.transactions.len());
-            info!("  Withdrawals: {}", block_builder.input.withdrawals.len());
-            info!("  Fee Recipient: {:?}", block_builder.input.beneficiary);
-            info!("  Gas limit: {}", block_builder.input.gas_limit);
-            info!("  Base fee per gas: {}", header.base_fee_per_gas);
-            info!("  Extra data: {:?}", block_builder.input.extra_data);
-        }
-
-        // initialize the EVM
-        let mut evm = EVM::new();
-
-        // set the EVM configuration
-        evm.env.cfg.chain_id = chain_id;
-        evm.env.cfg.spec_id = spec_id;
-
-        // set the EVM block environment
-        evm.env.block.number = header.number.try_into().unwrap();
-        evm.env.block.coinbase = block_builder.input.beneficiary;
-        evm.env.block.timestamp = header.timestamp;
-        evm.env.block.difficulty = U256::ZERO;
-        evm.env.block.prevrandao = Some(header.mix_hash);
-        evm.env.block.basefee = header.base_fee_per_gas;
-        evm.env.block.gas_limit = block_builder.input.gas_limit;
-
-        evm.database(block_builder.db.take().unwrap());
-
-        // bloom filter over all transaction logs
-        let mut logs_bloom = Bloom::default();
-        // keep track of the gas used over all transactions
-        let mut cumulative_gas_used = consts::ZERO;
-
-        let l1_info_depositor_address =
-            Address::from_str("0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001").unwrap();
-
-        let l1_block_attr_pre_deploy =
-            Address::from_str("0x4200000000000000000000000000000000000015").unwrap();
-
-        let l1_gas_oracle_pre_deploy =
-            Address::from_str("0x420000000000000000000000000000000000000F").unwrap();
-
-        let l1_fee_vault_pre_deploy =
-            Address::from_str("0x420000000000000000000000000000000000001A").unwrap();
-
-        let base_fee_vault_pre_deploy =
-            Address::from_str("0x4200000000000000000000000000000000000019").unwrap();
-
-        let l1_fee_overhead_decimals = U256::from(10).pow(read_uint(
-            &mut evm,
-            vec![0x31u8, 0x3cu8, 0xe5u8, 0x67u8],
-            Some(chain_id),
-            header.gas_limit,
-            l1_gas_oracle_pre_deploy,
-        )?);
-
-        // process all the transactions
-        let mut tx_trie = MptNode::default();
-        let mut receipt_trie = MptNode::default();
-        for (tx_no, tx) in take(&mut block_builder.input.transactions)
-            .into_iter()
-            .enumerate()
-        {
-            // verify the transaction signature
-            let tx_from = tx
-                .recover_from()
-                .with_context(|| format!("Error recovering address for transaction {}", tx_no))?;
-
-            #[cfg(not(target_os = "zkvm"))]
-            {
-                let tx_hash = tx.hash();
-                debug!("Tx no. {} (hash: {})", tx_no, tx_hash);
-                debug!("  Type: {}", tx.essence.tx_type());
-                debug!("  Fr: {:?}", tx_from);
-                debug!("  To: {:?}", tx.essence.to().unwrap_or_default());
-            }
-
-            // verify transaction gas
-            let block_available_gas = block_builder.input.gas_limit - cumulative_gas_used;
-            if block_available_gas < tx.essence.gas_limit() {
-                bail!("Error at transaction {}: gas exceeds block limit", tx_no);
-            }
-
-            let l1_gas_fees = match &tx.essence {
-                OptimismTxEssence::OptimismDeposited(deposit) => {
-                    // Disable gas fees
-                    evm.env.cfg.disable_base_fee = true;
-                    evm.env.cfg.disable_balance_check = true;
-                    // Irrevocably credit minted amount
-                    let db = evm.db().unwrap();
-                    increase_account_balance(db, tx_from, deposit.mint)?;
-                    // Retrieve effective nonce
-                    // todo: read this from contract
-                    let effective_nonce = if tx_from == l1_info_depositor_address {
-                        None
-                    } else {
-                        Some(db.basic(tx_from).unwrap().unwrap_or_default().nonce)
-                    };
-                    // Initialize tx environment
-                    fill_deposit_tx_env(&mut evm.env.tx, deposit, tx_from, effective_nonce);
-
-                    U256::ZERO
-                }
-                OptimismTxEssence::Ethereum(transaction) => {
-                    // L1 gas fee
-                    // todo: read these values only once after processing the first system tx
-                    let l1_base_fee = read_uint(
-                        &mut evm,
-                        vec![0x5cu8, 0xf2u8, 0x49u8, 0x69u8],
-                        Some(chain_id),
-                        header.gas_limit,
-                        l1_block_attr_pre_deploy,
-                    )?;
-                    let l1_fee_overhead = read_uint(
-                        &mut evm,
-                        vec![0x8bu8, 0x23u8, 0x9fu8, 0x73u8],
-                        Some(chain_id),
-                        header.gas_limit,
-                        l1_block_attr_pre_deploy,
-                    )?;
-                    let l1_fee_scalar = read_uint(
-                        &mut evm,
-                        vec![0x9eu8, 0x8cu8, 0x49u8, 0x66u8],
-                        Some(chain_id),
-                        header.gas_limit,
-                        l1_block_attr_pre_deploy,
-                    )?;
-
-                    let tx_data = tx.to_rlp();
-                    let non_zero = tx_data.iter().filter(|b| *b > &0u8).count() as u128;
-                    let zeroes = tx_data.len() as u128 - non_zero;
-                    let l1_gas = U256::from(16u128 * non_zero + 4u128 * zeroes) + l1_fee_overhead;
-                    let l1_gas_fees =
-                        (l1_base_fee * l1_gas * l1_fee_scalar) / l1_fee_overhead_decimals;
-
-                    // Deduct L1 fee from sender
-                    decrease_account_balance(evm.db().unwrap(), tx_from, l1_gas_fees)?;
-
-                    // Enable gas fees
-                    evm.env.cfg.disable_base_fee = false;
-                    evm.env.cfg.disable_balance_check = false;
-                    // Initialize tx environment
-                    fill_eth_tx_env(&mut evm.env.tx, transaction, tx_from);
-                    l1_gas_fees
-                }
-            };
-
-            // process the transaction
-            let ResultAndState { result, state } = evm
-                .transact()
-                .map_err(|evm_err| anyhow!("Error at transaction {}: {:?}", tx_no, evm_err))?;
-
-            let gas_used = result.gas_used().try_into().unwrap();
-            cumulative_gas_used = cumulative_gas_used.checked_add(gas_used).unwrap();
-
-            #[cfg(not(target_os = "zkvm"))]
-            debug!("  Ok: {:?}", result);
-
-            // create the receipt from the EVM result
-            let receipt = Receipt::new(
-                tx.essence.tx_type(),
-                result.is_success(),
-                cumulative_gas_used,
-                result.logs().into_iter().map(|log| log.into()).collect(),
-            );
-
-            // update account states
-            #[cfg(not(target_os = "zkvm"))]
-            for (address, account) in &state {
-                if account.is_touched() {
-                    // log account
-                    debug!(
-                        "  State {:?} (is_selfdestructed={}, is_loaded_as_not_existing={}, is_created={})",
-                        address,
-                        account.is_selfdestructed(),
-                        account.is_loaded_as_not_existing(),
-                        account.is_created()
-                    );
-                    // log balance changes
-                    debug!(
-                        "     After balance: {} (Nonce: {})",
-                        account.info.balance, account.info.nonce
-                    );
-
-                    // log state changes
-                    for (addr, slot) in &account.storage {
-                        if slot.is_changed() {
-                            debug!("    Storage address: {:?}", addr);
-                            debug!("      Before: {:?}", slot.original_value());
-                            debug!("       After: {:?}", slot.present_value());
-                        }
-                    }
-                }
-            }
-
-            let db = evm.db().unwrap();
-
-            db.commit(state);
-
-            if !matches!(tx.essence, OptimismTxEssence::OptimismDeposited(_)) {
-                // Credit L2 base fee
-                increase_account_balance(
-                    db,
-                    base_fee_vault_pre_deploy,
-                    gas_used * header.base_fee_per_gas,
-                )?;
-                // Credit L1 gas fee
-                increase_account_balance(db, l1_fee_vault_pre_deploy, l1_gas_fees)?;
-            }
-
-            // accumulate logs to the block bloom filter
-            logs_bloom.accrue_bloom(&receipt.payload.logs_bloom);
-
-            // Add receipt and tx to tries
-            let trie_key = tx_no.to_rlp();
-            tx_trie
-                .insert_rlp(&trie_key, tx)
-                .map_err(Into::<anyhow::Error>::into)
-                .context("failed to insert transaction")?;
-            receipt_trie
-                .insert_rlp(&trie_key, receipt)
-                .map_err(Into::<anyhow::Error>::into)
-                .context("failed to insert receipt")?;
-        }
-
-        let mut db = evm.take_db();
-
-        // process withdrawals unconditionally after any transactions
-        let mut withdrawals_trie = MptNode::default();
-        for (i, withdrawal) in take(&mut block_builder.input.withdrawals)
-            .into_iter()
-            .enumerate()
-        {
-            // the withdrawal amount is given in Gwei
-            let amount_wei = GWEI_TO_WEI
-                .checked_mul(withdrawal.amount.try_into().unwrap())
-                .unwrap();
-
-            #[cfg(not(target_os = "zkvm"))]
-            {
-                debug!("Withdrawal no. {}", withdrawal.index);
-                debug!("  Recipient: {:?}", withdrawal.address);
-                debug!("  Value: {}", amount_wei);
-            }
-            // Read account from database
-            let withdrawal_address = withdrawal.address;
-            let mut withdrawal_account: Account = db
-                .basic(withdrawal.address)
-                .map_err(|db_err| anyhow!("Error at withdrawal {}: {:?}", i, db_err))?
-                .unwrap_or_default()
-                .into();
-            // Credit withdrawal amount
-            withdrawal_account.info.balance = withdrawal_account
-                .info
-                .balance
-                .checked_add(amount_wei)
-                .unwrap();
-            withdrawal_account.mark_touch();
-            // Commit changes to database
-            db.commit([(withdrawal_address, withdrawal_account)].into());
-            // Add withdrawal to trie
-            withdrawals_trie
-                .insert_rlp(&i.to_rlp(), withdrawal)
-                .map_err(Into::<anyhow::Error>::into)
-                .context("failed to insert withdrawal")?;
-        }
-
-        // Update result header with computed values
-        header.transactions_root = tx_trie.hash();
-        header.receipts_root = receipt_trie.hash();
-        header.logs_bloom = logs_bloom;
-        header.gas_used = cumulative_gas_used;
-        header.withdrawals_root = if spec_id < SpecId::SHANGHAI {
-            None
-        } else {
-            Some(withdrawals_trie.hash())
-        };
-
-        // Leak memory, save cycles
-        guest_mem_forget([tx_trie, receipt_trie, withdrawals_trie]);
-        // Return block builder with updated database
-        Ok(block_builder.with_db(db))
-    }
-}
-
-fn read_uint<D>(
-    evm: &mut EVM<D>,
-    abi_call: Vec<u8>,
-    chain_id: Option<zeth_primitives::ChainId>,
-    gas_limit: U256,
-    address: Address,
-) -> Result<U256>
-where
-    D: Database + DatabaseCommit,
-    <D as Database>::Error: Debug,
-{
-    let op_l1_tx =
-        EthereumTxEssence::Legacy(zeth_primitives::transactions::ethereum::TxEssenceLegacy {
-            chain_id,
-            nonce: 0,
-            gas_price: U256::ZERO,
-            gas_limit,
-            to: TransactionKind::Call(address),
-            value: U256::ZERO,
-            data: abi_call.into(),
-        });
-
-    // disable base fees
-    evm.env.cfg.disable_base_fee = true;
-    evm.env.cfg.disable_balance_check = true;
-    fill_eth_tx_env(&mut evm.env.tx, &op_l1_tx, Default::default());
-
-    let Ok(ResultAndState {
-        result: execution_result,
-        ..
-    }) = evm.transact()
-    else {
-        bail!("Error during execution");
-    };
-
-    let revm::primitives::ExecutionResult::Success { output, .. } = execution_result else {
-        bail!("Result unsuccessful");
-    };
-
-    let revm::primitives::Output::Call(result_encoded) = output else {
-        bail!("Unsupported result");
-    };
-
-    // let ethers_core::abi::Token::Uint(uint_result) =
-    //     ethers_core::abi::decode(&[ethers_core::abi::ParamType::Uint(256)],
-    // &result_encoded)?         .pop()
-    //         .unwrap()
-    // else {
-    //     bail!("Could not decode result");
-    // };
-
-    // Ok(U256::from_limbs(uint_result.0))
-    // Todo (Cecilia): fix this
-    Ok(U256::default())
-}
-
-fn fill_deposit_tx_env(
-    tx_env: &mut TxEnv,
-    tx: &TxEssenceOptimismDeposited,
-    caller: Address,
-    deposit_nonce: Option<u64>,
-) {
-    tx_env.caller = caller; // previously overridden to tx.from
-    tx_env.gas_limit = tx.gas_limit.try_into().unwrap();
-    tx_env.gas_price = U256::ZERO;
-    tx_env.gas_priority_fee = None;
-    tx_env.transact_to = if let TransactionKind::Call(to_addr) = tx.to {
-        TransactTo::Call(to_addr)
-    } else {
-        TransactTo::create()
-    };
-    tx_env.value = tx.value;
-    tx_env.data = tx.data.clone();
-    tx_env.chain_id = None;
-    tx_env.nonce = deposit_nonce;
-    tx_env.access_list.clear();
-}
-
-pub fn decrease_account_balance<D>(
-    db: &mut D,
-    address: Address,
-    amount_wei: U256,
-) -> anyhow::Result<()>
-where
-    D: Database + DatabaseCommit,
-    <D as Database>::Error: Debug,
-{
-    // Read account from database
-    let mut account: Account = db
-        .basic(address)
-        .map_err(|db_err| {
-            anyhow!(
-                "Error decreasing account balance for {}: {:?}",
-                address,
-                db_err
-            )
-        })?
-        .unwrap_or_default()
-        .into();
-    // Credit withdrawal amount
-    account.info.balance = account.info.balance.checked_sub(amount_wei).unwrap();
-    account.mark_touch();
-    // Commit changes to database
-    db.commit([(address, account)].into());
-
-    Ok(())
-}
diff --git a/lib/src/host/mod.rs b/lib/src/host/mod.rs
index e8731b962..e4e02ad02 100644
--- a/lib/src/host/mod.rs
+++ b/lib/src/host/mod.rs
@@ -11,465 +11,10 @@
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 // See the License for the specific language governing permissions and
 // limitations under the License.
-use std::{
-    collections::HashSet,
-    fmt::Debug,
-    iter::{once, zip},
-};
-
-use anyhow::{Context, Result};
-use ethers_core::types::{Bytes, EIP1186ProofResponse, Transaction as EthersTransaction, H256};
-use hashbrown::HashMap;
-use log::info;
-use revm::Database;
-use zeth_primitives::{
-    block::Header,
-    ethers::{from_ethers_h160, from_ethers_h256, from_ethers_u256},
-    keccak::keccak,
-    transactions::{Transaction, TxEssence},
-    trie::{MptNode, MptNodeData, MptNodeReference, EMPTY_ROOT},
-    withdrawal::Withdrawal,
-    Address, B256, U256,
-};
-
-use crate::{
-    block_builder::{BlockBuilder, NetworkStrategyBundle},
-    consts::ChainSpec,
-    input::{Input, StorageEntry},
-    mem_db::MemDb,
-};
+extern crate std;
 
 pub mod mpt;
+pub mod preflight;
 pub mod provider;
 pub mod provider_db;
-pub mod taiko;
-
-use mpt::{orphaned_digests, resolve_digests, shorten_key};
-use provider::{new_provider, BlockQuery};
-use provider_db::ProviderDb;
-
-#[derive(Clone)]
-pub struct Init<E: TxEssence> {
-    pub db: MemDb,
-    pub init_block: Header,
-    pub init_proofs: HashMap<Address, EIP1186ProofResponse>,
-    pub fini_block: Header,
-    pub fini_transactions: Vec<Transaction<E>>,
-    pub fini_withdrawals: Vec<Withdrawal>,
-    pub fini_proofs: HashMap<Address, EIP1186ProofResponse>,
-    pub ancestor_headers: Vec<Header>,
-}
-
-pub fn get_initial_data<N: NetworkStrategyBundle>(
-    chain_spec: ChainSpec,
-    cache_path: Option<String>,
-    rpc_url: Option<String>,
-    block_no: u64,
-) -> Result<Init<N::TxEssence>>
-where
-    N::TxEssence: TryFrom<EthersTransaction>,
-    <N::TxEssence as TryFrom<EthersTransaction>>::Error: Debug,
-{
-    let mut provider = new_provider(cache_path, rpc_url)?;
-
-    // Fetch the initial block
-    let init_block = provider.get_partial_block(&BlockQuery {
-        block_no: block_no - 1,
-    })?;
-
-    info!(
-        "Initial block: {:?} ({:?})",
-        init_block.number.unwrap(),
-        init_block.hash.unwrap()
-    );
-
-    // Fetch the finished block
-    let fini_block = provider.get_full_block(&BlockQuery { block_no })?;
-
-    info!(
-        "Final block number: {:?} ({:?})",
-        fini_block.number.unwrap(),
-        fini_block.hash.unwrap()
-    );
-    info!("Transaction count: {:?}", fini_block.transactions.len());
-
-    // Create the provider DB
-    let provider_db = ProviderDb::new(provider, init_block.number.unwrap().as_u64());
-
-    // Create input
-    let input = Input {
-        beneficiary: fini_block.author.map(from_ethers_h160).unwrap_or_default(),
-        gas_limit: from_ethers_u256(fini_block.gas_limit),
-        timestamp: from_ethers_u256(fini_block.timestamp),
-        extra_data: fini_block.extra_data.0.clone().into(),
-        mix_hash: from_ethers_h256(fini_block.mix_hash.unwrap()),
-        transactions: fini_block
-            .transactions
-            .clone()
-            .into_iter()
-            .map(|tx| tx.try_into().unwrap())
-            .collect(),
-        withdrawals: fini_block
-            .withdrawals
-            .clone()
-            .unwrap_or_default()
-            .into_iter()
-            .map(|w| w.try_into().unwrap())
-            .collect(),
-        parent_state_trie: Default::default(),
-        parent_storage: Default::default(),
-        contracts: vec![],
-        parent_header: init_block.clone().try_into()?,
-        ancestor_headers: vec![],
-        base_fee_per_gas: Default::default(),
-    };
-
-    // Create the block builder, run the transactions and extract the DB
-    let mut builder = BlockBuilder::new(&chain_spec, input)
-        .with_db(provider_db)
-        .prepare_header::<N::HeaderPrepStrategy>()?
-        .execute_transactions::<N::TxExecStrategy>()?;
-    let provider_db = builder.mut_db().unwrap();
-
-    info!("Gathering inclusion proofs ...");
-
-    // Gather inclusion proofs for the initial and final state
-    let init_proofs = provider_db.get_initial_proofs()?;
-    let fini_proofs = provider_db.get_latest_proofs()?;
-
-    // Gather proofs for block history
-    let ancestor_headers = provider_db.get_ancestor_headers()?;
-
-    info!("Saving provider cache ...");
-
-    // Save the provider cache
-    provider_db.get_provider().save()?;
-
-    info!("Provider-backed execution is Done!");
-
-    let transactions = fini_block
-        .transactions
-        .clone()
-        .into_iter()
-        .map(|tx| tx.try_into().unwrap())
-        .collect();
-    let withdrawals = fini_block
-        .withdrawals
-        .clone()
-        .unwrap_or_default()
-        .into_iter()
-        .map(|w| w.try_into().unwrap())
-        .collect();
-
-    Ok(Init {
-        db: provider_db.get_initial_db().clone(),
-        init_block: init_block.try_into()?,
-        init_proofs,
-        fini_block: fini_block.try_into()?,
-        fini_transactions: transactions,
-        fini_withdrawals: withdrawals,
-        fini_proofs,
-        ancestor_headers,
-    })
-}
-
-#[derive(Debug)]
-pub enum VerifyError {
-    BalanceMismatch {
-        rpc_value: U256,
-        our_value: U256,
-        difference: U256,
-    },
-    NonceMismatch {
-        rpc_value: u64,
-        our_value: u64,
-    },
-    CodeHashMismatch {
-        rpc_value: B256,
-        our_value: B256,
-    },
-    StorageMismatch {
-        index: U256,
-        rpc_value: U256,
-        our_db_value: U256,
-        our_trie_value: U256,
-    },
-    StorageRootMismatch {
-        address: Address,
-        rpc_value: B256,
-        our_value: B256,
-        first_delta: Option<String>,
-        indices: usize,
-    },
-}
-
-pub fn verify_state(
-    mut fini_db: MemDb,
-    fini_proofs: HashMap<Address, EIP1186ProofResponse>,
-    mut storage_deltas: HashMap<Address, MptNode>,
-) -> Result<HashMap<Address, Vec<VerifyError>>> {
-    let mut errors = HashMap::new();
-    let fini_storage_keys = fini_db.storage_keys();
-
-    // Construct expected tries from fini proofs
-    let (nodes_by_pointer, mut storage) = proofs_to_tries(fini_proofs.values().cloned().collect());
-    storage
-        .values_mut()
-        .for_each(|(n, _)| *n = resolve_digests(n, &nodes_by_pointer));
-    storage_deltas
-        .values_mut()
-        .for_each(|n| *n = resolve_digests(n, &nodes_by_pointer));
-
-    for (address, indices) in fini_storage_keys {
-        let mut address_errors = Vec::new();
-
-        let account_proof = fini_proofs
-            .get(&address)
-            .with_context(|| format!("Proof not found: {}", address))?;
-        // for deleted accounts, use the default to compare
-        let account_info = fini_db.basic(address)?.unwrap_or_default();
-
-        // Account balance
-        {
-            let rpc_value = from_ethers_u256(account_proof.balance);
-            let our_value = account_info.balance;
-            if rpc_value != our_value {
-                let difference = rpc_value.abs_diff(our_value);
-                address_errors.push(VerifyError::BalanceMismatch {
-                    rpc_value,
-                    our_value,
-                    difference,
-                })
-            }
-        }
-
-        // Nonce
-        {
-            let rpc_value = account_proof.nonce.as_u64();
-            let our_value = account_info.nonce;
-            if rpc_value != our_value {
-                address_errors.push(VerifyError::NonceMismatch {
-                    rpc_value,
-                    our_value,
-                })
-            }
-        }
-
-        // Code hash
-        {
-            let rpc_value = from_ethers_h256(account_proof.code_hash);
-            let our_value = account_info.code_hash;
-            if rpc_value != our_value {
-                address_errors.push(VerifyError::CodeHashMismatch {
-                    rpc_value,
-                    our_value,
-                })
-            }
-        }
-
-        // Storage root
-        {
-            let storage_root_node = storage_deltas.get(&address).cloned().unwrap_or_default();
-            let our_value = storage_root_node.hash();
-            let rpc_value = from_ethers_h256(account_proof.storage_hash);
-            if rpc_value != our_value {
-                let expected = storage
-                    .get(&address)
-                    .unwrap()
-                    .0
-                    .debug_rlp::<zeth_primitives::U256>();
-                let found_pp = storage_root_node.debug_rlp::<zeth_primitives::U256>();
-                let first_delta = zip(expected, found_pp)
-                    .find(|(e, f)| e != f)
-                    .map(|(e, f)| format!("Storage trie delta!\nEXPECTED:\t{}FOUND:\t{}", e, f));
-                address_errors.push(VerifyError::StorageRootMismatch {
-                    address,
-                    rpc_value,
-                    our_value,
-                    first_delta,
-                    indices: indices.len(),
-                });
-            }
-        }
-
-        // Storage
-        {
-            let storage_trie = storage_deltas.get(&address).cloned().unwrap_or_default();
-            for index in indices {
-                let storage_index = H256::from(index.to_be_bytes());
-                let rpc_value = from_ethers_u256(
-                    account_proof
-                        .storage_proof
-                        .iter()
-                        .find(|&storage| storage_index == storage.key)
-                        .expect("Could not find storage proof")
-                        .value,
-                );
-                let our_db_value = fini_db.storage(address, index)?;
-                let trie_index = keccak(storage_index.as_bytes());
-                let our_trie_value = storage_trie.get_rlp(&trie_index)?.unwrap_or_default();
-                if rpc_value != our_db_value || our_db_value != our_trie_value {
-                    address_errors.push(VerifyError::StorageMismatch {
-                        index,
-                        rpc_value,
-                        our_db_value,
-                        our_trie_value,
-                    })
-                }
-            }
-        }
-
-        if !address_errors.is_empty() {
-            errors.insert(address, address_errors);
-        }
-    }
-
-    Ok(errors)
-}
-
-fn proofs_to_tries(
-    proofs: Vec<EIP1186ProofResponse>,
-) -> (
-    HashMap<MptNodeReference, MptNode>,
-    HashMap<Address, StorageEntry>,
-) {
-    // construct the proof tries
-    let mut nodes_by_reference = HashMap::new();
-    let mut storage = HashMap::new();
-    for proof in proofs {
-        // parse the nodes of the account proof
-        for bytes in &proof.account_proof {
-            let mpt_node = MptNode::decode(bytes).expect("Failed to decode state proof");
-            nodes_by_reference.insert(mpt_node.reference(), mpt_node);
-        }
-
-        // process the proof for each storage entry
-        let mut root_node = None;
-        for storage_proof in &proof.storage_proof {
-            // parse the nodes of the storage proof and return the root node
-            root_node = storage_proof
-                .proof
-                .iter()
-                .rev()
-                .map(|bytes| MptNode::decode(bytes).expect("Failed to decode storage proof"))
-                .inspect(|node| drop(nodes_by_reference.insert(node.reference(), node.clone())))
-                .last();
-            // the hash of the root node should match the proof's storage hash
-            assert_eq!(
-                root_node.as_ref().map_or(EMPTY_ROOT, |n| n.hash()),
-                from_ethers_h256(proof.storage_hash)
-            );
-        }
-
-        let root_node = if let Some(root_node) = root_node {
-            root_node
-        } else if proof.storage_hash.0 == EMPTY_ROOT.0 || proof.storage_hash.is_zero() {
-            MptNode::default()
-        } else {
-            // if there are no storage proofs but the root is non-empty, create a dummy
-            // as this is just the digest any tries to update this trie will fail
-            MptNodeData::Digest(from_ethers_h256(proof.storage_hash)).into()
-        };
-        // collect all storage slots with a proof
-        let slots = proof
-            .storage_proof
-            .into_iter()
-            .map(|p| zeth_primitives::U256::from_be_bytes(p.key.into()))
-            .collect();
-
-        storage.insert(from_ethers_h160(proof.address), (root_node, slots));
-    }
-    (nodes_by_reference, storage)
-}
-
-fn resolve_orphans(
-    nodes: &Vec<Bytes>,
-    orphans: &mut HashSet<MptNodeReference>,
-    nodes_by_reference: &mut HashMap<MptNodeReference, MptNode>,
-) {
-    for node in nodes {
-        let mpt_node = MptNode::decode(node).expect("Failed to decode state proof");
-        for potential_orphan in shorten_key(mpt_node) {
-            let potential_orphan_hash = potential_orphan.reference();
-            if orphans.remove(&potential_orphan_hash) {
-                nodes_by_reference.insert(potential_orphan_hash, potential_orphan);
-            }
-        }
-    }
-}
-
-impl<E: TxEssence> From<Init<E>> for Input<E> {
-    fn from(value: Init<E>) -> Input<E> {
-        // construct the proof tries
-        let (mut nodes_by_reference, mut storage) =
-            proofs_to_tries(value.init_proofs.values().cloned().collect());
-        // there should be a trie and a list of storage slots for every account
-        assert_eq!(storage.len(), value.db.accounts_len());
-
-        // collect the code from each account
-        let mut contracts = HashMap::new();
-        for account in value.db.accounts.values() {
-            let code = account.info.code.clone().unwrap();
-            if !code.is_empty() {
-                contracts.insert(code.hash_slow(), code.bytecode);
-            }
-        }
-
-        // extract the state trie
-        let state_root = value.init_block.state_root;
-        let state_trie = nodes_by_reference
-            .remove(&MptNodeReference::Digest(state_root))
-            .expect("State root node not found");
-        assert_eq!(state_root, state_trie.hash());
-
-        // identify orphaned digests, that could lead to issues when deleting nodes
-        let mut orphans = HashSet::new();
-        for root in storage.values().map(|v| &v.0).chain(once(&state_trie)) {
-            let root = resolve_digests(root, &nodes_by_reference);
-            orphans.extend(orphaned_digests(&root));
-        }
-        // resolve those orphans using the proofs of the final state
-        for fini_proof in value.fini_proofs.values() {
-            resolve_orphans(
-                &fini_proof.account_proof,
-                &mut orphans,
-                &mut nodes_by_reference,
-            );
-            for storage_proof in &fini_proof.storage_proof {
-                resolve_orphans(&storage_proof.proof, &mut orphans, &mut nodes_by_reference);
-            }
-        }
-
-        // resolve the pointers in the state root node and all storage root nodes
-        let state_trie = resolve_digests(&state_trie, &nodes_by_reference);
-        storage
-            .values_mut()
-            .for_each(|(n, _)| *n = resolve_digests(n, &nodes_by_reference));
-
-        info!(
-            "The partial state trie consists of {} nodes",
-            state_trie.size()
-        );
-        info!(
-            "The partial storage tries consist of {} nodes",
-            storage.values().map(|(n, _)| n.size()).sum::<usize>()
-        );
-
-        // Create the block builder input
-        Input {
-            parent_header: value.init_block,
-            beneficiary: value.fini_block.beneficiary,
-            gas_limit: value.fini_block.gas_limit,
-            timestamp: value.fini_block.timestamp,
-            extra_data: value.fini_block.extra_data.0.clone().into(),
-            mix_hash: value.fini_block.mix_hash,
-            transactions: value.fini_transactions,
-            withdrawals: value.fini_withdrawals,
-            parent_state_trie: state_trie,
-            parent_storage: storage.into_iter().collect(),
-            contracts: contracts.into_values().collect(),
-            ancestor_headers: value.ancestor_headers,
-            base_fee_per_gas: value.fini_block.base_fee_per_gas,
-        }
-    }
-}
+pub mod verify;
diff --git a/lib/src/host/mpt.rs b/lib/src/host/mpt.rs
index 90ff6b44f..d51c6d57f 100644
--- a/lib/src/host/mpt.rs
+++ b/lib/src/host/mpt.rs
@@ -12,87 +12,123 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+use anyhow::{bail, Context, Result};
 use hashbrown::HashMap;
 use zeth_primitives::trie::{to_encoded_path, MptNode, MptNodeData, MptNodeReference};
 
+/// Parses proof bytes into a vector of MPT nodes.
+pub fn parse_proof(proof: &[impl AsRef<[u8]>]) -> Result<Vec<MptNode>> {
+    Ok(proof
+        .iter()
+        .map(MptNode::decode)
+        .collect::<Result<Vec<_>, _>>()?)
+}
+
+/// Creates a Merkle Patricia trie from an EIP-1186 proof.
+/// For inclusion proofs the returned trie contains exactly one leaf with the value.
+pub fn mpt_from_proof(proof_nodes: &[MptNode]) -> Result<MptNode> {
+    let mut next: Option<MptNode> = None;
+    for (i, node) in proof_nodes.iter().enumerate().rev() {
+        // there is nothing to replace for the last node
+        let Some(replacement) = next else {
+            next = Some(node.clone());
+            continue;
+        };
+
+        // the next node must have a digest reference
+        let MptNodeReference::Digest(ref child_ref) = replacement.reference() else {
+            bail!("node {} in proof is not referenced by hash", i + 1);
+        };
+        // find the child that references the next node
+        let resolved: MptNode = match node.as_data().clone() {
+            MptNodeData::Branch(mut children) => {
+                if let Some(child) = children.iter_mut().flatten().find(
+                    |child| matches!(child.as_data(), MptNodeData::Digest(d) if d == child_ref),
+                ) {
+                    *child = Box::new(replacement);
+                } else {
+                    bail!("node {i} does not reference the successor");
+                }
+                MptNodeData::Branch(children).into()
+            }
+            MptNodeData::Extension(prefix, child) => {
+                if !matches!(child.as_data(), MptNodeData::Digest(d) if d == child_ref) {
+                    bail!("node {i} does not reference the successor");
+                }
+                MptNodeData::Extension(prefix, Box::new(replacement)).into()
+            }
+            MptNodeData::Null | MptNodeData::Leaf(_, _) | MptNodeData::Digest(_) => {
+                bail!("node {i} has no children to replace");
+            }
+        };
+
+        next = Some(resolved);
+    }
+
+    // the last node in the proof should be the root
+    Ok(next.unwrap_or_default())
+}
+
+/// Verifies that the given proof is a valid proof of exclusion for the given key.
+pub fn is_not_included(key: &[u8], proof_nodes: &[MptNode]) -> Result<bool> {
+    let proof_trie = mpt_from_proof(proof_nodes).context("invalid trie")?;
+    // for valid proofs, the get must not fail
+    let value = proof_trie.get(key)/* .context("invalid trie") */?;
+
+    Ok(value.is_none())
+}
+
 /// Creates a new MPT trie where all the digests contained in `node_store` are resolved.
-pub fn resolve_digests(trie: &MptNode, node_store: &HashMap<MptNodeReference, MptNode>) -> MptNode {
-    let result: MptNode = match trie.as_data() {
-        MptNodeData::Null | MptNodeData::Leaf(_, _) => trie.clone(),
+pub fn resolve_nodes(root: &MptNode, node_store: &HashMap<MptNodeReference, MptNode>) -> MptNode {
+    let trie = match root.as_data() {
+        MptNodeData::Null | MptNodeData::Leaf(_, _) => root.clone(),
         MptNodeData::Branch(children) => {
             let children: Vec<_> = children
                 .iter()
                 .map(|child| {
                     child
                         .as_ref()
-                        .map(|node| Box::new(resolve_digests(node, node_store)))
+                        .map(|node| Box::new(resolve_nodes(node, node_store)))
                 })
                 .collect();
             MptNodeData::Branch(children.try_into().unwrap()).into()
         }
-        MptNodeData::Extension(prefix, target) => MptNodeData::Extension(
-            prefix.clone(),
-            Box::new(resolve_digests(target, node_store)),
-        )
-        .into(),
+        MptNodeData::Extension(prefix, target) => {
+            MptNodeData::Extension(prefix.clone(), Box::new(resolve_nodes(target, node_store)))
+                .into()
+        }
         MptNodeData::Digest(digest) => {
             if let Some(node) = node_store.get(&MptNodeReference::Digest(*digest)) {
-                resolve_digests(node, node_store)
+                resolve_nodes(node, node_store)
             } else {
-                trie.clone()
+                root.clone()
             }
         }
     };
-    assert_eq!(trie.hash(), result.hash());
-    result
-}
+    // the root hash must not change
+    debug_assert_eq!(root.hash(), trie.hash());
 
-/// Returns all orphaned digests in the trie.
-pub fn orphaned_digests(trie: &MptNode) -> Vec<MptNodeReference> {
-    let mut result = Vec::new();
-    orphaned_digests_internal(trie, &mut result);
-    result
+    trie
 }
 
-fn orphaned_digests_internal(trie: &MptNode, orphans: &mut Vec<MptNodeReference>) {
-    match trie.as_data() {
-        MptNodeData::Branch(children) => {
-            // iterate over all digest children
-            let mut digests = children.iter().flatten().filter(|node| node.is_digest());
-            // if there is exactly one digest child, it is an orphan
-            if let Some(orphan_digest) = digests.next() {
-                if digests.next().is_none() {
-                    orphans.push(orphan_digest.reference());
-                }
-            };
-            // recurse
-            children.iter().flatten().for_each(|child| {
-                orphaned_digests_internal(child, orphans);
-            });
-        }
-        MptNodeData::Extension(_, target) => {
-            orphaned_digests_internal(target, orphans);
-        }
-        MptNodeData::Null | MptNodeData::Leaf(_, _) | MptNodeData::Digest(_) => {}
-    }
-}
-
-pub fn shorten_key(node: MptNode) -> Vec<MptNode> {
+/// Returns a list of all possible nodes that can be created by shortening the path of the
+/// given node.
+/// When nodes in an MPT are deleted, leaves or extensions may be extended. To still be
+/// able to identify the original nodes, we create all shortened versions of the node.
+pub fn shorten_node_path(node: &MptNode) -> Vec<MptNode> {
     let mut res = Vec::new();
     let nibs = node.nibs();
     match node.as_data() {
-        MptNodeData::Null | MptNodeData::Branch(_) | MptNodeData::Digest(_) => {
-            res.push(node.clone())
-        }
+        MptNodeData::Null | MptNodeData::Branch(_) | MptNodeData::Digest(_) => {}
         MptNodeData::Leaf(_, value) => {
             for i in 0..=nibs.len() {
                 res.push(MptNodeData::Leaf(to_encoded_path(&nibs[i..], true), value.clone()).into())
             }
         }
-        MptNodeData::Extension(_, target) => {
+        MptNodeData::Extension(_, child) => {
             for i in 0..=nibs.len() {
                 res.push(
-                    MptNodeData::Extension(to_encoded_path(&nibs[i..], false), target.clone())
+                    MptNodeData::Extension(to_encoded_path(&nibs[i..], false), child.clone())
                         .into(),
                 )
             }
diff --git a/lib/src/host/preflight.rs b/lib/src/host/preflight.rs
new file mode 100644
index 000000000..0a7315cec
--- /dev/null
+++ b/lib/src/host/preflight.rs
@@ -0,0 +1,355 @@
+// Copyright 2023 RISC Zero, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use std::{fmt::Debug, path::PathBuf};
+
+use anyhow::{anyhow, Context, Result};
+use ethers_core::types::{
+    Block as EthersBlock, EIP1186ProofResponse, Transaction as EthersTransaction,
+};
+use hashbrown::{HashMap, HashSet};
+use log::info;
+use zeth_primitives::{
+    block::Header,
+    ethers::{from_ethers_h160, from_ethers_h256, from_ethers_u256},
+    keccak::keccak,
+    transactions::{Transaction, TxEssence},
+    trie::{MptNode, MptNodeData, MptNodeReference, EMPTY_ROOT},
+    withdrawal::Withdrawal,
+    Address, B256, U256,
+    
+};
+use crate::{
+    builder::{BlockBuilder, BlockBuilderStrategy}, 
+    consts::ChainSpec, 
+    host::{mpt::{is_not_included, mpt_from_proof, parse_proof, resolve_nodes, shorten_node_path}, provider::{new_provider, BlockQuery}, provider_db::ProviderDb}, 
+    input::{Input, StorageEntry}, mem_db::MemDb
+};
+
+/// The initial data required to build a block as returned by the [Preflight].
+#[derive(Debug, Clone)]
+pub struct Data<E: TxEssence> {
+    pub db: MemDb,
+    pub parent_header: Header,
+    pub parent_proofs: HashMap<Address, EIP1186ProofResponse>,
+    pub header: Header,
+    pub transactions: Vec<Transaction<E>>,
+    pub withdrawals: Vec<Withdrawal>,
+    pub proofs: HashMap<Address, EIP1186ProofResponse>,
+    pub ancestor_headers: Vec<Header>,
+}
+
+pub trait Preflight<E: TxEssence> {
+    /// Executes the complete block using the input and state from the RPC provider.
+    /// It returns all the data required to build and validate the block.
+    fn run_preflight(
+        chain_spec: ChainSpec,
+        cache_path: Option<PathBuf>,
+        rpc_url: Option<String>,
+        block_no: u64,
+    ) -> Result<Data<E>>;
+}
+
+#[cfg(not(feature = "taiko"))]
+/// Implements the [Preflight] trait for all compatible [BlockBuilderStrategy]s.
+impl<N: BlockBuilderStrategy> Preflight<N::TxEssence> for N
+where
+    N::TxEssence: TryFrom<EthersTransaction>,
+    <N::TxEssence as TryFrom<EthersTransaction>>::Error: Debug,
+{
+    fn run_preflight(
+        chain_spec: ChainSpec,
+        cache_path: Option<PathBuf>,
+        rpc_url: Option<String>,
+        block_no: u64,
+    ) -> Result<Data<N::TxEssence>> {
+        let mut provider = new_provider(cache_path, rpc_url)?;
+
+        // Fetch the parent block
+        let parent_block = provider.get_partial_block(&BlockQuery {
+            block_no: block_no - 1,
+        })?;
+
+        info!(
+            "Initial block: {:?} ({:?})",
+            parent_block.number.unwrap(),
+            parent_block.hash.unwrap()
+        );
+        let parent_header: Header = parent_block.try_into().context("invalid parent block")?;
+
+        // Fetch the target block
+        let block = provider.get_full_block(&BlockQuery { block_no })?;
+
+        info!(
+            "Final block number: {:?} ({:?})",
+            block.number.unwrap(),
+            block.hash.unwrap()
+        );
+        info!("Transaction count: {:?}", block.transactions.len());
+
+        // Create the provider DB
+        let provider_db = ProviderDb::new(provider, parent_header.number);
+
+        // Create the input data
+        let input = new_preflight_input(block.clone(), parent_header.clone())?;
+        let transactions = input.transactions.clone();
+        let withdrawals = input.withdrawals.clone();
+
+        // Create the block builder, run the transactions and extract the DB
+        let mut builder = BlockBuilder::new(&chain_spec, input)
+            .with_db(provider_db)
+            .prepare_header::<N::HeaderPrepStrategy>()?
+            .execute_transactions::<N::TxExecStrategy>()?;
+        let provider_db = builder.mut_db().unwrap();
+
+        info!("Gathering inclusion proofs ...");
+
+        // Gather inclusion proofs for the initial and final state
+        let parent_proofs = provider_db.get_initial_proofs()?;
+        let proofs = provider_db.get_latest_proofs()?;
+
+        // Gather proofs for block history
+        let ancestor_headers = provider_db.get_ancestor_headers()?;
+
+        info!("Saving provider cache ...");
+
+        // Save the provider cache
+        provider_db.get_provider().save()?;
+
+        info!("Provider-backed execution is Done!");
+
+        Ok(Data {
+            db: provider_db.get_initial_db().clone(),
+            parent_header,
+            parent_proofs,
+            header: block.try_into().context("invalid block")?,
+            transactions,
+            withdrawals,
+            proofs,
+            ancestor_headers,
+        })
+    }
+}
+
+///
+pub fn new_preflight_input<E>(
+    block: EthersBlock<EthersTransaction>,
+    parent_header: Header,
+) -> Result<Input<E>>
+where
+    E: TxEssence + TryFrom<EthersTransaction>,
+    <E as TryFrom<EthersTransaction>>::Error: Debug,
+{
+    // convert each transaction
+    let transactions = block
+        .transactions
+        .into_iter()
+        .enumerate()
+        .map(|(i, tx)| {
+            tx.try_into()
+                .map_err(|err| anyhow!("transaction {i} invalid: {err:?}"))
+        })
+        .collect::<Result<Vec<_>, _>>()?;
+    // convert each withdrawal
+    let withdrawals = block
+        .withdrawals
+        .unwrap_or_default()
+        .into_iter()
+        .enumerate()
+        .map(|(i, tx)| {
+            tx.try_into()
+                .with_context(|| format!("withdrawal {i} invalid"))
+        })
+        .collect::<Result<Vec<_>, _>>()?;
+
+    let input = Input {
+        beneficiary: from_ethers_h160(block.author.context("author missing")?),
+        gas_limit: from_ethers_u256(block.gas_limit),
+        timestamp: from_ethers_u256(block.timestamp),
+        extra_data: block.extra_data.0.into(),
+        mix_hash: from_ethers_h256(block.mix_hash.context("mix_hash missing")?),
+        transactions,
+        withdrawals,
+        parent_state_trie: Default::default(),
+        parent_storage: Default::default(),
+        contracts: Default::default(),
+        parent_header,
+        ancestor_headers: Default::default(),
+        base_fee_per_gas: from_ethers_u256(
+            block.base_fee_per_gas.context("base_fee_per_gas missing")?,
+        ),
+    };
+    Ok(input)
+}
+
+/// Converts the [Data] returned by the [Preflight] into [Input] required by the
+/// [BlockBuilder].
+impl<E: TxEssence> TryFrom<Data<E>> for Input<E> {
+    type Error = anyhow::Error;
+
+    fn try_from(data: Data<E>) -> Result<Input<E>> {
+        // collect the code from each account
+        let mut contracts = HashSet::new();
+        for account in data.db.accounts.values() {
+            let code = account.info.code.clone().context("missing code")?;
+            if !code.is_empty() {
+                contracts.insert(code.bytecode);
+            }
+        }
+
+        // construct the sparse MPTs from the inclusion proofs
+        let (state_trie, storage) = proofs_to_tries(
+            data.parent_header.state_root,
+            data.parent_proofs,
+            data.proofs,
+        )?;
+
+        info!(
+            "The partial state trie consists of {} nodes",
+            state_trie.size()
+        );
+        info!(
+            "The partial storage tries consist of {} nodes",
+            storage.values().map(|(n, _)| n.size()).sum::<usize>()
+        );
+
+        // Create the block builder input
+        let input = Input {
+            parent_header: data.parent_header,
+            beneficiary: data.header.beneficiary,
+            gas_limit: data.header.gas_limit,
+            timestamp: data.header.timestamp,
+            extra_data: data.header.extra_data.0.clone().into(),
+            mix_hash: data.header.mix_hash,
+            transactions: data.transactions,
+            withdrawals: data.withdrawals,
+            parent_state_trie: state_trie,
+            parent_storage: storage,
+            contracts: contracts.into_iter().collect(),
+            ancestor_headers: data.ancestor_headers,
+            base_fee_per_gas: data.header.base_fee_per_gas,
+        };
+        Ok(input)
+    }
+}
+
+fn proofs_to_tries(
+    state_root: B256,
+    parent_proofs: HashMap<Address, EIP1186ProofResponse>,
+    proofs: HashMap<Address, EIP1186ProofResponse>,
+) -> Result<(MptNode, HashMap<Address, StorageEntry>)> {
+    // if no addresses are provided, return the trie only consisting of the state root
+    if parent_proofs.is_empty() {
+        return Ok((node_from_digest(state_root), HashMap::new()));
+    }
+
+    let mut storage: HashMap<Address, StorageEntry> = HashMap::with_capacity(parent_proofs.len());
+
+    let mut state_nodes = HashMap::new();
+    let mut state_root_node = MptNode::default();
+    for (address, proof) in parent_proofs {
+        let proof_nodes =
+            parse_proof(&proof.account_proof).context("invalid account_proof encoding")?;
+        mpt_from_proof(&proof_nodes).context("invalid account_proof")?;
+
+        // the first node in the proof is the root
+        if let Some(node) = proof_nodes.first() {
+            state_root_node = node.clone();
+        }
+
+        proof_nodes.into_iter().for_each(|node| {
+            state_nodes.insert(node.reference(), node);
+        });
+
+        let fini_proofs = proofs
+            .get(&address)
+            .with_context(|| format!("missing fini_proofs for address {address:#}"))?;
+
+        // assure that addresses can be deleted from the state trie
+        add_orphaned_leafs(address, &fini_proofs.account_proof, &mut state_nodes)?;
+
+        // if no slots are provided, return the trie only consisting of the storage root
+        let storage_root = from_ethers_h256(proof.storage_hash);
+        if proof.storage_proof.is_empty() {
+            let storage_root_node = node_from_digest(storage_root);
+            storage.insert(address, (storage_root_node, vec![]));
+            continue;
+        }
+
+        let mut storage_nodes = HashMap::new();
+        let mut storage_root_node = MptNode::default();
+        for storage_proof in &proof.storage_proof {
+            let proof_nodes =
+                parse_proof(&storage_proof.proof).context("invalid storage_proof encoding")?;
+            mpt_from_proof(&proof_nodes).context("invalid storage_proof")?;
+
+            // the first node in the proof is the root
+            if let Some(node) = proof_nodes.first() {
+                storage_root_node = node.clone();
+            }
+
+            proof_nodes.into_iter().for_each(|node| {
+                storage_nodes.insert(node.reference(), node);
+            });
+        }
+
+        // assure that slots can be deleted from the storage trie
+        for storage_proof in &fini_proofs.storage_proof {
+            add_orphaned_leafs(storage_proof.key, &storage_proof.proof, &mut storage_nodes)?;
+        }
+        // create the storage trie, from all the relevant nodes
+        let storage_trie = resolve_nodes(&storage_root_node, &storage_nodes);
+        assert_eq!(storage_trie.hash(), storage_root);
+
+        // convert the slots to a vector of U256
+        let slots = proof
+            .storage_proof
+            .iter()
+            .map(|p| U256::from_be_bytes(p.key.into()))
+            .collect();
+        storage.insert(address, (storage_trie, slots));
+    }
+    let state_trie = resolve_nodes(&state_root_node, &state_nodes);
+    assert_eq!(state_trie.hash(), state_root);
+
+    Ok((state_trie, storage))
+}
+
+/// Adds all the leaf nodes of non-inclusion proofs to the nodes.
+fn add_orphaned_leafs(
+    key: impl AsRef<[u8]>,
+    proof: &[impl AsRef<[u8]>],
+    nodes_by_reference: &mut HashMap<MptNodeReference, MptNode>,
+) -> Result<()> {
+    if !proof.is_empty() {
+        let proof_nodes = parse_proof(proof).context("invalid proof encoding")?;
+        if is_not_included(&keccak(key), &proof_nodes)? {
+            // add the leaf node to the nodes
+            let leaf = proof_nodes.last().expect("No leaf node");
+            shorten_node_path(leaf).into_iter().for_each(|node| {
+                nodes_by_reference.insert(node.reference(), node);
+            });
+        }
+    }
+
+    Ok(())
+}
+
+/// Creates a new MPT node from a digest.
+fn node_from_digest(digest: B256) -> MptNode {
+    match digest {
+        EMPTY_ROOT | B256::ZERO => MptNode::default(),
+        _ => MptNodeData::Digest(digest).into(),
+    }
+}
diff --git a/lib/src/host/provider/cached_rpc_provider.rs b/lib/src/host/provider/cached_rpc_provider.rs
index 8a8871183..ba9f04e82 100644
--- a/lib/src/host/provider/cached_rpc_provider.rs
+++ b/lib/src/host/provider/cached_rpc_provider.rs
@@ -12,15 +12,21 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+use std::path::PathBuf;
+
 use anyhow::Result;
-use ethers_core::types::{Block, Bytes, EIP1186ProofResponse, Transaction, H256, U256};
 #[cfg(feature = "taiko")]
-use zeth_primitives::taiko::BlockProposed;
+use ethers_core::types::Log;
+use ethers_core::types::{
+    Block, Bytes, EIP1186ProofResponse, Transaction, TransactionReceipt, H256, U256,
+};
 
 use super::{
     file_provider::FileProvider, rpc_provider::RpcProvider, AccountQuery, BlockQuery, MutProvider,
     ProofQuery, Provider, StorageQuery,
 };
+#[cfg(feature = "taiko")]
+use crate::host::provider::LogsQuery;
 
 pub struct CachedRpcProvider {
     cache: FileProvider,
@@ -28,8 +34,8 @@ pub struct CachedRpcProvider {
 }
 
 impl CachedRpcProvider {
-    pub fn new(cache_path: String, rpc_url: String) -> Result<Self> {
-        let cache = match FileProvider::read_from_file(cache_path.clone()) {
+    pub fn new(cache_path: PathBuf, rpc_url: String) -> Result<Self> {
+        let cache = match FileProvider::from_file(&cache_path) {
             Ok(provider) => provider,
             Err(_) => FileProvider::empty(cache_path),
         };
@@ -68,6 +74,18 @@ impl Provider for CachedRpcProvider {
         Ok(out)
     }
 
+    fn get_block_receipts(&mut self, query: &BlockQuery) -> Result<Vec<TransactionReceipt>> {
+        let cache_out = self.cache.get_block_receipts(query);
+        if cache_out.is_ok() {
+            return cache_out;
+        }
+
+        let out = self.rpc.get_block_receipts(query)?;
+        self.cache.insert_block_receipts(query.clone(), out.clone());
+
+        Ok(out)
+    }
+
     fn get_proof(&mut self, query: &ProofQuery) -> Result<EIP1186ProofResponse> {
         let cache_out = self.cache.get_proof(query);
         if cache_out.is_ok() {
@@ -129,34 +147,39 @@ impl Provider for CachedRpcProvider {
     }
 
     #[cfg(feature = "taiko")]
-    fn get_propose(&mut self, query: &super::ProposeQuery) -> Result<(Transaction, BlockProposed)> {
-        let cache_out = self.cache.get_propose(query);
+    fn get_logs(&mut self, query: &LogsQuery) -> Result<Vec<Log>> {
+        let cache_out = self.cache.get_logs(query);
         if cache_out.is_ok() {
             return cache_out;
         }
 
-        let out = self.rpc.get_propose(query)?;
-        self.cache.insert_propose(query.clone(), out.clone());
+        let out = self.rpc.get_logs(query)?;
+        self.cache.insert_logs(query.clone(), out.clone());
 
         Ok(out)
     }
 
     #[cfg(feature = "taiko")]
-    fn batch_get_partial_blocks(&mut self, query: &BlockQuery) -> Result<Vec<Block<H256>>> {
-        let cache_out = self.cache.batch_get_partial_blocks(query);
+    fn get_transaction(&mut self, query: &super::TxQuery) -> Result<Transaction> {
+        let cache_out = self.cache.get_transaction(query);
         if cache_out.is_ok() {
             return cache_out;
         }
 
-        let out = self.rpc.batch_get_partial_blocks(query)?;
-        for block in out.iter() {
-            self.cache.insert_partial_block(
-                BlockQuery {
-                    block_no: block.number.unwrap().as_u64(),
-                },
-                block.clone(),
-            );
+        // Search cached block for target Tx
+        if let Some(block_no) = query.block_no {
+            if let Ok(block) = self.cache.get_full_block(&BlockQuery { block_no }) {
+                for tx in block.transactions {
+                    if tx.hash == query.tx_hash {
+                        return Ok(tx.clone());
+                    }
+                }
+            }
         }
+
+        let out = self.rpc.get_transaction(query)?;
+        self.cache.insert_transaction(query.clone(), out.clone());
+
         Ok(out)
     }
 }
diff --git a/lib/src/host/provider/file_provider.rs b/lib/src/host/provider/file_provider.rs
index df1ea9fc5..568012610 100644
--- a/lib/src/host/provider/file_provider.rs
+++ b/lib/src/host/provider/file_provider.rs
@@ -14,32 +14,39 @@
 
 use alloc::vec::Vec;
 use std::{
-    collections::{BTreeMap, HashMap},
+    collections::HashMap,
     fs::File,
     io::{Read, Write},
     path::{Path, PathBuf},
 };
 
 use anyhow::{anyhow, Result};
-use ethers_core::types::{Block, Bytes, EIP1186ProofResponse, Transaction, H256, U256};
+use ethers_core::types::{
+    Block, Bytes, EIP1186ProofResponse, Log, Transaction, TransactionReceipt, H256, U256,
+};
 use serde::{Deserialize, Serialize};
 use serde_with::serde_as;
-#[cfg(feature = "taiko")]
-use zeth_primitives::taiko::BlockProposed;
 
+// #[cfg(feature = "taiko")]
+// use zeth_primitives::taiko::BlockProposed;
 use super::{AccountQuery, BlockQuery, MutProvider, ProofQuery, Provider, StorageQuery};
+#[cfg(feature = "taiko")]
+use super::{LogsQuery, TxQuery};
 
 #[serde_as]
-#[derive(Deserialize, Serialize)]
+#[derive(Default, Deserialize, Serialize)]
 pub struct FileProvider {
     #[serde(skip)]
-    file_path: String,
+    file_path: PathBuf,
     #[serde(skip)]
     dirty: bool,
     #[serde_as(as = "Vec<(_, _)>")]
     full_blocks: HashMap<BlockQuery, Block<Transaction>>,
     #[serde_as(as = "Vec<(_, _)>")]
-    partial_blocks: BTreeMap<BlockQuery, Block<H256>>,
+    partial_blocks: HashMap<BlockQuery, Block<H256>>,
+    #[serde(default)]
+    #[serde_as(as = "Vec<(_, _)>")]
+    receipts: HashMap<BlockQuery, Vec<TransactionReceipt>>,
     #[serde_as(as = "Vec<(_, _)>")]
     proofs: HashMap<ProofQuery, EIP1186ProofResponse>,
     #[serde_as(as = "Vec<(_, _)>")]
@@ -50,40 +57,48 @@ pub struct FileProvider {
     code: HashMap<AccountQuery, Bytes>,
     #[serde_as(as = "Vec<(_, _)>")]
     storage: HashMap<StorageQuery, H256>,
+
     #[cfg(feature = "taiko")]
-    propose: Option<(Transaction, BlockProposed)>,
+    #[serde_as(as = "Vec<(_, _)>")]
+    logs: HashMap<LogsQuery, Vec<Log>>,
+    #[cfg(feature = "taiko")]
+    #[serde_as(as = "Vec<(_, _)>")]
+    transactions: HashMap<TxQuery, Transaction>,
 }
 
 impl FileProvider {
-    pub fn empty(file_path: String) -> Self {
+    pub fn empty(file_path: PathBuf) -> Self {
         FileProvider {
             file_path,
             dirty: false,
             full_blocks: HashMap::new(),
-            partial_blocks: BTreeMap::new(),
+            partial_blocks: HashMap::new(),
+            receipts: HashMap::new(),
             proofs: HashMap::new(),
             transaction_count: HashMap::new(),
             balance: HashMap::new(),
             code: HashMap::new(),
             storage: HashMap::new(),
             #[cfg(feature = "taiko")]
-            propose: Default::default(),
+            logs: HashMap::new(),
+            #[cfg(feature = "taiko")]
+            transactions: HashMap::new(),
         }
     }
 
-    pub fn read_from_file(file_path: String) -> Result<Self> {
+    pub fn from_file(file_path: &PathBuf) -> Result<Self> {
         let mut buf = vec![];
-        let mut decoder = flate2::read::GzDecoder::new(File::open(&file_path)?);
+        let mut decoder = flate2::read::GzDecoder::new(File::open(file_path)?);
         decoder.read_to_end(&mut buf)?;
 
         let mut out: Self = serde_json::from_slice(&buf[..])?;
 
-        out.file_path = file_path;
+        out.file_path = file_path.clone();
         out.dirty = false;
         Ok(out)
     }
 
-    pub fn save_to_file(&self, file_path: &String) -> Result<()> {
+    pub fn save_to_file(&self, file_path: &Path) -> Result<()> {
         if self.dirty {
             let mut encoder = flate2::write::GzEncoder::new(
                 File::create(file_path)?,
@@ -105,66 +120,72 @@ impl Provider for FileProvider {
     fn get_full_block(&mut self, query: &BlockQuery) -> Result<Block<Transaction>> {
         match self.full_blocks.get(query) {
             Some(val) => Ok(val.clone()),
-            None => Err(anyhow!("No data for {:?}", query)),
+            None => Err(anyhow!("No data for {query:?}")),
         }
     }
 
     fn get_partial_block(&mut self, query: &BlockQuery) -> Result<Block<H256>> {
         match self.partial_blocks.get(query) {
             Some(val) => Ok(val.clone()),
-            None => Err(anyhow!("No data for {:?}", query)),
+            None => Err(anyhow!("No data for {query:?}")),
+        }
+    }
+
+    fn get_block_receipts(&mut self, query: &BlockQuery) -> Result<Vec<TransactionReceipt>> {
+        match self.receipts.get(query) {
+            Some(val) => Ok(val.clone()),
+            None => Err(anyhow!("No data for {query:?}")),
         }
     }
 
     fn get_proof(&mut self, query: &ProofQuery) -> Result<EIP1186ProofResponse> {
         match self.proofs.get(query) {
             Some(val) => Ok(val.clone()),
-            None => Err(anyhow!("No data for {:?}", query)),
+            None => Err(anyhow!("No data for {query:?}")),
         }
     }
 
     fn get_transaction_count(&mut self, query: &AccountQuery) -> Result<U256> {
         match self.transaction_count.get(query) {
             Some(val) => Ok(*val),
-            None => Err(anyhow!("No data for {:?}", query)),
+            None => Err(anyhow!("No data for {query:?}")),
         }
     }
 
     fn get_balance(&mut self, query: &AccountQuery) -> Result<U256> {
         match self.balance.get(query) {
             Some(val) => Ok(*val),
-            None => Err(anyhow!("No data for {:?}", query)),
+            None => Err(anyhow!("No data for {query:?}")),
         }
     }
 
     fn get_code(&mut self, query: &AccountQuery) -> Result<Bytes> {
         match self.code.get(query) {
             Some(val) => Ok(val.clone()),
-            None => Err(anyhow!("No data for {:?}", query)),
+            None => Err(anyhow!("No data for {query:?}")),
         }
     }
 
     fn get_storage(&mut self, query: &StorageQuery) -> Result<H256> {
         match self.storage.get(query) {
             Some(val) => Ok(*val),
-            None => Err(anyhow!("No data for {:?}", query)),
+            None => Err(anyhow!("No data for {query:?}")),
         }
     }
 
     #[cfg(feature = "taiko")]
-    fn get_propose(&mut self, query: &super::ProposeQuery) -> Result<(Transaction, BlockProposed)> {
-        match self.propose {
-            Some(ref val) => Ok(val.clone()),
-            None => Err(anyhow!("No data for {:?}", query)),
+    fn get_logs(&mut self, query: &LogsQuery) -> Result<Vec<Log>> {
+        match self.logs.get(query) {
+            Some(val) => Ok(val.clone()),
+            None => Err(anyhow!("No data for {query:?}")),
         }
     }
 
     #[cfg(feature = "taiko")]
-    fn batch_get_partial_blocks(&mut self, _: &BlockQuery) -> Result<Vec<Block<H256>>> {
-        if self.partial_blocks.is_empty() {
-            Err(anyhow!("No data for partial blocks"))
-        } else {
-            Ok(self.partial_blocks.values().cloned().collect())
+    fn get_transaction(&mut self, query: &TxQuery) -> Result<Transaction> {
+        match self.transactions.get(query) {
+            Some(val) => Ok(val.clone()),
+            None => Err(anyhow!("No data for {query:?}")),
         }
     }
 }
@@ -180,6 +201,11 @@ impl MutProvider for FileProvider {
         self.dirty = true;
     }
 
+    fn insert_block_receipts(&mut self, query: BlockQuery, val: Vec<TransactionReceipt>) {
+        self.receipts.insert(query, val);
+        self.dirty = true;
+    }
+
     fn insert_proof(&mut self, query: ProofQuery, val: EIP1186ProofResponse) {
         self.proofs.insert(query, val);
         self.dirty = true;
@@ -206,8 +232,14 @@ impl MutProvider for FileProvider {
     }
 
     #[cfg(feature = "taiko")]
-    fn insert_propose(&mut self, _query: super::ProposeQuery, val: (Transaction, BlockProposed)) {
-        self.propose = Some(val);
+    fn insert_logs(&mut self, query: LogsQuery, val: Vec<Log>) {
+        self.logs.insert(query, val);
+        self.dirty = true;
+    }
+
+    #[cfg(feature = "taiko")]
+    fn insert_transaction(&mut self, query: super::TxQuery, val: Transaction) {
+        self.transactions.insert(query, val);
         self.dirty = true;
     }
 }
@@ -215,7 +247,7 @@ impl MutProvider for FileProvider {
 #[cfg(feature = "taiko")]
 pub fn cache_file_path(cache_path: &Path, block_no: u64, is_l1: bool) -> PathBuf {
     let prefix = if is_l1 { "l1" } else { "l2" };
-    let file_name = format!("{}.{}.json.gz", block_no, prefix);
+    let file_name = format!("{block_no}.{prefix}.json.gz");
     cache_path.join(file_name)
 }
 
diff --git a/lib/src/host/provider/mod.rs b/lib/src/host/provider/mod.rs
index 0ffe659f0..ac1307d79 100644
--- a/lib/src/host/provider/mod.rs
+++ b/lib/src/host/provider/mod.rs
@@ -11,14 +11,18 @@
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 // See the License for the specific language governing permissions and
 // limitations under the License.
-
-use std::collections::BTreeSet;
-
-use anyhow::{anyhow, Result};
-use ethers_core::types::{Block, Bytes, EIP1186ProofResponse, Transaction, H160, H256, U256};
+use std::{collections::BTreeSet, path::PathBuf};
+
+use alloy_primitives::Address;
+use alloy_sol_types::SolEvent;
+use anyhow::{anyhow, Context, Result};
+use ethers_core::types::{
+    Block, Bytes, EIP1186ProofResponse, Log, Transaction, TransactionReceipt, H160, H256, U256,
+};
 use serde::{Deserialize, Serialize};
+
 #[cfg(feature = "taiko")]
-use zeth_primitives::taiko::BlockProposed;
+use crate::taiko::BlockProposed;
 
 pub mod cached_rpc_provider;
 pub mod file_provider;
@@ -51,10 +55,17 @@ pub struct StorageQuery {
 
 #[cfg(feature = "taiko")]
 #[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
-pub struct ProposeQuery {
-    pub l1_contract: H160,
-    pub l1_block_no: u64,
-    pub l2_block_no: u64,
+pub struct LogsQuery {
+    pub address: H160,
+    pub from_block: u64,
+    pub to_block: u64,
+}
+
+#[cfg(feature = "taiko")]
+#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
+pub struct TxQuery {
+    pub tx_hash: H256,
+    pub block_no: Option<u64>,
 }
 
 pub trait Provider: Send {
@@ -62,34 +73,36 @@ pub trait Provider: Send {
 
     fn get_full_block(&mut self, query: &BlockQuery) -> Result<Block<Transaction>>;
     fn get_partial_block(&mut self, query: &BlockQuery) -> Result<Block<H256>>;
+    fn get_block_receipts(&mut self, query: &BlockQuery) -> Result<Vec<TransactionReceipt>>;
     fn get_proof(&mut self, query: &ProofQuery) -> Result<EIP1186ProofResponse>;
     fn get_transaction_count(&mut self, query: &AccountQuery) -> Result<U256>;
     fn get_balance(&mut self, query: &AccountQuery) -> Result<U256>;
     fn get_code(&mut self, query: &AccountQuery) -> Result<Bytes>;
     fn get_storage(&mut self, query: &StorageQuery) -> Result<H256>;
-
     #[cfg(feature = "taiko")]
-    fn get_propose(&mut self, query: &ProposeQuery) -> Result<(Transaction, BlockProposed)>;
+    fn get_logs(&mut self, query: &LogsQuery) -> Result<Vec<Log>>;
     #[cfg(feature = "taiko")]
-    /// get 256 blocks one time to reduce the fetch time cost
-    fn batch_get_partial_blocks(&mut self, query: &BlockQuery) -> Result<Vec<Block<H256>>>;
+    fn get_transaction(&mut self, query: &TxQuery) -> Result<Transaction>;
 }
 
 pub trait MutProvider: Provider {
     fn insert_full_block(&mut self, query: BlockQuery, val: Block<Transaction>);
     fn insert_partial_block(&mut self, query: BlockQuery, val: Block<H256>);
+    fn insert_block_receipts(&mut self, query: BlockQuery, val: Vec<TransactionReceipt>);
     fn insert_proof(&mut self, query: ProofQuery, val: EIP1186ProofResponse);
     fn insert_transaction_count(&mut self, query: AccountQuery, val: U256);
     fn insert_balance(&mut self, query: AccountQuery, val: U256);
     fn insert_code(&mut self, query: AccountQuery, val: Bytes);
     fn insert_storage(&mut self, query: StorageQuery, val: H256);
-
     #[cfg(feature = "taiko")]
-    fn insert_propose(&mut self, query: ProposeQuery, val: (Transaction, BlockProposed));
+    fn insert_logs(&mut self, query: LogsQuery, val: Vec<Log>);
+    #[cfg(feature = "taiko")]
+    fn insert_transaction(&mut self, query: TxQuery, val: Transaction);
 }
 
-pub fn new_file_provider(file_path: String) -> Result<Box<dyn Provider>> {
-    let provider = file_provider::FileProvider::read_from_file(file_path)?;
+pub fn new_file_provider(file_path: PathBuf) -> Result<Box<dyn Provider>> {
+    let provider = file_provider::FileProvider::from_file(&file_path)
+        .with_context(|| anyhow!("invalid cache file: {}", file_path.display()))?;
 
     Ok(Box::new(provider))
 }
@@ -100,14 +113,14 @@ pub fn new_rpc_provider(rpc_url: String) -> Result<Box<dyn Provider>> {
     Ok(Box::new(provider))
 }
 
-pub fn new_cached_rpc_provider(cache_path: String, rpc_url: String) -> Result<Box<dyn Provider>> {
+pub fn new_cached_rpc_provider(cache_path: PathBuf, rpc_url: String) -> Result<Box<dyn Provider>> {
     let provider = cached_rpc_provider::CachedRpcProvider::new(cache_path, rpc_url)?;
 
     Ok(Box::new(provider))
 }
 
 pub fn new_provider(
-    cache_path: Option<String>,
+    cache_path: Option<PathBuf>,
     rpc_url: Option<String>,
 ) -> Result<Box<dyn Provider>> {
     match (cache_path, rpc_url) {
@@ -117,3 +130,81 @@ pub fn new_provider(
         (None, None) => Err(anyhow!("No cache_path or rpc_url given")),
     }
 }
+
+#[cfg(feature = "taiko")]
+impl dyn Provider {
+    pub fn filter_event_log<E: SolEvent>(
+        &mut self,
+        l1_contract: Address,
+        l1_block_no: u64,
+        _l2_block_no: u64,
+    ) -> Result<Vec<(Log, E)>> {
+        use alloy_sol_types::TopicList;
+        use zeth_primitives::ethers::from_ethers_h256;
+
+        let logs = self.get_logs(&LogsQuery {
+            address: l1_contract.into_array().into(),
+            from_block: l1_block_no,
+            to_block: l1_block_no,
+        })?;
+        let res = logs
+            .iter()
+            .filter(|log| log.topics.len() == <<E as SolEvent>::TopicList as TopicList>::COUNT)
+            .filter(|log| from_ethers_h256(log.topics[0]) == E::SIGNATURE_HASH)
+            .map(|log| {
+                let topics = log.topics.iter().map(|topic| from_ethers_h256(*topic));
+                let event = E::decode_raw_log(topics, &log.data, false)
+                    .unwrap_or_else(|_| panic!("Decode log failed for l1_block_no {l1_block_no}"));
+                (log.clone(), event)
+            })
+            .collect::<Vec<_>>();
+
+        Ok(res)
+    }
+
+    #[allow(dead_code)]
+    fn filter_block_proposal(
+        &mut self,
+        l1_contract: H160,
+        l1_block_no: u64,
+        l2_block_no: u64,
+    ) -> Result<(Transaction, BlockProposed)> {
+        use alloy_sol_types::TopicList;
+        use zeth_primitives::ethers::from_ethers_h256;
+
+        let logs = self.get_logs(&LogsQuery {
+            address: l1_contract,
+            from_block: l1_block_no,
+            to_block: l1_block_no,
+        })?;
+        let mut res = logs
+            .iter()
+            .filter(|log| {
+                log.topics.len() == <<BlockProposed as SolEvent>::TopicList as TopicList>::COUNT
+            })
+            .filter(|log| from_ethers_h256(log.topics[0]) == BlockProposed::SIGNATURE_HASH)
+            .map(|log| {
+                let topics = log.topics.iter().map(|topic| from_ethers_h256(*topic));
+                let block_proposed = BlockProposed::decode_raw_log(topics, &log.data, false)
+                    .unwrap_or_else(|_| panic!("Decode log failed for l1_block_no {l1_block_no}"));
+                (log.block_number, log.transaction_hash, block_proposed)
+            })
+            .filter(|(_block_no, _tx_hash, event)| {
+                event.blockId == revm::primitives::U256::from(l2_block_no)
+            })
+            .collect::<Vec<_>>();
+
+        let (block_no, tx_hash, event) = res
+            .pop()
+            .with_context(|| anyhow!("Cannot find BlockProposed event for {l2_block_no}"))?;
+
+        let tx = self
+            .get_transaction(&TxQuery {
+                tx_hash: tx_hash.unwrap(),
+                block_no: block_no.map(|b| b.as_u64()),
+            })
+            .with_context(|| anyhow!("Cannot find BlockProposed Tx {tx_hash:?}"))?;
+
+        Ok((tx, event))
+    }
+}
diff --git a/lib/src/host/provider/rpc_provider.rs b/lib/src/host/provider/rpc_provider.rs
index 53480beec..e2cc22724 100644
--- a/lib/src/host/provider/rpc_provider.rs
+++ b/lib/src/host/provider/rpc_provider.rs
@@ -12,25 +12,30 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-use anyhow::{anyhow, Context, Result};
+use anyhow::{anyhow, Result};
+#[cfg(feature = "taiko")]
+use ethers_core::types::Log;
 use ethers_core::types::{
-    Block, Bytes, EIP1186ProofResponse, Filter, Log, Transaction, H256, U256,
+    Block, Bytes, EIP1186ProofResponse, Filter, Transaction, TransactionReceipt, H256, U256,
 };
-use ethers_providers::{Http, Middleware};
+use ethers_providers::{Http, Middleware, RetryClient};
 use log::info;
-#[cfg(feature = "taiko")]
-use zeth_primitives::taiko::BlockProposed;
 
+// #[cfg(feature = "taiko")]
+// use zeth_primitives::taiko::BlockProposed;
 use super::{AccountQuery, BlockQuery, ProofQuery, Provider, StorageQuery};
+#[cfg(feature = "taiko")]
+use crate::host::provider::LogsQuery;
 
 pub struct RpcProvider {
-    http_client: ethers_providers::Provider<Http>,
+    http_client: ethers_providers::Provider<RetryClient<Http>>,
     tokio_handle: tokio::runtime::Handle,
 }
 
 impl RpcProvider {
     pub fn new(rpc_url: String) -> Result<Self> {
-        let http_client = ethers_providers::Provider::<Http>::try_from(&rpc_url)?;
+        let http_client =
+            ethers_providers::Provider::<RetryClient<Http>>::new_client(&rpc_url, 3, 500)?;
         let tokio_handle = tokio::runtime::Handle::current();
 
         Ok(RpcProvider {
@@ -46,7 +51,7 @@ impl Provider for RpcProvider {
     }
 
     fn get_full_block(&mut self, query: &BlockQuery) -> Result<Block<Transaction>> {
-        info!("Querying RPC for full block: {:?}", query);
+        info!("Querying RPC for full block: {query:?}");
 
         let response = self
             .tokio_handle
@@ -54,12 +59,12 @@ impl Provider for RpcProvider {
 
         match response {
             Some(out) => Ok(out),
-            None => Err(anyhow!("No data for {:?}", query)),
+            None => Err(anyhow!("No data for {query:?}")),
         }
     }
 
     fn get_partial_block(&mut self, query: &BlockQuery) -> Result<Block<H256>> {
-        info!("Querying RPC for partial block: {:?}", query);
+        info!("Querying RPC for partial block: {query:?}");
 
         let response = self
             .tokio_handle
@@ -67,12 +72,22 @@ impl Provider for RpcProvider {
 
         match response {
             Some(out) => Ok(out),
-            None => Err(anyhow!("No data for {:?}", query)),
+            None => Err(anyhow!("No data for {query:?}")),
         }
     }
 
+    fn get_block_receipts(&mut self, query: &BlockQuery) -> Result<Vec<TransactionReceipt>> {
+        info!("Querying RPC for block receipts: {query:?}");
+
+        let response = self
+            .tokio_handle
+            .block_on(async { self.http_client.get_block_receipts(query.block_no).await })?;
+
+        Ok(response)
+    }
+
     fn get_proof(&mut self, query: &ProofQuery) -> Result<EIP1186ProofResponse> {
-        info!("Querying RPC for inclusion proof: {:?}", query);
+        info!("Querying RPC for inclusion proof: {query:?}");
 
         let out = self.tokio_handle.block_on(async {
             self.http_client
@@ -88,7 +103,7 @@ impl Provider for RpcProvider {
     }
 
     fn get_transaction_count(&mut self, query: &AccountQuery) -> Result<U256> {
-        info!("Querying RPC for transaction count: {:?}", query);
+        info!("Querying RPC for transaction count: {query:?}");
 
         let out = self.tokio_handle.block_on(async {
             self.http_client
@@ -100,7 +115,7 @@ impl Provider for RpcProvider {
     }
 
     fn get_balance(&mut self, query: &AccountQuery) -> Result<U256> {
-        info!("Querying RPC for balance: {:?}", query);
+        info!("Querying RPC for balance: {query:?}");
 
         let out = self.tokio_handle.block_on(async {
             self.http_client
@@ -112,7 +127,7 @@ impl Provider for RpcProvider {
     }
 
     fn get_code(&mut self, query: &AccountQuery) -> Result<Bytes> {
-        info!("Querying RPC for code: {:?}", query);
+        info!("Querying RPC for code: {query:?}");
 
         let out = self.tokio_handle.block_on(async {
             self.http_client
@@ -124,7 +139,7 @@ impl Provider for RpcProvider {
     }
 
     fn get_storage(&mut self, query: &StorageQuery) -> Result<H256> {
-        info!("Querying RPC for storage: {:?}", query);
+        info!("Querying RPC for storage: {query:?}");
 
         let out = self.tokio_handle.block_on(async {
             self.http_client
@@ -136,70 +151,32 @@ impl Provider for RpcProvider {
     }
 
     #[cfg(feature = "taiko")]
-    fn get_propose(&mut self, query: &super::ProposeQuery) -> Result<(Transaction, BlockProposed)> {
-        use revm::primitives::U256;
-        info!("Querying RPC for propose: {:?}", query);
-        let filter = Filter::new()
-            .address(query.l1_contract)
-            .from_block(query.l1_block_no)
-            .to_block(query.l1_block_no);
-        let logs = self
-            .tokio_handle
-            .block_on(async { self.http_client.get_logs(&filter).await })?;
-        let result = taiko::filter_propose_block_event(&logs, U256::from(query.l2_block_no))?;
-        let (tx_hash, block_proposed) =
-            result.ok_or_else(|| anyhow!("No propose block event for {:?}", query))?;
-        let response = self
-            .tokio_handle
-            .block_on(async { self.http_client.get_transaction(tx_hash).await })?;
-        match response {
-            Some(out) => Ok((out, block_proposed)),
-            None => Err(anyhow!("No data for {:?}", query)),
-        }
-    }
-
-    #[cfg(feature = "taiko")]
-    /// get 256 blocks one time to reduce the fetch time cost
-    fn batch_get_partial_blocks(&mut self, query: &BlockQuery) -> Result<Vec<Block<H256>>> {
-        info!("Querying RPC for partial blocks: {:?}", query);
+    fn get_logs(&mut self, query: &LogsQuery) -> Result<Vec<Log>> {
+        info!("Querying RPC for logs: {query:?}");
 
         let out = self.tokio_handle.block_on(async {
-            use ethers_core::utils;
-            let id = utils::serialize(&query.block_no);
             self.http_client
-                .request("taiko_getL2ParentHeaders", [id])
+                .get_logs(
+                    &Filter::new()
+                        .address(query.address)
+                        .from_block(query.from_block)
+                        .to_block(query.to_block),
+                )
                 .await
         })?;
+
         Ok(out)
     }
-}
 
-#[cfg(feature = "taiko")]
-pub mod taiko {
-    use alloy_sol_types::{SolEvent, TopicList};
-    use revm::primitives::U256;
-    use zeth_primitives::{ethers::from_ethers_h256, taiko::BlockProposed};
-
-    use super::*;
-    pub fn filter_propose_block_event(
-        logs: &[Log],
-        block_id: U256,
-    ) -> Result<Option<(H256, BlockProposed)>> {
-        for log in logs {
-            if log.topics.len() != <<BlockProposed as SolEvent>::TopicList as TopicList>::COUNT {
-                continue;
-            }
-            if from_ethers_h256(log.topics[0]) != BlockProposed::SIGNATURE_HASH {
-                continue;
-            }
-            let topics = log.topics.iter().map(|topic| from_ethers_h256(*topic));
-            let block_proposed = BlockProposed::decode_log(topics, &log.data, false)
-                .map_err(|e| anyhow!(e.to_string()))
-                .with_context(|| "decode log failed")?;
-            if block_proposed.blockId == block_id {
-                return Ok(log.transaction_hash.map(|h| (h, block_proposed)));
-            }
+    #[cfg(feature = "taiko")]
+    fn get_transaction(&mut self, query: &super::TxQuery) -> Result<Transaction> {
+        info!("Querying RPC for tx: {query:?}");
+        let out = self
+            .tokio_handle
+            .block_on(async { self.http_client.get_transaction(query.tx_hash).await })?;
+        match out {
+            Some(out) => Ok(out),
+            None => Err(anyhow!("No data for {query:?}")),
         }
-        Ok(None)
     }
 }
diff --git a/lib/src/host/provider_db.rs b/lib/src/host/provider_db.rs
index bc009b3d0..083f89270 100644
--- a/lib/src/host/provider_db.rs
+++ b/lib/src/host/provider_db.rs
@@ -11,7 +11,7 @@
 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 // See the License for the specific language governing permissions and
 // limitations under the License.
-
+use alloc::vec::Vec;
 use std::collections::BTreeSet;
 
 use ethers_core::types::{EIP1186ProofResponse, H160, H256};
diff --git a/lib/src/host/taiko.rs b/lib/src/host/taiko.rs
deleted file mode 100644
index 4deca04e5..000000000
--- a/lib/src/host/taiko.rs
+++ /dev/null
@@ -1,547 +0,0 @@
-//! Prepare Input for guest
-use std::fmt::Debug;
-
-use anyhow::{anyhow, bail, Context, Result};
-use ethers_core::types::{Block, Transaction as EthersTransaction, H160, H256, U256, U64};
-use serde_json::to_string;
-use thiserror::Error as ThisError;
-use tracing::info;
-use zeth_primitives::{
-    block::Header,
-    ethers::{from_ethers_h160, from_ethers_h256, from_ethers_u256},
-    keccak,
-    taiko::{
-        deposits_hash, string_to_bytes32, BlockMetadata, EthDeposit, ProtocolInstance, Transition,
-        ANCHOR_GAS_LIMIT, *,
-    },
-    transactions::EthereumTransaction,
-    withdrawal::Withdrawal,
-    Address, TxHash, B256,
-};
-
-use super::{
-    provider::{new_provider, BlockQuery, ProofQuery, ProposeQuery, Provider},
-    provider_db, Init,
-};
-use crate::{
-    block_builder::{BlockBuilder, NetworkStrategyBundle},
-    consts::ChainSpec,
-    input::Input,
-    taiko::{utils::rlp_decode_list, Layer},
-    EthereumTxEssence,
-};
-
-#[derive(Debug)]
-pub struct TaikoExtra {
-    pub l1_hash: B256,
-    pub l1_height: u64,
-    pub l2_tx_list: Vec<u8>,
-    pub prover: Address,
-    pub graffiti: B256,
-    pub l1_signal_root: B256,
-    pub l2_signal_root: B256,
-    pub l2_withdrawals: Vec<Withdrawal>,
-    pub block_proposed: BlockProposed,
-    pub l1_next_block: Block<EthersTransaction>,
-    pub l2_fini_block: Block<EthersTransaction>,
-}
-
-#[allow(clippy::too_many_arguments)]
-pub fn get_taiko_initial_data<N: NetworkStrategyBundle<TxEssence = EthereumTxEssence>>(
-    l1_cache_path: Option<String>,
-    _l1_chain_spec: ChainSpec,
-    l1_rpc_url: Option<String>,
-    prover: Address,
-    l2_cache_path: Option<String>,
-    l2_chain_spec: ChainSpec,
-    l2_rpc_url: Option<String>,
-    l2_block_no: u64,
-    graffiti: B256,
-) -> Result<(Init<EthereumTxEssence>, TaikoExtra)> {
-    let (l2_provider, l2_init_block, mut l2_fini_block, l2_signal_root, l2_input) = fetch_data(
-        "L2",
-        l2_cache_path,
-        l2_rpc_url,
-        l2_block_no,
-        l2_chain_spec.l2_signal_service.unwrap(),
-        Layer::L2,
-    )?;
-    // Get anchor call parameters
-    let anchorCall {
-        l1Hash: anchor_l1_hash,
-        l1SignalRoot: anchor_l1_signal_root,
-        l1Height: l1_block_no,
-        parentGasUsed: l2_parent_gas_used,
-    } = decode_anchor_call_args(&l2_fini_block.transactions[0].input)?;
-
-    let (mut l1_provider, _l1_init_block, l1_fini_block, l1_signal_root, _l1_input) = fetch_data(
-        "L1",
-        l1_cache_path,
-        l1_rpc_url,
-        l1_block_no,
-        l2_chain_spec.l1_signal_service.unwrap(),
-        Layer::L1,
-    )?;
-
-    let (propose_tx, block_metadata) = l1_provider.get_propose(&ProposeQuery {
-        l1_contract: H160::from_slice(l2_chain_spec.l1_contract.unwrap().as_slice()),
-        l1_block_no: l1_block_no + 1,
-        l2_block_no,
-    })?;
-
-    let l1_next_block = l1_provider.get_full_block(&BlockQuery {
-        block_no: l1_block_no + 1,
-    })?;
-
-    // save l1 data
-    l1_provider.save()?;
-
-    let proposeBlockCall {
-        params: _,
-        txList: l2_tx_list,
-    } = decode_propose_block_call_args(&propose_tx.input)?;
-
-    // 1. check l2 parent gas used
-    if l2_init_block.gas_used != U256::from(l2_parent_gas_used) {
-        return Err(anyhow!(
-            "parent gas used mismatch, expect: {}, got: {}",
-            l2_init_block.gas_used,
-            l2_parent_gas_used
-        ));
-    }
-    // 2. check l1 signal root
-    if anchor_l1_signal_root != l1_signal_root {
-        return Err(anyhow!(
-            "l1 signal root mismatch, expect: {}, got: {}",
-            anchor_l1_signal_root,
-            l1_signal_root
-        ));
-    }
-    // 3. check l1 block hash
-    if Some(anchor_l1_hash) != l1_fini_block.hash.map(from_ethers_h256) {
-        return Err(anyhow!(
-            "l1 block hash mismatch, expect: {}, got: {:?}",
-            anchor_l1_hash,
-            l1_fini_block.hash
-        ));
-    }
-
-    let extra = TaikoExtra {
-        l1_hash: anchor_l1_hash,
-        l1_height: l1_block_no,
-        l2_tx_list,
-        prover,
-        graffiti,
-        l1_signal_root,
-        l2_signal_root,
-        l2_withdrawals: l2_input.withdrawals.clone(),
-        block_proposed: block_metadata,
-        l1_next_block,
-        l2_fini_block: l2_fini_block.clone(),
-    };
-
-    // rebuild transaction list by tx_list from l1 contract
-    rebuild_and_precheck_block(&l2_chain_spec, &mut l2_fini_block, &extra)?;
-
-    // execute transactions and get states
-    let init = execute_data::<N>(
-        l2_provider,
-        l2_chain_spec,
-        l2_init_block,
-        l2_input,
-        l2_fini_block,
-    )?;
-    Ok((init, extra))
-}
-
-// rebuild the block with anchor transaction and txlist from l1 contract, then precheck it
-pub fn rebuild_and_precheck_block(
-    l2_chain_spec: &ChainSpec,
-    l2_fini: &mut Block<EthersTransaction>,
-    extra: &TaikoExtra,
-) -> Result<()> {
-    let Some(anchor) = l2_fini.transactions.first().cloned() else {
-        bail!("no anchor transaction found");
-    };
-    // - check anchor transaction
-    precheck_anchor(l2_chain_spec, l2_fini, &anchor)
-        .map_err(|e| anyhow!(e.to_string()))
-        .with_context(|| "precheck anchor error")?;
-
-    let mut txs: Vec<EthersTransaction> = vec![];
-    // - tx list bytes must be less than MAX_TX_LIST_BYTES
-    if extra.l2_tx_list.len() <= MAX_TX_LIST_BYTES {
-        txs = rlp_decode_list(&extra.l2_tx_list).unwrap_or_else(|err| {
-            tracing::error!("decode tx list error: {}", err);
-            vec![]
-        });
-    } else {
-        tracing::error!(
-            "tx list bytes must be not more than MAX_TX_LIST_BYTES, got: {}",
-            extra.l2_tx_list.len()
-        );
-    }
-    // - tx list must be less than MAX_TX_LIST
-    if txs.len() > MAX_TX_LIST {
-        tracing::error!(
-            "tx list must be not more than MAX_TX_LIST, got: {}",
-            txs.len()
-        );
-        // reset to empty
-        txs.clear();
-    }
-    // - patch anchor transaction into tx list instead of those from l2 node's
-    // insert the anchor transaction into the tx list at the first position
-    txs.insert(0, anchor);
-    // reset transactions
-    l2_fini.transactions = txs;
-    Ok(())
-}
-
-#[derive(ThisError, Debug)]
-pub enum AnchorError {
-    #[error("anchor transaction type mismatch, expected: {expected}, got: {got}")]
-    AnchorTypeMisMatch { expected: u8, got: u8 },
-
-    #[error("anchor transaction from mismatch, expected: {expected}, got: {got:?}")]
-    AnchorFromMisMatch {
-        expected: Address,
-        got: Option<Address>,
-    },
-
-    #[error("anchor transaction to mismatch, expected: {expected}, got: {got:?}")]
-    AnchorToMisMatch {
-        expected: Address,
-        got: Option<Address>,
-    },
-
-    #[error("anchor transaction value mismatch, expected: {expected}, got: {got:?}")]
-    AnchorValueMisMatch { expected: U256, got: U256 },
-
-    #[error("anchor transaction gas limit mismatch, expected: {expected}, got: {got:?}")]
-    AnchorGasLimitMisMatch { expected: U256, got: U256 },
-
-    #[error("anchor transaction fee cap mismatch, expected: {expected:?}, got: {got:?}")]
-    AnchorFeeCapMisMatch {
-        expected: Option<U256>,
-        got: Option<U256>,
-    },
-
-    #[error("anchor transaction signature mismatch, {msg}")]
-    AnchorSignatureMismatch { msg: String },
-
-    #[error("anchor transaction decode error")]
-    Anyhow(#[from] anyhow::Error),
-}
-
-pub fn precheck_anchor(
-    l2_chain_spec: &ChainSpec,
-    l2_fini: &Block<EthersTransaction>,
-    anchor: &EthersTransaction,
-) -> Result<(), AnchorError> {
-    let tx1559_type = U64::from(0x2);
-    if anchor.transaction_type != Some(tx1559_type) {
-        return Err(AnchorError::AnchorTypeMisMatch {
-            expected: tx1559_type.as_u64() as u8,
-            got: anchor.transaction_type.unwrap_or_default().as_u64() as u8,
-        });
-    }
-    let tx: EthereumTransaction = anchor.clone().try_into()?;
-    // verify transaction
-    check_anchor_signature(&tx)?;
-    // verify the transaction signature
-    let from = from_ethers_h160(anchor.from);
-    if from != *GOLDEN_TOUCH_ACCOUNT {
-        return Err(AnchorError::AnchorFromMisMatch {
-            expected: *GOLDEN_TOUCH_ACCOUNT,
-            got: Some(from),
-        });
-    }
-    let Some(to) = anchor.to else {
-        return Err(AnchorError::AnchorToMisMatch {
-            expected: l2_chain_spec.l2_contract.unwrap(),
-            got: None,
-        });
-    };
-    let to = from_ethers_h160(to);
-    if to != l2_chain_spec.l2_contract.unwrap() {
-        return Err(AnchorError::AnchorFromMisMatch {
-            expected: l2_chain_spec.l2_contract.unwrap(),
-            got: Some(to),
-        });
-    }
-    if anchor.value != U256::zero() {
-        return Err(AnchorError::AnchorValueMisMatch {
-            expected: U256::zero(),
-            got: anchor.value,
-        });
-    }
-    if anchor.gas != U256::from(ANCHOR_GAS_LIMIT) {
-        return Err(AnchorError::AnchorGasLimitMisMatch {
-            expected: U256::from(ANCHOR_GAS_LIMIT),
-            got: anchor.gas,
-        });
-    }
-    // anchor's gas price should be the same as the block's
-    if anchor.max_fee_per_gas != l2_fini.base_fee_per_gas {
-        return Err(AnchorError::AnchorFeeCapMisMatch {
-            expected: l2_fini.base_fee_per_gas,
-            got: anchor.max_fee_per_gas,
-        });
-    }
-    Ok(())
-}
-
-pub fn assemble_protocol_instance(extra: &TaikoExtra, header: &Header) -> Result<ProtocolInstance> {
-    let tx_list_hash = TxHash::from(keccak::keccak(extra.l2_tx_list.as_slice()));
-    let deposits: Vec<EthDeposit> = extra
-        .l2_withdrawals
-        .iter()
-        .map(|w| EthDeposit {
-            recipient: w.address,
-            amount: w.amount as u128,
-            id: w.index,
-        })
-        .collect();
-    let deposits_hash = deposits_hash(&deposits);
-    let extra_data = string_to_bytes32(&header.extra_data);
-    //   meta.difficulty = meta.blobHash ^ bytes32(block.prevrandao * b.numBlocks *
-    // block.number);
-    let block_hash = tx_list_hash;
-    let block_hash_h256: zeth_primitives::U256 = block_hash.into();
-    let prevrando = if cfg!(feature = "pos") {
-        from_ethers_h256(extra.l1_next_block.mix_hash.unwrap_or_default()).into()
-    } else {
-        from_ethers_u256(extra.l1_next_block.difficulty)
-    };
-    let difficulty = block_hash_h256
-        ^ (prevrando
-            * zeth_primitives::U256::from(header.number)
-            * zeth_primitives::U256::from(extra.l1_next_block.number.unwrap_or_default().as_u64()));
-    let gas_limit: u64 = header.gas_limit.try_into().unwrap();
-    let mut pi = ProtocolInstance {
-        transition: Transition {
-            parentHash: header.parent_hash,
-            blockHash: header.hash(),
-            signalRoot: extra.l2_signal_root,
-            graffiti: extra.graffiti,
-        },
-        block_metadata: BlockMetadata {
-            l1Hash: extra.l1_hash,
-            difficulty: difficulty.into(),
-            blobHash: tx_list_hash,
-            extraData: extra_data.into(),
-            depositsHash: deposits_hash,
-            coinbase: header.beneficiary,
-            id: header.number,
-            gasLimit: (gas_limit - ANCHOR_GAS_LIMIT) as u32,
-            timestamp: header.timestamp.try_into().unwrap(),
-            l1Height: extra.l1_height,
-            txListByteOffset: 0u32,
-            txListByteSize: extra.l2_tx_list.len() as u32,
-            minTier: extra.block_proposed.meta.minTier,
-            blobUsed: extra.l2_tx_list.is_empty(),
-            parentMetaHash: extra.block_proposed.meta.parentMetaHash,
-        },
-        prover: extra.prover,
-    };
-    verify(header, &mut pi, extra)?;
-    Ok(pi)
-}
-
-pub fn verify(header: &Header, pi: &mut ProtocolInstance, extra: &TaikoExtra) -> Result<()> {
-    use alloy_sol_types::SolValue;
-    // check the block metadata
-    if pi.block_metadata.abi_encode() != extra.block_proposed.meta.abi_encode() {
-        return Err(anyhow!(
-            "block metadata mismatch, expected: {:?}, got: {:?}",
-            extra.block_proposed.meta,
-            pi.block_metadata
-        ));
-    }
-    // println!("Protocol instance Transition: {:?}", pi.transition);
-    // check the block hash
-    if Some(header.hash()) != extra.l2_fini_block.hash.map(from_ethers_h256) {
-        let txs: Vec<EthereumTransaction> = extra
-            .l2_fini_block
-            .transactions
-            .iter()
-            .filter_map(|tx| tx.clone().try_into().ok())
-            .collect();
-        return Err(anyhow!(
-            "block hash mismatch, expected: {}, got: {}",
-            to_string(&txs).unwrap_or_default(),
-            to_string(&header.transactions).unwrap_or_default(),
-        ));
-    }
-
-    Ok(())
-}
-
-#[allow(clippy::type_complexity)]
-pub fn fetch_data(
-    annotation: &str,
-    cache_path: Option<String>,
-    rpc_url: Option<String>,
-    block_no: u64,
-    signal_service: Address,
-    layer: Layer,
-) -> Result<(
-    Box<dyn Provider>,
-    Block<H256>,
-    Block<EthersTransaction>,
-    B256,
-    Input<EthereumTxEssence>,
-)> {
-    let mut provider = new_provider(cache_path, rpc_url)?;
-
-    let fini_query = BlockQuery { block_no };
-    match layer {
-        Layer::L1 => {}
-        Layer::L2 => {
-            provider.batch_get_partial_blocks(&fini_query)?;
-        }
-    }
-    // Fetch the initial block
-    let init_block = provider.get_partial_block(&BlockQuery {
-        block_no: block_no - 1,
-    })?;
-
-    info!(
-        "Initial {} block: {:?} ({:?})",
-        annotation,
-        init_block.number.unwrap(),
-        init_block.hash.unwrap()
-    );
-
-    // Fetch the finished block
-    let fini_block = provider.get_full_block(&fini_query)?;
-
-    info!(
-        "Final {} block number: {:?} ({:?})",
-        annotation,
-        fini_block.number.unwrap(),
-        fini_block.hash.unwrap()
-    );
-    info!("Transaction count: {:?}", fini_block.transactions.len());
-
-    // Get l2 signal root by signal service
-    let proof = provider.get_proof(&ProofQuery {
-        block_no,
-        address: H160::from_slice(signal_service.as_slice()),
-        indices: Default::default(),
-    })?;
-    let signal_root = from_ethers_h256(proof.storage_hash);
-
-    info!(
-        "Final {} signal root: {:?} ({:?})",
-        annotation,
-        fini_block.number.unwrap(),
-        signal_root,
-    );
-
-    // Create input
-    let input = Input {
-        beneficiary: fini_block.author.map(from_ethers_h160).unwrap_or_default(),
-        gas_limit: from_ethers_u256(fini_block.gas_limit),
-        timestamp: from_ethers_u256(fini_block.timestamp),
-        extra_data: fini_block.extra_data.0.clone().into(),
-        mix_hash: from_ethers_h256(fini_block.mix_hash.unwrap()),
-        transactions: fini_block
-            .transactions
-            .clone()
-            .into_iter()
-            .map(|tx| tx.try_into().unwrap())
-            .collect(),
-        withdrawals: fini_block
-            .withdrawals
-            .clone()
-            .unwrap_or_default()
-            .into_iter()
-            .map(|w| w.try_into().unwrap())
-            .collect(),
-        parent_state_trie: Default::default(),
-        parent_storage: Default::default(),
-        contracts: vec![],
-        parent_header: init_block.clone().try_into()?,
-        ancestor_headers: vec![],
-        base_fee_per_gas: from_ethers_u256(fini_block.base_fee_per_gas.unwrap_or_default()),
-    };
-
-    Ok((provider, init_block, fini_block, signal_root, input))
-}
-
-pub fn execute_data<N: NetworkStrategyBundle<TxEssence = EthereumTxEssence>>(
-    provider: Box<dyn Provider>,
-    chain_spec: ChainSpec,
-    init_block: Block<H256>,
-    input: Input<EthereumTxEssence>,
-    fini_block: Block<EthersTransaction>,
-) -> Result<Init<EthereumTxEssence>> {
-    // Create the provider DB
-    let provider_db = provider_db::ProviderDb::new(provider, init_block.number.unwrap().as_u64());
-    // Create the block builder, run the transactions and extract the DB
-    let mut builder = BlockBuilder::new(&chain_spec, input)
-        .with_db(provider_db)
-        .prepare_header::<N::HeaderPrepStrategy>()?
-        .execute_transactions::<N::TxExecStrategy>()?;
-    let provider_db = builder.mut_db().unwrap();
-
-    info!("Gathering inclusion proofs ...");
-
-    // Gather inclusion proofs for the initial and final state
-    let init_proofs = provider_db.get_initial_proofs()?;
-    let fini_proofs = provider_db.get_latest_proofs()?;
-
-    // Gather proofs for block history
-    let history_headers = provider_db.provider.batch_get_partial_blocks(&BlockQuery {
-        block_no: fini_block.number.unwrap().as_u64(),
-    })?;
-    // ancestors == history - current - parent
-    let ancestor_headers = if history_headers.len() > 2 {
-        history_headers
-            .into_iter()
-            .rev()
-            .skip(2)
-            .map(|header| {
-                header
-                    .try_into()
-                    .expect("Failed to convert ancestor headers")
-            })
-            .collect()
-    } else {
-        vec![]
-    };
-
-    info!("Saving provider cache ...");
-
-    // Save the provider cache
-    provider_db.get_provider().save()?;
-    info!("Provider-backed execution is Done!");
-    // assemble init
-    let transactions = fini_block
-        .transactions
-        .clone()
-        .into_iter()
-        .map(|tx| tx.try_into().unwrap())
-        .collect();
-    let withdrawals = fini_block
-        .withdrawals
-        .clone()
-        .unwrap_or_default()
-        .into_iter()
-        .map(|w| w.try_into().unwrap())
-        .collect();
-
-    let init = Init {
-        db: provider_db.get_initial_db().clone(),
-        init_block: init_block.try_into()?,
-        init_proofs,
-        fini_block: fini_block.try_into()?,
-        fini_transactions: transactions,
-        fini_withdrawals: withdrawals,
-        fini_proofs,
-        ancestor_headers,
-    };
-    Ok(init)
-}
diff --git a/lib/src/host/verify.rs b/lib/src/host/verify.rs
new file mode 100644
index 000000000..5d99b499e
--- /dev/null
+++ b/lib/src/host/verify.rs
@@ -0,0 +1,237 @@
+// Copyright 2023 RISC Zero, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+use alloc::vec::Vec;
+
+use anyhow::{anyhow, bail, Context, Result};
+use ethers_core::types::EIP1186ProofResponse;
+use hashbrown::HashMap;
+use log::error;
+use zeth_primitives::{
+    block::Header,
+    keccak::keccak,
+    transactions::TxEssence,
+    trie::{Error as TrieError, MptNode, StateAccount},
+    Address, B256, U256,
+};
+
+use super::{mpt, preflight};
+
+#[derive(Debug)]
+pub enum VerifyError {
+    BalanceMismatch {
+        rpc_value: U256,
+        our_value: U256,
+        difference: U256,
+    },
+    NonceMismatch {
+        rpc_value: u64,
+        our_value: u64,
+    },
+    CodeHashMismatch {
+        rpc_value: B256,
+        our_value: B256,
+    },
+    StorageMismatch {
+        index: U256,
+        rpc_value: U256,
+        our_db_value: U256,
+        our_trie_value: U256,
+    },
+    StorageRootMismatch {
+        rpc_value: B256,
+        our_value: B256,
+    },
+    /// The account is not in the trie, but the RPC response proves that it is included.
+    MissingAccount,
+    /// The account cannot be resolved in the trie.
+    UnresolvedAccount,
+}
+
+/// Verify the block header and state trie.
+pub trait Verifier {
+    fn verify_block(&self, header: &Header, state: &MptNode) -> Result<()>;
+}
+
+/// Verify using the preflight data.
+impl<E: TxEssence> Verifier for preflight::Data<E> {
+    fn verify_block(&self, header: &Header, state: &MptNode) -> Result<()> {
+        let errors =
+            verify_state_trie(state, &self.proofs).context("failed to verify state trie")?;
+
+        for (address, address_errors) in &errors {
+            error!(
+                "Verify found {:?} error(s) for address {address:?}",
+                address_errors.len(),
+            );
+            for error in address_errors {
+                error!("  Error: {error:?}");
+            }
+        }
+
+        let accounts_len = self.proofs.len();
+        let errors_len = errors.len();
+        if errors_len > 0 {
+            error!(
+                "Verify found {errors_len:?} account(s) with error(s) ({}% correct)",
+                (100.0 * (accounts_len - errors_len) as f64 / accounts_len as f64)
+            );
+        }
+
+        verify_header(header, &self.header)
+    }
+}
+
+fn verify_header(header: &Header, exp_header: &Header) -> Result<()> {
+    if header.state_root != exp_header.state_root {
+        error!(
+            "State root mismatch {} (expected {})",
+            header.state_root, exp_header.state_root
+        );
+    }
+
+    if header.transactions_root != exp_header.transactions_root {
+        error!(
+            "Transactions root mismatch {} (expected {})",
+            header.transactions_root, exp_header.transactions_root
+        );
+    }
+
+    if header.receipts_root != exp_header.receipts_root {
+        error!(
+            "Receipts root mismatch {} (expected {})",
+            header.receipts_root, exp_header.receipts_root
+        );
+    }
+
+    if header.base_fee_per_gas != exp_header.base_fee_per_gas {
+        error!(
+            "Base fee mismatch {} (expected {})",
+            header.base_fee_per_gas, exp_header.base_fee_per_gas
+        );
+    }
+
+    if header.withdrawals_root != exp_header.withdrawals_root {
+        error!(
+            "Withdrawals root mismatch {:?} (expected {:?})",
+            header.withdrawals_root, exp_header.withdrawals_root
+        );
+    }
+
+    let found_hash = header.hash();
+    let expected_hash = exp_header.hash();
+    if found_hash.as_slice() != expected_hash.as_slice() {
+        error!("Final block hash mismatch {found_hash} (expected {expected_hash})");
+
+        bail!("Invalid block hash");
+    }
+
+    Ok(())
+}
+
+fn verify_state_trie(
+    state_trie: &MptNode,
+    proofs: &HashMap<Address, EIP1186ProofResponse>,
+) -> Result<HashMap<Address, Vec<VerifyError>>> {
+    let mut errors = HashMap::new();
+
+    for (address, response) in proofs {
+        let account_proof = &response.account_proof;
+        let rpc_account: StateAccount = response.clone().into();
+
+        let key = keccak(address);
+        let mut address_errors = Vec::new();
+        match state_trie.get_rlp::<StateAccount>(&key) {
+            Ok(account) => match account {
+                // the account is not in the trie
+                None => {
+                    // the RPC response should prove that the account is not included
+                    if !account_deleted(&key, account_proof)
+                        .with_context(|| anyhow!("invalid account_proof for {address:#}"))?
+                    {
+                        address_errors.push(VerifyError::MissingAccount);
+                    }
+                }
+                Some(account_info) => {
+                    // Account balance
+                    {
+                        let rpc_value = rpc_account.balance;
+                        let our_value = account_info.balance;
+                        if rpc_value != our_value {
+                            let difference = rpc_value.abs_diff(our_value);
+                            address_errors.push(VerifyError::BalanceMismatch {
+                                rpc_value,
+                                our_value,
+                                difference,
+                            })
+                        }
+                    }
+
+                    // Nonce
+                    {
+                        let rpc_value = rpc_account.nonce;
+                        let our_value = account_info.nonce;
+                        if rpc_value != our_value {
+                            address_errors.push(VerifyError::NonceMismatch {
+                                rpc_value,
+                                our_value,
+                            })
+                        }
+                    }
+
+                    // Code hash
+                    {
+                        let rpc_value = rpc_account.code_hash;
+                        let our_value = account_info.code_hash;
+                        if rpc_value != our_value {
+                            address_errors.push(VerifyError::CodeHashMismatch {
+                                rpc_value,
+                                our_value,
+                            })
+                        }
+                    }
+
+                    // Storage root
+                    {
+                        let rpc_value = rpc_account.storage_root;
+                        let our_value = account_info.storage_root;
+                        if rpc_value != our_value {
+                            address_errors.push(VerifyError::StorageRootMismatch {
+                                rpc_value,
+                                our_value,
+                            });
+                        }
+                    }
+                }
+            },
+            // the account was pruned from the trie
+            Err(TrieError::NodeNotResolved(_)) => {
+                address_errors.push(VerifyError::UnresolvedAccount);
+            }
+            Err(err) => {
+                bail!("Error while fetching account {address:?}: {err:?}");
+            }
+        }
+
+        if !address_errors.is_empty() {
+            errors.insert(address.to_owned(), address_errors);
+        }
+    }
+
+    Ok(errors)
+}
+
+fn account_deleted(key: &[u8], proof: &[impl AsRef<[u8]>]) -> Result<bool> {
+    let proof_nodes = mpt::parse_proof(proof).context("invalid encoding")?;
+    mpt::is_not_included(key, &proof_nodes)
+}
diff --git a/lib/src/input.rs b/lib/src/input.rs
index a95a96680..b98f5a606 100644
--- a/lib/src/input.rs
+++ b/lib/src/input.rs
@@ -24,6 +24,11 @@ use zeth_primitives::{
     Address, Bytes, B256, U256,
 };
 
+/// Represents the state of an account's storage.
+/// The storage trie together with the used storage slots allow us to reconstruct all the
+/// required values.
+pub type StorageEntry = (MptNode, Vec<U256>);
+
 /// External block input.
 #[derive(Debug, Clone, Default, Deserialize, Serialize)]
 pub struct Input<E: TxEssence> {
@@ -55,8 +60,6 @@ pub struct Input<E: TxEssence> {
     pub base_fee_per_gas: U256,
 }
 
-pub type StorageEntry = (MptNode, Vec<U256>);
-
 #[cfg(test)]
 mod tests {
     use zeth_primitives::transactions::ethereum::EthereumTxEssence;
diff --git a/lib/src/lib.rs b/lib/src/lib.rs
index 224a2c185..32f6c10d3 100644
--- a/lib/src/lib.rs
+++ b/lib/src/lib.rs
@@ -12,29 +12,29 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 #![feature(path_file_prefix)]
-#![cfg_attr(target_os = "zkvm", no_std)]
-#![cfg_attr(not(feature = "std"), no_std)]
+#![cfg_attr(any(not(feature = "std"), target_os = "zkvm"), no_std)]
 
 extern crate alloc;
 extern crate core;
 
-pub mod block_builder;
+pub mod builder;
 pub mod consts;
-pub mod execution;
-pub mod finalization;
-pub mod initialization;
 pub mod input;
 pub mod mem_db;
-pub mod preparation;
+
+#[cfg(feature = "optimism")]
+pub mod optimism;
 
 #[cfg(feature = "taiko")]
 pub mod taiko;
 
-#[cfg(feature = "std")]
-#[cfg(not(target_os = "zkvm"))]
+#[cfg(all(feature = "std", not(target_os = "zkvm")))]
 pub mod host;
 
-pub use zeth_primitives::transactions::ethereum::EthereumTxEssence;
+#[cfg(feature = "optimism")]
+mod utils;
+
+pub use zeth_primitives::transactions::{ethereum::EthereumTxEssence, optimism::OptimismTxEssence};
 
 /// call forget only if running inside the guest
 pub fn guest_mem_forget<T>(_t: T) {
diff --git a/lib/src/optimism/batcher.rs b/lib/src/optimism/batcher.rs
new file mode 100644
index 000000000..d1b039fba
--- /dev/null
+++ b/lib/src/optimism/batcher.rs
@@ -0,0 +1,483 @@
+// Copyright 2024 RISC Zero, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use core::cmp::Ordering;
+use std::collections::{BTreeMap, VecDeque};
+
+use anyhow::{bail, ensure, Context, Result};
+use zeth_primitives::{
+    batch::{Batch, BatchEssence},
+    transactions::{
+        ethereum::EthereumTxEssence,
+        optimism::{OptimismTxEssence, OPTIMISM_DEPOSITED_TX_TYPE},
+        Transaction,
+    },
+    BlockHash, BlockNumber, B256, U256,
+};
+
+use super::{
+    batcher_channel::BatcherChannels, batcher_db::BlockInput, config::ChainConfig, deposits,
+};
+
+#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
+pub struct BlockId {
+    pub hash: B256,
+    pub number: BlockNumber,
+}
+
+#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
+pub struct L2BlockInfo {
+    pub hash: B256,
+    pub timestamp: u64,
+    pub l1_origin: BlockId,
+}
+
+#[derive(Clone, Debug, Default, PartialEq, Eq)]
+pub struct Epoch {
+    pub number: BlockNumber,
+    pub hash: B256,
+    pub timestamp: u64,
+    pub base_fee_per_gas: U256,
+    pub deposits: Vec<Transaction<OptimismTxEssence>>,
+}
+
+#[derive(Debug, Clone, Default)]
+pub struct State {
+    pub current_l1_block_number: BlockNumber,
+    pub current_l1_block_hash: BlockHash,
+    pub safe_head: L2BlockInfo,
+    pub epoch: Epoch,
+    pub op_epoch_queue: VecDeque<Epoch>,
+    pub next_epoch: Option<Epoch>,
+}
+
+impl State {
+    pub fn new(
+        current_l1_block_number: BlockNumber,
+        current_l1_block_hash: BlockHash,
+        safe_head: L2BlockInfo,
+        epoch: Epoch,
+    ) -> Self {
+        State {
+            current_l1_block_number,
+            current_l1_block_hash,
+            safe_head,
+            epoch,
+            op_epoch_queue: VecDeque::new(),
+            next_epoch: None,
+        }
+    }
+
+    pub fn do_next_epoch(&mut self) -> Result<()> {
+        self.epoch = self.next_epoch.take().context("no next epoch!")?;
+        self.deque_next_epoch_if_none()?;
+        Ok(())
+    }
+
+    pub fn push_epoch(&mut self, epoch: Epoch) -> Result<()> {
+        self.op_epoch_queue.push_back(epoch);
+        self.deque_next_epoch_if_none()?;
+        Ok(())
+    }
+
+    fn deque_next_epoch_if_none(&mut self) -> Result<()> {
+        if self.next_epoch.is_none() {
+            while let Some(next_epoch) = self.op_epoch_queue.pop_front() {
+                if next_epoch.number == self.epoch.number + 1 {
+                    self.next_epoch = Some(next_epoch);
+                    break;
+                }
+
+                if next_epoch.number > self.epoch.number {
+                    bail!("Epoch gap!");
+                }
+            }
+        }
+        Ok(())
+    }
+}
+
+#[derive(Debug, Clone, PartialEq)]
+enum BatchStatus {
+    Drop,
+    Accept,
+    Undecided,
+    Future,
+}
+
+/// A [Batch] with inclusion information.
+pub struct BatchWithInclusion {
+    pub essence: BatchEssence,
+    pub inclusion_block_number: BlockNumber,
+}
+
+pub struct Batcher {
+    /// Multimap of batches, keyed by timestamp
+    batches: BTreeMap<u64, VecDeque<BatchWithInclusion>>,
+    batcher_channel: BatcherChannels,
+    pub state: State,
+    pub config: ChainConfig,
+}
+
+impl Batcher {
+    pub fn new(
+        config: ChainConfig,
+        op_head: L2BlockInfo,
+        eth_block: &BlockInput<EthereumTxEssence>,
+    ) -> Result<Batcher> {
+        let eth_block_hash = eth_block.block_header.hash();
+
+        let batcher_channel = BatcherChannels::new(&config);
+
+        let state = State::new(
+            eth_block.block_header.number,
+            eth_block_hash,
+            op_head,
+            Epoch {
+                number: eth_block.block_header.number,
+                hash: eth_block_hash,
+                timestamp: eth_block.block_header.timestamp.try_into().unwrap(),
+                base_fee_per_gas: eth_block.block_header.base_fee_per_gas,
+                deposits: deposits::extract_transactions(&config, eth_block)?,
+            },
+        );
+
+        Ok(Batcher {
+            batches: BTreeMap::new(),
+            batcher_channel,
+            state,
+            config,
+        })
+    }
+
+    pub fn process_l1_block(&mut self, eth_block: &BlockInput<EthereumTxEssence>) -> Result<()> {
+        let eth_block_hash = eth_block.block_header.hash();
+
+        // Ensure block has correct parent
+        ensure!(
+            eth_block.block_header.parent_hash == self.state.current_l1_block_hash,
+            "Eth block has invalid parent hash"
+        );
+
+        // Update the system config. From the spec:
+        // "Upon traversal of the L1 block, the system configuration copy used by the L1 retrieval
+        //  stage is updated, such that the batch-sender authentication is always accurate to the
+        //  exact L1 block that is read by the stage"
+        if eth_block.receipts.is_some() {
+            self.config
+                .system_config
+                .update(&self.config.system_config_contract, eth_block)
+                .context("failed to update system config")?;
+        }
+
+        // Enqueue epoch
+        self.state.push_epoch(Epoch {
+            number: eth_block.block_header.number,
+            hash: eth_block_hash,
+            timestamp: eth_block.block_header.timestamp.try_into().unwrap(),
+            base_fee_per_gas: eth_block.block_header.base_fee_per_gas,
+            deposits: deposits::extract_transactions(&self.config, eth_block)?,
+        })?;
+
+        // process all transactions of this block to generate batches
+        self.batcher_channel
+            .process_l1_transactions(
+                self.config.system_config.batch_sender,
+                eth_block.block_header.number,
+                &eth_block.transactions,
+            )
+            .context("failed to process transactions")?;
+
+        // Read batches
+        while let Some(batches) = self.batcher_channel.read_batches() {
+            batches.into_iter().for_each(|batch| {
+                #[cfg(not(target_os = "zkvm"))]
+                log::debug!(
+                    "received batch: timestamp={}, parent_hash={}, epoch={}",
+                    batch.essence.timestamp,
+                    batch.essence.parent_hash,
+                    batch.essence.epoch_num
+                );
+                self.batches
+                    .entry(batch.essence.timestamp)
+                    .or_default()
+                    .push_back(batch);
+            });
+        }
+
+        self.state.current_l1_block_number = eth_block.block_header.number;
+        self.state.current_l1_block_hash = eth_block_hash;
+
+        Ok(())
+    }
+
+    pub fn read_batch(&mut self) -> Result<Option<Batch>> {
+        let epoch = &self.state.epoch;
+        let safe_l2_head = self.state.safe_head;
+
+        ensure!(
+            safe_l2_head.l1_origin.hash == epoch.hash
+                || safe_l2_head.l1_origin.number == epoch.number - 1,
+            "buffered L1 chain epoch does not match safe head origin"
+        );
+
+        let mut next_batch = None;
+
+        // Grab the first accepted batch. From the spec:
+        // "The batches are processed in order of the inclusion on L1: if multiple batches can be
+        //  accept-ed the first is applied. An implementation can defer future batches a later
+        //  derivation step to reduce validation work."
+        'outer: while let Some((ts, mut batches)) = self.batches.pop_first() {
+            // iterate over all batches, in order of inclusion and find the first accepted batch
+            // retain batches that may be processed in the future, or those we are undecided on
+            while let Some(batch) = batches.pop_front() {
+                match self.batch_status(&batch) {
+                    BatchStatus::Accept => {
+                        next_batch = Some(batch);
+                        // if there are still batches left, insert them back into the map
+                        if !batches.is_empty() {
+                            self.batches.insert(ts, batches);
+                        }
+                        break 'outer;
+                    }
+                    BatchStatus::Drop => {}
+                    BatchStatus::Future | BatchStatus::Undecided => {
+                        batches.push_front(batch);
+                        self.batches.insert(ts, batches);
+                        break 'outer;
+                    }
+                }
+            }
+        }
+
+        if let Some(batch) = next_batch {
+            return Ok(Some(Batch(batch.essence)));
+        }
+
+        // If there are no accepted batches, attempt to generate the default batch. From the spec:
+        // "If no batch can be accept-ed, and the stage has completed buffering of all batches
+        //  that can fully be read from the L1 block at height epoch.number +
+        //  sequence_window_size, and the next_epoch is available, then an empty batch can be
+        //  derived."
+        let current_l1_block = self.state.current_l1_block_number;
+        let sequence_window_size = self.config.seq_window_size;
+        let first_of_epoch = epoch.number == safe_l2_head.l1_origin.number + 1;
+
+        if current_l1_block <= epoch.number + sequence_window_size {
+            return Ok(None);
+        }
+
+        let Some(next_epoch) = &self.state.next_epoch else {
+            return Ok(None);
+        };
+
+        let next_timestamp = safe_l2_head.timestamp + self.config.blocktime;
+        let batch_epoch = if next_timestamp < next_epoch.timestamp || first_of_epoch {
+            // From the spec:
+            // "If next_timestamp < next_epoch.time: the current L1 origin is repeated,
+            //  to preserve the L2 time invariant."
+            // "If the batch is the first batch of the epoch, that epoch is used instead
+            //  of advancing the epoch to ensure that there is at least one L2 block per
+            //  epoch."
+            epoch
+        } else {
+            next_epoch
+        };
+
+        Ok(Some(Batch::new(
+            safe_l2_head.hash,
+            batch_epoch.number,
+            batch_epoch.hash,
+            next_timestamp,
+        )))
+    }
+
+    fn batch_status(&self, batch: &BatchWithInclusion) -> BatchStatus {
+        // Apply the batch status rules. The spec describes a precise order for these checks.
+
+        let epoch = &self.state.epoch;
+        let next_epoch = &self.state.next_epoch;
+        let safe_l2_head = self.state.safe_head;
+        let next_timestamp = safe_l2_head.timestamp + self.config.blocktime;
+
+        // From the spec:
+        // "batch.timestamp > next_timestamp -> future"
+        // "batch.timestamp < next_timestamp -> drop"
+        match batch.essence.timestamp.cmp(&next_timestamp) {
+            Ordering::Greater => {
+                #[cfg(not(target_os = "zkvm"))]
+                log::debug!(
+                    "Future batch: {} = batch.timestamp > next_timestamp = {}",
+                    &batch.essence.timestamp,
+                    &next_timestamp
+                );
+                return BatchStatus::Future;
+            }
+            Ordering::Less => {
+                #[cfg(not(target_os = "zkvm"))]
+                log::debug!(
+                    "Batch too old: {} = batch.timestamp < next_timestamp = {}",
+                    &batch.essence.timestamp,
+                    &next_timestamp
+                );
+                return BatchStatus::Drop;
+            }
+            Ordering::Equal => (),
+        }
+
+        // From the spec:
+        // "batch.parent_hash != safe_l2_head.hash -> drop"
+        if batch.essence.parent_hash != safe_l2_head.hash {
+            #[cfg(not(target_os = "zkvm"))]
+            log::debug!(
+                "Incorrect parent hash: {} != {}",
+                batch.essence.parent_hash,
+                safe_l2_head.hash
+            );
+            return BatchStatus::Drop;
+        }
+
+        // From the spec:
+        // "batch.epoch_num + sequence_window_size < inclusion_block_number -> drop"
+        if batch.essence.epoch_num + self.config.seq_window_size < batch.inclusion_block_number {
+            #[cfg(not(target_os = "zkvm"))]
+            log::debug!(
+                "Batch is not timely: {} + {} < {}",
+                batch.essence.epoch_num,
+                self.config.seq_window_size,
+                batch.inclusion_block_number
+            );
+            return BatchStatus::Drop;
+        }
+
+        // From the spec:
+        // "batch.epoch_num < epoch.number -> drop"
+        if batch.essence.epoch_num < epoch.number {
+            #[cfg(not(target_os = "zkvm"))]
+            log::debug!(
+                "Batch epoch number is too low: {} < {}",
+                batch.essence.epoch_num,
+                epoch.number
+            );
+            return BatchStatus::Drop;
+        }
+
+        let batch_origin = match batch.essence.epoch_num {
+            // From the spec:
+            // "batch.epoch_num == epoch.number: define batch_origin as epoch"
+            n if n == epoch.number => epoch,
+            // From the spec:
+            // "batch.epoch_num == epoch.number+1:"
+            // "  If known, then define batch_origin as next_epoch"
+            // "  If next_epoch is not known -> undecided"
+            n if n == epoch.number + 1 => match next_epoch {
+                Some(epoch) => epoch,
+                None => return BatchStatus::Undecided,
+            },
+            // From the spec:
+            // "batch.epoch_num > epoch.number+1 -> drop"
+            _ => {
+                #[cfg(not(target_os = "zkvm"))]
+                log::debug!(
+                    "Batch epoch number is too large: {} > {}",
+                    batch.essence.epoch_num,
+                    epoch.number + 1
+                );
+                return BatchStatus::Drop;
+            }
+        };
+
+        // From the spec:
+        // "batch.epoch_hash != batch_origin.hash -> drop"
+        if batch.essence.epoch_hash != batch_origin.hash {
+            #[cfg(not(target_os = "zkvm"))]
+            log::debug!(
+                "Epoch hash mismatch: {} != {}",
+                batch.essence.epoch_hash,
+                batch_origin.hash
+            );
+            return BatchStatus::Drop;
+        }
+
+        // From the spec:
+        // "batch.timestamp < batch_origin.time -> drop"
+        if batch.essence.timestamp < batch_origin.timestamp {
+            #[cfg(not(target_os = "zkvm"))]
+            log::debug!(
+                "Batch violates timestamp rule: {} < {}",
+                batch.essence.timestamp,
+                batch_origin.timestamp
+            );
+            return BatchStatus::Drop;
+        }
+
+        // From the spec:
+        // "batch.timestamp > batch_origin.time + max_sequencer_drift: enforce the L2 timestamp
+        //  drift rule, but with exceptions to preserve above min L2 timestamp invariant:"
+        if batch.essence.timestamp > batch_origin.timestamp + self.config.max_seq_drift {
+            #[cfg(not(target_os = "zkvm"))]
+            log::debug!(
+                "Sequencer drift detected: {} > {} + {}",
+                batch.essence.timestamp,
+                batch_origin.timestamp,
+                self.config.max_seq_drift
+            );
+
+            // From the spec:
+            // "len(batch.transactions) > 0: -> drop"
+            if !batch.essence.transactions.is_empty() {
+                #[cfg(not(target_os = "zkvm"))]
+                log::debug!("Sequencer drift detected for non-empty batch; drop.");
+                return BatchStatus::Drop;
+            }
+
+            // From the spec:
+            // "len(batch.transactions) == 0:"
+            //    epoch.number == batch.epoch_num: this implies the batch does not already
+            //    advance the L1 origin, and must thus be checked against next_epoch."
+            if epoch.number == batch.essence.epoch_num {
+                let Some(next_epoch) = next_epoch else {
+                    // From the spec:
+                    // "If next_epoch is not known -> undecided"
+                    #[cfg(not(target_os = "zkvm"))]
+                    log::debug!("Sequencer drift detected, but next epoch is not known; undecided");
+                    return BatchStatus::Undecided;
+                };
+
+                // From the spec:
+                // "If batch.timestamp >= next_epoch.time -> drop"
+                if batch.essence.timestamp >= next_epoch.timestamp {
+                    #[cfg(not(target_os = "zkvm"))]
+                    log::debug!("Sequencer drift detected; drop; batch timestamp is too far into the future. {} >= {}", batch.essence.timestamp, next_epoch.timestamp);
+                    return BatchStatus::Drop;
+                }
+            }
+        }
+
+        // From the spec:
+        // "batch.transactions: drop if the batch.transactions list contains a transaction that is
+        //  invalid or derived by other means exclusively:
+        //    any transaction that is empty (zero length byte string)
+        //    any deposited transactions (identified by the transaction type prefix byte)"
+        for tx in &batch.essence.transactions {
+            if matches!(tx.first(), None | Some(&OPTIMISM_DEPOSITED_TX_TYPE)) {
+                #[cfg(not(target_os = "zkvm"))]
+                log::debug!("Batch contains empty or invalid transaction");
+                return BatchStatus::Drop;
+            }
+        }
+
+        BatchStatus::Accept
+    }
+}
diff --git a/lib/src/optimism/batcher_channel.rs b/lib/src/optimism/batcher_channel.rs
new file mode 100644
index 000000000..7a3718e9b
--- /dev/null
+++ b/lib/src/optimism/batcher_channel.rs
@@ -0,0 +1,579 @@
+// Copyright 2024 RISC Zero, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use std::{
+    collections::{BTreeMap, VecDeque},
+    io::Read,
+};
+
+use anyhow::{bail, ensure, Context, Result};
+use bytes::Buf;
+use libflate::zlib::Decoder;
+use zeth_primitives::{
+    batch::Batch,
+    rlp::Decodable,
+    transactions::{ethereum::EthereumTxEssence, Transaction, TxEssence},
+    Address, BlockNumber,
+};
+
+use super::{batcher::BatchWithInclusion, config::ChainConfig};
+use crate::utils::MultiReader;
+
+pub const MAX_RLP_BYTES_PER_CHANNEL: u64 = 10_000_000;
+
+pub struct BatcherChannels {
+    batch_inbox: Address,
+    max_channel_bank_size: u64,
+    channel_timeout: u64,
+    channels: VecDeque<Channel>,
+    batches: VecDeque<Vec<BatchWithInclusion>>,
+}
+
+impl BatcherChannels {
+    pub fn new(config: &ChainConfig) -> Self {
+        Self {
+            batch_inbox: config.batch_inbox,
+            max_channel_bank_size: config.max_channel_bank_size,
+            channel_timeout: config.channel_timeout,
+            channels: VecDeque::new(),
+            batches: VecDeque::new(),
+        }
+    }
+
+    /// Processes all batcher transactions in the given block.
+    /// The given batch_sender must match the potentially updated batcher address loaded
+    /// from the system config.
+    pub fn process_l1_transactions(
+        &mut self,
+        batch_sender: Address,
+        block_number: BlockNumber,
+        transactions: &Vec<Transaction<EthereumTxEssence>>,
+    ) -> Result<()> {
+        for tx in transactions {
+            // From the spec:
+            // "The receiver must be the configured batcher inbox address."
+            if tx.essence.to() != Some(self.batch_inbox) {
+                continue;
+            }
+            // From the spec:
+            // "The sender must match the batcher address loaded from the system config matching
+            //  the L1 block of the data."
+            if tx.recover_from().context("invalid signature")? != batch_sender {
+                continue;
+            }
+
+            #[cfg(not(target_os = "zkvm"))]
+            log::debug!("received batcher tx: {}", tx.hash());
+
+            // From the spec:
+            // "If any one frame fails to parse, the all frames in the transaction are rejected."
+            let frames = match Frame::process_batcher_transaction(&tx.essence) {
+                Ok(frames) => frames,
+                Err(_err) => {
+                    #[cfg(not(target_os = "zkvm"))]
+                    log::warn!("failed to decode all frames; skip entire batcher tx: {_err:#}");
+                    continue;
+                }
+            };
+
+            // load received frames into the channel bank
+            for frame in frames {
+                #[cfg(not(target_os = "zkvm"))]
+                log::debug!(
+                    "received frame: channel_id={}, frame_number={}, is_last={}",
+                    frame.channel_id,
+                    frame.number,
+                    frame.is_last
+                );
+
+                self.add_frame(block_number, frame);
+            }
+
+            // Remove all timed-out channels at the front of the queue. From the spec:
+            // "Upon reading, while the first opened channel is timed-out, remove it from the
+            // channel-bank."
+            while matches!(self.channels.front(), Some(channel) if block_number > channel.open_l1_block + self.channel_timeout)
+            {
+                let _channel = self.channels.pop_front().unwrap();
+                #[cfg(not(target_os = "zkvm"))]
+                log::debug!("timed-out channel: {}", _channel.id);
+            }
+
+            // read all ready channels from the front of the queue
+            while matches!(self.channels.front(), Some(channel) if channel.is_ready()) {
+                let channel = self.channels.pop_front().unwrap();
+                #[cfg(not(target_os = "zkvm"))]
+                log::debug!("received channel: {}", channel.id);
+
+                self.batches.push_back(channel.read_batches(block_number));
+            }
+        }
+
+        Ok(())
+    }
+
+    pub fn read_batches(&mut self) -> Option<Vec<BatchWithInclusion>> {
+        self.batches.pop_front()
+    }
+
+    /// Adds a frame to the channel bank. Frames that cannot be added are ignored.
+    fn add_frame(&mut self, block_number: BlockNumber, frame: Frame) {
+        let channel = self
+            .channel_index(frame.channel_id)
+            .and_then(|idx| self.channels.get_mut(idx));
+
+        match channel {
+            Some(channel) => {
+                if block_number > channel.open_l1_block + self.channel_timeout {
+                    // From the spec:
+                    // "New frames for timed-out channels are dropped instead of buffered."
+                    #[cfg(not(target_os = "zkvm"))]
+                    log::warn!("frame's channel is timed out; ignored");
+                    return;
+                }
+                if let Err(_err) = channel.add_frame(frame) {
+                    #[cfg(not(target_os = "zkvm"))]
+                    log::warn!("failed to add frame to channel; ignored: {_err:#}");
+                    return;
+                }
+            }
+            None => {
+                // Create new channel. From the spec:
+                // "When a channel ID referenced by a frame is not already present in the
+                //  Channel Bank, a new channel is opened, tagged with the current L1
+                //  block, and appended to the channel-queue"
+                self.channels.push_back(Channel::new(block_number, frame));
+            }
+        }
+
+        // From the spec:
+        // "After successfully inserting a new frame, the ChannelBank is pruned: channels
+        //  are dropped in FIFO order, until total_size <= MAX_CHANNEL_BANK_SIZE."
+        self.prune();
+    }
+
+    /// Enforces max_channel_bank_size by dropping channels in FIFO order.
+    fn prune(&mut self) {
+        let mut total_size = self.total_size();
+        while total_size as u64 > self.max_channel_bank_size {
+            let dropped_channel = self.channels.pop_front().unwrap();
+            total_size -= dropped_channel.size;
+
+            #[cfg(not(target_os = "zkvm"))]
+            log::debug!(
+                "pruned channel: {} (channel_size: {})",
+                dropped_channel.id,
+                dropped_channel.size
+            );
+        }
+    }
+
+    fn total_size(&self) -> usize {
+        self.channels.iter().map(|c| c.size).sum()
+    }
+
+    fn channel_index(&self, channel_id: ChannelId) -> Option<usize> {
+        self.channels.iter().position(|c| c.id == channel_id)
+    }
+}
+
+/// A [ChannelId] is a unique identifier for a [Channel].
+type ChannelId = u128;
+
+/// A [Channel] is a set of batches that are split into at least one, but possibly
+/// multiple frames. Frames are allowed to be ingested in any order.
+#[derive(Clone, Debug, Default)]
+struct Channel {
+    /// The channel ID.
+    id: ChannelId,
+    /// The number of the L1 block that opened this channel.
+    open_l1_block: u64,
+    /// The number of the frame that closes this channel.
+    close_frame_number: Option<u16>,
+    /// All frames belonging to this channel by their frame number.
+    frames: BTreeMap<u16, Frame>,
+    /// The estimated memory size, used to drop the channel if we have too much data.
+    size: usize,
+}
+
+impl Channel {
+    const FRAME_OVERHEAD: usize = 200;
+
+    /// Creates a new channel from the given frame.
+    fn new(open_l1_block: u64, frame: Frame) -> Self {
+        let mut channel = Self {
+            id: frame.channel_id,
+            open_l1_block,
+            close_frame_number: None,
+            frames: BTreeMap::new(),
+            size: 0,
+        };
+
+        // cannot fail for an empty channel
+        channel.add_frame(frame).unwrap();
+
+        channel
+    }
+
+    /// Returns true if the channel is closed, i.e. the closing frame has been received.
+    fn is_closed(&self) -> bool {
+        self.close_frame_number.is_some()
+    }
+
+    /// Returns true if the channel is ready to be read.
+    fn is_ready(&self) -> bool {
+        // From the spec:
+        // "A channel is ready if:
+        //  - The channel is closed
+        //  - The channel has a contiguous sequence of frames until the closing frame"
+        matches!(self.close_frame_number, Some(n) if n as usize == self.frames.len() - 1)
+    }
+
+    fn add_frame(&mut self, frame: Frame) -> Result<()> {
+        ensure!(
+            frame.channel_id == self.id,
+            "frame channel_id does not match channel id"
+        );
+        if frame.is_last && self.is_closed() {
+            bail!("channel is already closed");
+        }
+        ensure!(
+            !self.frames.contains_key(&frame.number),
+            "duplicate frame number"
+        );
+        if let Some(close_frame_number) = self.close_frame_number {
+            ensure!(
+                frame.number < close_frame_number,
+                "frame number >= close_frame_number"
+            );
+        }
+
+        // From the spec:
+        // "If a frame is closing any existing higher-numbered frames are removed from the
+        // channel."
+        if frame.is_last {
+            // mark channel as closed
+            self.close_frame_number = Some(frame.number);
+            // prune frames with a number higher than the closing frame and update size
+            self.frames
+                .split_off(&frame.number)
+                .values()
+                .for_each(|pruned| self.size -= Self::FRAME_OVERHEAD + pruned.data.len());
+        }
+
+        self.size += Self::FRAME_OVERHEAD + frame.data.len();
+        self.frames.insert(frame.number, frame);
+
+        Ok(())
+    }
+
+    /// Reads all batches from an ready channel. If there is an invalid batch, the rest of
+    /// the channel is skipped, but previous batches are returned.
+    fn read_batches(&self, block_number: BlockNumber) -> Vec<BatchWithInclusion> {
+        debug_assert!(self.is_ready());
+
+        let mut batches = Vec::new();
+        if let Err(_err) = self.decode_batches(block_number, &mut batches) {
+            #[cfg(not(target_os = "zkvm"))]
+            log::warn!("failed to decode all batches; skipping rest of channel: {_err:#}");
+        }
+
+        batches
+    }
+
+    fn decode_batches(
+        &self,
+        block_number: BlockNumber,
+        batches: &mut Vec<BatchWithInclusion>,
+    ) -> Result<()> {
+        let decompressed = self
+            .decompress()
+            .context("failed to decompress channel data")?;
+
+        let mut channel_data = decompressed.as_slice();
+        while !channel_data.is_empty() {
+            let batch = Batch::decode(&mut channel_data)
+                .with_context(|| format!("failed to decode batch {}", batches.len()))?;
+
+            batches.push(BatchWithInclusion {
+                essence: batch.0,
+                inclusion_block_number: block_number,
+            });
+        }
+
+        Ok(())
+    }
+
+    fn decompress(&self) -> Result<Vec<u8>> {
+        // chain all frames' data together
+        let data = MultiReader::new(self.frames.values().map(|frame| frame.data.as_slice()));
+
+        // From the spec:
+        // "When decompressing a channel, we limit the amount of decompressed data to
+        //  MAX_RLP_BYTES_PER_CHANNEL (currently 10,000,000 bytes), in order to avoid "zip-bomb"
+        //  types of attack (where a small compressed input decompresses to a humongous amount
+        //  of data). If the decompressed data exceeds the limit, things proceeds as though the
+        //  channel contained only the first MAX_RLP_BYTES_PER_CHANNEL decompressed bytes."
+        let mut buf = Vec::new();
+        Decoder::new(data)?
+            .take(MAX_RLP_BYTES_PER_CHANNEL)
+            .read_to_end(&mut buf)?;
+
+        Ok(buf)
+    }
+}
+
+/// A [Frame] is a chunk of data belonging to a [Channel]. Batcher transactions carry one
+/// or multiple frames. The reason to split a channel into frames is that a channel might
+/// too large to include in a single batcher transaction.
+#[derive(Debug, Default, Clone)]
+struct Frame {
+    /// The channel ID this frame belongs to.
+    pub channel_id: ChannelId,
+    /// The index of this frame within the channel.
+    pub number: u16,
+    /// A sequence of bytes belonging to the channel.
+    pub data: Vec<u8>,
+    /// Whether this is the last frame of the channel.
+    pub is_last: bool,
+}
+
+impl Frame {
+    const HEADER_SIZE: usize = 22;
+    const MAX_FRAME_DATA_LENGTH: u32 = 1_000_000;
+
+    /// Processes a batcher transaction and returns the list of contained frames.
+    pub fn process_batcher_transaction(tx_essence: &EthereumTxEssence) -> Result<Vec<Self>> {
+        let (version, mut rollup_payload) = tx_essence
+            .data()
+            .split_first()
+            .context("empty transaction data")?;
+        ensure!(version == &0, "invalid transaction version: {version}");
+
+        let mut frames = Vec::new();
+        while !rollup_payload.is_empty() {
+            let frame = Frame::decode(&mut rollup_payload)
+                .with_context(|| format!("failed to decode frame {}", frames.len()))?;
+            frames.push(frame);
+        }
+
+        Ok(frames)
+    }
+
+    /// Decodes a [Frame] from the given buffer, advancing the buffer's position.
+    fn decode(buf: &mut &[u8]) -> Result<Self> {
+        ensure!(buf.remaining() > Self::HEADER_SIZE, "input too short");
+
+        let channel_id = buf.get_u128();
+        let frame_number = buf.get_u16();
+        // From the spec:
+        // "frame_data_length is the length of frame_data in bytes. It is capped to 1,000,000."
+        let frame_data_length = buf.get_u32();
+        ensure!(
+            frame_data_length <= Self::MAX_FRAME_DATA_LENGTH,
+            "frame_data_length too large"
+        );
+
+        let frame_data = buf
+            .get(..frame_data_length as usize)
+            .context("input too short")?;
+        buf.advance(frame_data_length as usize);
+
+        // From the spec:
+        // "is_last is a single byte with a value of 1 if the frame is the last in the channel,
+        //  0 if there are frames in the channel. Any other value makes the frame invalid."
+        ensure!(buf.has_remaining(), "input too short");
+        let is_last = match buf.get_u8() {
+            0 => false,
+            1 => true,
+            _ => bail!("invalid is_last value"),
+        };
+
+        Ok(Self {
+            channel_id,
+            number: frame_number,
+            data: frame_data.to_vec(),
+            is_last,
+        })
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    // test vectors from https://github.com/ethereum-optimism/optimism/blob/711f33b4366f6cd268a265e7ed8ccb37085d86a2/op-node/rollup/derive/channel_test.go
+    mod channel {
+        use super::*;
+
+        const CHANNEL_ID: ChannelId = 0xff;
+
+        fn new_channel() -> Channel {
+            Channel {
+                id: CHANNEL_ID,
+                ..Default::default()
+            }
+        }
+
+        #[test]
+        fn frame_validity() {
+            // wrong channel
+            {
+                let frame = Frame {
+                    channel_id: 0xee,
+                    ..Default::default()
+                };
+
+                let mut channel = new_channel();
+                channel.add_frame(frame).unwrap_err();
+                assert_eq!(channel.size, 0);
+            }
+
+            // double close
+            {
+                let frame_a = Frame {
+                    channel_id: CHANNEL_ID,
+                    number: 2,
+                    data: b"four".to_vec(),
+                    is_last: true,
+                };
+                let frame_b = Frame {
+                    channel_id: CHANNEL_ID,
+                    number: 1,
+                    is_last: true,
+                    ..Default::default()
+                };
+
+                let mut channel = new_channel();
+                channel.add_frame(frame_a).unwrap();
+                assert_eq!(channel.size, 204);
+                channel.add_frame(frame_b).unwrap_err();
+                assert_eq!(channel.size, 204);
+            }
+
+            // duplicate frame
+            {
+                let frame_a = Frame {
+                    channel_id: CHANNEL_ID,
+                    number: 2,
+                    data: b"four".to_vec(),
+                    ..Default::default()
+                };
+                let frame_b = Frame {
+                    channel_id: CHANNEL_ID,
+                    number: 2,
+                    data: b"seven__".to_vec(),
+                    ..Default::default()
+                };
+
+                let mut channel = new_channel();
+                channel.add_frame(frame_a).unwrap();
+                assert_eq!(channel.size, 204);
+                channel.add_frame(frame_b).unwrap_err();
+                assert_eq!(channel.size, 204);
+            }
+
+            // duplicate closing frame
+            {
+                let frame_a = Frame {
+                    channel_id: CHANNEL_ID,
+                    number: 2,
+                    data: b"four".to_vec(),
+                    is_last: true,
+                };
+                let frame_b = Frame {
+                    channel_id: CHANNEL_ID,
+                    number: 2,
+                    data: b"seven__".to_vec(),
+                    is_last: true,
+                };
+
+                let mut channel = new_channel();
+                channel.add_frame(frame_a).unwrap();
+                assert_eq!(channel.size, 204);
+                channel.add_frame(frame_b).unwrap_err();
+                assert_eq!(channel.size, 204);
+            }
+
+            // frame past closing
+            {
+                let frame_a = Frame {
+                    channel_id: CHANNEL_ID,
+                    number: 2,
+                    data: b"four".to_vec(),
+                    is_last: true,
+                };
+                let frame_b = Frame {
+                    channel_id: CHANNEL_ID,
+                    number: 10,
+                    data: b"seven__".to_vec(),
+                    ..Default::default()
+                };
+
+                let mut channel = new_channel();
+                channel.add_frame(frame_a).unwrap();
+                assert_eq!(channel.size, 204);
+                channel.add_frame(frame_b).unwrap_err();
+                assert_eq!(channel.size, 204);
+            }
+
+            // prune after close frame
+            {
+                let frame_a = Frame {
+                    channel_id: CHANNEL_ID,
+                    number: 10,
+                    data: b"seven__".to_vec(),
+                    is_last: false,
+                };
+                let frame_b = Frame {
+                    channel_id: CHANNEL_ID,
+                    number: 2,
+                    data: b"four".to_vec(),
+                    is_last: true,
+                };
+
+                let mut channel = new_channel();
+                channel.add_frame(frame_a).unwrap();
+                assert_eq!(channel.size, 207);
+                channel.add_frame(frame_b).unwrap();
+                assert_eq!(channel.size, 204);
+            }
+
+            // multiple valid frames
+            {
+                let frame_a = Frame {
+                    channel_id: CHANNEL_ID,
+                    number: 1,
+                    data: vec![202, 73, 81, 4, 0, 28, 73, 4, 62],
+                    is_last: true,
+                };
+                let frame_b = Frame {
+                    channel_id: CHANNEL_ID,
+                    number: 0,
+                    data: vec![120, 156, 243, 72, 205, 201, 201, 87, 8, 207, 47],
+                    ..Default::default()
+                };
+
+                let mut channel = new_channel();
+                channel.add_frame(frame_a).unwrap();
+                assert_eq!(channel.size, 209);
+                assert_eq!(channel.is_ready(), false);
+                channel.add_frame(frame_b).unwrap();
+                assert_eq!(channel.size, 420);
+                assert_eq!(channel.is_ready(), true);
+                assert_eq!(channel.decompress().unwrap(), b"Hello World!");
+            }
+        }
+    }
+}
diff --git a/lib/src/optimism/batcher_db.rs b/lib/src/optimism/batcher_db.rs
new file mode 100644
index 000000000..d88b22977
--- /dev/null
+++ b/lib/src/optimism/batcher_db.rs
@@ -0,0 +1,179 @@
+// Copyright 2023 RISC Zero, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use std::collections::HashMap;
+
+use anyhow::{ensure, Context, Result};
+use serde::{Deserialize, Serialize};
+use zeth_primitives::{
+    block::Header,
+    receipt::Receipt,
+    transactions::{
+        ethereum::EthereumTxEssence, optimism::OptimismTxEssence, Transaction, TxEssence,
+    },
+    trie::MptNode,
+    RlpBytes,
+};
+
+use crate::optimism::{config::OPTIMISM_CHAIN_SPEC, deposits, system_config};
+
+/// Input for extracting deposits.
+#[derive(Debug, Clone, Deserialize, Serialize)]
+pub struct BlockInput<E: TxEssence> {
+    /// Header of the block.
+    pub block_header: Header,
+    /// Transactions of the block.
+    pub transactions: Vec<Transaction<E>>,
+    /// Transaction receipts of the block or `None` if not required.
+    pub receipts: Option<Vec<Receipt>>,
+}
+
+pub trait BatcherDb {
+    fn validate(&self) -> Result<()>;
+    fn get_full_op_block(&mut self, block_no: u64) -> Result<BlockInput<OptimismTxEssence>>;
+    fn get_op_block_header(&mut self, block_no: u64) -> Result<Header>;
+    fn get_full_eth_block(&mut self, block_no: u64) -> Result<&BlockInput<EthereumTxEssence>>;
+}
+
+#[derive(Debug, Clone, Deserialize, Serialize)]
+pub struct MemDb {
+    pub full_op_block: HashMap<u64, BlockInput<OptimismTxEssence>>,
+    pub op_block_header: HashMap<u64, Header>,
+    pub full_eth_block: HashMap<u64, BlockInput<EthereumTxEssence>>,
+    pub eth_block_header: HashMap<u64, Header>,
+}
+
+impl MemDb {
+    pub fn new() -> Self {
+        MemDb {
+            full_op_block: HashMap::new(),
+            op_block_header: HashMap::new(),
+            full_eth_block: HashMap::new(),
+            eth_block_header: HashMap::new(),
+        }
+    }
+}
+
+impl Default for MemDb {
+    fn default() -> Self {
+        Self::new()
+    }
+}
+
+impl BatcherDb for MemDb {
+    fn validate(&self) -> Result<()> {
+        for (block_no, op_block) in &self.full_op_block {
+            ensure!(
+                *block_no == op_block.block_header.number,
+                "Block number mismatch"
+            );
+
+            // Validate tx list
+            {
+                let mut tx_trie = MptNode::default();
+                for (tx_no, tx) in op_block.transactions.iter().enumerate() {
+                    let trie_key = tx_no.to_rlp();
+                    tx_trie.insert_rlp(&trie_key, tx)?;
+                }
+                ensure!(
+                    tx_trie.hash() == op_block.block_header.transactions_root,
+                    "Invalid op block transaction data!"
+                );
+            }
+
+            // Validate receipts
+            ensure!(
+                op_block.receipts.is_none(),
+                "Op blocks should not contain receipts"
+            );
+        }
+
+        for (block_no, op_block) in &self.op_block_header {
+            ensure!(*block_no == op_block.number, "Block number mismatch");
+        }
+
+        for (block_no, eth_block) in &self.full_eth_block {
+            ensure!(
+                *block_no == eth_block.block_header.number,
+                "Block number mismatch"
+            );
+
+            // Validate tx list
+            {
+                let mut tx_trie = MptNode::default();
+                for (tx_no, tx) in eth_block.transactions.iter().enumerate() {
+                    let trie_key = tx_no.to_rlp();
+                    tx_trie.insert_rlp(&trie_key, tx)?;
+                }
+                ensure!(
+                    tx_trie.hash() == eth_block.block_header.transactions_root,
+                    "Invalid eth block transaction data!"
+                );
+            }
+
+            // Validate receipts
+            if eth_block.receipts.is_some() {
+                let mut receipt_trie = MptNode::default();
+                for (tx_no, receipt) in eth_block.receipts.as_ref().unwrap().iter().enumerate() {
+                    let trie_key = tx_no.to_rlp();
+                    receipt_trie.insert_rlp(&trie_key, receipt)?;
+                }
+                ensure!(
+                    receipt_trie.hash() == eth_block.block_header.receipts_root,
+                    "Invalid eth block receipt data!"
+                );
+            } else {
+                let can_contain_deposits = deposits::can_contain(
+                    &OPTIMISM_CHAIN_SPEC.deposit_contract,
+                    &eth_block.block_header.logs_bloom,
+                );
+                let can_contain_config = system_config::can_contain(
+                    &OPTIMISM_CHAIN_SPEC.system_config_contract,
+                    &eth_block.block_header.logs_bloom,
+                );
+                ensure!(
+                    !can_contain_deposits,
+                    "Eth block has no receipts, but bloom filter indicates it has deposits"
+                );
+                ensure!(
+                    !can_contain_config,
+                    "Eth block has no receipts, but bloom filter indicates it has config updates"
+                );
+            }
+        }
+
+        Ok(())
+    }
+
+    fn get_full_op_block(&mut self, block_no: u64) -> Result<BlockInput<OptimismTxEssence>> {
+        let op_block = self.full_op_block.remove(&block_no).unwrap();
+
+        Ok(op_block)
+    }
+
+    fn get_op_block_header(&mut self, block_no: u64) -> Result<Header> {
+        let op_block = self
+            .op_block_header
+            .remove(&block_no)
+            .context("not or no longer in db")?;
+
+        Ok(op_block)
+    }
+
+    fn get_full_eth_block(&mut self, block_no: u64) -> Result<&BlockInput<EthereumTxEssence>> {
+        let eth_block = self.full_eth_block.get(&block_no).unwrap();
+
+        Ok(eth_block)
+    }
+}
diff --git a/lib/src/optimism/config.rs b/lib/src/optimism/config.rs
new file mode 100644
index 000000000..e1f8f57b0
--- /dev/null
+++ b/lib/src/optimism/config.rs
@@ -0,0 +1,75 @@
+// Copyright 2023 RISC Zero, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use ruint::uint;
+use serde::{Deserialize, Serialize};
+use zeth_primitives::{address, Address};
+
+use super::system_config::SystemConfig;
+
+/// A Chain Configuration
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct ChainConfig {
+    /// The initial system config value
+    pub system_config: SystemConfig,
+    /// The L1 attributes depositor address
+    pub l1_attributes_depositor: Address,
+    /// The L1 attributes contract
+    pub l1_attributes_contract: Address,
+    /// The L2 address accumulating any transaction priority fee
+    pub sequencer_fee_vault: Address,
+    /// The batch inbox address
+    pub batch_inbox: Address,
+    /// The deposit contract address
+    pub deposit_contract: Address,
+    /// The L1 system config contract
+    pub system_config_contract: Address,
+    /// The maximum byte size of all pending channels
+    pub max_channel_bank_size: u64,
+    /// The max timeout for a channel (as measured by the frame L1 block number)
+    pub channel_timeout: u64,
+    /// Number of L1 blocks in a sequence window
+    pub seq_window_size: u64,
+    /// Maximum timestamp drift
+    pub max_seq_drift: u64,
+    /// Network blocktime
+    pub blocktime: u64,
+}
+
+impl ChainConfig {
+    pub const fn optimism() -> Self {
+        Self {
+            system_config: SystemConfig {
+                batch_sender: address!("6887246668a3b87f54deb3b94ba47a6f63f32985"),
+                gas_limit: uint!(30_000_000_U256),
+                l1_fee_overhead: uint!(188_U256),
+                l1_fee_scalar: uint!(684000_U256),
+                unsafe_block_signer: address!("AAAA45d9549EDA09E70937013520214382Ffc4A2"),
+            },
+            l1_attributes_depositor: address!("deaddeaddeaddeaddeaddeaddeaddeaddead0001"),
+            l1_attributes_contract: address!("4200000000000000000000000000000000000015"),
+            sequencer_fee_vault: address!("4200000000000000000000000000000000000011"),
+            batch_inbox: address!("ff00000000000000000000000000000000000010"),
+            deposit_contract: address!("bEb5Fc579115071764c7423A4f12eDde41f106Ed"),
+            system_config_contract: address!("229047fed2591dbec1eF1118d64F7aF3dB9EB290"),
+            max_channel_bank_size: 100_000_000,
+            channel_timeout: 300,
+            seq_window_size: 3600,
+            max_seq_drift: 600,
+            blocktime: 2,
+        }
+    }
+}
+
+pub const OPTIMISM_CHAIN_SPEC: ChainConfig = ChainConfig::optimism();
diff --git a/lib/src/optimism/deposits.rs b/lib/src/optimism/deposits.rs
new file mode 100644
index 000000000..ecefb1734
--- /dev/null
+++ b/lib/src/optimism/deposits.rs
@@ -0,0 +1,154 @@
+// Copyright 2023 RISC Zero, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use alloy_sol_types::{sol_data, SolType};
+use anyhow::{anyhow, ensure, Context};
+use zeth_primitives::{
+    fixed_bytes, keccak256,
+    receipt::Log,
+    transactions::{
+        ethereum::{EthereumTxEssence, TransactionKind},
+        optimism::{OptimismTxEssence, TxEssenceOptimismDeposited},
+        Transaction,
+    },
+    Address, Bloom, BloomInput, B256, U160, U256,
+};
+
+use super::{batcher_db::BlockInput, config::ChainConfig};
+
+/// Signature of the deposit transaction event, i.e.
+/// keccak-256 hash of "TransactionDeposited(address,address,uint256,bytes)"
+const TRANSACTION_DEPOSITED_SIGNATURE: B256 =
+    fixed_bytes!("b3813568d9991fc951961fcb4c784893574240a28925604d09fc577c55bb7c32");
+/// Version of the deposit transaction event.
+const TRANSACTION_DEPOSITED_VERSION: B256 = B256::ZERO;
+
+/// Extracts deposits from the given block.
+pub fn extract_transactions(
+    config: &ChainConfig,
+    input: &BlockInput<EthereumTxEssence>,
+) -> anyhow::Result<Vec<Transaction<OptimismTxEssence>>> {
+    let block_hash = input.block_header.hash();
+
+    // if the bloom filter does not contain the corresponding topics, we have the guarantee
+    // that there are no deposits in the block
+    if !can_contain(&config.deposit_contract, &input.block_header.logs_bloom) {
+        return Ok(vec![]);
+    }
+
+    let receipts = input.receipts.as_ref().context("receipts missing")?;
+
+    let mut deposits = Vec::new();
+
+    let mut log_index = 0_usize;
+    for receipt in receipts {
+        let receipt = &receipt.payload;
+
+        // skip failed transactions
+        if !receipt.success {
+            log_index += receipt.logs.len();
+            continue;
+        }
+        // we could skip the transaction if the Bloom filter does not contain the deposit log, but
+        // since hashing is quite expensive on the guest, it seems faster to always check the
+        // logs
+
+        // parse all the logs for deposit transactions
+        for log in &receipt.logs {
+            if log.address == config.deposit_contract
+                && log.topics[0] == TRANSACTION_DEPOSITED_SIGNATURE
+            {
+                deposits.push(
+                    to_deposit_transaction(block_hash, log_index, log)
+                        .context("invalid deposit")?,
+                );
+            }
+
+            log_index += 1;
+        }
+    }
+
+    Ok(deposits)
+}
+
+/// Returns whether the given Bloom filter can contain a deposit log.
+pub fn can_contain(address: &Address, bloom: &Bloom) -> bool {
+    let input = BloomInput::Raw(address.as_slice());
+    if !bloom.contains_input(input) {
+        return false;
+    }
+    let input = BloomInput::Raw(TRANSACTION_DEPOSITED_SIGNATURE.as_slice());
+    if !bloom.contains_input(input) {
+        return false;
+    }
+    true
+}
+
+/// Converts a deposit log into a transaction.
+fn to_deposit_transaction(
+    block_hash: B256,
+    log_index: usize,
+    log: &Log,
+) -> anyhow::Result<Transaction<OptimismTxEssence>> {
+    let from = U160::try_from_be_slice(&log.topics[1][12..])
+        .context("invalid from")?
+        .into();
+    let to = U160::try_from_be_slice(&log.topics[2][12..])
+        .context("invalid to")?
+        .into();
+
+    // TODO: it is not 100% defined, what happens if the version is not 0
+    // it is assumed that this is an error and must not be ignored
+    ensure!(
+        log.topics[3] == TRANSACTION_DEPOSITED_VERSION,
+        "invalid version"
+    );
+
+    // the log data is just an ABI encoded `bytes` type representing the opaque_data
+    let opaque_data: Vec<u8> = sol_data::Bytes::abi_decode(&log.data, true)
+        .map_err(|e| anyhow!(e))
+        .context("invalid data")?;
+
+    ensure!(opaque_data.len() >= 73, "invalid opaque_data");
+    let mint = U256::try_from_be_slice(&opaque_data[0..32]).context("invalid mint")?;
+    let value = U256::try_from_be_slice(&opaque_data[32..64]).context("invalid value")?;
+    let gas_limit = U256::try_from_be_slice(&opaque_data[64..72]).context("invalid gas_limit")?;
+    let is_creation = opaque_data[72] != 0;
+    let data = opaque_data[73..].to_vec();
+
+    // compute the source hash
+    let h = keccak256([block_hash.0, U256::from(log_index).to_be_bytes()].concat());
+    let source_hash = keccak256([U256::from(0).to_be_bytes(), h.0].concat());
+
+    // construct the transaction
+    let essence = OptimismTxEssence::OptimismDeposited(TxEssenceOptimismDeposited {
+        source_hash,
+        from,
+        to: if is_creation {
+            TransactionKind::Create
+        } else {
+            TransactionKind::Call(to)
+        },
+        mint,
+        value,
+        gas_limit,
+        is_system_tx: false,
+        data: data.into(),
+    });
+
+    Ok(Transaction {
+        essence,
+        signature: Default::default(),
+    })
+}
diff --git a/lib/src/optimism/mod.rs b/lib/src/optimism/mod.rs
new file mode 100644
index 000000000..370b110a8
--- /dev/null
+++ b/lib/src/optimism/mod.rs
@@ -0,0 +1,432 @@
+// Copyright 2024 RISC Zero, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use core::iter::once;
+
+use alloy_sol_types::{sol, SolInterface};
+use anyhow::{anyhow, bail, ensure, Context, Result};
+#[cfg(not(target_os = "zkvm"))]
+use log::info;
+use serde::{Deserialize, Serialize};
+use zeth_primitives::{
+    batch::Batch,
+    keccak::keccak,
+    transactions::{
+        ethereum::TransactionKind,
+        optimism::{OptimismTxEssence, TxEssenceOptimismDeposited},
+        Transaction, TxEssence,
+    },
+    trie::MptNode,
+    uint, Address, BlockHash, BlockNumber, FixedBytes, RlpBytes, B256, U256,
+};
+
+use crate::{
+    consts::ONE,
+    optimism::{
+        batcher::{Batcher, BlockId, L2BlockInfo},
+        batcher_db::BatcherDb,
+        config::ChainConfig,
+    },
+};
+
+pub mod batcher;
+pub mod batcher_channel;
+pub mod batcher_db;
+pub mod config;
+pub mod deposits;
+pub mod system_config;
+
+sol! {
+    /// The values stored by the L1 Attributes Predeployed Contract.
+    #[derive(Debug)]
+    interface OpSystemInfo {
+        function setL1BlockValues(
+            /// L1 block attributes.
+            uint64 number,
+            uint64 timestamp,
+            uint256 basefee,
+            bytes32 hash,
+            /// Sequence number in the current epoch.
+            uint64 sequence_number,
+            /// A versioned hash of the current authorized batcher sender.
+            bytes32 batcher_hash,
+            /// The L1 fee overhead to apply to L1 cost computation of transactions.
+            uint256 l1_fee_overhead,
+            /// The L1 fee scalar to apply to L1 cost computation of transactions.
+            uint256 l1_fee_scalar
+        );
+    }
+}
+
+/// Represents the input for the derivation process.
+#[derive(Debug, Clone, Deserialize, Serialize)]
+pub struct DeriveInput<D> {
+    /// Database containing the blocks.
+    pub db: D,
+    /// Block number of the L2 head.
+    pub op_head_block_no: u64,
+    /// Block count for the operation.
+    pub op_derive_block_count: u64,
+}
+
+/// Represents the output of the derivation process.
+#[derive(Debug, Clone, Deserialize, Eq, PartialEq, Serialize)]
+pub struct DeriveOutput {
+    /// Ethereum tail block.
+    pub eth_tail: (BlockNumber, BlockHash),
+    /// Optimism head block.
+    pub op_head: (BlockNumber, BlockHash),
+    /// Derived Optimism blocks.
+    pub derived_op_blocks: Vec<(BlockNumber, BlockHash)>,
+}
+
+/// Implementation of the actual derivation process.
+pub struct DeriveMachine<D> {
+    /// Input for the derivation process.
+    pub derive_input: DeriveInput<D>,
+
+    op_head_block_hash: BlockHash,
+    op_block_no: u64,
+    op_block_seq_no: u64,
+    op_batcher: Batcher,
+}
+
+impl<D: BatcherDb> DeriveMachine<D> {
+    /// Creates a new instance of DeriveMachine.
+    pub fn new(chain_config: &ChainConfig, mut derive_input: DeriveInput<D>) -> Result<Self> {
+        derive_input.db.validate()?;
+
+        let op_block_no = derive_input.op_head_block_no;
+
+        // read system config from op_head (seq_no/epoch_no..etc)
+        let op_head = derive_input.db.get_full_op_block(op_block_no)?;
+        let op_head_block_hash = op_head.block_header.hash();
+
+        #[cfg(not(target_os = "zkvm"))]
+        info!(
+            "Fetched Op head (block no {}) {}",
+            op_block_no, op_head_block_hash
+        );
+
+        // the first transaction in a block MUST be a L1 attributes deposited transaction
+        let l1_attributes_tx = &op_head
+            .transactions
+            .first()
+            .context("block is empty")?
+            .essence;
+        if let Err(err) = validate_l1_attributes_deposited_tx(chain_config, l1_attributes_tx) {
+            bail!(
+                "First transaction in block is not a valid L1 attributes deposited transaction: {err}"
+            );
+        }
+        // decode the L1 attributes deposited transaction
+        let set_l1_block_values = {
+            let call = OpSystemInfo::OpSystemInfoCalls::abi_decode(l1_attributes_tx.data(), true)
+                .map_err(|e| anyhow!(e))
+                .context("invalid L1 attributes data")?;
+            match call {
+                OpSystemInfo::OpSystemInfoCalls::setL1BlockValues(x) => x,
+            }
+        };
+
+        let op_block_seq_no = set_l1_block_values.sequence_number;
+
+        // check that the correct L1 block is in the database
+        let eth_block_no = set_l1_block_values.number;
+        let eth_head = derive_input.db.get_full_eth_block(eth_block_no)?;
+        ensure!(
+            eth_head.block_header.hash() == set_l1_block_values.hash,
+            "Ethereum head block hash mismatch"
+        );
+        #[cfg(not(target_os = "zkvm"))]
+        info!(
+            "Fetched Eth head (block no {eth_block_no}) {}",
+            set_l1_block_values.hash
+        );
+
+        let op_batcher = {
+            // copy the chain config and update the system config
+            let mut op_chain_config = chain_config.clone();
+            op_chain_config.system_config.batch_sender =
+                Address::from_slice(&set_l1_block_values.batcher_hash.as_slice()[12..]);
+            op_chain_config.system_config.l1_fee_overhead = set_l1_block_values.l1_fee_overhead;
+            op_chain_config.system_config.l1_fee_scalar = set_l1_block_values.l1_fee_scalar;
+
+            Batcher::new(
+                op_chain_config,
+                L2BlockInfo {
+                    hash: op_head_block_hash,
+                    timestamp: op_head.block_header.timestamp.try_into().unwrap(),
+                    l1_origin: BlockId {
+                        number: set_l1_block_values.number,
+                        hash: set_l1_block_values.hash,
+                    },
+                },
+                eth_head,
+            )?
+        };
+
+        Ok(DeriveMachine {
+            derive_input,
+            op_head_block_hash,
+            op_block_no,
+            op_block_seq_no,
+            op_batcher,
+        })
+    }
+
+    pub fn derive(&mut self) -> Result<DeriveOutput> {
+        let target_block_no =
+            self.derive_input.op_head_block_no + self.derive_input.op_derive_block_count;
+
+        let mut derived_op_blocks = Vec::new();
+        let mut process_next_eth_block = false;
+
+        while self.op_block_no < target_block_no {
+            #[cfg(not(target_os = "zkvm"))]
+            info!(
+                "op_block_no = {}, eth_block_no = {}",
+                self.op_block_no, self.op_batcher.state.current_l1_block_number
+            );
+
+            // Process next Eth block. We do this on every iteration, except the first iteration.
+            // (The first iteration is handled by Batcher::new().)
+            if process_next_eth_block {
+                let eth_block = self
+                    .derive_input
+                    .db
+                    .get_full_eth_block(self.op_batcher.state.current_l1_block_number + 1)
+                    .context("block not found")?;
+
+                self.op_batcher
+                    .process_l1_block(eth_block)
+                    .context("failed to create batcher transactions")?;
+            }
+            process_next_eth_block = true;
+
+            // Process batches
+            while let Some(op_batch) = self.op_batcher.read_batch()? {
+                // Process the batch
+                self.op_block_no += 1;
+
+                #[cfg(not(target_os = "zkvm"))]
+                info!(
+                    "Read batch for Op block {}: timestamp={}, epoch={}, tx count={}, parent hash={:?}",
+                    self.op_block_no,
+                    op_batch.0.timestamp,
+                    op_batch.0.epoch_num,
+                    op_batch.0.transactions.len(),
+                    op_batch.0.parent_hash,
+                );
+
+                // Update sequence number (and fetch deposits if start of new epoch)
+                let l2_safe_head = &self.op_batcher.state.safe_head;
+                let deposits = if l2_safe_head.l1_origin.number != op_batch.0.epoch_num {
+                    self.op_block_seq_no = 0;
+                    self.op_batcher.state.do_next_epoch()?;
+
+                    self.op_batcher
+                        .state
+                        .epoch
+                        .deposits
+                        .iter()
+                        .map(|tx| tx.to_rlp())
+                        .collect()
+                } else {
+                    self.op_block_seq_no += 1;
+
+                    Vec::new()
+                };
+
+                // obtain verified op block header
+                let new_op_head = {
+                    // load the next op block header
+                    let new_op_head = self
+                        .derive_input
+                        .db
+                        .get_op_block_header(self.op_block_no)
+                        .context("op block not found")?;
+
+                    // Verify that the op block header loaded from the DB matches the payload
+                    // attributes of the batch.
+                    ensure!(
+                        new_op_head.parent_hash == self.op_batcher.state.safe_head.hash,
+                        "Invalid op block parent hash"
+                    );
+                    ensure!(
+                        new_op_head.beneficiary == self.op_batcher.config.sequencer_fee_vault,
+                        "Invalid op block beneficiary"
+                    );
+                    ensure!(
+                        new_op_head.gas_limit == self.op_batcher.config.system_config.gas_limit,
+                        "Invalid op block gas limit"
+                    );
+                    ensure!(
+                        new_op_head.timestamp == U256::from(op_batch.0.timestamp),
+                        "Invalid op block timestamp"
+                    );
+                    ensure!(
+                        new_op_head.extra_data.is_empty(),
+                        "Invalid op block extra data"
+                    );
+
+                    // verify that the new op head mix hash matches the mix hash of the L1 block
+                    {
+                        let l1_epoch_header = self
+                            .derive_input
+                            .db
+                            .get_full_eth_block(op_batch.0.epoch_num)
+                            .context("eth block not found")?
+                            .block_header
+                            .clone();
+                        ensure!(
+                            new_op_head.mix_hash == l1_epoch_header.mix_hash,
+                            "Invalid op block mix hash"
+                        );
+                    }
+
+                    // verify that the new op head transactions match the batch transactions
+                    {
+                        // From the spec:
+                        // The first transaction MUST be a L1 attributes deposited transaction,
+                        // followed by an array of zero-or-more user-deposited transactions.
+                        let l1_attributes_tx = self.derive_l1_attributes_deposited_tx(&op_batch);
+                        let derived_transactions = once(l1_attributes_tx.to_rlp())
+                            .chain(deposits)
+                            .chain(op_batch.0.transactions.iter().map(|tx| tx.to_vec()))
+                            .enumerate();
+
+                        let mut tx_trie = MptNode::default();
+                        for (tx_no, tx) in derived_transactions {
+                            let trie_key = tx_no.to_rlp();
+                            tx_trie.insert(&trie_key, tx)?;
+                        }
+
+                        ensure!(
+                            tx_trie.hash() == new_op_head.transactions_root,
+                            "Invalid op block transactions"
+                        );
+                    }
+
+                    ensure!(
+                        new_op_head.withdrawals_root.is_none(),
+                        "Invalid op block withdrawals"
+                    );
+
+                    new_op_head
+                };
+
+                let new_op_head_hash = new_op_head.hash();
+
+                #[cfg(not(target_os = "zkvm"))]
+                info!(
+                    "Derived Op block {} w/ hash {new_op_head_hash}",
+                    new_op_head.number
+                );
+
+                self.op_batcher.state.safe_head = L2BlockInfo {
+                    hash: new_op_head_hash,
+                    timestamp: new_op_head.timestamp.try_into().unwrap(),
+                    l1_origin: BlockId {
+                        number: self.op_batcher.state.epoch.number,
+                        hash: self.op_batcher.state.epoch.hash,
+                    },
+                };
+
+                derived_op_blocks.push((new_op_head.number, new_op_head_hash));
+
+                if self.op_block_no == target_block_no {
+                    break;
+                }
+            }
+        }
+
+        Ok(DeriveOutput {
+            eth_tail: (
+                self.op_batcher.state.current_l1_block_number,
+                self.op_batcher.state.current_l1_block_hash,
+            ),
+            op_head: (self.derive_input.op_head_block_no, self.op_head_block_hash),
+            derived_op_blocks,
+        })
+    }
+
+    fn derive_l1_attributes_deposited_tx(
+        &mut self,
+        op_batch: &Batch,
+    ) -> Transaction<OptimismTxEssence> {
+        let batcher_hash = {
+            let all_zero: FixedBytes<12> = FixedBytes::ZERO;
+            all_zero.concat_const::<20, 32>(self.op_batcher.config.system_config.batch_sender.0)
+        };
+
+        let set_l1_block_values =
+            OpSystemInfo::OpSystemInfoCalls::setL1BlockValues(OpSystemInfo::setL1BlockValuesCall {
+                number: self.op_batcher.state.epoch.number,
+                timestamp: self.op_batcher.state.epoch.timestamp,
+                basefee: self.op_batcher.state.epoch.base_fee_per_gas,
+                hash: self.op_batcher.state.epoch.hash,
+                sequence_number: self.op_block_seq_no,
+                batcher_hash,
+                l1_fee_overhead: self.op_batcher.config.system_config.l1_fee_overhead,
+                l1_fee_scalar: self.op_batcher.config.system_config.l1_fee_scalar,
+            });
+
+        let source_hash: B256 = {
+            let l1_block_hash = op_batch.0.epoch_hash.0;
+            let seq_number = U256::from(self.op_block_seq_no).to_be_bytes::<32>();
+            let source_hash_sequencing = keccak([l1_block_hash, seq_number].concat());
+            keccak([ONE.to_be_bytes::<32>(), source_hash_sequencing].concat()).into()
+        };
+        let config = &self.op_batcher.config;
+
+        Transaction {
+            essence: OptimismTxEssence::OptimismDeposited(TxEssenceOptimismDeposited {
+                source_hash,
+                from: config.l1_attributes_depositor,
+                to: TransactionKind::Call(config.l1_attributes_contract),
+                mint: Default::default(),
+                value: Default::default(),
+                gas_limit: uint!(1_000_000_U256),
+                is_system_tx: false,
+                data: set_l1_block_values.abi_encode().into(),
+            }),
+            signature: Default::default(),
+        }
+    }
+}
+
+fn validate_l1_attributes_deposited_tx(config: &ChainConfig, tx: &OptimismTxEssence) -> Result<()> {
+    match tx {
+        OptimismTxEssence::Ethereum(_) => {
+            bail!("No Optimism deposit transaction");
+        }
+        OptimismTxEssence::OptimismDeposited(op) => {
+            ensure!(
+                op.from == config.l1_attributes_depositor,
+                "Invalid from address"
+            );
+            ensure!(
+                matches!(op.to, TransactionKind::Call(addr) if addr == config.l1_attributes_contract),
+                "Invalid to address"
+            );
+            ensure!(op.mint == U256::ZERO, "Invalid mint value");
+            ensure!(op.value == U256::ZERO, "Invalid value");
+            ensure!(op.gas_limit == uint!(1_000_000_U256), "Invalid gas limit");
+            ensure!(!op.is_system_tx, "Invalid is_system_tx value");
+        }
+    }
+
+    Ok(())
+}
diff --git a/lib/src/optimism/system_config.rs b/lib/src/optimism/system_config.rs
new file mode 100644
index 000000000..93ece36b1
--- /dev/null
+++ b/lib/src/optimism/system_config.rs
@@ -0,0 +1,146 @@
+// Copyright 2023 RISC Zero, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use anyhow::{self, bail, ensure, Context, Ok};
+use serde::{Deserialize, Serialize};
+use zeth_primitives::{
+    b256, transactions::ethereum::EthereumTxEssence, Address, Bloom, BloomInput, B256, U256,
+};
+
+use super::batcher_db::BlockInput;
+
+/// Signature of the deposit transaction event, i.e.
+/// keccak-256 hash of "ConfigUpdate(uint256,uint8,bytes)"
+const CONFIG_UPDATE_SIGNATURE: B256 =
+    b256!("1d2b0bda21d56b8bd12d4f94ebacffdfb35f5e226f84b461103bb8beab6353be");
+/// Version of the deposit transaction event.
+const CONFIG_UPDATE_VERSION: B256 = B256::ZERO;
+
+/// Optimism system config contract values
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct SystemConfig {
+    /// Batch sender address
+    pub batch_sender: Address,
+    /// L2 gas limit
+    pub gas_limit: U256,
+    /// Fee overhead
+    pub l1_fee_overhead: U256,
+    /// Fee scalar
+    pub l1_fee_scalar: U256,
+    /// Sequencer's signer for unsafe blocks
+    pub unsafe_block_signer: Address,
+}
+
+impl SystemConfig {
+    /// Updates the system config based on the given input. Returns whether the config was
+    /// updated.
+    pub fn update(
+        &mut self,
+        system_config_contract: &Address,
+        input: &BlockInput<EthereumTxEssence>,
+    ) -> anyhow::Result<bool> {
+        let mut updated = false;
+
+        // if the bloom filter does not contain the corresponding topics, we have the guarantee
+        // that there are no config updates in the block
+        if !can_contain(system_config_contract, &input.block_header.logs_bloom) {
+            return Ok(updated);
+        }
+
+        #[cfg(not(target_os = "zkvm"))]
+        log::info!("Process config");
+
+        let receipts = input.receipts.as_ref().context("receipts missing")?;
+        for receipt in receipts {
+            let receipt = &receipt.payload;
+
+            // skip failed transactions
+            if !receipt.success {
+                continue;
+            }
+
+            for log in &receipt.logs {
+                // the log event contract address must match the system config contract
+                // the first log event topic must match the ConfigUpdate signature
+                if &log.address == system_config_contract
+                    && log.topics[0] == CONFIG_UPDATE_SIGNATURE
+                {
+                    updated = true;
+
+                    // the second topic determines the version
+                    ensure!(log.topics[1] == CONFIG_UPDATE_VERSION, "invalid version");
+
+                    // the third topic determines the type of update
+                    let update_type: u64 = U256::from_be_bytes(log.topics[2].0)
+                        .try_into()
+                        .expect("invalid update type");
+
+                    // TODO: use proper ABI decoding of the data
+                    match update_type {
+                        // type 0: batcherHash overwrite, as bytes32 payload
+                        0 => {
+                            let addr_bytes = log
+                                .data
+                                .get(76..96)
+                                .context("invalid batch sender address")?;
+
+                            self.batch_sender = Address::from_slice(addr_bytes);
+                        }
+                        // type 1: overhead and scalar overwrite, as two packed uint256 entries
+                        1 => {
+                            let fee_overhead = log.data.get(64..96).context("invalid data")?;
+                            let fee_scalar = log.data.get(96..128).context("invalid data")?;
+
+                            self.l1_fee_overhead = U256::try_from_be_slice(fee_overhead)
+                                .context("invalid overhead")?;
+                            self.l1_fee_scalar =
+                                U256::try_from_be_slice(fee_scalar).context("invalid scalar")?;
+                        }
+                        // type 2: gasLimit overwrite, as uint64 payload
+                        2 => {
+                            let gas_limit = log.data.get(64..96).context("invalid data")?;
+
+                            self.gas_limit =
+                                U256::try_from_be_slice(gas_limit).context("invalid gas limit")?;
+                        }
+                        // type 3: unsafeBlockSigner overwrite, as address payload
+                        3 => {
+                            let addr_bytes = log
+                                .data
+                                .get(76..96)
+                                .context("invalid unsafe block signer address")?;
+
+                            self.unsafe_block_signer = Address::from_slice(addr_bytes);
+                        }
+                        _ => {
+                            bail!("invalid update type");
+                        }
+                    }
+                }
+            }
+        }
+
+        Ok(updated)
+    }
+}
+
+/// Returns whether the given Bloom filter can contain a config update log.
+pub fn can_contain(address: &Address, bloom: &Bloom) -> bool {
+    let input = BloomInput::Raw(address.as_slice());
+    if !bloom.contains_input(input) {
+        return false;
+    }
+    let input = BloomInput::Raw(CONFIG_UPDATE_SIGNATURE.as_slice());
+    !bloom.contains_input(input)
+}
diff --git a/lib/src/taiko/block_builder.rs b/lib/src/taiko/block_builder.rs
deleted file mode 100644
index 43fb16430..000000000
--- a/lib/src/taiko/block_builder.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-use zeth_primitives::transactions::ethereum::EthereumTxEssence;
-
-use crate::{
-    block_builder::{ConfiguredBlockBuilder, NetworkStrategyBundle},
-    finalization::BuildFromMemDbStrategy,
-    initialization::MemDbInitStrategy,
-    mem_db::MemDb,
-    taiko::{execute::TaikoTxExecStrategy, prepare::TaikoHeaderPrepStrategy},
-};
-
-pub struct TaikoStrategyBundle {}
-
-impl NetworkStrategyBundle for TaikoStrategyBundle {
-    type Database = MemDb;
-    type TxEssence = EthereumTxEssence;
-    type DbInitStrategy = MemDbInitStrategy;
-    type HeaderPrepStrategy = TaikoHeaderPrepStrategy;
-    type TxExecStrategy = TaikoTxExecStrategy;
-    type BlockBuildStrategy = BuildFromMemDbStrategy;
-}
-
-pub type TaikoBlockBuilder<'a> = ConfiguredBlockBuilder<'a, TaikoStrategyBundle>;
diff --git a/primitives/src/taiko/consts.rs b/lib/src/taiko/consts.rs
similarity index 59%
rename from primitives/src/taiko/consts.rs
rename to lib/src/taiko/consts.rs
index 1807b8d74..cc43e3cc9 100644
--- a/primitives/src/taiko/consts.rs
+++ b/lib/src/taiko/consts.rs
@@ -1,7 +1,9 @@
 use core::str::FromStr;
 
 use alloy_primitives::{uint, Address, U256};
+use anyhow::{anyhow, bail, Result};
 use once_cell::sync::Lazy;
+use zeth_primitives::transactions::EthereumTransaction;
 
 pub static ANCHOR_GAS_LIMIT: u64 = 250_000;
 pub static MAX_TX_LIST: usize = 79;
@@ -12,6 +14,28 @@ pub static GOLDEN_TOUCH_ACCOUNT: Lazy<Address> = Lazy::new(|| {
         .expect("invalid golden touch account")
 });
 
+macro_rules! taiko_contracts {
+    ($name:ident) => {{
+        use crate::taiko::consts::$name::*;
+        Ok((
+            *L1_CONTRACT,
+            *L2_CONTRACT,
+            *L1_SIGNAL_SERVICE,
+            *L2_SIGNAL_SERVICE,
+        ))
+    }};
+}
+
+pub fn get_contracts(name: &str) -> Result<(Address, Address, Address, Address)> {
+    match name {
+        "testnet" => taiko_contracts!(testnet),
+        "internal_devnet_a" => taiko_contracts!(internal_devnet_a),
+        "internal_devnet_b" => taiko_contracts!(internal_devnet_b),
+        #[allow(clippy::needless_return)]
+        _ => bail!("invalid chain name: {name}"),
+    }
+}
+
 pub mod testnet {
     use super::*;
     pub static CHAIN_ID: u64 = 167008;
@@ -79,3 +103,39 @@ pub mod internal_devnet_b {
             .expect("invalid l2 signal service")
     });
 }
+
+static GX1: Lazy<U256> =
+    Lazy::new(|| uint!(0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798_U256));
+static N: Lazy<U256> =
+    Lazy::new(|| uint!(0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141_U256));
+static GX1_MUL_PRIVATEKEY: Lazy<U256> =
+    Lazy::new(|| uint!(0x4341adf5a780b4a87939938fd7a032f6e6664c7da553c121d3b4947429639122_U256));
+static GX2: Lazy<U256> =
+    Lazy::new(|| uint!(0xc6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5_U256));
+
+/// check the anchor signature with fixed K value
+pub fn check_anchor_signature(anchor: &EthereumTransaction) -> Result<()> {
+    let sign = &anchor.signature;
+    if sign.r == *GX1 {
+        return Ok(());
+    }
+    let msg_hash = anchor.essence.signing_hash();
+    let msg_hash: U256 = msg_hash.into();
+    if sign.r == *GX2 {
+        // when r == GX2 require s == 0 if k == 1
+        // alias: when r == GX2 require N == msg_hash + *GX1_MUL_PRIVATEKEY
+        if *N != msg_hash + *GX1_MUL_PRIVATEKEY {
+            bail!(
+                "r == GX2, but N != msg_hash + *GX1_MUL_PRIVATEKEY, N: {}, msg_hash: {msg_hash}, *GX1_MUL_PRIVATEKEY: {}",
+                *N, *GX1_MUL_PRIVATEKEY
+            );
+        }
+        return Ok(());
+    }
+    Err(anyhow!(
+        "r != *GX1 && r != GX2, r: {}, *GX1: {}, GX2: {}",
+        sign.r,
+        *GX1,
+        *GX2
+    ))
+}
diff --git a/lib/src/taiko/execute.rs b/lib/src/taiko/execute.rs
deleted file mode 100644
index 34a09a6c7..000000000
--- a/lib/src/taiko/execute.rs
+++ /dev/null
@@ -1,400 +0,0 @@
-// Copyright 2023 RISC Zero, Inc.
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-//     http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-use alloc::vec;
-use core::{fmt::Debug, mem::take, str::from_utf8};
-
-use anyhow::{anyhow, bail, Context};
-#[cfg(all(not(target_os = "zkvm"), not(feature = "server")))]
-use log::debug;
-use revm::{
-    primitives::{Account, Address, ResultAndState, SpecId, TransactTo, TxEnv, U256},
-    Database, DatabaseCommit, EVM,
-};
-#[cfg(all(not(target_os = "zkvm"), feature = "server"))]
-use tracing::debug;
-use zeth_primitives::{
-    receipt::Receipt,
-    transactions::{
-        ethereum::{EthereumTxEssence, TransactionKind},
-        TxEssence,
-    },
-    trie::MptNode,
-    Bloom, RlpBytes,
-};
-
-use crate::{
-    block_builder::BlockBuilder,
-    consts,
-    consts::{ChainSpec, GWEI_TO_WEI, MIN_SPEC_ID},
-    execution::TxExecStrategy,
-    guest_mem_forget,
-};
-
-pub struct TaikoTxExecStrategy {}
-
-impl TxExecStrategy<EthereumTxEssence> for TaikoTxExecStrategy {
-    fn execute_transactions<D>(
-        mut block_builder: BlockBuilder<D, EthereumTxEssence>,
-    ) -> anyhow::Result<BlockBuilder<D, EthereumTxEssence>>
-    where
-        D: Database + DatabaseCommit,
-        <D as Database>::Error: Debug,
-    {
-        let header = block_builder
-            .header
-            .as_mut()
-            .expect("Header is not initialized");
-        // Compute the spec id
-        let spec_id = block_builder.chain_spec.spec_id(header.number);
-        if !SpecId::enabled(spec_id, MIN_SPEC_ID) {
-            bail!(
-                "Invalid protocol version: expected >= {:?}, got {:?}",
-                MIN_SPEC_ID,
-                spec_id,
-            )
-        }
-
-        #[cfg(not(target_os = "zkvm"))]
-        {
-            use chrono::{TimeZone, Utc};
-            use log::info;
-            let dt = Utc
-                .timestamp_opt(block_builder.input.timestamp.try_into().unwrap(), 0)
-                .unwrap();
-
-            info!("Block no. {}", header.number);
-            info!("  EVM spec ID: {:?}", spec_id);
-            info!("  Timestamp: {}", dt);
-            info!("  Transactions: {}", block_builder.input.transactions.len());
-            info!("  Withdrawals: {}", block_builder.input.withdrawals.len());
-            info!("  Fee Recipient: {:?}", block_builder.input.beneficiary);
-            info!("  Gas limit: {}", block_builder.input.gas_limit);
-            info!("  Base fee per gas: {}", header.base_fee_per_gas);
-            info!("  Extra data: {:?}", block_builder.input.extra_data);
-        }
-
-        // initialize the EVM
-        let mut evm = EVM::new();
-
-        // set the EVM configuration
-        evm.env.cfg.chain_id = block_builder.chain_spec.chain_id();
-        evm.env.cfg.spec_id = spec_id;
-
-        // set the EVM block environment
-        evm.env.block.number = header.number.try_into().unwrap();
-        evm.env.block.coinbase = block_builder.input.beneficiary;
-        evm.env.block.timestamp = header.timestamp;
-        evm.env.block.difficulty = U256::ZERO;
-        evm.env.block.prevrandao = Some(header.mix_hash);
-        evm.env.block.basefee = header.base_fee_per_gas;
-        evm.env.block.gas_limit = block_builder.input.gas_limit;
-
-        evm.database(block_builder.db.take().unwrap());
-
-        // bloom filter over all transaction logs
-        let mut logs_bloom = Bloom::default();
-        // keep track of the gas used over all transactions
-        let mut cumulative_gas_used = consts::ZERO;
-
-        // process all the transactions
-        let mut tx_trie = MptNode::default();
-        let mut txs = vec![];
-        let mut receipt_trie = MptNode::default();
-        let mut actual_tx_no = 0usize;
-        for (tx_no, tx) in take(&mut block_builder.input.transactions)
-            .into_iter()
-            .enumerate()
-        {
-            // anchor transaction must be executed successfully
-            let is_anchor = tx_no == 0;
-            // verify the transaction signature
-            let tx_from = match tx.recover_from() {
-                Ok(tx_from) => tx_from,
-                Err(err) => {
-                    if is_anchor {
-                        bail!("Error recovering anchor signature: {}", err);
-                    }
-                    #[cfg(not(target_os = "zkvm"))]
-                    debug!(
-                        "Error recovering address for transaction {}, error: {}",
-                        tx_no, err
-                    );
-                    continue;
-                }
-            };
-
-            #[cfg(not(target_os = "zkvm"))]
-            {
-                let tx_hash = tx.hash();
-                debug!("Tx no. {} (hash: {})", tx_no, tx_hash);
-                debug!("  Type: {}", tx.essence.tx_type());
-                debug!("  Fr: {:?}", tx_from);
-                debug!("  To: {:?}", tx.essence.to().unwrap_or_default());
-            }
-
-            // verify transaction gas
-            let block_available_gas = block_builder.input.gas_limit - cumulative_gas_used;
-            if block_available_gas < tx.essence.gas_limit() {
-                if is_anchor {
-                    bail!("Error at transaction {}: gas exceeds block limit", tx_no);
-                }
-                #[cfg(not(target_os = "zkvm"))]
-                debug!("Error at transaction {}: gas exceeds block limit", tx_no);
-                continue;
-            }
-
-            // process the transaction
-            fill_eth_tx_env(
-                block_builder.chain_spec,
-                &mut evm.env.tx,
-                &tx.essence,
-                tx_from,
-                is_anchor,
-            );
-            let ResultAndState { result, state } = match evm.transact() {
-                Ok(result) => result,
-                Err(err) => {
-                    if is_anchor {
-                        bail!("Error at transaction {}: {:?}", tx_no, err);
-                    }
-                    #[cfg(not(target_os = "zkvm"))]
-                    debug!("Error at transaction {}: {:?}", tx_no, err);
-                    continue;
-                }
-            };
-
-            if is_anchor && !result.is_success() {
-                bail!(
-                    "Error at transaction {}: execute anchor failed {:?}, output {:?}",
-                    tx_no,
-                    result,
-                    result.output().map(|o| from_utf8(o).unwrap_or_default())
-                );
-            }
-
-            let gas_used = result.gas_used().try_into().unwrap();
-            cumulative_gas_used = cumulative_gas_used.checked_add(gas_used).unwrap();
-
-            #[cfg(not(target_os = "zkvm"))]
-            debug!("  Ok: {:?}", result);
-
-            // create the receipt from the EVM result
-            let receipt = Receipt::new(
-                tx.essence.tx_type(),
-                result.is_success(),
-                cumulative_gas_used,
-                result.logs().into_iter().map(|log| log.into()).collect(),
-            );
-
-            // accumulate logs to the block bloom filter
-            logs_bloom.accrue_bloom(&receipt.payload.logs_bloom);
-
-            // Add receipt and tx to tries
-            let trie_key = actual_tx_no.to_rlp();
-            actual_tx_no += 1;
-            txs.push(tx.clone());
-            match tx_trie.insert_rlp(&trie_key, tx) {
-                Ok(_) => (),
-                Err(err) => {
-                    if is_anchor {
-                        bail!("Failed to insert transaction {}: {:?}", actual_tx_no, err);
-                    }
-                    #[cfg(not(target_os = "zkvm"))]
-                    debug!("Failed to insert transaction {}: {:?}", actual_tx_no, err);
-                }
-            }
-            match receipt_trie.insert_rlp(&trie_key, receipt) {
-                Ok(_) => (),
-                Err(err) => {
-                    if is_anchor {
-                        bail!("Failed to insert receipt {}: {:?}", actual_tx_no, err);
-                    }
-                    #[cfg(not(target_os = "zkvm"))]
-                    debug!("Failed to insert receipt {}: {:?}", actual_tx_no, err);
-                }
-            }
-
-            // update account states
-            #[cfg(not(target_os = "zkvm"))]
-            for (address, account) in &state {
-                if account.is_touched() {
-                    // log account
-                    debug!(
-                        "  State {:?} (is_selfdestructed={}, is_loaded_as_not_existing={}, is_created={}, is_empty={})",
-                        address,
-                        account.is_selfdestructed(),
-                        account.is_loaded_as_not_existing(),
-                        account.is_created(),
-                        account.is_empty(),
-                    );
-                    // log balance changes
-                    debug!(
-                        "     After balance: {} (Nonce: {})",
-                        account.info.balance, account.info.nonce
-                    );
-
-                    // log state changes
-                    for (addr, slot) in &account.storage {
-                        if slot.is_changed() {
-                            debug!("    Storage address: {:?}", addr);
-                            debug!("      Before: {:?}", slot.original_value());
-                            debug!("       After: {:?}", slot.present_value());
-                        }
-                    }
-                }
-            }
-
-            evm.db().unwrap().commit(state);
-        }
-
-        let mut db = evm.take_db();
-
-        // process withdrawals unconditionally after any transactions
-        let mut withdrawals_trie = MptNode::default();
-        for (i, withdrawal) in take(&mut block_builder.input.withdrawals)
-            .into_iter()
-            .enumerate()
-        {
-            // the withdrawal amount is given in Gwei
-            let amount_wei = GWEI_TO_WEI
-                .checked_mul(withdrawal.amount.try_into().unwrap())
-                .unwrap();
-
-            #[cfg(not(target_os = "zkvm"))]
-            {
-                debug!("Withdrawal no. {}", withdrawal.index);
-                debug!("  Recipient: {:?}", withdrawal.address);
-                debug!("  Value: {}", amount_wei);
-            }
-            // Credit withdrawal amount
-            increase_account_balance(&mut db, withdrawal.address, amount_wei)?;
-            // Add withdrawal to trie
-            withdrawals_trie
-                .insert_rlp(&i.to_rlp(), withdrawal)
-                .map_err(Into::<anyhow::Error>::into)
-                .with_context(|| "failed to insert withdrawal")?;
-        }
-
-        // Update result header with computed values
-        header.transactions_root = tx_trie.hash();
-        header.transactions = txs;
-        header.receipts_root = receipt_trie.hash();
-        header.logs_bloom = logs_bloom;
-        header.gas_used = cumulative_gas_used;
-        header.withdrawals_root = if spec_id < SpecId::SHANGHAI {
-            None
-        } else {
-            Some(withdrawals_trie.hash())
-        };
-
-        // Leak memory, save cycles
-        guest_mem_forget([tx_trie, receipt_trie, withdrawals_trie]);
-        // Return block builder with updated database
-        Ok(block_builder.with_db(db))
-    }
-}
-
-pub fn fill_eth_tx_env(
-    l2_chain_spec: &ChainSpec,
-    tx_env: &mut TxEnv,
-    essence: &EthereumTxEssence,
-    caller: Address,
-    is_anchor: bool,
-) {
-    // claim the anchor
-    tx_env.taiko.is_anchor = is_anchor;
-    // set the treasury address
-    tx_env.taiko.treasury = l2_chain_spec.l2_contract.unwrap();
-    match essence {
-        EthereumTxEssence::Legacy(tx) => {
-            tx_env.caller = caller;
-            tx_env.gas_limit = tx.gas_limit.try_into().unwrap();
-            tx_env.gas_price = tx.gas_price;
-            tx_env.gas_priority_fee = None;
-            tx_env.transact_to = if let TransactionKind::Call(to_addr) = tx.to {
-                TransactTo::Call(to_addr)
-            } else {
-                TransactTo::create()
-            };
-            tx_env.value = tx.value;
-            tx_env.data = tx.data.clone();
-            tx_env.chain_id = tx.chain_id;
-            tx_env.nonce = Some(tx.nonce);
-            tx_env.access_list.clear();
-        }
-        EthereumTxEssence::Eip2930(tx) => {
-            tx_env.caller = caller;
-            tx_env.gas_limit = tx.gas_limit.try_into().unwrap();
-            tx_env.gas_price = tx.gas_price;
-            tx_env.gas_priority_fee = None;
-            tx_env.transact_to = if let TransactionKind::Call(to_addr) = tx.to {
-                TransactTo::Call(to_addr)
-            } else {
-                TransactTo::create()
-            };
-            tx_env.value = tx.value;
-            tx_env.data = tx.data.clone();
-            tx_env.chain_id = Some(tx.chain_id);
-            tx_env.nonce = Some(tx.nonce);
-            tx_env.access_list = tx.access_list.clone().into();
-        }
-        EthereumTxEssence::Eip1559(tx) => {
-            tx_env.caller = caller;
-            tx_env.gas_limit = tx.gas_limit.try_into().unwrap();
-            tx_env.gas_price = tx.max_fee_per_gas;
-            tx_env.gas_priority_fee = Some(tx.max_priority_fee_per_gas);
-            tx_env.transact_to = if let TransactionKind::Call(to_addr) = tx.to {
-                TransactTo::Call(to_addr)
-            } else {
-                TransactTo::create()
-            };
-            tx_env.value = tx.value;
-            tx_env.data = tx.data.clone();
-            tx_env.chain_id = Some(tx.chain_id);
-            tx_env.nonce = Some(tx.nonce);
-            tx_env.access_list = tx.access_list.clone().into();
-        }
-    };
-}
-
-pub fn increase_account_balance<D>(
-    db: &mut D,
-    address: Address,
-    amount_wei: U256,
-) -> anyhow::Result<()>
-where
-    D: Database + DatabaseCommit,
-    <D as Database>::Error: Debug,
-{
-    // Read account from database
-    let mut account: Account = db
-        .basic(address)
-        .map_err(|db_err| {
-            anyhow!(
-                "Error increasing account balance for {}: {:?}",
-                address,
-                db_err
-            )
-        })?
-        .unwrap_or_default()
-        .into();
-    // Credit withdrawal amount
-    account.info.balance = account.info.balance.checked_add(amount_wei).unwrap();
-    account.mark_touch();
-    // Commit changes to database
-    db.commit([(address, account)].into());
-
-    Ok(())
-}
diff --git a/lib/src/taiko/host.rs b/lib/src/taiko/host.rs
new file mode 100644
index 000000000..3c38bcf10
--- /dev/null
+++ b/lib/src/taiko/host.rs
@@ -0,0 +1,258 @@
+use alloc::{string::String, vec::Vec};
+use std::path::PathBuf;
+
+use alloy_primitives::{Address, B256};
+use anyhow::{bail, ensure, Context, Result};
+use ethers_core::types::Transaction as EthersTransaction;
+use log::info;
+use rlp::{Decodable, DecoderError, Rlp};
+use zeth_primitives::{
+    block::Header, ethers::from_ethers_h256, transactions::ethereum::EthereumTxEssence,
+};
+
+use super::{provider::TaikoProvider, TaikoSystemInfo};
+use crate::{
+    builder::{prepare::EthHeaderPrepStrategy, BlockBuilder, TaikoStrategy, TkoTxExecStrategy},
+    consts::ChainSpec,
+    host::{
+        preflight::{new_preflight_input, Data, Preflight},
+        provider::{BlockQuery, ProofQuery},
+        provider_db::ProviderDb,
+    },
+    input::Input,
+    taiko::consts::{get_contracts, MAX_TX_LIST, MAX_TX_LIST_BYTES},
+};
+
+#[derive(Debug, Clone)]
+pub struct HostArgs {
+    pub l1_cache: Option<PathBuf>,
+    pub l1_rpc: Option<String>,
+    pub l2_cache: Option<PathBuf>,
+    pub l2_rpc: Option<String>,
+}
+
+pub fn init_taiko(
+    args: HostArgs,
+    l2_chain_spec: ChainSpec,
+    testnet: &str,
+    l2_block_no: u64,
+    graffiti: B256,
+    prover: Address,
+) -> Result<(Input<EthereumTxEssence>, TaikoSystemInfo)> {
+    let mut tp = TaikoProvider::new(
+        args.l1_cache.clone(),
+        args.l1_rpc.clone(),
+        args.l2_cache.clone(),
+        args.l2_rpc.clone(),
+    )?
+    .with_prover(prover)
+    .with_l2_spec(l2_chain_spec.clone())
+    .with_contracts(|| get_contracts(testnet));
+
+    let sys_info = derive_sys_info(&mut tp, l2_block_no, prover, graffiti)?;
+    tp.save()?;
+
+    let preflight_data =
+        TaikoStrategy::run_preflight(l2_chain_spec, args.l2_cache, args.l2_rpc, l2_block_no)?;
+
+    // Create the guest input from [Init]
+    let input: Input<EthereumTxEssence> = preflight_data
+        .clone()
+        .try_into()
+        .context("invalid preflight data")?;
+
+    Ok((input, sys_info))
+}
+
+pub fn derive_sys_info(
+    tp: &mut TaikoProvider,
+    l2_block_no: u64,
+    prover: Address,
+    graffiti: B256,
+) -> Result<TaikoSystemInfo> {
+    let l2_block = tp.get_l2_full_block(l2_block_no)?;
+    let l2_parent_block = tp.get_l2_full_block(l2_block_no - 1)?;
+
+    let (anchor_tx, anchor_call) = tp.get_anchor(&l2_block)?;
+
+    let l1_block_no = anchor_call.l1Height;
+    let l1_block = tp.get_l1_full_block(l1_block_no)?;
+    let l1_next_block = tp.get_l1_full_block(l1_block_no + 1)?;
+
+    let (proposal_call, proposal_event) = tp.get_proposal(l1_block_no, l2_block_no)?;
+
+    // 0. check anchor Tx
+    tp.check_anchor_tx(&anchor_tx, &l2_block)?;
+
+    // 1. check l2 parent gas used
+    ensure!(
+        l2_parent_block.gas_used == ethers_core::types::U256::from(anchor_call.parentGasUsed),
+        "parentGasUsed mismatch"
+    );
+
+    // 2. check l1 signal root
+    let Some(l1_signal_service) = tp.l1_signal_service else {
+        bail!("l1_signal_service not set");
+    };
+
+    let proof = tp.l1_provider.get_proof(&ProofQuery {
+        block_no: l1_block_no,
+        address: l1_signal_service.into_array().into(),
+        indices: Default::default(),
+    })?;
+
+    let l1_signal_root = from_ethers_h256(proof.storage_hash);
+
+    ensure!(
+        l1_signal_root == anchor_call.l1SignalRoot,
+        "l1SignalRoot mismatch"
+    );
+
+    // 3. check l1 block hash
+    ensure!(
+        l1_block.hash.unwrap() == ethers_core::types::H256::from(anchor_call.l1Hash.0),
+        "l1Hash mismatch"
+    );
+
+    let proof = tp.l2_provider.get_proof(&ProofQuery {
+        block_no: l2_block_no,
+        address: tp
+            .l2_signal_service
+            .expect("l2_signal_service not set")
+            .into_array()
+            .into(),
+        indices: Default::default(),
+    })?;
+    let l2_signal_root = from_ethers_h256(proof.storage_hash);
+
+    tp.l1_provider.save()?;
+    tp.l2_provider.save()?;
+
+    let sys_info = TaikoSystemInfo {
+        l1_hash: anchor_call.l1Hash,
+        l1_height: anchor_call.l1Height,
+        l2_tx_list: proposal_call.txList,
+        prover,
+        graffiti,
+        l1_signal_root,
+        l2_signal_root,
+        l2_withdrawals: l2_block
+            .withdrawals
+            .clone()
+            .unwrap_or_default()
+            .into_iter()
+            .map(|w| w.try_into().unwrap())
+            .collect(),
+        block_proposed: proposal_event,
+        l1_next_block,
+        l2_block,
+    };
+
+    Ok(sys_info)
+}
+
+impl Preflight<EthereumTxEssence> for TaikoStrategy {
+    fn run_preflight(
+        chain_spec: ChainSpec,
+        cache_path: Option<std::path::PathBuf>,
+        rpc_url: Option<String>,
+        block_no: u64,
+    ) -> Result<Data<EthereumTxEssence>> {
+        let mut tp = TaikoProvider::new(None, None, cache_path, rpc_url)?;
+
+        // Fetch the parent block
+        let parent_block = tp.l2_provider.get_partial_block(&BlockQuery {
+            block_no: block_no - 1,
+        })?;
+
+        info!(
+            "Initial block: {:?} ({:?})",
+            parent_block.number.unwrap(),
+            parent_block.hash.unwrap()
+        );
+        let parent_header: Header = parent_block.try_into().context("invalid parent block")?;
+
+        // Fetch the target block
+        let mut block = tp.l2_provider.get_full_block(&BlockQuery { block_no })?;
+        let (anchor_tx, anchor_call) = tp.get_anchor(&block)?;
+        let (proposal_call, _) = tp.get_proposal(anchor_call.l1Height, block_no)?;
+
+        let mut l2_tx_list: Vec<EthersTransaction> = rlp_decode_list(&proposal_call.txList)?;
+        ensure!(
+            proposal_call.txList.len() <= MAX_TX_LIST_BYTES,
+            "tx list bytes must be not more than MAX_TX_LIST_BYTES"
+        );
+        ensure!(
+            l2_tx_list.len() <= MAX_TX_LIST,
+            "tx list size must be not more than MAX_TX_LISTs"
+        );
+
+        // TODO(Cecilia): reset to empty necessary if wrong?
+        // tracing::log for particular reason instead of uniform error handling?
+        // txs.clear();
+
+        info!(
+            "Inserted anchor {:?} in tx_list decoded from {:?}",
+            anchor_tx.hash, proposal_call.txList
+        );
+        l2_tx_list.insert(0, anchor_tx);
+        block.transactions = l2_tx_list;
+
+        info!(
+            "Final block number: {:?} ({:?})",
+            block.number.unwrap(),
+            block.hash.unwrap()
+        );
+        info!("Transaction count: {:?}", block.transactions.len());
+
+        // Create the provider DB
+        let provider_db = ProviderDb::new(tp.l2_provider, parent_header.number);
+
+        // Create the input data
+        let input = new_preflight_input(block.clone(), parent_header.clone())?;
+        let transactions = input.transactions.clone();
+        let withdrawals = input.withdrawals.clone();
+
+        // Create the block builder, run the transactions and extract the DB
+        let mut builder = BlockBuilder::new(&chain_spec, input)
+            .with_db(provider_db)
+            .prepare_header::<EthHeaderPrepStrategy>()?
+            .execute_transactions::<TkoTxExecStrategy>()?;
+        let provider_db = builder.mut_db().unwrap();
+
+        info!("Gathering inclusion proofs ...");
+
+        // Gather inclusion proofs for the initial and final state
+        let parent_proofs = provider_db.get_initial_proofs()?;
+        let proofs = provider_db.get_latest_proofs()?;
+
+        // Gather proofs for block history
+        let ancestor_headers = provider_db.get_ancestor_headers()?;
+
+        info!("Saving provider cache ...");
+
+        // Save the provider cache
+        provider_db.get_provider().save()?;
+
+        info!("Provider-backed execution is Done!");
+
+        Ok(Data {
+            db: provider_db.get_initial_db().clone(),
+            parent_header,
+            parent_proofs,
+            header: block.try_into().context("invalid block")?,
+            transactions,
+            withdrawals,
+            proofs,
+            ancestor_headers,
+        })
+    }
+}
+
+fn rlp_decode_list<T>(bytes: &[u8]) -> Result<Vec<T>, DecoderError>
+where
+    T: Decodable,
+{
+    let rlp = Rlp::new(bytes);
+    rlp.as_list()
+}
diff --git a/lib/src/taiko/mod.rs b/lib/src/taiko/mod.rs
index e7311ae1e..2b12307e6 100644
--- a/lib/src/taiko/mod.rs
+++ b/lib/src/taiko/mod.rs
@@ -1,10 +1,102 @@
-pub mod block_builder;
-#[cfg(not(target_os = "zkvm"))]
-pub mod execute;
-pub mod prepare;
-pub mod utils;
-
-pub enum Layer {
-    L1,
-    L2,
+use alloc::vec::Vec;
+
+use alloy_primitives::{Address, B256};
+use alloy_sol_types::{sol, SolCall};
+use anyhow::{anyhow, Result};
+use ethers_core::types::{Block, Transaction as EthersTransaction};
+use serde::{Deserialize, Serialize};
+use zeth_primitives::withdrawal::Withdrawal;
+
+pub mod consts;
+#[cfg(all(feature = "std", not(target_os = "zkvm")))]
+pub mod host;
+pub mod protocol_instance;
+#[cfg(all(feature = "std", not(target_os = "zkvm")))]
+pub mod provider;
+
+sol! {
+    function anchor(
+        bytes32 l1Hash,
+        bytes32 l1SignalRoot,
+        uint64 l1Height,
+        uint32 parentGasUsed
+    )
+        external
+    {}
+}
+
+#[inline]
+pub fn decode_anchor(bytes: &[u8]) -> Result<anchorCall> {
+    anchorCall::abi_decode(bytes, true).map_err(|e| anyhow!(e))
+    // .context("Invalid anchor call")
+}
+
+sol! {
+    #[derive(Debug, Default, Deserialize, Serialize)]
+    struct EthDeposit {
+        address recipient;
+        uint96 amount;
+        uint64 id;
+    }
+
+    #[derive(Debug, Default, Deserialize, Serialize)]
+    struct BlockMetadata {
+        bytes32 l1Hash; // slot 1
+        bytes32 difficulty; // slot 2
+        bytes32 blobHash; //or txListHash (if Blob not yet supported), // slot 3
+        bytes32 extraData; // slot 4
+        bytes32 depositsHash; // slot 5
+        address coinbase; // L2 coinbase, // slot 6
+        uint64 id;
+        uint32 gasLimit;
+        uint64 timestamp; // slot 7
+        uint64 l1Height;
+        uint24 txListByteOffset;
+        uint24 txListByteSize;
+        uint16 minTier;
+        bool blobUsed;
+        bytes32 parentMetaHash; // slot 8
+    }
+
+    #[derive(Debug)]
+    struct Transition {
+        bytes32 parentHash;
+        bytes32 blockHash;
+        bytes32 signalRoot;
+        bytes32 graffiti;
+    }
+
+    #[derive(Debug, Default, Clone, Deserialize, Serialize)]
+    event BlockProposed(
+        uint256 indexed blockId,
+        address indexed prover,
+        uint96 livenessBond,
+        BlockMetadata meta,
+        EthDeposit[] depositsProcessed
+    );
+
+    #[derive(Debug)]
+    struct TierProof {
+        uint16 tier;
+        bytes data;
+    }
+
+    function proposeBlock(bytes calldata params, bytes calldata txList) {}
+
+    function proveBlock(uint64 blockId, bytes calldata input) {}
+}
+
+#[derive(Debug)]
+pub struct TaikoSystemInfo {
+    pub l1_hash: B256,
+    pub l1_height: u64,
+    pub l2_tx_list: Vec<u8>,
+    pub prover: Address,
+    pub graffiti: B256,
+    pub l1_signal_root: B256,
+    pub l2_signal_root: B256,
+    pub l2_withdrawals: Vec<Withdrawal>,
+    pub block_proposed: BlockProposed,
+    pub l1_next_block: Block<EthersTransaction>,
+    pub l2_block: Block<EthersTransaction>,
 }
diff --git a/lib/src/taiko/prepare.rs b/lib/src/taiko/prepare.rs
deleted file mode 100644
index 551dc6e87..000000000
--- a/lib/src/taiko/prepare.rs
+++ /dev/null
@@ -1,67 +0,0 @@
-use core::fmt::Debug;
-
-use anyhow::{bail, Context, Result};
-use revm::{Database, DatabaseCommit};
-use zeth_primitives::{block::Header, taiko::BLOCK_GAS_LIMIT, transactions::TxEssence};
-
-use crate::{
-    block_builder::BlockBuilder, consts::MAX_EXTRA_DATA_BYTES, preparation::HeaderPrepStrategy,
-};
-
-pub struct TaikoHeaderPrepStrategy {}
-
-impl HeaderPrepStrategy for TaikoHeaderPrepStrategy {
-    fn prepare_header<D, E>(mut block_builder: BlockBuilder<D, E>) -> Result<BlockBuilder<D, E>>
-    where
-        D: Database + DatabaseCommit,
-        <D as Database>::Error: Debug,
-        E: TxEssence,
-    {
-        // Validate gas limit
-        if block_builder.input.gas_limit != *BLOCK_GAS_LIMIT {
-            bail!(
-                "Invalid gas limit: expected == {}, got {}",
-                *BLOCK_GAS_LIMIT,
-                block_builder.input.gas_limit,
-            );
-        }
-        // Validate timestamp
-        if block_builder.input.timestamp < block_builder.input.parent_header.timestamp {
-            bail!(
-                "Invalid timestamp: expected >= {}, got {}",
-                block_builder.input.parent_header.timestamp,
-                block_builder.input.timestamp,
-            );
-        }
-        // Validate extra data
-        let extra_data_bytes = block_builder.input.extra_data.len();
-        if extra_data_bytes > MAX_EXTRA_DATA_BYTES {
-            bail!(
-                "Invalid extra data: expected <= {}, got {}",
-                MAX_EXTRA_DATA_BYTES,
-                extra_data_bytes,
-            )
-        }
-        // Derive header
-        block_builder.header = Some(Header {
-            // Initialize fields that we can compute from the parent
-            parent_hash: block_builder.input.parent_header.hash(),
-            number: block_builder
-                .input
-                .parent_header
-                .number
-                .checked_add(1)
-                .with_context(|| "Invalid block number: too large")?,
-            base_fee_per_gas: block_builder.input.base_fee_per_gas,
-            // Initialize metadata from input
-            beneficiary: block_builder.input.beneficiary,
-            gas_limit: block_builder.input.gas_limit,
-            timestamp: block_builder.input.timestamp,
-            mix_hash: block_builder.input.mix_hash,
-            extra_data: block_builder.input.extra_data.clone(),
-            // do not fill the remaining fields
-            ..Default::default()
-        });
-        Ok(block_builder)
-    }
-}
diff --git a/lib/src/taiko/protocol_instance.rs b/lib/src/taiko/protocol_instance.rs
new file mode 100644
index 000000000..6d9cc3316
--- /dev/null
+++ b/lib/src/taiko/protocol_instance.rs
@@ -0,0 +1,168 @@
+use alloc::vec::Vec;
+
+use alloy_primitives::{Address, TxHash, B256};
+use alloy_sol_types::SolValue;
+use anyhow::{anyhow, Result};
+use revm::primitives::SpecId;
+use zeth_primitives::{
+    block::Header,
+    ethers::{from_ethers_h256, from_ethers_u256},
+    keccak::keccak,
+    transactions::EthereumTransaction,
+};
+
+use super::{consts::ANCHOR_GAS_LIMIT, BlockMetadata, EthDeposit, TaikoSystemInfo, Transition};
+use crate::consts::TKO_MAINNET_CHAIN_SPEC;
+
+#[derive(Debug)]
+pub struct ProtocolInstance {
+    pub transition: Transition,
+    pub block_metadata: BlockMetadata,
+    pub prover: Address,
+}
+
+impl ProtocolInstance {
+    pub fn meta_hash(&self) -> B256 {
+        keccak(self.block_metadata.abi_encode()).into()
+    }
+
+    // keccak256(abi.encode(tran, newInstance, prover, metaHash))
+    pub fn instance_hash(&self, evidence_type: EvidenceType) -> B256 {
+        match evidence_type {
+            EvidenceType::Sgx { new_pubkey } => keccak(
+                (
+                    self.transition.clone(),
+                    new_pubkey,
+                    self.prover,
+                    self.meta_hash(),
+                )
+                    .abi_encode(),
+            )
+            .into(),
+            EvidenceType::Pse => todo!(),
+            EvidenceType::Powdr => todo!(),
+        }
+    }
+}
+
+#[derive(Debug)]
+pub enum EvidenceType {
+    Sgx {
+        new_pubkey: Address, // the evidence signature public key
+    },
+    Pse,
+    Powdr,
+}
+
+// TODO(cecilia): rewrite
+pub fn assemble_protocol_instance(
+    sys: &TaikoSystemInfo,
+    header: &Header,
+) -> Result<ProtocolInstance> {
+    let tx_list_hash = TxHash::from(keccak(sys.l2_tx_list.as_slice()));
+    let block_hash: zeth_primitives::U256 = tx_list_hash.into();
+
+    let deposits = sys
+        .l2_withdrawals
+        .iter()
+        .map(|w| EthDeposit {
+            recipient: w.address,
+            amount: w.amount as u128,
+            id: w.index,
+        })
+        .collect::<Vec<_>>();
+    let deposits_hash: B256 = keccak(deposits.abi_encode()).into();
+
+    let extra_data: B256 = bytes_to_bytes32(&header.extra_data).into();
+
+    let prevrandao = if TKO_MAINNET_CHAIN_SPEC.spec_id(header.number) >= SpecId::SHANGHAI {
+        from_ethers_h256(sys.l1_next_block.mix_hash.unwrap_or_default()).into()
+    } else {
+        from_ethers_u256(sys.l1_next_block.difficulty)
+    };
+    let difficulty = block_hash
+        ^ (prevrandao
+            * zeth_primitives::U256::from(header.number)
+            * zeth_primitives::U256::from(sys.l1_next_block.number.unwrap_or_default().as_u64()));
+
+    let gas_limit: u64 = header.gas_limit.try_into().unwrap();
+    let mut pi = ProtocolInstance {
+        transition: Transition {
+            parentHash: header.parent_hash,
+            blockHash: header.hash(),
+            signalRoot: sys.l2_signal_root,
+            graffiti: sys.graffiti,
+        },
+        block_metadata: BlockMetadata {
+            l1Hash: sys.l1_hash,
+            difficulty: difficulty.into(),
+            blobHash: tx_list_hash,
+            extraData: extra_data,
+            depositsHash: deposits_hash,
+            coinbase: header.beneficiary,
+            id: header.number,
+            gasLimit: (gas_limit - ANCHOR_GAS_LIMIT) as u32,
+            timestamp: header.timestamp.try_into().unwrap(),
+            l1Height: sys.l1_height,
+            txListByteOffset: 0u32,
+            txListByteSize: sys.l2_tx_list.len() as u32,
+            minTier: sys.block_proposed.meta.minTier,
+            blobUsed: sys.l2_tx_list.is_empty(),
+            parentMetaHash: sys.block_proposed.meta.parentMetaHash,
+        },
+        prover: sys.prover,
+    };
+    verify(sys, header, &mut pi)?;
+    Ok(pi)
+}
+
+pub fn verify(sys: &TaikoSystemInfo, header: &Header, pi: &mut ProtocolInstance) -> Result<()> {
+    // check the block metadata
+    if pi.block_metadata.abi_encode() != sys.block_proposed.meta.abi_encode() {
+        return Err(anyhow!(
+            "block metadata mismatch, expected: {:?}, got: {:?}",
+            sys.block_proposed.meta,
+            pi.block_metadata
+        ));
+    }
+    // Check the block hash
+    if Some(header.hash()) != sys.l2_block.hash.map(from_ethers_h256) {
+        let _txs: Vec<EthereumTransaction> = sys
+            .l2_block
+            .transactions
+            .iter()
+            .filter_map(|tx| tx.clone().try_into().ok())
+            .collect();
+        return Err(anyhow!(
+            "block hash mismatch, expected: {}, got: {}",
+            header.hash(),
+            sys.l2_block.hash.map(from_ethers_h256).unwrap()
+        ));
+    }
+
+    Ok(())
+}
+
+fn bytes_to_bytes32(input: &[u8]) -> [u8; 32] {
+    let mut bytes = [0u8; 32];
+    let len = core::cmp::min(input.len(), 32);
+    bytes[..len].copy_from_slice(&input[..len]);
+    bytes
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+    #[test]
+    fn bytes_to_bytes32_test() {
+        let input = "";
+        let byte = bytes_to_bytes32(input.as_bytes());
+        assert_eq!(
+            byte,
+            [
+                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+                0, 0, 0, 0
+            ]
+        );
+    }
+}
diff --git a/lib/src/taiko/provider.rs b/lib/src/taiko/provider.rs
new file mode 100644
index 000000000..7e3a39603
--- /dev/null
+++ b/lib/src/taiko/provider.rs
@@ -0,0 +1,204 @@
+use alloc::string::String;
+use std::path::PathBuf;
+
+use alloy_primitives::Address;
+use alloy_sol_types::SolCall;
+use anyhow::{anyhow, bail, ensure, Context, Result};
+use ethers_core::types::{Block, Transaction, H256, U256, U64};
+use zeth_primitives::{
+    ethers::{from_ethers_h160, from_ethers_h256},
+    transactions::EthereumTransaction,
+};
+
+use super::{anchorCall, decode_anchor, proposeBlockCall, BlockProposed};
+use crate::{
+    consts::ChainSpec,
+    host::provider::{new_provider, BlockQuery, ProofQuery, Provider, TxQuery},
+    taiko::consts::{check_anchor_signature, ANCHOR_GAS_LIMIT, GOLDEN_TOUCH_ACCOUNT},
+};
+
+pub struct TaikoProvider {
+    pub l1_provider: Box<dyn Provider>,
+    pub l2_provider: Box<dyn Provider>,
+    pub l2_spec: Option<ChainSpec>,
+    pub prover: Option<Address>,
+    pub l1_contract: Option<Address>,
+    pub l2_contract: Option<Address>,
+    pub l1_signal_service: Option<Address>,
+    pub l2_signal_service: Option<Address>,
+}
+
+impl TaikoProvider {
+    pub fn new(
+        l1_cache: Option<PathBuf>,
+        l1_rpc: Option<String>,
+        l2_cache: Option<PathBuf>,
+        l2_rpc: Option<String>,
+    ) -> Result<Self> {
+        Ok(Self {
+            l1_provider: new_provider(l1_cache, l1_rpc)?,
+            l2_provider: new_provider(l2_cache, l2_rpc)?,
+            l2_spec: None,
+            prover: None,
+            l1_contract: None,
+            l2_contract: None,
+            l1_signal_service: None,
+            l2_signal_service: None,
+        })
+    }
+
+    pub fn with_l2_spec(mut self, spec: ChainSpec) -> Self {
+        self.l2_spec = Some(spec);
+        self
+    }
+
+    pub fn with_prover(mut self, prover: Address) -> Self {
+        self.prover = Some(prover);
+        self
+    }
+
+    pub fn with_contracts(
+        mut self,
+        f: impl FnOnce() -> Result<(Address, Address, Address, Address)>,
+    ) -> Self {
+        if let Ok((l1_contract, l2_contract, l1_signal_service, l2_signal_service)) = f() {
+            self.l1_contract = Some(l1_contract);
+            self.l2_contract = Some(l2_contract);
+            self.l1_signal_service = Some(l1_signal_service);
+            self.l2_signal_service = Some(l2_signal_service);
+        }
+        self
+    }
+
+    pub fn save(&mut self) -> Result<()> {
+        self.l1_provider.save()?;
+        self.l2_provider.save()?;
+        Ok(())
+    }
+
+    pub fn get_l1_full_block(&mut self, l1_block_no: u64) -> Result<Block<Transaction>> {
+        self.l1_provider.get_full_block(&BlockQuery {
+            block_no: l1_block_no,
+        })
+    }
+
+    pub fn get_l2_full_block(&mut self, l2_block_no: u64) -> Result<Block<Transaction>> {
+        self.l2_provider.get_full_block(&BlockQuery {
+            block_no: l2_block_no,
+        })
+    }
+
+    pub fn get_anchor(&self, l2_block: &Block<Transaction>) -> Result<(Transaction, anchorCall)> {
+        let tx = l2_block.transactions[0].clone();
+        let call = decode_anchor(tx.input.as_ref())?;
+        Ok((tx, call))
+    }
+
+    pub fn get_proposal(
+        &mut self,
+        l1_block_no: u64,
+        l2_block_no: u64,
+    ) -> Result<(proposeBlockCall, BlockProposed)> {
+        let logs = self.l1_provider.filter_event_log::<BlockProposed>(
+            self.l1_contract.unwrap(),
+            l1_block_no,
+            l2_block_no,
+        )?;
+        for (log, event) in logs {
+            if event.blockId == zeth_primitives::U256::from(l2_block_no) {
+                let tx = self
+                    .l1_provider
+                    .get_transaction(&TxQuery {
+                        tx_hash: log.transaction_hash.unwrap(),
+                        block_no: log.block_number.map(|b| b.as_u64()),
+                    })
+                    .with_context(|| {
+                        anyhow!(
+                            "Cannot find BlockProposed Tx {:?}",
+                            log.transaction_hash.unwrap()
+                        )
+                    })?;
+                let call = proposeBlockCall::abi_decode(&tx.input, false).unwrap();
+                // .with_context(|| "failed to decode propose block call")?;
+                return Ok((call, event));
+            }
+        }
+        bail!("No BlockProposed event found for block {l2_block_no}");
+    }
+
+    pub fn check_anchor_with_blocks<TX1, TX2>(
+        &mut self,
+        l1_block: &Block<TX1>,
+        l2_parent_block: &Block<TX2>,
+        anchor: anchorCall,
+    ) -> Result<()> {
+        // 1. check l2 parent gas used
+        ensure!(
+            l2_parent_block.gas_used == U256::from(anchor.parentGasUsed),
+            "parentGasUsed mismatch"
+        );
+
+        // 2. check l1 signal root
+        let Some(l1_signal_service) = self.l1_signal_service else {
+            bail!("l1_signal_service not set");
+        };
+
+        let proof = self.l1_provider.get_proof(&ProofQuery {
+            block_no: l1_block.number.unwrap().as_u64(),
+            address: l1_signal_service.into_array().into(),
+            indices: Default::default(),
+        })?;
+        let signal_root = from_ethers_h256(proof.storage_hash);
+
+        ensure!(signal_root == anchor.l1SignalRoot, "l1SignalRoot mismatch");
+
+        // 3. check l1 block hash
+        ensure!(
+            l1_block.hash.unwrap() == H256::from(anchor.l1Hash.0),
+            "l1Hash mismatch"
+        );
+
+        Ok(())
+    }
+
+    pub fn check_anchor_tx(
+        &self,
+        anchor: &Transaction,
+        l2_block: &Block<Transaction>,
+    ) -> Result<()> {
+        let tx1559_type = U64::from(0x2);
+        ensure!(
+            anchor.transaction_type == Some(tx1559_type),
+            "anchor transaction type mismatch"
+        );
+
+        let tx: EthereumTransaction = anchor
+            .clone()
+            .try_into()
+            .context(anyhow!("failed to decode anchor transaction: {:?}", anchor))?;
+        check_anchor_signature(&tx).context(anyhow!("failed to check anchor signature"))?;
+
+        ensure!(
+            from_ethers_h160(anchor.from) == *GOLDEN_TOUCH_ACCOUNT,
+            "anchor transaction from mismatch"
+        );
+        ensure!(
+            from_ethers_h160(anchor.to.unwrap()) == self.l1_contract.unwrap(),
+            "anchor transaction to mismatch"
+        );
+        ensure!(
+            anchor.value == U256::from(0),
+            "anchor transaction value mismatch"
+        );
+        ensure!(
+            anchor.gas == U256::from(ANCHOR_GAS_LIMIT),
+            "anchor transaction gas price mismatch"
+        );
+        ensure!(
+            anchor.max_fee_per_gas == l2_block.base_fee_per_gas,
+            "anchor transaction gas mismatch"
+        );
+
+        Ok(())
+    }
+}
diff --git a/lib/src/taiko/utils.rs b/lib/src/taiko/utils.rs
deleted file mode 100644
index e552d39e4..000000000
--- a/lib/src/taiko/utils.rs
+++ /dev/null
@@ -1,11 +0,0 @@
-use alloc::vec::Vec;
-
-use rlp::{Decodable, DecoderError, Rlp};
-
-pub fn rlp_decode_list<T>(bytes: &[u8]) -> Result<Vec<T>, DecoderError>
-where
-    T: Decodable,
-{
-    let rlp = Rlp::new(bytes);
-    rlp.as_list()
-}
diff --git a/lib/src/utils.rs b/lib/src/utils.rs
new file mode 100644
index 000000000..db91e675f
--- /dev/null
+++ b/lib/src/utils.rs
@@ -0,0 +1,63 @@
+// Copyright 2023 RISC Zero, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+use std::{io, io::Read};
+
+/// An adaptor that chains multiple readers together.
+pub struct MultiReader<I, R> {
+    readers: I,
+    current: Option<R>,
+}
+
+impl<I, R> MultiReader<I, R>
+where
+    I: IntoIterator<Item = R>,
+    R: Read,
+{
+    /// Creates a new instance of `MultiReader`.
+    ///
+    /// This function takes an iterator over readers and returns a `MultiReader`.
+    pub fn new(readers: I) -> MultiReader<I::IntoIter, R> {
+        let mut readers = readers.into_iter();
+        let current = readers.next();
+        MultiReader { readers, current }
+    }
+}
+
+/// Implementation of the `Read` trait for `MultiReader`.
+impl<I, R> Read for MultiReader<I, R>
+where
+    I: Iterator<Item = R>,
+    R: Read,
+{
+    /// Reads data from the current reader into a buffer.
+    ///
+    /// This function reads as much data as possible from the current reader into the
+    /// buffer, and switches to the next reader when the current one is exhausted.
+    #[inline]
+    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+        loop {
+            match self.current {
+                Some(ref mut r) => {
+                    let n = r.read(buf)?;
+                    if n > 0 {
+                        return Ok(n);
+                    }
+                }
+                None => return Ok(0),
+            }
+            self.current = self.readers.next();
+        }
+    }
+}
diff --git a/primitives/Cargo.toml b/primitives/Cargo.toml
index 7a4d3a42c..f84c0f85f 100644
--- a/primitives/Cargo.toml
+++ b/primitives/Cargo.toml
@@ -4,20 +4,20 @@ version = "0.1.0"
 edition = "2021"
 
 [dependencies]
-alloy-primitives = { version = "0.4", default-features = false, features = [
+alloy-primitives = { version = "0.6", default-features = false, features = [
   "rlp",
   "serde",
 ] }
-alloy-sol-types = { version = "0.4", default-features = false, optional = true }
-alloy-dyn-abi = { version = "0.4",default-features = false, optional = true }
+alloy-sol-types = { version = "0.6", default-features = false, optional = true }
+alloy-dyn-abi = { version = "0.6",default-features = false, optional = true }
 alloy-rlp = { version = "0.3", default-features = false }
 alloy-rlp-derive = { version = "0.3", default-features = false }
 anyhow = { version = "1.0", default-features = false }
 bytes = { version = "1.1", default-features = false }
 ethers-core = { version = "2.0", optional = true, features = ["optimism"] }
-k256 = { version = "=0.13.1", features = ["ecdsa"], default_features = false }
+k256 = { version = "^0.13.3", features = ["ecdsa"], default_features = false }
 
-revm-primitives = { workspace = true, optional = true }
+revm-primitives = { workspace = true, optional = true, default-features = false }
 rlp = { version = "0.5.2", default-features = false }
 serde = { version = "1.0", default-features = false, features = ["derive"] }
 sha3 = { version = "0.10", default-features = false}
@@ -34,11 +34,7 @@ serde_json = { version = "1.0", default-features = false }
 
 [features]
 std = []
+taiko = ["revm-primitives/taiko"]
+optimism = ["revm-primitives/optimism"]
 ethers = ["dep:ethers-core"]
 revm = ["dep:revm-primitives"]
-taiko = [
-  "revm-primitives/taiko",
-  "dep:alloy-sol-types",
-  "dep:alloy-dyn-abi",
-  "dep:once_cell",
-]
diff --git a/primitives/src/batch.rs b/primitives/src/batch.rs
new file mode 100644
index 000000000..2e22977dd
--- /dev/null
+++ b/primitives/src/batch.rs
@@ -0,0 +1,116 @@
+// Copyright 2024 RISC Zero, Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+use alloc::vec::Vec;
+
+use alloy_primitives::{Bytes, B256};
+use alloy_rlp::{Decodable, Encodable};
+use alloy_rlp_derive::{RlpDecodable, RlpEncodable};
+use serde::{Deserialize, Serialize};
+
+/// Bytes for RLP-encoded transactions.
+pub type RawTransaction = Bytes;
+
+/// A batch represents the inputs needed to build Optimism block.
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
+pub struct Batch(pub BatchEssence);
+
+/// Represents the core details of a [Batch], specifically the portion that is derived
+/// from the batcher transactions.
+#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, RlpEncodable, RlpDecodable)]
+pub struct BatchEssence {
+    /// The block hash of the previous L2 block.
+    pub parent_hash: B256,
+    /// The number of the L1 block corresponding to the sequencing epoch of the L2 block.
+    pub epoch_num: u64,
+    /// The hash of the L1 block corresponding to the sequencing epoch of the L2 block.
+    pub epoch_hash: B256,
+    /// The timestamp of the L2 block.
+    pub timestamp: u64,
+    /// An RLP-encoded list of EIP-2718 encoded transactions.
+    pub transactions: Vec<RawTransaction>,
+}
+
+impl Batch {
+    pub fn new(parent_hash: B256, epoch_num: u64, epoch_hash: B256, timestamp: u64) -> Self {
+        Batch(BatchEssence {
+            parent_hash,
+            epoch_num,
+            epoch_hash,
+            timestamp,
+            transactions: Vec::new(),
+        })
+    }
+}
+
+impl Encodable for Batch {
+    #[inline]
+    fn encode(&self, out: &mut dyn alloy_rlp::BufMut) {
+        // wrap the RLP-essence inside a bytes payload
+        alloy_rlp::Header {
+            list: false,
+            payload_length: self.0.length() + 1,
+        }
+        .encode(out);
+        out.put_u8(0x00);
+        self.0.encode(out);
+    }
+
+    #[inline]
+    fn length(&self) -> usize {
+        let bytes_length = self.0.length() + 1;
+        alloy_rlp::length_of_length(bytes_length) + bytes_length
+    }
+}
+
+impl Decodable for Batch {
+    #[inline]
+    fn decode(buf: &mut &[u8]) -> alloy_rlp::Result<Self> {
+        let bytes = alloy_rlp::Header::decode_bytes(buf, false)?;
+        match bytes.split_first() {
+            Some((0, mut payload)) => Ok(Self(BatchEssence::decode(&mut payload)?)),
+            Some(_) => Err(alloy_rlp::Error::Custom("invalid version")),
+            None => Err(alloy_rlp::Error::InputTooShort),
+        }
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use alloc::vec;
+
+    use hex_literal::hex;
+    use serde_json::json;
+
+    use super::*;
+
+    #[test]
+    fn rlp_roundtrip() {
+        let expected = hex!("b85000f84da0dbf6a80fef073de06add9b0d14026d6e5a86c85f6d102c36d3d8e9cf89c2afd3840109d8fea0438335a20d98863a4c0c97999eb2481921ccd28553eac6f913af7c12aec0410884647f5ea9c0");
+        let batch: Batch = serde_json::from_value(json!({
+          "parent_hash": "0xdbf6a80fef073de06add9b0d14026d6e5a86c85f6d102c36d3d8e9cf89c2afd3",
+          "epoch_num": 17422590,
+          "epoch_hash": "0x438335a20d98863a4c0c97999eb2481921ccd28553eac6f913af7c12aec04108",
+          "timestamp": 1686068905,
+          "transactions": []
+        }))
+        .unwrap();
+
+        let encoded = alloy_rlp::encode(&batch);
+        assert_eq!(encoded.len(), batch.length());
+        assert_eq!(encoded, expected);
+
+        let decoded = Batch::decode(&mut &encoded[..]).unwrap();
+        assert_eq!(batch, decoded);
+    }
+}
diff --git a/primitives/src/block.rs b/primitives/src/block.rs
index 68c394617..61a812cbd 100644
--- a/primitives/src/block.rs
+++ b/primitives/src/block.rs
@@ -107,6 +107,8 @@ impl Header {
 
 #[cfg(test)]
 mod tests {
+    use alloc::string::ToString;
+
     use serde_json::json;
 
     use super::*;
diff --git a/primitives/src/ethers.rs b/primitives/src/ethers.rs
index a83b189c5..3faa3bb34 100644
--- a/primitives/src/ethers.rs
+++ b/primitives/src/ethers.rs
@@ -37,21 +37,25 @@ use ethers_core::types::{
     transaction::eip2930::{
         AccessList as EthersAccessList, AccessListItem as EthersAccessListItem,
     },
-    Block as EthersBlock, Bytes as EthersBytes, Transaction as EthersTransaction,
+    Block as EthersBlock, Bytes as EthersBytes, EIP1186ProofResponse,
+    Transaction as EthersTransaction, TransactionReceipt as EthersReceipt,
     Withdrawal as EthersWithdrawal, H160 as EthersH160, H256 as EthersH256, U256 as EthersU256,
+    U64,
 };
 
 use crate::{
     access_list::{AccessList, AccessListItem},
     block::Header,
-    signature::TxSignature,
+    receipt::{Log, Receipt, ReceiptPayload},
     transactions::{
         ethereum::{
             EthereumTxEssence, TransactionKind, TxEssenceEip1559, TxEssenceEip2930, TxEssenceLegacy,
         },
         optimism::{OptimismTxEssence, TxEssenceOptimismDeposited},
+        signature::TxSignature,
         Transaction, TxEssence,
     },
+    trie::StateAccount,
     withdrawal::Withdrawal,
 };
 
@@ -61,6 +65,12 @@ pub fn from_ethers_u256(v: EthersU256) -> U256 {
     U256::from_limbs(v.0)
 }
 
+/// Convert an `U256` type to the `EthersU256` type.
+#[inline]
+pub fn to_ethers_u256(v: U256) -> EthersU256 {
+    EthersU256(v.into_limbs())
+}
+
 /// Convert an `EthersH160` type to the `Address` type.
 #[inline]
 pub fn from_ethers_h160(v: EthersH160) -> Address {
@@ -173,13 +183,13 @@ impl TryFrom<EthersTransaction> for EthereumTxEssence {
                     Some(chain_id) => Some(
                         chain_id
                             .try_into()
-                            .map_err(|err| anyhow!("invalid chain_id: {}", err))?,
+                            .map_err(|err| anyhow!("invalid chain_id: {err}"))?,
                     ),
                 },
                 nonce: tx
                     .nonce
                     .try_into()
-                    .map_err(|err| anyhow!("invalid nonce: {}", err))?,
+                    .map_err(|err| anyhow!("invalid nonce: {err}"))?,
                 gas_price: from_ethers_u256(tx.gas_price.context("gas_price missing")?),
                 gas_limit: from_ethers_u256(tx.gas),
                 to: tx.to.into(),
@@ -191,11 +201,11 @@ impl TryFrom<EthersTransaction> for EthereumTxEssence {
                     .chain_id
                     .context("chain_id missing")?
                     .try_into()
-                    .map_err(|err| anyhow!("invalid chain_id: {}", err))?,
+                    .map_err(|err| anyhow!("invalid chain_id: {err}"))?,
                 nonce: tx
                     .nonce
                     .try_into()
-                    .map_err(|err| anyhow!("invalid nonce: {}", err))?,
+                    .map_err(|err| anyhow!("invalid nonce: {err}"))?,
                 gas_price: from_ethers_u256(tx.gas_price.context("gas_price missing")?),
                 gas_limit: from_ethers_u256(tx.gas),
                 to: tx.to.into(),
@@ -208,11 +218,11 @@ impl TryFrom<EthersTransaction> for EthereumTxEssence {
                     .chain_id
                     .context("chain_id missing")?
                     .try_into()
-                    .map_err(|err| anyhow!("invalid chain_id: {}", err))?,
+                    .map_err(|err| anyhow!("invalid chain_id: {err}"))?,
                 nonce: tx
                     .nonce
                     .try_into()
-                    .map_err(|err| anyhow!("invalid nonce: {}", err))?,
+                    .map_err(|err| anyhow!("invalid nonce: {err}"))?,
                 max_priority_fee_per_gas: from_ethers_u256(
                     tx.max_priority_fee_per_gas
                         .context("max_priority_fee_per_gas missing")?,
@@ -245,9 +255,9 @@ impl TryFrom<EthersTransaction> for OptimismTxEssence {
                 to: tx.to.into(),
                 value: from_ethers_u256(tx.value),
                 data: tx.input.0.into(),
-                source_hash: from_ethers_h256(tx.source_hash.unwrap_or_default()),
-                mint: from_ethers_u256(tx.mint.unwrap_or_default()),
-                is_system_tx: tx.is_system_tx.unwrap_or_default(),
+                source_hash: from_ethers_h256(tx.source_hash),
+                mint: from_ethers_u256(tx.mint.context("mint missing")?),
+                is_system_tx: tx.is_system_tx,
             }),
             _ => OptimismTxEssence::Ethereum(tx.try_into()?),
         };
@@ -268,7 +278,53 @@ impl TryFrom<EthersWithdrawal> for Withdrawal {
             amount: withdrawal
                 .amount
                 .try_into()
-                .map_err(|err| anyhow!("invalid amount: {}", err))?,
+                .map_err(|err| anyhow!("invalid amount: {err}"))?,
+        })
+    }
+}
+
+impl TryFrom<EthersReceipt> for Receipt {
+    type Error = anyhow::Error;
+
+    fn try_from(receipt: EthersReceipt) -> Result<Self, Self::Error> {
+        Ok(Receipt {
+            tx_type: receipt
+                .transaction_type
+                .context("transaction_type missing")?
+                .as_u64()
+                .try_into()
+                .context("invalid transaction_type")?,
+            payload: ReceiptPayload {
+                success: receipt.status.context("status missing")? == U64::one(),
+                cumulative_gas_used: from_ethers_u256(receipt.cumulative_gas_used),
+                logs_bloom: Bloom::from_slice(receipt.logs_bloom.as_bytes()),
+                logs: receipt
+                    .logs
+                    .into_iter()
+                    .map(|log| {
+                        let address = log.address.0.into();
+                        let topics = log.topics.into_iter().map(from_ethers_h256).collect();
+                        let data = log.data.0.into();
+                        Log {
+                            address,
+                            topics,
+                            data,
+                        }
+                    })
+                    .collect(),
+            },
         })
     }
 }
+
+/// Conversion from `EIP1186ProofResponse` to the local [StateAccount].
+impl From<EIP1186ProofResponse> for StateAccount {
+    fn from(response: EIP1186ProofResponse) -> Self {
+        StateAccount {
+            nonce: response.nonce.as_u64(),
+            balance: from_ethers_u256(response.balance),
+            storage_root: from_ethers_h256(response.storage_hash),
+            code_hash: from_ethers_h256(response.code_hash),
+        }
+    }
+}
diff --git a/primitives/src/lib.rs b/primitives/src/lib.rs
index 630c95cda..7866603a7 100644
--- a/primitives/src/lib.rs
+++ b/primitives/src/lib.rs
@@ -22,9 +22,6 @@ pub mod access_list;
 pub mod block;
 pub mod keccak;
 pub mod receipt;
-pub mod signature;
-#[cfg(feature = "taiko")]
-pub mod taiko;
 pub mod transactions;
 pub mod trie;
 pub mod withdrawal;
@@ -32,6 +29,7 @@ pub mod withdrawal;
 #[cfg(feature = "ethers")]
 pub mod ethers;
 
+pub mod batch;
 #[cfg(feature = "revm")]
 pub mod revm;
 
diff --git a/primitives/src/revm.rs b/primitives/src/revm.rs
index 18504ea97..2cee7a4e5 100644
--- a/primitives/src/revm.rs
+++ b/primitives/src/revm.rs
@@ -1,4 +1,4 @@
-// Copyright 2023 RISC Zero, Inc.
+// Copyright 2024 RISC Zero, Inc.
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
 // you may not use this file except in compliance with the License.
@@ -66,8 +66,8 @@ impl From<RevmLog> for Log {
     fn from(log: RevmLog) -> Self {
         Log {
             address: log.address,
-            topics: log.topics,
-            data: log.data,
+            topics: log.data.topics().to_vec(),
+            data: log.data.data,
         }
     }
 }
diff --git a/primitives/src/taiko/anchor.rs b/primitives/src/taiko/anchor.rs
deleted file mode 100644
index 1b3222d3c..000000000
--- a/primitives/src/taiko/anchor.rs
+++ /dev/null
@@ -1,61 +0,0 @@
-use alloy_sol_types::{sol, SolCall};
-use anyhow::{anyhow, bail, Context, Result};
-use once_cell::sync::Lazy;
-
-use super::AbiEncodeError;
-use crate::{transactions::EthereumTransaction, uint, U256};
-
-static GX1: Lazy<U256> =
-    Lazy::new(|| uint!(0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798_U256));
-static N: Lazy<U256> =
-    Lazy::new(|| uint!(0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141_U256));
-static GX1_MUL_PRIVATEKEY: Lazy<U256> =
-    Lazy::new(|| uint!(0x4341adf5a780b4a87939938fd7a032f6e6664c7da553c121d3b4947429639122_U256));
-static GX2: Lazy<U256> =
-    Lazy::new(|| uint!(0xc6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5_U256));
-
-sol! {
-    function anchor(
-        bytes32 l1Hash,
-        bytes32 l1SignalRoot,
-        uint64 l1Height,
-        uint32 parentGasUsed
-    )
-        external
-    {}
-}
-
-/// decode anchor arguments from anchor transaction
-pub fn decode_anchor_call_args(data: &[u8]) -> Result<anchorCall> {
-    let anchor_call = anchorCall::abi_decode(data, false)
-        .map_err(|e| anyhow!(AbiEncodeError::from(e)))
-        .with_context(|| "failed to decode anchor call")?;
-    Ok(anchor_call)
-}
-
-/// check the anchor signature with fixed K value
-pub fn check_anchor_signature(anchor: &EthereumTransaction) -> Result<()> {
-    let sign = &anchor.signature;
-    if sign.r == *GX1 {
-        return Ok(());
-    }
-    let msg_hash = anchor.essence.signing_hash();
-    let msg_hash: U256 = msg_hash.into();
-    if sign.r == *GX2 {
-        // when r == GX2 require s == 0 if k == 1
-        // alias: when r == GX2 require N == msg_hash + *GX1_MUL_PRIVATEKEY
-        if *N != msg_hash + *GX1_MUL_PRIVATEKEY {
-            bail!(
-                "r == GX2, but N != msg_hash + *GX1_MUL_PRIVATEKEY, N: {}, msg_hash: {}, *GX1_MUL_PRIVATEKEY: {}",
-                *N, msg_hash, *GX1_MUL_PRIVATEKEY
-            );
-        }
-        return Ok(());
-    }
-    Err(anyhow!(
-        "r != *GX1 && r != GX2, r: {}, *GX1: {}, GX2: {}",
-        sign.r,
-        *GX1,
-        *GX2
-    ))
-}
diff --git a/primitives/src/taiko/mod.rs b/primitives/src/taiko/mod.rs
deleted file mode 100644
index 5da19820d..000000000
--- a/primitives/src/taiko/mod.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-pub mod anchor;
-pub mod consts;
-pub mod proposal;
-pub mod protocol_instance;
-pub mod utils;
-
-pub use anchor::*;
-pub use consts::*;
-pub use proposal::*;
-pub use protocol_instance::*;
-use thiserror_no_std::Error as ThisError;
-pub use utils::*;
-
-#[derive(ThisError, Debug)]
-#[error(transparent)]
-struct AbiEncodeError(#[from] alloy_sol_types::Error);
diff --git a/primitives/src/taiko/proposal.rs b/primitives/src/taiko/proposal.rs
deleted file mode 100644
index ec01d1e0a..000000000
--- a/primitives/src/taiko/proposal.rs
+++ /dev/null
@@ -1,19 +0,0 @@
-use alloy_sol_types::{sol, SolCall};
-use anyhow::{anyhow, Context, Result};
-
-use super::AbiEncodeError;
-
-sol! {
-    function proposeBlock(
-        bytes calldata params,
-        bytes calldata txList
-    )
-    {}
-}
-
-pub fn decode_propose_block_call_args(data: &[u8]) -> Result<proposeBlockCall> {
-    let propose_block_call = proposeBlockCall::abi_decode(data, false)
-        .map_err(|e| anyhow!(AbiEncodeError::from(e)))
-        .with_context(|| "failed to decode propose block call")?;
-    Ok(propose_block_call)
-}
diff --git a/primitives/src/taiko/protocol_instance.rs b/primitives/src/taiko/protocol_instance.rs
deleted file mode 100644
index c09971fbc..000000000
--- a/primitives/src/taiko/protocol_instance.rs
+++ /dev/null
@@ -1,126 +0,0 @@
-use alloc::vec::Vec;
-
-use alloy_primitives::{Address, B256};
-use alloy_sol_types::{sol, SolValue};
-use serde::{Deserialize, Serialize};
-
-use crate::keccak;
-
-sol! {
-    #[derive(Debug, Default, Deserialize, Serialize)]
-    struct EthDeposit {
-        address recipient;
-        uint96 amount;
-        uint64 id;
-    }
-
-    #[derive(Debug, Default, Deserialize, Serialize)]
-    struct BlockMetadata {
-        bytes32 l1Hash; // slot 1
-        bytes32 difficulty; // slot 2
-        bytes32 blobHash; //or txListHash (if Blob not yet supported), // slot 3
-        bytes32 extraData; // slot 4
-        bytes32 depositsHash; // slot 5
-        address coinbase; // L2 coinbase, // slot 6
-        uint64 id;
-        uint32 gasLimit;
-        uint64 timestamp; // slot 7
-        uint64 l1Height;
-        uint24 txListByteOffset;
-        uint24 txListByteSize;
-        uint16 minTier;
-        bool blobUsed;
-        bytes32 parentMetaHash; // slot 8
-    }
-
-    #[derive(Debug)]
-    struct Transition {
-        bytes32 parentHash;
-        bytes32 blockHash;
-        bytes32 signalRoot;
-        bytes32 graffiti;
-    }
-
-    #[derive(Debug, Default, Clone, Deserialize, Serialize)]
-    event BlockProposed(
-        uint256 indexed blockId,
-        address indexed prover,
-        uint96 livenessBond,
-        BlockMetadata meta,
-        EthDeposit[] depositsProcessed
-    );
-
-    #[derive(Debug)]
-    struct TierProof {
-        uint16 tier;
-        bytes data;
-    }
-
-    function proveBlock(uint64 blockId, bytes calldata input) {}
-}
-
-#[derive(Debug)]
-pub enum EvidenceType {
-    Sgx {
-        new_pubkey: Address, // the evidence signature public key
-    },
-    PseZk,
-}
-
-#[derive(Debug)]
-pub struct ProtocolInstance {
-    pub transition: Transition,
-    pub block_metadata: BlockMetadata,
-    pub prover: Address,
-}
-
-impl ProtocolInstance {
-    pub fn meta_hash(&self) -> B256 {
-        keccak::keccak(self.block_metadata.abi_encode()).into()
-    }
-
-    // keccak256(abi.encode(tran, newInstance, prover, metaHash))
-    pub fn hash(&self, evidence_type: EvidenceType) -> B256 {
-        match evidence_type {
-            EvidenceType::Sgx { new_pubkey } => keccak::keccak(
-                (
-                    self.transition.clone(),
-                    new_pubkey,
-                    self.prover,
-                    self.meta_hash(),
-                )
-                    .abi_encode(),
-            )
-            .into(),
-            EvidenceType::PseZk => todo!(),
-        }
-    }
-}
-
-pub fn deposits_hash(deposits: &[EthDeposit]) -> B256 {
-    keccak::keccak(deposits.abi_encode()).into()
-}
-
-#[cfg(test)]
-mod tests {
-    use alloy_sol_types::SolCall;
-
-    use super::*;
-    #[test]
-    fn test_prove_block_call() {
-        let input = "0x10d008bd000000000000000000000000000000000000000000000000000000000000299e0000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000034057a97bd6f6930af5ca9e7caf48e663588755b690e9de0f82486416960135939559b91a6700c8af9442fe68f4339066d1d7858263c6be97ebcaca787ef70b1a7f8be37f1ab1fe1209f525f7cbced8a86ed49d1813849896c99835628f8eea703b302e31382e302d64657600000000000000000000000000000000000000000000569e75fc77c1a856f6daaf9e69d8a9566ca34aa47f9133711ce065a571af0cfd000000000000000000000000e1e210594771824dad216568b91c9cb4ceed361c000000000000000000000000000000000000000000000000000000000000299e0000000000000000000000000000000000000000000000000000000000e4e1c00000000000000000000000000000000000000000000000000000000065a63e6400000000000000000000000000000000000000000000000000000000000b6785000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000056220000000000000000000000000000000000000000000000000000000000000064000000000000000000000000000000000000000000000000000000000000000012d5f89f4195325e38f76ac324b08c34ab0c5c9ec430fc00dd967aa44b0bd05c11a7c619d13210437142d7adae4025ee65581228d0a8ed7a0df022634b2f1feadb23b17eaa3a5d3a7cfede2fa7d1653ac512117963c9fbe5f2df6a9dd555041ff20f4e661443b23d0c39ddbbb2725002cd2f7d5edb84d1c1eed9d8c71ddeba300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000000c800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000059000000000041035896fb7ccbed43b0fd70a82758535f3aa70e317bc173b815f18c416274d39cdd4918013cb12ccffc959700b8ae824b4a421d462c6fa19e28bdc64d6f753d978e0e76c33ce84aadfa19b68163c99dc62a631b00000000000000";
-
-        let input_data = hex::decode(&input[2..]).unwrap();
-        let proveBlockCall { blockId, input } =
-            proveBlockCall::abi_decode(&input_data, false).unwrap();
-        // println!("blockId: {}", blockId);
-        let (meta, trans, proof) =
-            <(BlockMetadata, Transition, TierProof)>::abi_decode_params(&input, false).unwrap();
-        // println!("meta: {:?}", meta);
-        let meta_hash: B256 = keccak::keccak(meta.abi_encode()).into();
-        // println!("meta_hash: {:?}", meta_hash);
-        // println!("trans: {:?}", trans);
-        // println!("proof: {:?}", proof.tier);
-        // println!("proof: {:?}", hex::encode(proof.data));
-    }
-}
diff --git a/primitives/src/taiko/utils.rs b/primitives/src/taiko/utils.rs
deleted file mode 100644
index 32bf28a2a..000000000
--- a/primitives/src/taiko/utils.rs
+++ /dev/null
@@ -1,25 +0,0 @@
-use core::cmp::min;
-
-pub fn string_to_bytes32(input: &[u8]) -> [u8; 32] {
-    let mut bytes = [0u8; 32];
-    let len = min(input.len(), 32);
-    bytes[..len].copy_from_slice(&input[..len]);
-    bytes
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    #[test]
-    fn string_to_bytes32_test() {
-        let input = "";
-        let byte = string_to_bytes32(input.as_bytes());
-        assert_eq!(
-            byte,
-            [
-                0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
-                0, 0, 0, 0
-            ]
-        );
-    }
-}
diff --git a/primitives/src/transactions/ethereum.rs b/primitives/src/transactions/ethereum.rs
index f4b3982e9..c36654b1a 100644
--- a/primitives/src/transactions/ethereum.rs
+++ b/primitives/src/transactions/ethereum.rs
@@ -33,7 +33,6 @@ use alloy_primitives::{Address, Bytes, ChainId, TxNumber, B256, U256};
 use alloy_rlp::{Encodable, EMPTY_STRING_CODE};
 use alloy_rlp_derive::RlpEncodable;
 use anyhow::{anyhow, Context};
-use bytes::BufMut;
 use k256::{
     ecdsa::{RecoveryId, Signature as K256Signature, VerifyingKey as K256VerifyingKey},
     elliptic_curve::sec1::ToEncodedPoint,
@@ -42,12 +41,8 @@ use k256::{
 use serde::{Deserialize, Serialize};
 use thiserror_no_std::Error as ThisError;
 
-use crate::{
-    access_list::AccessList,
-    keccak::keccak,
-    signature::TxSignature,
-    transactions::{Transaction, TxEssence},
-};
+use super::signature::TxSignature;
+use crate::{access_list::AccessList, keccak::keccak, transactions::TxEssence};
 
 /// Represents a legacy Ethereum transaction as detailed in [EIP-155](https://eips.ethereum.org/EIPS/eip-155).
 ///
@@ -67,8 +62,8 @@ pub struct TxEssenceLegacy {
     pub gas_price: U256,
     /// The maximum amount of gas allocated for the transaction's execution.
     pub gas_limit: U256,
-    /// The 160-bit address of the intended recipient for a message call. For contract
-    /// creation transactions, this is null.
+    /// The 160-bit address of the intended recipient for a message call or
+    /// [TransactionKind::Create] for contract creation.
     pub to: TransactionKind,
     /// The amount, in Wei, to be transferred to the recipient of the message call.
     pub value: U256,
@@ -93,11 +88,12 @@ impl TxEssenceLegacy {
     /// Encodes the transaction essence into the provided `out` buffer for the purpose of
     /// signing.
     ///
-    /// The method follows the RLP encoding scheme. If a `chain_id` is present,
-    /// the encoding adheres to the specifications set out in [EIP-155](https://eips.ethereum.org/EIPS/eip-155).
+    /// According to EIP-155, if `chain_id` is present, `(chain_id, 0, 0)` must be
+    /// appended to the regular RLP encoding when computing the hash of a transaction for
+    /// the purposes of signing.
     pub fn signing_encode(&self, out: &mut dyn alloy_rlp::BufMut) {
         let mut payload_length = self.payload_length();
-        // Append chain ID according to EIP-155 if present
+        // append chain ID according to EIP-155 if present
         if let Some(chain_id) = self.chain_id {
             payload_length += chain_id.length() + 1 + 1;
         }
@@ -126,11 +122,11 @@ impl TxEssenceLegacy {
     /// including any additional bytes required for the encoding format.
     pub fn signing_length(&self) -> usize {
         let mut payload_length = self.payload_length();
-        // Append chain ID according to EIP-155 if present
+        // append chain ID according to EIP-155 if present
         if let Some(chain_id) = self.chain_id {
             payload_length += chain_id.length() + 1 + 1;
         }
-        alloy_rlp::length_of_length(payload_length) + payload_length
+        payload_length + alloy_rlp::length_of_length(payload_length)
     }
 }
 
@@ -141,6 +137,7 @@ impl Encodable for TxEssenceLegacy {
     ///
     /// This method follows the RLP encoding scheme, but intentionally omits the
     /// `chain_id` to ensure compatibility with legacy transactions.
+    #[inline]
     fn encode(&self, out: &mut dyn alloy_rlp::BufMut) {
         alloy_rlp::Header {
             list: true,
@@ -159,9 +156,10 @@ impl Encodable for TxEssenceLegacy {
     ///
     /// This method calculates the total length of the transaction when it is RLP-encoded,
     /// excluding the `chain_id`.
+    #[inline]
     fn length(&self) -> usize {
         let payload_length = self.payload_length();
-        alloy_rlp::length_of_length(payload_length) + payload_length
+        payload_length + alloy_rlp::length_of_length(payload_length)
     }
 }
 
@@ -300,9 +298,8 @@ impl Encodable for TransactionKind {
 /// Represents the core essence of an Ethereum transaction, specifically the portion that
 /// gets signed.
 ///
-/// The `TxEssence` enum provides a way to handle different types of Ethereum
-/// transactions, from legacy transactions to more recent types introduced by various
-/// Ethereum Improvement Proposals (EIPs).
+/// The [EthereumTxEssence] enum provides a way to handle different types of Ethereum
+/// transactions.
 #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
 pub enum EthereumTxEssence {
     /// Represents a legacy Ethereum transaction, which follows the original transaction
@@ -318,14 +315,13 @@ pub enum EthereumTxEssence {
     Eip1559(TxEssenceEip1559),
 }
 
-// Implement the Encodable trait for the TxEssence enum.
-// Ensures that each variant of the `TxEssence` enum can be RLP-encoded.
 impl Encodable for EthereumTxEssence {
     /// Encodes the [EthereumTxEssence] enum variant into the provided `out` buffer.
     ///
     /// Depending on the variant of the [EthereumTxEssence] enum, this method will
     /// delegate the encoding process to the appropriate transaction type's encoding
     /// method.
+    #[inline]
     fn encode(&self, out: &mut dyn alloy_rlp::BufMut) {
         match self {
             EthereumTxEssence::Legacy(tx) => tx.encode(out),
@@ -339,6 +335,7 @@ impl Encodable for EthereumTxEssence {
     /// Depending on the variant of the [EthereumTxEssence] enum, this method will
     /// delegate the length computation to the appropriate transaction type's length
     /// method.
+    #[inline]
     fn length(&self) -> usize {
         match self {
             EthereumTxEssence::Legacy(tx) => tx.length(),
@@ -353,7 +350,7 @@ impl EthereumTxEssence {
     ///
     /// This method calculates the Keccak hash of the data that needs to be signed
     /// for the transaction, ensuring the integrity and authenticity of the transaction.
-    pub(crate) fn signing_hash(&self) -> B256 {
+    pub fn signing_hash(&self) -> B256 {
         keccak(self.signing_data()).into()
     }
 
@@ -384,11 +381,10 @@ impl EthereumTxEssence {
         }
     }
 
-    /// Determines whether the y-coordinate of the ECDSA signature's associated public key
-    /// is odd.
+    /// Returns the parity of the y-value of the curve point for which `signature.r` is
+    /// the x-value. This is encoded in the `v` field of the signature.
     ///
-    /// This information is derived from the `v` component of the signature and is used
-    /// during public key recovery.
+    /// It returns `None` if the parity cannot be determined.
     fn is_y_odd(&self, signature: &TxSignature) -> Option<bool> {
         match self {
             EthereumTxEssence::Legacy(TxEssenceLegacy { chain_id: None, .. }) => {
@@ -404,13 +400,7 @@ impl EthereumTxEssence {
 }
 
 /// Converts a given value into a boolean based on its parity.
-///
-/// Returns:
-/// - `Some(true)` if the value is 1.
-/// - `Some(false)` if the value is 0.
-/// - `None` otherwise.
-#[inline]
-pub fn checked_bool(v: u64) -> Option<bool> {
+fn checked_bool(v: u64) -> Option<bool> {
     match v {
         0 => Some(false),
         1 => Some(true),
@@ -419,12 +409,7 @@ pub fn checked_bool(v: u64) -> Option<bool> {
 }
 
 impl TxEssence for EthereumTxEssence {
-    /// Determines the type of the transaction based on its essence.
-    ///
-    /// Returns a byte representing the transaction type:
-    /// - `0x00` for Legacy transactions.
-    /// - `0x01` for EIP-2930 transactions.
-    /// - `0x02` for EIP-1559 transactions.
+    /// Returns the EIP-2718 transaction type or `0x00` for Legacy transactions.
     fn tx_type(&self) -> u8 {
         match self {
             EthereumTxEssence::Legacy(_) => 0x00,
@@ -432,10 +417,7 @@ impl TxEssence for EthereumTxEssence {
             EthereumTxEssence::Eip1559(_) => 0x02,
         }
     }
-    /// Retrieves the gas limit set for the transaction.
-    ///
-    /// The gas limit represents the maximum amount of gas units that the transaction
-    /// is allowed to consume. It ensures that transactions don't run indefinitely.
+    /// Returns the gas limit set for the transaction.
     fn gas_limit(&self) -> U256 {
         match self {
             EthereumTxEssence::Legacy(tx) => tx.gas_limit,
@@ -443,10 +425,7 @@ impl TxEssence for EthereumTxEssence {
             EthereumTxEssence::Eip1559(tx) => tx.gas_limit,
         }
     }
-    /// Retrieves the recipient address of the transaction, if available.
-    ///
-    /// For contract creation transactions, this method returns `None` as there's no
-    /// recipient address.
+    /// Returns the recipient address of the transaction, if available.
     fn to(&self) -> Option<Address> {
         match self {
             EthereumTxEssence::Legacy(tx) => tx.to.into(),
@@ -455,10 +434,6 @@ impl TxEssence for EthereumTxEssence {
         }
     }
     /// Recovers the Ethereum address of the sender from the transaction's signature.
-    ///
-    /// This method uses the ECDSA recovery mechanism to derive the sender's public key
-    /// and subsequently their Ethereum address. If the recovery is unsuccessful, an
-    /// error is returned.
     fn recover_from(&self, signature: &TxSignature) -> anyhow::Result<Address> {
         let is_y_odd = self.is_y_odd(signature).context("v invalid")?;
         let signature =
@@ -482,11 +457,7 @@ impl TxEssence for EthereumTxEssence {
 
         Ok(Address::from_slice(&hash[12..]))
     }
-    /// Computes the length of the RLP-encoded payload in bytes for the transaction
-    /// essence.
-    ///
-    /// This method calculates the length of the transaction data when it is RLP-encoded,
-    /// which is used for serialization and deserialization in the Ethereum network.
+    /// Returns the length of the RLP-encoding payload in bytes.
     fn payload_length(&self) -> usize {
         match self {
             EthereumTxEssence::Legacy(tx) => tx.payload_length(),
@@ -494,21 +465,13 @@ impl TxEssence for EthereumTxEssence {
             EthereumTxEssence::Eip1559(tx) => tx._alloy_rlp_payload_length(),
         }
     }
-
-    fn encode_with_signature(&self, signature: &TxSignature, out: &mut dyn BufMut) {
-        // join the essence lists and the signature list into one
-        rlp_join_lists(self, signature, out);
-    }
-
-    #[inline]
-    fn length(transaction: &Transaction<Self>) -> usize {
-        let payload_length =
-            transaction.essence.payload_length() + transaction.signature.payload_length();
-        let mut length = payload_length + alloy_rlp::length_of_length(payload_length);
-        if transaction.essence.tx_type() != 0 {
-            length += 1;
+    /// Returns a reference to the transaction's call data
+    fn data(&self) -> &Bytes {
+        match self {
+            EthereumTxEssence::Legacy(tx) => &tx.data,
+            EthereumTxEssence::Eip2930(tx) => &tx.data,
+            EthereumTxEssence::Eip1559(tx) => &tx.data,
         }
-        length
     }
 }
 
@@ -516,43 +479,205 @@ impl TxEssence for EthereumTxEssence {
 #[error(transparent)]
 struct EcdsaError(#[from] k256::ecdsa::Error);
 
-/// Joins two RLP-encoded lists into a single RLP-encoded list.
-///
-/// This function takes two RLP-encoded lists, decodes their headers to ensure they are
-/// valid lists, and then combines their payloads into a single RLP-encoded list. The
-/// resulting list is written to the provided `out` buffer.
-///
-/// # Arguments
-///
-/// * `a` - The first RLP-encoded list to be joined.
-/// * `b` - The second RLP-encoded list to be joined.
-/// * `out` - The buffer where the resulting RLP-encoded list will be written.
-///
-/// # Panics
-///
-/// This function will panic if either `a` or `b` are not valid RLP-encoded lists.
-fn rlp_join_lists(a: impl Encodable, b: impl Encodable, out: &mut dyn alloy_rlp::BufMut) {
-    let a_buf = alloy_rlp::encode(a);
-    let header = alloy_rlp::Header::decode(&mut &a_buf[..]).unwrap();
-    if !header.list {
-        panic!("`a` not a list");
+#[cfg(test)]
+mod tests {
+    use alloy_primitives::{address, b256};
+    use serde_json::json;
+
+    use super::*;
+    use crate::transactions::EthereumTransaction;
+
+    #[test]
+    fn legacy() {
+        // Tx: 0x5c504ed432cb51138bcf09aa5e8a410dd4a1e204ef84bfed1be16dfba1b22060
+        let tx = json!({
+                "Legacy": {
+                    "nonce": 0,
+                    "gas_price": "0x2d79883d2000",
+                    "gas_limit": "0x5208",
+                    "to": { "Call": "0x5df9b87991262f6ba471f09758cde1c0fc1de734" },
+                    "value": "0x7a69",
+                    "data": "0x"
+                  }
+        });
+        let essence: EthereumTxEssence = serde_json::from_value(tx).unwrap();
+
+        let signature: TxSignature = serde_json::from_value(json!({
+            "v": 28,
+            "r": "0x88ff6cf0fefd94db46111149ae4bfc179e9b94721fffd821d38d16464b3f71d0",
+            "s": "0x45e0aff800961cfce805daef7016b9b675c137a6a41a548f7b60a3484c06a33a"
+        }))
+        .unwrap();
+        let transaction = EthereumTransaction { essence, signature };
+
+        // verify that bincode serialization works
+        let _: EthereumTransaction =
+            bincode::deserialize(&bincode::serialize(&transaction).unwrap()).unwrap();
+
+        assert_eq!(
+            transaction.hash(),
+            b256!("5c504ed432cb51138bcf09aa5e8a410dd4a1e204ef84bfed1be16dfba1b22060")
+        );
+        let recovered = transaction.recover_from().unwrap();
+        assert_eq!(
+            recovered,
+            address!("a1e4380a3b1f749673e270229993ee55f35663b4")
+        );
+    }
+
+    #[test]
+    fn eip155() {
+        // Tx: 0x4540eb9c46b1654c26353ac3c65e56451f711926982ce1b02f15c50e7459caf7
+        let tx = json!({
+                "Legacy": {
+                    "nonce": 537760,
+                    "gas_price": "0x03c49bfa04",
+                    "gas_limit": "0x019a28",
+                    "to": { "Call": "0xf0ee707731d1be239f9f482e1b2ea5384c0c426f" },
+                    "value": "0x06df842eaa9fb800",
+                    "data": "0x",
+                    "chain_id": 1
+                  }
+        });
+        let essence: EthereumTxEssence = serde_json::from_value(tx).unwrap();
+
+        let signature: TxSignature = serde_json::from_value(json!({
+            "v": 38,
+            "r": "0xcadd790a37b78e5613c8cf44dc3002e3d7f06a5325d045963c708efe3f9fdf7a",
+            "s": "0x1f63adb9a2d5e020c6aa0ff64695e25d7d9a780ed8471abe716d2dc0bf7d4259"
+        }))
+        .unwrap();
+        let transaction = EthereumTransaction { essence, signature };
+
+        // verify that bincode serialization works
+        let _: EthereumTransaction =
+            bincode::deserialize(&bincode::serialize(&transaction).unwrap()).unwrap();
+
+        assert_eq!(
+            transaction.hash(),
+            b256!("4540eb9c46b1654c26353ac3c65e56451f711926982ce1b02f15c50e7459caf7")
+        );
+        let recovered = transaction.recover_from().unwrap();
+        assert_eq!(
+            recovered,
+            address!("974caa59e49682cda0ad2bbe82983419a2ecc400")
+        );
     }
-    let a_head_length = header.length();
-    let a_payload_length = a_buf.len() - a_head_length;
 
-    let b_buf = alloy_rlp::encode(b);
-    let header = alloy_rlp::Header::decode(&mut &b_buf[..]).unwrap();
-    if !header.list {
-        panic!("`b` not a list");
+    #[test]
+    fn eip2930() {
+        // Tx: 0xbe4ef1a2244e99b1ef518aec10763b61360be22e3b649dcdf804103719b1faef
+        let tx = json!({
+          "Eip2930": {
+            "chain_id": 1,
+            "nonce": 93847,
+            "gas_price": "0xf46a5a9d8",
+            "gas_limit": "0x21670",
+            "to": { "Call": "0xc11ce44147c9f6149fbe54adb0588523c38718d7" },
+            "value": "0x10d1471",
+            "data": "0x050000000002b8809aef26206090eafd7d5688615d48197d1c5ce09be6c30a33be4c861dee44d13f6dd33c2e8c5cad7e2725f88a8f0000000002d67ca5eb0e5fb6",
+            "access_list": [
+              {
+                "address": "0xd6e64961ba13ba42858ad8a74ed9a9b051a4957d",
+                "storage_keys": [
+                  "0x0000000000000000000000000000000000000000000000000000000000000008",
+                  "0x0b4b38935f88a7bddbe6be76893de2a04640a55799d6160729a82349aff1ffae",
+                  "0xc59ee2ee2ba599569b2b1f06989dadbec5ee157c8facfe64f36a3e33c2b9d1bf"
+                ]
+              },
+              {
+                "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
+                "storage_keys": [
+                  "0x7635825e4f8dfeb20367f8742c8aac958a66caa001d982b3a864dcc84167be80",
+                  "0x42555691810bdf8f236c31de88d2cc9407a8ff86cd230ba3b7029254168df92a",
+                  "0x29ece5a5f4f3e7751868475502ab752b5f5fa09010960779bf7204deb72f5dde"
+                ]
+              },
+              {
+                "address": "0x4c861dee44d13f6dd33c2e8c5cad7e2725f88a8f",
+                "storage_keys": [
+                  "0x000000000000000000000000000000000000000000000000000000000000000c",
+                  "0x0000000000000000000000000000000000000000000000000000000000000008",
+                  "0x0000000000000000000000000000000000000000000000000000000000000006",
+                  "0x0000000000000000000000000000000000000000000000000000000000000007"
+                ]
+              },
+              {
+                "address": "0x90eafd7d5688615d48197d1c5ce09be6c30a33be",
+                "storage_keys": [
+                  "0x0000000000000000000000000000000000000000000000000000000000000001",
+                  "0x9c04773acff4c5c42718bd0120c72761f458e43068a3961eb935577d1ed4effb",
+                  "0x0000000000000000000000000000000000000000000000000000000000000008",
+                  "0x0000000000000000000000000000000000000000000000000000000000000000",
+                  "0x0000000000000000000000000000000000000000000000000000000000000004"
+                ]
+              }
+            ]
+          }
+        });
+        let essence: EthereumTxEssence = serde_json::from_value(tx).unwrap();
+
+        let signature: TxSignature = serde_json::from_value(json!({
+            "v": 1,
+            "r": "0xf86aa2dfde99b0d6a41741e96cfcdee0c6271febd63be4056911db19ae347e66",
+            "s": "0x601deefbc4835cb15aa1af84af6436fc692dea3428d53e7ff3d34a314cefe7fc"
+        }))
+        .unwrap();
+        let transaction = EthereumTransaction { essence, signature };
+
+        // verify that bincode serialization works
+        let _: EthereumTransaction =
+            bincode::deserialize(&bincode::serialize(&transaction).unwrap()).unwrap();
+
+        assert_eq!(
+            transaction.hash(),
+            b256!("be4ef1a2244e99b1ef518aec10763b61360be22e3b649dcdf804103719b1faef")
+        );
+        let recovered = transaction.recover_from().unwrap();
+        assert_eq!(
+            recovered,
+            address!("79b7a69d90c82e014bf0315e164208119b510fa0")
+        );
     }
-    let b_head_length = header.length();
-    let b_payload_length = b_buf.len() - b_head_length;
 
-    alloy_rlp::Header {
-        list: true,
-        payload_length: a_payload_length + b_payload_length,
+    #[test]
+    fn eip1559() {
+        // Tx: 0x2bcdc03343ca9c050f8dfd3c87f32db718c762ae889f56762d8d8bdb7c5d69ff
+        let tx = json!({
+                "Eip1559": {
+                  "chain_id": 1,
+                  "nonce": 32,
+                  "max_priority_fee_per_gas": "0x3b9aca00",
+                  "max_fee_per_gas": "0x89d5f3200",
+                  "gas_limit": "0x5b04",
+                  "to": { "Call": "0xa9d1e08c7793af67e9d92fe308d5697fb81d3e43" },
+                  "value": "0x1dd1f234f68cde2",
+                  "data": "0x",
+                  "access_list": []
+                }
+        });
+        let essence: EthereumTxEssence = serde_json::from_value(tx).unwrap();
+
+        let signature: TxSignature = serde_json::from_value(json!({
+            "v": 0,
+            "r": "0x2bdf47562da5f2a09f09cce70aed35ec9ac62f5377512b6a04cc427e0fda1f4d",
+            "s": "0x28f9311b515a5f17aa3ad5ea8bafaecfb0958801f01ca11fd593097b5087121b"
+        }))
+        .unwrap();
+        let transaction = EthereumTransaction { essence, signature };
+
+        // verify that bincode serialization works
+        let _: EthereumTransaction =
+            bincode::deserialize(&bincode::serialize(&transaction).unwrap()).unwrap();
+
+        assert_eq!(
+            transaction.hash(),
+            b256!("2bcdc03343ca9c050f8dfd3c87f32db718c762ae889f56762d8d8bdb7c5d69ff")
+        );
+        let recovered = transaction.recover_from().unwrap();
+        assert_eq!(
+            recovered,
+            address!("4b9f4114d50e7907bff87728a060ce8d53bf4cf7")
+        );
     }
-    .encode(out);
-    out.put_slice(&a_buf[a_head_length..]); // skip the header
-    out.put_slice(&b_buf[b_head_length..]); // skip the header
 }
diff --git a/primitives/src/transactions/mod.rs b/primitives/src/transactions/mod.rs
index 0b05aacb7..04f4baf31 100644
--- a/primitives/src/transactions/mod.rs
+++ b/primitives/src/transactions/mod.rs
@@ -13,50 +13,49 @@
 // limitations under the License.
 use core::{clone::Clone, option::Option};
 
-use alloy_primitives::{Address, TxHash};
+use alloy_primitives::{Address, Bytes, TxHash};
 use alloy_rlp::Encodable;
 use serde::{Deserialize, Serialize};
 
-use crate::{
-    keccak::keccak, signature::TxSignature, transactions::ethereum::EthereumTxEssence, U256,
+use self::{
+    optimism::{OptimismTxEssence, OPTIMISM_DEPOSITED_TX_TYPE},
+    signature::TxSignature,
 };
+use crate::{keccak::keccak, transactions::ethereum::EthereumTxEssence, U256};
 
 pub mod ethereum;
 pub mod optimism;
+pub mod signature;
 
 pub type EthereumTransaction = Transaction<EthereumTxEssence>;
+pub type OptimismTransaction = Transaction<OptimismTxEssence>;
 
-/// Represents a complete Ethereum transaction, encompassing its core essence and the
-/// associated signature.
+/// Represents a complete transaction, encompassing its core essence and the associated
+/// signature.
 ///
 /// The `Transaction` struct encapsulates both the core details of the transaction (the
 /// essence) and its cryptographic signature. The signature ensures the authenticity and
 /// integrity of the transaction, confirming it was issued by the rightful sender.
 #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
 pub struct Transaction<E: TxEssence> {
-    /// The core details of the transaction, which include its type (e.g., legacy,
-    /// EIP-2930, EIP-1559) and associated data (e.g., recipient address, value, gas
-    /// details).
+    /// The core details of the transaction, which includes the data that is signed.
     pub essence: E,
     /// The cryptographic signature associated with the transaction, generated by signing
     /// the transaction essence.
     pub signature: TxSignature,
 }
 
+/// Represents the core details of a [Transaction], specifically the portion that gets
+/// signed.
 pub trait TxEssence: Encodable + Clone {
-    /// Determines the type of the transaction based on its essence.
-    ///
-    /// Returns a byte representing the transaction type:
-    /// - `0x00` for Legacy transactions.
-    /// - `0x01` for EIP-2930 transactions.
-    /// - `0x02` for EIP-1559 transactions.
+    /// Returns the EIP-2718 transaction type or `0x00` for Legacy transactions.
     fn tx_type(&self) -> u8;
-    /// Retrieves the gas limit set for the transaction.
+    /// Returns the gas limit set for the transaction.
     ///
     /// The gas limit represents the maximum amount of gas units that the transaction
     /// is allowed to consume. It ensures that transactions don't run indefinitely.
     fn gas_limit(&self) -> U256;
-    /// Retrieves the recipient address of the transaction, if available.
+    /// Returns the recipient address of the transaction, if available.
     ///
     /// For contract creation transactions, this method returns `None` as there's no
     /// recipient address.
@@ -67,26 +66,16 @@ pub trait TxEssence: Encodable + Clone {
     /// and subsequently their Ethereum address. If the recovery is unsuccessful, an
     /// error is returned.
     fn recover_from(&self, signature: &TxSignature) -> anyhow::Result<Address>;
-    /// Computes the length of the RLP-encoded payload in bytes.
+    /// Returns the length of the RLP-encoding payload in bytes.
     ///
     /// This method calculates the combined length of all the individual fields
     /// of the transaction when they are RLP-encoded.
     fn payload_length(&self) -> usize;
-    /// RLP encodes the transaction essence and signature into the provided `out` buffer.
-    fn encode_with_signature(&self, signature: &TxSignature, out: &mut dyn alloy_rlp::BufMut);
-    /// Computes the length of an encompassing RLP-encoded [Transaction] struct in bytes.
-    ///
-    /// The computed length includes the lengths of the encoded transaction essence and
-    /// signature. If the transaction type (as per EIP-2718) is not zero, an
-    /// additional byte is added to the length.
-    fn length(transaction: &Transaction<Self>) -> usize;
+    /// Returns a reference to the transaction's call data
+    fn data(&self) -> &Bytes;
 }
 
-/// Provides RLP encoding functionality for the [Transaction] struct.
-///
-/// This implementation ensures that the entire transaction, including its essence and
-/// signature, can be RLP-encoded. The encoding process also considers the EIP-2718
-/// transaction type.
+/// Provides RLP encoding functionality for [Transaction].
 impl<E: TxEssence> Encodable for Transaction<E> {
     /// Encodes the [Transaction] struct into the provided `out` buffer.
     ///
@@ -96,13 +85,20 @@ impl<E: TxEssence> Encodable for Transaction<E> {
     /// reusing as much of the generated RLP code as possible.
     #[inline]
     fn encode(&self, out: &mut dyn alloy_rlp::BufMut) {
-        // prepend the EIP-2718 transaction type
-        match self.essence.tx_type() {
-            0 => {}
-            tx_type => out.put_u8(tx_type),
+        let tx_type = self.essence.tx_type();
+        // prepend the EIP-2718 transaction type for non-legacy transactions
+        if tx_type != 0 {
+            out.put_u8(tx_type);
         }
-        // encode according to essence type
-        self.essence.encode_with_signature(&self.signature, out);
+        if tx_type == OPTIMISM_DEPOSITED_TX_TYPE {
+            // optimism deposited transactions have no signature
+            self.essence.encode(out);
+            return;
+        }
+
+        // join the essence lists and the signature list into one
+        // this allows to reuse as much of the generated RLP code as possible
+        rlp_join_lists(&self.essence, &self.signature, out);
     }
 
     /// Computes the length of the RLP-encoded [Transaction] struct in bytes.
@@ -112,7 +108,22 @@ impl<E: TxEssence> Encodable for Transaction<E> {
     /// additional byte is added to the length.
     #[inline]
     fn length(&self) -> usize {
-        <E as TxEssence>::length(self)
+        let tx_type = self.essence.tx_type();
+        let payload_length = self.essence.payload_length()
+            + if tx_type == OPTIMISM_DEPOSITED_TX_TYPE {
+                // optimism deposited transactions have no signature
+                0
+            } else {
+                self.signature.payload_length()
+            };
+
+        let length = payload_length + alloy_rlp::length_of_length(payload_length);
+        // add the EIP-2718 transaction type for non-legacy transactions
+        if tx_type != 0 {
+            length + 1
+        } else {
+            length
+        }
     }
 }
 
@@ -120,6 +131,7 @@ impl<E: TxEssence> Transaction<E> {
     /// Calculates the Keccak hash of the RLP-encoded transaction.
     ///
     /// This hash uniquely identifies the transaction on the Ethereum network.
+    #[inline]
     pub fn hash(&self) -> TxHash {
         keccak(alloy_rlp::encode(self)).into()
     }
@@ -129,258 +141,83 @@ impl<E: TxEssence> Transaction<E> {
     /// This method uses the ECDSA recovery mechanism to derive the sender's public key
     /// and subsequently their Ethereum address. If the recovery is unsuccessful, an
     /// error is returned.
+    #[inline]
     pub fn recover_from(&self) -> anyhow::Result<Address> {
         self.essence.recover_from(&self.signature)
     }
 }
 
+/// Joins two RLP-encoded lists into a single RLP-encoded list.
+///
+/// This function takes two RLP-encoded lists, decodes their headers to ensure they are
+/// valid lists, and then combines their payloads into a single RLP-encoded list. The
+/// resulting list is written to the provided `out` buffer.
+///
+/// # Panics
+///
+/// This function will panic if either `a` or `b` are not valid RLP-encoded lists.
+fn rlp_join_lists(a: impl Encodable, b: impl Encodable, out: &mut dyn alloy_rlp::BufMut) {
+    let a_buf = alloy_rlp::encode(a);
+    let header = alloy_rlp::Header::decode(&mut &a_buf[..]).unwrap();
+    if !header.list {
+        panic!("`a` not a list");
+    }
+    let a_head_length = header.length();
+    let a_payload_length = a_buf.len() - a_head_length;
+
+    let b_buf = alloy_rlp::encode(b);
+    let header = alloy_rlp::Header::decode(&mut &b_buf[..]).unwrap();
+    if !header.list {
+        panic!("`b` not a list");
+    }
+    let b_head_length = header.length();
+    let b_payload_length = b_buf.len() - b_head_length;
+
+    alloy_rlp::Header {
+        list: true,
+        payload_length: a_payload_length + b_payload_length,
+    }
+    .encode(out);
+    out.put_slice(&a_buf[a_head_length..]); // skip the header
+    out.put_slice(&b_buf[b_head_length..]); // skip the header
+}
+
 #[cfg(test)]
 mod tests {
     use serde_json::json;
 
     use super::*;
+    use crate::transactions::EthereumTransaction;
 
     #[test]
-    fn legacy() {
-        // Tx: 0x5c504ed432cb51138bcf09aa5e8a410dd4a1e204ef84bfed1be16dfba1b22060
-        let tx = json!({
-                "Legacy": {
-                    "nonce": 0,
-                    "gas_price": "0x2d79883d2000",
-                    "gas_limit": "0x5208",
-                    "to": { "Call": "0x5df9b87991262f6ba471f09758cde1c0fc1de734" },
-                    "value": "0x7a69",
-                    "data": "0x"
-                  }
-        });
-        let essence: EthereumTxEssence = serde_json::from_value(tx).unwrap();
-
-        let signature: TxSignature = serde_json::from_value(json!({
-            "v": 28,
-            "r": "0x88ff6cf0fefd94db46111149ae4bfc179e9b94721fffd821d38d16464b3f71d0",
-            "s": "0x45e0aff800961cfce805daef7016b9b675c137a6a41a548f7b60a3484c06a33a"
-        }))
-        .unwrap();
-        let transaction = EthereumTransaction { essence, signature };
-
-        // verify that bincode serialization works
-        let _: EthereumTransaction =
-            bincode::deserialize(&bincode::serialize(&transaction).unwrap()).unwrap();
-
-        assert_eq!(
-            "0x5c504ed432cb51138bcf09aa5e8a410dd4a1e204ef84bfed1be16dfba1b22060",
-            transaction.hash().to_string()
-        );
-        let recovered = transaction.recover_from().unwrap();
-        assert_eq!(
-            "0xa1e4380a3b1f749673e270229993ee55f35663b4".to_lowercase(),
-            recovered.to_string().to_lowercase()
-        );
-    }
-
-    #[test]
-    fn eip155() {
-        // Tx: 0x4540eb9c46b1654c26353ac3c65e56451f711926982ce1b02f15c50e7459caf7
+    fn rlp_length() {
         let tx = json!({
-                "Legacy": {
-                    "nonce": 537760,
-                    "gas_price": "0x03c49bfa04",
-                    "gas_limit": "0x019a28",
-                    "to": { "Call": "0xf0ee707731d1be239f9f482e1b2ea5384c0c426f" },
-                    "value": "0x06df842eaa9fb800",
-                    "data": "0x",
-                    "chain_id": 1
-                  }
-        });
-        let essence: EthereumTxEssence = serde_json::from_value(tx).unwrap();
-
-        let signature: TxSignature = serde_json::from_value(json!({
+          "essence": {
+            "Legacy": {
+                "nonce": 537760,
+                "gas_price": "0x03c49bfa04",
+                "gas_limit": "0x019a28",
+                "to": { "Call": "0xf0ee707731d1be239f9f482e1b2ea5384c0c426f" },
+                "value": "0x06df842eaa9fb800",
+                "data": "0x",
+                "chain_id": 1
+              }
+          },
+          "signature": {
             "v": 38,
             "r": "0xcadd790a37b78e5613c8cf44dc3002e3d7f06a5325d045963c708efe3f9fdf7a",
             "s": "0x1f63adb9a2d5e020c6aa0ff64695e25d7d9a780ed8471abe716d2dc0bf7d4259"
-        }))
-        .unwrap();
-        let transaction = EthereumTransaction { essence, signature };
-
-        // verify that bincode serialization works
-        let _: EthereumTransaction =
-            bincode::deserialize(&bincode::serialize(&transaction).unwrap()).unwrap();
-
-        assert_eq!(
-            "0x4540eb9c46b1654c26353ac3c65e56451f711926982ce1b02f15c50e7459caf7",
-            transaction.hash().to_string()
-        );
-        let recovered = transaction.recover_from().unwrap();
-        assert_eq!(
-            "0x974caa59e49682cda0ad2bbe82983419a2ecc400".to_lowercase(),
-            recovered.to_string().to_lowercase()
-        );
-    }
-
-    #[test]
-    fn eip2930() {
-        // Tx: 0xbe4ef1a2244e99b1ef518aec10763b61360be22e3b649dcdf804103719b1faef
-        let tx = json!({
-          "Eip2930": {
-            "chain_id": 1,
-            "nonce": 93847,
-            "gas_price": "0xf46a5a9d8",
-            "gas_limit": "0x21670",
-            "to": { "Call": "0xc11ce44147c9f6149fbe54adb0588523c38718d7" },
-            "value": "0x10d1471",
-            "data": "0x050000000002b8809aef26206090eafd7d5688615d48197d1c5ce09be6c30a33be4c861dee44d13f6dd33c2e8c5cad7e2725f88a8f0000000002d67ca5eb0e5fb6",
-            "access_list": [
-              {
-                "address": "0xd6e64961ba13ba42858ad8a74ed9a9b051a4957d",
-                "storage_keys": [
-                  "0x0000000000000000000000000000000000000000000000000000000000000008",
-                  "0x0b4b38935f88a7bddbe6be76893de2a04640a55799d6160729a82349aff1ffae",
-                  "0xc59ee2ee2ba599569b2b1f06989dadbec5ee157c8facfe64f36a3e33c2b9d1bf"
-                ]
-              },
-              {
-                "address": "0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2",
-                "storage_keys": [
-                  "0x7635825e4f8dfeb20367f8742c8aac958a66caa001d982b3a864dcc84167be80",
-                  "0x42555691810bdf8f236c31de88d2cc9407a8ff86cd230ba3b7029254168df92a",
-                  "0x29ece5a5f4f3e7751868475502ab752b5f5fa09010960779bf7204deb72f5dde"
-                ]
-              },
-              {
-                "address": "0x4c861dee44d13f6dd33c2e8c5cad7e2725f88a8f",
-                "storage_keys": [
-                  "0x000000000000000000000000000000000000000000000000000000000000000c",
-                  "0x0000000000000000000000000000000000000000000000000000000000000008",
-                  "0x0000000000000000000000000000000000000000000000000000000000000006",
-                  "0x0000000000000000000000000000000000000000000000000000000000000007"
-                ]
-              },
-              {
-                "address": "0x90eafd7d5688615d48197d1c5ce09be6c30a33be",
-                "storage_keys": [
-                  "0x0000000000000000000000000000000000000000000000000000000000000001",
-                  "0x9c04773acff4c5c42718bd0120c72761f458e43068a3961eb935577d1ed4effb",
-                  "0x0000000000000000000000000000000000000000000000000000000000000008",
-                  "0x0000000000000000000000000000000000000000000000000000000000000000",
-                  "0x0000000000000000000000000000000000000000000000000000000000000004"
-                ]
-              }
-            ]
           }
         });
-        let essence: EthereumTxEssence = serde_json::from_value(tx).unwrap();
+        let transaction: EthereumTransaction = serde_json::from_value(tx).unwrap();
 
-        let signature: TxSignature = serde_json::from_value(json!({
-            "v": 1,
-            "r": "0xf86aa2dfde99b0d6a41741e96cfcdee0c6271febd63be4056911db19ae347e66",
-            "s": "0x601deefbc4835cb15aa1af84af6436fc692dea3428d53e7ff3d34a314cefe7fc"
-        }))
-        .unwrap();
-        let transaction = EthereumTransaction { essence, signature };
+        let encoded = alloy_rlp::encode(&transaction.essence);
+        assert_eq!(encoded.len(), transaction.essence.length());
 
-        // verify that bincode serialization works
-        let _: EthereumTransaction =
-            bincode::deserialize(&bincode::serialize(&transaction).unwrap()).unwrap();
-
-        assert_eq!(
-            "0xbe4ef1a2244e99b1ef518aec10763b61360be22e3b649dcdf804103719b1faef",
-            transaction.hash().to_string()
-        );
-        let recovered = transaction.recover_from().unwrap();
-        assert_eq!(
-            "0x79b7a69d90c82e014bf0315e164208119b510fa0".to_lowercase(),
-            recovered.to_string().to_lowercase()
-        );
-    }
-
-    #[test]
-    fn eip1559() {
-        // Tx: 0x2bcdc03343ca9c050f8dfd3c87f32db718c762ae889f56762d8d8bdb7c5d69ff
-        let tx = json!({
-                "Eip1559": {
-                  "chain_id": 1,
-                  "nonce": 32,
-                  "max_priority_fee_per_gas": "0x3b9aca00",
-                  "max_fee_per_gas": "0x89d5f3200",
-                  "gas_limit": "0x5b04",
-                  "to": { "Call": "0xa9d1e08c7793af67e9d92fe308d5697fb81d3e43" },
-                  "value": "0x1dd1f234f68cde2",
-                  "data": "0x",
-                  "access_list": []
-                }
-        });
-        let essence: EthereumTxEssence = serde_json::from_value(tx).unwrap();
-
-        let signature: TxSignature = serde_json::from_value(json!({
-            "v": 0,
-            "r": "0x2bdf47562da5f2a09f09cce70aed35ec9ac62f5377512b6a04cc427e0fda1f4d",
-            "s": "0x28f9311b515a5f17aa3ad5ea8bafaecfb0958801f01ca11fd593097b5087121b"
-        }))
-        .unwrap();
-        let transaction = EthereumTransaction { essence, signature };
-
-        // verify that bincode serialization works
-        let _: EthereumTransaction =
-            bincode::deserialize(&bincode::serialize(&transaction).unwrap()).unwrap();
-
-        assert_eq!(
-            "0x2bcdc03343ca9c050f8dfd3c87f32db718c762ae889f56762d8d8bdb7c5d69ff",
-            transaction.hash().to_string()
-        );
-        let recovered = transaction.recover_from().unwrap();
-        assert_eq!(
-            "0x4b9f4114d50e7907bff87728a060ce8d53bf4cf7".to_lowercase(),
-            recovered.to_string().to_lowercase()
-        );
-    }
-
-    #[test]
-    fn rlp() {
-        // Tx: 0x275631a3549307b2e8c93b18dfcc0fe8aedf0276bb650c28eaa0a8a011d18867
-        let tx = json!({
-                "Eip1559": {
-                  "chain_id": 1,
-                  "nonce": 267,
-                  "max_priority_fee_per_gas": "0x05f5e100",
-                  "max_fee_per_gas": "0x0cb2bf61c2",
-                  "gas_limit": "0x0278be",
-                  "to": { "Call": "0x00005ea00ac477b1030ce78506496e8c2de24bf5" },
-                  "value": "0x01351609ff758000",
-                  "data": "0x161ac21f0000000000000000000000007de6f03b8b50b835f706e51a40b3224465802ddc0000000000000000000000000000a26b00c1f0df003000390027140000faa71900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003360c6ebe",
-                  "access_list": []
-                }
-        });
-        let essence: EthereumTxEssence = serde_json::from_value(tx).unwrap();
-
-        let encoded = alloy_rlp::encode(&essence);
-        assert_eq!(encoded.len(), essence.length());
-        assert_eq!(
-            essence.payload_length() + alloy_rlp::length_of_length(essence.payload_length()),
-            encoded.len()
-        );
-
-        let signature: TxSignature = serde_json::from_value(json!({
-            "v": 0,
-            "r": "0x5fc1441d3469a16715c862240794ef76656c284930e08820b79fd703a98b380a",
-            "s": "0x37488b0ceef613dc68116ed44b8e63769dbcf039222e25acc1cb9e85e777ade2"
-        }))
-        .unwrap();
-
-        let encoded = alloy_rlp::encode(&signature);
-        assert_eq!(encoded.len(), signature.length());
-        assert_eq!(
-            signature.payload_length() + alloy_rlp::length_of_length(signature.payload_length()),
-            encoded.len()
-        );
-
-        let transaction = EthereumTransaction { essence, signature };
+        let encoded = alloy_rlp::encode(&transaction.signature);
+        assert_eq!(encoded.len(), transaction.signature.length());
 
         let encoded = alloy_rlp::encode(&transaction);
         assert_eq!(encoded.len(), transaction.length());
-
-        assert_eq!(
-            "0x275631a3549307b2e8c93b18dfcc0fe8aedf0276bb650c28eaa0a8a011d18867",
-            transaction.hash().to_string()
-        );
     }
 }
diff --git a/primitives/src/transactions/optimism.rs b/primitives/src/transactions/optimism.rs
index cd01c46a1..8e2a7de3e 100644
--- a/primitives/src/transactions/optimism.rs
+++ b/primitives/src/transactions/optimism.rs
@@ -19,59 +19,54 @@ use alloy_rlp_derive::RlpEncodable;
 use bytes::BufMut;
 use serde::{Deserialize, Serialize};
 
-use crate::{
-    signature::TxSignature,
-    transactions::{
-        ethereum::{EthereumTxEssence, TransactionKind},
-        Transaction, TxEssence,
-    },
+use super::signature::TxSignature;
+use crate::transactions::{
+    ethereum::{EthereumTxEssence, TransactionKind},
+    TxEssence,
 };
 
+/// The EIP-2718 transaction type for an Optimism deposited transaction.
+pub const OPTIMISM_DEPOSITED_TX_TYPE: u8 = 0x7E;
+
+/// Represents an Optimism depositing transaction that is a L2 transaction that was
+/// derived from L1 and included in a L2 block.
 #[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize, RlpEncodable)]
 pub struct TxEssenceOptimismDeposited {
-    /// The source hash which uniquely identifies the origin of the deposit
+    /// The source hash which uniquely identifies the origin of the deposit.
     pub source_hash: B256,
     /// The 160-bit address of the sender.
     pub from: Address,
-    /// The 160-bit address of the message call's recipient or, for a contract creation
-    /// transaction, ∅.
+    /// The 160-bit address of the intended recipient for a message call or
+    /// [TransactionKind::Create] for contract creation.
     pub to: TransactionKind,
-    /// The ETH value to mint on L2
+    /// The ETH value to mint on L2.
     pub mint: U256,
-    /// A scalar value equal to the number of Wei to be transferred to the message call's
-    /// recipient.
+    /// The amount, in Wei, to be transferred to the recipient of the message call.
     pub value: U256,
-    /// A scalar value equal to the maximum amount of gas that should be used in executing
-    /// this transaction.
+    /// The maximum amount of gas allocated for the execution of the L2 transaction.
     pub gas_limit: U256,
     /// If true, the transaction does not interact with the L2 block gas pool.
-    /// Note: boolean is disabled (enforced to be false) starting from the Regolith
-    /// upgrade.
     pub is_system_tx: bool,
-    /// An unlimited size byte array specifying the transaction data.
+    /// The transaction's payload, represented as a variable-length byte array.
     pub data: Bytes,
 }
 
-impl TxEssenceOptimismDeposited {
-    pub fn payload_length(&self) -> usize {
-        self.source_hash.length()
-            + self.from.length()
-            + self.to.length()
-            + self.mint.length()
-            + self.value.length()
-            + self.gas_limit.length()
-            + self.is_system_tx.length()
-            + self.data.length()
-    }
-}
-
+/// Represents the core essence of an Optimism transaction, specifically the portion that
+/// gets signed.
+///
+/// The [OptimismTxEssence] enum provides a way to handle different types of Optimism
+/// transactions.
 #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
 pub enum OptimismTxEssence {
+    /// Represents an Ethereum-compatible L2 transaction.
     Ethereum(EthereumTxEssence),
+    /// Represents an Optimism depositing transaction.
     OptimismDeposited(TxEssenceOptimismDeposited),
 }
 
 impl Encodable for OptimismTxEssence {
+    /// Encodes the [OptimismTxEssence] enum variant into the provided `out` buffer.
+    #[inline]
     fn encode(&self, out: &mut dyn BufMut) {
         match self {
             OptimismTxEssence::Ethereum(eth) => eth.encode(out),
@@ -79,6 +74,8 @@ impl Encodable for OptimismTxEssence {
         }
     }
 
+    /// Computes the length of the RLP-encoded [OptimismTxEssence] enum variant in bytes.
+    #[inline]
     fn length(&self) -> usize {
         match self {
             OptimismTxEssence::Ethereum(eth) => eth.length(),
@@ -88,60 +85,144 @@ impl Encodable for OptimismTxEssence {
 }
 
 impl TxEssence for OptimismTxEssence {
+    /// Returns the EIP-2718 transaction type.
     fn tx_type(&self) -> u8 {
         match self {
             OptimismTxEssence::Ethereum(eth) => eth.tx_type(),
-            OptimismTxEssence::OptimismDeposited(_) => 0x7E,
+            OptimismTxEssence::OptimismDeposited(_) => OPTIMISM_DEPOSITED_TX_TYPE,
         }
     }
-
+    /// Returns the gas limit set for the transaction.
     fn gas_limit(&self) -> U256 {
         match self {
             OptimismTxEssence::Ethereum(eth) => eth.gas_limit(),
             OptimismTxEssence::OptimismDeposited(op) => op.gas_limit,
         }
     }
-
+    /// Returns the recipient address of the transaction, if available.
     fn to(&self) -> Option<Address> {
         match self {
             OptimismTxEssence::Ethereum(eth) => eth.to(),
             OptimismTxEssence::OptimismDeposited(op) => op.to.into(),
         }
     }
-
+    /// Recovers the Ethereum address of the sender from the transaction's signature.
     fn recover_from(&self, signature: &TxSignature) -> anyhow::Result<Address> {
         match self {
             OptimismTxEssence::Ethereum(eth) => eth.recover_from(signature),
             OptimismTxEssence::OptimismDeposited(op) => Ok(op.from),
         }
     }
-
+    /// Returns the length of the RLP-encoding payload in bytes.
     fn payload_length(&self) -> usize {
         match self {
             OptimismTxEssence::Ethereum(eth) => eth.payload_length(),
-            OptimismTxEssence::OptimismDeposited(op) => op.payload_length(),
+            OptimismTxEssence::OptimismDeposited(op) => op._alloy_rlp_payload_length(),
         }
     }
-
-    fn encode_with_signature(&self, signature: &TxSignature, out: &mut dyn BufMut) {
+    /// Returns a reference to the transaction's call data
+    fn data(&self) -> &Bytes {
         match self {
-            OptimismTxEssence::Ethereum(eth) => eth.encode_with_signature(signature, out),
-            OptimismTxEssence::OptimismDeposited(op) => op.encode(out),
+            OptimismTxEssence::Ethereum(eth) => eth.data(),
+            OptimismTxEssence::OptimismDeposited(op) => &op.data,
         }
     }
+}
 
-    #[inline]
-    fn length(transaction: &Transaction<Self>) -> usize {
-        let payload_length = match &transaction.essence {
-            OptimismTxEssence::Ethereum(eth) => {
-                eth.payload_length() + transaction.signature.payload_length()
+#[cfg(test)]
+mod tests {
+    use alloc::vec;
+
+    use alloy_primitives::{address, b256};
+    use serde_json::json;
+
+    use super::*;
+    use crate::transactions::OptimismTransaction;
+
+    #[test]
+    fn ethereum() {
+        // Tx: 0x9125dcdf2a82f349bbcd8c1201cc601b7b4f98975c76d1f8ee3ce9270334fb8a
+        let tx = json!({
+            "Ethereum": {
+                "Eip1559": {
+                  "chain_id": 10,
+                  "nonce": 17,
+                  "max_priority_fee_per_gas": "0x3b9cdd02",
+                  "max_fee_per_gas": "0x3b9cdd02",
+                  "gas_limit": "0x01a1a7",
+                  "to": { "Call": "0x7f5c764cbc14f9669b88837ca1490cca17c31607" },
+                  "value": "0x0",
+                  "data": "0x095ea7b30000000000000000000000004c5d5234f232bd2d76b96aa33f5ae4fcf0e4bfabffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+                  "access_list": []
+                }
             }
-            OptimismTxEssence::OptimismDeposited(op) => op.payload_length(),
+        });
+        let essence: OptimismTxEssence = serde_json::from_value(tx).unwrap();
+
+        let signature: TxSignature = serde_json::from_value(json!({
+            "v": 0,
+            "r": "0x044e091fe419b233ddc76c616f60f33f5c68a5d6ea315b0b22afdbe5af66b9e6",
+            "s": "0x7f00ccbff42777c6c2e5d5e85579a7984783be446cc1b9a7b8e080d167d56fa8"
+        }))
+        .unwrap();
+
+        let transaction = OptimismTransaction { essence, signature };
+
+        // verify that bincode serialization works
+        let _: OptimismTransaction =
+            bincode::deserialize(&bincode::serialize(&transaction).unwrap()).unwrap();
+
+        let encoded = alloy_rlp::encode(&transaction);
+        assert_eq!(encoded.len(), transaction.length());
+
+        assert_eq!(
+            transaction.hash(),
+            b256!("9125dcdf2a82f349bbcd8c1201cc601b7b4f98975c76d1f8ee3ce9270334fb8a")
+        );
+        let recovered = transaction.recover_from().unwrap();
+        assert_eq!(
+            recovered,
+            address!("96dd9c6f1fd5b3fbaa70898f09bedff903237d6d")
+        );
+    }
+
+    #[test]
+    fn optimism_deposited() {
+        // Tx: 0x2bf9119d4faa19593ca1b3cda4b4ac03c0ced487454a50fbdcd09aebe21210e3
+        let tx = json!({
+                "OptimismDeposited": {
+                    "source_hash": "0x20b925f36904e1e62099920d902925817c4357e9f674b8b14d13363196139010",
+                    "from": "0x36bde71c97b33cc4729cf772ae268934f7ab70b2",
+                    "to": { "Call": "0x4200000000000000000000000000000000000007" },
+                    "mint": "0x030d98d59a960000",
+                    "value": "0x030d98d59a960000",
+                    "gas_limit": "0x077d2e",
+                    "is_system_tx": false,
+                    "data": "0xd764ad0b000100000000000000000000000000000000000000000000000000000000af8600000000000000000000000099c9fc46f92e8a1c0dec1b1747d010903e884be10000000000000000000000004200000000000000000000000000000000000010000000000000000000000000000000000000000000000000030d98d59a9600000000000000000000000000000000000000000000000000000000000000030d4000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000a41635f5fd000000000000000000000000ab12275f2d91f87b301a4f01c9af4e83b3f45baa000000000000000000000000ab12275f2d91f87b301a4f01c9af4e83b3f45baa000000000000000000000000000000000000000000000000030d98d59a9600000000000000000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
+                  }
+        });
+        let essence: OptimismTxEssence = serde_json::from_value(tx).unwrap();
+
+        let transaction = OptimismTransaction {
+            essence,
+            signature: TxSignature::default(),
         };
-        let mut length = payload_length + alloy_rlp::length_of_length(payload_length);
-        if transaction.essence.tx_type() != 0 {
-            length += 1;
-        }
-        length
+
+        // verify that bincode serialization works
+        let _: OptimismTransaction =
+            bincode::deserialize(&bincode::serialize(&transaction).unwrap()).unwrap();
+
+        let encoded = alloy_rlp::encode(&transaction);
+        assert_eq!(encoded.len(), transaction.length());
+
+        assert_eq!(
+            transaction.hash(),
+            b256!("2bf9119d4faa19593ca1b3cda4b4ac03c0ced487454a50fbdcd09aebe21210e3")
+        );
+        let recovered = transaction.recover_from().unwrap();
+        assert_eq!(
+            recovered,
+            address!("36bde71c97b33cc4729cf772ae268934f7ab70b2")
+        );
     }
 }
diff --git a/primitives/src/signature.rs b/primitives/src/transactions/signature.rs
similarity index 93%
rename from primitives/src/signature.rs
rename to primitives/src/transactions/signature.rs
index 7feb94944..6b110c1ad 100644
--- a/primitives/src/signature.rs
+++ b/primitives/src/transactions/signature.rs
@@ -21,7 +21,9 @@ use serde::{Deserialize, Serialize};
 /// The `TxSignature` struct encapsulates the components of an ECDSA signature: `v`, `r`,
 /// and `s`. This signature can be used to recover the public key of the signer, ensuring
 /// the authenticity of the transaction.
-#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, RlpEncodable, RlpMaxEncodedLen)]
+#[derive(
+    Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, RlpEncodable, RlpMaxEncodedLen,
+)]
 pub struct TxSignature {
     pub v: u64,
     pub r: U256,
diff --git a/raiko-guest/src/one_shot.rs b/raiko-guest/src/one_shot.rs
index b8a5234cb..f58ac4673 100644
--- a/raiko-guest/src/one_shot.rs
+++ b/raiko-guest/src/one_shot.rs
@@ -11,13 +11,17 @@ use base64_serde::base64_serde_type;
 use secp256k1::KeyPair;
 use serde::Serialize;
 use zeth_lib::{
-    consts::{get_taiko_chain_spec, ChainSpec, ETH_MAINNET_CHAIN_SPEC},
-    host::{taiko::TaikoExtra, Init},
+    builder::{BlockBuilderStrategy, TaikoStrategy},
+    consts::TKO_MAINNET_CHAIN_SPEC,
     input::Input,
-    taiko::block_builder::{TaikoBlockBuilder, TaikoStrategyBundle},
+    taiko::{
+        host::{init_taiko, HostArgs},
+        protocol_instance::{assemble_protocol_instance, EvidenceType},
+        TaikoSystemInfo,
+    },
     EthereumTxEssence,
 };
-use zeth_primitives::{taiko::EvidenceType, Address, B256};
+use zeth_primitives::{Address, B256};
 base64_serde_type!(Base64Standard, base64::engine::general_purpose::STANDARD);
 
 use crate::{
@@ -87,7 +91,7 @@ pub fn bootstrap(global_opts: GlobalOpts) -> Result<()> {
     println!("Public key: 0x{}", key_pair.public_key());
     let new_instance = public_key_to_address(&key_pair.public_key());
     save_attestation_user_report_data(new_instance)?;
-    println!("Instance address: {}", new_instance);
+    println!("Instance address: {new_instance}");
     let quote = get_sgx_quote()?;
     let bootstrap_details_file_path = global_opts.config_dir.join(BOOTSTRAP_INFO_FILENAME);
     save_bootstrap_details(&key_pair, new_instance, quote, &bootstrap_details_file_path)?;
@@ -101,13 +105,10 @@ pub fn bootstrap(global_opts: GlobalOpts) -> Result<()> {
 
 pub async fn one_shot(global_opts: GlobalOpts, args: OneShotArgs) -> Result<()> {
     if !is_bootstrapped(&global_opts.secrets_dir) {
-        bail!("Application was not bootstrapped. Bootstrap it first.")
+        bail!("Application was not bootstrapped. Bootstrap it first.");
     }
 
-    println!(
-        "Global options: {:?}, OneShot options: {:?}",
-        global_opts, args
-    );
+    println!("Global options: {global_opts:?}, OneShot options: {args:?}");
 
     let path_str = args.blocks_data_file.to_string_lossy().to_string();
     let block_no = u64::from_str(&String::from(
@@ -118,18 +119,17 @@ pub async fn one_shot(global_opts: GlobalOpts, args: OneShotArgs) -> Result<()>
             .unwrap(),
     ))?;
 
-    println!("Reading input file {} (block no: {})", path_str, block_no);
+    println!("Reading input file {path_str} (block no: {block_no})");
 
     let privkey_path = global_opts.secrets_dir.join(PRIV_KEY_FILENAME);
     let prev_privkey = load_private_key(&privkey_path)?;
     // let (new_privkey, new_pubkey) = generate_new_keypair()?;
     let new_pubkey = public_key(&prev_privkey);
     let new_instance = public_key_to_address(&new_pubkey);
-    let l2_chain_spec = get_taiko_chain_spec(&args.l2_chain.unwrap());
 
     // fs::write(privkey_path, new_privkey.to_bytes())?;
     let pi_hash = get_data_to_sign(
-        &l2_chain_spec,
+        "testnet".to_string(),
         path_str,
         args.l1_blocks_data_file.to_string_lossy().to_string(),
         args.prover,
@@ -139,7 +139,7 @@ pub async fn one_shot(global_opts: GlobalOpts, args: OneShotArgs) -> Result<()>
     )
     .await?;
 
-    println!("Data to be signed: {}", pi_hash);
+    println!("Data to be signed: {pi_hash}");
 
     let sig = sign_message(&prev_privkey, pi_hash)?;
 
@@ -153,12 +153,12 @@ pub async fn one_shot(global_opts: GlobalOpts, args: OneShotArgs) -> Result<()>
     save_attestation_user_report_data(new_instance)?;
     let quote = get_sgx_quote()?;
     let data = serde_json::json!({
-        "proof": format!("0x{}", proof),
+        "proof": format!("0x{proof}"),
         "quote": hex::encode(quote),
-        "public_key": format!("0x{}", new_pubkey),
+        "public_key": format!("0x{new_pubkey}"),
         "instance_address": new_instance.to_string(),
     });
-    println!("{}", data);
+    println!("{data}");
 
     print_sgx_info()
 }
@@ -169,7 +169,7 @@ fn is_bootstrapped(secrets_dir: &Path) -> bool {
 }
 
 async fn get_data_to_sign(
-    l2_chain_spec: &ChainSpec,
+    testnet: String,
     path_str: String,
     l1_blocks_path: String,
     prover: Address,
@@ -177,8 +177,8 @@ async fn get_data_to_sign(
     block_no: u64,
     new_pubkey: Address,
 ) -> Result<B256> {
-    let (init, extra) = parse_to_init(
-        l2_chain_spec,
+    let (input, sys_info) = parse_to_init(
+        testnet,
         path_str,
         l1_blocks_path,
         prover,
@@ -186,40 +186,39 @@ async fn get_data_to_sign(
         graffiti,
     )
     .await?;
-    let input: Input<zeth_lib::EthereumTxEssence> = init.clone().into();
-    let output = TaikoBlockBuilder::build_from(l2_chain_spec, input)
+    let (header, _mpt_node) = TaikoStrategy::build_from(&TKO_MAINNET_CHAIN_SPEC.clone(), input)
         .expect("Failed to build the resulting block");
-    let pi = zeth_lib::host::taiko::assemble_protocol_instance(&extra, &output)?;
-    let pi_hash = pi.hash(EvidenceType::Sgx { new_pubkey });
+    let pi = assemble_protocol_instance(&sys_info, &header)?;
+    let pi_hash = pi.instance_hash(EvidenceType::Sgx { new_pubkey });
     Ok(pi_hash)
 }
 
 async fn parse_to_init(
-    l2_chain_spec: &ChainSpec,
+    testnet: String,
     blocks_path: String,
     l1_blocks_path: String,
     prover: Address,
     block_no: u64,
     graffiti: B256,
-) -> Result<(Init<zeth_lib::EthereumTxEssence>, TaikoExtra), Error> {
-    let l2_chain_spec = l2_chain_spec.clone();
-    let (init, extra) = tokio::task::spawn_blocking(move || {
-        zeth_lib::host::taiko::get_taiko_initial_data::<TaikoStrategyBundle>(
-            Some(l1_blocks_path),
-            ETH_MAINNET_CHAIN_SPEC.clone(),
-            None,
-            prover,
-            Some(blocks_path),
-            l2_chain_spec,
-            None,
+) -> Result<(Input<EthereumTxEssence>, TaikoSystemInfo), Error> {
+    let (input, sys_info) = tokio::task::spawn_blocking(move || {
+        init_taiko(
+            HostArgs {
+                l1_cache: PathBuf::from_str(&l1_blocks_path).ok(),
+                l1_rpc: None,
+                l2_cache: PathBuf::from_str(&blocks_path).ok(),
+                l2_rpc: None,
+            },
+            TKO_MAINNET_CHAIN_SPEC.clone(),
+            &testnet,
             block_no,
             graffiti,
+            prover,
         )
-        .expect("Could not init")
+        .expect("Init taiko failed")
     })
     .await?;
-
-    Ok::<(Init<EthereumTxEssence>, TaikoExtra), _>((init, extra))
+    Ok((input, sys_info))
 }
 
 fn save_attestation_user_report_data(pubkey: Address) -> Result<()> {
@@ -230,7 +229,7 @@ fn save_attestation_user_report_data(pubkey: Address) -> Result<()> {
         .open(ATTESTATION_USER_REPORT_DATA_DEVICE_FILE)?;
     user_report_data_file
         .write_all(&extended_pubkey)
-        .map_err(|err| anyhow!("Failed to save user report data: {}", err))
+        .map_err(|err| anyhow!("Failed to save user report data: {err}"))
 }
 
 fn print_sgx_info() -> Result<()> {
@@ -280,15 +279,15 @@ fn print_sgx_info() -> Result<()> {
 
 fn get_sgx_attestation_type() -> Result<String> {
     let mut attestation_type = String::new();
-    if File::open(ATTESTATION_TYPE_DEVICE_FILE)
+    if !File::open(ATTESTATION_TYPE_DEVICE_FILE)
         .and_then(|mut file| file.read_to_string(&mut attestation_type))
         .is_ok()
     {
-        return Ok(attestation_type.trim().to_string());
+        bail!(
+            "Cannot find `{}`; are you running under SGX, with remote attestation enabled?",
+            ATTESTATION_TYPE_DEVICE_FILE
+        );
     }
 
-    bail!(
-        "Cannot find `{}`; are you running under SGX, with remote attestation enabled?",
-        ATTESTATION_TYPE_DEVICE_FILE
-    );
+    Ok(attestation_type.trim().to_string())
 }
diff --git a/raiko-guest/src/signature.rs b/raiko-guest/src/signature.rs
index 92bf53922..21084060a 100644
--- a/raiko-guest/src/signature.rs
+++ b/raiko-guest/src/signature.rs
@@ -5,7 +5,7 @@ use secp256k1::{
     ecdsa::{RecoverableSignature, RecoveryId},
     Error, KeyPair, Message, PublicKey, SecretKey, SECP256K1,
 };
-use zeth_primitives::{keccak256, signature::TxSignature, Address, B256, U256};
+use zeth_primitives::{keccak256, transactions::signature::TxSignature, Address, B256, U256};
 
 pub fn generate_key() -> KeyPair {
     KeyPair::new_global(&mut OsRng)
@@ -84,7 +84,7 @@ mod tests {
         let pubkey = public_key(&priv_key);
         let pub_addr = public_key_to_address(&pubkey);
         assert_eq!(pub_addr, proof_addr);
-        println!("Public address: {}", pub_addr);
-        println!("Proof public address: {}", proof_addr);
+        println!("Public address: {pub_addr}");
+        println!("Proof public address: {proof_addr}");
     }
 }
diff --git a/raiko-host/Cargo.toml b/raiko-host/Cargo.toml
index 87686bfc5..c3c251d2f 100644
--- a/raiko-host/Cargo.toml
+++ b/raiko-host/Cargo.toml
@@ -5,8 +5,8 @@ edition = "2021"
 
 [dependencies]
 anyhow = "1.0"
-alloy-sol-types = { version = "0.4", optional = true }
-alloy-primitives = { version = "0.4", default-features = false }
+alloy-sol-types = { version = "0.6", optional = true }
+alloy-primitives = { version = "0.6", default-features = false }
 bincode = "1.3.3"
 bonsai-sdk = { workspace = true }
 bytemuck = "1.13"
@@ -22,7 +22,7 @@ serde = "1.0"
 serde_with = "3.4.0"
 tempfile = "3.6"
 tokio = { version = "1.23", features = ["full"] }
-zeth-lib = { path = "../lib", features = ["taiko", "server", "std"] }
+zeth-lib = { path = "../lib", features = ["taiko", "std"] }
 zeth-primitives = { path = "../primitives", features = ["taiko"] }
 serde_json = "1.0"
 hyper = { version = "0.14.27", features = ["server"] }
diff --git a/raiko-host/src/prover/execution.rs b/raiko-host/src/prover/execution.rs
index 55e978e05..91774e864 100644
--- a/raiko-host/src/prover/execution.rs
+++ b/raiko-host/src/prover/execution.rs
@@ -1,7 +1,5 @@
 use std::time::Instant;
 
-use zeth_lib::taiko::block_builder::TaikoStrategyBundle;
-
 use super::{
     context::Context,
     error::Result,
@@ -39,7 +37,7 @@ pub async fn execute(
     let result = async {
         // 1. load input data into cache path
         let start = Instant::now();
-        let _ = prepare_input::<TaikoStrategyBundle>(ctx, req).await?;
+        let _ = prepare_input(ctx, req.clone()).await?;
         let elapsed = Instant::now().duration_since(start).as_millis() as i64;
         observe_input(elapsed);
         // 2. run proof
diff --git a/raiko-host/src/prover/prepare_input.rs b/raiko-host/src/prover/prepare_input.rs
index 0ebca4f55..926477d07 100644
--- a/raiko-host/src/prover/prepare_input.rs
+++ b/raiko-host/src/prover/prepare_input.rs
@@ -1,31 +1,26 @@
 //! Prepare Input for guest
-use std::fmt::Debug;
 
 use zeth_lib::{
-    block_builder::NetworkStrategyBundle,
-    consts::{get_taiko_chain_spec, ETH_MAINNET_CHAIN_SPEC},
-    host::{
-        provider::file_provider::cache_file_path,
-        taiko::{get_taiko_initial_data, TaikoExtra},
-        Init,
+    consts::TKO_MAINNET_CHAIN_SPEC,
+    input::Input,
+    taiko::{
+        host::{init_taiko, HostArgs},
+        TaikoSystemInfo,
     },
     EthereumTxEssence,
 };
 
 use super::{
     context::Context,
-    error::Result,
+    error::{Error, Result},
     request::{ProofRequest, PseZkRequest, SgxRequest},
 };
 
 /// prepare input data for guests
-pub async fn prepare_input<N: NetworkStrategyBundle<TxEssence = EthereumTxEssence>>(
+pub async fn prepare_input(
     ctx: &mut Context,
-    req: &ProofRequest,
-) -> Result<(Init<N::TxEssence>, TaikoExtra)>
-where
-    <N::Database as revm::primitives::db::Database>::Error: Debug,
-{
+    req: ProofRequest,
+) -> Result<(Input<EthereumTxEssence>, TaikoSystemInfo)> {
     match req {
         ProofRequest::Sgx(SgxRequest {
             block,
@@ -34,33 +29,28 @@ where
             prover,
             graffiti,
         }) => {
-            let l2_block = *block;
-
-            let l2_spec = get_taiko_chain_spec(&ctx.l2_chain);
-            let l2_rpc = l2_rpc.to_owned();
-
-            let l1_spec = ETH_MAINNET_CHAIN_SPEC.clone();
-            let l1_rpc = l1_rpc.to_owned();
-            let prover = prover.to_owned();
-            let graffiti = *graffiti;
-            // run sync task in blocking mode
-            let l1_cache_path = ctx.l1_cache_file.as_ref().unwrap().to_owned();
-            let l2_cache_path = ctx.l2_cache_file.as_ref().unwrap().to_owned();
+            // Todo(Cecilia): should contract address as args, curently hardcode
+            let l1_cache = ctx.l1_cache_file.clone();
+            let l2_cache = ctx.l2_cache_file.clone();
+            let testnet = ctx.l2_chain.clone();
             tokio::task::spawn_blocking(move || {
-                get_taiko_initial_data::<N>(
-                    Some(l1_cache_path.into_os_string().into_string().unwrap()),
-                    l1_spec,
-                    Some(l1_rpc),
-                    prover,
-                    Some(l2_cache_path.into_os_string().into_string().unwrap()),
-                    l2_spec,
-                    Some(l2_rpc),
-                    l2_block,
+                init_taiko(
+                    HostArgs {
+                        l1_cache,
+                        l1_rpc: Some(l1_rpc),
+                        l2_cache,
+                        l2_rpc: Some(l2_rpc),
+                    },
+                    TKO_MAINNET_CHAIN_SPEC.clone(),
+                    &testnet,
+                    block,
                     graffiti,
+                    prover,
                 )
+                .expect("Init taiko failed")
             })
-            .await?
-            .map_err(Into::into)
+            .await
+            .map_err(Into::<Error>::into)
         }
         ProofRequest::PseZk(PseZkRequest { .. }) => todo!(),
     }
diff --git a/raiko-host/src/prover/proof/powdr.rs b/raiko-host/src/prover/proof/powdr.rs
new file mode 100644
index 000000000..2fd82aae4
--- /dev/null
+++ b/raiko-host/src/prover/proof/powdr.rs
@@ -0,0 +1,83 @@
+use std::str;
+
+use serde_json::Value;
+use tokio::process::Command;
+use tracing::{debug, info};
+
+use crate::{
+    metrics::inc_sgx_error,
+    prover::{
+        consts::*,
+        context::Context,
+        request::{SgxRequest, SgxResponse},
+        utils::guest_executable_path,
+    },
+};
+
+pub async fn execute_sgx(ctx: &mut Context, req: &SgxRequest) -> Result<SgxResponse, String> {
+    let guest_path = guest_executable_path(&ctx.guest_path, SGX_PARENT_DIR);
+    debug!("Guest path: {:?}", guest_path);
+    let mut cmd = {
+        let bin_directory = guest_path
+            .parent()
+            .ok_or(String::from("missing sgx executable directory"))?;
+        let bin = guest_path
+            .file_name()
+            .ok_or(String::from("missing sgx executable"))?;
+        let mut cmd = Command::new("sudo");
+        cmd.current_dir(bin_directory)
+            .arg("gramine-sgx")
+            .arg(bin)
+            .arg("one-shot");
+        cmd
+    };
+    let output = cmd
+        .arg("--blocks-data-file")
+        .arg(ctx.l2_cache_file.as_ref().unwrap())
+        .arg("--l1-blocks-data-file")
+        .arg(ctx.l1_cache_file.as_ref().unwrap())
+        .arg("--prover")
+        .arg(req.prover.to_string())
+        .arg("--graffiti")
+        .arg(req.graffiti.to_string())
+        .arg("--sgx-instance-id")
+        .arg(ctx.sgx_context.instance_id.to_string())
+        .arg("--l2-chain")
+        .arg(&ctx.l2_chain)
+        .output()
+        .await
+        .map_err(|e| e.to_string())?;
+    info!("Sgx execution stderr: {:?}", str::from_utf8(&output.stderr));
+    info!("Sgx execution stdout: {:?}", str::from_utf8(&output.stdout));
+    if !output.status.success() {
+        inc_sgx_error(req.block);
+        Err(output.status.to_string())
+    } else {
+        parse_sgx_result(output.stdout)
+    }
+}
+
+fn parse_sgx_result(output: Vec<u8>) -> Result<SgxResponse, String> {
+    let mut json_value: Option<Value> = None;
+    let output = String::from_utf8(output).map_err(|e| e.to_string())?;
+
+    for line in output.lines() {
+        if let Ok(value) = serde_json::from_str::<Value>(line.trim()) {
+            json_value = Some(value);
+            break;
+        }
+    }
+
+    let extract_field = |field| {
+        json_value
+            .as_ref()
+            .and_then(|json| json.get(field).and_then(|v| v.as_str()))
+            .unwrap_or("")
+            .to_string()
+    };
+
+    let proof = extract_field("proof");
+    let quote = extract_field("quote");
+
+    Ok(SgxResponse { proof, quote })
+}
diff --git a/testing/ef-tests/Cargo.toml b/testing/ef-tests/Cargo.toml
index a6231be78..c3314bd27 100644
--- a/testing/ef-tests/Cargo.toml
+++ b/testing/ef-tests/Cargo.toml
@@ -18,6 +18,7 @@ zeth-lib = { path = "../../lib" }
 zeth-primitives = { path = "../../primitives" }
 
 [dev-dependencies]
+diff = "0.1"
 env_logger = "0.10"
 log = "0.4"
 risc0-zkvm = { workspace = true, features = ["prove"] }
diff --git a/testing/ef-tests/src/ethers.rs b/testing/ef-tests/src/ethers.rs
index 657c7cc05..bffdb68f2 100644
--- a/testing/ef-tests/src/ethers.rs
+++ b/testing/ef-tests/src/ethers.rs
@@ -12,8 +12,11 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
+use std::collections::BTreeSet;
+
 use ethers_core::types::{
-    Block, Bloom, Bytes, EIP1186ProofResponse, StorageProof, Transaction, H256, U256,
+    Block, Bloom, Bytes, EIP1186ProofResponse, StorageProof, Transaction, TransactionReceipt, H256,
+    U256,
 };
 use zeth_primitives::U256 as LibU256;
 
@@ -23,6 +26,7 @@ use super::*;
 pub struct TestProvider {
     pub state: TestState,
     pub header: Header,
+    pub post: TestState,
 }
 
 impl Provider for TestProvider {
@@ -62,14 +66,28 @@ impl Provider for TestProvider {
         })
     }
 
-    fn get_proof(&mut self, query: &ProofQuery) -> Result<EIP1186ProofResponse, anyhow::Error> {
-        assert_eq!(query.block_no, self.header.number);
+    fn get_block_receipts(
+        &mut self,
+        _query: &BlockQuery,
+    ) -> anyhow::Result<Vec<TransactionReceipt>> {
+        unimplemented!()
+    }
 
+    fn get_proof(&mut self, query: &ProofQuery) -> Result<EIP1186ProofResponse, anyhow::Error> {
         let indices = query
             .indices
             .iter()
             .map(|idx| LibU256::from_be_bytes(idx.0));
-        get_proof(from_ethers_h160(query.address), indices, &self.state)
+
+        match query.block_no {
+            n if n == self.header.number => {
+                get_proof(from_ethers_h160(query.address), indices, &self.state)
+            }
+            n if n == self.header.number + 1 => {
+                get_proof(from_ethers_h160(query.address), indices, &self.post)
+            }
+            _ => panic!("invalid block number: {}", query.block_no),
+        }
     }
 
     fn get_transaction_count(&mut self, query: &AccountQuery) -> Result<U256, anyhow::Error> {
@@ -125,7 +143,8 @@ impl Provider for TestProvider {
     }
 }
 
-fn build_tries(state: &TestState) -> (MptNode, HashMap<Address, MptNode>) {
+/// Builds the state trie and storage tries from the test state.
+pub fn build_tries(state: &TestState) -> (MptNode, HashMap<Address, MptNode>) {
     let mut state_trie = MptNode::default();
     let mut storage_tries = HashMap::new();
     for (address, account) in &state.0 {
@@ -168,9 +187,10 @@ fn get_proof(
         .into_iter()
         .map(|p| p.into())
         .collect();
-    let mut storage_proof = vec![];
-    for index in indices {
-        let proof = StorageProof {
+    let index_set = indices.into_iter().collect::<BTreeSet<_>>();
+    let storage_proof = index_set
+        .into_iter()
+        .map(|index| StorageProof {
             key: index.to_be_bytes().into(),
             proof: mpt_proof(&storage_trie, keccak(index.to_be_bytes::<32>()))?
                 .into_iter()
@@ -183,9 +203,8 @@ fn get_proof(
                 .unwrap_or_default()
                 .to_be_bytes()
                 .into(),
-        };
-        storage_proof.push(proof);
-    }
+        })
+        .collect::<Vec<_>>();
 
     Ok(EIP1186ProofResponse {
         address: address.into_array().into(),
@@ -197,17 +216,3 @@ fn get_proof(
         storage_proof,
     })
 }
-
-/// Get EIP-1186 proofs for a set of addresses and storage keys.
-pub fn get_state_update_proofs(
-    provider: &ProviderDb,
-    storage_keys: HashMap<Address, Vec<LibU256>>,
-) -> Result<HashMap<Address, EIP1186ProofResponse>, anyhow::Error> {
-    let state = provider.into();
-
-    let mut result = HashMap::new();
-    for (address, indices) in storage_keys {
-        result.insert(address, get_proof(address, indices, &state)?);
-    }
-    Ok(result)
-}
diff --git a/testing/ef-tests/src/lib.rs b/testing/ef-tests/src/lib.rs
index b701d93cf..421ae3df0 100644
--- a/testing/ef-tests/src/lib.rs
+++ b/testing/ef-tests/src/lib.rs
@@ -19,28 +19,26 @@ use hashbrown::HashMap;
 use serde::{Deserialize, Serialize};
 use serde_with::{serde_as, NoneAsEmptyString};
 use zeth_lib::{
-    block_builder::BlockBuilder,
+    builder::{BlockBuilder, BlockBuilderStrategy, EthereumStrategy},
     consts::ChainSpec,
-    execution::ethereum::EthTxExecStrategy,
     host::{
+        preflight::Data,
         provider::{AccountQuery, BlockQuery, ProofQuery, Provider, StorageQuery},
         provider_db::ProviderDb,
-        Init,
     },
     input::Input,
     mem_db::{AccountState, DbAccount, MemDb},
-    preparation::EthHeaderPrepStrategy,
 };
 use zeth_primitives::{
     access_list::{AccessList, AccessListItem},
     block::Header,
     ethers::from_ethers_h160,
     keccak::keccak,
-    signature::TxSignature,
     transactions::{
         ethereum::{
             EthereumTxEssence, TransactionKind, TxEssenceEip1559, TxEssenceEip2930, TxEssenceLegacy,
         },
+        signature::TxSignature,
         EthereumTransaction,
     },
     trie::{self, MptNode, MptNodeData, StateAccount},
@@ -48,10 +46,9 @@ use zeth_primitives::{
     Address, Bloom, Bytes, RlpBytes, StorageKey, B256, B64, U256, U64,
 };
 
-use crate::ethers::{get_state_update_proofs, TestProvider};
+use crate::ethers::TestProvider;
 
 pub mod ethers;
-
 pub mod ethtests;
 
 pub mod guests {
@@ -105,7 +102,7 @@ impl From<DbAccount> for TestAccount {
     }
 }
 
-#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
+#[derive(Debug, Clone, Default, Serialize, Deserialize, PartialEq, Eq)]
 #[serde(rename_all = "camelCase")]
 pub struct TestState(pub HashMap<Address, TestAccount>);
 
@@ -114,8 +111,10 @@ impl From<&MemDb> for TestState {
         TestState(
             db.accounts
                 .iter()
-                .filter(|(_, account)| account.state != AccountState::Deleted)
-                .map(|(addr, account)| (*addr, account.clone().into()))
+                .filter_map(|(addr, account)| {
+                    (account.state != AccountState::Deleted)
+                        .then_some((*addr, account.clone().into()))
+                })
                 .collect(),
         )
     }
@@ -287,17 +286,15 @@ fn proof_internal(node: &MptNode, key_nibs: &[u8]) -> Result<Vec<Vec<u8>>, anyho
     let mut path: Vec<Vec<u8>> = match node.as_data() {
         MptNodeData::Null | MptNodeData::Leaf(_, _) => vec![],
         MptNodeData::Branch(children) => {
-            let mut path = Vec::new();
-            for node in children.iter().flatten() {
-                path.extend(proof_internal(node, &key_nibs[1..])?);
+            let (i, tail) = key_nibs.split_first().unwrap();
+            match &children[*i as usize] {
+                Some(child) => proof_internal(child, tail)?,
+                None => vec![],
             }
-            path
         }
         MptNodeData::Extension(_, child) => {
-            let ext_nibs = node.nibs();
-            let ext_len = ext_nibs.len();
-            if key_nibs[..ext_len] == ext_nibs {
-                proof_internal(child, &key_nibs[ext_len..])?
+            if let Some(tail) = key_nibs.strip_prefix(node.nibs().as_slice()) {
+                proof_internal(child, tail)?
             } else {
                 vec![]
             }
@@ -314,17 +311,19 @@ pub const BIG_STACK_SIZE: usize = 8 * 1024 * 1024;
 
 pub fn create_input(
     chain_spec: &ChainSpec,
-    state: TestState,
     parent_header: Header,
+    parent_state: TestState,
     header: Header,
     transactions: Vec<TestTransaction>,
     withdrawals: Vec<Withdrawal>,
+    state: TestState,
 ) -> Input<EthereumTxEssence> {
     // create the provider DB
     let provider_db = ProviderDb::new(
         Box::new(TestProvider {
-            state,
+            state: parent_state,
             header: parent_header.clone(),
+            post: state,
         }),
         parent_header.number,
     );
@@ -350,29 +349,28 @@ pub fn create_input(
     };
 
     // create and run the block builder once to create the initial DB
-    let mut builder = BlockBuilder::new(chain_spec, input)
+    let mut builder = BlockBuilder::new(&chain_spec, input)
         .with_db(provider_db)
-        .prepare_header::<EthHeaderPrepStrategy>()
+        .prepare_header::<<EthereumStrategy as BlockBuilderStrategy>::HeaderPrepStrategy>()
         .unwrap()
-        .execute_transactions::<EthTxExecStrategy>()
+        .execute_transactions::<<EthereumStrategy as BlockBuilderStrategy>::TxExecStrategy>()
         .unwrap();
-
     let provider_db = builder.mut_db().unwrap();
 
-    let init_proofs = provider_db.get_initial_proofs().unwrap();
-    let fini_proofs =
-        get_state_update_proofs(provider_db, provider_db.get_latest_db().storage_keys()).unwrap();
+    let parent_proofs = provider_db.get_initial_proofs().unwrap();
+    let proofs = provider_db.get_latest_proofs().unwrap();
     let ancestor_headers = provider_db.get_ancestor_headers().unwrap();
 
-    Init {
+    let preflight_data = Data {
         db: provider_db.get_initial_db().clone(),
-        init_block: parent_header,
-        init_proofs,
-        fini_block: header,
-        fini_transactions: transactions,
-        fini_withdrawals: withdrawals,
-        fini_proofs,
+        parent_header,
+        parent_proofs,
+        header,
+        transactions,
+        withdrawals,
+        proofs,
         ancestor_headers,
-    }
-    .into()
+    };
+
+    preflight_data.try_into().unwrap()
 }
diff --git a/testing/ef-tests/testguest/Cargo.lock b/testing/ef-tests/testguest/Cargo.lock
index a0e246635..fa658e5ee 100644
--- a/testing/ef-tests/testguest/Cargo.lock
+++ b/testing/ef-tests/testguest/Cargo.lock
@@ -4,9 +4,9 @@ version = 3
 
 [[package]]
 name = "addr2line"
-version = "0.20.0"
+version = "0.21.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f4fa78e18c64fce05e902adecd7a5eed15a5e0a3439f7b0e169f0252214865e3"
+checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb"
 dependencies = [
  "gimli",
 ]
@@ -17,22 +17,29 @@ version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
 
+[[package]]
+name = "adler32"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234"
+
 [[package]]
 name = "ahash"
-version = "0.8.3"
+version = "0.8.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f"
+checksum = "42cd52102d3df161c77a887b608d7a4897d7cc112886a9537b738a887a03aaff"
 dependencies = [
  "cfg-if",
  "once_cell",
  "version_check",
+ "zerocopy",
 ]
 
 [[package]]
 name = "aho-corasick"
-version = "1.0.3"
+version = "1.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "86b8f9420f797f2d9e935edf629310eb938a0d839f984e25327f3c7eed22300c"
+checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
 dependencies = [
  "memchr",
 ]
@@ -45,9 +52,9 @@ checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5"
 
 [[package]]
 name = "alloy-primitives"
-version = "0.4.0"
+version = "0.6.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6b4084879b7257d5b95b9009837c07a1868bd7d60e66418a7764b9b580ae64e0"
+checksum = "f4b6fb2b432ff223d513db7f908937f63c252bee0af9b82bfd25b0a5dd1eb0d8"
 dependencies = [
  "alloy-rlp",
  "bytes",
@@ -56,6 +63,8 @@ dependencies = [
  "derive_more",
  "hex-literal",
  "itoa",
+ "k256",
+ "keccak-asm",
  "proptest",
  "rand",
  "ruint",
@@ -65,25 +74,23 @@ dependencies = [
 
 [[package]]
 name = "alloy-rlp"
-version = "0.3.2"
+version = "0.3.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f938f00332d63a5b0ac687bd6f46d03884638948921d9f8b50c59563d421ae25"
+checksum = "8d58d9f5da7b40e9bfff0b7e7816700be4019db97d4b6359fe7f94a9e22e42ac"
 dependencies = [
- "alloy-rlp-derive",
  "arrayvec",
  "bytes",
- "smol_str",
 ]
 
 [[package]]
 name = "alloy-rlp-derive"
-version = "0.3.2"
+version = "0.3.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9aa5bb468bc7c46e0c5074d418f575262ff79451242e5ac1380121ed4e23c4fd"
+checksum = "1a047897373be4bbb0224c1afdabca92648dc57a9c9ef6e7b0be3aff7a859c83"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.28",
+ "syn 2.0.48",
 ]
 
 [[package]]
@@ -103,9 +110,133 @@ dependencies = [
 
 [[package]]
 name = "anyhow"
-version = "1.0.72"
+version = "1.0.79"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca"
+
+[[package]]
+name = "ark-ff"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6b3235cc41ee7a12aaaf2c575a2ad7b46713a8a50bda2fc3b003a04845c05dd6"
+dependencies = [
+ "ark-ff-asm 0.3.0",
+ "ark-ff-macros 0.3.0",
+ "ark-serialize 0.3.0",
+ "ark-std 0.3.0",
+ "derivative",
+ "num-bigint",
+ "num-traits",
+ "paste",
+ "rustc_version 0.3.3",
+ "zeroize",
+]
+
+[[package]]
+name = "ark-ff"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba"
+dependencies = [
+ "ark-ff-asm 0.4.2",
+ "ark-ff-macros 0.4.2",
+ "ark-serialize 0.4.2",
+ "ark-std 0.4.0",
+ "derivative",
+ "digest 0.10.7",
+ "itertools",
+ "num-bigint",
+ "num-traits",
+ "paste",
+ "rustc_version 0.4.0",
+ "zeroize",
+]
+
+[[package]]
+name = "ark-ff-asm"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db02d390bf6643fb404d3d22d31aee1c4bc4459600aef9113833d17e786c6e44"
+dependencies = [
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "ark-ff-asm"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348"
+dependencies = [
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "ark-ff-macros"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db2fd794a08ccb318058009eefdf15bcaaaaf6f8161eb3345f907222bac38b20"
+dependencies = [
+ "num-bigint",
+ "num-traits",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "ark-ff-macros"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565"
+dependencies = [
+ "num-bigint",
+ "num-traits",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "ark-serialize"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d6c2b318ee6e10f8c2853e73a83adc0ccb88995aa978d8a3408d492ab2ee671"
+dependencies = [
+ "ark-std 0.3.0",
+ "digest 0.9.0",
+]
+
+[[package]]
+name = "ark-serialize"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5"
+dependencies = [
+ "ark-std 0.4.0",
+ "digest 0.10.7",
+ "num-bigint",
+]
+
+[[package]]
+name = "ark-std"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c"
+dependencies = [
+ "num-traits",
+ "rand",
+]
+
+[[package]]
+name = "ark-std"
+version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3b13c32d80ecc7ab747b80c3784bce54ee8a7a0cc4fbda9bf4cda2cf6fe90854"
+checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185"
+dependencies = [
+ "num-traits",
+ "rand",
+]
 
 [[package]]
 name = "arrayvec"
@@ -115,13 +246,13 @@ checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
 
 [[package]]
 name = "async-trait"
-version = "0.1.72"
+version = "0.1.77"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cc6dde6e4ed435a4c1ee4e73592f5ba9da2151af10076cc04858746af9352d09"
+checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.28",
+ "syn 2.0.48",
 ]
 
 [[package]]
@@ -132,19 +263,28 @@ checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c"
 dependencies = [
  "futures",
  "pharos",
- "rustc_version",
+ "rustc_version 0.4.0",
+]
+
+[[package]]
+name = "aurora-engine-modexp"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bfacad86e9e138fca0670949eb8ed4ffdf73a55bded8887efe0863cd1a3a6f70"
+dependencies = [
+ "hex",
+ "num",
 ]
 
 [[package]]
 name = "auto_impl"
-version = "1.1.0"
+version = "1.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fee3da8ef1276b0bee5dd1c7258010d8fffd31801447323115a25560e1327b89"
+checksum = "823b8bb275161044e2ac7a25879cb3e2480cb403e3943022c7c769c599b756aa"
 dependencies = [
- "proc-macro-error",
  "proc-macro2",
  "quote",
- "syn 1.0.109",
+ "syn 2.0.48",
 ]
 
 [[package]]
@@ -155,9 +295,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
 
 [[package]]
 name = "backtrace"
-version = "0.3.68"
+version = "0.3.69"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4319208da049c43661739c5fade2ba182f09d1dc2299b32298d3a31692b17e12"
+checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837"
 dependencies = [
  "addr2line",
  "cc",
@@ -182,9 +322,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
 
 [[package]]
 name = "base64"
-version = "0.21.2"
+version = "0.21.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d"
+checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
 
 [[package]]
 name = "base64ct"
@@ -192,29 +332,6 @@ version = "1.6.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
 
-[[package]]
-name = "bindgen"
-version = "0.66.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f2b84e06fc203107bfbad243f4aba2af864eb7db3b1cf46ea0a023b0b433d2a7"
-dependencies = [
- "bitflags 2.4.0",
- "cexpr",
- "clang-sys",
- "lazy_static",
- "lazycell",
- "log",
- "peeking_take_while",
- "prettyplease",
- "proc-macro2",
- "quote",
- "regex",
- "rustc-hash",
- "shlex",
- "syn 2.0.28",
- "which",
-]
-
 [[package]]
 name = "bit-set"
 version = "0.5.3"
@@ -238,9 +355,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 
 [[package]]
 name = "bitflags"
-version = "2.4.0"
+version = "2.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
+checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf"
 dependencies = [
  "serde",
 ]
@@ -264,7 +381,7 @@ version = "0.10.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe"
 dependencies = [
- "digest",
+ "digest 0.10.7",
 ]
 
 [[package]]
@@ -290,9 +407,9 @@ dependencies = [
 
 [[package]]
 name = "bumpalo"
-version = "3.13.0"
+version = "3.14.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
+checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
 
 [[package]]
 name = "byte-slice-cast"
@@ -302,46 +419,45 @@ checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c"
 
 [[package]]
 name = "bytemuck"
-version = "1.13.1"
+version = "1.14.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea"
+checksum = "a2ef034f05691a48569bd920a96c81b9d91bbad1ab5ac7c4616c1f6ef36cb79f"
 dependencies = [
  "bytemuck_derive",
 ]
 
 [[package]]
 name = "bytemuck_derive"
-version = "1.4.1"
+version = "1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fdde5c9cd29ebd706ce1b35600920a33550e402fc998a2e53ad3b42c3c47a192"
+checksum = "965ab7eb5f8f97d2a083c799f3a1b994fc397b2fe2da5d1da1626ce15a39f2b1"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.28",
+ "syn 2.0.48",
 ]
 
 [[package]]
 name = "byteorder"
-version = "1.4.3"
+version = "1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
 
 [[package]]
 name = "bytes"
-version = "1.4.0"
+version = "1.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be"
+checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223"
 dependencies = [
  "serde",
 ]
 
 [[package]]
 name = "c-kzg"
-version = "0.1.1"
+version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac926d808fb72fe09ebf471a091d6d72918876ccf0b4989766093d2d0d24a0ef"
+checksum = "b9d8c306be83ec04bf5f73710badd8edf56dea23f2f0d8b7f9fe4644d371c758"
 dependencies = [
- "bindgen",
  "blst",
  "cc",
  "glob",
@@ -359,15 +475,6 @@ dependencies = [
  "libc",
 ]
 
-[[package]]
-name = "cexpr"
-version = "0.6.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766"
-dependencies = [
- "nom",
-]
-
 [[package]]
 name = "cfg-if"
 version = "1.0.0"
@@ -376,45 +483,35 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "chrono"
-version = "0.4.26"
+version = "0.4.34"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5"
+checksum = "5bc015644b92d5890fab7489e49d21f879d5c990186827d42ec511919404f38b"
 dependencies = [
  "android-tzdata",
  "iana-time-zone",
  "num-traits",
  "serde",
- "winapi",
-]
-
-[[package]]
-name = "clang-sys"
-version = "1.6.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c688fc74432808e3eb684cae8830a86be1d66a2bd58e1f248ed0960a590baf6f"
-dependencies = [
- "glob",
- "libc",
- "libloading",
+ "windows-targets 0.52.0",
 ]
 
 [[package]]
 name = "const-hex"
-version = "1.6.1"
+version = "1.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "268f52aae268980d03dd9544c1ea591965b2735b038d6998d6e4ab37c8c24445"
+checksum = "18d59688ad0945eaf6b84cb44fedbe93484c81b48970e98f09db8a22832d7961"
 dependencies = [
  "cfg-if",
  "cpufeatures",
  "hex",
+ "proptest",
  "serde",
 ]
 
 [[package]]
 name = "const-oid"
-version = "0.9.5"
+version = "0.9.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f"
+checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8"
 
 [[package]]
 name = "convert_case"
@@ -422,26 +519,45 @@ version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e"
 
+[[package]]
+name = "core-foundation"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
 [[package]]
 name = "core-foundation-sys"
-version = "0.8.4"
+version = "0.8.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
+checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f"
+
+[[package]]
+name = "core2"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b49ba7ef1ad6107f8824dbe97de947cbaac53c44e7f9756a1fba0d37c1eec505"
+dependencies = [
+ "memchr",
+]
 
 [[package]]
 name = "cpufeatures"
-version = "0.2.9"
+version = "0.2.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1"
+checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504"
 dependencies = [
  "libc",
 ]
 
 [[package]]
 name = "crc32fast"
-version = "1.3.2"
+version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
+checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa"
 dependencies = [
  "cfg-if",
 ]
@@ -476,9 +592,9 @@ dependencies = [
 
 [[package]]
 name = "darling"
-version = "0.20.3"
+version = "0.20.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e"
+checksum = "fc5d6b04b3fd0ba9926f945895de7d806260a2d7431ba82e7edaecb043c4c6b8"
 dependencies = [
  "darling_core",
  "darling_macro",
@@ -486,34 +602,40 @@ dependencies = [
 
 [[package]]
 name = "darling_core"
-version = "0.20.3"
+version = "0.20.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621"
+checksum = "04e48a959bcd5c761246f5d090ebc2fbf7b9cd527a492b07a67510c108f1e7e3"
 dependencies = [
  "fnv",
  "ident_case",
  "proc-macro2",
  "quote",
  "strsim",
- "syn 2.0.28",
+ "syn 2.0.48",
 ]
 
 [[package]]
 name = "darling_macro"
-version = "0.20.3"
+version = "0.20.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5"
+checksum = "1d1545d67a2149e1d93b7e5c7752dce5a7426eb5d1357ddcfd89336b94444f77"
 dependencies = [
  "darling_core",
  "quote",
- "syn 2.0.28",
+ "syn 2.0.48",
 ]
 
+[[package]]
+name = "dary_heap"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7762d17f1241643615821a8455a0b2c3e803784b058693d990b11f2dce25a0ca"
+
 [[package]]
 name = "data-encoding"
-version = "2.4.0"
+version = "2.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308"
+checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5"
 
 [[package]]
 name = "der"
@@ -527,13 +649,25 @@ dependencies = [
 
 [[package]]
 name = "deranged"
-version = "0.3.7"
+version = "0.3.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7684a49fb1af197853ef7b2ee694bc1f5b4179556f1e5710e1760c5db6f5e929"
+checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4"
 dependencies = [
+ "powerfmt",
  "serde",
 ]
 
+[[package]]
+name = "derivative"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
 [[package]]
 name = "derive_more"
 version = "0.99.17"
@@ -543,10 +677,19 @@ dependencies = [
  "convert_case",
  "proc-macro2",
  "quote",
- "rustc_version",
+ "rustc_version 0.4.0",
  "syn 1.0.109",
 ]
 
+[[package]]
+name = "digest"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
+dependencies = [
+ "generic-array",
+]
+
 [[package]]
 name = "digest"
 version = "0.10.7"
@@ -560,32 +703,19 @@ dependencies = [
 ]
 
 [[package]]
-name = "dyn_partial_eq"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a07039d197226c4b9a3810c4f165328fb4e715258a4b8584f143d38e9de04301"
-dependencies = [
- "dyn_partial_eq_derive",
-]
-
-[[package]]
-name = "dyn_partial_eq_derive"
-version = "0.1.2"
+name = "downcast-rs"
+version = "1.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0e217c6c1435ebf9b88662354589d339192b8eaf506edd22951e75e045c8e8bd"
-dependencies = [
- "quote",
- "syn 1.0.109",
-]
+checksum = "9ea835d29036a4087793836fa931b08837ad5e957da9e23886b29586fb9b6650"
 
 [[package]]
 name = "ecdsa"
-version = "0.16.8"
+version = "0.16.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4b1e0c257a9e9f25f90ff76d7a68360ed497ee519c8e428d1825ef0000799d4"
+checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca"
 dependencies = [
  "der",
- "digest",
+ "digest 0.10.7",
  "elliptic-curve",
  "rfc6979",
  "signature",
@@ -594,19 +724,25 @@ dependencies = [
 
 [[package]]
 name = "either"
-version = "1.9.0"
+version = "1.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a"
+
+[[package]]
+name = "elf"
+version = "0.7.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
+checksum = "4445909572dbd556c457c849c4ca58623d84b27c8fff1e74b0b4227d8b90d17b"
 
 [[package]]
 name = "elliptic-curve"
-version = "0.13.5"
+version = "0.13.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "968405c8fdc9b3bf4df0a6638858cc0b52462836ab6b1c87377785dd09cf1c0b"
+checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47"
 dependencies = [
  "base16ct",
  "crypto-bigint",
- "digest",
+ "digest 0.10.7",
  "ff",
  "generic-array",
  "group",
@@ -619,20 +755,20 @@ dependencies = [
 
 [[package]]
 name = "encoding_rs"
-version = "0.8.32"
+version = "0.8.33"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394"
+checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1"
 dependencies = [
  "cfg-if",
 ]
 
 [[package]]
 name = "enr"
-version = "0.8.1"
+version = "0.9.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf56acd72bb22d2824e66ae8e9e5ada4d0de17a69c7fd35569dde2ada8ec9116"
+checksum = "fe81b5c06ecfdbc71dd845216f225f53b62a10cb8a16c946836a3467f701d05b"
 dependencies = [
- "base64 0.13.1",
+ "base64 0.21.7",
  "bytes",
  "hex",
  "k256",
@@ -646,13 +782,13 @@ dependencies = [
 
 [[package]]
 name = "enumn"
-version = "0.1.11"
+version = "0.1.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b893c4eb2dc092c811165f84dc7447fae16fb66521717968c34c509b39b1a5c5"
+checksum = "6fd000fd6988e73bbe993ea3db9b1aa64906ab88766d654973924340c8cddb42"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.28",
+ "syn 2.0.48",
 ]
 
 [[package]]
@@ -661,34 +797,14 @@ version = "1.0.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
 
-[[package]]
-name = "erased-serde"
-version = "0.3.28"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da96524cc884f6558f1769b6c46686af2fe8e8b4cd253bd5a3cdba8181b8e070"
-dependencies = [
- "serde",
-]
-
 [[package]]
 name = "errno"
-version = "0.3.2"
+version = "0.3.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f"
+checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245"
 dependencies = [
- "errno-dragonfly",
- "libc",
- "windows-sys",
-]
-
-[[package]]
-name = "errno-dragonfly"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
-dependencies = [
- "cc",
  "libc",
+ "windows-sys 0.52.0",
 ]
 
 [[package]]
@@ -741,17 +857,17 @@ dependencies = [
 
 [[package]]
 name = "ethers-core"
-version = "2.0.8"
+version = "2.0.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "60ca2514feb98918a0a31de7e1983c29f2267ebf61b2dc5d4294f91e5b866623"
+checksum = "aab3cef6cc1c9fd7f787043c81ad3052eff2b96a3878ef1526aa446311bdbfc9"
 dependencies = [
  "arrayvec",
  "bytes",
  "chrono",
+ "const-hex",
  "elliptic-curve",
  "ethabi",
  "generic-array",
- "hex",
  "k256",
  "num_enum",
  "open-fastrlp",
@@ -768,14 +884,15 @@ dependencies = [
 
 [[package]]
 name = "ethers-providers"
-version = "2.0.8"
+version = "2.0.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b411b119f1cf0efb69e2190883dee731251882bb21270f893ee9513b3a697c48"
+checksum = "fb6b15393996e3b8a78ef1332d6483c11d839042c17be58decc92fa8b1c3508a"
 dependencies = [
  "async-trait",
  "auto_impl",
- "base64 0.21.2",
+ "base64 0.21.7",
  "bytes",
+ "const-hex",
  "enr",
  "ethers-core",
  "futures-channel",
@@ -783,9 +900,9 @@ dependencies = [
  "futures-timer",
  "futures-util",
  "hashers",
- "hex",
  "http",
  "instant",
+ "jsonwebtoken",
  "once_cell",
  "pin-project",
  "reqwest",
@@ -805,9 +922,20 @@ dependencies = [
 
 [[package]]
 name = "fastrand"
-version = "2.0.0"
+version = "2.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5"
+
+[[package]]
+name = "fastrlp"
+version = "0.3.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764"
+checksum = "139834ddba373bbdd213dffe02c8d110508dcf1726c2be27e8d1f7d7e1856418"
+dependencies = [
+ "arrayvec",
+ "auto_impl",
+ "bytes",
+]
 
 [[package]]
 name = "ff"
@@ -833,9 +961,9 @@ dependencies = [
 
 [[package]]
 name = "flate2"
-version = "1.0.26"
+version = "1.0.28"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743"
+checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e"
 dependencies = [
  "crc32fast",
  "miniz_oxide",
@@ -849,9 +977,9 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
 
 [[package]]
 name = "form_urlencoded"
-version = "1.2.0"
+version = "1.2.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652"
+checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
 dependencies = [
  "percent-encoding",
 ]
@@ -864,9 +992,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
 
 [[package]]
 name = "futures"
-version = "0.3.28"
+version = "0.3.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40"
+checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0"
 dependencies = [
  "futures-channel",
  "futures-core",
@@ -879,9 +1007,9 @@ dependencies = [
 
 [[package]]
 name = "futures-channel"
-version = "0.3.28"
+version = "0.3.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2"
+checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
 dependencies = [
  "futures-core",
  "futures-sink",
@@ -889,15 +1017,15 @@ dependencies = [
 
 [[package]]
 name = "futures-core"
-version = "0.3.28"
+version = "0.3.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c"
+checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
 
 [[package]]
 name = "futures-executor"
-version = "0.3.28"
+version = "0.3.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0"
+checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d"
 dependencies = [
  "futures-core",
  "futures-task",
@@ -906,32 +1034,32 @@ dependencies = [
 
 [[package]]
 name = "futures-io"
-version = "0.3.28"
+version = "0.3.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964"
+checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
 
 [[package]]
 name = "futures-macro"
-version = "0.3.28"
+version = "0.3.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
+checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.28",
+ "syn 2.0.48",
 ]
 
 [[package]]
 name = "futures-sink"
-version = "0.3.28"
+version = "0.3.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e"
+checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
 
 [[package]]
 name = "futures-task"
-version = "0.3.28"
+version = "0.3.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65"
+checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
 
 [[package]]
 name = "futures-timer"
@@ -945,9 +1073,9 @@ dependencies = [
 
 [[package]]
 name = "futures-util"
-version = "0.3.28"
+version = "0.3.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533"
+checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
 dependencies = [
  "futures-channel",
  "futures-core",
@@ -983,9 +1111,9 @@ dependencies = [
 
 [[package]]
 name = "getrandom"
-version = "0.2.10"
+version = "0.2.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427"
+checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5"
 dependencies = [
  "cfg-if",
  "libc",
@@ -994,9 +1122,9 @@ dependencies = [
 
 [[package]]
 name = "gimli"
-version = "0.27.3"
+version = "0.28.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e"
+checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253"
 
 [[package]]
 name = "glob"
@@ -1029,9 +1157,9 @@ dependencies = [
 
 [[package]]
 name = "h2"
-version = "0.3.20"
+version = "0.3.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "97ec8491ebaf99c8eaa73058b045fe58073cd6be7f596ac993ced0b0a0c01049"
+checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9"
 dependencies = [
  "bytes",
  "fnv",
@@ -1039,7 +1167,7 @@ dependencies = [
  "futures-sink",
  "futures-util",
  "http",
- "indexmap 1.9.3",
+ "indexmap 2.2.3",
  "slab",
  "tokio",
  "tokio-util",
@@ -1054,9 +1182,18 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
 
 [[package]]
 name = "hashbrown"
-version = "0.14.0"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
+dependencies = [
+ "ahash",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.14.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a"
+checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
 dependencies = [
  "ahash",
  "allocator-api2",
@@ -1080,9 +1217,9 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
 
 [[package]]
 name = "hermit-abi"
-version = "0.3.2"
+version = "0.3.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "443144c8cdadd93ebf52ddb4056d257f5b52c04d3c804e657d19eb73fc33668b"
+checksum = "bd5256b483761cd23699d0da46cc6fd2ee3be420bbe6d020ae4a091e70b7e9fd"
 
 [[package]]
 name = "hex"
@@ -1105,23 +1242,14 @@ version = "0.12.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
 dependencies = [
- "digest",
-]
-
-[[package]]
-name = "home"
-version = "0.5.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb"
-dependencies = [
- "windows-sys",
+ "digest 0.10.7",
 ]
 
 [[package]]
 name = "http"
-version = "0.2.9"
+version = "0.2.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482"
+checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb"
 dependencies = [
  "bytes",
  "fnv",
@@ -1130,9 +1258,9 @@ dependencies = [
 
 [[package]]
 name = "http-body"
-version = "0.4.5"
+version = "0.4.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1"
+checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2"
 dependencies = [
  "bytes",
  "http",
@@ -1147,15 +1275,15 @@ checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904"
 
 [[package]]
 name = "httpdate"
-version = "1.0.2"
+version = "1.0.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
+checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
 
 [[package]]
 name = "hyper"
-version = "0.14.27"
+version = "0.14.28"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ffb1cfd654a8219eaef89881fdb3bb3b1cdc5fa75ded05d6933b2b382e395468"
+checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80"
 dependencies = [
  "bytes",
  "futures-channel",
@@ -1168,7 +1296,7 @@ dependencies = [
  "httpdate",
  "itoa",
  "pin-project-lite",
- "socket2 0.4.9",
+ "socket2",
  "tokio",
  "tower-service",
  "tracing",
@@ -1177,9 +1305,9 @@ dependencies = [
 
 [[package]]
 name = "hyper-rustls"
-version = "0.24.1"
+version = "0.24.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8d78e1e73ec14cf7375674f74d7dde185c8206fd9dea6fb6295e8a98098aaa97"
+checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590"
 dependencies = [
  "futures-util",
  "http",
@@ -1191,16 +1319,16 @@ dependencies = [
 
 [[package]]
 name = "iana-time-zone"
-version = "0.1.57"
+version = "0.1.60"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613"
+checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141"
 dependencies = [
  "android_system_properties",
  "core-foundation-sys",
  "iana-time-zone-haiku",
  "js-sys",
  "wasm-bindgen",
- "windows",
+ "windows-core",
 ]
 
 [[package]]
@@ -1220,9 +1348,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
 
 [[package]]
 name = "idna"
-version = "0.4.0"
+version = "0.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c"
+checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6"
 dependencies = [
  "unicode-bidi",
  "unicode-normalization",
@@ -1279,12 +1407,12 @@ dependencies = [
 
 [[package]]
 name = "indexmap"
-version = "2.0.0"
+version = "2.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d5477fe2230a79769d8dc68e0eabf5437907c0457a5614a9e8dddb67f65eb65d"
+checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177"
 dependencies = [
  "equivalent",
- "hashbrown 0.14.0",
+ "hashbrown 0.14.3",
  "serde",
 ]
 
@@ -1298,36 +1426,53 @@ dependencies = [
 ]
 
 [[package]]
-name = "inventory"
-version = "0.3.11"
+name = "ipnet"
+version = "2.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a53088c87cf71c9d4f3372a2cb9eea1e7b8a0b1bf8b7f7d23fe5b76dbb07e63b"
+checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3"
 
 [[package]]
-name = "ipnet"
-version = "2.8.0"
+name = "itertools"
+version = "0.10.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6"
+checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
+dependencies = [
+ "either",
+]
 
 [[package]]
 name = "itoa"
-version = "1.0.9"
+version = "1.0.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38"
+checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
 
 [[package]]
 name = "js-sys"
-version = "0.3.64"
+version = "0.3.68"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a"
+checksum = "406cda4b368d531c842222cf9d2600a9a4acce8d29423695379c6868a143a9ee"
 dependencies = [
  "wasm-bindgen",
 ]
 
+[[package]]
+name = "jsonwebtoken"
+version = "8.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6971da4d9c3aa03c3d8f3ff0f4155b534aad021292003895a469716b2a230378"
+dependencies = [
+ "base64 0.21.7",
+ "pem",
+ "ring 0.16.20",
+ "serde",
+ "serde_json",
+ "simple_asn1",
+]
+
 [[package]]
 name = "k256"
-version = "0.13.1"
-source = "git+https://github.com/risc0/RustCrypto-elliptic-curves?tag=k256/v0.13.1-risczero.1#5fea17d53fbaa0ff72dbe16da3ee2c2d02f2490c"
+version = "0.13.3"
+source = "git+https://github.com/risc0/RustCrypto-elliptic-curves?tag=k256/v0.13.3-risczero.0#d4f457a04410397cbb652a67c168b6cd6e9757c4"
 dependencies = [
  "cfg-if",
  "ecdsa",
@@ -1339,61 +1484,79 @@ dependencies = [
 
 [[package]]
 name = "keccak"
-version = "0.1.4"
+version = "0.1.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8f6d5ed8676d904364de097082f4e7d240b571b67989ced0240f08b7f966f940"
+checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654"
 dependencies = [
  "cpufeatures",
 ]
 
+[[package]]
+name = "keccak-asm"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bb8515fff80ed850aea4a1595f2e519c003e2a00a82fe168ebf5269196caf444"
+dependencies = [
+ "digest 0.10.7",
+ "sha3-asm",
+]
+
 [[package]]
 name = "lazy_static"
 version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
 dependencies = [
- "spin",
+ "spin 0.5.2",
 ]
 
 [[package]]
-name = "lazycell"
-version = "1.3.0"
+name = "libc"
+version = "0.2.153"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55"
+checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
 
 [[package]]
-name = "libc"
-version = "0.2.148"
+name = "libflate"
+version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b"
+checksum = "9f7d5654ae1795afc7ff76f4365c2c8791b0feb18e8996a96adad8ffd7c3b2bf"
+dependencies = [
+ "adler32",
+ "core2",
+ "crc32fast",
+ "dary_heap",
+ "libflate_lz77",
+]
 
 [[package]]
-name = "libloading"
-version = "0.7.4"
+name = "libflate_lz77"
+version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f"
+checksum = "be5f52fb8c451576ec6b79d3f4deb327398bc05bbdbd99021a6e77a4c855d524"
 dependencies = [
- "cfg-if",
- "winapi",
+ "core2",
+ "hashbrown 0.13.2",
+ "rle-decode-fast",
 ]
 
 [[package]]
 name = "libm"
-version = "0.2.7"
+version = "0.2.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4"
+checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058"
 
 [[package]]
 name = "linux-raw-sys"
-version = "0.4.8"
+version = "0.4.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3852614a3bd9ca9804678ba6be5e3b8ce76dfc902cae004e3e0c44051b6e88db"
+checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c"
 
 [[package]]
 name = "lock_api"
-version = "0.4.10"
+version = "0.4.11"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16"
+checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45"
 dependencies = [
  "autocfg",
  "scopeguard",
@@ -1401,15 +1564,15 @@ dependencies = [
 
 [[package]]
 name = "log"
-version = "0.4.19"
+version = "0.4.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4"
+checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
 
 [[package]]
 name = "memchr"
-version = "2.5.0"
+version = "2.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
+checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149"
 
 [[package]]
 name = "mime"
@@ -1417,40 +1580,24 @@ version = "0.3.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
 
-[[package]]
-name = "minimal-lexical"
-version = "0.2.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
-
 [[package]]
 name = "miniz_oxide"
-version = "0.7.1"
+version = "0.7.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
+checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7"
 dependencies = [
  "adler",
 ]
 
 [[package]]
 name = "mio"
-version = "0.8.8"
+version = "0.8.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2"
+checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09"
 dependencies = [
  "libc",
  "wasi",
- "windows-sys",
-]
-
-[[package]]
-name = "nom"
-version = "7.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a"
-dependencies = [
- "memchr",
- "minimal-lexical",
+ "windows-sys 0.48.0",
 ]
 
 [[package]]
@@ -1469,9 +1616,9 @@ dependencies = [
 
 [[package]]
 name = "num-bigint"
-version = "0.4.3"
+version = "0.4.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f"
+checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0"
 dependencies = [
  "autocfg",
  "num-integer",
@@ -1480,39 +1627,44 @@ dependencies = [
 
 [[package]]
 name = "num-complex"
-version = "0.4.3"
+version = "0.4.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "02e0d21255c828d6f128a1e41534206671e8c3ea0c62f32291e808dc82cff17d"
+checksum = "23c6602fda94a57c990fe0df199a035d83576b496aa29f4e634a8ac6004e68a6"
 dependencies = [
  "num-traits",
 ]
 
+[[package]]
+name = "num-conv"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9"
+
 [[package]]
 name = "num-derive"
-version = "0.4.0"
+version = "0.4.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9e6a0fd4f737c707bd9086cc16c925f294943eb62eb71499e9fd4cf71f8b9f4e"
+checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.28",
+ "syn 2.0.48",
 ]
 
 [[package]]
 name = "num-integer"
-version = "0.1.45"
+version = "0.1.46"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
+checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
 dependencies = [
- "autocfg",
  "num-traits",
 ]
 
 [[package]]
 name = "num-iter"
-version = "0.1.43"
+version = "0.1.44"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252"
+checksum = "d869c01cc0c455284163fd0092f1f93835385ccab5a98a0dcc497b2f8bf055a9"
 dependencies = [
  "autocfg",
  "num-integer",
@@ -1533,9 +1685,9 @@ dependencies = [
 
 [[package]]
 name = "num-traits"
-version = "0.2.16"
+version = "0.2.18"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f30b0abd723be7e2ffca1272140fac1a2f084c77ec3e123c192b66af1ee9e6c2"
+checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a"
 dependencies = [
  "autocfg",
  "libm",
@@ -1553,39 +1705,39 @@ dependencies = [
 
 [[package]]
 name = "num_enum"
-version = "0.6.1"
+version = "0.7.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a015b430d3c108a207fd776d2e2196aaf8b1cf8cf93253e3a097ff3085076a1"
+checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845"
 dependencies = [
  "num_enum_derive",
 ]
 
 [[package]]
 name = "num_enum_derive"
-version = "0.6.1"
+version = "0.7.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "96667db765a921f7b295ffee8b60472b686a51d4f21c2ee4ffdb94c7013b65a6"
+checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b"
 dependencies = [
- "proc-macro-crate",
+ "proc-macro-crate 3.1.0",
  "proc-macro2",
  "quote",
- "syn 2.0.28",
+ "syn 2.0.48",
 ]
 
 [[package]]
 name = "object"
-version = "0.31.1"
+version = "0.32.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8bda667d9f2b5051b8833f59f3bf748b28ef54f850f4fcb389a252aa383866d1"
+checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441"
 dependencies = [
  "memchr",
 ]
 
 [[package]]
 name = "once_cell"
-version = "1.18.0"
+version = "1.19.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
+checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
 
 [[package]]
 name = "open-fastrlp"
@@ -1614,9 +1766,9 @@ dependencies = [
 
 [[package]]
 name = "parity-scale-codec"
-version = "3.6.4"
+version = "3.6.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd8e946cc0cc711189c0b0249fb8b599cbeeab9784d83c415719368bb8d4ac64"
+checksum = "881331e34fa842a2fb61cc2db9643a8fedc615e47cfcc52597d1af0db9a7e8fe"
 dependencies = [
  "arrayvec",
  "bitvec",
@@ -1628,11 +1780,11 @@ dependencies = [
 
 [[package]]
 name = "parity-scale-codec-derive"
-version = "3.6.4"
+version = "3.6.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2a296c3079b5fefbc499e1de58dc26c09b1b9a5952d26694ee89f04a43ebbb3e"
+checksum = "be30eaf4b0a9fba5336683b38de57bb86d179a35862ba6bfcf57625d006bde5b"
 dependencies = [
- "proc-macro-crate",
+ "proc-macro-crate 2.0.0",
  "proc-macro2",
  "quote",
  "syn 1.0.109",
@@ -1650,15 +1802,15 @@ dependencies = [
 
 [[package]]
 name = "parking_lot_core"
-version = "0.9.8"
+version = "0.9.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447"
+checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e"
 dependencies = [
  "cfg-if",
  "libc",
  "redox_syscall",
  "smallvec",
- "windows-targets",
+ "windows-targets 0.48.5",
 ]
 
 [[package]]
@@ -1668,16 +1820,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
 
 [[package]]
-name = "peeking_take_while"
-version = "0.1.2"
+name = "pem"
+version = "1.1.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099"
+checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8"
+dependencies = [
+ "base64 0.13.1",
+]
 
 [[package]]
 name = "percent-encoding"
-version = "2.3.0"
+version = "2.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
+
+[[package]]
+name = "pest"
+version = "2.7.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94"
+checksum = "219c0dcc30b6a27553f9cc242972b67f75b60eb0db71f0b5462f38b058c41546"
+dependencies = [
+ "memchr",
+ "thiserror",
+ "ucd-trie",
+]
 
 [[package]]
 name = "pharos"
@@ -1686,34 +1852,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414"
 dependencies = [
  "futures",
- "rustc_version",
+ "rustc_version 0.4.0",
 ]
 
 [[package]]
 name = "pin-project"
-version = "1.1.3"
+version = "1.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422"
+checksum = "0302c4a0442c456bd56f841aee5c3bfd17967563f6fadc9ceb9f9c23cf3807e0"
 dependencies = [
  "pin-project-internal",
 ]
 
 [[package]]
 name = "pin-project-internal"
-version = "1.1.3"
+version = "1.1.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405"
+checksum = "266c042b60c9c76b8d53061e52b2e0d1116abc57cefc8c5cd671619a56ac3690"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.28",
+ "syn 2.0.48",
 ]
 
 [[package]]
 name = "pin-project-lite"
-version = "0.2.12"
+version = "0.2.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "12cc1b0bf1727a77a54b6654e7b5f1af8604923edc8b81885f8ec92f9e3f0a05"
+checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58"
 
 [[package]]
 name = "pin-utils"
@@ -1732,26 +1898,22 @@ dependencies = [
 ]
 
 [[package]]
-name = "ppv-lite86"
-version = "0.2.17"
+name = "powerfmt"
+version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
+checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391"
 
 [[package]]
-name = "prettyplease"
-version = "0.2.12"
+name = "ppv-lite86"
+version = "0.2.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c64d9ba0963cdcea2e1b2230fbae2bab30eb25a174be395c41e764bfb65dd62"
-dependencies = [
- "proc-macro2",
- "syn 2.0.28",
-]
+checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
 
 [[package]]
 name = "primitive-types"
-version = "0.12.1"
+version = "0.12.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9f3486ccba82358b11a77516035647c34ba167dfa53312630de83b12bd4f3d66"
+checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2"
 dependencies = [
  "fixed-hash",
  "impl-codec",
@@ -1768,57 +1930,51 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919"
 dependencies = [
  "once_cell",
- "toml_edit",
+ "toml_edit 0.19.15",
 ]
 
 [[package]]
-name = "proc-macro-error"
-version = "1.0.4"
+name = "proc-macro-crate"
+version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
+checksum = "7e8366a6159044a37876a2b9817124296703c586a5c92e2c53751fa06d8d43e8"
 dependencies = [
- "proc-macro-error-attr",
- "proc-macro2",
- "quote",
- "syn 1.0.109",
- "version_check",
+ "toml_edit 0.20.7",
 ]
 
 [[package]]
-name = "proc-macro-error-attr"
-version = "1.0.4"
+name = "proc-macro-crate"
+version = "3.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
+checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284"
 dependencies = [
- "proc-macro2",
- "quote",
- "version_check",
+ "toml_edit 0.21.1",
 ]
 
 [[package]]
 name = "proc-macro2"
-version = "1.0.66"
+version = "1.0.78"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
+checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
 dependencies = [
  "unicode-ident",
 ]
 
 [[package]]
 name = "proptest"
-version = "1.2.0"
+version = "1.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4e35c06b98bf36aba164cc17cb25f7e232f5c4aeea73baa14b8a9f0d92dbfa65"
+checksum = "31b476131c3c86cb68032fdc5cb6d5a1045e3e42d96b69fa599fd77701e1f5bf"
 dependencies = [
  "bit-set",
- "bitflags 1.3.2",
- "byteorder",
+ "bit-vec",
+ "bitflags 2.4.2",
  "lazy_static",
  "num-traits",
  "rand",
  "rand_chacha",
  "rand_xorshift",
- "regex-syntax 0.6.29",
+ "regex-syntax",
  "rusty-fork",
  "tempfile",
  "unarray",
@@ -1832,9 +1988,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0"
 
 [[package]]
 name = "quote"
-version = "1.0.32"
+version = "1.0.35"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965"
+checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
 dependencies = [
  "proc-macro2",
 ]
@@ -1886,55 +2042,49 @@ dependencies = [
 
 [[package]]
 name = "redox_syscall"
-version = "0.3.5"
+version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29"
+checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
 dependencies = [
  "bitflags 1.3.2",
 ]
 
 [[package]]
 name = "regex"
-version = "1.9.3"
+version = "1.10.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "81bc1d4caf89fac26a70747fe603c130093b53c773888797a6329091246d651a"
+checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15"
 dependencies = [
  "aho-corasick",
  "memchr",
  "regex-automata",
- "regex-syntax 0.7.4",
+ "regex-syntax",
 ]
 
 [[package]]
 name = "regex-automata"
-version = "0.3.6"
+version = "0.4.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fed1ceff11a1dddaee50c9dc8e4938bd106e9d89ae372f192311e7da498e3b69"
+checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd"
 dependencies = [
  "aho-corasick",
  "memchr",
- "regex-syntax 0.7.4",
+ "regex-syntax",
 ]
 
 [[package]]
 name = "regex-syntax"
-version = "0.6.29"
+version = "0.8.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
-
-[[package]]
-name = "regex-syntax"
-version = "0.7.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2"
+checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
 
 [[package]]
 name = "reqwest"
-version = "0.11.18"
+version = "0.11.24"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55"
+checksum = "c6920094eb85afde5e4a138be3f2de8bbdf28000f0029e72c45025a56b042251"
 dependencies = [
- "base64 0.21.2",
+ "base64 0.21.7",
  "bytes",
  "encoding_rs",
  "futures-core",
@@ -1956,6 +2106,8 @@ dependencies = [
  "serde",
  "serde_json",
  "serde_urlencoded",
+ "sync_wrapper",
+ "system-configuration",
  "tokio",
  "tokio-rustls",
  "tower-service",
@@ -1963,15 +2115,14 @@ dependencies = [
  "wasm-bindgen",
  "wasm-bindgen-futures",
  "web-sys",
- "webpki-roots 0.22.6",
+ "webpki-roots",
  "winreg",
 ]
 
 [[package]]
 name = "revm"
 version = "3.5.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68f4ca8ae0345104523b4af1a8a7ea97cfa1865cdb7a7c25d23c1a18d9b48598"
+source = "git+https://github.com/ceciliaz030/revm.git?branch=sync-taiko-v3.5#09531f2d92b80989c79fb9508ef20f8e9cbdd079"
 dependencies = [
  "auto_impl",
  "revm-interpreter",
@@ -1983,8 +2134,7 @@ dependencies = [
 [[package]]
 name = "revm-interpreter"
 version = "1.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f959cafdf64a7f89b014fa73dc2325001cf654b3d9400260b212d19a2ebe3da0"
+source = "git+https://github.com/ceciliaz030/revm.git?branch=sync-taiko-v3.5#09531f2d92b80989c79fb9508ef20f8e9cbdd079"
 dependencies = [
  "revm-primitives",
  "serde",
@@ -1993,12 +2143,11 @@ dependencies = [
 [[package]]
 name = "revm-precompile"
 version = "2.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4d360a88223d85709d2e95d4609eb1e19c649c47e28954bfabae5e92bb37e83e"
+source = "git+https://github.com/ceciliaz030/revm.git?branch=sync-taiko-v3.5#09531f2d92b80989c79fb9508ef20f8e9cbdd079"
 dependencies = [
+ "aurora-engine-modexp",
  "c-kzg",
  "k256",
- "num",
  "once_cell",
  "revm-primitives",
  "ripemd",
@@ -2010,17 +2159,15 @@ dependencies = [
 [[package]]
 name = "revm-primitives"
 version = "1.3.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "51187b852d9e458816a2e19c81f1dd6c924077e1a8fccd16e4f044f865f299d7"
+source = "git+https://github.com/ceciliaz030/revm.git?branch=sync-taiko-v3.5#09531f2d92b80989c79fb9508ef20f8e9cbdd079"
 dependencies = [
  "alloy-primitives",
- "alloy-rlp",
  "auto_impl",
- "bitflags 2.4.0",
+ "bitflags 2.4.2",
  "bitvec",
  "c-kzg",
  "enumn",
- "hashbrown 0.14.0",
+ "hashbrown 0.14.3",
  "hex",
  "serde",
 ]
@@ -2044,25 +2191,68 @@ dependencies = [
  "cc",
  "libc",
  "once_cell",
- "spin",
- "untrusted",
+ "spin 0.5.2",
+ "untrusted 0.7.1",
  "web-sys",
  "winapi",
 ]
 
+[[package]]
+name = "ring"
+version = "0.17.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74"
+dependencies = [
+ "cc",
+ "getrandom",
+ "libc",
+ "spin 0.9.8",
+ "untrusted 0.9.0",
+ "windows-sys 0.48.0",
+]
+
 [[package]]
 name = "ripemd"
 version = "0.1.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f"
 dependencies = [
- "digest",
+ "digest 0.10.7",
+]
+
+[[package]]
+name = "risc0-binfmt"
+version = "0.19.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "923c85a23cb9a9475b8cd4479ad3a06252604a361626e9ae7dc0dc635af22c22"
+dependencies = [
+ "anyhow",
+ "elf",
+ "log",
+ "risc0-zkp",
+ "risc0-zkvm-platform",
+ "serde",
+]
+
+[[package]]
+name = "risc0-circuit-recursion"
+version = "0.19.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97547e10e9fdaaab8b64ffb45dc158b31f023b1a68015c6ce9f12fe3e403012a"
+dependencies = [
+ "anyhow",
+ "bytemuck",
+ "log",
+ "risc0-core",
+ "risc0-zkp",
+ "tracing",
 ]
 
 [[package]]
 name = "risc0-circuit-rv32im"
-version = "0.16.1"
-source = "git+https://github.com/risc0/risc0.git?branch=release-0.16#cbb6ccab08718506a524af999baa6d1386c51cbb"
+version = "0.19.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a269d01b18cba24ee1a08f68726fc3623e8705ed79d158377d12e9129dcde2e"
 dependencies = [
  "anyhow",
  "log",
@@ -2074,8 +2264,9 @@ dependencies = [
 
 [[package]]
 name = "risc0-core"
-version = "0.16.1"
-source = "git+https://github.com/risc0/risc0.git?branch=release-0.16#cbb6ccab08718506a524af999baa6d1386c51cbb"
+version = "0.19.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "477e0bb8d2ec0b7955088b521eb596901e652d0faa2ea73bda0b77e05af5c07d"
 dependencies = [
  "bytemuck",
  "rand_core",
@@ -2083,13 +2274,14 @@ dependencies = [
 
 [[package]]
 name = "risc0-zkp"
-version = "0.16.1"
-source = "git+https://github.com/risc0/risc0.git?branch=release-0.16#cbb6ccab08718506a524af999baa6d1386c51cbb"
+version = "0.19.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d5abb1a0cf847d3f9aed1e563b76c358107e7ba66dbfab28f7144252c990bd82"
 dependencies = [
  "anyhow",
  "blake2",
  "bytemuck",
- "digest",
+ "digest 0.10.7",
  "hex",
  "log",
  "paste",
@@ -2098,39 +2290,51 @@ dependencies = [
  "risc0-zkvm-platform",
  "serde",
  "sha2",
- "thiserror",
  "tracing",
 ]
 
 [[package]]
 name = "risc0-zkvm"
-version = "0.16.1"
-source = "git+https://github.com/risc0/risc0.git?branch=release-0.16#cbb6ccab08718506a524af999baa6d1386c51cbb"
+version = "0.19.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3cf80df202c038efc2199be34fda8114b38bfc5b2b51c60cbbdf1f425b07b384"
 dependencies = [
  "anyhow",
  "bytemuck",
  "cfg-if",
- "dyn_partial_eq",
  "getrandom",
  "hex",
- "libm",
  "log",
  "num-derive",
  "num-traits",
+ "risc0-binfmt",
+ "risc0-circuit-recursion",
  "risc0-circuit-rv32im",
  "risc0-core",
  "risc0-zkp",
  "risc0-zkvm-platform",
+ "rrs-lib",
+ "semver 1.0.21",
  "serde",
- "thiserror",
  "tracing",
- "typetag",
 ]
 
 [[package]]
 name = "risc0-zkvm-platform"
-version = "0.16.1"
-source = "git+https://github.com/risc0/risc0.git?branch=release-0.16#cbb6ccab08718506a524af999baa6d1386c51cbb"
+version = "0.19.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2dcd6b66f7a4972001db0acf3f06d99b7851c8d9f0de1f7e0fb4496c66c5cd02"
+dependencies = [
+ "bytemuck",
+ "getrandom",
+ "libm",
+]
+
+[[package]]
+name = "rle-decode-fast"
+version = "1.0.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3582f63211428f83597b51b2ddb88e2a91a9d52d12831f9d08f5e624e8977422"
 
 [[package]]
 name = "rlp"
@@ -2154,15 +2358,34 @@ dependencies = [
  "syn 1.0.109",
 ]
 
+[[package]]
+name = "rrs-lib"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b4382d3af3a4ebdae7f64ba6edd9114fff92c89808004c4943b393377a25d001"
+dependencies = [
+ "downcast-rs",
+ "paste",
+]
+
 [[package]]
 name = "ruint"
-version = "1.10.1"
+version = "1.11.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "95294d6e3a6192f3aabf91c38f56505a625aa495533442744185a36d75a790c4"
+checksum = "608a5726529f2f0ef81b8fde9873c4bb829d6b5b5ca6be4d97345ddf0749c825"
 dependencies = [
  "alloy-rlp",
+ "ark-ff 0.3.0",
+ "ark-ff 0.4.2",
+ "bytes",
+ "fastrlp",
+ "num-bigint",
+ "num-traits",
+ "parity-scale-codec",
+ "primitive-types",
  "proptest",
  "rand",
+ "rlp",
  "ruint-macro",
  "serde",
  "valuable",
@@ -2181,79 +2404,72 @@ version = "0.1.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
 
-[[package]]
-name = "rustc-hash"
-version = "1.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
-
 [[package]]
 name = "rustc-hex"
 version = "2.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3e75f6a532d0fd9f7f13144f392b6ad56a32696bfcd9c78f797f16bbb6f072d6"
 
+[[package]]
+name = "rustc_version"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee"
+dependencies = [
+ "semver 0.11.0",
+]
+
 [[package]]
 name = "rustc_version"
 version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
 dependencies = [
- "semver",
+ "semver 1.0.21",
 ]
 
 [[package]]
 name = "rustix"
-version = "0.38.17"
+version = "0.38.31"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f25469e9ae0f3d0047ca8b93fc56843f38e6774f0914a107ff8b41be8be8e0b7"
+checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949"
 dependencies = [
- "bitflags 2.4.0",
+ "bitflags 2.4.2",
  "errno",
  "libc",
  "linux-raw-sys",
- "windows-sys",
+ "windows-sys 0.52.0",
 ]
 
 [[package]]
 name = "rustls"
-version = "0.21.6"
+version = "0.21.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d1feddffcfcc0b33f5c6ce9a29e341e4cd59c3f78e7ee45f4a40c038b1d6cbb"
+checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba"
 dependencies = [
  "log",
- "ring",
- "rustls-webpki 0.101.3",
+ "ring 0.17.7",
+ "rustls-webpki",
  "sct",
 ]
 
 [[package]]
 name = "rustls-pemfile"
-version = "1.0.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2"
-dependencies = [
- "base64 0.21.2",
-]
-
-[[package]]
-name = "rustls-webpki"
-version = "0.100.1"
+version = "1.0.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d6207cd5ed3d8dca7816f8f3725513a34609c0c765bf652b8c3cb4cfd87db46b"
+checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c"
 dependencies = [
- "ring",
- "untrusted",
+ "base64 0.21.7",
 ]
 
 [[package]]
 name = "rustls-webpki"
-version = "0.101.3"
+version = "0.101.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "261e9e0888cba427c3316e6322805653c9425240b6fd96cee7cb671ab70ab8d0"
+checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765"
 dependencies = [
- "ring",
- "untrusted",
+ "ring 0.17.7",
+ "untrusted 0.9.0",
 ]
 
 [[package]]
@@ -2276,15 +2492,15 @@ dependencies = [
 
 [[package]]
 name = "ryu"
-version = "1.0.15"
+version = "1.0.16"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ad4cc8da4ef723ed60bced201181d83791ad433213d8c24efffda1eec85d741"
+checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c"
 
 [[package]]
 name = "scale-info"
-version = "2.9.0"
+version = "2.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "35c0a159d0c45c12b20c5a844feb1fe4bea86e28f17b92a5f0c42193634d3782"
+checksum = "7f7d66a1128282b7ef025a8ead62a4a9fcf017382ec53b8ffbf4d7bf77bd3c60"
 dependencies = [
  "cfg-if",
  "derive_more",
@@ -2294,11 +2510,11 @@ dependencies = [
 
 [[package]]
 name = "scale-info-derive"
-version = "2.9.0"
+version = "2.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "912e55f6d20e0e80d63733872b40e1227c0bce1e1ab81ba67d696339bfd7fd29"
+checksum = "abf2c68b89cafb3b8d918dd07b42be0da66ff202cf1155c5739a4e0c1ea0dc19"
 dependencies = [
- "proc-macro-crate",
+ "proc-macro-crate 1.3.1",
  "proc-macro2",
  "quote",
  "syn 1.0.109",
@@ -2312,12 +2528,12 @@ checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
 
 [[package]]
 name = "sct"
-version = "0.7.0"
+version = "0.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4"
+checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414"
 dependencies = [
- "ring",
- "untrusted",
+ "ring 0.17.7",
+ "untrusted 0.9.0",
 ]
 
 [[package]]
@@ -2336,27 +2552,45 @@ dependencies = [
 
 [[package]]
 name = "secp256k1"
-version = "0.27.0"
+version = "0.28.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "25996b82292a7a57ed3508f052cfff8640d38d32018784acd714758b43da9c8f"
+checksum = "d24b59d129cdadea20aea4fb2352fa053712e5d713eee47d700cd4b2bc002f10"
 dependencies = [
  "secp256k1-sys",
 ]
 
 [[package]]
 name = "secp256k1-sys"
-version = "0.8.1"
+version = "0.9.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70a129b9e9efbfb223753b9163c4ab3b13cff7fd9c7f010fbac25ab4099fa07e"
+checksum = "e5d1746aae42c19d583c3c1a8c646bfad910498e2051c551a7f2e3c0c9fbb7eb"
 dependencies = [
  "cc",
 ]
 
 [[package]]
 name = "semver"
-version = "1.0.18"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6"
+dependencies = [
+ "semver-parser",
+]
+
+[[package]]
+name = "semver"
+version = "1.0.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918"
+checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0"
+
+[[package]]
+name = "semver-parser"
+version = "0.10.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7"
+dependencies = [
+ "pest",
+]
 
 [[package]]
 name = "send_wrapper"
@@ -2372,31 +2606,31 @@ checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73"
 
 [[package]]
 name = "serde"
-version = "1.0.183"
+version = "1.0.196"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "32ac8da02677876d532745a130fc9d8e6edfa81a269b107c5b00829b91d8eb3c"
+checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32"
 dependencies = [
  "serde_derive",
 ]
 
 [[package]]
 name = "serde_derive"
-version = "1.0.183"
+version = "1.0.196"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aafe972d60b0b9bee71a91b92fee2d4fb3c9d7e8f6b179aa99f27203d99a4816"
+checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.28",
+ "syn 2.0.48",
 ]
 
 [[package]]
 name = "serde_json"
-version = "1.0.104"
+version = "1.0.113"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c"
+checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79"
 dependencies = [
- "indexmap 2.0.0",
+ "indexmap 2.2.3",
  "itoa",
  "ryu",
  "serde",
@@ -2416,16 +2650,17 @@ dependencies = [
 
 [[package]]
 name = "serde_with"
-version = "3.2.0"
+version = "3.6.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1402f54f9a3b9e2efe71c1cea24e648acce55887983553eeb858cf3115acfd49"
+checksum = "15d167997bd841ec232f5b2b8e0e26606df2e7caa4c31b95ea9ca52b200bd270"
 dependencies = [
- "base64 0.21.2",
+ "base64 0.21.7",
  "chrono",
  "hex",
  "indexmap 1.9.3",
- "indexmap 2.0.0",
+ "indexmap 2.2.3",
  "serde",
+ "serde_derive",
  "serde_json",
  "serde_with_macros",
  "time",
@@ -2433,25 +2668,25 @@ dependencies = [
 
 [[package]]
 name = "serde_with_macros"
-version = "3.2.0"
+version = "3.6.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9197f1ad0e3c173a0222d3c4404fb04c3afe87e962bcb327af73e8301fa203c7"
+checksum = "865f9743393e638991566a8b7a479043c2c8da94a33e0a31f18214c9cae0a64d"
 dependencies = [
  "darling",
  "proc-macro2",
  "quote",
- "syn 2.0.28",
+ "syn 2.0.48",
 ]
 
 [[package]]
 name = "sha1"
-version = "0.10.5"
+version = "0.10.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3"
+checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
 dependencies = [
  "cfg-if",
  "cpufeatures",
- "digest",
+ "digest 0.10.7",
 ]
 
 [[package]]
@@ -2461,7 +2696,7 @@ source = "git+https://github.com/risc0/RustCrypto-hashes?tag=sha2-v0.10.6-riscze
 dependencies = [
  "cfg-if",
  "cpufeatures",
- "digest",
+ "digest 0.10.7",
 ]
 
 [[package]]
@@ -2470,15 +2705,19 @@ version = "0.10.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60"
 dependencies = [
- "digest",
+ "digest 0.10.7",
  "keccak",
 ]
 
 [[package]]
-name = "shlex"
-version = "1.2.0"
+name = "sha3-asm"
+version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a7cee0529a6d40f580e7a5e6c495c8fbfe21b7b52795ed4bb5e62cdf92bc6380"
+checksum = "bac61da6b35ad76b195eb4771210f947734321a8d81d7738e1580d953bc7a15e"
+dependencies = [
+ "cc",
+ "cfg-if",
+]
 
 [[package]]
 name = "signal-hook-registry"
@@ -2491,56 +2730,49 @@ dependencies = [
 
 [[package]]
 name = "signature"
-version = "2.1.0"
+version = "2.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500"
+checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de"
 dependencies = [
- "digest",
+ "digest 0.10.7",
  "rand_core",
 ]
 
 [[package]]
-name = "slab"
-version = "0.4.8"
+name = "simple_asn1"
+version = "0.6.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d"
+checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085"
 dependencies = [
- "autocfg",
+ "num-bigint",
+ "num-traits",
+ "thiserror",
+ "time",
 ]
 
 [[package]]
-name = "smallvec"
-version = "1.11.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62bb4feee49fdd9f707ef802e22365a35de4b7b299de4763d44bfea899442ff9"
-
-[[package]]
-name = "smol_str"
-version = "0.2.0"
+name = "slab"
+version = "0.4.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "74212e6bbe9a4352329b2f68ba3130c15a3f26fe88ff22dbdc6cdd58fa85e99c"
+checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
 dependencies = [
- "serde",
+ "autocfg",
 ]
 
 [[package]]
-name = "socket2"
-version = "0.4.9"
+name = "smallvec"
+version = "1.13.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662"
-dependencies = [
- "libc",
- "winapi",
-]
+checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7"
 
 [[package]]
 name = "socket2"
-version = "0.5.3"
+version = "0.5.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877"
+checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9"
 dependencies = [
  "libc",
- "windows-sys",
+ "windows-sys 0.48.0",
 ]
 
 [[package]]
@@ -2549,11 +2781,17 @@ version = "0.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
 
+[[package]]
+name = "spin"
+version = "0.9.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
+
 [[package]]
 name = "spki"
-version = "0.7.2"
+version = "0.7.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a"
+checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d"
 dependencies = [
  "base64ct",
  "der",
@@ -2582,15 +2820,15 @@ dependencies = [
 
 [[package]]
 name = "strum_macros"
-version = "0.25.2"
+version = "0.25.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad8d03b598d3d0fff69bf533ee3ef19b8eeb342729596df84bcc7e1f96ec4059"
+checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0"
 dependencies = [
  "heck",
  "proc-macro2",
  "quote",
  "rustversion",
- "syn 2.0.28",
+ "syn 2.0.48",
 ]
 
 [[package]]
@@ -2625,15 +2863,42 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "2.0.28"
+version = "2.0.48"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567"
+checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f"
 dependencies = [
  "proc-macro2",
  "quote",
  "unicode-ident",
 ]
 
+[[package]]
+name = "sync_wrapper"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160"
+
+[[package]]
+name = "system-configuration"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7"
+dependencies = [
+ "bitflags 1.3.2",
+ "core-foundation",
+ "system-configuration-sys",
+]
+
+[[package]]
+name = "system-configuration-sys"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9"
+dependencies = [
+ "core-foundation-sys",
+ "libc",
+]
+
 [[package]]
 name = "tap"
 version = "1.0.1"
@@ -2642,44 +2907,62 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
 
 [[package]]
 name = "tempfile"
-version = "3.7.1"
+version = "3.10.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dc02fddf48964c42031a0b3fe0428320ecf3a73c401040fc0096f97794310651"
+checksum = "a365e8cd18e44762ef95d87f284f4b5cd04107fec2ff3052bd6a3e6069669e67"
 dependencies = [
  "cfg-if",
  "fastrand",
- "redox_syscall",
  "rustix",
- "windows-sys",
+ "windows-sys 0.52.0",
 ]
 
 [[package]]
 name = "test-guest"
 version = "0.1.0"
 dependencies = [
- "k256",
  "risc0-zkvm",
  "zeth-lib",
 ]
 
 [[package]]
 name = "thiserror"
-version = "1.0.44"
+version = "1.0.57"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90"
+checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b"
 dependencies = [
  "thiserror-impl",
 ]
 
 [[package]]
 name = "thiserror-impl"
-version = "1.0.44"
+version = "1.0.57"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.48",
+]
+
+[[package]]
+name = "thiserror-impl-no-std"
+version = "2.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96"
+checksum = "58e6318948b519ba6dc2b442a6d0b904ebfb8d411a3ad3e07843615a72249758"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.28",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "thiserror-no-std"
+version = "2.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a3ad459d94dd517257cc96add8a43190ee620011bb6e6cdc82dafd97dfafafea"
+dependencies = [
+ "thiserror-impl-no-std",
 ]
 
 [[package]]
@@ -2693,12 +2976,14 @@ dependencies = [
 
 [[package]]
 name = "time"
-version = "0.3.25"
+version = "0.3.34"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b0fdd63d58b18d663fbdf70e049f00a22c8e42be082203be7f26589213cd75ea"
+checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749"
 dependencies = [
  "deranged",
  "itoa",
+ "num-conv",
+ "powerfmt",
  "serde",
  "time-core",
  "time-macros",
@@ -2706,16 +2991,17 @@ dependencies = [
 
 [[package]]
 name = "time-core"
-version = "0.1.1"
+version = "0.1.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb"
+checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3"
 
 [[package]]
 name = "time-macros"
-version = "0.2.11"
+version = "0.2.17"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eb71511c991639bb078fd5bf97757e03914361c48100d52878b8e52b46fb92cd"
+checksum = "7ba3a3ef41e6672a2f0f001392bb5dcd3ff0a9992d618ca761a11c3121547774"
 dependencies = [
+ "num-conv",
  "time-core",
 ]
 
@@ -2745,9 +3031,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
 
 [[package]]
 name = "tokio"
-version = "1.30.0"
+version = "1.36.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2d3ce25f50619af8b0aec2eb23deebe84249e19e2ddd393a6e16e3300a6dadfd"
+checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931"
 dependencies = [
  "backtrace",
  "bytes",
@@ -2757,20 +3043,20 @@ dependencies = [
  "parking_lot",
  "pin-project-lite",
  "signal-hook-registry",
- "socket2 0.5.3",
+ "socket2",
  "tokio-macros",
- "windows-sys",
+ "windows-sys 0.48.0",
 ]
 
 [[package]]
 name = "tokio-macros"
-version = "2.1.0"
+version = "2.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e"
+checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.28",
+ "syn 2.0.48",
 ]
 
 [[package]]
@@ -2785,9 +3071,9 @@ dependencies = [
 
 [[package]]
 name = "tokio-tungstenite"
-version = "0.19.0"
+version = "0.20.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec509ac96e9a0c43427c74f003127d953a265737636129424288d27cb5c4b12c"
+checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c"
 dependencies = [
  "futures-util",
  "log",
@@ -2795,14 +3081,14 @@ dependencies = [
  "tokio",
  "tokio-rustls",
  "tungstenite",
- "webpki-roots 0.23.1",
+ "webpki-roots",
 ]
 
 [[package]]
 name = "tokio-util"
-version = "0.7.8"
+version = "0.7.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d"
+checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15"
 dependencies = [
  "bytes",
  "futures-core",
@@ -2814,17 +3100,39 @@ dependencies = [
 
 [[package]]
 name = "toml_datetime"
-version = "0.6.3"
+version = "0.6.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1"
+
+[[package]]
+name = "toml_edit"
+version = "0.19.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
+dependencies = [
+ "indexmap 2.2.3",
+ "toml_datetime",
+ "winnow",
+]
+
+[[package]]
+name = "toml_edit"
+version = "0.20.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b"
+checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81"
+dependencies = [
+ "indexmap 2.2.3",
+ "toml_datetime",
+ "winnow",
+]
 
 [[package]]
 name = "toml_edit"
-version = "0.19.14"
+version = "0.21.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a"
+checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1"
 dependencies = [
- "indexmap 2.0.0",
+ "indexmap 2.2.3",
  "toml_datetime",
  "winnow",
 ]
@@ -2837,11 +3145,10 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52"
 
 [[package]]
 name = "tracing"
-version = "0.1.37"
+version = "0.1.40"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
+checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
 dependencies = [
- "cfg-if",
  "pin-project-lite",
  "tracing-attributes",
  "tracing-core",
@@ -2849,20 +3156,20 @@ dependencies = [
 
 [[package]]
 name = "tracing-attributes"
-version = "0.1.26"
+version = "0.1.27"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab"
+checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.28",
+ "syn 2.0.48",
 ]
 
 [[package]]
 name = "tracing-core"
-version = "0.1.31"
+version = "0.1.32"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a"
+checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
 dependencies = [
  "once_cell",
 ]
@@ -2879,15 +3186,15 @@ dependencies = [
 
 [[package]]
 name = "try-lock"
-version = "0.2.4"
+version = "0.2.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
+checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
 
 [[package]]
 name = "tungstenite"
-version = "0.19.0"
+version = "0.20.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "15fba1a6d6bb030745759a9a2a588bfe8490fc8b4751a277db3a0be1c9ebbf67"
+checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9"
 dependencies = [
  "byteorder",
  "bytes",
@@ -2901,38 +3208,19 @@ dependencies = [
  "thiserror",
  "url",
  "utf-8",
- "webpki",
 ]
 
 [[package]]
 name = "typenum"
-version = "1.16.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
-
-[[package]]
-name = "typetag"
-version = "0.2.12"
+version = "1.17.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aec6850cc671cd0cfb3ab285465e48a3b927d9de155051c35797446b32f9169f"
-dependencies = [
- "erased-serde",
- "inventory",
- "once_cell",
- "serde",
- "typetag-impl",
-]
+checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
 
 [[package]]
-name = "typetag-impl"
-version = "0.2.12"
+name = "ucd-trie"
+version = "0.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "30c49a6815b4f8379c36f06618bc1b80ca77aaf8a3fd4d8549dca6fdb016000f"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn 2.0.28",
-]
+checksum = "ed646292ffc8188ef8ea4d1e0e0150fb15a5c2e12ad9b8fc191ae7a8a7f3c4b9"
 
 [[package]]
 name = "uint"
@@ -2954,15 +3242,15 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94"
 
 [[package]]
 name = "unicode-bidi"
-version = "0.3.13"
+version = "0.3.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
+checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75"
 
 [[package]]
 name = "unicode-ident"
-version = "1.0.11"
+version = "1.0.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c"
+checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
 
 [[package]]
 name = "unicode-normalization"
@@ -2985,11 +3273,17 @@ version = "0.7.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
 
+[[package]]
+name = "untrusted"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1"
+
 [[package]]
 name = "url"
-version = "2.4.0"
+version = "2.5.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "50bff7831e19200a85b17131d085c25d7811bc4e186efdaf54bbd132994a88cb"
+checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633"
 dependencies = [
  "form_urlencoded",
  "idna",
@@ -3040,9 +3334,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
 [[package]]
 name = "wasm-bindgen"
-version = "0.2.87"
+version = "0.2.91"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342"
+checksum = "c1e124130aee3fb58c5bdd6b639a0509486b0338acaaae0c84a5124b0f588b7f"
 dependencies = [
  "cfg-if",
  "wasm-bindgen-macro",
@@ -3050,24 +3344,24 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-backend"
-version = "0.2.87"
+version = "0.2.91"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd"
+checksum = "c9e7e1900c352b609c8488ad12639a311045f40a35491fb69ba8c12f758af70b"
 dependencies = [
  "bumpalo",
  "log",
  "once_cell",
  "proc-macro2",
  "quote",
- "syn 2.0.28",
+ "syn 2.0.48",
  "wasm-bindgen-shared",
 ]
 
 [[package]]
 name = "wasm-bindgen-futures"
-version = "0.4.37"
+version = "0.4.41"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03"
+checksum = "877b9c3f61ceea0e56331985743b13f3d25c406a7098d45180fb5f09bc19ed97"
 dependencies = [
  "cfg-if",
  "js-sys",
@@ -3077,9 +3371,9 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro"
-version = "0.2.87"
+version = "0.2.91"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d"
+checksum = "b30af9e2d358182b5c7449424f017eba305ed32a7010509ede96cdc4696c46ed"
 dependencies = [
  "quote",
  "wasm-bindgen-macro-support",
@@ -3087,72 +3381,38 @@ dependencies = [
 
 [[package]]
 name = "wasm-bindgen-macro-support"
-version = "0.2.87"
+version = "0.2.91"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
+checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.28",
+ "syn 2.0.48",
  "wasm-bindgen-backend",
  "wasm-bindgen-shared",
 ]
 
 [[package]]
 name = "wasm-bindgen-shared"
-version = "0.2.87"
+version = "0.2.91"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1"
+checksum = "4f186bd2dcf04330886ce82d6f33dd75a7bfcf69ecf5763b89fcde53b6ac9838"
 
 [[package]]
 name = "web-sys"
-version = "0.3.64"
+version = "0.3.68"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9b85cbef8c220a6abc02aefd892dfc0fc23afb1c6a426316ec33253a3877249b"
+checksum = "96565907687f7aceb35bc5fc03770a8a0471d82e479f25832f54a0e3f4b28446"
 dependencies = [
  "js-sys",
  "wasm-bindgen",
 ]
 
-[[package]]
-name = "webpki"
-version = "0.22.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd"
-dependencies = [
- "ring",
- "untrusted",
-]
-
 [[package]]
 name = "webpki-roots"
-version = "0.22.6"
+version = "0.25.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87"
-dependencies = [
- "webpki",
-]
-
-[[package]]
-name = "webpki-roots"
-version = "0.23.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b03058f88386e5ff5310d9111d53f48b17d732b401aeb83a8d5190f2ac459338"
-dependencies = [
- "rustls-webpki 0.100.1",
-]
-
-[[package]]
-name = "which"
-version = "4.4.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7"
-dependencies = [
- "either",
- "home",
- "once_cell",
- "rustix",
-]
+checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1"
 
 [[package]]
 name = "winapi"
@@ -3177,12 +3437,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 
 [[package]]
-name = "windows"
-version = "0.48.0"
+name = "windows-core"
+version = "0.52.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
+checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9"
 dependencies = [
- "windows-targets",
+ "windows-targets 0.52.0",
 ]
 
 [[package]]
@@ -3191,82 +3451,149 @@ version = "0.48.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
 dependencies = [
- "windows-targets",
+ "windows-targets 0.48.5",
+]
+
+[[package]]
+name = "windows-sys"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+dependencies = [
+ "windows-targets 0.52.0",
 ]
 
 [[package]]
 name = "windows-targets"
-version = "0.48.1"
+version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f"
+checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
 dependencies = [
- "windows_aarch64_gnullvm",
- "windows_aarch64_msvc",
- "windows_i686_gnu",
- "windows_i686_msvc",
- "windows_x86_64_gnu",
- "windows_x86_64_gnullvm",
- "windows_x86_64_msvc",
+ "windows_aarch64_gnullvm 0.48.5",
+ "windows_aarch64_msvc 0.48.5",
+ "windows_i686_gnu 0.48.5",
+ "windows_i686_msvc 0.48.5",
+ "windows_x86_64_gnu 0.48.5",
+ "windows_x86_64_gnullvm 0.48.5",
+ "windows_x86_64_msvc 0.48.5",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd"
+dependencies = [
+ "windows_aarch64_gnullvm 0.52.0",
+ "windows_aarch64_msvc 0.52.0",
+ "windows_i686_gnu 0.52.0",
+ "windows_i686_msvc 0.52.0",
+ "windows_x86_64_gnu 0.52.0",
+ "windows_x86_64_gnullvm 0.52.0",
+ "windows_x86_64_msvc 0.52.0",
 ]
 
 [[package]]
 name = "windows_aarch64_gnullvm"
-version = "0.48.0"
+version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
+checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea"
 
 [[package]]
 name = "windows_aarch64_msvc"
-version = "0.48.0"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
+checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef"
 
 [[package]]
 name = "windows_i686_gnu"
-version = "0.48.0"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
+checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313"
 
 [[package]]
 name = "windows_i686_msvc"
-version = "0.48.0"
+version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
+checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a"
 
 [[package]]
 name = "windows_x86_64_gnu"
-version = "0.48.0"
+version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
+checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd"
 
 [[package]]
 name = "windows_x86_64_gnullvm"
-version = "0.48.0"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
+checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e"
 
 [[package]]
 name = "windows_x86_64_msvc"
-version = "0.48.0"
+version = "0.48.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
+checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
 
 [[package]]
 name = "winnow"
-version = "0.5.7"
+version = "0.5.40"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "19f495880723d0999eb3500a9064d8dbcf836460b24c17df80ea7b5794053aac"
+checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876"
 dependencies = [
  "memchr",
 ]
 
 [[package]]
 name = "winreg"
-version = "0.10.1"
+version = "0.50.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d"
+checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1"
 dependencies = [
- "winapi",
+ "cfg-if",
+ "windows-sys 0.48.0",
 ]
 
 [[package]]
@@ -3280,7 +3607,7 @@ dependencies = [
  "js-sys",
  "log",
  "pharos",
- "rustc_version",
+ "rustc_version 0.4.0",
  "send_wrapper 0.6.0",
  "thiserror",
  "wasm-bindgen",
@@ -3297,11 +3624,31 @@ dependencies = [
  "tap",
 ]
 
+[[package]]
+name = "zerocopy"
+version = "0.7.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be"
+dependencies = [
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.7.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.48",
+]
+
 [[package]]
 name = "zeroize"
-version = "1.6.0"
+version = "1.7.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9"
+checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d"
 dependencies = [
  "zeroize_derive",
 ]
@@ -3314,29 +3661,31 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
 dependencies = [
  "proc-macro2",
  "quote",
- "syn 2.0.28",
+ "syn 2.0.48",
 ]
 
 [[package]]
 name = "zeth-lib"
 version = "0.1.0"
 dependencies = [
+ "alloy-primitives",
  "anyhow",
+ "bytes",
  "chrono",
  "ethers-core",
  "ethers-providers",
  "flate2",
- "hashbrown 0.14.0",
- "hex",
+ "hashbrown 0.14.3",
+ "libflate",
  "log",
  "once_cell",
  "revm",
- "rlp",
  "ruint",
  "serde",
  "serde_json",
  "serde_with",
  "thiserror",
+ "thiserror-no-std",
  "tokio",
  "zeth-primitives",
 ]
@@ -3358,5 +3707,5 @@ dependencies = [
  "ruint",
  "serde",
  "sha3",
- "thiserror",
+ "thiserror-no-std",
 ]
diff --git a/testing/ef-tests/testguest/Cargo.toml b/testing/ef-tests/testguest/Cargo.toml
index eefde440f..05f427530 100644
--- a/testing/ef-tests/testguest/Cargo.toml
+++ b/testing/ef-tests/testguest/Cargo.toml
@@ -6,12 +6,11 @@ edition = "2021"
 [workspace]
 
 [dependencies]
-k256 = { version = "=0.13.1", features = ["std", "ecdsa"], default_features = false }
-risc0-zkvm = { git = "https://github.com/risc0/risc0.git", branch = "release-0.16", default-features = false, features = ['std'] }
+risc0-zkvm = { version = "0.19", default-features = false, features = ['std'] }
 zeth-lib = { path = "../../../lib", default-features = false }
 
 [patch.crates-io]
 # use optimized risc0 circuit
 crypto-bigint = { git = "https://github.com/risc0/RustCrypto-crypto-bigint", tag = "v0.5.2-risczero.0" }
-k256 = { git = "https://github.com/risc0/RustCrypto-elliptic-curves", tag = "k256/v0.13.1-risczero.1" }
-sha2 = { git = "https://github.com/risc0/RustCrypto-hashes", tag = "sha2-v0.10.6-risczero.0" }
\ No newline at end of file
+k256 = { git = "https://github.com/risc0/RustCrypto-elliptic-curves", tag = "k256/v0.13.3-risczero.0" }
+sha2 = { git = "https://github.com/risc0/RustCrypto-hashes", tag = "sha2-v0.10.6-risczero.0" }
diff --git a/testing/ef-tests/testguest/src/main.rs b/testing/ef-tests/testguest/src/main.rs
index 48956a918..6abd32f6e 100644
--- a/testing/ef-tests/testguest/src/main.rs
+++ b/testing/ef-tests/testguest/src/main.rs
@@ -15,7 +15,10 @@
 #![no_main]
 
 use risc0_zkvm::guest::env;
-use zeth_lib::{block_builder::EthereumBlockBuilder, consts::ChainSpec};
+use zeth_lib::{
+    builder::{BlockBuilderStrategy, EthereumStrategy},
+    consts::ChainSpec,
+};
 
 risc0_zkvm::guest::entry!(main);
 
@@ -25,10 +28,10 @@ pub fn main() {
     // Read the input previous block and transaction data
     let input = env::read();
     // Build the resulting block
-    let output = EthereumBlockBuilder::build_from(&chain_spec, input)
+    let (header, state) = EthereumStrategy::build_from(&chain_spec, input)
         .expect("Failed to build the resulting block");
     // Output the resulting block's hash to the journal
-    env::commit(&output.hash());
+    env::commit(&header.hash());
     // Leak memory, save cycles
-    core::mem::forget(output);
+    core::mem::forget((header, state));
 }
diff --git a/testing/ef-tests/tests/evm.rs b/testing/ef-tests/tests/evm.rs
index c06321b2d..7abc2a862 100644
--- a/testing/ef-tests/tests/evm.rs
+++ b/testing/ef-tests/tests/evm.rs
@@ -17,15 +17,11 @@
 use std::path::PathBuf;
 
 use rstest::rstest;
-use zeth_lib::{
-    block_builder::BlockBuilder, execution::ethereum::EthTxExecStrategy,
-    finalization::BuildFromMemDbStrategy, initialization::MemDbInitStrategy,
-    preparation::EthHeaderPrepStrategy,
-};
-use zeth_primitives::block::Header;
+use zeth_lib::builder::{BlockBuilderStrategy, EthereumStrategy};
+use zeth_primitives::{block::Header, trie::StateAccount};
 use zeth_testeth::{
+    create_input, ethers,
     ethtests::{read_eth_test, EthTestCase},
-    *,
 };
 
 #[rstest]
@@ -41,50 +37,60 @@ fn evm(
         .try_init();
 
     for EthTestCase {
-        json,
+        mut json,
         genesis,
         chain_spec,
     } in read_eth_test(path)
     {
-        let mut state = json.pre;
-        let mut parent_header = genesis;
-        let mut ancestor_headers = vec![];
-        for block in json.blocks {
-            // skip failing tests for now
-            if let Some(message) = block.expect_exception {
-                println!("skipping ({})", message);
-                break;
-            }
+        // only one block supported for now
+        assert_eq!(json.blocks.len(), 1);
+        let block = json.blocks.pop().unwrap();
+
+        // skip failing tests for now
+        if let Some(message) = block.expect_exception {
+            println!("skipping ({message})");
+            break;
+        }
 
-            let block_header = block.block_header.unwrap();
-            let expected_header: Header = block_header.clone().into();
-            assert_eq!(&expected_header.hash(), &block_header.hash);
+        let block_header = block.block_header.unwrap();
+        let expected_header: Header = block_header.clone().into();
+        assert_eq!(&expected_header.hash(), &block_header.hash);
 
-            let input = create_input(
-                &chain_spec,
-                state,
-                parent_header.clone(),
-                expected_header.clone(),
-                block.transactions,
-                block.withdrawals.unwrap_or_default(),
-            );
-            let builder = BlockBuilder::new(&chain_spec, input)
-                .initialize_database::<MemDbInitStrategy>()
-                .unwrap()
-                .prepare_header::<EthHeaderPrepStrategy>()
-                .unwrap()
-                .execute_transactions::<EthTxExecStrategy>()
-                .unwrap();
-            // update the state
-            state = builder.db().unwrap().into();
+        // using the empty/default state for the input prepares all accounts for deletion
+        // this leads to larger input, but can never fail
+        let post_state = json.post.clone().unwrap_or_default();
 
-            let result_header = builder.build::<BuildFromMemDbStrategy>().unwrap();
-            // the headers should match
-            assert_eq!(result_header, expected_header);
+        let input = create_input(
+            &chain_spec,
+            genesis,
+            json.pre,
+            expected_header.clone(),
+            block.transactions,
+            block.withdrawals.unwrap_or_default(),
+            post_state,
+        );
 
-            // update the headers
-            ancestor_headers.push(parent_header);
-            parent_header = block_header.into();
+        let (header, state) = EthereumStrategy::build_from(&chain_spec, input).unwrap();
+
+        if let Some(post) = json.post {
+            let (exp_state, _) = ethers::build_tries(&post);
+
+            println!("diffing state trie:");
+            for diff in diff::slice(
+                &state.debug_rlp::<StateAccount>(),
+                &exp_state.debug_rlp::<StateAccount>(),
+            ) {
+                match diff {
+                    diff::Result::Left(l) => println!("✗{l}"),
+                    diff::Result::Right(r) => println!("✓{r}"),
+                    diff::Result::Both(l, _) => println!(" {l}"),
+                }
+            }
+            assert_eq!(state.hash(), exp_state.hash());
         }
+
+        // the headers should match
+        assert_eq!(header, expected_header);
+        assert_eq!(header.hash(), expected_header.hash());
     }
 }
diff --git a/testing/ef-tests/tests/executor.rs b/testing/ef-tests/tests/executor.rs
index 5ee0587be..f23b9fbe0 100644
--- a/testing/ef-tests/tests/executor.rs
+++ b/testing/ef-tests/tests/executor.rs
@@ -16,10 +16,7 @@
 
 use std::path::PathBuf;
 
-use risc0_zkvm::{
-    serde::{from_slice, to_vec},
-    Executor, ExecutorEnv, FileSegmentRef,
-};
+use risc0_zkvm::{ExecutorEnv, ExecutorImpl, FileSegmentRef};
 use rstest::rstest;
 use tempfile::tempdir;
 use zeth_primitives::{block::Header, BlockHash};
@@ -29,7 +26,7 @@ use zeth_testeth::{
     guests::TEST_GUEST_ELF,
 };
 
-const SEGMENT_LIMIT_PO2: usize = 21;
+const SEGMENT_LIMIT_PO2: u32 = 21;
 
 #[rstest]
 fn executor(
@@ -55,7 +52,7 @@ fn executor(
 
         // skip failing tests for now
         if let Some(message) = block.expect_exception {
-            println!("skipping ({})", message);
+            println!("skipping ({message})");
             break;
         }
 
@@ -65,21 +62,24 @@ fn executor(
 
         let input = create_input(
             &chain_spec,
-            json.pre,
             genesis,
+            json.pre,
             expected_header.clone(),
             block.transactions,
             block.withdrawals.unwrap_or_default(),
+            json.post.unwrap(),
         );
 
         let env = ExecutorEnv::builder()
             .session_limit(None)
             .segment_limit_po2(SEGMENT_LIMIT_PO2)
-            .add_input(&to_vec(&chain_spec).unwrap())
-            .add_input(&to_vec(&input).unwrap())
+            .write(&chain_spec)
+            .unwrap()
+            .write(&input)
+            .unwrap()
             .build()
             .unwrap();
-        let mut exec = Executor::from_elf(env, TEST_GUEST_ELF).unwrap();
+        let mut exec = ExecutorImpl::from_elf(env, TEST_GUEST_ELF).unwrap();
 
         let segment_dir = tempdir().unwrap();
         let session = exec
@@ -89,8 +89,8 @@ fn executor(
             .unwrap();
         println!("Generated {} segments", session.segments.len());
 
-        let found_hash: BlockHash = from_slice(&session.journal).unwrap();
-        println!("Block hash (from executor): {}", found_hash);
+        let found_hash: BlockHash = session.journal.decode().unwrap();
+        println!("Block hash (from executor): {found_hash}");
         assert_eq!(found_hash, expected_header.hash());
     }
 }
diff --git a/tests/geth/src/lib.rs b/tests/geth/src/lib.rs
index 427517dd5..ae2edc597 100644
--- a/tests/geth/src/lib.rs
+++ b/tests/geth/src/lib.rs
@@ -4,7 +4,6 @@ use std::{
     os::raw::c_char,
 };
 
-use hex;
 use serde::Deserialize;
 extern "C" {
     fn MptRoot(str: *const c_char) -> *const c_char;
@@ -85,8 +84,8 @@ mod tests {
         let txs = r#"
         [{"essence":{"Eip1559":{"chain_id":167008,"nonce":23206,"max_priority_fee_per_gas":"0x0","max_fee_per_gas":"0x1","gas_limit":"0x3d090","to":{"Call":"0x1670080000000000000000000000000000010001"},"value":"0x0","data":"0xda69d3db5e05b7df7c06a03d7b463a5374c9e8aeb9f3dc21c152f7309cac258958f6b15dd80f1a3f49e593ac3be25fa60632d332f386880624acbee8edd73679adfc49ec00000000000000000000000000000000000000000000000000000000000ba5a10000000000000000000000000000000000000000000000000000000000e076be","access_list":[]}},"signature":{"v":1,"r":"0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798","s":"0x64053f595237fe5f29377f48c113c40576452a7373c385d676a849c804d02144"}},{"essence":{"Eip1559":{"chain_id":167008,"nonce":8,"max_priority_fee_per_gas":"0x59682f00","max_fee_per_gas":"0x59682f01","gas_limit":"0x2a351","to":{"Call":"0xf2f88e7ea95f2c93339484529dc7af9014657cfa"},"value":"0x0","data":"0xd37c353b0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000036697066733a2f2f516d547463666873625363536b47453366324c633167517274394241415661464d6958586b353646316a64676d692f000000000000000000000000000000000000000000000000000000000000000000000000000000000000","access_list":[]}},"signature":{"v":0,"r":"0xee56a183c013a6901e9a309a449186118cd7c5cdd7487d6fa74257a31c1ef534","s":"0x6a5adba439ad3423a8c2a24ff60eb4efa897284dba946ad8ac025dd12063843b"}},{"essence":{"Eip1559":{"chain_id":167008,"nonce":7,"max_priority_fee_per_gas":"0x59682f00","max_fee_per_gas":"0x59682f01","gas_limit":"0x1e4b0","to":"Create","value":"0x0","data":"0x608060405234801561000f575f80fd5b506101438061001d5f395ff3fe608060405234801561000f575f80fd5b5060043610610034575f3560e01c80632e64cec1146100385780636057361d14610056575b5f80fd5b610040610072565b60405161004d919061009b565b60405180910390f35b610070600480360381019061006b91906100e2565b61007a565b005b5f8054905090565b805f8190555050565b5f819050919050565b61009581610083565b82525050565b5f6020820190506100ae5f83018461008c565b92915050565b5f80fd5b6100c181610083565b81146100cb575f80fd5b50565b5f813590506100dc816100b8565b92915050565b5f602082840312156100f7576100f66100b4565b5b5f610104848285016100ce565b9150509291505056fea26469706673582212207ca8a77a375aff548bc76892f6b2093ea5bec72e34f6638bcd6bc43f620679bc64736f6c63430008160033","access_list":[]}},"signature":{"v":1,"r":"0x8f822b9f11612d0ad65c31c03168f13c3be44615b3d99edfa744e367241e65b0","s":"0x178c11d68167aace32216f8a2163e6087d996b73c73c606e3e682d80cf5b678f"}},{"essence":{"Eip1559":{"chain_id":167008,"nonce":3,"max_priority_fee_per_gas":"0x59682f00","max_fee_per_gas":"0x59682f01","gas_limit":"0x31752","to":{"Call":"0xd2c3cbb943fed0cfc8389b14a3f6df518fd46346"},"value":"0xb1a2bc2ec50000","data":"0x3593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000065a970bc00000000000000000000000000000000000000000000000000000000000000020b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000b1a2bc2ec500000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000b1a2bc2ec500000000000000000000000000000000000000000000000000000000000b00aa1f0400000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002b0011e559da84dde3f841e22dc33f3adbf184d84a0000642a99837850543e223c134687f0c2b7e059873047000000000000000000000000000000000000000000","access_list":[]}},"signature":{"v":1,"r":"0xa114a8306dc24ae55eabdb8693342bb96d38ec5e02bfcf49258d4fe1585142c1","s":"0x1431ab11ed548dd466edc5e759a3bec24f3ae07620f57d858fb77c9b246ce23a"}},{"essence":{"Eip1559":{"chain_id":167008,"nonce":49,"max_priority_fee_per_gas":"0x59682f00","max_fee_per_gas":"0x59682f01","gas_limit":"0x9f96c","to":{"Call":"0x5cbfccd27db8a3981fe9965b0de59d436b2bd8b9"},"value":"0x13c3777bf34ffb","data":"0xac9650d800000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000164883164560000000000000000000000000011e559da84dde3f841e22dc33f3adbf184d84a0000000000000000000000002a99837850543e223c134687f0c2b7e05987304700000000000000000000000000000000000000000000000000000000000001f4fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdbb56fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffdff620000000000000000000000000000000000000000000000000013c3777bf34ffb000000000000000000000000000000000000000000000000000000018e3ea11800000000000000000000000000000000000000000000000000139ae99228cb98000000000000000000000000000000000000000000000000000000018bb4e1fb000000000000000000000000a29b384a523729bc9e076013fa035ce9c2544cbc0000000000000000000000000000000000000000000000000000000065a970bc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000412210e8a00000000000000000000000000000000000000000000000000000000","access_list":[]}},"signature":{"v":1,"r":"0x689068e5ae1aa38507a8d58a8a7a2c93435bf79de56285b7579f5be542c2d76","s":"0x31eda5de43d522209ac8a01bd73e6c3c1c2e4b7a71df1671e683c8e78aa6f5dd"}},{"essence":{"Eip1559":{"chain_id":167008,"nonce":10,"max_priority_fee_per_gas":"0x59682f00","max_fee_per_gas":"0x59682f01","gas_limit":"0x2a351","to":{"Call":"0x2fcc2e44ff836fbf5c3d7e9c2ebdf3b1509cf4f3"},"value":"0x0","data":"0xd37c353b0000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000036697066733a2f2f516d62507a4d336645634561365270424c4765694d686e4467734d4c7347447531334263324a6b514d6e77564c482f000000000000000000000000000000000000000000000000000000000000000000000000000000000000","access_list":[]}},"signature":{"v":1,"r":"0x7f1f660b98f4600538e0c59b2eda352bce86a8229e4c32a7e5ff36373b44afb6","s":"0xd74d693dfd28bb0a611d34f5d38c1c5350aaa07a92890d065cf8705f90fd44f"}},{"essence":{"Eip1559":{"chain_id":167008,"nonce":3,"max_priority_fee_per_gas":"0x59682f00","max_fee_per_gas":"0x59682f01","gas_limit":"0x7e0c3","to":{"Call":"0x5cbfccd27db8a3981fe9965b0de59d436b2bd8b9"},"value":"0x66dea16dd4bad73","data":"0xac9650d800000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000164883164560000000000000000000000000011e559da84dde3f841e22dc33f3adbf184d84a000000000000000000000000d69d3e64d71844bbdda51cd7f23ed3631e9fac490000000000000000000000000000000000000000000000000000000000002710fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2766000000000000000000000000000000000000000000000000000000000000d89a0000000000000000000000000000000000000000000000000066dea16dd4bad73000000000000000000000000000000000000000000000046791fc84e07cff5100000000000000000000000000000000000000000000000000669d0a34d4952160000000000000000000000000000000000000000000000464bf6fe6f905302050000000000000000000000003da1db2cfab5f12239ee5ed0c84112a3ac6ed14b0000000000000000000000000000000000000000000000000000000065a970bc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000412210e8a00000000000000000000000000000000000000000000000000000000","access_list":[]}},"signature":{"v":0,"r":"0xeb181f0b30e077e595db6b4141e51e31fc77ad6050fee4b93c714e679db5ed40","s":"0x7e8dadd2fd476a3da2163f553402c97fbacbf621ac35680bca4cde75752f5cd2"}},{"essence":{"Eip1559":{"chain_id":167008,"nonce":7,"max_priority_fee_per_gas":"0x59682f00","max_fee_per_gas":"0x59682f01","gas_limit":"0x1e4b0","to":"Create","value":"0x0","data":"0x608060405234801561000f575f80fd5b506101438061001d5f395ff3fe608060405234801561000f575f80fd5b5060043610610034575f3560e01c80632e64cec1146100385780636057361d14610056575b5f80fd5b610040610072565b60405161004d919061009b565b60405180910390f35b610070600480360381019061006b91906100e2565b61007a565b005b5f8054905090565b805f8190555050565b5f819050919050565b61009581610083565b82525050565b5f6020820190506100ae5f83018461008c565b92915050565b5f80fd5b6100c181610083565b81146100cb575f80fd5b50565b5f813590506100dc816100b8565b92915050565b5f602082840312156100f7576100f66100b4565b5b5f610104848285016100ce565b9150509291505056fea2646970667358221220175b5ff5925b348b9f880264a1038aba4c999696f4387cf13a5ccdd35467fb6664736f6c63430008160033","access_list":[]}},"signature":{"v":0,"r":"0x92186532daaee1105b32dc5d9f6a08af177fa70a1c82b78f4f300f7883bc05da","s":"0x60446c625c010ec561f7e58ce5c9e5397552c43c47cb21360dda05084d38a44d"}},{"essence":{"Eip1559":{"chain_id":167008,"nonce":4,"max_priority_fee_per_gas":"0x59682f00","max_fee_per_gas":"0x59682f01","gas_limit":"0x1e4a4","to":"Create","value":"0x0","data":"0x608060405234801561000f575f80fd5b506101438061001d5f395ff3fe608060405234801561000f575f80fd5b5060043610610034575f3560e01c80632e64cec1146100385780636057361d14610056575b5f80fd5b610040610072565b60405161004d919061009b565b60405180910390f35b610070600480360381019061006b91906100e2565b61007a565b005b5f8054905090565b805f8190555050565b5f819050919050565b61009581610083565b82525050565b5f6020820190506100ae5f83018461008c565b92915050565b5f80fd5b6100c181610083565b81146100cb575f80fd5b50565b5f813590506100dc816100b8565b92915050565b5f602082840312156100f7576100f66100b4565b5b5f610104848285016100ce565b9150509291505056fea2646970667358221220af7008041a150a4ff43e9709ce67654cf19205ed004c4b1fe1500399ade56b9b64736f6c63430008170033","access_list":[]}},"signature":{"v":0,"r":"0x258ee024e15f77051480ac80950a73fa01a63ad3177d4ec7c95777799bf63f03","s":"0x40153d47a283de30db685aa6ae382f55415bd22733c115c6dc089fc8a5115bd7"}},{"essence":{"Eip1559":{"chain_id":167008,"nonce":5,"max_priority_fee_per_gas":"0x59682f00","max_fee_per_gas":"0x59682f01","gas_limit":"0xf34f","to":{"Call":"0xd69d3e64d71844bbdda51cd7f23ed3631e9fac49"},"value":"0x0","data":"0x095ea7b30000000000000000000000005cbfccd27db8a3981fe9965b0de59d436b2bd8b9ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff","access_list":[]}},"signature":{"v":1,"r":"0x6262be6fbbf8faabf3dade6f0ed9db7c0c640a5c4635e69f917858c9fbb83377","s":"0x4d18809f51c9f0ac05b6d11c7a9fad3cc188737a63e7c27dfc37c9dc2bf1fb33"}},{"essence":{"Eip1559":{"chain_id":167008,"nonce":34,"max_priority_fee_per_gas":"0x59682f00","max_fee_per_gas":"0x59682f01","gas_limit":"0x2cae4","to":{"Call":"0xd2c3cbb943fed0cfc8389b14a3f6df518fd46346"},"value":"0x11c37937e080000","data":"0x3593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000065a970bc00000000000000000000000000000000000000000000000000000000000000020b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000011c37937e08000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000000000119a5a1d9e00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002b0011e559da84dde3f841e22dc33f3adbf184d84a0000642a99837850543e223c134687f0c2b7e059873047000000000000000000000000000000000000000000","access_list":[]}},"signature":{"v":1,"r":"0x229795aac8a953809780d882cef11783aa775a348e13e13937990c15fbb0c4e","s":"0x1071aba3e0a1a1f91dd2d4aaacd4077c292cfbaf5dbb77e5290b226e9b06708a"}},{"essence":{"Eip1559":{"chain_id":167008,"nonce":0,"max_priority_fee_per_gas":"0x59682f00","max_fee_per_gas":"0x59682f01","gas_limit":"0x18e05","to":{"Call":"0x1670080000000000000000000000000000000001"},"value":"0x26c6036ae68a20","data":"0x33bcd0cc0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000085841072598236162b9a8fff9f254a9e20e9cc2d0000000000000000000000000000000000000000000000000000000000028c60000000000000000000000000000000000000000000000000000000000000426800000000000000000000000085841072598236162b9a8fff9f254a9e20e9cc2d00000000000000000000000085841072598236162b9a8fff9f254a9e20e9cc2d00000000000000000000000085841072598236162b9a8fff9f254a9e20e9cc2d000000000000000000000000000000000000000000000000002386f26fc1000000000000000000000000000000000000000000000000000000033f10fb258a2000000000000000000000000000000000000000000000000000000000000222e0000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001a000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000","access_list":[]}},"signature":{"v":1,"r":"0x69c02aca8c3ebb8f3ab9c3ec247538acc3c600d4a80b155a1a97f76124c3e9be","s":"0x71fe7065af839d2e7722430d162b806bec0ff65f3a7d70e39a0b9e8deb163a47"}},{"essence":{"Eip1559":{"chain_id":167008,"nonce":9,"max_priority_fee_per_gas":"0x59682f00","max_fee_per_gas":"0x59682f01","gas_limit":"0x1c71f","to":{"Call":"0x5d04bc3ddd8bcbdf3ff71ab39e62287ca185ae3e"},"value":"0x38d7ea4c68000","data":"0x1249c58b","access_list":[]}},"signature":{"v":0,"r":"0xfb9511460ab049660f2481840ed862642528247687800f9f00fb2b7b73a2c8bf","s":"0x2c38d48b31721f3893228be8705e0b34b5774011a5fdb54f3d3a18560a3955c5"}},{"essence":{"Eip1559":{"chain_id":167008,"nonce":3,"max_priority_fee_per_gas":"0x59682f00","max_fee_per_gas":"0x59682f01","gas_limit":"0xf34f","to":{"Call":"0xd69d3e64d71844bbdda51cd7f23ed3631e9fac49"},"value":"0x0","data":"0x095ea7b30000000000000000000000005cbfccd27db8a3981fe9965b0de59d436b2bd8b9ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff","access_list":[]}},"signature":{"v":1,"r":"0x4c2a32a6a6747c871566ecf4415255fd94ee3c2f648f46b8ea15cb509ffafed8","s":"0x58c53a01ff12fd74f21f00fea903753dd632c0c6a5763ccf680f9e9c8ca242e9"}},{"essence":{"Eip1559":{"chain_id":167008,"nonce":18,"max_priority_fee_per_gas":"0x59682f00","max_fee_per_gas":"0x59682f01","gas_limit":"0xfc55","to":{"Call":"0x5535b9ff2aa1a63b87921599850cb942f813323b"},"value":"0x0","data":"0xa9059cbb000000000000000000000000eb15859af4dc37738f32e8bb468eb1ffde5bd7a700000000000000000000000000000000000000000000021e19e0c9bab2400000","access_list":[]}},"signature":{"v":1,"r":"0xac3db1534cf8dad72a8cb063c3fea0d1d0f48d27ab0c7f8eb16054e9324395f","s":"0x458c8ac58e9f6d94dc64d59747b56cbfeef3b2db7ba0db8ccadc049d84069337"}},{"essence":{"Eip1559":{"chain_id":167008,"nonce":13,"max_priority_fee_per_gas":"0x59682f00","max_fee_per_gas":"0x59682f01","gas_limit":"0xd105","to":{"Call":"0xae2c46ddb314b9ba743c6dee4878f151881333d9"},"value":"0x0","data":"0x095ea7b3000000000000000000000000fde807b7c79f69f22622acb73db5b59654e115b60000000000000000000000000000000000000000000000000000000000402a73","access_list":[]}},"signature":{"v":1,"r":"0x907171397fefd07536584acf07fa05e113b7887964aa802761b7c8b161fe1bcd","s":"0x3be9419669fc93e94f68f3cd67edb941b0d6257a63ef860e9bb44eb2311d105"}},{"essence":{"Eip1559":{"chain_id":167008,"nonce":2,"max_priority_fee_per_gas":"0x59682f00","max_fee_per_gas":"0x59682f01","gas_limit":"0x66a97","to":{"Call":"0x1670080000000000000000000000000000000001"},"value":"0x0","data":"0x0138240800000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000001d764000000000000000000000000d209f6fbdce2462f3063321be3b96b481b44858100000000000000000000000000000000000000000000000000000000000042680000000000000000000000000000000000000000000000000000000000028c60000000000000000000000000d209f6fbdce2462f3063321be3b96b481b448581000000000000000000000000d209f6fbdce2462f3063321be3b96b481b448581000000000000000000000000d209f6fbdce2462f3063321be3b96b481b4485810000000000000000000000000000000000000000000000000011c37937e080000000000000000000000000000000000000000000000000000004cbd15e801ba000000000000000000000000000000000000000000000000000000000000222e0000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000009800000000000000000000000000000000000000000000000000000000000000020000000000000000000000000167008000000000000000000000000000001000100000000000000000000000000000000000000000000000000000000000ba59a000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000009400000000000000000000000000000000000000000000000000000000000000896f90893b90214f90211a04d338534c32c08dad0c101fe1798d1203edb20b2549468d1a3bb35237f5b76d9a04f2a94632c3c16f5c0f122731eb2beb951b7acf3249414e7a7ccd04597d9c746a0685df84299cc6f9ac64b2f49e2568d02f0c77aad28ee5b664748192e11f007a4a0aee90207fdca1d5e1ea19b61c3ae4b24d7e1aa4b7d283e66029e191e709c864ba0f197a203c989c02cd7f150f0596333d98079e4db2975a53cff67892497c208fda06303c9fce964d57aefb2bc0933477768fd48159deae37fac7138c2a3b8d51cc4a0179b035da2f9fdbb8bcf0ecafefb8d192ad5461aa146c6a690d20f1aa2089cd2a03e7b4458cbef3a6450004d40e0405a5571d030aa726d3a3da927d2a0ad1ba2fca0a4fffc6f869f6fc1bd00e64717df0035bee73e053c8ffa2765fbe2b27e86b3cfa06a1c14b1afbc465cc1553022116dde190b75cb92f8934074d2d046819d96dc00a0ec5386f3963a273e86060b6331ffc6c80a0df3a62e80193e6b9e66fe3262a9a6a066b2ff83824da5d831dda93c61a86c1b7a47492e558812878fcac7eacc1fa2a3a0e956b036b9570e798ddd15d9addf05a9f4e6a59bb3fd390ee86af1ba59632399a07ba682d91356cbb366314dab761dc97f6b53408562220b6233d2d7548d8522c4a0d9193d56e31ed7c50961592f21100febfcad45483fdd936d90ea8d8a2373cd31a0c9c8646daffe4b5fd7034deb172d4395462b3d72496a694c932b2908d1b2fbf780b90214f90211a0696c733cbbb18499e545004214dcb110a35c6acd9ce77461f9ab4f2f30311203a002b91aaa1ce363e25b95e77273990878898c9b100f038b51eafbf1f96baeae89a0984508740e4512154619a4274f22b5cdee7eb6e4faae6ed5741d4b6027390152a06e3344335cd57cda7affb56155f126c60d2fe34b02e9ce8d2be7f1f88ab98a10a0b3254e9ef461f192c9044a65d0e60b304142649ad2057c684f1f26acdae63230a00a65ce7f2398a7a71eb158670acfc4f349e0152a5020d6dc279c4447ef8e9793a001049d0c5ebac806f9189934025ed3820c83fc7ccb4a67387a46fc53d0e9e3b8a0f4e9edeb76a7f2d1e1f70c315cfd2c642c48a4b2e53d6f9fdac1f26d1ad3f60aa03059144b248f828a560a3fec36da447b4f22cc81910db5690d5587844cbd7948a010a11769e51f30f523001bbdcd72370d8e2eea566889ccdd02cde1e3a7beb1ada010c9a764788bf1b6891589350c4f38847832992fe94351fb212d6b33baf0a283a0c4da0adc3b7b82324a20d15760487a79562cbb0f406bc8559e1deab5cee3f260a0e6a50d75e9499e7ba4bf0ed5b45ccee2935088aed62450406228c84c3c317b22a0c206a8a4627daf678da0710496c28dfb2a09e2ed9d10c4d78dcd992a733b8e4aa00e7a51b5c5a86483925750dc1eb0b6b2e597d59ca5e402a4bcd3010fcbb4b0bfa0f565212ee1fdbbc53a29832495f71ac368c06c1b2988d64fd6588dd69ddd020880b90214f90211a0094855f0e01800ab91e234bd4475b26cee6c4b8bafd93be4890bcbe6aa929819a0091bb2ef5ab4862381362ffb0378c9d30e05eae96211f8527e3e255747886d33a0faaf2e875df5fdd723e58919ed9caf447dc6c0248a25f8fd0cb148e04215872ba0db91cc17d08bd087d67a236984c2e12cc9ddea4862a1a21a13f478dc6c80d855a0733fddac882f5a7fce648478daf566988aeefc82a668e4fc1857d98199b01b66a0db33be24d2f3f3df19167f1a08dceb543d47e4530f334eb73bd10fad7e945cfaa0de73de062cab691c79044a024d499c53ef2306afb3955781bb4791d3f95460f0a0f9e7845a7fc516fb1fb3697045addcc638cf084e8ac5810ac70022a4c7c670c7a0a0c2f93c0c5718871c846ca47f449833f131610146ff59e1d943aed70eb79712a04ce6d5d782d3d61cb9c3160ceadcf377384c31a49ed0ac427e26cbf04691586ba0a49205927873adfa81c1dfc05ce22459e3e9ad7c7aa43111d3238412aa70de5fa095fcb28f0fa956ba3236f7cb2bf5f0240ce26671bd2805bd42f9739ccb027814a060d982e4f8d08a0ac23f2f05436d086fa2491a1927162bb2cc02059fcc421090a0612c90d3cd9d84e9baded563e523cef2fbe63fe7713fb666628e6123236e5313a02cbc5e9b1fee2358f2b3a12049778e5c7f8589d1dd8077a98fe549c2969fbdbda0d81256248ec40a800150815c2880135654a428b67665f7d1a2767736e371536f80b901d4f901d1a06e6a5be3912d1e57cd7e62c8cd26bac69f85d985238bdee92dc3d1e76217f021a074e4d0d470f4e14d7039a8bf622f28d71727b857815a26d9116b612e0ad6062580a0dd3b2dd3e45de43392021d9b6711ae51f0ddce380706cc873854eb79fa9702c1a0e6c2420f1bbca66b295de1b50c8098283df205e36b21cbd1fe28bb8f5d478a84a0e08af052acaad51a6ca56e8eab502daaaf1750992c8f75dce02e4064cd6e67c5a07da506423017a0796f02c910edc631dc0efb8a5bcc8f4b71b2a4c7d53ba5afb6a0ef5fdc8453a143c403bb1db38026bb78edfd4e86f4c4af1c0a7d2712c21c573ba05b392046508ce0894d57c3e44579eb71ff03a73d06b7e39894aa0dc39b9cba09a0dfcec8f3f4d10129f4d14843f3c957f2b16d1e262efd72b9babcf997d280527fa070ce02729dbe2f92a5f612e3602f020ed7f7b88c7f288e3112128d53505c6848a04f94d5e5a1a910d400f378e3dadf2cc07c0aa2e637d86b09922a0f8477f8bc5a80a012afb69e9d1de641d4d4f91fe240d7104e594c15a282f51097771908b92153b7a03ef659dcc44ebd4fd09a9d4f98ffe749a41d8b1a4bfead679dcfa6e92c25b2dda0af80c4e08ac9185959a41fe015532674a0b1b030735d6ba8991e59a7b617c53e80b853f851808080a00224e1fdf1ab331b3134156b057cb59d9bc1428229a324ccc7a1261676e7557c80808080808080a0e6e623c65732560b5e311649960f5ae5c9d9c93da90f3f41b98bc3f52a5c50798080808080a1e09e3bf3e72547899f614325047fbbd95aa7d3089f0a4fe8da9293a0b34e5ec901000000000000000000000000000000000000000000000000000000000000000000000000000000000000","access_list":[]}},"signature":{"v":0,"r":"0xf622a174fc4803fd9c5f3581671487e0e1ccbec5c7128f231252a81364ab772d","s":"0x71cadc95edcfd863e0192cebee1b867212b5662f75ddc3d11e8d2450bb1c5f4"}},{"essence":{"Eip1559":{"chain_id":167008,"nonce":2,"max_priority_fee_per_gas":"0x59682f00","max_fee_per_gas":"0x59682f01","gas_limit":"0xc989","to":{"Call":"0xd69d3e64d71844bbdda51cd7f23ed3631e9fac49"},"value":"0x0","data":"0x095ea7b3000000000000000000000000fde807b7c79f69f22622acb73db5b59654e115b6000000000000000000000000000000000000000000000000d02ab486cedc0000","access_list":[]}},"signature":{"v":0,"r":"0x374cacab8e656e89b5726c0a62b0184a9922e58b625abfe442333affef9cb5d2","s":"0x3fc455c2876bb3c5c6c33550459e6a5da56a444327577ffea74851bf5554e3da"}},{"essence":{"Eip1559":{"chain_id":167008,"nonce":6,"max_priority_fee_per_gas":"0x59682f00","max_fee_per_gas":"0x59682f01","gas_limit":"0x7e07b","to":{"Call":"0x5cbfccd27db8a3981fe9965b0de59d436b2bd8b9"},"value":"0x221b262dd8000","data":"0xac9650d800000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000001e00000000000000000000000000000000000000000000000000000000000000164883164560000000000000000000000000011e559da84dde3f841e22dc33f3adbf184d84a000000000000000000000000d69d3e64d71844bbdda51cd7f23ed3631e9fac490000000000000000000000000000000000000000000000000000000000002710fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff2766000000000000000000000000000000000000000000000000000000000000d89a0000000000000000000000000000000000000000000000000000221b262dd8000000000000000000000000000000000000000000000000000175d77c37d3e32d00000000000000000000000000000000000000000000000000002205671c88644000000000000000000000000000000000000000000000000174e7ed3b949b396000000000000000000000000b56d486406d4c8e7af2da8b79eab680309f7b0030000000000000000000000000000000000000000000000000000000065a970bc00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000412210e8a00000000000000000000000000000000000000000000000000000000","access_list":[]}},"signature":{"v":1,"r":"0xe969a2e7c314fc6a369e72b2ce5bd99340f81072d5ef42cec35cc7510d4f1f06","s":"0x75b5f0a869c54fd473023cc362edb2dc1ae41868a11e4c29efde300fd9ae6eb"}},{"essence":{"Eip1559":{"chain_id":167008,"nonce":3,"max_priority_fee_per_gas":"0x59682f00","max_fee_per_gas":"0x59682f01","gas_limit":"0x1e4b0","to":"Create","value":"0x0","data":"0x608060405234801561000f575f80fd5b506101438061001d5f395ff3fe608060405234801561000f575f80fd5b5060043610610034575f3560e01c80632e64cec1146100385780636057361d14610056575b5f80fd5b610040610072565b60405161004d919061009b565b60405180910390f35b610070600480360381019061006b91906100e2565b61007a565b005b5f8054905090565b805f8190555050565b5f819050919050565b61009581610083565b82525050565b5f6020820190506100ae5f83018461008c565b92915050565b5f80fd5b6100c181610083565b81146100cb575f80fd5b50565b5f813590506100dc816100b8565b92915050565b5f602082840312156100f7576100f66100b4565b5b5f610104848285016100ce565b9150509291505056fea26469706673582212207ca8a77a375aff548bc76892f6b2093ea5bec72e34f6638bcd6bc43f620679bc64736f6c63430008160033","access_list":[]}},"signature":{"v":1,"r":"0x8faabd527d388ef1a925df7b6cda79a8db15fa4841c7b65cefb9feb79bc0c191","s":"0x6da937d631650c8f0583d449c5a7d963a0868dc24eb86f31895111bf6b77fcec"}},{"essence":{"Eip1559":{"chain_id":167008,"nonce":1,"max_priority_fee_per_gas":"0x59682f00","max_fee_per_gas":"0x59682f01","gas_limit":"0x47eb9","to":{"Call":"0xd2c3cbb943fed0cfc8389b14a3f6df518fd46346"},"value":"0xb1a2bc2ec500000","data":"0x3593564c000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000065a970bc00000000000000000000000000000000000000000000000000000000000000030b000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000003000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000001e0000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000b1a2bc2ec5000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000006a94d74f4300000000000000000000000000000000000000000000000000000000000000132060300000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002b0011e559da84dde3f841e22dc33f3adbf184d84a0001f4ae2c46ddb314b9ba743c6dee4878f151881333d9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000470de4df82000000000000000000000000000000000000000000000000000000000000000cbd3eb00000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002b0011e559da84dde3f841e22dc33f3adbf184d84a000bb8ae2c46ddb314b9ba743c6dee4878f151881333d9000000000000000000000000000000000000000000","access_list":[]}},"signature":{"v":0,"r":"0x400e80dc05b0d0500951513bf209257e00c71b28d4e777b9f1dd4dae7f898489","s":"0x7a8fa0a5ebcc6d924a6c1875efdf7242786ac03e1a84101eeb833458608742d7"}},{"essence":{"Eip1559":{"chain_id":167008,"nonce":802,"max_priority_fee_per_gas":"0x186a0","max_fee_per_gas":"0x186a1","gas_limit":"0x55200","to":{"Call":"0xbfcfd6fb89c1fdd0d87c3d24dd8fc1d371203651"},"value":"0x0","data":"0x783cf332000000000000000000000000000000000000000000000000000000395bb93400","access_list":[]}},"signature":{"v":0,"r":"0xcbaea2f53ed121fa6d314add4cb619dd971e0578bec2b1c9d91912d54f7bac7a","s":"0x6c7819f144ff6caba3c31ed383fde2c6f8eed40a3dfbff5183f00fb2095ff208"}}]
         "#;
-        let rust_root = rust_mtp_root(&txs).unwrap();
-        let go_root = go_mtp_root(&txs).unwrap();
+        let rust_root = rust_mtp_root(txs).unwrap();
+        let go_root = go_mtp_root(txs).unwrap();
 
         assert_eq!(rust_root.rlps.len(), go_root.rlps.len());
         println!("rust_root.rlps[0]: {}", rust_root.rlps[0]);