diff --git a/Cargo.lock b/Cargo.lock index 55ce62b..00bd78d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,16 +2,6 @@ # It is not intended for manual editing. version = 4 -[[package]] -name = "Inflector" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" -dependencies = [ - "lazy_static", - "regex", -] - [[package]] name = "addchain" version = "0.2.0" @@ -38,17 +28,6 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" -[[package]] -name = "aes" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" -dependencies = [ - "cfg-if", - "cipher", - "cpufeatures", -] - [[package]] name = "ahash" version = "0.8.12" @@ -361,7 +340,7 @@ dependencies = [ "serde", "sha3", "tiny-keccak", - "zkm-zkvm", + "zkm-zkvm 2.0.0 (git+https://github.com/ProjectZKM/Ziren)", ] [[package]] @@ -539,7 +518,7 @@ dependencies = [ "alloy-rlp", "alloy-serde", "alloy-sol-types", - "itertools 0.14.0", + "itertools 0.13.0", "serde", "serde_json", "serde_with", @@ -608,7 +587,7 @@ checksum = "6d792e205ed3b72f795a8044c52877d2e6b6e9b1d13f431478121d8d4eaa9028" dependencies = [ "alloy-sol-macro-input", "const-hex", - "heck 0.5.0", + "heck", "indexmap 2.12.1", "proc-macro-error2", "proc-macro2", @@ -626,7 +605,7 @@ checksum = "0bd1247a8f90b465ef3f1207627547ec16940c35597875cdc09c49d58b19693c" dependencies = [ "const-hex", "dunce", - "heck 0.5.0", + "heck", "macro-string", "proc-macro2", "quote", @@ -707,7 +686,7 @@ dependencies = [ "rustls 0.23.35", "serde_json", "tokio", - "tokio-tungstenite 0.26.2", + "tokio-tungstenite", "tracing", "ws_stream_wasm", ] @@ -1090,12 +1069,15 @@ dependencies = [ ] [[package]] -name = "ascii-canvas" -version = "3.0.0" +name = "async-compression" +version = "0.4.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" +checksum = "ee19bd99b43e3691acbad4e840420a4881cea6c0b66a208125a824f8fd53f5a1" dependencies = [ - "term", + "compression-codecs", + "compression-core", + "pin-project-lite", + "tokio", ] [[package]] @@ -1297,12 +1279,6 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - [[package]] name = "base64" version = "0.21.7" @@ -1321,12 +1297,6 @@ version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e050f626429857a27ddccb31e0aca21356bfa709c04041aefddac081a8f068a" -[[package]] -name = "bech32" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d86b93f97252c47b41663388e6d155714a9d0c398b99f1005cbc5f978b29f445" - [[package]] name = "bimap" version = "0.6.3" @@ -1353,7 +1323,7 @@ dependencies = [ "clang-sys", "itertools 0.13.0", "log", - "prettyplease 0.2.37", + "prettyplease", "proc-macro2", "quote", "regex", @@ -1362,30 +1332,15 @@ dependencies = [ "syn 2.0.111", ] -[[package]] -name = "bit-set" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" -dependencies = [ - "bit-vec 0.6.3", -] - [[package]] name = "bit-set" version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" dependencies = [ - "bit-vec 0.8.0", + "bit-vec", ] -[[package]] -name = "bit-vec" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" - [[package]] name = "bit-vec" version = "0.8.0" @@ -1456,6 +1411,19 @@ dependencies = [ "constant_time_eq 0.3.1", ] +[[package]] +name = "blake3" +version = "1.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d9e454fc11f76977dc803893aff6304ed33d6a26efae8696573bea74baa27ae" +dependencies = [ + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq 0.4.2", + "cpufeatures 0.3.1", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -1493,12 +1461,14 @@ version = "0.8.0" source = "git+https://github.com/ziren-patches/bls12_381?branch=patch-0.8.0#bcf9397426410acc171ad625416b508dc913be8e" dependencies = [ "cfg-if", + "digest 0.10.7", "ff 0.13.1", "group 0.13.0", + "hex", "pairing 0.23.0", "rand_core 0.6.4", "subtle", - "zkm-lib", + "zkm-lib 2.0.0 (git+https://github.com/ProjectZKM/Ziren)", ] [[package]] @@ -1536,16 +1506,6 @@ dependencies = [ "syn 2.0.111", ] -[[package]] -name = "bs58" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" -dependencies = [ - "sha2", - "tinyvec", -] - [[package]] name = "bumpalo" version = "3.19.0" @@ -1593,26 +1553,6 @@ dependencies = [ "serde", ] -[[package]] -name = "bzip2" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdb116a6ef3f6c3698828873ad02c3014b3c85cadb88496095628e3ef1e347f8" -dependencies = [ - "bzip2-sys", - "libc", -] - -[[package]] -name = "bzip2-sys" -version = "0.1.13+1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225bff33b2141874fe80d71e07d6eec4f85c5c216453dd96388240f96e1acc14" -dependencies = [ - "cc", - "pkg-config", -] - [[package]] name = "c-kzg" version = "2.1.5" @@ -1720,16 +1660,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "cipher" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" -dependencies = [ - "crypto-common", - "inout", -] - [[package]] name = "clang-sys" version = "1.8.1" @@ -1769,7 +1699,7 @@ version = "4.5.49" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro2", "quote", "syn 2.0.111", @@ -1791,62 +1721,27 @@ dependencies = [ ] [[package]] -name = "coins-bip32" -version = "0.8.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b6be4a5df2098cd811f3194f64ddb96c267606bffd9689ac7b0160097b01ad3" -dependencies = [ - "bs58", - "coins-core", - "digest 0.10.7", - "hmac", - "k256", - "serde", - "sha2", - "thiserror 1.0.69", -] - -[[package]] -name = "coins-bip39" -version = "0.8.7" +name = "colorchoice" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3db8fba409ce3dc04f7d804074039eb68b960b0829161f8e06c95fea3f122528" -dependencies = [ - "bitvec", - "coins-bip32", - "hmac", - "once_cell", - "pbkdf2 0.12.2", - "rand 0.8.5", - "sha2", - "thiserror 1.0.69", -] +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" [[package]] -name = "coins-core" -version = "0.8.7" +name = "compression-codecs" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5286a0843c21f8367f7be734f89df9b822e0321d8bcce8d6e735aadff7d74979" +checksum = "98fc98460ba0ad5317075d3632b8dfc45d0be8c4a49347c2a38272019717614a" dependencies = [ - "base64 0.21.7", - "bech32", - "bs58", - "digest 0.10.7", - "generic-array 0.14.7", - "hex", - "ripemd", - "serde", - "serde_derive", - "sha2", - "sha3", - "thiserror 1.0.69", + "compression-core", + "flate2", + "memchr", ] [[package]] -name = "colorchoice" -version = "1.0.4" +name = "compression-core" +version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" +checksum = "6e8ccc4ea9f6acc32d102c0f6d471d11d913ad15f20c04de743374861fa1d414" [[package]] name = "console" @@ -1868,7 +1763,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3bb320cac8a0750d7f25280aa97b09c26edfe161164238ecbbb31092b079e735" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "proptest", "serde_core", ] @@ -1901,15 +1796,15 @@ dependencies = [ [[package]] name = "constant_time_eq" -version = "0.1.5" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" [[package]] name = "constant_time_eq" -version = "0.3.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" +checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" [[package]] name = "convert_case" @@ -1945,6 +1840,15 @@ dependencies = [ "libc", ] +[[package]] +name = "cpufeatures" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca28b0ae3115b884660db4118d803791fd6756b6e88f39c0f3f7859060d7566" +dependencies = [ + "libc", +] + [[package]] name = "crc" version = "3.4.0" @@ -2049,15 +1953,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "ctr" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" -dependencies = [ - "cipher", -] - [[package]] name = "ctrlc" version = "3.5.1" @@ -2076,7 +1971,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "curve25519-dalek-derive", "fiat-crypto", "rustc_version 0.4.1", @@ -2345,16 +2240,6 @@ dependencies = [ "dirs-sys", ] -[[package]] -name = "dirs-next" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" -dependencies = [ - "cfg-if", - "dirs-sys-next", -] - [[package]] name = "dirs-sys" version = "0.4.1" @@ -2367,17 +2252,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "dirs-sys-next" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" -dependencies = [ - "libc", - "redox_users", - "winapi", -] - [[package]] name = "dispatch2" version = "0.3.0" @@ -2431,6 +2305,33 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" +[[package]] +name = "dynasm" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33dc03612f42465a8ed7f5e354bc2b79ba54cedefa81d5bd3a064f1835adaba8" +dependencies = [ + "bitflags 1.3.2", + "byteorder", + "lazy_static", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "dynasmrt" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7dccc31a678058996aef614f6bd418ced384da70f284e83e2b7bf29b27b6a28" +dependencies = [ + "byteorder", + "dynasm", + "fnv", + "memmap2 0.5.10", +] + [[package]] name = "ecdsa" version = "0.16.9" @@ -2494,15 +2395,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "ena" -version = "0.14.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d248bdd43ce613d87415282f69b9bb99d947d290b10962dd6c56233312c2ad5" -dependencies = [ - "log", -] - [[package]] name = "encode_unicode" version = "1.0.0" @@ -2518,31 +2410,13 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "enr" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a3d8dc56e02f954cac8eb489772c552c473346fc34f67412bb6244fd647f7e4" -dependencies = [ - "base64 0.21.7", - "bytes", - "hex", - "k256", - "log", - "rand 0.8.5", - "rlp", - "serde", - "sha3", - "zeroize", -] - [[package]] name = "enum-as-inner" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1e6a265c649f3f5979b601d26f1d05ada116434c87741c9493cb56218f76cbc" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro2", "quote", "syn 2.0.111", @@ -2628,28 +2502,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "eth-keystore" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fda3bf123be441da5260717e0661c25a2fd9cb2b2c1d20bf2e05580047158ab" -dependencies = [ - "aes", - "ctr", - "digest 0.10.7", - "hex", - "hmac", - "pbkdf2 0.11.0", - "rand 0.8.5", - "scrypt", - "serde", - "serde_json", - "sha2", - "sha3", - "thiserror 1.0.69", - "uuid 0.8.2", -] - [[package]] name = "eth-proofs" version = "0.1.0" @@ -2660,12 +2512,16 @@ dependencies = [ "alloy-transport", "alloy-transport-ws", "base64 0.22.1", + "bincode", "clap", "dotenv", "eyre", + "fs2", "futures", "guest-executor", + "hex", "host-executor", + "libc", "primitives", "provider", "reqwest 0.12.25", @@ -2673,347 +2529,55 @@ dependencies = [ "reqwest-retry", "serde", "serde_json", + "sha2", + "tempfile", "time", "tokio", "tracing", "tracing-subscriber", "url", "zkm-build", + "zkm-cuda", + "zkm-prover", "zkm-sdk", ] [[package]] -name = "ethabi" -version = "18.0.0" +name = "eyre" +version = "0.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7413c5f74cc903ea37386a8965a936cbeb334bd270862fdece542c1b2dcbc898" +checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" dependencies = [ - "ethereum-types", - "hex", + "indenter", "once_cell", - "regex", - "serde", - "serde_json", - "sha3", - "thiserror 1.0.69", - "uint", ] [[package]] -name = "ethbloom" -version = "0.13.0" +name = "fastrand" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c22d4b5885b6aa2fe5e8b9329fb8d232bf739e434e6b87347c63bdd00c120f60" -dependencies = [ - "crunchy", - "fixed-hash", - "impl-codec", - "impl-rlp", - "impl-serde", - "scale-info", - "tiny-keccak", -] +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] -name = "ethereum-types" -version = "0.14.1" +name = "fastrlp" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d215cbf040552efcbe99a38372fe80ab9d00268e20012b79fcd0f073edd8ee" +checksum = "139834ddba373bbdd213dffe02c8d110508dcf1726c2be27e8d1f7d7e1856418" dependencies = [ - "ethbloom", - "fixed-hash", - "impl-codec", - "impl-rlp", - "impl-serde", - "primitive-types", - "scale-info", - "uint", + "arrayvec", + "auto_impl", + "bytes", ] [[package]] -name = "ethers" -version = "2.0.14" +name = "fastrlp" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "816841ea989f0c69e459af1cf23a6b0033b19a55424a1ea3a30099becdb8dec0" +checksum = "ce8dba4714ef14b8274c371879b175aa55b16b30f269663f19d576f380018dc4" dependencies = [ - "ethers-addressbook", - "ethers-contract", - "ethers-core", - "ethers-etherscan", - "ethers-middleware", - "ethers-providers", - "ethers-signers", - "ethers-solc", -] - -[[package]] -name = "ethers-addressbook" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5495afd16b4faa556c3bba1f21b98b4983e53c1755022377051a975c3b021759" -dependencies = [ - "ethers-core", - "once_cell", - "serde", - "serde_json", -] - -[[package]] -name = "ethers-contract" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fceafa3578c836eeb874af87abacfb041f92b4da0a78a5edd042564b8ecdaaa" -dependencies = [ - "const-hex", - "ethers-contract-abigen", - "ethers-contract-derive", - "ethers-core", - "ethers-providers", - "futures-util", - "once_cell", - "pin-project", - "serde", - "serde_json", - "thiserror 1.0.69", -] - -[[package]] -name = "ethers-contract-abigen" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04ba01fbc2331a38c429eb95d4a570166781f14290ef9fdb144278a90b5a739b" -dependencies = [ - "Inflector", - "const-hex", - "dunce", - "ethers-core", - "ethers-etherscan", - "eyre", - "prettyplease 0.2.37", - "proc-macro2", - "quote", - "regex", - "reqwest 0.11.27", - "serde", - "serde_json", - "syn 2.0.111", - "toml", - "walkdir", -] - -[[package]] -name = "ethers-contract-derive" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87689dcabc0051cde10caaade298f9e9093d65f6125c14575db3fd8c669a168f" -dependencies = [ - "Inflector", - "const-hex", - "ethers-contract-abigen", - "ethers-core", - "proc-macro2", - "quote", - "serde_json", - "syn 2.0.111", -] - -[[package]] -name = "ethers-core" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82d80cc6ad30b14a48ab786523af33b37f28a8623fc06afd55324816ef18fb1f" -dependencies = [ - "arrayvec", - "bytes", - "cargo_metadata", - "chrono", - "const-hex", - "elliptic-curve", - "ethabi", - "generic-array 0.14.7", - "k256", - "num_enum", - "once_cell", - "open-fastrlp", - "rand 0.8.5", - "rlp", - "serde", - "serde_json", - "strum 0.26.3", - "syn 2.0.111", - "tempfile", - "thiserror 1.0.69", - "tiny-keccak", - "unicode-xid", -] - -[[package]] -name = "ethers-etherscan" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79e5973c26d4baf0ce55520bd732314328cabe53193286671b47144145b9649" -dependencies = [ - "chrono", - "ethers-core", - "reqwest 0.11.27", - "semver 1.0.27", - "serde", - "serde_json", - "thiserror 1.0.69", - "tracing", -] - -[[package]] -name = "ethers-middleware" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48f9fdf09aec667c099909d91908d5eaf9be1bd0e2500ba4172c1d28bfaa43de" -dependencies = [ - "async-trait", - "auto_impl", - "ethers-contract", - "ethers-core", - "ethers-etherscan", - "ethers-providers", - "ethers-signers", - "futures-channel", - "futures-locks", - "futures-util", - "instant", - "reqwest 0.11.27", - "serde", - "serde_json", - "thiserror 1.0.69", - "tokio", - "tracing", - "tracing-futures", - "url", -] - -[[package]] -name = "ethers-providers" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6434c9a33891f1effc9c75472e12666db2fa5a0fec4b29af6221680a6fe83ab2" -dependencies = [ - "async-trait", - "auto_impl", - "base64 0.21.7", - "bytes", - "const-hex", - "enr", - "ethers-core", - "futures-core", - "futures-timer", - "futures-util", - "hashers", - "http 0.2.12", - "instant", - "jsonwebtoken", - "once_cell", - "pin-project", - "reqwest 0.11.27", - "serde", - "serde_json", - "thiserror 1.0.69", - "tokio", - "tokio-tungstenite 0.20.1", - "tracing", - "tracing-futures", - "url", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", - "ws_stream_wasm", -] - -[[package]] -name = "ethers-signers" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "228875491c782ad851773b652dd8ecac62cda8571d3bc32a5853644dd26766c2" -dependencies = [ - "async-trait", - "coins-bip32", - "coins-bip39", - "const-hex", - "elliptic-curve", - "eth-keystore", - "ethers-core", - "rand 0.8.5", - "sha2", - "thiserror 1.0.69", - "tracing", -] - -[[package]] -name = "ethers-solc" -version = "2.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66244a771d9163282646dbeffe0e6eca4dda4146b6498644e678ac6089b11edd" -dependencies = [ - "cfg-if", - "const-hex", - "dirs", - "dunce", - "ethers-core", - "glob", - "home", - "md-5", - "num_cpus", - "once_cell", - "path-slash", - "rayon", - "regex", - "semver 1.0.27", - "serde", - "serde_json", - "solang-parser", - "svm-rs", - "thiserror 1.0.69", - "tiny-keccak", - "tokio", - "tracing", - "walkdir", - "yansi", -] - -[[package]] -name = "eyre" -version = "0.6.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cd915d99f24784cdc19fd37ef22b97e3ff0ae756c7e492e9fbfe897d61e2aec" -dependencies = [ - "indenter", - "once_cell", -] - -[[package]] -name = "fastrand" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" - -[[package]] -name = "fastrlp" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "139834ddba373bbdd213dffe02c8d110508dcf1726c2be27e8d1f7d7e1856418" -dependencies = [ - "arrayvec", - "auto_impl", - "bytes", -] - -[[package]] -name = "fastrlp" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce8dba4714ef14b8274c371879b175aa55b16b30f269663f19d576f380018dc4" -dependencies = [ - "arrayvec", - "auto_impl", - "bytes", + "arrayvec", + "auto_impl", + "bytes", ] [[package]] @@ -3061,6 +2625,16 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" +[[package]] +name = "filetime" +version = "0.2.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c287a33c7f0a620c38e641e7f60827713987b3c0f26e8ddc9462cc69cf75759" +dependencies = [ + "cfg-if", + "libc", +] + [[package]] name = "find-msvc-tools" version = "0.1.5" @@ -3207,16 +2781,6 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" -[[package]] -name = "futures-locks" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45ec6fe3675af967e67c5536c0b9d44e34e6c52f86bedc4ea49c5317b8e94d06" -dependencies = [ - "futures-channel", - "futures-task", -] - [[package]] name = "futures-macro" version = "0.3.31" @@ -3240,16 +2804,6 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" -[[package]] -name = "futures-timer" -version = "3.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" -dependencies = [ - "gloo-timers", - "send_wrapper 0.4.0", -] - [[package]] name = "futures-util" version = "0.3.31" @@ -3274,21 +2828,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42012b0f064e01aa58b545fe3727f90f7dd4020f4a3ea735b50344965f5a57e9" -[[package]] -name = "fxhash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -dependencies = [ - "byteorder", -] - -[[package]] -name = "gcd" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a" - [[package]] name = "generic-array" version = "0.14.7" @@ -3363,18 +2902,6 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" -[[package]] -name = "gloo-timers" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b995a66bb87bebce9a0f4a95aed01daca4872c050bfcb21653361c03bc35e5c" -dependencies = [ - "futures-channel", - "futures-core", - "js-sys", - "wasm-bindgen", -] - [[package]] name = "group" version = "0.12.1" @@ -3407,7 +2934,9 @@ dependencies = [ "alloy-network", "alloy-primitives", "alloy-rpc-types", + "aurora-engine-modexp", "bincode", + "bls12_381 0.8.0", "itertools 0.13.0", "kzg-rs", "mpt", @@ -3434,7 +2963,9 @@ dependencies = [ "serde", "serde_json", "serde_with", + "substrate-bn", "thiserror 1.0.69", + "zkm-lib 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", ] [[package]] @@ -3498,50 +3029,6 @@ dependencies = [ "rayon", ] -[[package]] -name = "halo2curves" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d380afeef3f1d4d3245b76895172018cfb087d9976a7cabcd5597775b2933e07" -dependencies = [ - "blake2", - "digest 0.10.7", - "ff 0.13.1", - "group 0.13.0", - "halo2derive", - "hex", - "lazy_static", - "num-bigint 0.4.6", - "num-integer", - "num-traits", - "pairing 0.23.0", - "pasta_curves 0.5.1", - "paste", - "rand 0.8.5", - "rand_core 0.6.4", - "rayon", - "serde", - "serde_arrays 0.1.0", - "sha2", - "static_assertions", - "subtle", - "unroll", -] - -[[package]] -name = "halo2derive" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdb99e7492b4f5ff469d238db464131b86c2eaac814a78715acba369f64d2c76" -dependencies = [ - "num-bigint 0.4.6", - "num-integer", - "num-traits", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "hashbrown" version = "0.12.3" @@ -3581,21 +3068,6 @@ dependencies = [ "serde_core", ] -[[package]] -name = "hashers" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2bca93b15ea5a746f220e56587f71e73c6165eab783df9e26590069953e3c30" -dependencies = [ - "fxhash", -] - -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - [[package]] name = "heck" version = "0.5.0" @@ -3613,9 +3085,6 @@ name = "hex" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -dependencies = [ - "serde", -] [[package]] name = "hex-conservative" @@ -3695,15 +3164,6 @@ dependencies = [ "digest 0.10.7", ] -[[package]] -name = "home" -version = "0.5.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc627f471c528ff0c4a49e1d5e60450c8f6461dd6d10ba9dcd3a61d3dff7728d" -dependencies = [ - "windows-sys 0.61.2", -] - [[package]] name = "host" version = "0.1.0" @@ -3983,7 +3443,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "socket2 0.6.1", - "system-configuration 0.6.1", + "system-configuration", "tokio", "tower-service", "tracing", @@ -4131,24 +3591,6 @@ dependencies = [ "parity-scale-codec", ] -[[package]] -name = "impl-rlp" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28220f89297a075ddc7245cd538076ee98b01f2a9c23a53a4f1105d5a322808" -dependencies = [ - "rlp", -] - -[[package]] -name = "impl-serde" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc88fc67028ae3db0c853baa36269d398d5f45b6982f95549ff5def78c935cd" -dependencies = [ - "serde", -] - [[package]] name = "impl-trait-for-tuples" version = "0.2.3" @@ -4202,15 +3644,6 @@ dependencies = [ "web-time", ] -[[package]] -name = "inout" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" -dependencies = [ - "generic-array 0.14.7", -] - [[package]] name = "instant" version = "0.1.13" @@ -4343,20 +3776,6 @@ 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 = "jubjub" version = "0.9.0" @@ -4384,7 +3803,7 @@ dependencies = [ "serdect", "sha2", "signature", - "zkm-lib", + "zkm-lib 2.0.0 (git+https://github.com/ProjectZKM/Ziren)", ] [[package]] @@ -4393,7 +3812,7 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" dependencies = [ - "cpufeatures", + "cpufeatures 0.2.17", ] [[package]] @@ -4414,41 +3833,11 @@ dependencies = [ "bls12_381 0.8.0", "ff 0.13.1", "hex", - "serde_arrays 0.2.0", + "serde_arrays", "sha2", "spin 0.9.8", ] -[[package]] -name = "lalrpop" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55cb077ad656299f160924eb2912aa147d7339ea7d69e1b5517326fdcec3c1ca" -dependencies = [ - "ascii-canvas", - "bit-set 0.5.3", - "ena", - "itertools 0.11.0", - "lalrpop-util", - "petgraph 0.6.5", - "regex", - "regex-syntax", - "string_cache", - "term", - "tiny-keccak", - "unicode-xid", - "walkdir", -] - -[[package]] -name = "lalrpop-util" -version = "0.20.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "507460a910eb7b32ee961886ff48539633b788a36b65692b95f225b844c82553" -dependencies = [ - "regex-automata", -] - [[package]] name = "lazy_static" version = "1.5.0" @@ -4494,11 +3883,10 @@ checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" [[package]] name = "libredox" -version = "0.1.10" +version = "0.1.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" +checksum = "61ff90caf6077a803a240f62fdbe88645a890bbca49ef8174c3cb0404362171d" dependencies = [ - "bitflags 2.10.0", "libc", ] @@ -4523,12 +3911,6 @@ dependencies = [ "serde", ] -[[package]] -name = "linux-raw-sys" -version = "0.4.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" - [[package]] name = "linux-raw-sys" version = "0.11.0" @@ -4635,20 +4017,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e7465ac9959cc2b1404e8e2367b43684a6d13790fe23056cc8c6c5a6b7bcb94" [[package]] -name = "md-5" -version = "0.10.6" +name = "memchr" +version = "2.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "memfd" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d89e7ee0cfbedfc4da3340218492196241d89eefb6dab27de5df917a6d2e78cf" +checksum = "57804b2c9b69967f1536a56f86297e367a33b19e98852ed624b84551cdbc0d90" dependencies = [ - "cfg-if", - "digest 0.10.7", + "rustix", ] [[package]] -name = "memchr" -version = "2.7.6" +name = "memmap2" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" +checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" +dependencies = [ + "libc", +] + +[[package]] +name = "memmap2" +version = "0.9.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1219ed1b7f229ee7104d281dd01d6802fe28bb6e95d292942c4daacdeb798c0" +dependencies = [ + "libc", +] [[package]] name = "memuse" @@ -4719,18 +4118,13 @@ dependencies = [ "alloy-rpc-types", "alloy-rpc-types-debug", "hex-literal", + "reth-primitives-traits", "reth-trie", "rlp", "serde", "thiserror 1.0.69", ] -[[package]] -name = "multimap" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ce46fe64a9d73be07dcbe690a38ce1b293be448fd8ce1e6c1b8062c9f72c6a" - [[package]] name = "multimap" version = "0.10.1" @@ -4754,12 +4148,6 @@ dependencies = [ "tempfile", ] -[[package]] -name = "new_debug_unreachable" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086" - [[package]] name = "nix" version = "0.30.1" @@ -4790,9 +4178,9 @@ dependencies = [ [[package]] name = "ntapi" -version = "0.4.1" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4" +checksum = "c3b335231dfd352ffb0f8017f3b6027a4917f7df785ea2143d8af2adc66980ae" dependencies = [ "winapi", ] @@ -4839,7 +4227,6 @@ checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ "num-integer", "num-traits", - "rand 0.8.5", ] [[package]] @@ -4960,18 +4347,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" -[[package]] -name = "nums" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf3c74f925fb8cfc49a8022f2afce48a0683b70f9e439885594e84c5edbf5b01" -dependencies = [ - "num-bigint 0.4.6", - "num-integer", - "num-traits", - "rand 0.8.5", -] - [[package]] name = "nybbles" version = "0.4.6" @@ -5106,31 +4481,6 @@ dependencies = [ "revm", ] -[[package]] -name = "open-fastrlp" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "786393f80485445794f6043fd3138854dd109cc6c4bd1a6383db304c9ce9b9ce" -dependencies = [ - "arrayvec", - "auto_impl", - "bytes", - "ethereum-types", - "open-fastrlp-derive", -] - -[[package]] -name = "open-fastrlp-derive" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "003b2be5c6c53c1cfeb0a238b8a1c3915cd410feb684457a36c10038f764bb1c" -dependencies = [ - "bytes", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "openssl" version = "0.10.75" @@ -5191,52 +4541,53 @@ dependencies = [ "hex", "primeorder", "sha2", - "zkm-lib", + "zkm-lib 2.0.0 (git+https://github.com/ProjectZKM/Ziren)", ] [[package]] name = "p3-air" -version = "0.1.0" -source = "git+https://github.com/ProjectZKM/Plonky3#faa24ca4597eebeecbf71b194b71c7d1a99b3f01" +version = "0.5.1" +source = "git+https://github.com/ProjectZKM/Plonky3?rev=4dd0d47a8176503fbaa7293c9f0e3b20004e16b2#4dd0d47a8176503fbaa7293c9f0e3b20004e16b2" dependencies = [ "p3-field", "p3-matrix", + "tracing", ] [[package]] -name = "p3-bn254-fr" -version = "0.1.0" -source = "git+https://github.com/ProjectZKM/Plonky3#faa24ca4597eebeecbf71b194b71c7d1a99b3f01" +name = "p3-bn254" +version = "0.5.1" +source = "git+https://github.com/ProjectZKM/Plonky3?rev=4dd0d47a8176503fbaa7293c9f0e3b20004e16b2#4dd0d47a8176503fbaa7293c9f0e3b20004e16b2" dependencies = [ - "ff 0.13.1", - "halo2curves", "num-bigint 0.4.6", "p3-field", "p3-poseidon2", "p3-symmetric", - "rand 0.8.5", + "p3-util", + "paste", + "rand 0.10.3", "serde", ] [[package]] name = "p3-challenger" -version = "0.1.0" -source = "git+https://github.com/ProjectZKM/Plonky3#faa24ca4597eebeecbf71b194b71c7d1a99b3f01" +version = "0.5.1" +source = "git+https://github.com/ProjectZKM/Plonky3?rev=4dd0d47a8176503fbaa7293c9f0e3b20004e16b2#4dd0d47a8176503fbaa7293c9f0e3b20004e16b2" dependencies = [ "p3-field", "p3-maybe-rayon", + "p3-monty-31", "p3-symmetric", "p3-util", - "serde", "tracing", ] [[package]] name = "p3-circle" -version = "0.1.0" -source = "git+https://github.com/ProjectZKM/Plonky3#faa24ca4597eebeecbf71b194b71c7d1a99b3f01" +version = "0.5.1" +source = "git+https://github.com/ProjectZKM/Plonky3?rev=4dd0d47a8176503fbaa7293c9f0e3b20004e16b2#4dd0d47a8176503fbaa7293c9f0e3b20004e16b2" dependencies = [ - "itertools 0.13.0", + "itertools 0.14.0", "p3-challenger", "p3-commit", "p3-dft", @@ -5246,59 +4597,61 @@ dependencies = [ "p3-maybe-rayon", "p3-util", "serde", + "thiserror 2.0.17", "tracing", ] [[package]] name = "p3-commit" -version = "0.1.0" -source = "git+https://github.com/ProjectZKM/Plonky3#faa24ca4597eebeecbf71b194b71c7d1a99b3f01" +version = "0.5.1" +source = "git+https://github.com/ProjectZKM/Plonky3?rev=4dd0d47a8176503fbaa7293c9f0e3b20004e16b2#4dd0d47a8176503fbaa7293c9f0e3b20004e16b2" dependencies = [ - "itertools 0.13.0", + "itertools 0.14.0", "p3-challenger", "p3-dft", "p3-field", + "p3-interpolation", "p3-matrix", + "p3-multilinear-util", "p3-util", "serde", ] [[package]] name = "p3-dft" -version = "0.1.0" -source = "git+https://github.com/ProjectZKM/Plonky3#faa24ca4597eebeecbf71b194b71c7d1a99b3f01" +version = "0.5.1" +source = "git+https://github.com/ProjectZKM/Plonky3?rev=4dd0d47a8176503fbaa7293c9f0e3b20004e16b2#4dd0d47a8176503fbaa7293c9f0e3b20004e16b2" dependencies = [ - "itertools 0.13.0", + "itertools 0.14.0", "p3-field", "p3-matrix", "p3-maybe-rayon", "p3-util", + "spin 0.10.1", "tracing", ] [[package]] name = "p3-field" -version = "0.1.0" -source = "git+https://github.com/ProjectZKM/Plonky3#faa24ca4597eebeecbf71b194b71c7d1a99b3f01" +version = "0.5.1" +source = "git+https://github.com/ProjectZKM/Plonky3?rev=4dd0d47a8176503fbaa7293c9f0e3b20004e16b2#4dd0d47a8176503fbaa7293c9f0e3b20004e16b2" dependencies = [ - "itertools 0.13.0", + "itertools 0.14.0", "num-bigint 0.4.6", - "num-integer", - "num-traits", - "nums", "p3-maybe-rayon", "p3-util", - "rand 0.8.5", + "paste", + "rand 0.10.3", "serde", "tracing", ] [[package]] name = "p3-fri" -version = "0.1.0" -source = "git+https://github.com/ProjectZKM/Plonky3#faa24ca4597eebeecbf71b194b71c7d1a99b3f01" +version = "0.5.1" +source = "git+https://github.com/ProjectZKM/Plonky3?rev=4dd0d47a8176503fbaa7293c9f0e3b20004e16b2#4dd0d47a8176503fbaa7293c9f0e3b20004e16b2" dependencies = [ - "itertools 0.13.0", + "itertools 0.14.0", "p3-challenger", "p3-commit", "p3-dft", @@ -5307,15 +4660,17 @@ dependencies = [ "p3-matrix", "p3-maybe-rayon", "p3-util", - "rand 0.8.5", + "rand 0.10.3", "serde", + "spin 0.10.1", + "thiserror 2.0.17", "tracing", ] [[package]] name = "p3-interpolation" -version = "0.1.0" -source = "git+https://github.com/ProjectZKM/Plonky3#faa24ca4597eebeecbf71b194b71c7d1a99b3f01" +version = "0.5.1" +source = "git+https://github.com/ProjectZKM/Plonky3?rev=4dd0d47a8176503fbaa7293c9f0e3b20004e16b2#4dd0d47a8176503fbaa7293c9f0e3b20004e16b2" dependencies = [ "p3-field", "p3-matrix", @@ -5325,11 +4680,9 @@ dependencies = [ [[package]] name = "p3-keccak" -version = "0.1.0" -source = "git+https://github.com/ProjectZKM/Plonky3#faa24ca4597eebeecbf71b194b71c7d1a99b3f01" +version = "0.5.1" +source = "git+https://github.com/ProjectZKM/Plonky3?rev=4dd0d47a8176503fbaa7293c9f0e3b20004e16b2#4dd0d47a8176503fbaa7293c9f0e3b20004e16b2" dependencies = [ - "itertools 0.13.0", - "p3-field", "p3-symmetric", "p3-util", "tiny-keccak", @@ -5337,174 +4690,202 @@ dependencies = [ [[package]] name = "p3-keccak-air" -version = "0.1.0" -source = "git+https://github.com/ProjectZKM/Plonky3#faa24ca4597eebeecbf71b194b71c7d1a99b3f01" +version = "0.5.1" +source = "git+https://github.com/ProjectZKM/Plonky3?rev=4dd0d47a8176503fbaa7293c9f0e3b20004e16b2#4dd0d47a8176503fbaa7293c9f0e3b20004e16b2" dependencies = [ "p3-air", "p3-field", "p3-matrix", "p3-maybe-rayon", "p3-util", + "rand 0.10.3", "tracing", ] [[package]] name = "p3-koala-bear" -version = "0.1.0" -source = "git+https://github.com/ProjectZKM/Plonky3#faa24ca4597eebeecbf71b194b71c7d1a99b3f01" +version = "0.5.1" +source = "git+https://github.com/ProjectZKM/Plonky3?rev=4dd0d47a8176503fbaa7293c9f0e3b20004e16b2#4dd0d47a8176503fbaa7293c9f0e3b20004e16b2" dependencies = [ + "p3-challenger", "p3-field", "p3-mds", "p3-monty-31", + "p3-poseidon1", "p3-poseidon2", "p3-symmetric", - "rand 0.8.5", - "serde", + "rand 0.10.3", ] [[package]] name = "p3-matrix" -version = "0.1.0" -source = "git+https://github.com/ProjectZKM/Plonky3#faa24ca4597eebeecbf71b194b71c7d1a99b3f01" +version = "0.5.1" +source = "git+https://github.com/ProjectZKM/Plonky3?rev=4dd0d47a8176503fbaa7293c9f0e3b20004e16b2#4dd0d47a8176503fbaa7293c9f0e3b20004e16b2" dependencies = [ - "itertools 0.13.0", + "itertools 0.14.0", "p3-field", "p3-maybe-rayon", "p3-util", - "rand 0.8.5", + "rand 0.10.3", "serde", "tracing", - "transpose", ] [[package]] name = "p3-maybe-rayon" -version = "0.1.0" -source = "git+https://github.com/ProjectZKM/Plonky3#faa24ca4597eebeecbf71b194b71c7d1a99b3f01" +version = "0.5.1" +source = "git+https://github.com/ProjectZKM/Plonky3?rev=4dd0d47a8176503fbaa7293c9f0e3b20004e16b2#4dd0d47a8176503fbaa7293c9f0e3b20004e16b2" dependencies = [ "rayon", ] [[package]] name = "p3-mds" -version = "0.1.0" -source = "git+https://github.com/ProjectZKM/Plonky3#faa24ca4597eebeecbf71b194b71c7d1a99b3f01" +version = "0.5.1" +source = "git+https://github.com/ProjectZKM/Plonky3?rev=4dd0d47a8176503fbaa7293c9f0e3b20004e16b2#4dd0d47a8176503fbaa7293c9f0e3b20004e16b2" dependencies = [ - "itertools 0.13.0", "p3-dft", "p3-field", - "p3-matrix", "p3-symmetric", "p3-util", - "rand 0.8.5", + "rand 0.10.3", ] [[package]] name = "p3-merkle-tree" -version = "0.1.0" -source = "git+https://github.com/ProjectZKM/Plonky3#faa24ca4597eebeecbf71b194b71c7d1a99b3f01" +version = "0.5.1" +source = "git+https://github.com/ProjectZKM/Plonky3?rev=4dd0d47a8176503fbaa7293c9f0e3b20004e16b2#4dd0d47a8176503fbaa7293c9f0e3b20004e16b2" dependencies = [ - "itertools 0.13.0", + "itertools 0.14.0", "p3-commit", "p3-field", "p3-matrix", "p3-maybe-rayon", "p3-symmetric", "p3-util", - "rand 0.8.5", + "rand 0.10.3", "serde", + "thiserror 2.0.17", "tracing", ] [[package]] name = "p3-mersenne-31" -version = "0.1.0" -source = "git+https://github.com/ProjectZKM/Plonky3#faa24ca4597eebeecbf71b194b71c7d1a99b3f01" +version = "0.5.1" +source = "git+https://github.com/ProjectZKM/Plonky3?rev=4dd0d47a8176503fbaa7293c9f0e3b20004e16b2#4dd0d47a8176503fbaa7293c9f0e3b20004e16b2" dependencies = [ - "itertools 0.13.0", + "itertools 0.14.0", "num-bigint 0.4.6", + "p3-challenger", "p3-dft", "p3-field", "p3-matrix", - "p3-maybe-rayon", "p3-mds", + "p3-poseidon1", "p3-poseidon2", "p3-symmetric", "p3-util", - "rand 0.8.5", + "paste", + "rand 0.10.3", "serde", ] [[package]] name = "p3-monty-31" -version = "0.1.0" -source = "git+https://github.com/ProjectZKM/Plonky3#faa24ca4597eebeecbf71b194b71c7d1a99b3f01" +version = "0.5.1" +source = "git+https://github.com/ProjectZKM/Plonky3?rev=4dd0d47a8176503fbaa7293c9f0e3b20004e16b2#4dd0d47a8176503fbaa7293c9f0e3b20004e16b2" dependencies = [ - "itertools 0.13.0", + "itertools 0.14.0", "num-bigint 0.4.6", "p3-dft", "p3-field", "p3-matrix", "p3-maybe-rayon", "p3-mds", + "p3-poseidon1", "p3-poseidon2", "p3-symmetric", "p3-util", - "rand 0.8.5", + "paste", + "rand 0.10.3", "serde", - "serde_json", + "spin 0.10.1", "tracing", - "transpose", +] + +[[package]] +name = "p3-multilinear-util" +version = "0.5.1" +source = "git+https://github.com/ProjectZKM/Plonky3?rev=4dd0d47a8176503fbaa7293c9f0e3b20004e16b2#4dd0d47a8176503fbaa7293c9f0e3b20004e16b2" +dependencies = [ + "itertools 0.14.0", + "p3-field", + "p3-matrix", + "p3-maybe-rayon", + "p3-util", + "rand 0.10.3", + "serde", + "tracing", +] + +[[package]] +name = "p3-poseidon1" +version = "0.5.1" +source = "git+https://github.com/ProjectZKM/Plonky3?rev=4dd0d47a8176503fbaa7293c9f0e3b20004e16b2#4dd0d47a8176503fbaa7293c9f0e3b20004e16b2" +dependencies = [ + "p3-field", + "p3-symmetric", + "rand 0.10.3", ] [[package]] name = "p3-poseidon2" -version = "0.1.0" -source = "git+https://github.com/ProjectZKM/Plonky3#faa24ca4597eebeecbf71b194b71c7d1a99b3f01" +version = "0.5.1" +source = "git+https://github.com/ProjectZKM/Plonky3?rev=4dd0d47a8176503fbaa7293c9f0e3b20004e16b2#4dd0d47a8176503fbaa7293c9f0e3b20004e16b2" dependencies = [ - "gcd", "p3-field", "p3-mds", "p3-symmetric", - "rand 0.8.5", - "serde", + "p3-util", + "rand 0.10.3", ] [[package]] name = "p3-symmetric" -version = "0.1.0" -source = "git+https://github.com/ProjectZKM/Plonky3#faa24ca4597eebeecbf71b194b71c7d1a99b3f01" +version = "0.5.1" +source = "git+https://github.com/ProjectZKM/Plonky3?rev=4dd0d47a8176503fbaa7293c9f0e3b20004e16b2#4dd0d47a8176503fbaa7293c9f0e3b20004e16b2" dependencies = [ - "itertools 0.13.0", + "itertools 0.14.0", "p3-field", + "p3-util", "serde", ] [[package]] name = "p3-uni-stark" -version = "0.1.0" -source = "git+https://github.com/ProjectZKM/Plonky3#faa24ca4597eebeecbf71b194b71c7d1a99b3f01" +version = "0.5.1" +source = "git+https://github.com/ProjectZKM/Plonky3?rev=4dd0d47a8176503fbaa7293c9f0e3b20004e16b2#4dd0d47a8176503fbaa7293c9f0e3b20004e16b2" dependencies = [ - "itertools 0.13.0", + "itertools 0.14.0", "p3-air", "p3-challenger", "p3-commit", - "p3-dft", "p3-field", "p3-matrix", "p3-maybe-rayon", "p3-util", "serde", + "thiserror 2.0.17", "tracing", ] [[package]] name = "p3-util" -version = "0.1.0" -source = "git+https://github.com/ProjectZKM/Plonky3#faa24ca4597eebeecbf71b194b71c7d1a99b3f01" +version = "0.5.1" +source = "git+https://github.com/ProjectZKM/Plonky3?rev=4dd0d47a8176503fbaa7293c9f0e3b20004e16b2#4dd0d47a8176503fbaa7293c9f0e3b20004e16b2" dependencies = [ - "lock_api", "serde", + "transpose", ] [[package]] @@ -5601,17 +4982,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "password-hash" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700" -dependencies = [ - "base64ct", - "rand_core 0.6.4", - "subtle", -] - [[package]] name = "pasta_curves" version = "0.4.1" @@ -5636,10 +5006,8 @@ dependencies = [ "blake2b_simd", "ff 0.13.1", "group 0.13.0", - "hex", "lazy_static", "rand 0.8.5", - "serde", "static_assertions", "subtle", ] @@ -5650,43 +5018,6 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" -[[package]] -name = "path-slash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e91099d4268b0e11973f036e885d652fb0b21fedcf69738c627f94db6a44f42" - -[[package]] -name = "pbkdf2" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" -dependencies = [ - "digest 0.10.7", - "hmac", - "password-hash", - "sha2", -] - -[[package]] -name = "pbkdf2" -version = "0.12.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ed6a7761f76e3b9f92dfb0a60a6a6477c61024b775147ff0973a02653abaf2" -dependencies = [ - "digest 0.10.7", - "hmac", -] - -[[package]] -name = "pem" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" -dependencies = [ - "base64 0.13.1", -] - [[package]] name = "pem-rfc7468" version = "0.7.0" @@ -5742,37 +5073,17 @@ dependencies = [ "rustc_version 0.4.1", ] -[[package]] -name = "phf" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" -dependencies = [ - "phf_macros 0.11.3", - "phf_shared 0.11.3", -] - [[package]] name = "phf" version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c1562dc717473dbaa4c1f85a36410e03c047b2e7df7f45ee938fbef64ae7fadf" dependencies = [ - "phf_macros 0.13.1", - "phf_shared 0.13.1", + "phf_macros", + "phf_shared", "serde", ] -[[package]] -name = "phf_generator" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c80231409c20246a13fddb31776fb942c38553c51e871f8cbd687a4cfb5843d" -dependencies = [ - "phf_shared 0.11.3", - "rand 0.8.5", -] - [[package]] name = "phf_generator" version = "0.13.1" @@ -5780,20 +5091,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "135ace3a761e564ec88c03a77317a7c6b80bb7f7135ef2544dbe054243b89737" dependencies = [ "fastrand", - "phf_shared 0.13.1", -] - -[[package]] -name = "phf_macros" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84ac04429c13a7ff43785d75ad27569f2951ce0ffd30a3321230db2fc727216" -dependencies = [ - "phf_generator 0.11.3", - "phf_shared 0.11.3", - "proc-macro2", - "quote", - "syn 2.0.111", + "phf_shared", ] [[package]] @@ -5802,22 +5100,13 @@ version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "812f032b54b1e759ccd5f8b6677695d5268c588701effba24601f6932f8269ef" dependencies = [ - "phf_generator 0.13.1", - "phf_shared 0.13.1", + "phf_generator", + "phf_shared", "proc-macro2", "quote", "syn 2.0.111", ] -[[package]] -name = "phf_shared" -version = "0.11.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67eabc2ef2a60eb7faa00097bd1ffdb5bd28e62bf39990626a582201b7a754e5" -dependencies = [ - "siphasher", -] - [[package]] name = "phf_shared" version = "0.13.1" @@ -5883,9 +5172,9 @@ checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" [[package]] name = "portable-atomic-util" -version = "0.2.4" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +checksum = "c2a106d1259c23fac8e543272398ae0e3c0b8d33c88ed73d0cc71b0f1d902618" dependencies = [ "portable-atomic", ] @@ -5914,22 +5203,6 @@ dependencies = [ "zerocopy", ] -[[package]] -name = "precomputed-hash" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" - -[[package]] -name = "prettyplease" -version = "0.1.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8646e95016a7a6c4adea95bafa8a16baab64b583356217f2c85db4a39d9a86" -dependencies = [ - "proc-macro2", - "syn 1.0.109", -] - [[package]] name = "prettyplease" version = "0.2.37" @@ -5956,9 +5229,6 @@ checksum = "0b34d9fd68ae0b74a41b21c03c2f62847aa0ffea044eee893b4c140b37e244e2" dependencies = [ "fixed-hash", "impl-codec", - "impl-rlp", - "impl-serde", - "scale-info", "uint", ] @@ -5985,7 +5255,31 @@ version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" dependencies = [ - "toml_edit 0.23.9", + "toml_edit", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", ] [[package]] @@ -6025,8 +5319,8 @@ version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bee689443a2bd0a16ab0348b52ee43e3b2d1b1f931c8aa5c9f8de4c86fbe8c40" dependencies = [ - "bit-set 0.8.0", - "bit-vec 0.8.0", + "bit-set", + "bit-vec", "bitflags 2.10.0", "num-traits", "rand 0.9.2", @@ -6040,12 +5334,12 @@ dependencies = [ [[package]] name = "prost" -version = "0.11.9" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b82eaa1d779e9a4bc1c3217db8ffbeabaae1dca241bf70183242128d48681cd" +checksum = "deb1435c188b76130da55f17a466d252ff7b1418b2ad3e037d127b94e3411f29" dependencies = [ "bytes", - "prost-derive 0.11.9", + "prost-derive 0.12.6", ] [[package]] @@ -6060,24 +5354,23 @@ dependencies = [ [[package]] name = "prost-build" -version = "0.11.9" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "119533552c9a7ffacc21e099c24a0ac8bb19c2a2a3f363de84cd9b844feab270" +checksum = "22505a5c94da8e3b7c2996394d1c933236c4d743e81a410bcca4e6989fc066a4" dependencies = [ "bytes", - "heck 0.4.1", - "itertools 0.10.5", - "lazy_static", + "heck", + "itertools 0.11.0", "log", - "multimap 0.8.3", + "multimap", + "once_cell", "petgraph 0.6.5", - "prettyplease 0.1.25", - "prost 0.11.9", - "prost-types 0.11.9", + "prettyplease", + "prost 0.12.6", + "prost-types 0.12.6", "regex", - "syn 1.0.109", + "syn 2.0.111", "tempfile", - "which", ] [[package]] @@ -6086,13 +5379,13 @@ version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be769465445e8c1474e9c5dac2018218498557af32d9ed057325ec9a41ae81bf" dependencies = [ - "heck 0.5.0", - "itertools 0.14.0", + "heck", + "itertools 0.10.5", "log", - "multimap 0.10.1", + "multimap", "once_cell", "petgraph 0.7.1", - "prettyplease 0.2.37", + "prettyplease", "prost 0.13.5", "prost-types 0.13.5", "regex", @@ -6102,15 +5395,15 @@ dependencies = [ [[package]] name = "prost-derive" -version = "0.11.9" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5d2d8d10f3c6ded6da8b05b5fb3b8a5082514344d56c9f871412d29b4e075b4" +checksum = "81bddcdb20abf9501610992b6759a4c888aef7d1a7247ef75e2404275ac24af1" dependencies = [ "anyhow", - "itertools 0.10.5", + "itertools 0.11.0", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.111", ] [[package]] @@ -6120,7 +5413,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a56d757972c98b346a9b766e3f02746cde6dd1cd1d1d563472929fdd74bec4d" dependencies = [ "anyhow", - "itertools 0.14.0", + "itertools 0.10.5", "proc-macro2", "quote", "syn 2.0.111", @@ -6128,11 +5421,11 @@ dependencies = [ [[package]] name = "prost-types" -version = "0.11.9" +version = "0.12.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213622a1460818959ac1181aaeb2dc9c7f63df720db7d788b3e24eacd1983e13" +checksum = "9091c90b0a32608e984ff2fa4091273cbdd755d54935c51d520887f4a1dbd5b0" dependencies = [ - "prost 0.11.9", + "prost 0.12.6", ] [[package]] @@ -6152,6 +5445,7 @@ dependencies = [ "alloy-provider", "alloy-rpc-client", "alloy-transport", + "reqwest 0.12.25", "url", ] @@ -6201,7 +5495,7 @@ dependencies = [ "getrandom 0.3.4", "lru-slab", "rand 0.9.2", - "ring 0.17.14", + "ring", "rustc-hash 2.1.1", "rustls 0.23.35", "rustls-pki-types", @@ -6270,6 +5564,15 @@ dependencies = [ "serde", ] +[[package]] +name = "rand" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65c9fb96cbc91e3478eaae79a69fcd3f1ae4ad052e471fe6732fff548984b4af" +dependencies = [ + "rand_core 0.10.1", +] + [[package]] name = "rand_chacha" version = "0.3.1" @@ -6309,6 +5612,12 @@ dependencies = [ "serde", ] +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + [[package]] name = "rand_xorshift" version = "0.4.0" @@ -6320,9 +5629,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" +checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d" dependencies = [ "either", "rayon-core", @@ -6455,7 +5764,7 @@ dependencies = [ "serde_json", "serde_urlencoded", "sync_wrapper 0.1.2", - "system-configuration 0.5.1", + "system-configuration", "tokio", "tokio-rustls 0.24.1", "tokio-util", @@ -7073,7 +6382,7 @@ name = "reth-zstd-compressors" version = "1.9.3" source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" dependencies = [ - "zstd 0.13.3", + "zstd", ] [[package]] @@ -7111,7 +6420,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2c6b5e6e8dd1e28a4a60e5f46615d4ef0809111c9e63208e55b5c7058200fb0" dependencies = [ "bitvec", - "phf 0.13.1", + "phf", "revm-primitives", "serde", ] @@ -7280,21 +6589,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "ring" -version = "0.16.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" -dependencies = [ - "cc", - "libc", - "once_cell", - "spin 0.5.2", - "untrusted 0.7.1", - "web-sys", - "winapi", -] - [[package]] name = "ring" version = "0.17.14" @@ -7305,7 +6599,7 @@ dependencies = [ "cfg-if", "getrandom 0.2.16", "libc", - "untrusted 0.9.0", + "untrusted", "windows-sys 0.52.0", ] @@ -7325,19 +6619,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb919243f34364b6bd2fc10ef797edbfa75f33c252e7998527479c6d6b47e1ec" dependencies = [ "bytes", - "rlp-derive", "rustc-hex", ] [[package]] -name = "rlp-derive" -version = "0.1.0" +name = "rmp" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e33d7b2abe0c340d8797fe2907d3f20d3b5ea5908683618bfe80df7f621f672a" +checksum = "4ba8be72d372b2c9b35542551678538b562e7cf86c3315773cae48dfbfe7790c" dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", + "num-traits", +] + +[[package]] +name = "rmp-serde" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72f81bee8c8ef9b577d1681a70ebbc962c232461e397b22c208c43c04b67a155" +dependencies = [ + "rmp", + "serde", ] [[package]] @@ -7345,9 +6646,12 @@ name = "rpc-db" version = "0.1.0" dependencies = [ "alloy-consensus", + "alloy-eips", "alloy-primitives", "alloy-provider", "alloy-rlp", + "alloy-rpc-types", + "alloy-rpc-types-debug", "alloy-transport", "alloy-trie", "async-trait", @@ -7358,6 +6662,8 @@ dependencies = [ "revm-database-interface", "revm-primitives", "revm-state", + "serde", + "serde_json", "thiserror 1.0.69", "tokio", "tracing", @@ -7439,19 +6745,6 @@ dependencies = [ "semver 1.0.27", ] -[[package]] -name = "rustix" -version = "0.38.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" -dependencies = [ - "bitflags 2.10.0", - "errno", - "libc", - "linux-raw-sys 0.4.15", - "windows-sys 0.59.0", -] - [[package]] name = "rustix" version = "1.1.2" @@ -7461,22 +6754,10 @@ dependencies = [ "bitflags 2.10.0", "errno", "libc", - "linux-raw-sys 0.11.0", + "linux-raw-sys", "windows-sys 0.61.2", ] -[[package]] -name = "rustls" -version = "0.20.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b80e3dec595989ea8510028f30c408a4630db12c9cbb8de34203b89d6577e99" -dependencies = [ - "log", - "ring 0.16.20", - "sct", - "webpki", -] - [[package]] name = "rustls" version = "0.21.12" @@ -7484,7 +6765,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ "log", - "ring 0.17.14", + "ring", "rustls-webpki 0.101.7", "sct", ] @@ -7496,7 +6777,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f" dependencies = [ "once_cell", - "ring 0.17.14", + "ring", "rustls-pki-types", "rustls-webpki 0.103.8", "subtle", @@ -7540,8 +6821,8 @@ version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ - "ring 0.17.14", - "untrusted 0.9.0", + "ring", + "untrusted", ] [[package]] @@ -7550,9 +6831,9 @@ version = "0.103.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" dependencies = [ - "ring 0.17.14", + "ring", "rustls-pki-types", - "untrusted 0.9.0", + "untrusted", ] [[package]] @@ -7579,24 +6860,6 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" -[[package]] -name = "salsa20" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97a22f5af31f73a954c10289c93e8a50cc23d971e80ee446f1f6f7137a088213" -dependencies = [ - "cipher", -] - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - [[package]] name = "scale-info" version = "2.11.6" @@ -7660,26 +6923,14 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" -[[package]] -name = "scrypt" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f9e24d2b632954ded8ab2ef9fea0a0c769ea56ea98bddbafbad22caeeadf45d" -dependencies = [ - "hmac", - "pbkdf2 0.11.0", - "salsa20", - "sha2", -] - [[package]] name = "sct" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ - "ring 0.17.14", - "untrusted 0.9.0", + "ring", + "untrusted", ] [[package]] @@ -7769,12 +7020,6 @@ dependencies = [ "pest", ] -[[package]] -name = "send_wrapper" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f638d531eccd6e23b980caf34876660d38e265409d8e99b397ab71eb3612fad0" - [[package]] name = "send_wrapper" version = "0.6.0" @@ -7791,15 +7036,6 @@ dependencies = [ "serde_derive", ] -[[package]] -name = "serde_arrays" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38636132857f68ec3d5f3eb121166d2af33cb55174c4d5ff645db6165cbef0fd" -dependencies = [ - "serde", -] - [[package]] name = "serde_arrays" version = "0.2.0" @@ -7853,15 +7089,6 @@ dependencies = [ "serde_core", ] -[[package]] -name = "serde_spanned" -version = "0.6.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" -dependencies = [ - "serde", -] - [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -7934,7 +7161,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "digest 0.10.7", ] @@ -7944,7 +7171,7 @@ version = "0.10.9" source = "git+https://github.com/ziren-patches/RustCrypto-hashes?branch=patch-sha2-0.10.9#dbfdbd088ac7b55e03c0b9eb192278efe35d67dc" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "digest 0.10.7", ] @@ -8008,18 +7235,6 @@ version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" -[[package]] -name = "simple_asn1" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "297f631f50729c8c99b84667867963997ec0b50f32b2a7dbcab828ef0541e8bb" -dependencies = [ - "num-bigint 0.4.6", - "num-traits", - "thiserror 2.0.17", - "time", -] - [[package]] name = "siphasher" version = "1.0.1" @@ -8077,31 +7292,20 @@ dependencies = [ "windows-sys 0.60.2", ] -[[package]] -name = "solang-parser" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c425ce1c59f4b154717592f0bdf4715c3a1d55058883622d3157e1f0908a5b26" -dependencies = [ - "itertools 0.11.0", - "lalrpop", - "lalrpop-util", - "phf 0.11.3", - "thiserror 1.0.69", - "unicode-xid", -] - [[package]] name = "spin" -version = "0.5.2" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" [[package]] name = "spin" -version = "0.9.8" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +checksum = "023a211cb3138dbc438680b32560ad89f699977624c9f8dbb95a47d5b4c07dd3" +dependencies = [ + "lock_api", +] [[package]] name = "spki" @@ -8131,18 +7335,6 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fe895eb47f22e2ddd4dabc02bce419d2e643c8e3b585c78158b349195bc24d82" -[[package]] -name = "string_cache" -version = "0.8.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf776ba3fa74f83bf4b63c3dcbbf82173db2632ed8452cb2d891d33f459de70f" -dependencies = [ - "new_debug_unreachable", - "parking_lot 0.12.5", - "phf_shared 0.11.3", - "precomputed-hash", -] - [[package]] name = "strsim" version = "0.10.0" @@ -8179,7 +7371,7 @@ version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro2", "quote", "rustversion", @@ -8192,7 +7384,7 @@ version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7695ce3845ea4b33927c055a39dc438a45b059f7c1b3d91d38d10355fb8cbca7" dependencies = [ - "heck 0.5.0", + "heck", "proc-macro2", "quote", "syn 2.0.111", @@ -8211,7 +7403,7 @@ dependencies = [ "num-bigint 0.4.6", "rand 0.8.5", "rustc-hex", - "zkm-lib", + "zkm-lib 2.0.0 (git+https://github.com/ProjectZKM/Ziren)", ] [[package]] @@ -8220,26 +7412,6 @@ version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" -[[package]] -name = "svm-rs" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11297baafe5fa0c99d5722458eac6a5e25c01eb1b8e5cd137f54079093daa7a4" -dependencies = [ - "dirs", - "fs2", - "hex", - "once_cell", - "reqwest 0.11.27", - "semver 1.0.27", - "serde", - "serde_json", - "sha2", - "thiserror 1.0.69", - "url", - "zip", -] - [[package]] name = "syn" version = "1.0.109" @@ -8323,18 +7495,7 @@ checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" dependencies = [ "bitflags 1.3.2", "core-foundation", - "system-configuration-sys 0.5.0", -] - -[[package]] -name = "system-configuration" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" -dependencies = [ - "bitflags 2.10.0", - "core-foundation", - "system-configuration-sys 0.6.0", + "system-configuration-sys", ] [[package]] @@ -8347,22 +7508,23 @@ dependencies = [ "libc", ] -[[package]] -name = "system-configuration-sys" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e1d1b10ced5ca923a1fcb8d03e96b8d3268065d724548c0211415ff6ac6bac4" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "tap" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" +[[package]] +name = "tar" +version = "0.4.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6221d9a6003c78398e3b239969f352578258df48c8eb051caadae0015bc840" +dependencies = [ + "filetime", + "libc", + "xattr", +] + [[package]] name = "tempfile" version = "3.23.0" @@ -8372,21 +7534,10 @@ dependencies = [ "fastrand", "getrandom 0.3.4", "once_cell", - "rustix 1.1.2", + "rustix", "windows-sys 0.61.2", ] -[[package]] -name = "term" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" -dependencies = [ - "dirs-next", - "rustversion", - "winapi", -] - [[package]] name = "thiserror" version = "1.0.69" @@ -8566,17 +7717,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-rustls" -version = "0.23.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" -dependencies = [ - "rustls 0.20.9", - "tokio", - "webpki", -] - [[package]] name = "tokio-rustls" version = "0.24.1" @@ -8609,21 +7749,6 @@ dependencies = [ "tokio-util", ] -[[package]] -name = "tokio-tungstenite" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" -dependencies = [ - "futures-util", - "log", - "rustls 0.21.12", - "tokio", - "tokio-rustls 0.24.1", - "tungstenite 0.20.1", - "webpki-roots 0.25.4", -] - [[package]] name = "tokio-tungstenite" version = "0.26.2" @@ -8636,7 +7761,7 @@ dependencies = [ "rustls-pki-types", "tokio", "tokio-rustls 0.26.4", - "tungstenite 0.26.2", + "tungstenite", "webpki-roots 0.26.11", ] @@ -8653,27 +7778,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "toml" -version = "0.8.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" -dependencies = [ - "serde", - "serde_spanned", - "toml_datetime 0.6.11", - "toml_edit 0.22.27", -] - -[[package]] -name = "toml_datetime" -version = "0.6.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" -dependencies = [ - "serde", -] - [[package]] name = "toml_datetime" version = "0.7.3" @@ -8683,20 +7787,6 @@ dependencies = [ "serde_core", ] -[[package]] -name = "toml_edit" -version = "0.22.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" -dependencies = [ - "indexmap 2.12.1", - "serde", - "serde_spanned", - "toml_datetime 0.6.11", - "toml_write", - "winnow", -] - [[package]] name = "toml_edit" version = "0.23.9" @@ -8704,7 +7794,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d7cbc3b4b49633d57a0509303158ca50de80ae32c265093b24c414705807832" dependencies = [ "indexmap 2.12.1", - "toml_datetime 0.7.3", + "toml_datetime", "toml_parser", "winnow", ] @@ -8718,25 +7808,17 @@ dependencies = [ "winnow", ] -[[package]] -name = "toml_write" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" - [[package]] name = "tonic" -version = "0.8.3" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f219fad3b929bef19b1f86fbc0358d35daed8f2cac972037ac0dc10bbb8d5fb" +checksum = "d560933a0de61cf715926b9cac824d4c883c2c43142f787595e48280c40a1d0e" dependencies = [ "async-stream", "async-trait", "axum 0.6.20", - "base64 0.13.1", + "base64 0.21.7", "bytes", - "futures-core", - "futures-util", "h2 0.3.27", "http 0.2.12", "http-body 0.4.6", @@ -8744,32 +7826,30 @@ dependencies = [ "hyper-timeout", "percent-encoding", "pin-project", - "prost 0.11.9", - "prost-derive 0.11.9", + "prost 0.12.6", + "rustls 0.21.12", "rustls-native-certs", "rustls-pemfile", "tokio", - "tokio-rustls 0.23.4", + "tokio-rustls 0.24.1", "tokio-stream", - "tokio-util", "tower 0.4.13", "tower-layer", "tower-service", "tracing", - "tracing-futures", ] [[package]] name = "tonic-build" -version = "0.8.4" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bf5e9b9c0f7e0a7c027dcfaba7b2c60816c7049171f679d99ee2ff65d0de8c4" +checksum = "9d021fc044c18582b9a2408cd0dd05b1596e3ecdb5c4df822bb0183545683889" dependencies = [ - "prettyplease 0.1.25", + "prettyplease", "proc-macro2", - "prost-build 0.11.9", + "prost-build 0.12.6", "quote", - "syn 1.0.109", + "syn 2.0.111", ] [[package]] @@ -8814,13 +7894,18 @@ version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" dependencies = [ + "async-compression", "bitflags 2.10.0", "bytes", + "futures-core", "futures-util", "http 1.4.0", "http-body 1.0.1", + "http-body-util", "iri-string", "pin-project-lite", + "tokio", + "tokio-util", "tower 0.5.2", "tower-layer", "tower-service", @@ -8840,9 +7925,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.43" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d15d90a0b5c19378952d479dc858407149d7bb45a14de0142f6c534b16fc647" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ "log", "pin-project-lite", @@ -8863,9 +7948,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.35" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a04e24fab5c89c6a36eb8558c9656f30d81de51dfa4d3b45f26b21d61fa0a6c" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ "once_cell", "valuable", @@ -8884,16 +7969,6 @@ dependencies = [ "tracing-subscriber", ] -[[package]] -name = "tracing-futures" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" -dependencies = [ - "pin-project", - "tracing", -] - [[package]] name = "tracing-log" version = "0.2.0" @@ -8939,26 +8014,6 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" -[[package]] -name = "tungstenite" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" -dependencies = [ - "byteorder", - "bytes", - "data-encoding", - "http 0.2.12", - "httparse", - "log", - "rand 0.8.5", - "rustls 0.21.12", - "sha1", - "thiserror 1.0.69", - "url", - "utf-8", -] - [[package]] name = "tungstenite" version = "0.26.2" @@ -9063,22 +8118,6 @@ version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" -[[package]] -name = "unroll" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ad948c1cb799b1a70f836077721a92a35ac177d4daddf4c20a633786d4cf618" -dependencies = [ - "quote", - "syn 1.0.109", -] - -[[package]] -name = "untrusted" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" - [[package]] name = "untrusted" version = "0.9.0" @@ -9115,16 +8154,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" -[[package]] -name = "uuid" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" -dependencies = [ - "getrandom 0.2.16", - "serde", -] - [[package]] name = "uuid" version = "1.19.0" @@ -9198,16 +8227,6 @@ dependencies = [ "libc", ] -[[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] - [[package]] name = "want" version = "0.3.1" @@ -9352,16 +8371,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "webpki" -version = "0.22.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed63aea5ce73d0ff405984102c42de94fc55a6b75765d621c65262469b3c9b53" -dependencies = [ - "ring 0.17.14", - "untrusted 0.9.0", -] - [[package]] name = "webpki-roots" version = "0.25.4" @@ -9386,18 +8395,6 @@ dependencies = [ "rustls-pki-types", ] -[[package]] -name = "which" -version = "4.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87ba24419a2078cd2b0f2ede2691b6c66d8e47836da3b6db8265ebad47afbfc7" -dependencies = [ - "either", - "home", - "once_cell", - "rustix 0.38.44", -] - [[package]] name = "widestring" version = "1.2.1" @@ -9420,15 +8417,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -[[package]] -name = "winapi-util" -version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" -dependencies = [ - "windows-sys 0.61.2", -] - [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -9810,7 +8798,7 @@ dependencies = [ "log", "pharos", "rustc_version 0.4.1", - "send_wrapper 0.6.0", + "send_wrapper", "thiserror 2.0.17", "wasm-bindgen", "wasm-bindgen-futures", @@ -9826,6 +8814,16 @@ dependencies = [ "tap", ] +[[package]] +name = "xattr" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" +dependencies = [ + "libc", + "rustix", +] + [[package]] name = "yaml-rust" version = "0.4.5" @@ -9835,12 +8833,6 @@ dependencies = [ "linked-hash-map", ] -[[package]] -name = "yansi" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" - [[package]] name = "yoke" version = "0.8.1" @@ -9964,18 +8956,10 @@ version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "760394e246e4c28189f19d488c058bf16f564016aefac5d32bb1f3b51d5e9261" dependencies = [ - "aes", "byteorder", - "bzip2", - "constant_time_eq 0.1.5", "crc32fast", "crossbeam-utils", "flate2", - "hmac", - "pbkdf2 0.11.0", - "sha1", - "time", - "zstd 0.11.2+zstd.1.5.2", ] [[package]] @@ -10007,8 +8991,8 @@ dependencies = [ [[package]] name = "zkm-build" -version = "1.2.5" -source = "git+https://github.com/ProjectZKM/Ziren#c736a41cccd623427295f89b53306673adc89966" +version = "2.0.0" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ "anyhow", "cargo_metadata", @@ -10018,8 +9002,8 @@ dependencies = [ [[package]] name = "zkm-core-executor" -version = "1.2.5" -source = "git+https://github.com/ProjectZKM/Ziren#c736a41cccd623427295f89b53306673adc89966" +version = "2.0.0" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ "anyhow", "bincode", @@ -10031,6 +9015,7 @@ dependencies = [ "hashbrown 0.14.5", "hex", "itertools 0.13.0", + "libc", "log", "nohash-hasher", "num", @@ -10041,6 +9026,7 @@ dependencies = [ "p3-symmetric", "rand 0.8.5", "rayon-scan", + "rustc-hash 2.1.1", "serde", "serde_json", "sha2", @@ -10052,15 +9038,33 @@ dependencies = [ "tracing-subscriber", "typenum", "vec_map", + "zkm-core-jit", "zkm-curves", - "zkm-primitives", - "zkm-stark", + "zkm-pcs", + "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", +] + +[[package]] +name = "zkm-core-jit" +version = "2.0.0" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" +dependencies = [ + "dynasmrt", + "hashbrown 0.14.5", + "libc", + "memfd", + "memmap2 0.9.11", + "p3-field", + "p3-koala-bear", + "serde", + "thiserror 1.0.69", + "tracing", ] [[package]] name = "zkm-core-machine" -version = "1.2.5" -source = "git+https://github.com/ProjectZKM/Ziren#c736a41cccd623427295f89b53306673adc89966" +version = "2.0.0" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ "bincode", "cfg-if", @@ -10105,14 +9109,14 @@ dependencies = [ "zkm-core-executor", "zkm-curves", "zkm-derive", - "zkm-primitives", - "zkm-stark", + "zkm-pcs", + "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", ] [[package]] name = "zkm-cuda" -version = "1.2.5" -source = "git+https://github.com/ProjectZKM/Ziren#c736a41cccd623427295f89b53306673adc89966" +version = "2.0.0" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ "bincode", "ctrlc", @@ -10129,8 +9133,8 @@ dependencies = [ [[package]] name = "zkm-curves" -version = "1.2.5" -source = "git+https://github.com/ProjectZKM/Ziren#c736a41cccd623427295f89b53306673adc89966" +version = "2.0.0" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ "cfg-if", "curve25519-dalek", @@ -10147,14 +9151,14 @@ dependencies = [ "thiserror 1.0.69", "tracing", "typenum", - "zkm-primitives", - "zkm-stark", + "zkm-poly", + "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", ] [[package]] name = "zkm-derive" -version = "1.2.5" -source = "git+https://github.com/ProjectZKM/Ziren#c736a41cccd623427295f89b53306673adc89966" +version = "2.0.0" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ "proc-macro2", "quote", @@ -10163,23 +9167,111 @@ dependencies = [ [[package]] name = "zkm-lib" -version = "1.2.5" -source = "git+https://github.com/ProjectZKM/Ziren#c736a41cccd623427295f89b53306673adc89966" +version = "2.0.0" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" +dependencies = [ + "bincode", + "cfg-if", + "elliptic-curve", + "serde", + "sha2", + "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", +] + +[[package]] +name = "zkm-lib" +version = "2.0.0" +source = "git+https://github.com/ProjectZKM/Ziren#0dd65a15db3d7bad5cf582c5dbc7492440ea2830" dependencies = [ "bincode", "cfg-if", "elliptic-curve", "serde", "sha2", - "zkm-primitives", + "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren)", +] + +[[package]] +name = "zkm-pcs" +version = "2.0.0" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" +dependencies = [ + "arrayref", + "bincode", + "hashbrown 0.14.5", + "itertools 0.13.0", + "num-bigint 0.4.6", + "num-traits", + "p3-air", + "p3-challenger", + "p3-circle", + "p3-commit", + "p3-dft", + "p3-field", + "p3-fri", + "p3-keccak", + "p3-koala-bear", + "p3-matrix", + "p3-maybe-rayon", + "p3-merkle-tree", + "p3-mersenne-31", + "p3-poseidon2", + "p3-symmetric", + "p3-uni-stark", + "p3-util", + "rand 0.8.5", + "rayon", + "rayon-scan", + "rmp-serde", + "serde", + "strum 0.26.3", + "strum_macros 0.26.4", + "sysinfo", + "tracing", + "tracing-forest", + "tracing-subscriber", + "zkm-derive", + "zkm-poly", + "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", + "zkm-zkvm 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", +] + +[[package]] +name = "zkm-poly" +version = "2.0.0" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" +dependencies = [ + "itertools 0.13.0", + "p3-field", +] + +[[package]] +name = "zkm-primitives" +version = "2.0.0" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" +dependencies = [ + "bincode", + "blake3", + "hex", + "lazy_static", + "num-bigint 0.4.6", + "p3-field", + "p3-koala-bear", + "p3-monty-31", + "p3-poseidon2", + "p3-symmetric", + "serde", + "sha2", + "tracing", ] [[package]] name = "zkm-primitives" -version = "1.2.5" -source = "git+https://github.com/ProjectZKM/Ziren#c736a41cccd623427295f89b53306673adc89966" +version = "2.0.0" +source = "git+https://github.com/ProjectZKM/Ziren#0dd65a15db3d7bad5cf582c5dbc7492440ea2830" dependencies = [ "bincode", + "blake3", "hex", "lazy_static", "num-bigint 0.4.6", @@ -10190,28 +9282,32 @@ dependencies = [ "p3-symmetric", "serde", "sha2", + "tracing", ] [[package]] name = "zkm-prover" -version = "1.2.5" -source = "git+https://github.com/ProjectZKM/Ziren#c736a41cccd623427295f89b53306673adc89966" +version = "2.0.0" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ "anyhow", "bincode", "clap", "dirs", "eyre", + "hex", "itertools 0.13.0", "lru 0.12.5", "num-bigint 0.4.6", - "p3-bn254-fr", + "p3-air", + "p3-bn254", "p3-challenger", "p3-commit", "p3-field", "p3-koala-bear", "p3-matrix", "p3-symmetric", + "p3-uni-stark", "p3-util", "rayon", "serde", @@ -10221,24 +9317,24 @@ dependencies = [ "tracing-subscriber", "zkm-core-executor", "zkm-core-machine", - "zkm-primitives", + "zkm-pcs", + "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", "zkm-recursion-circuit", "zkm-recursion-compiler", "zkm-recursion-core", "zkm-recursion-gnark-ffi", - "zkm-stark", ] [[package]] name = "zkm-recursion-circuit" -version = "1.2.5" -source = "git+https://github.com/ProjectZKM/Ziren#c736a41cccd623427295f89b53306673adc89966" +version = "2.0.0" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ "hashbrown 0.14.5", "itertools 0.13.0", "num-traits", "p3-air", - "p3-bn254-fr", + "p3-bn254", "p3-challenger", "p3-commit", "p3-dft", @@ -10255,21 +9351,21 @@ dependencies = [ "zkm-core-executor", "zkm-core-machine", "zkm-derive", - "zkm-primitives", + "zkm-pcs", + "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", "zkm-recursion-compiler", "zkm-recursion-core", "zkm-recursion-gnark-ffi", - "zkm-stark", ] [[package]] name = "zkm-recursion-compiler" -version = "1.2.5" -source = "git+https://github.com/ProjectZKM/Ziren#c736a41cccd623427295f89b53306673adc89966" +version = "2.0.0" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ "backtrace", "itertools 0.13.0", - "p3-bn254-fr", + "p3-bn254", "p3-field", "p3-koala-bear", "p3-symmetric", @@ -10277,23 +9373,24 @@ dependencies = [ "tracing", "vec_map", "zkm-core-machine", - "zkm-primitives", + "zkm-pcs", + "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", "zkm-recursion-core", "zkm-recursion-derive", - "zkm-stark", ] [[package]] name = "zkm-recursion-core" -version = "1.2.5" -source = "git+https://github.com/ProjectZKM/Ziren#c736a41cccd623427295f89b53306673adc89966" +version = "2.0.0" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ "backtrace", + "bincode", "ff 0.13.1", "hashbrown 0.14.5", "itertools 0.13.0", "p3-air", - "p3-bn254-fr", + "p3-bn254", "p3-challenger", "p3-commit", "p3-dft", @@ -10309,6 +9406,7 @@ dependencies = [ "p3-util", "rand 0.8.5", "serde", + "sha2", "static_assertions", "thiserror 1.0.69", "tracing", @@ -10316,14 +9414,14 @@ dependencies = [ "zkhash", "zkm-core-machine", "zkm-derive", - "zkm-primitives", - "zkm-stark", + "zkm-pcs", + "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", ] [[package]] name = "zkm-recursion-derive" -version = "1.2.5" -source = "git+https://github.com/ProjectZKM/Ziren#c736a41cccd623427295f89b53306673adc89966" +version = "2.0.0" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ "quote", "syn 1.0.109", @@ -10331,8 +9429,8 @@ dependencies = [ [[package]] name = "zkm-recursion-gnark-ffi" -version = "1.2.5" -source = "git+https://github.com/ProjectZKM/Ziren#c736a41cccd623427295f89b53306673adc89966" +version = "2.0.0" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ "anyhow", "bincode", @@ -10349,23 +9447,22 @@ dependencies = [ "sha2", "tempfile", "zkm-core-machine", + "zkm-pcs", "zkm-recursion-compiler", - "zkm-stark", ] [[package]] name = "zkm-sdk" -version = "1.2.5" -source = "git+https://github.com/ProjectZKM/Ziren#c736a41cccd623427295f89b53306673adc89966" +version = "2.0.0" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ "alloy-primitives", - "alloy-signer", "anyhow", "async-trait", "bincode", "cfg-if", "dirs", - "ethers", + "flate2", "futures", "hashbrown 0.14.5", "hex", @@ -10376,12 +9473,13 @@ dependencies = [ "p3-field", "p3-fri", "p3-koala-bear", - "prost 0.11.9", + "prost 0.12.6", "reqwest 0.11.27", "serde", "serde_json", "strum 0.26.3", "strum_macros 0.26.4", + "tar", "tempfile", "thiserror 1.0.69", "tokio", @@ -10389,63 +9487,37 @@ dependencies = [ "tonic-build", "tracing", "twirp-rs", - "uuid 1.19.0", + "uuid", "vergen", "zkm-build", "zkm-core-executor", "zkm-core-machine", "zkm-cuda", - "zkm-primitives", + "zkm-pcs", + "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", "zkm-prover", - "zkm-stark", ] [[package]] -name = "zkm-stark" -version = "1.2.5" -source = "git+https://github.com/ProjectZKM/Ziren#c736a41cccd623427295f89b53306673adc89966" +name = "zkm-zkvm" +version = "2.0.0" +source = "git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm#8a9ab4fed7d83e1acfd08d40ceacd12ddf8a00c0" dependencies = [ - "arrayref", - "hashbrown 0.14.5", - "itertools 0.13.0", - "num-bigint 0.4.6", - "num-traits", - "p3-air", - "p3-challenger", - "p3-circle", - "p3-commit", - "p3-dft", - "p3-field", - "p3-fri", - "p3-keccak", - "p3-koala-bear", - "p3-matrix", - "p3-maybe-rayon", - "p3-mds", - "p3-merkle-tree", - "p3-mersenne-31", - "p3-poseidon2", - "p3-symmetric", - "p3-uni-stark", - "p3-util", + "bincode", + "cfg-if", + "getrandom 0.2.16", + "lazy_static", "rand 0.8.5", - "rayon-scan", "serde", - "strum 0.26.3", - "strum_macros 0.26.4", - "sysinfo", - "tracing", - "tracing-forest", - "tracing-subscriber", - "zkm-derive", - "zkm-primitives", - "zkm-zkvm", + "sha2", + "zkm-lib 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", + "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren?branch=perf%2Fshamir-msm)", ] [[package]] name = "zkm-zkvm" -version = "1.2.5" -source = "git+https://github.com/ProjectZKM/Ziren#c736a41cccd623427295f89b53306673adc89966" +version = "2.0.0" +source = "git+https://github.com/ProjectZKM/Ziren#0dd65a15db3d7bad5cf582c5dbc7492440ea2830" dependencies = [ "bincode", "cfg-if", @@ -10455,17 +9527,8 @@ dependencies = [ "rand 0.8.5", "serde", "sha2", - "zkm-lib", - "zkm-primitives", -] - -[[package]] -name = "zstd" -version = "0.11.2+zstd.1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" -dependencies = [ - "zstd-safe 5.0.2+zstd.1.5.2", + "zkm-lib 2.0.0 (git+https://github.com/ProjectZKM/Ziren)", + "zkm-primitives 2.0.0 (git+https://github.com/ProjectZKM/Ziren)", ] [[package]] @@ -10474,17 +9537,7 @@ version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" dependencies = [ - "zstd-safe 7.2.4", -] - -[[package]] -name = "zstd-safe" -version = "5.0.2+zstd.1.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" -dependencies = [ - "libc", - "zstd-sys", + "zstd-safe", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 1f7fb48..85a1fdb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,10 +47,11 @@ primitives = { path = "./crates/primitives" } provider = { path = "./crates/provider" } # Ziren -zkm-build = { git = "https://github.com/ProjectZKM/Ziren" } -zkm-core-executor = { git = "https://github.com/ProjectZKM/Ziren" } -zkm-prover = { git = "https://github.com/ProjectZKM/Ziren" } -zkm-sdk = { git = "https://github.com/ProjectZKM/Ziren" } +zkm-build = { git = "https://github.com/ProjectZKM/Ziren", branch = "perf/shamir-msm" } +zkm-core-executor = { git = "https://github.com/ProjectZKM/Ziren", branch = "perf/shamir-msm" } +zkm-prover = { git = "https://github.com/ProjectZKM/Ziren", branch = "perf/shamir-msm" } +zkm-cuda = { git = "https://github.com/ProjectZKM/Ziren", branch = "perf/shamir-msm" } +zkm-sdk = { git = "https://github.com/ProjectZKM/Ziren", branch = "perf/shamir-msm" } # reth reth-primitives-traits = { git = "https://github.com/paradigmxyz/reth", tag = "v1.9.3", default-features = false } diff --git a/bin/eth-proofs/Cargo.toml b/bin/eth-proofs/Cargo.toml index bd8a843..99b5c92 100644 --- a/bin/eth-proofs/Cargo.toml +++ b/bin/eth-proofs/Cargo.toml @@ -4,7 +4,7 @@ name = "eth-proofs" edition = "2021" [dependencies] -tokio.workspace = true +tokio = { workspace = true, features = ["signal"] } url.workspace = true tracing.workspace = true serde_json.workspace = true @@ -13,6 +13,11 @@ tracing-subscriber = "0.3.18" dotenv = "0.15.0" clap = { version = "4.5.7", features = ["derive", "env"] } eyre = "0.6.12" +bincode = "1.3.3" +sha2 = "0.10.8" +hex = "0.4.3" +fs2 = "0.4.3" +libc = "0.2" reqwest = { workspace = true, features = ["json"] } reqwest-middleware = { version = "0.3.3", features = ["json"] } reqwest-retry = "0.6.1" @@ -28,6 +33,8 @@ provider.workspace = true # Ziren zkm-sdk.workspace = true +zkm-cuda.workspace = true +zkm-prover.workspace = true # alloy alloy-chains.workspace = true @@ -41,3 +48,6 @@ zkm-build.workspace = true [features] test = [] + +[dev-dependencies] +tempfile = "3" diff --git a/bin/eth-proofs/build.rs b/bin/eth-proofs/build.rs index dcfa0c5..5029151 100644 --- a/bin/eth-proofs/build.rs +++ b/bin/eth-proofs/build.rs @@ -1,5 +1,12 @@ -use zkm_build::build_program; +use zkm_build::{build_program_with_args, BuildArgs}; fn main() { - build_program("../guest"); + println!("cargo:rerun-if-env-changed=ETH_PROOFS_BUILD_ELF"); + if let Ok(path) = std::env::var("ETH_PROOFS_BUILD_ELF") { + let path = std::fs::canonicalize(path).expect("ETH_PROOFS_BUILD_ELF must exist"); + println!("cargo:rerun-if-changed={}", path.display()); + println!("cargo:rustc-env=ZKM_ELF_reth={}", path.display()); + } else { + build_program_with_args("../guest", BuildArgs { locked: true, ..Default::default() }); + } } diff --git a/bin/eth-proofs/src/cli.rs b/bin/eth-proofs/src/cli.rs index 03ef128..ad71299 100644 --- a/bin/eth-proofs/src/cli.rs +++ b/bin/eth-proofs/src/cli.rs @@ -14,7 +14,7 @@ pub struct Args { /// The WS rpc url used to fetch data about the block. #[clap(long, env)] - pub ws_rpc_url: Url, + pub ws_rpc_url: Option, /// The debug HTTP rpc url used to fetch data about the block trace. #[clap(long, env)] @@ -28,6 +28,29 @@ pub struct Args { #[clap(long, default_value_t = 100)] pub block_interval: u64, + /// Which residue class of `block_interval` this instance proves: blocks + /// with `number % block_interval == block_residue`. Two instances with + /// `--block-interval 2` and residues 0 and 1 split the chain between two + /// provers and prove two blocks at a time. + #[clap(long, default_value_t = 0)] + pub block_residue: u64, + + /// How many prepared blocks (fetched + natively executed) may wait for the + /// prover. The fetch of block N+1 always overlaps the proof of block N; + /// this bounds how far ahead the fetcher runs. + #[clap(long, default_value_t = 1)] + pub prefetch_depth: usize, + + /// Skip a block when it is more than this many blocks behind the newest + /// header seen (0 = never skip: prove every block the stream delivers). + #[clap(long, default_value_t = 0)] + pub max_lag: u64, + + /// In local mode, select the latest eligible head before each preparation. + /// Prepare ahead of proving; retain only the newest completed witness. + #[clap(long)] + pub latest_block: bool, + /// ETH proofs endpoint. #[clap(long, env)] pub eth_proofs_endpoint: String, @@ -44,6 +67,34 @@ pub struct Args { #[clap(long, env)] pub pager_duty_integration_key: Option, + /// Direct local GPU server, set by Fleet for an integrated app worker. + #[clap(long, env = "FLEET_GPU_ENDPOINT")] + pub local_gpu_endpoint: Option, + + /// Persistent local worker state. Required with --local-gpu-endpoint. + #[clap(long, env = "FLEET_APP_STORAGE_ROOT", requires = "local_gpu_endpoint")] + pub state_dir: Option, + + /// Use an existing production guest instead of the embedded ELF. + #[clap(long, env = "ETH_PROOFS_ELF_FILE")] + pub elf_file: Option, + + /// Reject a guest whose digest differs from this app's configured program. + #[clap(long, env = "FLEET_APP_ELF_ID")] + pub expected_elf_id: Option, + + /// First block for a new durable stream; restarts resume persisted progress. + #[clap(long)] + pub start_block: Option, + + /// Witness preparation concurrency (1 or 2; consecutive results are delivered in order). + #[clap(long, default_value_t = 1)] + pub prepare_concurrency: usize, + + /// Pause proving when this many completed reports await acknowledgment. + #[clap(long, default_value_t = 128)] + pub max_pending_reports: usize, + /// Moongate server endpoint. #[clap(long, env)] pub moongate_endpoint: Option, diff --git a/bin/eth-proofs/src/consecutive.rs b/bin/eth-proofs/src/consecutive.rs new file mode 100644 index 0000000..b128c6b --- /dev/null +++ b/bin/eth-proofs/src/consecutive.rs @@ -0,0 +1,293 @@ +//! Bounded preparation of consecutive blocks with ordered, durable publication. +use futures::{channel::mpsc, pin_mut, SinkExt, Stream, StreamExt}; +use std::{future::Future, time::Duration}; +use tokio::sync::watch; + +pub async fn run( + blocks: S, + concurrency: usize, + mut output: mpsc::Sender<(u64, T)>, + mut shutdown: watch::Receiver, + mut prepare: P, + mut persist: C, +) -> eyre::Result<()> +where + S: Stream>, + P: FnMut(u64) -> PF, + PF: Future>, + C: FnMut(u64, &T) -> eyre::Result<()>, +{ + eyre::ensure!(concurrency > 0, "preparation concurrency must be positive"); + let prepared = blocks + .map(move |number| { + let pending = number.map(|number| (number, prepare(number))); + async move { + let (number, future) = pending?; + Ok::<_, eyre::Report>((number, future.await?)) + } + }) + .buffered(concurrency); + pin_mut!(prepared); + loop { + if *shutdown.borrow() { + return Ok(()); + } + let next = tokio::select! { + biased; + _ = shutdown.changed() => return Ok(()), + next = prepared.next() => next, + }; + let Some(next) = next else { return Ok(()) }; + let (number, input) = next?; + // Later completions cannot be persisted or published ahead of this block. + persist(number, &input)?; + tokio::select! { + biased; + _ = shutdown.changed() => return Ok(()), + result = output.send((number, input)) => { + if result.is_err() { return Ok(()) } + }, + } + } +} + +/// A preparation failure occupies its original slot until the same block succeeds. +pub async fn retry( + number: u64, + delay: Duration, + mut prepare: P, + mut on_error: E, +) -> T +where + P: FnMut(u64) -> PF, + PF: Future>, + E: FnMut(u64, eyre::Report) -> EF, + EF: Future, +{ + loop { + match prepare(number).await { + Ok(input) => return input, + Err(error) => { + on_error(number, error).await; + tokio::time::sleep(delay).await; + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use futures::{stream, FutureExt}; + use std::sync::{ + atomic::{AtomicUsize, Ordering}, + Arc, Mutex, + }; + use tokio::sync::Semaphore; + + #[tokio::test] + async fn overlaps_preparation_but_persists_and_delivers_in_block_order() { + let first = Arc::new(Semaphore::new(0)); + let second = Arc::new(Semaphore::new(0)); + let started = Arc::new(Mutex::new(Vec::new())); + let finished = Arc::new(Mutex::new(Vec::new())); + let persisted = Arc::new(Mutex::new(Vec::new())); + let (tx, mut rx) = mpsc::channel(4); + let (_stop, shutdown) = watch::channel(false); + let task = tokio::spawn({ + let first = first.clone(); + let second = second.clone(); + let started = started.clone(); + let finished = finished.clone(); + let persisted = persisted.clone(); + async move { + run( + stream::iter((100..104).map(Ok)), + 2, + tx, + shutdown, + move |number| { + let first = first.clone(); + let second = second.clone(); + let started = started.clone(); + let finished = finished.clone(); + async move { + started.lock().unwrap().push(number); + if number == 100 { + first.acquire().await.unwrap().forget(); + } + if number == 101 { + second.acquire().await.unwrap().forget(); + } + finished.lock().unwrap().push(number); + Ok(number) + } + }, + move |number, _| { + persisted.lock().unwrap().push(number); + Ok(()) + }, + ) + .await + } + }); + tokio::time::timeout(Duration::from_secs(2), async { + while started.lock().unwrap().len() < 2 { + tokio::task::yield_now().await; + } + }) + .await + .unwrap(); + assert_eq!(*started.lock().unwrap(), vec![100, 101]); + second.add_permits(1); + tokio::time::timeout(Duration::from_secs(2), async { + while !finished.lock().unwrap().contains(&101) { + tokio::task::yield_now().await; + } + }) + .await + .unwrap(); + assert!(rx.next().now_or_never().is_none()); + assert!(persisted.lock().unwrap().is_empty()); + first.add_permits(1); + let mut received = Vec::new(); + while let Some((number, value)) = rx.next().await { + assert_eq!(number, value); + received.push(number); + } + task.await.unwrap().unwrap(); + assert_eq!(received, vec![100, 101, 102, 103]); + assert_eq!(*persisted.lock().unwrap(), received); + } + + #[tokio::test] + async fn retries_a_failed_block_before_delivering_its_ready_successor() { + let attempts = Arc::new(AtomicUsize::new(0)); + let failures = Arc::new(Mutex::new(Vec::new())); + let (tx, mut rx) = mpsc::channel(4); + let (_stop, shutdown) = watch::channel(false); + let task = tokio::spawn({ + let attempts = attempts.clone(); + let failures = failures.clone(); + async move { + run( + stream::iter([Ok(100), Ok(101)]), + 2, + tx, + shutdown, + move |number| { + let attempts = attempts.clone(); + let failures = failures.clone(); + async move { + Ok(retry( + number, + Duration::from_millis(10), + move |number| { + let failed = number == 100 && + attempts.fetch_add(1, Ordering::SeqCst) == 0; + std::future::ready(if failed { + Err(eyre::eyre!("witness unavailable")) + } else { + Ok(number) + }) + }, + move |number, _| { + failures.lock().unwrap().push(number); + std::future::ready(()) + }, + ) + .await) + } + }, + |_, _| Ok(()), + ) + .await + } + }); + assert_eq!(rx.next().await, Some((100, 100))); + assert_eq!(rx.next().await, Some((101, 101))); + task.await.unwrap().unwrap(); + assert_eq!(*failures.lock().unwrap(), vec![100]); + assert_eq!(attempts.load(Ordering::SeqCst), 2); + } + + #[tokio::test] + async fn shutdown_cancels_pending_work_without_persisting_later_results() { + let started = Arc::new(AtomicUsize::new(0)); + let persisted = Arc::new(AtomicUsize::new(0)); + let (tx, _rx) = mpsc::channel(1); + let (stop, shutdown) = watch::channel(false); + let task = tokio::spawn({ + let started = started.clone(); + let persisted = persisted.clone(); + async move { + run( + stream::iter((100..110).map(Ok)), + 2, + tx, + shutdown, + move |number| { + started.fetch_add(1, Ordering::SeqCst); + async move { + if number == 100 { + std::future::pending::<()>().await; + } + Ok(number) + } + }, + move |_, _| { + persisted.fetch_add(1, Ordering::SeqCst); + Ok(()) + }, + ) + .await + } + }); + tokio::time::timeout(Duration::from_secs(2), async { + while started.load(Ordering::SeqCst) < 2 { + tokio::task::yield_now().await; + } + }) + .await + .unwrap(); + stop.send(true).unwrap(); + tokio::time::timeout(Duration::from_secs(2), task).await.unwrap().unwrap().unwrap(); + assert_eq!(started.load(Ordering::SeqCst), 2); + assert_eq!(persisted.load(Ordering::SeqCst), 0); + } + + #[tokio::test] + async fn paused_consumer_bounds_preparation_and_shutdown_interrupts_backpressure() { + let started = Arc::new(AtomicUsize::new(0)); + let (tx, _rx) = mpsc::channel(1); + let (stop, shutdown) = watch::channel(false); + let task = tokio::spawn({ + let started = started.clone(); + async move { + run( + stream::iter((100..200).map(Ok)), + 2, + tx, + shutdown, + move |number| { + started.fetch_add(1, Ordering::SeqCst); + std::future::ready(Ok(number)) + }, + |_, _| Ok(()), + ) + .await + } + }); + tokio::time::timeout(Duration::from_secs(2), async { + while started.load(Ordering::SeqCst) < 2 { + tokio::task::yield_now().await; + } + }) + .await + .unwrap(); + tokio::time::sleep(Duration::from_millis(20)).await; + assert!(started.load(Ordering::SeqCst) <= 5, "producer ran past its bounded queue"); + stop.send(true).unwrap(); + tokio::time::timeout(Duration::from_secs(2), task).await.unwrap().unwrap().unwrap(); + } +} diff --git a/bin/eth-proofs/src/eth_proofs.rs b/bin/eth-proofs/src/eth_proofs.rs index 327437d..208f44e 100644 --- a/bin/eth-proofs/src/eth_proofs.rs +++ b/bin/eth-proofs/src/eth_proofs.rs @@ -1,29 +1,154 @@ -use std::time::Duration; +use crate::state::State; +use std::{sync::Arc, time::Duration}; use base64::{engine::general_purpose::STANDARD, Engine}; use eyre::eyre; use host_executor::ExecutionHooks; use reqwest_middleware::{ClientBuilder, ClientWithMiddleware}; use reqwest_retry::{policies::ExponentialBackoff, RetryTransientMiddleware}; -use tracing::error; +use tracing::{error, info}; use zkm_sdk::{HashableKey, ZKMVerifyingKey}; -#[derive(Debug, Clone)] +#[derive(Clone)] pub struct EthProofsClient { cluster_id: u64, endpoint: String, api_token: String, client: ClientWithMiddleware, + state: Option>, } impl EthProofsClient { pub fn new(cluster_id: u64, endpoint: String, api_token: String) -> Self { let retry_policy = ExponentialBackoff::builder().build_with_max_retries(3); - let client = ClientBuilder::new(reqwest::Client::new()) - .with(RetryTransientMiddleware::new_with_policy(retry_policy)) - .build(); + let client = ClientBuilder::new( + reqwest::Client::builder().timeout(Duration::from_secs(60)).build().unwrap(), + ) + .with(RetryTransientMiddleware::new_with_policy(retry_policy)) + .build(); - Self { cluster_id, endpoint, api_token, client } + Self { cluster_id, endpoint, api_token, client, state: None } + } + + pub fn with_state(mut self, state: Arc) -> Self { + self.state = Some(state); + self + } + + pub fn start_reporter(&self) -> tokio::task::JoinHandle<()> { + let this = self.clone(); + tokio::spawn(async move { + let Some(state) = &this.state else { + return; + }; + loop { + match state.pending() { + Ok(pending) => { + for (block, payload) in pending { + let result = this + .client + .post(format!("{}/proofs/proved", this.endpoint)) + .header("Authorization", format!("Bearer {}", this.api_token)) + .json(&payload) + .send() + .await; + match result { + Ok(response) if response.status().is_success() => { + if let Err(err) = state.acknowledge(block) { + error!(block, %err, "report accepted but acknowledgment persistence failed"); + } else { + info!(block, "durable EthProofs report acknowledged"); + } + } + Ok(response) + if response.status() == reqwest::StatusCode::CONFLICT => + { + match this.already_published(block, &payload).await { + Ok(true) => { + if let Err(err) = state.acknowledge(block) { + error!(block, %err, "duplicate acknowledgment persistence failed"); + } else { + info!( + block, + duplicate = true, + "durable EthProofs report acknowledged" + ); + } + } + Ok(false) => error!( + block, + "conflicting API proof differs; report remains pending" + ), + Err(err) => { + error!(block, %err, "duplicate proof lookup failed; report remains pending") + } + } + } + Ok(response) => { + error!(block, status = %response.status(), "EthProofs report remains pending") + } + Err(err) => error!(block, %err, "EthProofs report remains pending"), + } + } + } + Err(err) => error!(%err, "reading persistent reporting outbox failed"), + } + tokio::select! { + _ = state.report_ready() => {}, + _ = tokio::time::sleep(Duration::from_secs(3)) => {}, + } + } + }) + } + + /// A lost local acknowledgment can turn a successful retry into HTTP 409. + /// Only accept it after checking the cluster, block, and exact published bytes. + async fn already_published( + &self, + block: u64, + payload: &serde_json::Value, + ) -> eyre::Result { + let rows: serde_json::Value = self + .client + .get(format!("{}/proofs?block={block}&limit=100", self.endpoint)) + .header("Authorization", format!("Bearer {}", self.api_token)) + .send() + .await? + .error_for_status()? + .json() + .await?; + let expected = STANDARD + .decode(payload["proof"].as_str().ok_or_else(|| eyre!("missing proof bytes"))?)?; + let proofs = rows["proofs"].as_array().ok_or_else(|| eyre!("invalid proof listing"))?; + for proof in proofs { + if proof["block_number"].as_u64() != Some(block) || + proof["proof_status"].as_str() != Some("proved") || + proof["cluster_version"]["cluster"]["index"].as_u64() != Some(self.cluster_id) + { + continue; + } + let id = match &proof["proof_id"] { + serde_json::Value::Number(id) => id.to_string(), + serde_json::Value::String(id) => id.clone(), + _ => continue, + }; + if id.is_empty() || !id.chars().all(|c| c.is_ascii_alphanumeric() || c == '-') { + continue; + } + let published = self + .client + .get(format!("{}/proofs/download/{id}", self.endpoint)) + .header("Authorization", format!("Bearer {}", self.api_token)) + .send() + .await? + .error_for_status()? + .bytes() + .await?; + if published.as_ref() == expected.as_slice() { + return Ok(true); + } + } + Ok(false) } pub async fn queued(&self, block_number: u64) { @@ -113,8 +238,12 @@ impl EthProofsClient { .map_err(|e| eyre!(e)) .and_then(|r| r.error_for_status().map_err(|e| eyre!(e))); - if let Err(err) = response { - error!("Failed to report proof proving: {}", err) + match response { + Ok(_) => info!( + "Reported proved block {} to eth-proofs: {} cycles, {:.1} s", + block_number, cycles, elapsed + ), + Err(err) => error!("Failed to report proof proved: {}", err), } }); } @@ -145,9 +274,170 @@ impl ExecutionHooks for EthProofsClient { cycles: u64, proving_duration: Duration, ) -> eyre::Result<()> { - #[cfg(not(feature = "test"))] - self.proved(proof_bytes, block_number, cycles, proving_duration.as_secs_f32(), vk).await; + if let Some(state) = &self.state { + let payload = serde_json::json!({ + "proof": STANDARD.encode(proof_bytes), "block_number": block_number, + "proving_cycles": cycles, "proving_time": proving_duration.as_millis() as u64, + "verifier_id": vk.bytes32(), "cluster_id": self.cluster_id, + }); + // Commit the output and its retryable report before the cursor advances. + state.commit(block_number, proof_bytes, _public_values_bytes, payload)?; + } else { + #[cfg(not(feature = "test"))] + self.proved(proof_bytes, block_number, cycles, proving_duration.as_secs_f32(), vk) + .await; + } Ok(()) } } + +#[cfg(test)] +mod tests { + use super::*; + use crate::state::Identity; + use tokio::io::{AsyncReadExt, AsyncWriteExt}; + + #[tokio::test] + async fn duplicate_lookup_requires_the_same_cluster_block_and_bytes() { + for (cluster, block, bytes, expected) in [ + (8, 10, b"proof".as_slice(), true), + (9, 10, b"proof".as_slice(), false), + (8, 11, b"proof".as_slice(), false), + (8, 10, b"different".as_slice(), false), + ] { + let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap(); + let client = EthProofsClient::new( + 8, + format!("http://{}", listener.local_addr().unwrap()), + "test".into(), + ); + let server = tokio::spawn(async move { + let listing = serde_json::json!({"proofs":[{ + "block_number":block,"proof_status":"proved","proof_id":123, + "cluster_version":{"cluster":{"index":cluster}} + }]}) + .to_string(); + let count = if cluster == 8 && block == 10 { 2 } else { 1 }; + for i in 0..count { + let (mut socket, _) = listener.accept().await.unwrap(); + let mut request = vec![0; 4096]; + let n = socket.read(&mut request).await.unwrap(); + let request = String::from_utf8_lossy(&request[..n]); + assert!(request.starts_with(if i == 0 { + "GET /proofs?block=10&limit=100 " + } else { + "GET /proofs/download/123 " + })); + let body = if i == 0 { listing.as_bytes() } else { bytes }; + socket.write_all(format!("HTTP/1.1 200 OK\r\nContent-Type: application/json\r\nContent-Length: {}\r\nConnection: close\r\n\r\n",body.len()).as_bytes()).await.unwrap(); + socket.write_all(body).await.unwrap(); + } + }); + let actual = tokio::time::timeout( + Duration::from_secs(5), + client + .already_published(10, &serde_json::json!({"proof":STANDARD.encode(b"proof")})), + ) + .await + .unwrap() + .unwrap(); + assert_eq!(actual, expected); + server.await.unwrap(); + } + } + + #[tokio::test] + async fn report_is_retained_until_http_success() { + let root = tempfile::tempdir().unwrap(); + let state = Arc::new( + State::open( + root.path(), + Identity { + namespace: "test".into(), + tenant: "ethproofs".into(), + chain_id: 1, + cluster_id: 8, + elf_id: "elf".into(), + interval: 1, + residue: 0, + }, + Some(10), + ) + .unwrap(), + ); + let listener = tokio::net::TcpListener::bind("127.0.0.1:0").await.unwrap(); + let client = EthProofsClient::new( + 8, + format!("http://{}", listener.local_addr().unwrap()), + "test".into(), + ) + .with_state(state.clone()); + let reporter = client.start_reporter(); + // Let the reporter enter its idle wait, then commit a new output. + tokio::time::sleep(Duration::from_millis(50)).await; + state.commit(10, b"proof", b"values", serde_json::json!({"block_number":10})).unwrap(); + for status in ["401 Unauthorized", "200 OK"] { + let timeout = if status.starts_with("401") { 1 } else { 10 }; + let (mut socket, _) = + tokio::time::timeout(Duration::from_secs(timeout), listener.accept()) + .await + .unwrap() + .unwrap(); + let mut request = Vec::new(); + loop { + let mut bytes = [0; 2048]; + let n = socket.read(&mut bytes).await.unwrap(); + request.extend_from_slice(&bytes[..n]); + if let Some(end) = request.windows(4).position(|w| w == b"\r\n\r\n") { + let headers = String::from_utf8_lossy(&request[..end]).to_ascii_lowercase(); + let length = headers + .lines() + .find_map(|line| line.strip_prefix("content-length: ")) + .unwrap() + .parse::() + .unwrap(); + if request.len() >= end + 4 + length { + break; + } + } + assert!(n > 0); + } + assert!(String::from_utf8_lossy(&request).starts_with("POST /proofs/proved")); + assert_eq!(state.pending_count().unwrap(), 1); + socket + .write_all( + format!("HTTP/1.1 {status}\r\nContent-Length: 0\r\nConnection: close\r\n\r\n") + .as_bytes(), + ) + .await + .unwrap(); + } + tokio::time::timeout(Duration::from_secs(5), async { + while state.pending_count().unwrap() != 0 { + tokio::time::sleep(Duration::from_millis(10)).await; + } + }) + .await + .unwrap(); + reporter.abort(); + let _ = reporter.await; + drop(client); + drop(state); + let restored = State::open( + root.path(), + Identity { + namespace: "test".into(), + tenant: "ethproofs".into(), + chain_id: 1, + cluster_id: 8, + elf_id: "elf".into(), + interval: 1, + residue: 0, + }, + None, + ) + .unwrap(); + assert_eq!(restored.pending_count().unwrap(), 0); + } +} diff --git a/bin/eth-proofs/src/latest.rs b/bin/eth-proofs/src/latest.rs new file mode 100644 index 0000000..5b45bac --- /dev/null +++ b/bin/eth-proofs/src/latest.rs @@ -0,0 +1,233 @@ +//! A bounded latest-head preparation pool. The prover consumes a single slot; +//! older completions cannot replace newer ones, even when RPCs finish out of order. +use futures::{stream::FuturesUnordered, StreamExt}; +use std::{ + collections::HashSet, + future::Future, + sync::Arc, + time::{Duration, Instant}, +}; +use tokio::sync::watch; +use tracing::{info, warn}; + +pub type Prepared = (u64, Arc>); + +pub async fn run( + concurrency: usize, + minimum: u64, + interval: u64, + residue: u64, + output: watch::Sender>, + mut shutdown: watch::Receiver, + mut head: H, + mut prepare: P, +) -> eyre::Result<()> +where + H: FnMut() -> HF, + HF: Future>, + P: FnMut(u64) -> PF, + PF: Future>>>, +{ + eyre::ensure!(concurrency > 0 && interval > 0, "invalid preparation limits"); + let mut running = FuturesUnordered::new(); + let mut selected = None; + let mut published = None; + let mut active_blocks = HashSet::new(); + let mut retry_after = None; + let mut poll = tokio::time::interval(Duration::from_millis(500)); + poll.set_missed_tick_behavior(tokio::time::MissedTickBehavior::Skip); + loop { + if *shutdown.borrow() || output.is_closed() { + break; + } + tokio::select! { + _ = shutdown.changed() => break, + result = running.next(), if !running.is_empty() => { + if let Some((number, result)) = result { + active_blocks.remove(&number); + match result { + Ok(bytes) if published.is_none_or(|previous| number > previous) => { + info!(number, "latest-head witness ready"); + published = Some(number); + output.send_replace(Some((number, bytes))); + }, + Ok(_) => {}, // A slower older witness must never replace a newer one. + Err(err) => { + warn!(number, %err, "latest-head witness preparation failed"); + if selected == Some(number) { + retry_after = Some((number, Instant::now() + Duration::from_secs(2))); + } + }, + } + } + }, + head_result = async { poll.tick().await; head().await }, if running.len() < concurrency => { + let newest = match head_result { + Ok(head) => super::latest_selected_block(head, interval, residue), + Err(err) => { + warn!(%err, "latest head lookup failed; retrying"); + continue; + } + }; + if let Some(number) = newest.filter(|number| { + *number >= minimum && selected.is_none_or(|previous| *number >= previous) + && published.is_none_or(|previous| *number > previous) + && !active_blocks.contains(number) + && retry_after.is_none_or(|(failed, until)| *number != failed || Instant::now() >= until) + }) { + selected = Some(number); + active_blocks.insert(number); + let future = prepare(number); + running.push(async move { (number, future.await) }); + info!(number, active = running.len(), "latest-head witness preparation started"); + } + }, + } + } + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + use std::sync::atomic::{AtomicU64, AtomicUsize, Ordering}; + use tokio::sync::Semaphore; + + #[tokio::test] + async fn overlaps_two_preparations_and_keeps_newest_out_of_order_completion() { + let head = Arc::new(AtomicU64::new(100)); + let active = Arc::new(AtomicUsize::new(0)); + let first = Arc::new(Semaphore::new(0)); + let second = Arc::new(Semaphore::new(0)); + let (output, mut ready) = watch::channel(None); + let (stop, shutdown) = watch::channel(false); + let task = tokio::spawn({ + let head = head.clone(); + let active = active.clone(); + let first = first.clone(); + let second = second.clone(); + async move { + run( + 2, + 100, + 1, + 0, + output, + shutdown, + || std::future::ready(Ok(head.load(Ordering::SeqCst))), + |number| { + let active = active.clone(); + let gate = if number == 100 { first.clone() } else { second.clone() }; + async move { + active.fetch_add(1, Ordering::SeqCst); + let _permit = gate.acquire().await.unwrap(); + active.fetch_sub(1, Ordering::SeqCst); + Ok(Arc::new(vec![number as u8])) + } + }, + ) + .await + } + }); + tokio::time::timeout(Duration::from_secs(3), async { + while active.load(Ordering::SeqCst) != 1 { + tokio::task::yield_now().await; + } + head.store(101, Ordering::SeqCst); + while active.load(Ordering::SeqCst) != 2 { + tokio::task::yield_now().await; + } + // Both slots are occupied. Advancing the head must not start a third job. + head.store(102, Ordering::SeqCst); + tokio::time::sleep(Duration::from_millis(550)).await; + assert_eq!(active.load(Ordering::SeqCst), 2); + head.store(101, Ordering::SeqCst); + second.add_permits(1); + ready.changed().await.unwrap(); + assert_eq!(ready.borrow_and_update().as_ref().unwrap().0, 101); + first.add_permits(1); + while active.load(Ordering::SeqCst) != 0 { + tokio::task::yield_now().await; + } + tokio::time::sleep(Duration::from_millis(20)).await; + assert_eq!(ready.borrow().as_ref().unwrap().0, 101); + assert!(!ready.has_changed().unwrap()); + }) + .await + .unwrap(); + stop.send(true).unwrap(); + task.await.unwrap().unwrap(); + } + + #[tokio::test] + async fn replaces_waiting_witness_instead_of_building_a_backlog() { + let head = Arc::new(AtomicU64::new(100)); + let (output, mut ready) = watch::channel(None); + let (stop, shutdown) = watch::channel(false); + let task = tokio::spawn({ + let head = head.clone(); + async move { + run( + 2, + 100, + 1, + 0, + output, + shutdown, + || std::future::ready(Ok(head.load(Ordering::SeqCst))), + |number| std::future::ready(Ok(Arc::new(vec![number as u8]))), + ) + .await + } + }); + tokio::time::timeout(Duration::from_secs(3), async { + ready.changed().await.unwrap(); + assert_eq!(ready.borrow_and_update().as_ref().unwrap().0, 100); + // Simulate a busy prover: no receive while new heads are prepared. + head.store(105, Ordering::SeqCst); + ready.changed().await.unwrap(); + assert_eq!(ready.borrow_and_update().as_ref().unwrap().0, 105); + head.store(110, Ordering::SeqCst); + ready.changed().await.unwrap(); + assert_eq!(ready.borrow_and_update().as_ref().unwrap().0, 110); + }) + .await + .unwrap(); + stop.send(true).unwrap(); + task.await.unwrap().unwrap(); + } + #[tokio::test] + async fn retries_an_announced_head_until_its_witness_is_available() { + let attempts = Arc::new(AtomicUsize::new(0)); + let (output, mut ready) = watch::channel(None); + let (stop, shutdown) = watch::channel(false); + let task = tokio::spawn({ + let attempts = attempts.clone(); + async move { + run( + 2, + 100, + 1, + 0, + output, + shutdown, + || std::future::ready(Ok(100)), + |_| { + let attempt = attempts.fetch_add(1, Ordering::SeqCst); + std::future::ready(if attempt == 0 { + Err(eyre::eyre!("witness RPC has not received this head yet")) + } else { + Ok(Arc::new(vec![1])) + }) + }, + ) + .await + } + }); + tokio::time::timeout(Duration::from_secs(4), ready.changed()).await.unwrap().unwrap(); + assert_eq!(ready.borrow().as_ref().unwrap().0, 100); + assert_eq!(attempts.load(Ordering::SeqCst), 2); + stop.send(true).unwrap(); + task.await.unwrap().unwrap(); + } +} diff --git a/bin/eth-proofs/src/main.rs b/bin/eth-proofs/src/main.rs index 688a05b..5b8f382 100644 --- a/bin/eth-proofs/src/main.rs +++ b/bin/eth-proofs/src/main.rs @@ -1,25 +1,34 @@ -use std::{env, sync::Arc}; +use sha2::{Digest, Sha256}; +use state::{Identity, State}; +use std::{env, sync::Arc, time::Duration}; +use zkm_cuda::ZKMGpuServer; +use zkm_prover::ZKMProver; +use zkm_sdk::provers::CudaProver; use alloy_provider::{Provider, ProviderBuilder, WsConnect}; use clap::Parser; use cli::Args; use eth_proofs::EthProofsClient; -use futures::{future::ready, StreamExt}; +use futures::{channel::mpsc, future::ready, FutureExt, StreamExt}; use host_executor::{ - alerting::AlertingClient, create_eth_block_execution_strategy_factory, BlockExecutor, - EthExecutorComponents, FullExecutor, + alerting::AlertingClient, create_eth_block_execution_strategy_factory, EthExecutorComponents, + FullExecutor, }; use provider::create_provider; -use tracing::{error, info}; +use tracing::{error, info, warn}; use tracing_subscriber::{fmt, layer::SubscriberExt, util::SubscriberInitExt, EnvFilter}; use zkm_sdk::{include_elf, ProverClient}; mod cli; +mod consecutive; +mod latest; +mod state; mod eth_proofs; #[tokio::main] async fn main() -> eyre::Result<()> { + exit_with_parent()?; // Initialize the environment variables. dotenv::dotenv().ok(); @@ -43,7 +52,57 @@ async fn main() -> eyre::Result<()> { let args = Args::parse(); let config = args.as_config().await?; - let elf = include_elf!("reth").to_vec(); + eyre::ensure!(args.block_interval > 0, "block interval must be positive"); + eyre::ensure!(args.max_pending_reports > 0, "pending report limit must be positive"); + eyre::ensure!( + (1..=2).contains(&args.prepare_concurrency) && args.prefetch_depth > 0, + "preparation concurrency must be 1 or 2 and queue depth must be positive" + ); + let elf = match &args.elf_file { + Some(path) => std::fs::read(path)?, + None => include_elf!("reth").to_vec(), + }; + let elf_id = hex::encode(Sha256::digest(&elf)); + if let Some(expected) = &args.expected_elf_id { + eyre::ensure!(*expected == elf_id, "guest ELF differs from the app's configured digest"); + } + let state = if let Some(endpoint) = &args.local_gpu_endpoint { + eyre::ensure!( + endpoint.scheme() == "http" && + matches!(endpoint.host_str(), Some("127.0.0.1" | "localhost" | "[::1]")), + "local GPU endpoint must be loopback HTTP" + ); + eyre::ensure!( + !args.execute_only && args.max_lag == 0, + "durable local mode requires proving and never skips lagging blocks" + ); + let root = args + .state_dir + .as_ref() + .ok_or_else(|| eyre::eyre!("local proving requires --state-dir"))?; + eyre::ensure!(args.expected_elf_id.is_some(), "local proving requires --expected-elf-id"); + let state = Arc::new(State::open( + root, + Identity { + namespace: std::env::var("FLEET_APP_NAMESPACE")?, + tenant: std::env::var("FLEET_APP_TENANT")?, + chain_id: 1, + cluster_id: args.eth_proofs_cluster_id, + elf_id: elf_id.clone(), + interval: args.block_interval, + residue: args.block_residue % args.block_interval, + }, + args.start_block, + )?); + // FullExecutor's verification-key file belongs to this replica's storage. + std::env::set_current_dir(std::fs::canonicalize(root)?)?; + Some(state) + } else { + eyre::ensure!(args.state_dir.is_none(), "durable worker state requires local proving"); + None + }; + eyre::ensure!(!args.latest_block || state.is_some(), "--latest-block requires local mode"); + info!(%elf_id, local = state.is_some(), "starting EthProofs app pipeline"); let block_execution_strategy_factory = create_eth_block_execution_strategy_factory(&config.genesis, None); @@ -52,25 +111,102 @@ async fn main() -> eyre::Result<()> { args.eth_proofs_endpoint, args.eth_proofs_api_token, ); + let eth_proofs_client = match &state { + Some(state) => eth_proofs_client.with_state(state.clone()), + None => eth_proofs_client, + }; + let reporter = eth_proofs_client.start_reporter(); + let (shutdown_tx, mut shutdown) = tokio::sync::watch::channel(false); + if state.is_some() { + tokio::spawn(async move { + #[cfg(unix)] + { + let mut terminate = + tokio::signal::unix::signal(tokio::signal::unix::SignalKind::terminate()) + .unwrap(); + tokio::select! { _ = terminate.recv() => {}, _ = tokio::signal::ctrl_c() => {} } + } + #[cfg(not(unix))] + { + let _ = tokio::signal::ctrl_c().await; + } + info!("draining EthProofs worker; finish the current proof and persist its cursor"); + let _ = shutdown_tx.send(true); + }); + } + let alerting_client = args.pager_duty_integration_key.map(AlertingClient::new); - let ws = WsConnect::new(args.ws_rpc_url); - #[allow(deprecated)] - let ws_provider = ProviderBuilder::new().on_ws(ws).await?; let http_provider = create_provider(args.http_rpc_url); let debug_http_provider = create_provider(args.debug_http_rpc_url); - - // Subscribe to block headers. - let subscription = ws_provider.subscribe_blocks().await?; - let mut stream = - subscription.into_stream().filter(|h| ready(h.number % args.block_interval == 0)); - - // let mut builder = ProverClient::builder().cuda(); - if let Some(_endpoint) = &args.moongate_endpoint { - // builder = builder.with_moongate_endpoint(endpoint) - } - - let client = Arc::new(ProverClient::new()); + eyre::ensure!( + http_provider.get_chain_id().await? == 1, + "EthProofs worker requires Ethereum mainnet RPC" + ); + let block_interval = args.block_interval; + let block_residue = args.block_residue % block_interval; + // Local mode uses HTTP head polling: a WS disconnect cannot discard the cursor. + let ws_provider = if state.is_none() { + #[allow(deprecated)] + let provider = ProviderBuilder::new() + .on_ws(WsConnect::new( + args.ws_rpc_url + .ok_or_else(|| eyre::eyre!("network proving requires --ws-rpc-url"))?, + )) + .await?; + Some(provider) + } else { + None + }; + let head_shutdown = shutdown.clone(); + let stream = if state.is_some() { + futures::stream::unfold( + (http_provider.clone(), None, head_shutdown), + |(provider, mut previous, shutdown)| async move { + loop { + if *shutdown.borrow() { + return None; + } + match provider.get_block_number().await { + Ok(head) if previous != Some(head) => { + previous = Some(head); + return Some((head, (provider, previous, shutdown))); + } + Ok(_) => {} + Err(err) => { + warn!(%err, "head RPC failed; retrying without advancing cursor") + } + } + tokio::time::sleep(Duration::from_secs(2)).await; + } + }, + ) + .boxed() + } else { + ws_provider + .as_ref() + .unwrap() + .subscribe_blocks() + .await? + .into_stream() + .filter(move |h| ready(h.number % block_interval == block_residue)) + .map(|h| h.number) + .boxed() + }; + let client = if let Some(endpoint) = args.local_gpu_endpoint { + let endpoint = endpoint.to_string(); + Arc::new( + tokio::task::spawn_blocking(move || ProverClient { + prover: Box::new(CudaProver::new( + ZKMProver::new(), + ZKMGpuServer::External { endpoint }, + )), + }) + .await?, + ) + } else { + Arc::new(ProverClient::new()) + }; let executor = FullExecutor::, _>::try_new( http_provider.clone(), @@ -85,19 +221,312 @@ async fn main() -> eyre::Result<()> { info!("Latest block number: {}", http_provider.get_block_number().await?); - while let Some(header) = stream.next().await { - // Wait for the block to be avaliable in the HTTP provider - executor.wait_for_block(header.number).await?; - - if let Err(err) = executor.execute(header.number).await { - let error_message = format!("Error handling block {}: {err}", header.number); - error!(error_message); + // Two-stage pipeline. The fetcher pulls headers off the subscription, + // fetches the block + witness and runs the native execution; the prover + // loop below consumes the prepared inputs one at a time. Block N+1's + // fetch therefore overlaps block N's proof instead of leaving the cards + // idle for the RPC round trips. + let executor = Arc::new(executor); + let alerting_client = Arc::new(alerting_client); + let (tx, mut rx) = mpsc::channel(args.prefetch_depth.max(1)); + let (latest_tx, mut latest_rx) = tokio::sync::watch::channel(None); + // Recover a completed proof before choosing a fresh head. Only this prover + // owns the durable cursor; preparations never advance or delete its inputs. + if args.latest_block { + let state = state.as_ref().unwrap(); + if let Some(number) = state.next_block() { + if state.is_committed(number)? { + state.advance(number, true)?; + } + } + } + let mut fetcher = { + let executor = executor.clone(); + let alerting_client = alerting_client.clone(); + let max_lag = args.max_lag; + let state = state.clone(); + let preparation_shutdown = shutdown.clone(); + let latest_block = args.latest_block; + let head_provider = http_provider.clone(); + let prepare_concurrency = args.prepare_concurrency; + tokio::spawn(async move { + if latest_block { + let minimum = state.as_ref().unwrap().next_block().unwrap_or(0); + return latest::run( + prepare_concurrency, + minimum, + block_interval, + block_residue, + latest_tx, + preparation_shutdown, + || { + let provider = head_provider.clone(); + async move { Ok(provider.get_block_number().await?) } + }, + |number| { + let executor = executor.clone(); + async move { + executor.wait_for_block(number).await?; + let input = executor.prepare(number).await?; + Ok(Arc::new(bincode::serialize(&input)?)) + } + }, + ) + .await; + } + // Headers bound how far ahead we may prepare. The durable cursor is + // advanced only by the prover, after committing each ordered output. + let next = state.as_ref().and_then(|s| s.next_block()).unwrap_or(0); + let blocks = futures::stream::try_unfold((0u64, next, stream), { + let state = state.clone(); + move |(mut head, mut next, mut stream)| { + let state = state.clone(); + async move { + loop { + if next == 0 || next > head { + match stream.next().await { + Some(header) => { + head = head.max(header); + if next == 0 { + next = header - + ((header + block_interval - block_residue) % + block_interval); + if let Some(state) = &state { + state.initialize(next)?; + } + } + continue; + } + None => return Ok::<_, eyre::Report>(None), + } + } + while let Some(Some(header)) = stream.next().now_or_never() { + head = head.max(header); + } + let number = next; + next = next + .checked_add(block_interval) + .ok_or_else(|| eyre::eyre!("preparation block cursor overflow"))?; + if max_lag > 0 && head - number > max_lag { + warn!( + "skipping block {number}: {} behind the newest header", + head - number + ); + continue; + } + return Ok(Some((number, (head, next, stream)))); + } + } + } + }) + .boxed(); + let persist_state = state.clone(); + consecutive::run( + blocks, + prepare_concurrency, + tx, + preparation_shutdown, + move |number| { + let executor = executor.clone(); + let state = state.clone(); + let alerting_client = alerting_client.clone(); + async move { + if let Some(state) = &state { + if state.is_committed(number)? { + return Ok(None); + } + if let Some(bytes) = state.input(number)? { + return Ok(Some(bincode::deserialize(&bytes)?)); + } + } + let input = consecutive::retry( + number, + Duration::from_secs(5), + move |number| { + let executor = executor.clone(); + async move { + executor.wait_for_block(number).await?; + executor.prepare(number).await + } + }, + move |number, err| { + let alerting_client = alerting_client.clone(); + async move { report_error(&alerting_client, number, err).await } + }, + ) + .await; + Ok(Some(input)) + } + .boxed() + }, + move |number, input| { + if let (Some(state), Some(input)) = (&persist_state, input) { + state.save_input(number, &bincode::serialize(input)?)?; + } + Ok(()) + }, + ) + .await + }) + }; - if let Some(alerting_client) = &alerting_client { - alerting_client.send_alert(error_message).await; + // NOT pipelined, deliberately. Sending block N+1's request early is + // worth ~0.3 s of transfer per block, but the server parks a session + // guard between a block's core and its compress and a new core request + // drops it: a request that lands in that window lets two blocks + // interleave on one card, which is what the guard is there to stop. + 'worker: loop { + if *shutdown.borrow() { + break; + } + let next = if args.latest_block { + loop { + let prepared = latest_rx.borrow_and_update().clone(); + if let Some((number, bytes)) = prepared { + let state = state.as_ref().unwrap(); + if state.next_block().is_none_or(|next| number >= next) { + state.initialize(number)?; + let next = state.next_block().unwrap(); + if number > next { + warn!( + from = next, + to = number, + "skipping lagging blocks to newest prepared head" + ); + state.skip_to(number)?; + } + state.save_input(number, &bytes)?; + break Some((number, Some(bincode::deserialize(&bytes)?))); + } + } + tokio::select! { + changed = latest_rx.changed() => { + if changed.is_err() { break None; } + }, + _ = shutdown.changed() => break None, + } + } + } else { + tokio::select! { + next = rx.next() => next, + _ = shutdown.changed(), if state.is_some() => None, + } + }; + let Some((number, client_input)) = next else { + break; + }; + if let Some(state) = &state { + while state.pending_count()? >= args.max_pending_reports { + warn!(number, "report outbox full; waiting before starting another proof"); + tokio::select! { + _ = tokio::time::sleep(Duration::from_secs(3)) => {}, + _ = shutdown.changed() => break, + } + } + if *shutdown.borrow() { + break; } } + if let Some(client_input) = client_input { + let committed = + state.as_ref().map(|s| s.is_committed(number)).transpose()?.unwrap_or(false); + if !committed { + if let Some(state) = &state { + let block = loop { + let result = tokio::select! { + block = http_provider.get_block_by_number(number.into()) => block, + _ = shutdown.changed() => break 'worker, + }; + match result { + Ok(Some(block)) => break block, + Ok(None) => warn!(number, "waiting for prepared block to be available"), + Err(err) => { + warn!(number, %err, "canonical block lookup failed; retrying") + } + } + tokio::time::sleep(Duration::from_secs(3)).await; + }; + if block.header.hash != client_input.current_block.header.hash_slow() { + fetcher.abort(); + let _ = (&mut fetcher).await; + state.discard_inputs_from(number)?; + eyre::bail!( + "prepared inputs invalidated by a reorg; restart from durable cursor" + ); + } + } + if let Err(err) = executor.prove_prepared(client_input).await { + report_error(&alerting_client, number, err).await; + // The replica lifecycle recovers failed GPU servers; input stays durable. + if state.is_some() { + return Err(eyre::eyre!( + "local proof failed; durable input retained for restart" + )); + } + } + } + } + if let Some(state) = &state { + state.advance(number, true)?; + } } + if *shutdown.borrow() { + fetcher.abort(); + let _ = fetcher.await; + } else { + fetcher.await??; + } + reporter.abort(); + if state.is_some() && !*shutdown.borrow() { + eyre::bail!("local worker preparation stream ended unexpectedly"); + } + + Ok(()) +} + +fn latest_selected_block(head: u64, interval: u64, residue: u64) -> Option { + let remainder = head % interval; + let distance = + if remainder >= residue { remainder - residue } else { interval - (residue - remainder) }; + head.checked_sub(distance) +} + +#[cfg(test)] +mod selection_tests { + use super::latest_selected_block; + #[test] + fn newest_selection_aligns_to_the_stream_and_handles_early_heads() { + assert_eq!(latest_selected_block(123, 1, 0), Some(123)); + assert_eq!(latest_selected_block(100, 10, 2), Some(92)); + assert_eq!(latest_selected_block(103, 10, 2), Some(102)); + assert_eq!(latest_selected_block(1, 10, 2), None); + assert_eq!(latest_selected_block(u64::MAX, u64::MAX, u64::MAX - 1), Some(u64::MAX - 1)); + } +} + +async fn report_error(alerting_client: &Option, number: u64, err: eyre::Report) { + let error_message = format!("Error handling block {number}: {err}"); + error!(error_message); + + if let Some(alerting_client) = alerting_client { + alerting_client.send_alert(error_message).await; + } +} + +/// Actor death must not leave an orphan holding the durable stream lock. +fn exit_with_parent() -> eyre::Result<()> { + if env::var("FLEET_EXIT_WITH_PARENT").as_deref() != Ok("true") { + return Ok(()); + } + #[cfg(target_os = "linux")] + unsafe { + let parent = libc::getppid(); + eyre::ensure!(parent > 1, "Fleet worker has no live parent"); + if libc::prctl(libc::PR_SET_PDEATHSIG, libc::SIGTERM) != 0 { + return Err(std::io::Error::last_os_error().into()); + } + eyre::ensure!(libc::getppid() == parent, "Fleet parent exited during startup"); + } Ok(()) } diff --git a/bin/eth-proofs/src/state.rs b/bin/eth-proofs/src/state.rs new file mode 100644 index 0000000..3cb4146 --- /dev/null +++ b/bin/eth-proofs/src/state.rs @@ -0,0 +1,410 @@ +//! Restart-safe state for a single, machine-pinned EthProofs stream. +use eyre::{bail, Context}; +use fs2::FileExt; +use serde::{Deserialize, Serialize}; +use serde_json::Value; +use sha2::{Digest, Sha256}; +use std::{ + fs::{self, File, OpenOptions}, + io::Write, + path::{Path, PathBuf}, + sync::Mutex, +}; + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +pub struct Identity { + pub namespace: String, + pub tenant: String, + pub chain_id: u64, + pub cluster_id: u64, + pub elf_id: String, + pub interval: u64, + pub residue: u64, +} +#[derive(Debug, Clone, Serialize, Deserialize)] +struct Checkpoint { + version: u32, + identity: Identity, + next_block: Option, + last_proved: Option, +} +#[derive(Debug, Serialize, Deserialize)] +struct Committed { + block: u64, + proof_hash: String, + public_values_hash: String, + report: Value, +} +pub struct State { + root: PathBuf, + _lock: File, + checkpoint: Mutex, + report_ready: tokio::sync::Notify, +} +impl State { + pub fn open(root: &Path, identity: Identity, start: Option) -> eyre::Result { + if identity.interval == 0 || identity.residue >= identity.interval { + bail!("invalid block interval or residue"); + } + if start.is_some_and(|n| n % identity.interval != identity.residue) { + bail!("start block does not belong to this stream's residue"); + } + fs::create_dir_all(root)?; + let lock = OpenOptions::new() + .create(true) + .truncate(false) + .read(true) + .write(true) + .open(root.join("worker.lock"))?; + lock.try_lock_exclusive().wrap_err("another worker owns this storage root")?; + for name in ["inputs", "outputs", "outbox", "reported"] { + fs::create_dir_all(root.join(name))?; + } + let path = root.join("checkpoint.json"); + let checkpoint = if path.exists() { + let checkpoint: Checkpoint = serde_json::from_slice(&fs::read(path)?)?; + if checkpoint.version != 1 || checkpoint.identity != identity { + bail!("worker state identity differs from configured chain, cluster, program or stream"); + } + checkpoint + } else { + Checkpoint { version: 1, identity, next_block: start, last_proved: None } + }; + let state = Self { + root: fs::canonicalize(root)?, + _lock: lock, + checkpoint: Mutex::new(checkpoint), + report_ready: tokio::sync::Notify::new(), + }; + state.save_checkpoint()?; + state.recover_reports()?; + Ok(state) + } + fn save_checkpoint(&self) -> eyre::Result<()> { + atomic_write( + &self.root.join("checkpoint.json"), + &serde_json::to_vec(&*self.checkpoint.lock().unwrap())?, + ) + } + pub fn next_block(&self) -> Option { + self.checkpoint.lock().unwrap().next_block + } + pub fn initialize(&self, block: u64) -> eyre::Result<()> { + { + let mut c = self.checkpoint.lock().unwrap(); + if c.next_block.is_none() { + c.next_block = Some(block); + } + } + self.save_checkpoint() + } + pub fn advance(&self, block: u64, proved: bool) -> eyre::Result<()> { + { + let mut c = self.checkpoint.lock().unwrap(); + if c.next_block != Some(block) { + bail!("refusing to advance out of order"); + } + c.next_block = Some( + block + .checked_add(c.identity.interval) + .ok_or_else(|| eyre::eyre!("block cursor overflow"))?, + ); + if proved { + c.last_proved = Some(block); + } + } + self.save_checkpoint()?; + let input = self.root.join("inputs").join(format!("{block}.bin")); + if input.exists() { + fs::remove_file(input)?; + } + let hash = self.root.join("inputs").join(format!("{block}.sha256")); + if hash.exists() { + fs::remove_file(hash)?; + } + sync_dir(&self.root.join("inputs"))?; + Ok(()) + } + + /// Skip unproved input backlog without changing completed outputs or reports. + pub fn skip_to(&self, block: u64) -> eyre::Result<()> { + { + let mut c = self.checkpoint.lock().unwrap(); + let next = c.next_block.ok_or_else(|| eyre::eyre!("cursor is not initialized"))?; + if block < next || block % c.identity.interval != c.identity.residue { + bail!("refusing to skip backwards or outside the selected residue"); + } + c.next_block = Some(block); + } + self.save_checkpoint()?; + for entry in fs::read_dir(self.root.join("inputs"))? { + let path = entry?.path(); + if path + .file_stem() + .and_then(|s| s.to_str()) + .and_then(|s| s.parse::().ok()) + .is_some_and(|number| number < block) + { + fs::remove_file(path)?; + } + } + sync_dir(&self.root.join("inputs")) + } + pub fn input(&self, block: u64) -> eyre::Result>> { + let p = self.root.join("inputs").join(format!("{block}.bin")); + if !p.exists() { + return Ok(None); + } + let bytes = fs::read(p)?; + let hash = fs::read_to_string(self.root.join("inputs").join(format!("{block}.sha256")))?; + if digest(&bytes) != hash { + bail!("prepared input checksum mismatch"); + } + Ok(Some(bytes)) + } + pub fn save_input(&self, block: u64, bytes: &[u8]) -> eyre::Result<()> { + // A partial write can always be prepared again; the binary is published last. + atomic_write( + &self.root.join("inputs").join(format!("{block}.sha256")), + digest(bytes).as_bytes(), + )?; + atomic_write(&self.root.join("inputs").join(format!("{block}.bin")), bytes) + } + pub fn commit( + &self, + block: u64, + proof: &[u8], + public_values: &[u8], + report: Value, + ) -> eyre::Result<()> { + let dir = self.root.join("outputs").join(block.to_string()); + fs::create_dir_all(&dir)?; + sync_dir(&self.root.join("outputs"))?; + atomic_write(&dir.join("proof.bin"), proof)?; + atomic_write(&dir.join("public_values.bin"), public_values)?; + let committed = Committed { + block, + proof_hash: digest(proof), + public_values_hash: digest(public_values), + report, + }; + atomic_write(&dir.join("manifest.json"), &serde_json::to_vec(&committed)?)?; + self.ensure_report(&committed)?; + self.report_ready.notify_one(); + Ok(()) + } + pub fn is_committed(&self, block: u64) -> eyre::Result { + let dir = self.root.join("outputs").join(block.to_string()); + if !dir.join("manifest.json").exists() { + return Ok(false); + } + let m: Committed = serde_json::from_slice(&fs::read(dir.join("manifest.json"))?)?; + if m.block != block || + digest(&fs::read(dir.join("proof.bin"))?) != m.proof_hash || + digest(&fs::read(dir.join("public_values.bin"))?) != m.public_values_hash + { + bail!("committed output checksum mismatch"); + } + self.ensure_report(&m)?; + Ok(true) + } + fn ensure_report(&self, m: &Committed) -> eyre::Result<()> { + if !self.root.join("reported").join(format!("{}.json", m.block)).exists() { + let path = self.root.join("outbox").join(format!("{}.json", m.block)); + if !path.exists() { + atomic_write(&path, &serde_json::to_vec(&m.report)?)?; + } + } + Ok(()) + } + fn recover_reports(&self) -> eyre::Result<()> { + // Only the current block can be committed before its outbox/cursor write. + // Earlier blocks advanced only after both were persisted. + if let Some(block) = self.next_block() { + self.is_committed(block)?; + } + Ok(()) + } + pub fn discard_inputs_from(&self, block: u64) -> eyre::Result<()> { + for entry in fs::read_dir(self.root.join("inputs"))? { + let path = entry?.path(); + if path + .file_stem() + .and_then(|s| s.to_str()) + .and_then(|s| s.parse::().ok()) + .is_some_and(|n| n >= block) + { + fs::remove_file(path)?; + } + } + sync_dir(&self.root.join("inputs")) + } + pub async fn report_ready(&self) { + self.report_ready.notified().await; + } + pub fn pending_count(&self) -> eyre::Result { + Ok(fs::read_dir(self.root.join("outbox"))? + .filter_map(Result::ok) + .filter(|e| e.path().extension().and_then(|s| s.to_str()) == Some("json")) + .count()) + } + pub fn pending(&self) -> eyre::Result> { + let mut blocks = Vec::new(); + for entry in fs::read_dir(self.root.join("outbox"))? { + let path = entry?.path(); + if path.extension().and_then(|s| s.to_str()) != Some("json") { + continue; + } + blocks.push(path.file_stem().unwrap().to_str().unwrap().parse::()?); + } + blocks.sort_unstable(); + let mut pending = Vec::new(); + // Load one proof at a time so an API outage cannot inflate reporter memory. + if let Some(block) = blocks.first() { + pending.push(( + *block, + serde_json::from_slice(&fs::read( + self.root.join("outbox").join(format!("{block}.json")), + )?)?, + )); + } + Ok(pending) + } + pub fn acknowledge(&self, block: u64) -> eyre::Result<()> { + let source = self.root.join("outbox").join(format!("{block}.json")); + if source.exists() { + fs::rename(source, self.root.join("reported").join(format!("{block}.json")))?; + sync_dir(&self.root.join("reported"))?; + sync_dir(&self.root.join("outbox"))?; + } + Ok(()) + } +} +pub fn atomic_write(path: &Path, bytes: &[u8]) -> eyre::Result<()> { + let temp = path.with_extension("tmp"); + let mut file = OpenOptions::new().create(true).truncate(true).write(true).open(&temp)?; + file.write_all(bytes)?; + file.sync_all()?; + fs::rename(&temp, path)?; + sync_dir(path.parent().unwrap()) +} +fn sync_dir(path: &Path) -> eyre::Result<()> { + File::open(path)?.sync_all()?; + Ok(()) +} +fn digest(bytes: &[u8]) -> String { + hex::encode(Sha256::digest(bytes)) +} + +#[cfg(test)] +mod tests { + use super::*; + fn identity() -> Identity { + Identity { + namespace: "test".into(), + tenant: "ethproofs".into(), + chain_id: 1, + cluster_id: 8, + elf_id: "abc".into(), + interval: 1, + residue: 0, + } + } + #[test] + fn skip_preserves_completed_proofs_reports_and_restart_cursor() { + let root = tempfile::tempdir().unwrap(); + let state = State::open(root.path(), identity(), Some(10)).unwrap(); + state.commit(10, b"proof", b"values", serde_json::json!({"block_number":10})).unwrap(); + state.advance(10, true).unwrap(); + state.save_input(11, b"stale").unwrap(); + state.save_input(20, b"latest").unwrap(); + state.skip_to(20).unwrap(); + assert!(state.input(11).unwrap().is_none()); + assert_eq!(state.input(20).unwrap().unwrap(), b"latest"); + assert!(state.is_committed(10).unwrap()); + assert_eq!(state.pending_count().unwrap(), 1); + assert!(state.skip_to(19).is_err()); + drop(state); + let state = State::open(root.path(), identity(), None).unwrap(); + assert_eq!(state.next_block(), Some(20)); + assert_eq!(state.checkpoint.lock().unwrap().last_proved, Some(10)); + assert_eq!(state.pending_count().unwrap(), 1); + } + + #[test] + fn skip_rejects_a_block_outside_the_stream_residue() { + let root = tempfile::tempdir().unwrap(); + let mut scope = identity(); + scope.interval = 2; + scope.residue = 1; + let state = State::open(root.path(), scope, Some(11)).unwrap(); + assert!(state.skip_to(20).is_err()); + assert_eq!(state.next_block(), Some(11)); + } + #[test] + fn restart_recovers_proof_and_pending_report_without_reproving() { + let root = tempfile::tempdir().unwrap(); + let state = State::open(root.path(), identity(), Some(10)).unwrap(); + state.save_input(10, b"input").unwrap(); + state.commit(10, b"proof", b"values", serde_json::json!({"block_number":10})).unwrap(); + // Simulate the window after output commit, before cursor advancement. + fs::remove_file(root.path().join("outbox/10.json")).unwrap(); + drop(state); + let state = State::open(root.path(), identity(), None).unwrap(); + assert!(state.is_committed(10).unwrap()); + assert_eq!(state.pending().unwrap().len(), 1); + state.advance(10, true).unwrap(); + state.acknowledge(10).unwrap(); + drop(state); + let state = State::open(root.path(), identity(), None).unwrap(); + assert_eq!(state.next_block(), Some(11)); + assert!(state.pending().unwrap().is_empty()); + assert!(state.input(10).unwrap().is_none()); + } + #[test] + fn duplicate_owner_and_changed_program_are_rejected() { + let root = tempfile::tempdir().unwrap(); + let state = State::open(root.path(), identity(), Some(10)).unwrap(); + assert!(State::open(root.path(), identity(), None).is_err()); + drop(state); + let mut changed = identity(); + changed.elf_id = "other".into(); + assert!(State::open(root.path(), changed, None).is_err()); + } + #[test] + fn corrupted_input_or_output_is_not_reused() { + let root = tempfile::tempdir().unwrap(); + let state = State::open(root.path(), identity(), Some(10)).unwrap(); + state.save_input(10, b"input").unwrap(); + fs::write(root.path().join("inputs/10.bin"), b"bad").unwrap(); + assert!(state.input(10).is_err()); + state.commit(10, b"proof", b"values", Value::Null).unwrap(); + fs::write(root.path().join("outputs/10/proof.bin"), b"bad").unwrap(); + assert!(state.is_committed(10).is_err()); + assert!(state.advance(11, true).is_err()); + } + + #[test] + fn restart_preserves_prefetch_and_reorg_discards_all_future_inputs() { + let root = tempfile::tempdir().unwrap(); + let state = State::open(root.path(), identity(), Some(10)).unwrap(); + for block in 10..14 { + state.save_input(block, &[block as u8]).unwrap(); + } + state.commit(10, b"proof", b"values", serde_json::json!({"block_number":10})).unwrap(); + state.advance(10, true).unwrap(); + drop(state); + let state = State::open(root.path(), identity(), None).unwrap(); + assert_eq!(state.next_block(), Some(11)); + for block in 11..14 { + assert_eq!(state.input(block).unwrap().unwrap(), [block as u8]); + } + state.discard_inputs_from(11).unwrap(); + assert_eq!(state.next_block(), Some(11)); + for block in 11..14 { + assert!(state.input(block).unwrap().is_none()); + } + assert!(state.is_committed(10).unwrap()); + assert_eq!(state.pending_count().unwrap(), 1); + } +} diff --git a/bin/guest/Cargo.lock b/bin/guest/Cargo.lock index 00f6f4c..26a1a2f 100644 --- a/bin/guest/Cargo.lock +++ b/bin/guest/Cargo.lock @@ -4,9 +4,9 @@ version = 4 [[package]] name = "addchain" -version = "0.2.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e33f6a175ec6a9e0aca777567f9ff7c3deefc255660df887e7fa3585e9801d8" +checksum = "3b2e69442aa5628ea6951fa33e24efe8313f4321a91bd729fc2f75bdfc858570" dependencies = [ "num-bigint 0.3.3", "num-integer", @@ -33,9 +33,9 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "alloy-chains" -version = "0.2.34" +version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84e0378e959aa6a885897522080a990e80eb317f1e9a222a604492ea50e13096" +checksum = "35d744058a9daa51a8cf22a3009607498fcf82d3cf4c5444dd8056cdf651f471" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -46,16 +46,41 @@ dependencies = [ [[package]] name = "alloy-consensus" -version = "1.8.3" +version = "1.0.41" +source = "git+https://github.com/ziren-patches/alloy?branch=patch-1.0.41#08557d4e5f4ca766194a45c1925d8f1625258793" +dependencies = [ + "alloy-eips 1.0.41", + "alloy-primitives", + "alloy-rlp", + "alloy-serde 1.0.41", + "alloy-trie", + "alloy-tx-macros 1.0.41", + "auto_impl", + "c-kzg", + "derive_more", + "either", + "k256", + "once_cell", + "rand 0.8.5", + "secp256k1", + "serde", + "serde_json", + "serde_with", + "thiserror 2.0.17", +] + +[[package]] +name = "alloy-consensus" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f16daaf7e1f95f62c6c3bf8a3fc3d78b08ae9777810c0bb5e94966c7cd57ef0" +checksum = "2e318e25fb719e747a7e8db1654170fc185024f3ed5b10f86c08d448a912f6e2" dependencies = [ - "alloy-eips", + "alloy-eips 1.1.3", "alloy-primitives", "alloy-rlp", - "alloy-serde", + "alloy-serde 1.1.3", "alloy-trie", - "alloy-tx-macros", + "alloy-tx-macros 1.1.3", "auto_impl", "borsh", "c-kzg", @@ -63,25 +88,25 @@ dependencies = [ "either", "k256", "once_cell", - "rand 0.8.6", + "rand 0.8.5", "secp256k1", "serde", "serde_json", "serde_with", - "thiserror 2.0.18", + "thiserror 2.0.17", ] [[package]] name = "alloy-consensus-any" -version = "1.8.3" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "118998d9015332ab1b4720ae1f1e3009491966a0349938a1f43ff45a8a4c6299" +checksum = "364380a845193a317bcb7a5398fc86cdb66c47ebe010771dde05f6869bf9e64a" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 1.1.3", + "alloy-eips 1.1.3", "alloy-primitives", "alloy-rlp", - "alloy-serde", + "alloy-serde 1.1.3", "serde", ] @@ -95,7 +120,7 @@ dependencies = [ "alloy-rlp", "crc", "serde", - "thiserror 2.0.18", + "thiserror 2.0.17", ] [[package]] @@ -122,36 +147,42 @@ dependencies = [ "k256", "serde", "serde_with", - "thiserror 2.0.18", + "thiserror 2.0.17", ] [[package]] -name = "alloy-eip7928" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b827a6d7784fe3eb3489d40699407a4cdcce74271421a01bdffe60cf573bb16" +name = "alloy-eips" +version = "1.0.41" +source = "git+https://github.com/ziren-patches/alloy?branch=patch-1.0.41#08557d4e5f4ca766194a45c1925d8f1625258793" dependencies = [ + "alloy-eip2124", + "alloy-eip2930", + "alloy-eip7702", "alloy-primitives", "alloy-rlp", - "borsh", - "once_cell", + "alloy-serde 1.0.41", + "auto_impl", + "c-kzg", + "derive_more", + "either", "serde", - "thiserror 2.0.18", + "serde_with", + "sha2", + "thiserror 2.0.17", ] [[package]] name = "alloy-eips" -version = "1.8.3" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ef28c9fdad22d4eec52d894f5f2673a0895f1e5ef196734568e68c0f6caca8" +checksum = "a4c4d7c5839d9f3a467900c625416b24328450c65702eb3d8caff8813e4d1d33" dependencies = [ "alloy-eip2124", "alloy-eip2930", "alloy-eip7702", - "alloy-eip7928", "alloy-primitives", "alloy-rlp", - "alloy-serde", + "alloy-serde 1.1.3", "auto_impl", "borsh", "c-kzg", @@ -160,6 +191,7 @@ dependencies = [ "serde", "serde_with", "sha2", + "thiserror 2.0.17", ] [[package]] @@ -168,26 +200,26 @@ version = "0.23.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "527b47dc39850c6168002ddc1f7a2063e15d26137c1bb5330f6065a7524c1aa9" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 1.1.3", + "alloy-eips 1.1.3", "alloy-hardforks", "alloy-primitives", "alloy-sol-types", "auto_impl", "derive_more", "revm", - "thiserror 2.0.18", + "thiserror 2.0.17", ] [[package]] name = "alloy-genesis" -version = "1.8.3" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbf9480307b09d22876efb67d30cadd9013134c21f3a17ec9f93fd7536d38024" +checksum = "1ba4b1be0988c11f0095a2380aa596e35533276b8fa6c9e06961bbfe0aebcac5" dependencies = [ - "alloy-eips", + "alloy-eips 1.1.3", "alloy-primitives", - "alloy-serde", + "alloy-serde 1.1.3", "alloy-trie", "borsh", "serde", @@ -196,9 +228,9 @@ dependencies = [ [[package]] name = "alloy-hardforks" -version = "0.4.7" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83ba208044232d14d4adbfa77e57d6329f51bc1acc21f5667bb7db72d88a0831" +checksum = "2d9a33550fc21fd77a3f8b63e99969d17660eec8dcc50a95a80f7c9964f7680b" dependencies = [ "alloy-chains", "alloy-eip2124", @@ -221,34 +253,34 @@ dependencies = [ [[package]] name = "alloy-json-rpc" -version = "1.8.3" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "422d110f1c40f1f8d0e5562b0b649c35f345fccb7093d9f02729943dcd1eef71" +checksum = "f72cf87cda808e593381fb9f005ffa4d2475552b7a6c5ac33d087bf77d82abd0" dependencies = [ "alloy-primitives", "alloy-sol-types", "http", "serde", "serde_json", - "thiserror 2.0.18", + "thiserror 2.0.17", "tracing", ] [[package]] name = "alloy-network" -version = "1.8.3" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7197a66d94c4de1591cdc16a9bcea5f8cccd0da81b865b49aef97b1b4016e0fa" +checksum = "12aeb37b6f2e61b93b1c3d34d01ee720207c76fe447e2a2c217e433ac75b17f5" dependencies = [ - "alloy-consensus", + "alloy-consensus 1.1.3", "alloy-consensus-any", - "alloy-eips", + "alloy-eips 1.1.3", "alloy-json-rpc", "alloy-network-primitives", "alloy-primitives", "alloy-rpc-types-any", "alloy-rpc-types-eth", - "alloy-serde", + "alloy-serde 1.1.3", "alloy-signer", "alloy-sol-types", "async-trait", @@ -257,41 +289,41 @@ dependencies = [ "futures-utils-wasm", "serde", "serde_json", - "thiserror 2.0.18", + "thiserror 2.0.17", ] [[package]] name = "alloy-network-primitives" -version = "1.8.3" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb82711d59a43fdfd79727c99f270b974c784ec4eb5728a0d0d22f26716c87ef" +checksum = "abd29ace62872083e30929cd9b282d82723196d196db589f3ceda67edcc05552" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 1.1.3", + "alloy-eips 1.1.3", "alloy-primitives", - "alloy-serde", + "alloy-serde 1.1.3", "serde", ] [[package]] name = "alloy-primitives" version = "1.4.1" -source = "git+https://github.com/ziren-patches/core.git?branch=patch-alloy-primitives-1.4.1#59313700f710f1373a5b4cdc05c51dc3227d8064" +source = "git+https://github.com/ziren-patches/core.git?branch=patch-alloy-primitives-1.4.1-hasher#8846a1c3b6f6595020ab4189034a6f463ffbffc7" dependencies = [ "alloy-rlp", "bytes", "cfg-if", "const-hex", "derive_more", - "foldhash 0.2.0", + "foldhash", "hashbrown 0.16.1", - "indexmap 2.14.0", + "indexmap 2.12.1", "itoa", "k256", "keccak-asm", "paste", "proptest", - "rand 0.9.4", + "rand 0.9.2", "ruint", "rustc-hash", "serde", @@ -302,9 +334,9 @@ dependencies = [ [[package]] name = "alloy-rlp" -version = "0.3.15" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc90b1e703d3c03f4ff7f48e82dd0bc1c8211ab7d079cd836a06fcfeb06651cb" +checksum = "5f70d83b765fdc080dbcd4f4db70d8d23fe4761f2f02ebfa9146b833900634b4" dependencies = [ "alloy-rlp-derive", "arrayvec", @@ -313,43 +345,43 @@ dependencies = [ [[package]] name = "alloy-rlp-derive" -version = "0.3.15" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f36834a5c0a2fa56e171bf256c34d70fca07d0c0031583edea1c4946b7889c9e" +checksum = "64b728d511962dda67c1bc7ea7c03736ec275ed2cf4c35d9585298ac9ccf3b73" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] name = "alloy-rpc-types" -version = "1.8.3" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4faad925d3a669ffc15f43b3deec7fbdf2adeb28a4d6f9cf4bc661698c0f8f4b" +checksum = "39cf1398cb33aacb139a960fa3d8cf8b1202079f320e77e952a0b95967bf7a9f" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", - "alloy-serde", + "alloy-serde 1.1.3", "serde", ] [[package]] name = "alloy-rpc-types-any" -version = "1.8.3" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3823026d1ed239a40f12364fac50726c8daf1b6ab8077a97212c5123910429ed" +checksum = "6a63fb40ed24e4c92505f488f9dd256e2afaed17faa1b7a221086ebba74f4122" dependencies = [ "alloy-consensus-any", "alloy-rpc-types-eth", - "alloy-serde", + "alloy-serde 1.1.3", ] [[package]] name = "alloy-rpc-types-debug" -version = "1.8.3" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2145138f3214928f08cd13da3cb51ef7482b5920d8ac5a02ecd4e38d1a8f6d1e" +checksum = "4936f579d9d10eae01772b2ab3497f9d568684f05f26f8175e12f9a1a2babc33" dependencies = [ "alloy-primitives", "derive_more", @@ -359,12 +391,12 @@ dependencies = [ [[package]] name = "alloy-rpc-types-engine" -version = "1.8.3" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb9b97b6e7965679ad22df297dda809b11cebc13405c1b537e5cffecc95834fa" +checksum = "4c60bdce3be295924122732b7ecd0b2495ce4790bedc5370ca7019c08ad3f26e" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 1.1.3", + "alloy-eips 1.1.3", "alloy-primitives", "alloy-rlp", "derive_more", @@ -373,30 +405,40 @@ dependencies = [ [[package]] name = "alloy-rpc-types-eth" -version = "1.8.3" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59c095f92c4e1ff4981d89e9aa02d5f98c762a1980ab66bec49c44be11349da2" +checksum = "9eae0c7c40da20684548cbc8577b6b7447f7bf4ddbac363df95e3da220e41e72" dependencies = [ - "alloy-consensus", + "alloy-consensus 1.1.3", "alloy-consensus-any", - "alloy-eips", + "alloy-eips 1.1.3", "alloy-network-primitives", "alloy-primitives", "alloy-rlp", - "alloy-serde", + "alloy-serde 1.1.3", "alloy-sol-types", "itertools 0.14.0", "serde", "serde_json", "serde_with", - "thiserror 2.0.18", + "thiserror 2.0.17", +] + +[[package]] +name = "alloy-serde" +version = "1.0.41" +source = "git+https://github.com/ziren-patches/alloy?branch=patch-1.0.41#08557d4e5f4ca766194a45c1925d8f1625258793" +dependencies = [ + "alloy-primitives", + "serde", + "serde_json", ] [[package]] name = "alloy-serde" -version = "1.8.3" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11ece63b89294b8614ab3f483560c08d016930f842bf36da56bf0b764a15c11e" +checksum = "c0df1987ed0ff2d0159d76b52e7ddfc4e4fbddacc54d2fbee765e0d14d7c01b5" dependencies = [ "alloy-primitives", "serde", @@ -405,9 +447,9 @@ dependencies = [ [[package]] name = "alloy-signer" -version = "1.8.3" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43f447aefab0f1c0649f71edc33f590992d4e122bc35fb9cdbbf67d4421ace85" +checksum = "6ff69deedee7232d7ce5330259025b868c5e6a52fa8dffda2c861fb3a5889b24" dependencies = [ "alloy-primitives", "async-trait", @@ -415,46 +457,46 @@ dependencies = [ "either", "elliptic-curve", "k256", - "thiserror 2.0.18", + "thiserror 2.0.17", ] [[package]] name = "alloy-sol-macro" -version = "1.5.7" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab81bab693da9bb79f7a95b64b394718259fdd7e41dceeced4cad57cb71c4f6a" +checksum = "f3ce480400051b5217f19d6e9a82d9010cdde20f1ae9c00d53591e4a1afbb312" dependencies = [ "alloy-sol-macro-expander", "alloy-sol-macro-input", "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] name = "alloy-sol-macro-expander" -version = "1.5.7" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "489f1620bb7e2483fb5819ed01ab6edc1d2f93939dce35a5695085a1afd1d699" +checksum = "6d792e205ed3b72f795a8044c52877d2e6b6e9b1d13f431478121d8d4eaa9028" dependencies = [ "alloy-sol-macro-input", "const-hex", "heck", - "indexmap 2.14.0", + "indexmap 2.12.1", "proc-macro-error2", "proc-macro2", "quote", - "sha3", - "syn 2.0.117", + "syn 2.0.111", "syn-solidity", + "tiny-keccak", ] [[package]] name = "alloy-sol-macro-input" -version = "1.5.7" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56cef806ad22d4392c5fc83cf8f2089f988eb99c7067b4e0c6f1971fc1cca318" +checksum = "0bd1247a8f90b465ef3f1207627547ec16940c35597875cdc09c49d58b19693c" dependencies = [ "const-hex", "dunce", @@ -462,18 +504,18 @@ dependencies = [ "macro-string", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", "syn-solidity", ] [[package]] name = "alloy-sol-type-parser" -version = "1.5.7" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6df77fea9d6a2a75c0ef8d2acbdfd92286cc599983d3175ccdc170d3433d249" +checksum = "954d1b2533b9b2c7959652df3076954ecb1122a28cc740aa84e7b0a49f6ac0a9" dependencies = [ "serde", - "winnow 0.7.15", + "winnow", ] [[package]] @@ -490,30 +532,42 @@ dependencies = [ [[package]] name = "alloy-trie" -version = "0.9.5" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f14b5d9b2c2173980202c6ff470d96e7c5e202c65a9f67884ad565226df7fbb" +checksum = "e3412d52bb97c6c6cc27ccc28d4e6e8cf605469101193b50b0bd5813b1f990b5" dependencies = [ "alloy-primitives", "alloy-rlp", + "arrayvec", "derive_more", "nybbles", "serde", "smallvec", - "thiserror 2.0.18", "tracing", ] [[package]] name = "alloy-tx-macros" -version = "1.8.3" +version = "1.0.41" +source = "git+https://github.com/ziren-patches/alloy?branch=patch-1.0.41#08557d4e5f4ca766194a45c1925d8f1625258793" +dependencies = [ + "alloy-primitives", + "darling", + "proc-macro2", + "quote", + "syn 2.0.111", +] + +[[package]] +name = "alloy-tx-macros" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d69722eddcdf1ce096c3ab66cf8116999363f734eb36fe94a148f4f71c85da84" +checksum = "333544408503f42d7d3792bfc0f7218b643d968a03d2c0ed383ae558fb4a76d0" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] @@ -525,12 +579,6 @@ dependencies = [ "libc", ] -[[package]] -name = "anyhow" -version = "1.0.102" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" - [[package]] name = "ark-bls12-381" version = "0.5.0" @@ -660,7 +708,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" dependencies = [ "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] @@ -698,7 +746,7 @@ dependencies = [ "num-traits", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] @@ -758,7 +806,7 @@ checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] @@ -768,7 +816,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1df2c09229cbc5a028b1d70e00fdb2acee28b1055dfb5ca73eea49c5a25c4e7c" dependencies = [ "num-traits", - "rand 0.8.6", + "rand 0.8.5", ] [[package]] @@ -778,7 +826,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" dependencies = [ "num-traits", - "rand 0.8.6", + "rand 0.8.5", ] [[package]] @@ -788,7 +836,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "246a225cc6131e9ee4f24619af0f19d67761fff15d7ccc22e42b80846e69449a" dependencies = [ "num-traits", - "rand 0.8.6", + "rand 0.8.5", ] [[package]] @@ -802,6 +850,9 @@ name = "arrayvec" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +dependencies = [ + "serde", +] [[package]] name = "async-trait" @@ -811,7 +862,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] @@ -832,7 +883,7 @@ checksum = "ffdcb70bdbc4d478427380519163274ac86e52916e10f0a8889adf0f96d3fee7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] @@ -855,9 +906,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" -version = "1.8.3" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" +checksum = "0e050f626429857a27ddccb31e0aca21356bfa709c04041aefddac081a8f068a" [[package]] name = "bincode" @@ -901,9 +952,9 @@ dependencies = [ [[package]] name = "bitflags" -version = "2.11.1" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" dependencies = [ "serde_core", ] @@ -921,6 +972,19 @@ dependencies = [ "wyz", ] +[[package]] +name = "blake3" +version = "1.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d9e454fc11f76977dc803893aff6304ed33d6a26efae8696573bea74baa27ae" +dependencies = [ + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", + "cpufeatures 0.3.1", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -936,8 +1000,10 @@ version = "0.8.0" source = "git+https://github.com/ziren-patches/bls12_381?branch=patch-0.8.0#bcf9397426410acc171ad625416b508dc913be8e" dependencies = [ "cfg-if", + "digest 0.10.7", "ff", "group", + "hex", "pairing", "rand_core 0.6.4", "subtle", @@ -958,42 +1024,32 @@ dependencies = [ [[package]] name = "borsh" -version = "1.6.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfd1e3f8955a5d7de9fab72fc8373fade9fb8a703968cb200ae3dc6cf08e185a" +checksum = "d1da5ab77c1437701eeff7c88d968729e7766172279eab0676857b3d63af7a6f" dependencies = [ "borsh-derive", - "bytes", "cfg_aliases", ] [[package]] name = "borsh-derive" -version = "1.6.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfcfdc083699101d5a7965e49925975f2f55060f94f9a05e7187be95d530ca59" +checksum = "0686c856aa6aac0c4498f936d7d6a02df690f614c03e4d906d1018062b5c5e2c" dependencies = [ "once_cell", "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.117", -] - -[[package]] -name = "bs58" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" -dependencies = [ - "tinyvec", + "syn 2.0.111", ] [[package]] name = "bumpalo" -version = "3.20.2" +version = "3.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" +checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" [[package]] name = "byte-slice-cast" @@ -1003,9 +1059,9 @@ checksum = "7575182f7272186991736b70173b0ea045398f984bf5ebbb3804736ce1330c9d" [[package]] name = "bytemuck" -version = "1.25.0" +version = "1.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" +checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" dependencies = [ "bytemuck_derive", ] @@ -1018,7 +1074,7 @@ checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] @@ -1029,18 +1085,18 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.11.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" +checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" dependencies = [ "serde", ] [[package]] name = "c-kzg" -version = "2.1.7" +version = "2.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6648ed1e4ea8e8a1a4a2c78e1cda29a3fd500bc622899c340d8525ea9a76b24a" +checksum = "e00bf4b112b07b505472dbefd19e37e53307e2bfed5a79e0cc161d58ccd0e687" dependencies = [ "blst", "cc", @@ -1053,9 +1109,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.62" +version = "1.2.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1dce859f0832a7d088c4f1119888ab94ef4b5d6795d1ce05afb7fe159d79f98" +checksum = "90583009037521a116abf44494efecd645ba48b6622457080f080b85544e2215" dependencies = [ "find-msvc-tools", "jobserver", @@ -1077,9 +1133,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chrono" -version = "0.4.44" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" +checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" dependencies = [ "iana-time-zone", "num-traits", @@ -1089,12 +1145,12 @@ dependencies = [ [[package]] name = "const-hex" -version = "1.19.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20d9a563d167a9cce0f94153382b33cb6eded6dfabff03c69ad65a28ea1514e0" +checksum = "3bb320cac8a0750d7f25280aa97b09c26edfe161164238ecbbb31092b079e735" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "proptest", "serde_core", ] @@ -1107,12 +1163,11 @@ checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "const_format" -version = "0.2.36" +version = "0.2.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4481a617ad9a412be3b97c5d403fef8ed023103368908b9c50af598ff467cc1e" +checksum = "7faa7469a93a566e9ccc1c73fe783b4a65c274c5ace346038dca9c39fe0030ad" dependencies = [ "const_format_proc_macros", - "konst", ] [[package]] @@ -1126,6 +1181,12 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "constant_time_eq" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" + [[package]] name = "convert_case" version = "0.10.0" @@ -1150,6 +1211,15 @@ dependencies = [ "libc", ] +[[package]] +name = "cpufeatures" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ca28b0ae3115b884660db4118d803791fd6756b6e88f39c0f3f7859060d7566" +dependencies = [ + "libc", +] + [[package]] name = "crc" version = "3.4.0" @@ -1161,9 +1231,9 @@ dependencies = [ [[package]] name = "crc-catalog" -version = "2.5.0" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "217698eaf96b4a3f0bc4f3662aaa55bdf913cd54d7204591faa790070c6d0853" +checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" [[package]] name = "critical-section" @@ -1226,9 +1296,9 @@ dependencies = [ [[package]] name = "darling" -version = "0.23.0" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" +checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" dependencies = [ "darling_core", "darling_macro", @@ -1236,27 +1306,28 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.23.0" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" +checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" dependencies = [ + "fnv", "ident_case", "proc-macro2", "quote", "serde", "strsim", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] name = "darling_macro" -version = "0.23.0" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" +checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" dependencies = [ "darling_core", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] @@ -1271,9 +1342,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.5.8" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" +checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" dependencies = [ "powerfmt", "serde_core", @@ -1292,35 +1363,35 @@ dependencies = [ [[package]] name = "derive-where" -version = "1.6.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d08b3a0bcc0d079199cd476b2cae8435016ec11d1c0986c6901c5ac223041534" +checksum = "ef941ded77d15ca19b40374869ac6000af1c9f2a4c0f3d4c70926287e6364a8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] name = "derive_more" -version = "2.1.1" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d751e9e49156b02b44f9c1815bcb94b984cdcc4396ecc32521c739452808b134" +checksum = "10b768e943bed7bf2cab53df09f4bc34bfd217cdb57d971e769874c9a6710618" dependencies = [ "derive_more-impl", ] [[package]] name = "derive_more-impl" -version = "2.1.1" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799a97264921d8623a957f6c3b9011f3b5492f557bbb7a5a19b7fa6d06ba8dcb" +checksum = "6d286bfdaf75e988b4a78e013ecd79c581e06399ab53fbacd2d916c2f904f30b" dependencies = [ "convert_case", "proc-macro2", "quote", "rustc_version 0.4.1", - "syn 2.0.117", + "syn 2.0.111", "unicode-xid", ] @@ -1353,7 +1424,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] @@ -1391,7 +1462,7 @@ dependencies = [ "enum-ordinalize", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] @@ -1441,7 +1512,7 @@ checksum = "8ca9601fb2d62598ee17836250842873a413586e5d7ed88b356e38ddbb0ec631" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] @@ -1472,9 +1543,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.4.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" [[package]] name = "fastrlp" @@ -1527,9 +1598,9 @@ dependencies = [ [[package]] name = "find-msvc-tools" -version = "0.1.9" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" +checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" [[package]] name = "fixed-hash" @@ -1538,7 +1609,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "835c052cb0c08c1acf6ffd71c022172e18723949c8282f2b9f27efbc51e64534" dependencies = [ "byteorder", - "rand 0.8.6", + "rand 0.8.5", "rustc-hex", "static_assertions", ] @@ -1549,12 +1620,6 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" -[[package]] -name = "foldhash" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" - [[package]] name = "foldhash" version = "0.2.0" @@ -1578,26 +1643,26 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures-core" -version = "0.3.32" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-task" -version = "0.3.32" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-util" -version = "0.3.32" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-core", "futures-task", "pin-project-lite", - "slab", + "pin-utils", ] [[package]] @@ -1606,12 +1671,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42012b0f064e01aa58b545fe3727f90f7dd4020f4a3ea735b50344965f5a57e9" -[[package]] -name = "gcd" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a" - [[package]] name = "generic-array" version = "0.14.9" @@ -1625,9 +1684,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.17" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" dependencies = [ "cfg-if", "libc", @@ -1642,23 +1701,10 @@ checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "libc", - "r-efi 5.3.0", + "r-efi", "wasip2", ] -[[package]] -name = "getrandom" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" -dependencies = [ - "cfg-if", - "libc", - "r-efi 6.0.0", - "wasip2", - "wasip3", -] - [[package]] name = "glob" version = "0.3.3" @@ -1680,12 +1726,14 @@ dependencies = [ name = "guest-executor" version = "0.1.0" dependencies = [ - "alloy-consensus", + "alloy-consensus 1.1.3", "alloy-evm", "alloy-network", "alloy-primitives", "alloy-rpc-types", + "aurora-engine-modexp", "bincode", + "bls12_381", "itertools 0.13.0", "kzg-rs", "mpt", @@ -1706,7 +1754,9 @@ dependencies = [ "serde", "serde_json", "serde_with", + "substrate-bn", "thiserror 1.0.69", + "zkm-lib", ] [[package]] @@ -1722,7 +1772,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" dependencies = [ "allocator-api2", - "foldhash 0.1.5", ] [[package]] @@ -1731,17 +1780,11 @@ version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" dependencies = [ - "foldhash 0.2.0", + "foldhash", "serde", "serde_core", ] -[[package]] -name = "hashbrown" -version = "0.17.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" - [[package]] name = "heck" version = "0.5.0" @@ -1799,9 +1842,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.65" +version = "0.1.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -1823,13 +1866,12 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.2.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" dependencies = [ "displaydoc", "potential_utf", - "utf8_iter", "yoke", "zerofrom", "zerovec", @@ -1837,9 +1879,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.2.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" dependencies = [ "displaydoc", "litemap", @@ -1850,9 +1892,9 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.2.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" dependencies = [ "icu_collections", "icu_normalizer_data", @@ -1864,15 +1906,15 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.2.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" [[package]] name = "icu_properties" -version = "2.2.0" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" dependencies = [ "icu_collections", "icu_locale_core", @@ -1884,15 +1926,15 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "2.2.0" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" [[package]] name = "icu_provider" -version = "2.2.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" dependencies = [ "displaydoc", "icu_locale_core", @@ -1903,12 +1945,6 @@ dependencies = [ "zerovec", ] -[[package]] -name = "id-arena" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" - [[package]] name = "ident_case" version = "1.0.1" @@ -1928,9 +1964,9 @@ dependencies = [ [[package]] name = "idna_adapter" -version = "1.2.2" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" dependencies = [ "icu_normalizer", "icu_properties", @@ -1953,7 +1989,7 @@ checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] @@ -1975,12 +2011,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.14.0" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" dependencies = [ "equivalent", - "hashbrown 0.17.1", + "hashbrown 0.16.1", "serde", "serde_core", ] @@ -2014,9 +2050,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.18" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" [[package]] name = "jobserver" @@ -2030,12 +2066,10 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.98" +version = "0.3.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67df7112613f8bfd9150013a0314e196f4800d3201ae742489d999db2f979f08" +checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8" dependencies = [ - "cfg-if", - "futures-util", "once_cell", "wasm-bindgen", ] @@ -2057,38 +2091,23 @@ dependencies = [ [[package]] name = "keccak" -version = "0.1.6" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" dependencies = [ - "cpufeatures", + "cpufeatures 0.2.17", ] [[package]] name = "keccak-asm" -version = "0.1.6" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa468878266ad91431012b3e5ef1bf9b170eab22883503a318d46857afa4579a" +checksum = "505d1856a39b200489082f90d897c3f07c455563880bc5952e38eabf731c83b6" dependencies = [ "digest 0.10.7", "sha3-asm", ] -[[package]] -name = "konst" -version = "0.2.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "128133ed7824fcd73d6e7b17957c5eb7bacb885649bd8c69708b2331a10bcefb" -dependencies = [ - "konst_macro_rules", -] - -[[package]] -name = "konst_macro_rules" -version = "0.2.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4933f3f57a8e9d9da04db23fb153356ecaf00cbd14aee46279c33dc80925c37" - [[package]] name = "kzg-rs" version = "0.2.7" @@ -2099,7 +2118,7 @@ dependencies = [ "hex", "serde_arrays", "sha2", - "spin", + "spin 0.9.8", ] [[package]] @@ -2108,38 +2127,32 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" dependencies = [ - "spin", + "spin 0.9.8", ] -[[package]] -name = "leb128fmt" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" - [[package]] name = "libc" -version = "0.2.186" +version = "0.2.178" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" +checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" [[package]] name = "libm" -version = "0.2.16" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" +checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" [[package]] name = "linux-raw-sys" -version = "0.12.1" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "litemap" -version = "0.8.2" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" [[package]] name = "lock_api" @@ -2164,14 +2177,14 @@ checksum = "1b27834086c65ec3f9387b096d66e99f221cf081c2b738042aa252bcd41204e3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] name = "memchr" -version = "2.8.0" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "modular-bitfield" @@ -2241,7 +2254,6 @@ checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ "num-integer", "num-traits", - "rand 0.8.6", ] [[package]] @@ -2255,9 +2267,9 @@ dependencies = [ [[package]] name = "num-conv" -version = "0.2.1" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" [[package]] name = "num-integer" @@ -2312,9 +2324,9 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.6" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26" +checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c" dependencies = [ "num_enum_derive", "rustversion", @@ -2322,32 +2334,20 @@ dependencies = [ [[package]] name = "num_enum_derive" -version = "0.7.6" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8" +checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", -] - -[[package]] -name = "nums" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf3c74f925fb8cfc49a8022f2afce48a0683b70f9e439885594e84c5edbf5b01" -dependencies = [ - "num-bigint 0.4.6", - "num-integer", - "num-traits", - "rand 0.8.6", + "syn 2.0.111", ] [[package]] name = "nybbles" -version = "0.4.8" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d49ff0c0d00d4a502b39df9af3a525e1efeb14b9dabb5bb83335284c1309210" +checksum = "2c4b5ecbd0beec843101bffe848217f770e8b8da81d8355b7d6e226f2199b3dc" dependencies = [ "alloy-rlp", "cfg-if", @@ -2359,9 +2359,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.21.4" +version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" dependencies = [ "critical-section", "portable-atomic", @@ -2373,15 +2373,15 @@ version = "0.22.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "726da827358a547be9f1e37c2a756b9e3729cb0350f43408164794b370cad8ae" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 1.1.3", + "alloy-eips 1.1.3", "alloy-primitives", "alloy-rlp", - "alloy-serde", + "alloy-serde 1.1.3", "derive_more", "serde", "serde_with", - "thiserror 2.0.18", + "thiserror 2.0.17", ] [[package]] @@ -2397,136 +2397,157 @@ dependencies = [ "zkm-lib", ] +[[package]] +name = "p3-challenger" +version = "0.5.1" +source = "git+https://github.com/ProjectZKM/Plonky3?rev=4dd0d47a8176503fbaa7293c9f0e3b20004e16b2#4dd0d47a8176503fbaa7293c9f0e3b20004e16b2" +dependencies = [ + "p3-field", + "p3-maybe-rayon", + "p3-monty-31", + "p3-symmetric", + "p3-util", + "tracing", +] + [[package]] name = "p3-dft" -version = "0.1.0" -source = "git+https://github.com/ProjectZKM/Plonky3#faa24ca4597eebeecbf71b194b71c7d1a99b3f01" +version = "0.5.1" +source = "git+https://github.com/ProjectZKM/Plonky3?rev=4dd0d47a8176503fbaa7293c9f0e3b20004e16b2#4dd0d47a8176503fbaa7293c9f0e3b20004e16b2" dependencies = [ - "itertools 0.13.0", + "itertools 0.14.0", "p3-field", "p3-matrix", "p3-maybe-rayon", "p3-util", + "spin 0.10.1", "tracing", ] [[package]] name = "p3-field" -version = "0.1.0" -source = "git+https://github.com/ProjectZKM/Plonky3#faa24ca4597eebeecbf71b194b71c7d1a99b3f01" +version = "0.5.1" +source = "git+https://github.com/ProjectZKM/Plonky3?rev=4dd0d47a8176503fbaa7293c9f0e3b20004e16b2#4dd0d47a8176503fbaa7293c9f0e3b20004e16b2" dependencies = [ - "itertools 0.13.0", + "itertools 0.14.0", "num-bigint 0.4.6", - "num-integer", - "num-traits", - "nums", "p3-maybe-rayon", "p3-util", - "rand 0.8.6", + "paste", + "rand 0.10.2", "serde", "tracing", ] [[package]] name = "p3-koala-bear" -version = "0.1.0" -source = "git+https://github.com/ProjectZKM/Plonky3#faa24ca4597eebeecbf71b194b71c7d1a99b3f01" +version = "0.5.1" +source = "git+https://github.com/ProjectZKM/Plonky3?rev=4dd0d47a8176503fbaa7293c9f0e3b20004e16b2#4dd0d47a8176503fbaa7293c9f0e3b20004e16b2" dependencies = [ + "p3-challenger", "p3-field", "p3-mds", "p3-monty-31", + "p3-poseidon1", "p3-poseidon2", "p3-symmetric", - "rand 0.8.6", - "serde", + "rand 0.10.2", ] [[package]] name = "p3-matrix" -version = "0.1.0" -source = "git+https://github.com/ProjectZKM/Plonky3#faa24ca4597eebeecbf71b194b71c7d1a99b3f01" +version = "0.5.1" +source = "git+https://github.com/ProjectZKM/Plonky3?rev=4dd0d47a8176503fbaa7293c9f0e3b20004e16b2#4dd0d47a8176503fbaa7293c9f0e3b20004e16b2" dependencies = [ - "itertools 0.13.0", + "itertools 0.14.0", "p3-field", "p3-maybe-rayon", "p3-util", - "rand 0.8.6", + "rand 0.10.2", "serde", "tracing", - "transpose", ] [[package]] name = "p3-maybe-rayon" -version = "0.1.0" -source = "git+https://github.com/ProjectZKM/Plonky3#faa24ca4597eebeecbf71b194b71c7d1a99b3f01" +version = "0.5.1" +source = "git+https://github.com/ProjectZKM/Plonky3?rev=4dd0d47a8176503fbaa7293c9f0e3b20004e16b2#4dd0d47a8176503fbaa7293c9f0e3b20004e16b2" [[package]] name = "p3-mds" -version = "0.1.0" -source = "git+https://github.com/ProjectZKM/Plonky3#faa24ca4597eebeecbf71b194b71c7d1a99b3f01" +version = "0.5.1" +source = "git+https://github.com/ProjectZKM/Plonky3?rev=4dd0d47a8176503fbaa7293c9f0e3b20004e16b2#4dd0d47a8176503fbaa7293c9f0e3b20004e16b2" dependencies = [ - "itertools 0.13.0", "p3-dft", "p3-field", - "p3-matrix", "p3-symmetric", "p3-util", - "rand 0.8.6", + "rand 0.10.2", ] [[package]] name = "p3-monty-31" -version = "0.1.0" -source = "git+https://github.com/ProjectZKM/Plonky3#faa24ca4597eebeecbf71b194b71c7d1a99b3f01" +version = "0.5.1" +source = "git+https://github.com/ProjectZKM/Plonky3?rev=4dd0d47a8176503fbaa7293c9f0e3b20004e16b2#4dd0d47a8176503fbaa7293c9f0e3b20004e16b2" dependencies = [ - "itertools 0.13.0", + "itertools 0.14.0", "num-bigint 0.4.6", "p3-dft", "p3-field", "p3-matrix", "p3-maybe-rayon", "p3-mds", + "p3-poseidon1", "p3-poseidon2", "p3-symmetric", "p3-util", - "rand 0.8.6", + "paste", + "rand 0.10.2", "serde", - "serde_json", + "spin 0.10.1", "tracing", - "transpose", +] + +[[package]] +name = "p3-poseidon1" +version = "0.5.1" +source = "git+https://github.com/ProjectZKM/Plonky3?rev=4dd0d47a8176503fbaa7293c9f0e3b20004e16b2#4dd0d47a8176503fbaa7293c9f0e3b20004e16b2" +dependencies = [ + "p3-field", + "p3-symmetric", + "rand 0.10.2", ] [[package]] name = "p3-poseidon2" -version = "0.1.0" -source = "git+https://github.com/ProjectZKM/Plonky3#faa24ca4597eebeecbf71b194b71c7d1a99b3f01" +version = "0.5.1" +source = "git+https://github.com/ProjectZKM/Plonky3?rev=4dd0d47a8176503fbaa7293c9f0e3b20004e16b2#4dd0d47a8176503fbaa7293c9f0e3b20004e16b2" dependencies = [ - "gcd", "p3-field", "p3-mds", "p3-symmetric", - "rand 0.8.6", - "serde", + "p3-util", + "rand 0.10.2", ] [[package]] name = "p3-symmetric" -version = "0.1.0" -source = "git+https://github.com/ProjectZKM/Plonky3#faa24ca4597eebeecbf71b194b71c7d1a99b3f01" +version = "0.5.1" +source = "git+https://github.com/ProjectZKM/Plonky3?rev=4dd0d47a8176503fbaa7293c9f0e3b20004e16b2#4dd0d47a8176503fbaa7293c9f0e3b20004e16b2" dependencies = [ - "itertools 0.13.0", + "itertools 0.14.0", "p3-field", + "p3-util", "serde", ] [[package]] name = "p3-util" -version = "0.1.0" -source = "git+https://github.com/ProjectZKM/Plonky3#faa24ca4597eebeecbf71b194b71c7d1a99b3f01" +version = "0.5.1" +source = "git+https://github.com/ProjectZKM/Plonky3?rev=4dd0d47a8176503fbaa7293c9f0e3b20004e16b2#4dd0d47a8176503fbaa7293c9f0e3b20004e16b2" dependencies = [ - "lock_api", "serde", + "transpose", ] [[package]] @@ -2563,7 +2584,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] @@ -2580,9 +2601,9 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pest" -version = "2.8.6" +version = "2.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0848c601009d37dfa3430c4666e147e49cdcf1b92ecd3e63657d8a5f19da662" +checksum = "cbcfd20a6d4eeba40179f05735784ad32bdaef05ce8e8af05f180d45bb3e7e22" dependencies = [ "memchr", "ucd-trie", @@ -2619,7 +2640,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] @@ -2633,9 +2654,15 @@ dependencies = [ [[package]] name = "pin-project-lite" -version = "0.2.17" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pin-utils" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkcs8" @@ -2649,21 +2676,21 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.33" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" [[package]] name = "portable-atomic" -version = "1.13.1" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" +checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" [[package]] name = "potential_utf" -version = "0.1.5" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" dependencies = [ "zerovec", ] @@ -2683,16 +2710,6 @@ dependencies = [ "zerocopy", ] -[[package]] -name = "prettyplease" -version = "0.2.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" -dependencies = [ - "proc-macro2", - "syn 2.0.117", -] - [[package]] name = "primeorder" version = "0.13.1" @@ -2716,7 +2733,7 @@ dependencies = [ name = "primitives" version = "0.1.0" dependencies = [ - "alloy-eips", + "alloy-eips 1.1.3", "alloy-genesis", "alloy-rpc-types", "eyre", @@ -2729,9 +2746,9 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "3.5.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" dependencies = [ "toml_edit", ] @@ -2755,29 +2772,29 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] name = "proc-macro2" -version = "1.0.106" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" dependencies = [ "unicode-ident", ] [[package]] name = "proptest" -version = "1.11.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b45fcc2344c680f5025fe57779faef368840d0bd1f42f216291f0dc4ace4744" +checksum = "bee689443a2bd0a16ab0348b52ee43e3b2d1b1f931c8aa5c9f8de4c86fbe8c40" dependencies = [ "bit-set", "bit-vec", "bitflags", "num-traits", - "rand 0.9.4", + "rand 0.9.2", "rand_chacha 0.9.0", "rand_xorshift", "regex-syntax", @@ -2794,9 +2811,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.45" +version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" dependencies = [ "proc-macro2", ] @@ -2807,12 +2824,6 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" -[[package]] -name = "r-efi" -version = "6.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" - [[package]] name = "radium" version = "0.7.0" @@ -2821,9 +2832,9 @@ checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" [[package]] name = "rand" -version = "0.8.6" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha 0.3.1", @@ -2833,15 +2844,24 @@ dependencies = [ [[package]] name = "rand" -version = "0.9.4" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" +checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ "rand_chacha 0.9.0", - "rand_core 0.9.5", + "rand_core 0.9.3", "serde", ] +[[package]] +name = "rand" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80" +dependencies = [ + "rand_core 0.10.1", +] + [[package]] name = "rand_chacha" version = "0.3.1" @@ -2859,7 +2879,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core 0.9.5", + "rand_core 0.9.3", ] [[package]] @@ -2868,33 +2888,39 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.17", + "getrandom 0.2.16", ] [[package]] name = "rand_core" -version = "0.9.5" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" dependencies = [ "getrandom 0.3.4", "serde", ] +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + [[package]] name = "rand_xorshift" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" dependencies = [ - "rand_core 0.9.5", + "rand_core 0.9.3", ] [[package]] name = "rayon" -version = "1.12.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" dependencies = [ "either", "rayon-core", @@ -2927,14 +2953,14 @@ checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] name = "regex-syntax" -version = "0.8.10" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[package]] name = "reth" @@ -2953,8 +2979,8 @@ version = "1.9.3" source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" dependencies = [ "alloy-chains", - "alloy-consensus", - "alloy-eips", + "alloy-consensus 1.1.3", + "alloy-eips 1.1.3", "alloy-evm", "alloy-genesis", "alloy-primitives", @@ -2972,8 +2998,8 @@ name = "reth-codecs" version = "1.9.3" source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 1.1.3", + "alloy-eips 1.1.3", "alloy-genesis", "alloy-primitives", "alloy-trie", @@ -2992,7 +3018,7 @@ source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea8 dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] @@ -3000,12 +3026,12 @@ name = "reth-consensus" version = "1.9.3" source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" dependencies = [ - "alloy-consensus", + "alloy-consensus 1.1.3", "alloy-primitives", "auto_impl", "reth-execution-types", "reth-primitives-traits", - "thiserror 2.0.18", + "thiserror 2.0.17", ] [[package]] @@ -3013,8 +3039,8 @@ name = "reth-consensus-common" version = "1.9.3" source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 1.1.3", + "alloy-eips 1.1.3", "reth-chainspec", "reth-consensus", "reth-primitives-traits", @@ -3025,7 +3051,7 @@ name = "reth-db-models" version = "1.9.3" source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" dependencies = [ - "alloy-eips", + "alloy-eips 1.1.3", "alloy-primitives", "reth-primitives-traits", ] @@ -3038,7 +3064,7 @@ dependencies = [ "reth-consensus", "reth-execution-errors", "reth-storage-errors", - "thiserror 2.0.18", + "thiserror 2.0.17", ] [[package]] @@ -3046,8 +3072,8 @@ name = "reth-ethereum-consensus" version = "1.9.3" source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 1.1.3", + "alloy-eips 1.1.3", "alloy-primitives", "reth-chainspec", "reth-consensus", @@ -3074,12 +3100,12 @@ name = "reth-ethereum-primitives" version = "1.9.3" source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 1.1.3", + "alloy-eips 1.1.3", "alloy-primitives", "alloy-rlp", "alloy-rpc-types-eth", - "alloy-serde", + "alloy-serde 1.1.3", "reth-codecs", "reth-primitives-traits", "serde", @@ -3091,8 +3117,8 @@ name = "reth-evm" version = "1.9.3" source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 1.1.3", + "alloy-eips 1.1.3", "alloy-evm", "alloy-primitives", "auto_impl", @@ -3112,8 +3138,8 @@ name = "reth-evm-ethereum" version = "1.9.3" source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 1.1.3", + "alloy-eips 1.1.3", "alloy-evm", "alloy-primitives", "alloy-rpc-types-engine", @@ -3137,7 +3163,7 @@ dependencies = [ "alloy-rlp", "nybbles", "reth-storage-errors", - "thiserror 2.0.18", + "thiserror 2.0.17", ] [[package]] @@ -3145,8 +3171,8 @@ name = "reth-execution-types" version = "1.9.3" source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 1.1.3", + "alloy-eips 1.1.3", "alloy-evm", "alloy-primitives", "derive_more", @@ -3164,7 +3190,7 @@ dependencies = [ "alloy-primitives", "alloy-rlp", "serde_with", - "thiserror 2.0.18", + "thiserror 2.0.17", "url", ] @@ -3173,8 +3199,8 @@ name = "reth-primitives-traits" version = "1.9.3" source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 1.1.3", + "alloy-eips 1.1.3", "alloy-genesis", "alloy-primitives", "alloy-rlp", @@ -3192,7 +3218,7 @@ dependencies = [ "secp256k1", "serde", "serde_with", - "thiserror 2.0.18", + "thiserror 2.0.17", ] [[package]] @@ -3203,7 +3229,7 @@ dependencies = [ "alloy-primitives", "derive_more", "strum", - "thiserror 2.0.18", + "thiserror 2.0.17", ] [[package]] @@ -3231,8 +3257,8 @@ name = "reth-storage-api" version = "1.9.3" source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 1.1.3", + "alloy-eips 1.1.3", "alloy-primitives", "alloy-rpc-types-engine", "auto_impl", @@ -3253,7 +3279,7 @@ name = "reth-storage-errors" version = "1.9.3" source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" dependencies = [ - "alloy-eips", + "alloy-eips 1.1.3", "alloy-primitives", "alloy-rlp", "derive_more", @@ -3261,7 +3287,7 @@ dependencies = [ "reth-prune-types", "reth-static-file-types", "revm-database-interface", - "thiserror 2.0.18", + "thiserror 2.0.17", ] [[package]] @@ -3269,8 +3295,8 @@ name = "reth-trie" version = "1.9.3" source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" dependencies = [ - "alloy-consensus", - "alloy-eips", + "alloy-consensus 1.1.3", + "alloy-eips 1.1.3", "alloy-primitives", "alloy-rlp", "alloy-trie", @@ -3291,7 +3317,7 @@ name = "reth-trie-common" version = "1.9.3" source = "git+https://github.com/paradigmxyz/reth?tag=v1.9.3#27a8c0f5a6dfb27dea84c5751776ecabdd069646" dependencies = [ - "alloy-consensus", + "alloy-consensus 1.1.3", "alloy-primitives", "alloy-rlp", "alloy-trie", @@ -3330,8 +3356,7 @@ dependencies = [ [[package]] name = "revm" version = "31.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb67a5223602113cae59a305acde2d9936bc18f2478dda879a6124b267cebfb6" +source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32-dispatch#2a9844a05fc7541c05a067f5d3e32fc99489cd6d" dependencies = [ "revm-bytecode", "revm-context", @@ -3349,8 +3374,7 @@ dependencies = [ [[package]] name = "revm-bytecode" version = "7.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2c6b5e6e8dd1e28a4a60e5f46615d4ef0809111c9e63208e55b5c7058200fb0" +source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32-dispatch#2a9844a05fc7541c05a067f5d3e32fc99489cd6d" dependencies = [ "bitvec", "phf", @@ -3361,9 +3385,9 @@ dependencies = [ [[package]] name = "revm-context" version = "11.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92850e150f4f99d46c05a20ad0cd09286a7ad4ee21866fffb87101de6e602231" +source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32-dispatch#2a9844a05fc7541c05a067f5d3e32fc99489cd6d" dependencies = [ + "alloy-consensus 1.0.41", "bitvec", "cfg-if", "derive-where", @@ -3378,9 +3402,9 @@ dependencies = [ [[package]] name = "revm-context-interface" version = "12.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6d701e2c2347d65216b066489ab22a0a8e1f7b2568256110d73a7d5eff3385c" +source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32-dispatch#2a9844a05fc7541c05a067f5d3e32fc99489cd6d" dependencies = [ + "alloy-consensus 1.0.41", "alloy-eip2930", "alloy-eip7702", "auto_impl", @@ -3394,10 +3418,9 @@ dependencies = [ [[package]] name = "revm-database" version = "9.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "980d8d6bba78c5dd35b83abbb6585b0b902eb25ea4448ed7bfba6283b0337191" +source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32-dispatch#2a9844a05fc7541c05a067f5d3e32fc99489cd6d" dependencies = [ - "alloy-eips", + "alloy-eips 1.0.41", "revm-bytecode", "revm-database-interface", "revm-primitives", @@ -3408,8 +3431,7 @@ dependencies = [ [[package]] name = "revm-database-interface" version = "8.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cce03e3780287b07abe58faf4a7f5d8be7e81321f93ccf3343c8f7755602bae" +source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32-dispatch#2a9844a05fc7541c05a067f5d3e32fc99489cd6d" dependencies = [ "auto_impl", "either", @@ -3421,8 +3443,7 @@ dependencies = [ [[package]] name = "revm-handler" version = "12.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b45418ed95cfdf0cb19effdbb7633cf2144cab7fb0e6ffd6b0eb9117a50adff6" +source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32-dispatch#2a9844a05fc7541c05a067f5d3e32fc99489cd6d" dependencies = [ "auto_impl", "derive-where", @@ -3440,8 +3461,7 @@ dependencies = [ [[package]] name = "revm-inspector" version = "12.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c99801eac7da06cc112df2244bd5a64024f4ef21240e923b26e73c4b4a0e5da6" +source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32-dispatch#2a9844a05fc7541c05a067f5d3e32fc99489cd6d" dependencies = [ "auto_impl", "either", @@ -3457,8 +3477,7 @@ dependencies = [ [[package]] name = "revm-interpreter" version = "29.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22789ce92c5808c70185e3bc49732f987dc6fd907f77828c8d3470b2299c9c65" +source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32-dispatch#2a9844a05fc7541c05a067f5d3e32fc99489cd6d" dependencies = [ "revm-bytecode", "revm-context-interface", @@ -3470,8 +3489,7 @@ dependencies = [ [[package]] name = "revm-precompile" version = "29.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "968b124028960201abf6d6bf8e223f15fadebb4307df6b7dc9244a0aab5d2d05" +source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32-dispatch#2a9844a05fc7541c05a067f5d3e32fc99489cd6d" dependencies = [ "ark-bls12-381", "ark-bn254", @@ -3492,8 +3510,7 @@ dependencies = [ [[package]] name = "revm-primitives" version = "21.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29e161db429d465c09ba9cbff0df49e31049fe6b549e28eb0b7bd642fcbd4412" +source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32-dispatch#2a9844a05fc7541c05a067f5d3e32fc99489cd6d" dependencies = [ "alloy-primitives", "num_enum", @@ -3504,8 +3521,7 @@ dependencies = [ [[package]] name = "revm-state" version = "8.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d8be953b7e374dbdea0773cf360debed8df394ea8d82a8b240a6b5da37592fc" +source = "git+https://github.com/ziren-patches/revm?branch=patch-31.0.2-mips32-dispatch#2a9844a05fc7541c05a067f5d3e32fc99489cd6d" dependencies = [ "bitflags", "revm-bytecode", @@ -3543,9 +3559,8 @@ dependencies = [ [[package]] name = "ruint" -version = "1.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0298da754d1395046b0afdc2f20ee76d29a8ae310cd30ffa84ed42acba9cb12a" +version = "1.17.0" +source = "git+https://github.com/ziren-patches/ruint?branch=patch-1.17.0#572265b0666ae9b1ce749b0f0ce051108ec7253c" dependencies = [ "alloy-rlp", "ark-ff 0.3.0", @@ -3560,26 +3575,26 @@ dependencies = [ "parity-scale-codec", "primitive-types", "proptest", - "rand 0.8.6", - "rand 0.9.4", + "rand 0.8.5", + "rand 0.9.2", "rlp", "ruint-macro", "serde_core", "valuable", "zeroize", + "zkm-lib", ] [[package]] name = "ruint-macro" version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" +source = "git+https://github.com/ziren-patches/ruint?branch=patch-1.17.0#572265b0666ae9b1ce749b0f0ce051108ec7253c" [[package]] name = "rustc-hash" -version = "2.1.2" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" [[package]] name = "rustc-hex" @@ -3602,14 +3617,14 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ - "semver 1.0.28", + "semver 1.0.27", ] [[package]] name = "rustix" -version = "1.1.4" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" dependencies = [ "bitflags", "errno", @@ -3636,6 +3651,12 @@ dependencies = [ "wait-timeout", ] +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + [[package]] name = "schemars" version = "0.9.0" @@ -3650,9 +3671,9 @@ dependencies = [ [[package]] name = "schemars" -version = "1.2.1" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc" +checksum = "9558e172d4e8533736ba97870c4b2cd63f84b382a3d6eb063da41b91cce17289" dependencies = [ "dyn-clone", "ref-cast", @@ -3688,7 +3709,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b50c5943d326858130af85e049f2661ba3c78b26589b8ab98e65e80ae44a1252" dependencies = [ "bitcoin_hashes", - "rand 0.8.6", + "rand 0.8.5", "secp256k1-sys", "serde", ] @@ -3713,9 +3734,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.28" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" [[package]] name = "semver-parser" @@ -3762,36 +3783,35 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] name = "serde_json" -version = "1.0.149" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ "itoa", "memchr", + "ryu", "serde", "serde_core", - "zmij", ] [[package]] name = "serde_with" -version = "3.20.0" +version = "3.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e72c1c2cb7b223fafb600a619537a871c2818583d619401b785e7c0b746ccde2" +checksum = "4fa237f2807440d238e0364a218270b98f767a00d3dada77b1c53ae88940e2e7" dependencies = [ "base64", - "bs58", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.14.0", + "indexmap 2.12.1", "schemars 0.9.0", - "schemars 1.2.1", + "schemars 1.1.0", "serde_core", "serde_json", "serde_with_macros", @@ -3800,14 +3820,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.20.0" +version = "3.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b90c488738ecb4fb0262f41f43bc40efc5868d9fb744319ddf5f5317f417bfac" +checksum = "52a8e3ca0ca629121f70ab50f95249e5a6f925cc0f6ffe8256c45b728875706c" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] @@ -3826,15 +3846,15 @@ version = "0.10.9" source = "git+https://github.com/ziren-patches/RustCrypto-hashes?branch=patch-sha2-0.10.9#dbfdbd088ac7b55e03c0b9eb192278efe35d67dc" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "digest 0.10.7", ] [[package]] name = "sha3" -version = "0.10.9" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77fd7028345d415a4034cf8777cd4f8ab1851274233b45f84e3d955502d93874" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" dependencies = [ "digest 0.10.7", "keccak", @@ -3842,9 +3862,9 @@ dependencies = [ [[package]] name = "sha3-asm" -version = "0.1.6" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59cbb88c189d6352cc8ae96a39d19c7ecad8f7330b29461187f2587fdc2988d5" +checksum = "c28efc5e327c837aa837c59eae585fc250715ef939ac32881bcc11677cd02d46" dependencies = [ "cc", "cfg-if", @@ -3868,15 +3888,9 @@ dependencies = [ [[package]] name = "siphasher" -version = "1.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649" - -[[package]] -name = "slab" -version = "0.4.12" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" +checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" [[package]] name = "smallvec" @@ -3893,6 +3907,15 @@ version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +[[package]] +name = "spin" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "023a211cb3138dbc438680b32560ad89f699977624c9f8dbb95a47d5b4c07dd3" +dependencies = [ + "lock_api", +] + [[package]] name = "spki" version = "0.7.3" @@ -3945,13 +3968,13 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] name = "substrate-bn" version = "0.6.0" -source = "git+https://github.com/ziren-patches/bn?branch=patch-0.6.0#aba71380457d798039111e6cc0fdf2e0718c6766" +source = "git+https://github.com/ziren-patches/bn?branch=patch-0.6.0#509192f90ef14511bfa64681b2d7c8333df13979" dependencies = [ "bytemuck", "byteorder", @@ -3959,7 +3982,7 @@ dependencies = [ "crunchy", "lazy_static", "num-bigint 0.4.6", - "rand 0.8.6", + "rand 0.8.5", "rustc-hex", "zkm-lib", ] @@ -3983,9 +4006,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.117" +version = "2.0.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +checksum = "390cc9a294ab71bdb1aa2e99d13be9c753cd2d7bd6560c77118597410c4d2e87" dependencies = [ "proc-macro2", "quote", @@ -3994,14 +4017,14 @@ dependencies = [ [[package]] name = "syn-solidity" -version = "1.5.7" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53f425ae0b12e2f5ae65542e00898d500d4d318b4baf09f40fd0d410454e9947" +checksum = "ff790eb176cc81bb8936aed0f7b9f14fc4670069a2d371b3e3b0ecce908b2cb3" dependencies = [ "paste", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] @@ -4012,7 +4035,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] @@ -4023,12 +4046,12 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.27.0" +version = "3.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" +checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" dependencies = [ "fastrand", - "getrandom 0.4.2", + "getrandom 0.3.4", "once_cell", "rustix", "windows-sys", @@ -4045,11 +4068,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.18" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" dependencies = [ - "thiserror-impl 2.0.18", + "thiserror-impl 2.0.17", ] [[package]] @@ -4060,18 +4083,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] name = "thiserror-impl" -version = "2.0.18" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] @@ -4085,30 +4108,30 @@ dependencies = [ [[package]] name = "time" -version = "0.3.47" +version = "0.3.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" dependencies = [ "deranged", "itoa", "num-conv", "powerfmt", - "serde_core", + "serde", "time-core", "time-macros", ] [[package]] name = "time-core" -version = "0.1.8" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" +checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" [[package]] name = "time-macros" -version = "0.2.27" +version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" +checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" dependencies = [ "num-conv", "time-core", @@ -4125,57 +4148,42 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.3" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" dependencies = [ "displaydoc", "zerovec", ] -[[package]] -name = "tinyvec" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" - [[package]] name = "toml_datetime" -version = "1.1.1+spec-1.1.0" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" +checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533" dependencies = [ "serde_core", ] [[package]] name = "toml_edit" -version = "0.25.11+spec-1.1.0" +version = "0.23.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b" +checksum = "5d7cbc3b4b49633d57a0509303158ca50de80ae32c265093b24c414705807832" dependencies = [ - "indexmap 2.14.0", + "indexmap 2.12.1", "toml_datetime", "toml_parser", - "winnow 1.0.2", + "winnow", ] [[package]] name = "toml_parser" -version = "1.1.2+spec-1.1.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" +checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" dependencies = [ - "winnow 1.0.2", + "winnow", ] [[package]] @@ -4197,7 +4205,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] @@ -4221,9 +4229,9 @@ dependencies = [ [[package]] name = "typenum" -version = "1.20.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "ucd-trie" @@ -4251,15 +4259,15 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicode-ident" -version = "1.0.24" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "unicode-segmentation" -version = "1.13.2" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-xid" @@ -4269,9 +4277,9 @@ checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "url" -version = "2.5.8" +version = "2.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" dependencies = [ "form_urlencoded", "idna", @@ -4313,27 +4321,18 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasip2" -version = "1.0.3+wasi-0.2.9" +version = "1.0.1+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" dependencies = [ - "wit-bindgen 0.57.1", -] - -[[package]] -name = "wasip3" -version = "0.4.0+wasi-0.3.0-rc-2026-01-06" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" -dependencies = [ - "wit-bindgen 0.51.0", + "wit-bindgen", ] [[package]] name = "wasm-bindgen" -version = "0.2.121" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49ace1d07c165b0864824eee619580c4689389afa9dc9ed3a4c75040d82e6790" +checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd" dependencies = [ "cfg-if", "once_cell", @@ -4344,9 +4343,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.121" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e68e6f4afd367a562002c05637acb8578ff2dea1943df76afb9e83d177c8578" +checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -4354,60 +4353,26 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.121" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d95a9ec35c64b2a7cb35d3fead40c4238d0940c86d107136999567a4703259f2" +checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40" dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.121" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4e0100b01e9f0d03189a92b96772a1fb998639d981193d7dbab487302513441" +checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4" dependencies = [ "unicode-ident", ] -[[package]] -name = "wasm-encoder" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" -dependencies = [ - "leb128fmt", - "wasmparser", -] - -[[package]] -name = "wasm-metadata" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" -dependencies = [ - "anyhow", - "indexmap 2.14.0", - "wasm-encoder", - "wasmparser", -] - -[[package]] -name = "wasmparser" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" -dependencies = [ - "bitflags", - "hashbrown 0.15.5", - "indexmap 2.14.0", - "semver 1.0.28", -] - [[package]] name = "windows-core" version = "0.62.2" @@ -4429,7 +4394,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] @@ -4440,7 +4405,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] @@ -4478,121 +4443,24 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" -dependencies = [ - "memchr", -] - -[[package]] -name = "winnow" -version = "1.0.2" +version = "0.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ee1708bef14716a11bae175f579062d4554d95be2c6829f518df847b7b3fdd0" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" dependencies = [ "memchr", ] [[package]] name = "wit-bindgen" -version = "0.51.0" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" -dependencies = [ - "wit-bindgen-rust-macro", -] - -[[package]] -name = "wit-bindgen" -version = "0.57.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" - -[[package]] -name = "wit-bindgen-core" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" -dependencies = [ - "anyhow", - "heck", - "wit-parser", -] - -[[package]] -name = "wit-bindgen-rust" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" -dependencies = [ - "anyhow", - "heck", - "indexmap 2.14.0", - "prettyplease", - "syn 2.0.117", - "wasm-metadata", - "wit-bindgen-core", - "wit-component", -] - -[[package]] -name = "wit-bindgen-rust-macro" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" -dependencies = [ - "anyhow", - "prettyplease", - "proc-macro2", - "quote", - "syn 2.0.117", - "wit-bindgen-core", - "wit-bindgen-rust", -] - -[[package]] -name = "wit-component" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" -dependencies = [ - "anyhow", - "bitflags", - "indexmap 2.14.0", - "log", - "serde", - "serde_derive", - "serde_json", - "wasm-encoder", - "wasm-metadata", - "wasmparser", - "wit-parser", -] - -[[package]] -name = "wit-parser" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" -dependencies = [ - "anyhow", - "id-arena", - "indexmap 2.14.0", - "log", - "semver 1.0.28", - "serde", - "serde_derive", - "serde_json", - "unicode-xid", - "wasmparser", -] +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" [[package]] name = "writeable" -version = "0.6.3" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" [[package]] name = "wyz" @@ -4605,9 +4473,9 @@ dependencies = [ [[package]] name = "yoke" -version = "0.8.2" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" dependencies = [ "stable_deref_trait", "yoke-derive", @@ -4616,54 +4484,54 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.2" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", "synstructure", ] [[package]] name = "zerocopy" -version = "0.8.48" +version = "0.8.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" +checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.48" +version = "0.8.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" +checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] name = "zerofrom" -version = "0.1.8" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.7" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", "synstructure", ] @@ -4678,20 +4546,20 @@ dependencies = [ [[package]] name = "zeroize_derive" -version = "1.4.3" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] name = "zerotrie" -version = "0.2.4" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" dependencies = [ "displaydoc", "yoke", @@ -4700,9 +4568,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.6" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" dependencies = [ "yoke", "zerofrom", @@ -4711,19 +4579,18 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.3" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.111", ] [[package]] name = "zkm-lib" -version = "1.2.5" -source = "git+https://github.com/ProjectZKM/Ziren#7c2071eaa8d43d9d0cb76077ec94b9d98f33073e" +version = "2.0.0" dependencies = [ "bincode", "cfg-if", @@ -4735,10 +4602,10 @@ dependencies = [ [[package]] name = "zkm-primitives" -version = "1.2.5" -source = "git+https://github.com/ProjectZKM/Ziren#7c2071eaa8d43d9d0cb76077ec94b9d98f33073e" +version = "2.0.0" dependencies = [ "bincode", + "blake3", "hex", "lazy_static", "num-bigint 0.4.6", @@ -4749,31 +4616,25 @@ dependencies = [ "p3-symmetric", "serde", "sha2", + "tracing", ] [[package]] name = "zkm-zkvm" -version = "1.2.5" -source = "git+https://github.com/ProjectZKM/Ziren#7c2071eaa8d43d9d0cb76077ec94b9d98f33073e" +version = "2.0.0" dependencies = [ "bincode", "cfg-if", - "getrandom 0.2.17", + "getrandom 0.2.16", "lazy_static", "libm", - "rand 0.8.6", + "rand 0.8.5", "serde", "sha2", "zkm-lib", "zkm-primitives", ] -[[package]] -name = "zmij" -version = "1.0.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" - [[package]] name = "zstd" version = "0.13.3" diff --git a/bin/guest/Cargo.toml b/bin/guest/Cargo.toml index c4ddad3..6a07ceb 100644 --- a/bin/guest/Cargo.toml +++ b/bin/guest/Cargo.toml @@ -18,7 +18,7 @@ bincode = "1.3.3" guest-executor = { path = "../../crates/executor/guest" } # Ziren -zkm-zkvm = { git = "https://github.com/ProjectZKM/Ziren" } +zkm-zkvm = { git = "https://github.com/ProjectZKM/Ziren", branch = "perf/shamir-msm" } # zkm-zkvm = { path = "../../../Ziren/crates/zkvm/entrypoint" } # Statically turns off logging @@ -26,9 +26,35 @@ log = { version = "0.4", features = ["max_level_off", "release_max_level_off"] } tracing = { version = "0.1", features = ["max_level_off", "release_max_level_off"] } [patch.crates-io] -# Precompile patches +ruint = { git = "https://github.com/ziren-patches/ruint", branch = "patch-1.17.0" } +revm = { git = "https://github.com/ziren-patches/revm", branch = "patch-31.0.2-mips32-dispatch" } +revm-bytecode = { git = "https://github.com/ziren-patches/revm", branch = "patch-31.0.2-mips32-dispatch" } +revm-context = { git = "https://github.com/ziren-patches/revm", branch = "patch-31.0.2-mips32-dispatch" } +revm-context-interface = { git = "https://github.com/ziren-patches/revm", branch = "patch-31.0.2-mips32-dispatch" } +revm-database = { git = "https://github.com/ziren-patches/revm", branch = "patch-31.0.2-mips32-dispatch" } +revm-database-interface = { git = "https://github.com/ziren-patches/revm", branch = "patch-31.0.2-mips32-dispatch" } +revm-handler = { git = "https://github.com/ziren-patches/revm", branch = "patch-31.0.2-mips32-dispatch" } +revm-inspector = { git = "https://github.com/ziren-patches/revm", branch = "patch-31.0.2-mips32-dispatch" } +revm-interpreter = { git = "https://github.com/ziren-patches/revm", branch = "patch-31.0.2-mips32-dispatch" } +revm-precompile = { git = "https://github.com/ziren-patches/revm", branch = "patch-31.0.2-mips32-dispatch" } +revm-primitives = { git = "https://github.com/ziren-patches/revm", branch = "patch-31.0.2-mips32-dispatch" } +revm-state = { git = "https://github.com/ziren-patches/revm", branch = "patch-31.0.2-mips32-dispatch" } +# Precompile patches, and the revm workspace with its 32-bit interpreter +# fast paths (gas, stack exchange, memory words) and cheaper jumps (JUMPDEST +# folded into the jump, PUSH2 + JUMP / JUMPI run as one instruction). sha2 = { git = "https://github.com/ziren-patches/RustCrypto-hashes", branch = "patch-sha2-0.10.9", package = "sha2" } bn = { git = "https://github.com/ziren-patches/bn", branch = "patch-0.6.0", package = "substrate-bn" } k256 = { git = "https://github.com/ziren-patches/elliptic-curves", branch = "patch-k256-0.13.4" } p256 = { git = "https://github.com/ziren-patches/elliptic-curves", branch = "patch-p256-0.13.2" } -alloy-primitives-v1-4-1 = { git = "https://github.com/ziren-patches/core.git", package = "alloy-primitives", branch = "patch-alloy-primitives-1.4.1" } +alloy-primitives-v1-4-1 = { git = "https://github.com/ziren-patches/core.git", package = "alloy-primitives", branch = "patch-alloy-primitives-1.4.1-hasher" } + +# The guest's zkvm crates come from the canonical Ziren checkout next to this +# repo, the same way the GPU prover consumes it; check it out at the Ziren +# branch the dependencies above name. Every zkm-zkvm / zkm-lib in the graph +# (the precompile patches declare their own, unbranched, and cargo cannot +# redirect a git source to another branch of the same URL) resolves to this +# one source, so there is exactly one global allocator and the word-wise +# memcmp / zero-copy keccak reach every caller. +[patch."https://github.com/ProjectZKM/Ziren"] +zkm-zkvm = { path = "../../../Ziren/crates/zkvm/entrypoint" } +zkm-lib = { path = "../../../Ziren/crates/zkvm/lib" } diff --git a/bin/guest/src/main.rs b/bin/guest/src/main.rs index 15832d3..8c147d6 100644 --- a/bin/guest/src/main.rs +++ b/bin/guest/src/main.rs @@ -5,10 +5,14 @@ use guest_executor::verify_block; use std::sync::Arc; pub fn main() { - // Read the input. - let input = zkm_zkvm::io::read_vec(); + // Read the input. Leaked on purpose: the witness byte streams inside it + // are deserialised as borrows of this buffer rather than copies of it + // (`mpt::arena::input_bytes`), so it has to outlive the whole run. The + // vector is leaked as read: its capacity is the length rounded up to a + // word, and shrinking it to a boxed slice copied the whole input. + let input: &'static [u8] = Vec::leak(zkm_zkvm::io::read_vec()); - let (block_hash, _, _) = verify_block(&input); + let (block_hash, _, _) = verify_block(input); // Commit the block hash. zkm_zkvm::io::commit(&block_hash); diff --git a/bin/host/tests/cycle_count_diff.rs b/bin/host/tests/cycle_count_diff.rs index cf8c5e9..91285d8 100644 --- a/bin/host/tests/cycle_count_diff.rs +++ b/bin/host/tests/cycle_count_diff.rs @@ -39,7 +39,7 @@ async fn test_in_zkvm() { }; let rpc_url = Url::parse(env::var("RPC_1").unwrap().as_str()).expect("invalid rpc url"); - let elf = include_elf!("guest").to_vec(); + let elf = include_elf!("reth").to_vec(); let block_execution_strategy_factory = create_eth_block_execution_strategy_factory(&config.genesis, config.custom_beneficiary); diff --git a/crates/executor/guest/Cargo.toml b/crates/executor/guest/Cargo.toml index a3a8692..7b77915 100644 --- a/crates/executor/guest/Cargo.toml +++ b/crates/executor/guest/Cargo.toml @@ -52,9 +52,16 @@ op-alloy-network = { workspace = true, optional = true } op-alloy-rpc-types = { workspace = true, optional = true } kzg-rs.workspace = true +bls12_381 = { git = "https://github.com/ziren-patches/bls12_381", branch = "patch-0.8.0", default-features = false, features = ["groups", "pairings", "alloc", "experimental"] } +aurora-engine-modexp = "1.2.0" +zkm-lib = { git = "https://github.com/ProjectZKM/Ziren", branch = "perf/shamir-msm" } +bn = { git = "https://github.com/ziren-patches/bn", branch = "patch-0.6.0", package = "substrate-bn" } [features] +# Cycle-tracker spans around every precompile call in the zkVM (profiling only: +# the wrapper turns the precompile set into a map probed on every call). +precompile-tracking = [] optimism = [ "dep:op-alloy-network", "dep:op-alloy-rpc-types", diff --git a/crates/executor/guest/examples/convert_input.rs b/crates/executor/guest/examples/convert_input.rs new file mode 100644 index 0000000..5f3c78c --- /dev/null +++ b/crates/executor/guest/examples/convert_input.rs @@ -0,0 +1,54 @@ +use alloy_consensus::{Block, Header}; +use alloy_primitives::{Address, B256}; +use guest_executor::io::{EthClientExecutorInput, RawCode}; +use mpt::WitnessState; +use primitives::genesis::Genesis; +use reth_ethereum_primitives::TransactionSigned; +use revm::state::Bytecode; +use serde::Deserialize; +use serde_with::serde_as; + +#[serde_as] +#[derive(Deserialize)] +struct OldInput { + #[serde_as( + as = "reth_primitives_traits::serde_bincode_compat::Block<'_, TransactionSigned, Header>" + )] + current_block: Block, + #[serde_as(as = "Vec")] + ancestor_headers: Vec
, + parent_state: WitnessState, + bytecodes: Vec, + code_hashes: Vec, + genesis: Genesis, + custom_beneficiary: Option
, + opcode_tracking: bool, +} + +fn main() { + let args: Vec = std::env::args().collect(); + let old: OldInput = bincode::deserialize(&std::fs::read(&args[1]).unwrap()).unwrap(); + let old_codes = old.bytecodes.clone(); + let new = EthClientExecutorInput { + current_block: old.current_block, + ancestor_headers: old.ancestor_headers, + parent_state: old.parent_state, + bytecodes: old.bytecodes.iter().map(|b| RawCode::new(b.original_byte_slice())).collect(), + code_hashes: old.code_hashes, + genesis: old.genesis, + custom_beneficiary: old.custom_beneficiary, + opcode_tracking: old.opcode_tracking, + }; + for (old, new) in old_codes.iter().zip(&new.bytecodes) { + let analyzed = new.analyze(); + assert_eq!(old.original_byte_slice(), analyzed.original_byte_slice()); + assert_eq!( + old.legacy_jump_table().map(|j| j.as_slice().to_vec()), + analyzed.legacy_jump_table().map(|j| j.as_slice().to_vec()), + "jump table" + ); + } + let bytes = bincode::serialize(&new).unwrap(); + std::fs::write(&args[2], &bytes).unwrap(); + println!("wrote {} bytes", bytes.len()); +} diff --git a/crates/executor/guest/src/custom.rs b/crates/executor/guest/src/custom.rs index 3487bdb..def27d9 100644 --- a/crates/executor/guest/src/custom.rs +++ b/crates/executor/guest/src/custom.rs @@ -6,7 +6,7 @@ //! configuring the custom CustomEvmConfig precompiles and instructions. use alloy_evm::{precompiles::PrecompilesMap, EthEvm}; -use kzg_rs::{Bytes32, Bytes48, KzgProof, KzgSettings}; +use kzg_rs::KzgSettings; use reth_evm::{eth::EthEvmBuilder, Database, EvmEnv, EvmFactory}; use revm::{ bytecode::opcode::OpCode, @@ -18,7 +18,10 @@ use revm::{ interpreter_types::{Jumps, LoopControl}, Interpreter, InterpreterTypes, }, - precompile::{Crypto, PrecompileError, PrecompileSpecId, Precompiles}, + precompile::{ + bls12_381::{G1Point, G1PointScalar, G2Point, G2PointScalar}, + Crypto, PrecompileError, PrecompileSpecId, Precompiles, + }, Context, Inspector, }; use revm_primitives::{hardfork::SpecId, Address}; @@ -70,7 +73,7 @@ impl EvmFactory for CustomEvmFactory { PrecompileSpecId::from_spec_id(input.cfg_env.spec), )); - #[cfg(target_os = "zkvm")] + #[cfg(all(target_os = "zkvm", feature = "precompile-tracking"))] precompiles.map_precompiles(|address, p| { use alloy_evm::precompiles::Precompile; use reth_evm::precompiles::PrecompileInput; @@ -157,18 +160,73 @@ impl Inspector for OpCodeTrackingInspect } } -#[derive(Debug)] pub struct CustomCrypto { - kzg_settings: KzgSettings, + kzg: crate::precompiles::KzgVerifier, +} + +impl Debug for CustomCrypto { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str("CustomCrypto") + } } impl Default for CustomCrypto { fn default() -> Self { - Self { kzg_settings: KzgSettings::load_trusted_setup_file().unwrap() } + let settings = KzgSettings::load_trusted_setup_file().unwrap(); + Self { kzg: crate::precompiles::KzgVerifier::new(&settings) } } } impl Crypto for CustomCrypto { + fn bn254_g1_add(&self, p1: &[u8], p2: &[u8]) -> Result<[u8; 64], PrecompileError> { + crate::precompiles::bn254_g1_add(p1, p2) + } + + fn bn254_g1_mul(&self, point: &[u8], scalar: &[u8]) -> Result<[u8; 64], PrecompileError> { + crate::precompiles::bn254_g1_mul(point, scalar) + } + + fn bls12_381_g1_add(&self, a: G1Point, b: G1Point) -> Result<[u8; 96], PrecompileError> { + crate::precompiles::bls12_381_g1_add(a, b) + } + + fn bls12_381_g1_msm( + &self, + pairs: &mut dyn Iterator>, + ) -> Result<[u8; 96], PrecompileError> { + crate::precompiles::bls12_381_g1_msm(pairs) + } + + fn bls12_381_g2_add(&self, a: G2Point, b: G2Point) -> Result<[u8; 192], PrecompileError> { + crate::precompiles::bls12_381_g2_add(a, b) + } + + fn bls12_381_g2_msm( + &self, + pairs: &mut dyn Iterator>, + ) -> Result<[u8; 192], PrecompileError> { + crate::precompiles::bls12_381_g2_msm(pairs) + } + + fn bls12_381_pairing_check( + &self, + pairs: &[(G1Point, G2Point)], + ) -> Result { + crate::precompiles::bls12_381_pairing_check(pairs) + } + + fn bls12_381_fp_to_g1(&self, fp: &[u8; 48]) -> Result<[u8; 96], PrecompileError> { + crate::precompiles::bls12_381_fp_to_g1(fp) + } + + fn bls12_381_fp2_to_g2(&self, fp2: ([u8; 48], [u8; 48])) -> Result<[u8; 192], PrecompileError> { + crate::precompiles::bls12_381_fp2_to_g2(fp2) + } + + fn modexp(&self, base: &[u8], exp: &[u8], modulus: &[u8]) -> Result, PrecompileError> { + Ok(crate::precompiles::modexp(base, exp, modulus)) + } + fn verify_kzg_proof( &self, z: &[u8; 32], @@ -176,18 +234,9 @@ impl Crypto for CustomCrypto { commitment: &[u8; 48], proof: &[u8; 48], ) -> Result<(), PrecompileError> { - if !KzgProof::verify_kzg_proof( - &Bytes48(*commitment), - &Bytes32(*z), - &Bytes32(*y), - &Bytes48(*proof), - &self.kzg_settings, - ) - .map_err(|err| PrecompileError::other(err.to_string()))? - { + if !self.kzg.verify(z, y, commitment, proof)? { return Err(PrecompileError::BlobVerifyKzgProofFailed); } - Ok(()) } } diff --git a/crates/executor/guest/src/error.rs b/crates/executor/guest/src/error.rs index 557bd8e..23153c0 100644 --- a/crates/executor/guest/src/error.rs +++ b/crates/executor/guest/src/error.rs @@ -11,6 +11,8 @@ pub enum ClientError { MismatchedStateRoot, #[error("Mismatched storage root after executing the block")] MismatchedStorageRoot, + #[error("Invalid state witness: {0}")] + InvalidWitness(String), #[error("unknown chain ID: {}", .0)] UnknownChainId(u64), #[error("Missing bytecode for account {}", .0)] diff --git a/crates/executor/guest/src/executor.rs b/crates/executor/guest/src/executor.rs index 3e4dca8..a5bd665 100644 --- a/crates/executor/guest/src/executor.rs +++ b/crates/executor/guest/src/executor.rs @@ -11,13 +11,13 @@ use reth_evm::{ use reth_evm_ethereum::EthEvmConfig; use reth_execution_types::ExecutionOutcome; use reth_primitives_traits::Block; -use reth_trie::KeccakKeyHasher; use revm::{database::WrapDatabaseRef, install_crypto}; use revm_primitives::Address; use crate::{ custom::{CustomCrypto, CustomEvmFactory}, error::ClientError, + hashed_keys::MemoKeyHasher, into_primitives::FromInput, io::{ClientExecutorInput, TrieDB, WitnessInput}, tracking::OpCodesTrackingBlockExecutor, @@ -52,15 +52,17 @@ where { pub fn execute( &self, - mut input: ClientExecutorInput, + input: ClientExecutorInput, ) -> Result<(Header, B256), ClientError> { let sealed_headers = input.sealed_headers().collect::>(); - // Initialize the witnessed database with verified storage proofs. - let db = profile_report!(INIT_WITNESS_DB, { - let trie_db = input.witness_db(&sealed_headers).unwrap(); - WrapDatabaseRef(trie_db) - }); + // Materialise the witnessed state (every node hash-checked) and wrap it + // as the execution database. + let mut state = profile_report!(INIT_WITNESS_DB, { + mpt::ArenaState::from_witness(&input.parent_state) + .map_err(|e| ClientError::InvalidWitness(e.to_string())) + })?; + let db = WrapDatabaseRef(input.witness_db(&state, &sealed_headers)?); let chain_id: u64 = (&input.genesis).try_into().expect("convert chain id err"); @@ -77,7 +79,7 @@ where profile_report!(BLOCK_EXECUTION, { block_executor.execute(&block) })?; // Validate the block post execution. - profile_report!(VALIDATE_EXECUTION, { + let checked_bloom = profile_report!(VALIDATE_EXECUTION, { C::Primitives::validate_block_post_execution( &block, self.chain_spec.clone(), @@ -85,13 +87,21 @@ where ) })?; - // Accumulate the logs bloom. - let mut logs_bloom = Bloom::default(); - profile_report!(ACCRUE_LOG_BLOOM, { - execution_output.result.receipts.iter().for_each(|r| { - logs_bloom.accrue_bloom(&r.bloom()); - }) - }); + // The logs bloom: the one validation checked against the receipts, + // else accumulated here. A receipt bloom hashes every log address and + // topic, so accumulating it again cost a keccak per log entry. + let logs_bloom = match checked_bloom { + Some(bloom) => bloom, + None => { + let mut logs_bloom = Bloom::default(); + profile_report!(ACCRUE_LOG_BLOOM, { + execution_output.result.receipts.iter().for_each(|r| { + logs_bloom.accrue_bloom(&r.bloom()); + }) + }); + logs_bloom + } + }; // Convert the output to an execution outcome. let executor_outcome = ExecutionOutcome::new( @@ -101,12 +111,12 @@ where vec![execution_output.result.requests], ); - let parent_state_root = input.parent_state.state_root(); + let parent_state_root = input.parent_state.state_root; // Verify the state root. let state_root = profile_report!(COMPUTE_STATE_ROOT, { - input.parent_state.update(&executor_outcome.hash_state_slow::()); - input.parent_state.state_root() + state.update(&executor_outcome.hash_state_slow::()); + state.state_root() }); if state_root != input.current_block.header().state_root() { diff --git a/crates/executor/guest/src/hashed_keys.rs b/crates/executor/guest/src/hashed_keys.rs new file mode 100644 index 0000000..5cae19f --- /dev/null +++ b/crates/executor/guest/src/hashed_keys.rs @@ -0,0 +1,72 @@ +//! Memoised keccak of trie keys. +//! +//! A block hashes the same account addresses and storage slots many times: +//! [`TrieDB`](crate::io::TrieDB) hashes both on every read, and the post-state +//! root pass hashes every changed account and slot again. In the zkVM each of +//! those is a KeccakSponge precompile call, and that chip is about a third of a +//! block's proving area, so a repeat costs far more than the map probe that +//! avoids it (block 25955640: 17,311 of its 22,298 address and slot hashes were +//! repeats). +//! +//! The memo only ever holds digests this execution computed itself, so a hit +//! returns exactly what a fresh keccak would. Off the zkVM the functions hash +//! directly: the host runs one block after another in one process, where a +//! per-thread memo would only grow. + +use alloy_primitives::{keccak256, Address, B256}; +use reth_trie::KeyHasher; + +#[cfg(target_os = "zkvm")] +mod memo { + use std::cell::RefCell; + + use alloy_primitives::{keccak256, map::HashMap, Address, B256}; + + thread_local! { + static ADDRESSES: RefCell> = RefCell::new(HashMap::default()); + static SLOTS: RefCell> = RefCell::new(HashMap::default()); + } + + pub(super) fn address(address: Address) -> B256 { + ADDRESSES.with(|m| *m.borrow_mut().entry(address).or_insert_with(|| keccak256(address))) + } + + pub(super) fn slot(slot: B256) -> B256 { + SLOTS.with(|m| *m.borrow_mut().entry(slot).or_insert_with(|| keccak256(slot))) + } +} + +/// `keccak256(address)`, the account's key in the state trie. +#[inline] +pub fn hashed_address(address: Address) -> B256 { + #[cfg(target_os = "zkvm")] + return memo::address(address); + #[cfg(not(target_os = "zkvm"))] + keccak256(address) +} + +/// `keccak256(slot)`, the slot's key in its storage trie. +#[inline] +pub fn hashed_slot(slot: B256) -> B256 { + #[cfg(target_os = "zkvm")] + return memo::slot(slot); + #[cfg(not(target_os = "zkvm"))] + keccak256(slot) +} + +/// [`KeccakKeyHasher`](reth_trie::KeccakKeyHasher) through the memo: the +/// post-state pass hands it 20-byte addresses and 32-byte slots. +#[derive(Clone, Debug, Default)] +pub struct MemoKeyHasher; + +impl KeyHasher for MemoKeyHasher { + #[inline] + fn hash_key>(bytes: T) -> B256 { + let bytes = bytes.as_ref(); + match bytes.len() { + 20 => hashed_address(Address::from_slice(bytes)), + 32 => hashed_slot(B256::from_slice(bytes)), + _ => keccak256(bytes), + } + } +} diff --git a/crates/executor/guest/src/into_primitives.rs b/crates/executor/guest/src/into_primitives.rs index d074190..c160869 100644 --- a/crates/executor/guest/src/into_primitives.rs +++ b/crates/executor/guest/src/into_primitives.rs @@ -1,8 +1,9 @@ use std::sync::Arc; -use alloy_consensus::{Block, Header, TxEnvelope}; +use alloy_consensus::{Block, BlockHeader, Header, TxEnvelope}; use alloy_network::{Ethereum, Network}; -use reth_chainspec::{ChainSpec, EthChainSpec, NamedChain}; +use alloy_primitives::Bloom; +use reth_chainspec::{ChainSpec, EthChainSpec, EthereumHardforks, NamedChain}; use reth_consensus::HeaderValidator; use reth_consensus_common::validation::validate_body_against_header; use reth_errors::ConsensusError; @@ -39,11 +40,14 @@ pub trait BlockValidator: NodePrimitives { chain_spec: Arc, ) -> Result<(), ConsensusError>; + /// Validates the execution output against the block, and returns the + /// logs bloom that validation checked equal to the receipts' blooms, if + /// it checked one, so the caller need not accumulate it again. fn validate_block_post_execution( block: &RecoveredBlock, chain_spec: Arc, execution_output: &BlockExecutionOutput, - ) -> Result<(), ConsensusError>; + ) -> Result, ConsensusError>; } impl IntoPrimitives for EthPrimitives { @@ -104,13 +108,17 @@ impl BlockValidator for EthPrimitives { block: &RecoveredBlock, chain_spec: Arc, execution_output: &BlockExecutionOutput, - ) -> Result<(), ConsensusError> { + ) -> Result, ConsensusError> { reth_ethereum_consensus::validate_block_post_execution( block, &chain_spec, &execution_output.result.receipts, &execution_output.result.requests, - ) + )?; + // From Byzantium on, `verify_receipts` has compared the bloom of the + // receipts with the header's. + let header = block.header(); + Ok(chain_spec.is_byzantium_active_at_block(header.number()).then(|| header.logs_bloom())) } } @@ -184,12 +192,13 @@ impl BlockValidator block: &RecoveredBlock, chain_spec: Arc, execution_output: &BlockExecutionOutput, - ) -> Result<(), ConsensusError> { + ) -> Result, ConsensusError> { reth_optimism_consensus::validate_block_post_execution( block.header(), &chain_spec, &execution_output.result, - ) + )?; + Ok(None) } } diff --git a/crates/executor/guest/src/io.rs b/crates/executor/guest/src/io.rs index 1054f17..75c0caa 100644 --- a/crates/executor/guest/src/io.rs +++ b/crates/executor/guest/src/io.rs @@ -3,21 +3,24 @@ use std::iter::once; use alloy_consensus::{Block, BlockHeader, Header}; use alloy_primitives::map::HashMap; use itertools::Itertools; -use mpt::EthereumState; +use mpt::{ArenaState, WitnessState}; use primitives::genesis::Genesis; use reth_errors::ProviderError; use reth_ethereum_primitives::EthPrimitives; use reth_primitives_traits::{NodePrimitives, SealedHeader}; -use reth_trie::{TrieAccount, EMPTY_ROOT_HASH}; use revm::{ + bytecode::{eip7702::EIP7702_MAGIC_BYTES, JumpTable, LegacyAnalyzedBytecode}, state::{AccountInfo, Bytecode}, DatabaseRef, }; -use revm_primitives::{keccak256, Address, B256, U256}; +use revm_primitives::{keccak256, Address, Bytes, B256, U256}; use serde::{Deserialize, Serialize}; use serde_with::serde_as; -use crate::error::ClientError; +use crate::{ + error::ClientError, + hashed_keys::{hashed_address, hashed_slot}, +}; pub type EthClientExecutorInput = ClientExecutorInput; @@ -41,10 +44,19 @@ pub struct ClientExecutorInput { /// to provide the parent state root. #[serde_as(as = "Vec")] pub ancestor_headers: Vec
, - /// Network state as of the parent block. - pub parent_state: EthereumState, - /// Account bytecodes. - pub bytecodes: Vec, + /// Network state as of the parent block, in witness form (root hashes and + /// preorder streams of raw RLP nodes); the guest materialises it into an + /// [`ArenaState`], checking every node against the digest that references it. + pub parent_state: WitnessState, + /// Account bytecodes, as deployed: the guest derives the jump table + /// itself, since one taken from the host would decide which jumps are + /// valid without being bound by the code hash. + pub bytecodes: Vec, + /// The code hash the host claims for each entry of `bytecodes`; the guest + /// checks a claim the first time that code executes, so code that is only + /// shipped (touched accounts that never run) is never hashed. + #[serde(default)] + pub code_hashes: Vec, /// The genesis block, as a json string. pub genesis: Genesis, /// The genesis block, as a json string. @@ -60,15 +72,19 @@ impl ClientExecutorInput

{ self.ancestor_headers.last().unwrap() } - /// Creates a [`WitnessDb`]. - pub fn witness_db(&self, sealed_headers: &[SealedHeader]) -> Result, ClientError> { - ::witness_db(self, sealed_headers) + /// Creates a [`TrieDB`] over the materialised `state`. + pub fn witness_db<'a>( + &'a self, + state: &'a ArenaState, + sealed_headers: &[SealedHeader], + ) -> Result, ClientError> { + ::witness_db(self, state, sealed_headers) } } impl WitnessInput for ClientExecutorInput

{ #[inline(always)] - fn state(&self) -> &EthereumState { + fn state(&self) -> &WitnessState { &self.parent_state } @@ -78,10 +94,15 @@ impl WitnessInput for ClientExecutorInput

{ } #[inline(always)] - fn bytecodes(&self) -> impl Iterator { + fn bytecodes(&self) -> impl Iterator { self.bytecodes.iter() } + #[inline(always)] + fn code_hashes(&self) -> &[B256] { + &self.code_hashes + } + #[inline(always)] fn sealed_headers(&self) -> impl Iterator { self.ancestor_headers @@ -91,20 +112,126 @@ impl WitnessInput for ClientExecutorInput

{ } } +/// A contract's code as deployed followed by [`RawCode::PADDING`] zero +/// bytes, read from the input without a copy. The zeros are the `STOP`s the +/// interpreter runs into past the end of the code, at most a 32-byte push +/// operand and one `STOP`. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub struct RawCode(#[serde(deserialize_with = "mpt::input_bytes")] pub Bytes); + +impl RawCode { + pub const PADDING: usize = 33; + + /// `code` with its padding. + pub fn new(code: &[u8]) -> Self { + let mut padded = Vec::with_capacity(code.len() + Self::PADDING); + padded.extend_from_slice(code); + padded.resize(code.len() + Self::PADDING, 0); + Self(padded.into()) + } + + /// The code as deployed. + pub fn code(&self) -> &[u8] { + &self.0[..self.0.len() - Self::PADDING] + } + + /// The analyzed bytecode: its jump table derived here, the padding + /// checked to be zeros. + /// + /// # Panics + /// Panics if the padding is missing or not zero. + pub fn analyze(&self) -> Bytecode { + let len = self.0.len().checked_sub(Self::PADDING).expect("code padding"); + assert!(self.0[len..].iter().all(|&b| b == 0), "code padding is not zero"); + let code = &self.0[..len]; + if code.starts_with(&EIP7702_MAGIC_BYTES) { + return Bytecode::new_raw(self.0.slice(..len)); + } + let jump_table = JumpTable::from_bytes(jump_table(&self.0, len).into(), len); + Bytecode::LegacyAnalyzed(LegacyAnalyzedBytecode::new(self.0.clone(), len, jump_table)) + } +} + +/// Bytes an opcode spans, its own byte included: `n + 1` for `PUSHn`, else 1. +const OPCODE_SPAN: [u8; 256] = { + let mut span = [1u8; 256]; + let mut n = 1; + while n <= 32 { + span[0x5f + n] = n as u8 + 1; + n += 1; + } + span +}; + +#[cfg(target_os = "zkvm")] +core::arch::global_asm!(include_str!("jumpdest.s")); + +#[cfg(target_os = "zkvm")] +extern "C" { + /// [`jump_table_walk`] in assembly (`jumpdest.s`): `code` readable up to + /// `len + 32`, `table` holding `⌈len/8⌉` zeroed bytes. + fn reth_jumpdest_scan(code: *const u8, len: usize, table: *mut u8); +} + +/// The `JUMPDEST` bitmap of the first `len` bytes of `padded`, bit `i & 7` of +/// byte `i >> 3` set when byte `i` starts an instruction and is `0x5b`. +/// +/// `padded` holds the code's [`RawCode::PADDING`] bytes past `len`. The walk +/// is six cycles per opcode in the zkVM against nine compiled, which saves +/// ~5.6 M of the ~400 M cycles of a mainnet block (~3 M opcodes walked). +fn jump_table(padded: &[u8], len: usize) -> Vec { + assert!(len + RawCode::PADDING <= padded.len()); + let mut table = vec![0u8; len.div_ceil(8)]; + // SAFETY: `padded` is readable up to `len + 32` and `table` holds + // `⌈len/8⌉` zeroed bytes, as the walk requires. + #[cfg(target_os = "zkvm")] + unsafe { + reth_jumpdest_scan(padded.as_ptr(), len, table.as_mut_ptr()) + }; + #[cfg(not(target_os = "zkvm"))] + jump_table_walk(padded, len, &mut table); + table +} + +/// The walk of [`jump_table`] in Rust. +/// +/// It reads only bytes below `len`; a push operand may carry the cursor up to +/// 32 bytes past it, which ends the walk. The raw pointers are sound because +/// the cursor is compared against the end before every read and +/// `i >> 3 < ⌈len/8⌉` for every `i < len`. +#[cfg_attr(target_os = "zkvm", allow(dead_code))] +fn jump_table_walk(padded: &[u8], len: usize, table: &mut [u8]) { + assert!(len <= padded.len() && table.len() == len.div_ceil(8)); + let base = padded.as_ptr(); + let end = base.wrapping_add(len); + let mut p = base; + while p < end { + let op = unsafe { *p }; + if op == revm::bytecode::opcode::JUMPDEST { + let i = p as usize - base as usize; + unsafe { *table.get_unchecked_mut(i >> 3) |= 1 << (i & 7) }; + } + p = p.wrapping_add(OPCODE_SPAN[op as usize] as usize); + } +} + #[derive(Debug)] pub struct TrieDB<'a> { - inner: &'a EthereumState, + inner: &'a ArenaState, block_hashes: HashMap, - bytecode_by_hash: HashMap, + /// Keyed by the host's CLAIMED hash; a claim is trusted only after + /// `verified_code` holds its analysis. + bytecode_by_hash: HashMap, + verified_code: core::cell::RefCell>, } impl<'a> TrieDB<'a> { pub fn new( - inner: &'a EthereumState, + inner: &'a ArenaState, block_hashes: HashMap, - bytecode_by_hash: HashMap, + bytecode_by_hash: HashMap, ) -> Self { - Self { inner, block_hashes, bytecode_by_hash } + Self { inner, block_hashes, bytecode_by_hash, verified_code: Default::default() } } } @@ -122,10 +249,10 @@ impl DatabaseRef for TrieDB<'_> { return Ok(Some(AccountInfo::default())) } - let hashed_address = keccak256(address); + let hashed_address = hashed_address(address); let hashed_address = hashed_address.as_slice(); - let account_in_trie = self.inner.state_trie.get_rlp::(hashed_address).unwrap(); + let account_in_trie = self.inner.account(hashed_address).unwrap(); let account = account_in_trie.map(|account_in_trie| AccountInfo { balance: account_in_trie.balance, @@ -138,24 +265,28 @@ impl DatabaseRef for TrieDB<'_> { } /// Get account code by its hash. + /// + /// The claimed hash is checked, and the jump table derived, the first time + /// the code is used; a wrong claim aborts the execution. fn code_by_hash_ref(&self, hash: B256) -> Result { - Ok(self.bytecode_by_hash.get(&hash).map(|code| (*code).clone()).unwrap()) + if let Some(code) = self.verified_code.borrow().get(&hash) { + return Ok(code.clone()); + } + let raw = *self.bytecode_by_hash.get(&hash).expect("bytecode for hash must be provided"); + assert_eq!(keccak256(raw.code()), hash, "bytecode does not match its claimed hash"); + let code = raw.analyze(); + self.verified_code.borrow_mut().insert(hash, code.clone()); + Ok(code) } /// Get storage value of address at index. fn storage_ref(&self, address: Address, index: U256) -> Result { - let hashed_address = keccak256(address); - let hashed_address = hashed_address.as_slice(); + let hashed_address = hashed_address(address); - let storage_trie = self + Ok(self .inner - .storage_tries - .get(hashed_address) - .expect("A storage trie must be provided for each account"); - - Ok(storage_trie - .get_rlp::(keccak256(index.to_be_bytes::<32>()).as_slice()) - .expect("Can get from MPT") + .storage(&hashed_address, hashed_slot(B256::from(index.to_be_bytes::<32>())).as_slice()) + .map_err(|err| ProviderError::TrieWitnessError(err.to_string()))? .unwrap_or_default()) } @@ -170,15 +301,18 @@ impl DatabaseRef for TrieDB<'_> { /// A trait for constructing [`WitnessDb`]. pub trait WitnessInput { - /// Gets a reference to the state from which account info and storage slots are loaded. - fn state(&self) -> &EthereumState; + /// Gets the witness state from which account info and storage slots are loaded. + fn state(&self) -> &WitnessState; /// Gets the state trie root hash that the state referenced by /// [state()](trait.WitnessInput#tymethod.state) must conform to. fn state_anchor(&self) -> B256; - /// Gets an iterator over account bytecodes. - fn bytecodes(&self) -> impl Iterator; + /// Gets an iterator over account bytecodes, as deployed. + fn bytecodes(&self) -> impl Iterator; + + /// The claimed code hash of each bytecode, in the same order. + fn code_hashes(&self) -> &[B256]; /// Gets an iterator over references to a consecutive, reverse-chronological block headers /// starting from the current block header. @@ -192,24 +326,29 @@ pub trait WitnessInput { /// implementing this trait causes a zkVM run to cost over 5M cycles more. To avoid this, define /// a method inside the type that calls this trait method instead. #[inline(always)] - fn witness_db(&self, sealed_headers: &[SealedHeader]) -> Result, ClientError> { - let state = self.state(); - - if self.state_anchor() != state.state_root() { + fn witness_db<'a>( + &'a self, + state: &'a ArenaState, + sealed_headers: &[SealedHeader], + ) -> Result, ClientError> { + // `state` was built from `self.state()`: every node keccak-checked + // against its parent's digest, the state trie against + // `state_root`, every storage trie against its account's storage + // root. What remains is binding that root to the parent header. + if self.state_anchor() != self.state().state_root { return Err(ClientError::MismatchedStateRoot); } - for (hashed_address, storage_trie) in state.storage_tries.iter() { - let account = - state.state_trie.get_rlp::(hashed_address.as_slice()).unwrap(); - let storage_root = account.map_or(EMPTY_ROOT_HASH, |a| a.storage_root); - if storage_root != storage_trie.hash() { - return Err(ClientError::MismatchedStorageRoot); - } + // Bytecodes are indexed by the host's claimed hash and verified on + // first use (see `TrieDB::code_by_hash_ref`); hashing every shipped + // contract up front was ~8 M cycles on a reth block, much of it for + // code that never runs. + let claimed = self.code_hashes(); + if claimed.len() != self.bytecodes().count() { + return Err(ClientError::InvalidWitness("code_hashes/bytecodes length mismatch".into())); } - let bytecodes_by_hash = - self.bytecodes().map(|code| (code.hash_slow(), code)).collect::>(); + claimed.iter().copied().zip(self.bytecodes()).collect::>(); // Verify and build block hashes let mut block_hashes: HashMap = HashMap::with_hasher(Default::default()); diff --git a/crates/executor/guest/src/jumpdest.s b/crates/executor/guest/src/jumpdest.s new file mode 100644 index 0000000..0bc12a9 --- /dev/null +++ b/crates/executor/guest/src/jumpdest.s @@ -0,0 +1,71 @@ +// reth_jumpdest_scan(code: *const u8, len: usize, table: *mut u8) +// +// The JUMPDEST bitmap of `code[..len]` for the zkVM guest: bit `i & 7` of +// `table[i >> 3]` is set when byte `i` starts an instruction and is 0x5b. +// `table` holds ceil(len / 8) zeroed bytes, and `code` must be readable up to +// `len + 32`: the RawCode padding, which the walk reads ahead into. +// +// The compiled walk spends nine instructions per opcode, two of them nops in +// branch delay slots. Here the slots carry work: the cursor advance sits in +// the JUMPDEST test's slot and the next opcode's load in the loop branch's, +// six instructions per opcode. The load ahead reads at most 32 bytes past +// `len` (a PUSH32 at `len - 1`), inside the padding. + .section .rodata.reth_jumpdest_span,"a",@progbits + .p2align 2 +.Lreth_jumpdest_span: + # bytes an opcode spans: n + 1 for PUSHn (0x60..0x7f), else 1 + .fill 96, 1, 1 + .byte 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 + .byte 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33 + .fill 128, 1, 1 + + .text + .globl reth_jumpdest_scan + .p2align 2 + .type reth_jumpdest_scan,@function + .set nomicromips + .set nomips16 + .ent reth_jumpdest_scan +reth_jumpdest_scan: + .frame $sp,0,$ra + .set noreorder + .set nomacro + .set noat + beqz $5, .Lreth_jumpdest_done + addu $9, $4, $5 + lui $10, %hi(.Lreth_jumpdest_span) + addiu $10, $10, %lo(.Lreth_jumpdest_span) + addiu $11, $zero, 0x5b + move $12, $4 + lbu $13, 0($12) +.Lreth_jumpdest_loop: + # $12 cursor, $13 the opcode under it, $9 end + addu $14, $10, $13 + lbu $14, 0($14) + beq $13, $11, .Lreth_jumpdest_mark + addu $12, $12, $14 +.Lreth_jumpdest_next: + sltu $1, $12, $9 + bnez $1, .Lreth_jumpdest_loop + lbu $13, 0($12) +.Lreth_jumpdest_done: + jr $ra + nop +.Lreth_jumpdest_mark: + # the cursor is one past the JUMPDEST: its index is $12 - 1 - code + subu $14, $12, $4 + addiu $14, $14, -1 + srl $15, $14, 3 + addu $15, $6, $15 + lbu $24, 0($15) + andi $14, $14, 7 + addiu $25, $zero, 1 + sllv $25, $25, $14 + or $24, $24, $25 + b .Lreth_jumpdest_next + sb $24, 0($15) + .set at + .set macro + .set reorder + .end reth_jumpdest_scan + .size reth_jumpdest_scan, .-reth_jumpdest_scan diff --git a/crates/executor/guest/src/lib.rs b/crates/executor/guest/src/lib.rs index bb754b7..3fcaa1c 100644 --- a/crates/executor/guest/src/lib.rs +++ b/crates/executor/guest/src/lib.rs @@ -1,4 +1,5 @@ #![cfg_attr(not(test), warn(unused_crate_dependencies))] +#![cfg_attr(target_os = "zkvm", feature(asm_experimental_arch))] /// Client program input data types. pub mod io; @@ -7,6 +8,8 @@ mod utils; pub mod custom; pub mod error; pub mod executor; +pub mod hashed_keys; +pub mod precompiles; pub mod tracking; mod into_primitives; @@ -17,10 +20,21 @@ use executor::{EthClientExecutor, DESERIALZE_INPUTS}; use io::EthClientExecutorInput; use std::sync::Arc; +/// Verifies an Ethereum mainnet block and returns its hash, its state root and +/// its parent's. +/// +/// The proof commits only the block hash, so the rules the block runs under +/// must not come from the prover: the input's chain must be mainnet, with no +/// beneficiary override (a Clique-only setting that redirects block rewards). pub fn verify_block(input: &[u8]) -> (B256, B256, B256) { println!("cycle-tracker-report-start: {DESERIALZE_INPUTS}"); let input = bincode::deserialize::(input).unwrap(); println!("cycle-tracker-report-end: {DESERIALZE_INPUTS}"); + assert!( + matches!(input.genesis, primitives::genesis::Genesis::Mainnet), + "the guest verifies Ethereum mainnet blocks only" + ); + assert!(input.custom_beneficiary.is_none(), "mainnet blocks pay the header's beneficiary"); // Execute the block. let executor = EthClientExecutor::eth( diff --git a/crates/executor/guest/src/precompiles.rs b/crates/executor/guest/src/precompiles.rs new file mode 100644 index 0000000..be57eac --- /dev/null +++ b/crates/executor/guest/src/precompiles.rs @@ -0,0 +1,563 @@ +//! Precompile arithmetic over the zkVM's curve and field syscalls. +//! +//! revm's default `Crypto` backends run bn254 scalar multiplication in +//! Jacobian coordinates and every BLS12-381 operation on arkworks' pure +//! Montgomery arithmetic, both of which are ordinary MIPS code in the guest. +//! These routines take the same byte inputs and compute with the `bn` +//! fork's affine syscalls and the `bls12_381` fork's syscall-backed field. + +use bls12_381::{ + fp::Fp, fp2::Fp2, hash_to_curve::MapToCurve, multi_miller_loop, G1Affine, G1Projective, + G2Affine, G2Prepared, G2Projective, Gt, Scalar, +}; +use kzg_rs::{ + kzg_proof::{safe_g1_affine_from_bytes, safe_scalar_affine_from_bytes}, + Bytes32, Bytes48, KzgSettings, +}; +use revm::precompile::PrecompileError; + +const FP: usize = 48; + +// --------------------------------------------------------------------------- +// bn254 + +/// The `ecAdd` precompile on two 64-byte points. +pub fn bn254_g1_add(p1: &[u8], p2: &[u8]) -> Result<[u8; 64], PrecompileError> { + let a = bn254::point(p1)?; + let b = bn254::point(p2)?; + Ok(bn254::encode(bn254::add(a, b))) +} + +/// The `ecMul` precompile on a 64-byte point and a 32-byte big-endian scalar. +pub fn bn254_g1_mul(point: &[u8], scalar: &[u8]) -> Result<[u8; 64], PrecompileError> { + let p = bn254::point(point)?; + Ok(bn254::encode(bn254::mul(p, scalar))) +} + +/// bn254 G1 in affine coordinates over the zkVM's curve precompiles, which +/// add two distinct finite points and double a finite point; infinity and +/// the equal-`x` cases are decided here. A point is `x || y` as 32-bit +/// little-endian words, the layout the precompiles read. +#[cfg(target_os = "zkvm")] +mod bn254 { + use revm::precompile::PrecompileError; + use zkm_lib::{syscall_bn254_add, syscall_bn254_double, syscall_uint256_mulmod}; + + type Words = [u32; 8]; + pub type Point = [u32; 16]; + + /// The base field modulus `p`, little-endian words. + const P: Words = [ + 0xd87cfd47, 0x3c208c16, 0x6871ca8d, 0x97816a91, 0x8181585d, 0xb85045b6, 0xe131a029, + 0x30644e72, + ]; + /// The group order `n`, little-endian words. + const N: Words = [ + 0xf0000001, 0x43e1f593, 0x79b97091, 0x2833e848, 0x8181585d, 0xb85045b6, 0xe131a029, + 0x30644e72, + ]; + const ONE: Words = [1, 0, 0, 0, 0, 0, 0, 0]; + const THREE: Words = [3, 0, 0, 0, 0, 0, 0, 0]; + + fn words(be: &[u8]) -> Words { + let mut w = [0u32; 8]; + for (i, word) in w.iter_mut().enumerate() { + *word = u32::from_be_bytes(be[28 - 4 * i..32 - 4 * i].try_into().expect("4 bytes")); + } + w + } + + fn bytes(w: &Words, be: &mut [u8]) { + for (i, word) in w.iter().enumerate() { + be[28 - 4 * i..32 - 4 * i].copy_from_slice(&word.to_be_bytes()); + } + } + + fn lt(a: &Words, b: &Words) -> bool { + for i in (0..8).rev() { + if a[i] != b[i] { + return a[i] < b[i]; + } + } + false + } + + /// `(a · b) mod m` through the 256-bit multiplier, which reads `b` and + /// `m` as one 16-word block. + fn mul_mod(a: &Words, b: &Words, m: &Words) -> Words { + let mut x = *a; + let mut bm = [0u32; 16]; + bm[..8].copy_from_slice(b); + bm[8..].copy_from_slice(m); + unsafe { syscall_uint256_mulmod(&mut x, bm.as_ptr().cast()) }; + x + } + + /// `(a + b) mod p` for `a, b < p`. + fn add_mod_p(a: &Words, b: &Words) -> Words { + let mut r = [0u32; 8]; + let mut carry = 0u64; + for i in 0..8 { + let s = a[i] as u64 + b[i] as u64 + carry; + r[i] = s as u32; + carry = s >> 32; + } + if carry != 0 || !lt(&r, &P) { + let mut borrow = 0i64; + for i in 0..8 { + let d = r[i] as i64 - P[i] as i64 - borrow; + r[i] = d as u32; + borrow = (d < 0) as i64; + } + } + r + } + + /// A point from its 64-byte big-endian `x || y` encoding, `None` for + /// `(0, 0)`; the coordinates must be canonical and on `y² = x³ + 3`. + pub fn point(be: &[u8]) -> Result, PrecompileError> { + let x = words(&be[..32]); + let y = words(&be[32..64]); + if !lt(&x, &P) || !lt(&y, &P) { + return Err(PrecompileError::Bn254FieldPointNotAMember); + } + if x == [0; 8] && y == [0; 8] { + return Ok(None); + } + let lhs = mul_mod(&y, &y, &P); + let rhs = add_mod_p(&mul_mod(&mul_mod(&x, &x, &P), &x, &P), &THREE); + if lhs != rhs { + return Err(PrecompileError::Bn254AffineGFailedToCreate); + } + let mut p = [0u32; 16]; + p[..8].copy_from_slice(&x); + p[8..].copy_from_slice(&y); + Ok(Some(p)) + } + + pub fn encode(p: Option) -> [u8; 64] { + let mut out = [0u8; 64]; + if let Some(p) = p { + bytes(p[..8].try_into().expect("8 words"), &mut out[..32]); + bytes(p[8..].try_into().expect("8 words"), &mut out[32..]); + } + out + } + + fn double(mut p: Point) -> Point { + unsafe { syscall_bn254_double(&mut p) }; + p + } + + /// `a + b`: equal points are doubled, opposite points (equal `x`) cancel. + pub fn add(a: Option, b: Option) -> Option { + match (a, b) { + (None, b) => b, + (a, None) => a, + (Some(mut a), Some(b)) => { + if a[..8] == b[..8] { + if a[8..] == b[8..] { + Some(double(a)) + } else { + None + } + } else { + unsafe { syscall_bn254_add(&mut a, &b) }; + Some(a) + } + } + } + } + + /// `k · p` by double-and-add. `k` is reduced modulo `n` first, so no + /// partial sum `k' · p` with `k' ≤ k / 2 < n - 1` equals `-p`, the one + /// case the addition cannot take; the partial sum `p` itself is only + /// ever doubled. + pub fn mul(p: Option, k: &[u8]) -> Option { + let p = p?; + let k = mul_mod(&words(k), &ONE, &N); + let mut acc: Option = None; + for i in (0..8).rev() { + for j in (0..32).rev() { + if let Some(a) = acc { + acc = Some(double(a)); + } + if (k[i] >> j) & 1 == 1 { + acc = add(acc, Some(p)); + } + } + } + acc + } +} + +/// bn254 G1 off the zkVM, through the `bn` crate. +#[cfg(not(target_os = "zkvm"))] +mod bn254 { + use bn::{AffineG1, Fq, Fr, G1}; + use revm::precompile::PrecompileError; + + pub type Point = G1; + + pub fn point(be: &[u8]) -> Result, PrecompileError> { + let x = + Fq::from_slice(&be[..32]).map_err(|_| PrecompileError::Bn254FieldPointNotAMember)?; + let y = + Fq::from_slice(&be[32..64]).map_err(|_| PrecompileError::Bn254FieldPointNotAMember)?; + if x.is_zero() && y.is_zero() { + return Ok(None); + } + AffineG1::new(x, y) + .map(|p| Some(p.into())) + .map_err(|_| PrecompileError::Bn254AffineGFailedToCreate) + } + + pub fn encode(p: Option) -> [u8; 64] { + let mut out = [0u8; 64]; + if let Some(p) = p.and_then(AffineG1::from_jacobian) { + p.x().to_big_endian(&mut out[..32]).expect("32 bytes"); + p.y().to_big_endian(&mut out[32..]).expect("32 bytes"); + } + out + } + + pub fn add(a: Option, b: Option) -> Option { + match (a, b) { + (None, b) => b, + (a, None) => a, + (Some(a), Some(b)) => Some(a + b), + } + } + + pub fn mul(p: Option, k: &[u8]) -> Option { + let k = Fr::from_slice(k).expect("32 bytes"); + p.map(|p| p * k) + } +} + +// --------------------------------------------------------------------------- +// BLS12-381 + +fn is_zero(bytes: &[u8]) -> bool { + bytes.iter().all(|&b| b == 0) +} + +fn fp(bytes: &[u8; FP]) -> Result { + Option::from(Fp::from_bytes(bytes)).ok_or(PrecompileError::NonCanonicalFp) +} + +fn fp2(c0: &[u8; FP], c1: &[u8; FP]) -> Result { + Ok(Fp2 { c0: fp(c0)?, c1: fp(c1)? }) +} + +/// A G1 point from its EIP-2537 coordinates, `(0, 0)` being the identity; +/// checked to be canonical and on the curve, and in the subgroup when asked. +fn g1(x: &[u8; FP], y: &[u8; FP], subgroup: bool) -> Result { + if is_zero(x) && is_zero(y) { + return Ok(G1Affine::identity()); + } + let mut bytes = [0u8; 2 * FP]; + bytes[..FP].copy_from_slice(x); + bytes[FP..].copy_from_slice(y); + let p: G1Affine = Option::from(G1Affine::from_uncompressed_unchecked(&bytes)) + .ok_or(PrecompileError::NonCanonicalFp)?; + if !bool::from(p.is_on_curve()) { + return Err(PrecompileError::Bls12381G1NotOnCurve); + } + if subgroup && !bool::from(p.is_torsion_free()) { + return Err(PrecompileError::Bls12381G1NotInSubgroup); + } + Ok(p) +} + +/// A G2 point from its EIP-2537 coordinates `(x0, x1, y0, y1)`. The +/// library's uncompressed form orders each Fp2 as `c1 || c0`. +fn g2( + x0: &[u8; FP], + x1: &[u8; FP], + y0: &[u8; FP], + y1: &[u8; FP], + subgroup: bool, +) -> Result { + if is_zero(x0) && is_zero(x1) && is_zero(y0) && is_zero(y1) { + return Ok(G2Affine::identity()); + } + let mut bytes = [0u8; 4 * FP]; + bytes[..FP].copy_from_slice(x1); + bytes[FP..2 * FP].copy_from_slice(x0); + bytes[2 * FP..3 * FP].copy_from_slice(y1); + bytes[3 * FP..].copy_from_slice(y0); + let p: G2Affine = Option::from(G2Affine::from_uncompressed_unchecked(&bytes)) + .ok_or(PrecompileError::NonCanonicalFp)?; + if !bool::from(p.is_on_curve()) { + return Err(PrecompileError::Bls12381G2NotOnCurve); + } + if subgroup && !bool::from(p.is_torsion_free()) { + return Err(PrecompileError::Bls12381G2NotInSubgroup); + } + Ok(p) +} + +/// The EIP-2537 encoding of a G1 point, zeros for the identity. +fn encode_g1(p: &G1Affine) -> [u8; 2 * FP] { + if bool::from(p.is_identity()) { + return [0u8; 2 * FP]; + } + p.to_uncompressed() +} + +/// The EIP-2537 encoding `x0 || x1 || y0 || y1` of a G2 point. +fn encode_g2(p: &G2Affine) -> [u8; 4 * FP] { + let mut out = [0u8; 4 * FP]; + if bool::from(p.is_identity()) { + return out; + } + let lib = p.to_uncompressed(); + out[..FP].copy_from_slice(&lib[FP..2 * FP]); + out[FP..2 * FP].copy_from_slice(&lib[..FP]); + out[2 * FP..3 * FP].copy_from_slice(&lib[3 * FP..]); + out[3 * FP..].copy_from_slice(&lib[2 * FP..3 * FP]); + out +} + +/// A scalar from 32 big-endian bytes, reduced modulo the group order as +/// EIP-2537 asks. +fn scalar(bytes: &[u8; 32]) -> Scalar { + let mut wide = [0u8; 64]; + for (i, &b) in bytes.iter().enumerate() { + wide[31 - i] = b; + } + Scalar::from_bytes_wide(&wide) +} + +pub type G1Point = ([u8; FP], [u8; FP]); +pub type G2Point = ([u8; FP], [u8; FP], [u8; FP], [u8; FP]); + +pub fn bls12_381_g1_add(a: G1Point, b: G1Point) -> Result<[u8; 2 * FP], PrecompileError> { + let a = g1(&a.0, &a.1, false)?; + let b = g1(&b.0, &b.1, false)?; + Ok(encode_g1(&G1Affine::from(G1Projective::from(a) + b))) +} + +pub fn bls12_381_g2_add(a: G2Point, b: G2Point) -> Result<[u8; 4 * FP], PrecompileError> { + let a = g2(&a.0, &a.1, &a.2, &a.3, false)?; + let b = g2(&b.0, &b.1, &b.2, &b.3, false)?; + Ok(encode_g2(&G2Affine::from(G2Projective::from(a) + b))) +} + +pub fn bls12_381_g1_msm( + pairs: &mut dyn Iterator>, +) -> Result<[u8; 2 * FP], PrecompileError> { + let mut acc = G1Projective::identity(); + for pair in pairs { + let ((x, y), k) = pair?; + let p = g1(&x, &y, true)?; + if bool::from(p.is_identity()) || is_zero(&k) { + continue; + } + acc += p * scalar(&k); + } + Ok(encode_g1(&G1Affine::from(acc))) +} + +pub fn bls12_381_g2_msm( + pairs: &mut dyn Iterator>, +) -> Result<[u8; 4 * FP], PrecompileError> { + let mut acc = G2Projective::identity(); + for pair in pairs { + let ((x0, x1, y0, y1), k) = pair?; + let p = g2(&x0, &x1, &y0, &y1, true)?; + if bool::from(p.is_identity()) || is_zero(&k) { + continue; + } + acc += p * scalar(&k); + } + Ok(encode_g2(&G2Affine::from(acc))) +} + +/// Whether the product of the pairings is the identity. Every point is +/// validated (subgroup included); a pair with an identity contributes the +/// identity and is left out of the Miller loop. +pub fn bls12_381_pairing_check(pairs: &[(G1Point, G2Point)]) -> Result { + let mut g1s = Vec::with_capacity(pairs.len()); + let mut g2s = Vec::with_capacity(pairs.len()); + for ((x, y), (x0, x1, y0, y1)) in pairs { + let p = g1(x, y, true)?; + let q = g2(x0, x1, y0, y1, true)?; + if bool::from(p.is_identity()) || bool::from(q.is_identity()) { + continue; + } + g1s.push(p); + g2s.push(G2Prepared::from(q)); + } + if g1s.is_empty() { + return Ok(true); + } + let terms: Vec<(&G1Affine, &G2Prepared)> = g1s.iter().zip(&g2s).collect(); + Ok(multi_miller_loop(&terms).final_exponentiation() == Gt::identity()) +} + +pub fn bls12_381_fp_to_g1(bytes: &[u8; FP]) -> Result<[u8; 2 * FP], PrecompileError> { + let u = fp(bytes)?; + let p = G1Projective::map_to_curve(&u).clear_h(); + Ok(encode_g1(&G1Affine::from(p))) +} + +pub fn bls12_381_fp2_to_g2(c: ([u8; FP], [u8; FP])) -> Result<[u8; 4 * FP], PrecompileError> { + let u = fp2(&c.0, &c.1)?; + let p = G2Projective::map_to_curve(&u).clear_h(); + Ok(encode_g2(&G2Affine::from(p))) +} + +// --------------------------------------------------------------------------- +// KZG point evaluation + +/// The pairing check of the KZG point-evaluation precompile with its two +/// G2 arguments fixed, so both are prepared once: +/// +/// `e(P - y·G1, G2) · e(-π, τ·G2 - z·G2) = 1` is, by bilinearity, +/// `e(P - y·G1 + z·π, G2) · e(-π, τ·G2) = 1`, +/// +/// which moves the only scalar multiplication to G1, where it is one joint +/// double-and-add over `y` and `z`, and leaves the G2 side constant. +pub struct KzgVerifier { + g2: G2Prepared, + tau_g2: G2Prepared, +} + +impl KzgVerifier { + pub fn new(settings: &KzgSettings) -> Self { + Self { + g2: G2Prepared::from(G2Affine::generator()), + tau_g2: G2Prepared::from(settings.g2_points[1]), + } + } + + /// Whether `proof` opens `commitment` at `z` to `y`; the points are + /// decoded with kzg-rs's checks (canonical, on the curve, in the + /// subgroup), the scalars must be canonical. + pub fn verify( + &self, + z: &[u8; 32], + y: &[u8; 32], + commitment: &[u8; 48], + proof: &[u8; 48], + ) -> Result { + let other = |err: kzg_rs::KzgError| PrecompileError::other(err.to_string()); + let z = safe_scalar_affine_from_bytes(&Bytes32(*z)).map_err(other)?; + let y = safe_scalar_affine_from_bytes(&Bytes32(*y)).map_err(other)?; + let commitment = safe_g1_affine_from_bytes(&Bytes48(*commitment)).map_err(other)?; + let proof = safe_g1_affine_from_bytes(&Bytes48(*proof)).map_err(other)?; + + let minus_g1 = -G1Affine::generator(); + let a = + G1Affine::from(linear_combination(&minus_g1, &y, &proof, &z).add_mixed(&commitment)); + let minus_proof = -proof; + let mut terms: Vec<(&G1Affine, &G2Prepared)> = Vec::with_capacity(2); + if !bool::from(a.is_identity()) { + terms.push((&a, &self.g2)); + } + if !bool::from(minus_proof.is_identity()) { + terms.push((&minus_proof, &self.tau_g2)); + } + if terms.is_empty() { + return Ok(true); + } + Ok(multi_miller_loop(&terms).final_exponentiation() == Gt::identity()) + } +} + +/// `s·a + t·b` by one double-and-add over both scalars (Straus), with +/// `a + b` precomputed; nothing here is secret, so the walk is not +/// constant-time. +fn linear_combination(a: &G1Affine, s: &Scalar, b: &G1Affine, t: &Scalar) -> G1Projective { + let ab = G1Affine::from(G1Projective::from(*a).add_mixed(b)); + let s = s.to_bytes(); + let t = t.to_bytes(); + let mut acc = G1Projective::identity(); + let mut started = false; + for i in (0..256).rev() { + if started { + acc = acc.double(); + } + let sb = (s[i / 8] >> (i % 8)) & 1 == 1; + let tb = (t[i / 8] >> (i % 8)) & 1 == 1; + match (sb, tb) { + (true, true) => acc = acc.add_mixed(&ab), + (true, false) => acc = acc.add_mixed(a), + (false, true) => acc = acc.add_mixed(b), + (false, false) => {} + } + started |= sb | tb; + } + acc +} + +// --------------------------------------------------------------------------- +// modexp + +/// `base^exp mod modulus` as big-endian bytes, at most `modulus.len()` of +/// them. Operands of up to 256 bits run as a square-and-multiply ladder on +/// the uint256 multiplier; anything wider takes the generic implementation. +pub fn modexp(base: &[u8], exp: &[u8], modulus: &[u8]) -> Vec { + #[cfg(target_os = "zkvm")] + if base.len() <= 32 && modulus.len() <= 32 { + return modexp256::modexp(base, exp, modulus); + } + aurora_engine_modexp::modexp(base, exp, modulus) +} + +#[cfg(target_os = "zkvm")] +mod modexp256 { + use zkm_lib::syscall_uint256_mulmod; + + type Words = [u32; 8]; + + /// Big-endian bytes (at most 32) as little-endian words. + fn words(be: &[u8]) -> Words { + let mut padded = [0u8; 32]; + padded[32 - be.len()..].copy_from_slice(be); + let mut w = [0u32; 8]; + for (i, word) in w.iter_mut().enumerate() { + *word = u32::from_be_bytes(padded[28 - 4 * i..32 - 4 * i].try_into().expect("4 bytes")); + } + w + } + + /// `(a · b) mod m` for `m ≠ 0`; the multiplier reads `b` and `m` as one + /// 16-word block. + fn mul_mod(a: &Words, b: &Words, m: &Words) -> Words { + let mut x = *a; + let mut bm = [0u32; 16]; + bm[..8].copy_from_slice(b); + bm[8..].copy_from_slice(m); + unsafe { syscall_uint256_mulmod(&mut x, bm.as_ptr().cast()) }; + x + } + + pub fn modexp(base: &[u8], exp: &[u8], modulus: &[u8]) -> Vec { + let m = words(modulus); + if m == [0; 8] || m == [1, 0, 0, 0, 0, 0, 0, 0] { + return Vec::new(); + } + let b = mul_mod(&words(base), &[1, 0, 0, 0, 0, 0, 0, 0], &m); + let mut r: Words = [1, 0, 0, 0, 0, 0, 0, 0]; + let mut started = false; + for &byte in exp { + for j in (0..8).rev() { + if started { + r = mul_mod(&r, &r, &m); + } + if (byte >> j) & 1 == 1 { + r = mul_mod(&r, &b, &m); + started = true; + } + } + } + let mut out = [0u8; 32]; + for (i, word) in r.iter().enumerate() { + out[28 - 4 * i..32 - 4 * i].copy_from_slice(&word.to_be_bytes()); + } + out[32 - modulus.len()..].to_vec() + } +} diff --git a/crates/executor/host/examples/witness_census.rs b/crates/executor/host/examples/witness_census.rs new file mode 100644 index 0000000..34ee4eb --- /dev/null +++ b/crates/executor/host/examples/witness_census.rs @@ -0,0 +1,127 @@ +//! Native census of a cached client input's witness: how many trie nodes of +//! each kind the guest's arena loader walks, how many bytes, and how long the +//! native load takes. `cargo run --release --example witness_census -- ` +use std::time::Instant; + +use guest_executor::io::EthClientExecutorInput; +use mpt::ArenaState; + +const TAG_DIGEST: u8 = 0; +const TAG_NODE: u8 = 1; + +#[derive(Default, Debug)] +struct Census { + nodes: usize, + nulls: usize, + digests: usize, + leaves: usize, + extensions: usize, + branches: usize, + inline_children: usize, + node_bytes: usize, + keccak_blocks: usize, +} + +fn varint(buf: &[u8], pos: &mut usize) -> usize { + let (mut v, mut shift) = (0usize, 0); + loop { + let b = buf[*pos]; + *pos += 1; + v |= ((b & 0x7f) as usize) << shift; + if b & 0x80 == 0 { + return v; + } + shift += 7; + } +} + +fn items(payload: &[u8]) -> usize { + let mut rest = payload; + let mut n = 0; + while !rest.is_empty() { + let h = alloy_rlp::Header::decode(&mut rest).unwrap(); + rest = &rest[h.payload_length..]; + n += 1; + } + n +} + +fn walk(stream: &[u8], c: &mut Census) { + let mut pos = 0; + while pos < stream.len() { + let tag = stream[pos]; + pos += 1; + match tag { + TAG_DIGEST => c.digests += 1, + TAG_NODE => { + let len = varint(stream, &mut pos); + let node = &stream[pos..pos + len]; + pos += len; + c.nodes += 1; + c.node_bytes += len; + c.keccak_blocks += len.div_ceil(136); + let mut b = node; + let h = alloy_rlp::Header::decode(&mut b).unwrap(); + let payload = &b[..h.payload_length]; + if !h.list { + c.nulls += 1; + continue; + } + match items(payload) { + 2 => { + let mut r = payload; + let ph = alloy_rlp::Header::decode(&mut r).unwrap(); + let path = &r[..ph.payload_length]; + if path[0] & 0x20 == 0 { + c.extensions += 1 + } else { + c.leaves += 1 + } + } + 17 => { + c.branches += 1; + let mut r = payload; + for _ in 0..16 { + let ch = alloy_rlp::Header::decode(&mut r).unwrap(); + if ch.list { + c.inline_children += 1; + } + r = &r[ch.payload_length..]; + } + } + n => panic!("node with {n} items"), + } + } + _ => panic!("bad tag"), + } + } +} + +fn main() { + let path = std::env::args().nth(1).expect("input.bin"); + let bytes = std::fs::read(&path).unwrap(); + let t = Instant::now(); + let input: EthClientExecutorInput = bincode::deserialize(&bytes).unwrap(); + println!("input {} B, bincode decode {:?}", bytes.len(), t.elapsed()); + let w = &input.parent_state; + let mut state = Census::default(); + walk(&w.state_nodes, &mut state); + println!("state trie: {} B stream, {state:?}", w.state_nodes.len()); + let mut storage = Census::default(); + let mut storage_bytes = 0; + for sw in &w.storage { + storage_bytes += sw.nodes.len(); + walk(&sw.nodes, &mut storage); + } + println!("storage tries: {} tries, {storage_bytes} B streams, {storage:?}", w.storage.len()); + println!( + "bytecodes: {} ({} code bytes), txs {}", + input.bytecodes.len(), + input.bytecodes.iter().map(|b| b.code().len()).sum::(), + input.current_block.body.transactions.len() + ); + let t = Instant::now(); + let st = ArenaState::from_witness(w).unwrap(); + println!("native ArenaState::from_witness: {:?}", t.elapsed()); + std::hint::black_box(st); +} diff --git a/crates/executor/host/src/full_executor.rs b/crates/executor/host/src/full_executor.rs index 2785c03..1a5ffc6 100644 --- a/crates/executor/host/src/full_executor.rs +++ b/crates/executor/host/src/full_executor.rs @@ -113,10 +113,25 @@ pub trait BlockExecutor { info!("cycles: {:?}", proof_with_cycles.1); - let proving_duration = proving_start.elapsed(); + // Prefer the prover's own measure when it has one. This process + // times the whole call, which with a pipelined caller includes the + // request waiting in the prover's queue; the prover times only the + // proving. Everything downstream — the eth-proofs submission + // among it — should report proving, not queueing. + let proving_duration = self + .client() + .take_prove_ms() + .map(Duration::from_millis) + .unwrap_or_else(|| proving_start.elapsed()); let proof_bytes = bincode::serialize(&proof_with_cycles.0.proof).unwrap(); let public_values_bytes = bincode::serialize(&proof_with_cycles.0.public_values).unwrap(); + // Size census: dump the exact bytes that get submitted so the + // proof's composition can be measured offline. + if let Ok(path) = std::env::var("ZIREN_COMPRESS_PROOF_OUT") { + std::fs::write(&path, &proof_bytes)?; + info!("wrote {} proof bytes to {path}", proof_bytes.len()); + } hooks .on_proving_end( @@ -271,14 +286,12 @@ where } Ok(()) } -} -impl BlockExecutor for FullExecutor -where - C: ExecutorComponents, - P: Provider + Clone + std::fmt::Debug, -{ - async fn execute(&self, block_number: u64) -> eyre::Result<()> { + /// Fetch the block and witness and execute natively, without starting GPU proving. + pub async fn prepare( + &self, + block_number: u64, + ) -> eyre::Result> { self.hooks.on_execution_start(block_number).await?; let client_input_from_cache = self.config.cache_dir.as_ref().and_then(|cache_dir| { @@ -333,9 +346,25 @@ where }; info!("Block {} executed in {:?}", block_number, now.elapsed()); - self.process_client(client_input, &self.hooks, self.config.prove_mode).await?; + Ok(client_input) + } - Ok(()) + /// Prove a prepared input; callers serialize core and compression together. + pub async fn prove_prepared( + &self, + client_input: ClientExecutorInput, + ) -> eyre::Result<()> { + self.process_client(client_input, &self.hooks, self.config.prove_mode).await + } +} + +impl BlockExecutor for FullExecutor +where + C: ExecutorComponents, + P: Provider + Clone + std::fmt::Debug, +{ + async fn execute(&self, block_number: u64) -> eyre::Result<()> { + self.prove_prepared(self.prepare(block_number).await?).await } fn client(&self) -> Arc { @@ -471,7 +500,15 @@ fn try_load_input_from_cache( if cache_path.exists() { // TODO: prune the cache if invalid instead let mut cache_file = std::fs::File::open(cache_path)?; - let client_input = bincode::deserialize_from(&mut cache_file)?; + let client_input = match bincode::deserialize_from(&mut cache_file) { + Ok(input) => input, + Err(err) => { + tracing::warn!( + "cached input for block {block_number} is unreadable ({err}); refetching" + ); + return Ok(None); + } + }; Ok(Some(client_input)) } else { diff --git a/crates/executor/host/src/host_executor.rs b/crates/executor/host/src/host_executor.rs index 421e69b..8c24c67 100644 --- a/crates/executor/host/src/host_executor.rs +++ b/crates/executor/host/src/host_executor.rs @@ -76,22 +76,41 @@ impl HostExecutor { let chain_id: u64 = (&genesis).try_into().unwrap(); tracing::debug!("chain id: {}", chain_id); - // Fetch the current block and the previous block from the provider. + // Fetch the current block, the previous block and (with the + // execution-witness feature) the witness concurrently. Only the + // witness DB construction needs the parent's state root; the three RPC + // round trips themselves are independent, and run serially they were + // ~4 s of the ~4.2 s an uncached block spends before proving starts. tracing::info!("[{}] fetching the current block and the previous block", block_number); - let rpc_block = provider - .get_block_by_number(block_number.into()) - .full() - .await? - .ok_or(HostError::ExpectedBlock(block_number))?; + let fetch_current = async { + provider + .get_block_by_number(block_number.into()) + .full() + .await? + .ok_or(HostError::ExpectedBlock(block_number)) + }; + let fetch_previous = async { + provider + .get_block_by_number((block_number - 1).into()) + .full() + .await? + .ok_or(HostError::ExpectedBlock(block_number)) + .map(C::Primitives::into_primitive_block) + }; - let current_block = C::Primitives::into_primitive_block(rpc_block.clone()); + #[cfg(not(feature = "execution-witness"))] + let (rpc_block, previous_block) = futures::try_join!(fetch_current, fetch_previous)?; + #[cfg(feature = "execution-witness")] + let (rpc_block, previous_block, execution_witness) = { + let fetch_witness = async { + rpc_db::ExecutionWitnessRpcDb::<_, N>::fetch_witness(debug_provider, block_number) + .await + .map_err(HostError::from) + }; + futures::try_join!(fetch_current, fetch_previous, fetch_witness)? + }; - let previous_block = provider - .get_block_by_number((block_number - 1).into()) - .full() - .await? - .ok_or(HostError::ExpectedBlock(block_number)) - .map(C::Primitives::into_primitive_block)?; + let current_block = C::Primitives::into_primitive_block(rpc_block.clone()); tracing::info!("[{}] create rpc db", block_number); #[cfg(not(feature = "execution-witness"))] @@ -101,12 +120,12 @@ impl HostExecutor { previous_block.header().state_root(), ); #[cfg(feature = "execution-witness")] - let rpc_db = rpc_db::ExecutionWitnessRpcDb::new( + let rpc_db = rpc_db::ExecutionWitnessRpcDb::from_witness( debug_provider, block_number, previous_block.header().state_root(), - ) - .await?; + execution_witness, + ); tracing::info!("[{}] create rpc db done", block_number); let cache_db = CacheDB::new(&rpc_db); @@ -216,8 +235,15 @@ impl HostExecutor { let client_input = ClientExecutorInput { current_block: C::Primitives::into_input_block(current_block), ancestor_headers, - parent_state: state, - bytecodes: rpc_db.bytecodes(), + // Witness form: root hashes + preorder streams of raw RLP nodes; the + // guest builds its arena tries from it, hash-checking every node. + parent_state: state.to_witness_state(), + code_hashes: rpc_db.bytecodes().iter().map(|b| b.hash_slow()).collect(), + bytecodes: rpc_db + .bytecodes() + .iter() + .map(|b| guest_executor::io::RawCode::new(b.original_byte_slice())) + .collect(), genesis, custom_beneficiary, opcode_tracking, diff --git a/crates/mpt/Cargo.toml b/crates/mpt/Cargo.toml index f54e51c..c340c70 100644 --- a/crates/mpt/Cargo.toml +++ b/crates/mpt/Cargo.toml @@ -23,6 +23,7 @@ alloy-rpc-types-debug = {workspace = true, optional = true } [dev-dependencies] hex-literal.workspace = true +reth-primitives-traits.workspace = true [features] default = ["execution-witness"] diff --git a/crates/mpt/src/arena.rs b/crates/mpt/src/arena.rs new file mode 100644 index 0000000..0211249 --- /dev/null +++ b/crates/mpt/src/arena.rs @@ -0,0 +1,1364 @@ +//! Arena-backed Merkle Patricia trie for the guest. +//! +//! The guest used to deserialize the witness as a tree of boxed [`MptNode`]s +//! (one heap allocation and two ~112-byte copies per node, 16 of them per +//! branch) and then RLP-encode and keccak every node again to check the state +//! root. On a reth block that was ~37 M cycles of decoding plus ~31 M of +//! hashing for ~9.6 K nodes — a third of the block. +//! +//! Here the host ships each trie as a *preorder stream* of raw RLP nodes +//! ([`WitnessState`]), and the guest builds an [`ArenaTrie`] from it in one +//! pass: nodes live in one `Vec`, children are indices, every node is +//! keccak-checked exactly once against the digest its parent carries (the +//! root against the anchor), and the verified digest is kept as the node's +//! reference so the state-root pass only re-hashes what the block mutated. +//! No per-node allocation of children, no hash-map lookups. +//! +//! [`MptNode`] stays the host-side representation; it is also the test +//! oracle for this module. + +use alloy_primitives::{map::HashMap, Bytes, B256, U256}; +use alloy_rlp::Encodable; +use core::mem; +use reth_trie::{HashedPostState, HashedStorage, TrieAccount, EMPTY_ROOT_HASH}; +use serde::{Deserialize, Serialize}; + +use super::mpt::{ + keccak, lcp, prefix_nibs, to_encoded_path, Error, MptNode, MptNodeData, MptNodeReference, + RlpBytes, EMPTY_ROOT, +}; + +/// Stream tag: the referenced node is not part of the witness (stays a digest). +/// The RLP prefix of a 32-byte string: how a trie node references a child +/// that lives outside it. +const DIGEST_STRING_CODE: u8 = alloy_rlp::EMPTY_STRING_CODE + 32; + +const TAG_DIGEST: u8 = 0; +/// Stream tag: a node follows as `varint(len) || rlp`. +const TAG_NODE: u8 = 1; + +/// The state tries in witness form: for the state trie and every storage +/// trie, the root hash and a preorder stream of raw RLP nodes. +#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] +pub struct WitnessState { + pub state_root: B256, + #[serde(deserialize_with = "input_bytes")] + pub state_nodes: Bytes, + /// One entry per storage trie, sorted by hashed address so the input + /// bytes are reproducible. + pub storage: Vec, +} + +/// One account's storage trie in witness form: its hashed address, its root +/// and the preorder stream of its raw RLP nodes. +/// +/// Bincode writes a struct as its fields in order, so this is byte-identical +/// to the `(B256, B256, Bytes)` tuple it replaced and cached inputs stay +/// readable. +#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] +pub struct StorageWitness { + pub hashed_address: B256, + pub root: B256, + #[serde(deserialize_with = "input_bytes")] + pub nodes: Bytes, +} + +/// Deserialise a byte string into `Bytes` without copying it in the guest. +/// +/// The program input is read once and leaked by `main`, so it outlives the +/// run and bincode's borrowed slices of it can be kept as they are: the +/// witness streams are 6-7 MB per reth block, and copying them out of the +/// input buffer cost ~7 M cycles. Off the zkVM the bytes are copied. +pub fn input_bytes<'de, D: serde::Deserializer<'de>>(d: D) -> Result { + struct V; + impl<'de> serde::de::Visitor<'de> for V { + type Value = Bytes; + + fn expecting(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.write_str("a byte string") + } + + fn visit_borrowed_bytes(self, v: &'de [u8]) -> Result { + #[cfg(target_os = "zkvm")] + { + // SAFETY: the guest leaks its input buffer (bin/guest/src/main.rs), + // so every slice of it lives as long as the program. + let v: &'static [u8] = + unsafe { core::mem::transmute::<&'de [u8], &'static [u8]>(v) }; + Ok(Bytes::from_static(v)) + } + #[cfg(not(target_os = "zkvm"))] + { + Ok(Bytes::copy_from_slice(v)) + } + } + + fn visit_bytes(self, v: &[u8]) -> Result { + Ok(Bytes::copy_from_slice(v)) + } + + fn visit_byte_buf(self, v: Vec) -> Result { + Ok(Bytes::from(v)) + } + + fn visit_seq>(self, mut seq: A) -> Result { + let mut out = Vec::with_capacity(seq.size_hint().unwrap_or(0)); + while let Some(b) = seq.next_element::()? { + out.push(b); + } + Ok(Bytes::from(out)) + } + } + d.deserialize_bytes(V) +} + +// --------------------------------------------------------------------------- +// Host side: MptNode -> preorder stream +// --------------------------------------------------------------------------- + +fn put_varint(out: &mut Vec, mut v: usize) { + while v >= 0x80 { + out.push((v as u8) | 0x80); + v >>= 7; + } + out.push(v as u8); +} + +fn is_hashed(node: &MptNode) -> bool { + matches!(node.reference(), MptNodeReference::Digest(_)) +} + +/// Emit `node` (which its parent references by digest, or the root) and, +/// recursively, every digest-referenced descendant, in preorder. Children +/// inlined in their parent's RLP need no entry: an inline node cannot carry a +/// digest child, so its whole subtree is inside the parent's bytes. +fn emit_node(node: &MptNode, out: &mut Vec) { + match node.as_data() { + MptNodeData::Digest(_) => out.push(TAG_DIGEST), + _ => { + let rlp = node.to_rlp(); + out.push(TAG_NODE); + put_varint(out, rlp.len()); + out.extend_from_slice(&rlp); + emit_children(node, out); + } + } +} + +fn emit_children(node: &MptNode, out: &mut Vec) { + match node.as_data() { + MptNodeData::Branch(children) => { + for child in children.iter().flatten() { + if is_hashed(child) { + emit_node(child, out); + } else { + emit_children(child, out); + } + } + } + MptNodeData::Extension(_, child) => { + if is_hashed(child) { + emit_node(child, out); + } else { + emit_children(child, out); + } + } + _ => {} + } +} + +/// The preorder node stream of a trie rooted at `root`. +pub fn witness_stream(root: &MptNode) -> Bytes { + let mut out = Vec::new(); + emit_node(root, &mut out); + out.into() +} + +// --------------------------------------------------------------------------- +// Guest side: arena trie +// --------------------------------------------------------------------------- + +type NodeId = u32; +const NONE: NodeId = u32::MAX; + +#[derive(Debug, Clone, PartialEq, Eq)] +enum Node { + Null, + /// Compact-encoded path (as in the RLP) and the value, both slices of + /// the witness stream for a node read from it. + Leaf(Bytes, Bytes), + /// Compact-encoded path and the child. + Extension(Bytes, NodeId), + Branch([NodeId; 16]), + Digest(B256), +} + +#[derive(Debug, Clone, PartialEq, Eq)] +enum Ref { + /// Encodings shorter than 32 bytes are inlined by the parent. + Bytes(Vec), + Digest(B256), +} + +impl Ref { + fn encode(&self, out: &mut Vec) { + match self { + Ref::Bytes(b) => out.extend_from_slice(b), + Ref::Digest(d) => push_digest(out, &d.0), + } + } + fn length(&self) -> usize { + match self { + Ref::Bytes(b) => b.len(), + Ref::Digest(_) => 33, + } + } +} + +/// Appends the RLP of a 32-byte string, `0xa0` then `digest`, to `out`. +/// +/// The digest is moved as eight unaligned words rather than byte by byte: +/// a reth block's state-root pass writes ~100 K of them. The writes are +/// sound because `out` has room for 33 bytes after the reservation, every +/// word of `digest` is in bounds, and the length is set to what was written. +#[inline] +fn push_digest(out: &mut Vec, digest: &[u8; 32]) { + out.reserve(33); + let len = out.len(); + unsafe { + let dst = out.as_mut_ptr().add(len); + *dst = DIGEST_STRING_CODE; + let src = digest.as_ptr().cast::(); + let dst = dst.add(1).cast::(); + for w in 0..8 { + dst.add(w).write_unaligned(src.add(w).read_unaligned()); + } + out.set_len(len + 33); + } +} + +/// A child slot whose top bit is set holds no node: the low bits are the +/// byte offset, in `ArenaTrie::stream`, of the 32-byte digest the parent's +/// RLP references (a sibling outside the witness). The witness carries far +/// more such digests than nodes (a reth block: ~160 K digests against ~20 K +/// nodes), and materialising each as a node cost two arena pushes and a +/// reallocation or two per trie. +const DIGEST_BIT: NodeId = 1 << 31; + +/// A Merkle Patricia trie whose nodes live in one arena. +#[derive(Debug, Clone)] +pub struct ArenaTrie { + nodes: Vec, + /// Cached reference of each node; `None` after a mutation on its path. + refs: Vec>, + root: NodeId, + /// The witness stream the digest slots point into (empty for a trie + /// built by insertion). + stream: Bytes, +} + +impl Default for ArenaTrie { + fn default() -> Self { + Self { nodes: vec![Node::Null], refs: vec![None], root: 0, stream: Bytes::new() } + } +} + +struct Stream<'a> { + buf: &'a [u8], + pos: usize, +} + +impl<'a> Stream<'a> { + #[inline] + fn peek(&self) -> Option { + self.buf.get(self.pos).copied() + } + fn byte(&mut self) -> Result { + let b = *self.buf.get(self.pos).ok_or(Error::WitnessFormat("truncated stream"))?; + self.pos += 1; + Ok(b) + } + fn varint(&mut self) -> Result { + let mut v = 0usize; + let mut shift = 0; + loop { + let b = self.byte()?; + v |= ((b & 0x7f) as usize) << shift; + if b & 0x80 == 0 { + return Ok(v); + } + shift += 7; + if shift > 28 { + return Err(Error::WitnessFormat("varint too long")); + } + } + } + fn node(&mut self) -> Result<&'a [u8], Error> { + let len = self.varint()?; + let bytes = + self.buf.get(self.pos..self.pos + len).ok_or(Error::WitnessFormat("truncated node"))?; + self.pos += len; + Ok(bytes) + } +} + +/// Split one RLP item off the front of `buf`: (header, payload, whole item). +#[inline] +fn take_item<'a>( + buf: &mut &'a [u8], +) -> Result<(alloy_rlp::Header, &'a [u8], &'a [u8]), alloy_rlp::Error> { + // Fast paths. Nearly every item inside a witness trie node is either an + // absent child (`0x80`) or a 32-byte digest (`0xa0 ..`), and there are + // ~200 K of them per reth block: the generic header decoder's bounds + // checks and length arithmetic are most of what the witness load spends. + match buf.first() { + Some(&alloy_rlp::EMPTY_STRING_CODE) => { + let (whole, rest) = buf.split_at(1); + *buf = rest; + return Ok((alloy_rlp::Header { list: false, payload_length: 0 }, &whole[1..], whole)); + } + Some(&DIGEST_STRING_CODE) if buf.len() >= 33 => { + let (whole, rest) = buf.split_at(33); + *buf = rest; + return Ok((alloy_rlp::Header { list: false, payload_length: 32 }, &whole[1..], whole)); + } + _ => {} + } + let start = *buf; + let header = alloy_rlp::Header::decode(buf)?; + let payload = buf.get(..header.payload_length).ok_or(alloy_rlp::Error::InputTooShort)?; + *buf = &buf[header.payload_length..]; + let whole = &start[..start.len() - buf.len()]; + Ok((header, payload, whole)) +} + +impl ArenaTrie { + /// Build the trie from its root hash and preorder node stream, checking + /// every node's keccak against the digest that references it. + pub fn from_stream(root: B256, stream: Bytes) -> Result { + // Real nodes only: a witnessed node is a few hundred bytes on average + // (branches dominate), so this never reallocates. + let cap = stream.len() / 96 + 8; + let mut trie = ArenaTrie { + nodes: Vec::with_capacity(cap), + refs: Vec::with_capacity(cap), + root: NONE, + stream: stream.clone(), + }; + let mut s = Stream { buf: &stream, pos: 0 }; + let id = trie.build(&mut s, root, None)?; + if s.pos != stream.len() { + return Err(Error::WitnessFormat("trailing bytes")); + } + trie.root = id; + Ok(trie) + } + + #[inline] + fn is_digest(id: NodeId) -> bool { + id != NONE && id & DIGEST_BIT != 0 + } + + /// The digest a digest slot references. + #[inline] + fn digest_at(&self, id: NodeId) -> B256 { + let off = (id & !DIGEST_BIT) as usize; + B256::from_slice(&self.stream[off..off + 32]) + } + + #[inline] + fn push(&mut self, node: Node, r: Option) -> NodeId { + let id = self.nodes.len() as NodeId; + self.nodes.push(node); + self.refs.push(r); + id + } + + /// Next stream entry, which the parent references by `expected`. A + /// digest entry becomes `slot` when the parent offers one (the offset of + /// the digest in its own RLP), else a `Node::Digest` (the root). + fn build( + &mut self, + s: &mut Stream<'_>, + expected: B256, + slot: Option, + ) -> Result { + match s.byte()? { + TAG_DIGEST => Ok(match slot { + Some(id) => id, + None => self.push(Node::Digest(expected), Some(Ref::Digest(expected))), + }), + TAG_NODE => { + let bytes = s.node()?; + if !eq32(&keccak(bytes), &expected.0) { + return Err(Error::WitnessNodeMismatch(expected)); + } + let r = if bytes.len() < 32 { + Ref::Bytes(bytes.to_vec()) + } else { + Ref::Digest(expected) + }; + let mut buf = bytes; + let (header, payload, _) = take_item(&mut buf)?; + if !buf.is_empty() { + return Err(Error::WitnessFormat("node has trailing bytes")); + } + self.decode_item(header, payload, r, s) + } + _ => Err(Error::WitnessFormat("bad tag")), + } + } + + /// A child item inside a node's RLP: absent, a digest (whose node is the + /// next stream entry), or an inline node. + fn child( + &mut self, + header: alloy_rlp::Header, + payload: &[u8], + whole: &[u8], + s: &mut Stream<'_>, + ) -> Result { + if header.list { + return self.decode_item(header, payload, Ref::Bytes(whole.to_vec()), s); + } + match payload.len() { + 0 => Ok(NONE), + 32 => { + // Where this digest sits in the stream, for a digest slot. + let off = payload.as_ptr() as usize - self.stream.as_ptr() as usize; + self.build(s, B256::from_slice(payload), Some(DIGEST_BIT | off as NodeId)) + } + _ => Err(alloy_rlp::Error::UnexpectedLength.into()), + } + } + + /// A child item already split off its node: absent and digest-of-digest + /// children are resolved without a call, the rest through `child`. + #[inline] + fn common_child( + &mut self, + header: alloy_rlp::Header, + payload: &[u8], + whole: &[u8], + s: &mut Stream<'_>, + ) -> Result { + if !header.list { + if payload.is_empty() { + return Ok(NONE); + } + if payload.len() == 32 && s.peek() == Some(TAG_DIGEST) { + s.pos += 1; + let off = payload.as_ptr() as usize - self.stream.as_ptr() as usize; + return Ok(DIGEST_BIT | off as NodeId); + } + } + self.child(header, payload, whole, s) + } + + /// Decode one node item into the arena. + fn decode_item( + &mut self, + header: alloy_rlp::Header, + payload: &[u8], + r: Ref, + s: &mut Stream<'_>, + ) -> Result { + if !header.list { + return match payload.len() { + 0 => Ok(self.push(Node::Null, Some(r))), + _ => Err(alloy_rlp::Error::UnexpectedString.into()), + }; + } + // ONE pass. A node is either 2 items (leaf or extension) or 17 (a + // branch), and the first two tell them apart: a second item that does + // not end the payload means a branch. Counting the items first, as + // this did, parsed every node twice. + let mut rest = payload; + let (h0, p0, w0) = take_item(&mut rest)?; + let (h1, p1, w1) = take_item(&mut rest)?; + if rest.is_empty() { + // Item 0 is the compact-encoded path; its high nibble says whether + // item 1 is a value (leaf) or a child (extension). + if h0.list || p0.is_empty() { + return Err(alloy_rlp::Error::UnexpectedList.into()); + } + return if p0[0] & 0x20 == 0 { + let child = self.child(h1, p1, w1, s)?; + if child == NONE { + return Err(Error::WitnessFormat("extension without child")); + } + let prefix = self.stream.slice_ref(p0); + Ok(self.push(Node::Extension(prefix, child), Some(r))) + } else { + if h1.list { + return Err(alloy_rlp::Error::UnexpectedList.into()); + } + let (prefix, value) = (self.stream.slice_ref(p0), self.stream.slice_ref(p1)); + Ok(self.push(Node::Leaf(prefix, value), Some(r))) + }; + } + // A branch: 16 children then an empty value. The children are walked + // in order because `child` may consume the next stream entry. The + // two common children, absent (`0x80`) and a digest (`0xa0 ..`) whose + // stream entry is itself a digest, are handled here without the + // generic item split and the two calls behind it: they are ~95% of + // the ~160 K branch children of a reth block. + let mut children = [NONE; 16]; + children[0] = self.common_child(h0, p0, w0, s)?; + children[1] = self.common_child(h1, p1, w1, s)?; + for slot in children[2..].iter_mut() { + match rest.first() { + Some(&alloy_rlp::EMPTY_STRING_CODE) => { + rest = &rest[1..]; + } + Some(&DIGEST_STRING_CODE) if rest.len() >= 33 && s.peek() == Some(TAG_DIGEST) => { + s.pos += 1; + let off = rest.as_ptr() as usize + 1 - self.stream.as_ptr() as usize; + *slot = DIGEST_BIT | off as NodeId; + rest = &rest[33..]; + } + _ => { + let (h, item, whole) = take_item(&mut rest)?; + *slot = self.child(h, item, whole, s)?; + } + } + } + let (h, value, _) = take_item(&mut rest)?; + if h.list || !value.is_empty() { + return Err(Error::WitnessFormat("branch node with value")); + } + if !rest.is_empty() { + return Err(alloy_rlp::Error::UnexpectedLength.into()); + } + Ok(self.push(Node::Branch(children), Some(r))) + } + + // -- reads --------------------------------------------------------------- + + /// The value stored under `key`, if any. + pub fn get(&self, key: &[u8]) -> Result, Error> { + let (nibs, n) = nibbles(key); + self.get_internal(self.root, &nibs[..n]) + } + + /// The RLP-decoded value stored under `key`, if any. + pub fn get_rlp(&self, key: &[u8]) -> Result, Error> { + match self.get(key)? { + Some(mut bytes) => Ok(Some(T::decode(&mut bytes)?)), + None => Ok(None), + } + } + + fn get_internal(&self, id: NodeId, key_nibs: &[u8]) -> Result, Error> { + if Self::is_digest(id) { + return Err(Error::NodeNotResolved(self.digest_at(id))); + } + match &self.nodes[id as usize] { + Node::Null => Ok(None), + Node::Branch(children) => match key_nibs.split_first() { + Some((i, tail)) => match children[*i as usize] { + NONE => Ok(None), + child => self.get_internal(child, tail), + }, + None => Ok(None), + }, + Node::Leaf(prefix, value) => { + if strip_prefix_nibs(key_nibs, prefix) == Some(&[][..]) { + Ok(Some(&value[..])) + } else { + Ok(None) + } + } + Node::Extension(prefix, child) => match strip_prefix_nibs(key_nibs, prefix) { + Some(tail) => self.get_internal(*child, tail), + None => Ok(None), + }, + Node::Digest(digest) => Err(Error::NodeNotResolved(*digest)), + } + } + + /// Whether the trie holds no key. + pub fn is_empty(&self) -> bool { + matches!(self.nodes[self.root as usize], Node::Null) + } + + /// Remove every key. + pub fn clear(&mut self) { + self.nodes[self.root as usize] = Node::Null; + self.refs[self.root as usize] = None; + } + + // -- hashing ------------------------------------------------------------- + + /// The root hash. + pub fn hash(&mut self) -> B256 { + match self.nodes[self.root as usize] { + Node::Null => EMPTY_ROOT, + _ => match self.reference(self.root) { + Ref::Digest(d) => d, + Ref::Bytes(b) => keccak(b).into(), + }, + } + } + + fn reference(&mut self, id: NodeId) -> Ref { + if Self::is_digest(id) { + return Ref::Digest(self.digest_at(id)); + } + self.ensure_reference(id); + self.refs[id as usize].clone().expect("the reference is cached") + } + + /// Caches the reference of the node `id` (not a digest slot). + fn ensure_reference(&mut self, id: NodeId) { + if self.refs[id as usize].is_some() { + return; + } + let r = match &self.nodes[id as usize] { + Node::Null => Ref::Bytes(vec![alloy_rlp::EMPTY_STRING_CODE]), + Node::Digest(d) => Ref::Digest(*d), + _ => { + let encoded = self.encode(id); + if encoded.len() < 32 { + Ref::Bytes(encoded) + } else { + Ref::Digest(keccak(&encoded).into()) + } + } + }; + self.refs[id as usize] = Some(r); + } + + fn reference_length(&mut self, id: NodeId) -> usize { + if Self::is_digest(id) { + return 33; + } + self.ensure_reference(id); + self.refs[id as usize].as_ref().expect("the reference is cached").length() + } + + /// Writes the RLP reference of `id` to `out`: a digest slot's 32 bytes + /// from the witness stream, else the cached (or now computed) reference. + fn write_reference(&mut self, id: NodeId, out: &mut Vec) { + if Self::is_digest(id) { + let off = (id & !DIGEST_BIT) as usize; + let digest: &[u8; 32] = self.stream[off..off + 32].try_into().expect("32 bytes"); + push_digest(out, digest); + return; + } + self.ensure_reference(id); + self.refs[id as usize].as_ref().expect("the reference is cached").encode(out); + } + + fn encode(&mut self, id: NodeId) -> Vec { + match &self.nodes[id as usize] { + Node::Null => vec![alloy_rlp::EMPTY_STRING_CODE], + Node::Digest(d) => d.to_rlp(), + Node::Leaf(prefix, value) => { + let payload = prefix[..].length() + value[..].length(); + let mut out = Vec::with_capacity(payload + 3); + alloy_rlp::Header { list: true, payload_length: payload }.encode(&mut out); + prefix[..].encode(&mut out); + value[..].encode(&mut out); + out + } + Node::Extension(prefix, child) => { + let child = *child; + let prefix_len = prefix[..].length(); + let payload = prefix_len + self.reference_length(child); + let mut out = Vec::with_capacity(payload + 3); + alloy_rlp::Header { list: true, payload_length: payload }.encode(&mut out); + let Node::Extension(prefix, _) = &self.nodes[id as usize] else { + unreachable!("the node is an extension") + }; + prefix[..].encode(&mut out); + self.write_reference(child, &mut out); + out + } + Node::Branch(children) => { + let children = *children; + // Two passes over the children, sizing then writing, so a + // digest slot never has to become a `Ref`: its 32 bytes are + // copied straight from the witness stream into the output. + let mut payload = 1; // the empty value + for child in children.iter() { + payload += if *child == NONE { 1 } else { self.reference_length(*child) }; + } + let mut out = Vec::with_capacity(payload + 3); + alloy_rlp::Header { list: true, payload_length: payload }.encode(&mut out); + for child in children.iter() { + if *child == NONE { + out.push(alloy_rlp::EMPTY_STRING_CODE); + } else { + self.write_reference(*child, &mut out); + } + } + out.push(alloy_rlp::EMPTY_STRING_CODE); + out + } + } + } + + // -- writes -------------------------------------------------------------- + + /// Insert or update `key`; `true` if the trie changed. + pub fn insert(&mut self, key: &[u8], value: Vec) -> Result { + assert!(!value.is_empty(), "value must not be empty"); + let (nibs, n) = nibbles(key); + self.insert_internal(self.root, &nibs[..n], value.into()) + } + + /// Insert or update `key` with the RLP encoding of `value`. + pub fn insert_rlp(&mut self, key: &[u8], value: impl Encodable) -> Result { + let (nibs, n) = nibbles(key); + self.insert_internal(self.root, &nibs[..n], value.to_rlp().into()) + } + + #[inline] + fn leaf(&mut self, nibs: &[u8], value: Bytes) -> NodeId { + self.push(Node::Leaf(to_encoded_path(nibs, true).into(), value), None) + } + + fn insert_internal( + &mut self, + id: NodeId, + key_nibs: &[u8], + value: Bytes, + ) -> Result { + if Self::is_digest(id) { + return Err(Error::NodeNotResolved(self.digest_at(id))); + } + let changed = match &mut self.nodes[id as usize] { + Node::Null => { + self.nodes[id as usize] = Node::Leaf(to_encoded_path(key_nibs, true).into(), value); + true + } + Node::Branch(children) => { + let Some((i, tail)) = key_nibs.split_first() else { + return Err(Error::ValueInBranch); + }; + let child = children[*i as usize]; + if child != NONE { + if !self.insert_internal(child, tail, value)? { + return Ok(false); + } + } else { + let (i, tail) = (*i as usize, tail.to_vec()); + let leaf = self.leaf(&tail, value); + if let Node::Branch(children) = &mut self.nodes[id as usize] { + children[i] = leaf; + } + } + true + } + Node::Leaf(prefix, old_value) => { + let self_nibs = prefix_nibs(prefix); + let common_len = lcp(&self_nibs, key_nibs); + if common_len == self_nibs.len() && common_len == key_nibs.len() { + if *old_value == value { + return Ok(false); + } + *old_value = value; + } else if common_len == self_nibs.len() || common_len == key_nibs.len() { + return Err(Error::ValueInBranch); + } else { + let old_value = mem::take(old_value); + let split = common_len + 1; + let mut children = [NONE; 16]; + children[self_nibs[common_len] as usize] = + self.leaf(&self_nibs[split..], old_value); + children[key_nibs[common_len] as usize] = self.leaf(&key_nibs[split..], value); + self.replace_with_branch(id, &self_nibs[..common_len], children); + } + true + } + Node::Extension(prefix, existing_child) => { + let existing_child = *existing_child; + let self_nibs = prefix_nibs(prefix); + let common_len = lcp(&self_nibs, key_nibs); + if common_len == self_nibs.len() { + if !self.insert_internal(existing_child, &key_nibs[common_len..], value)? { + return Ok(false); + } + } else if common_len == key_nibs.len() { + return Err(Error::ValueInBranch); + } else { + let split = common_len + 1; + let mut children = [NONE; 16]; + children[self_nibs[common_len] as usize] = if split < self_nibs.len() { + self.push( + Node::Extension( + to_encoded_path(&self_nibs[split..], false).into(), + existing_child, + ), + None, + ) + } else { + existing_child + }; + children[key_nibs[common_len] as usize] = self.leaf(&key_nibs[split..], value); + self.replace_with_branch(id, &self_nibs[..common_len], children); + } + true + } + Node::Digest(digest) => return Err(Error::NodeNotResolved(*digest)), + }; + if changed { + self.refs[id as usize] = None; + } + Ok(changed) + } + + /// Node `id` becomes `branch`, under an extension for `prefix_nibs` when + /// that is non-empty. + fn replace_with_branch(&mut self, id: NodeId, prefix_nibs: &[u8], children: [NodeId; 16]) { + if prefix_nibs.is_empty() { + self.nodes[id as usize] = Node::Branch(children); + } else { + let branch = self.push(Node::Branch(children), None); + self.nodes[id as usize] = + Node::Extension(to_encoded_path(prefix_nibs, false).into(), branch); + } + } + + /// Delete `key`; `true` if it was present. + pub fn delete(&mut self, key: &[u8]) -> Result { + let (nibs, n) = nibbles(key); + self.delete_internal(self.root, &nibs[..n]) + } + + fn delete_internal(&mut self, id: NodeId, key_nibs: &[u8]) -> Result { + if Self::is_digest(id) { + return Err(Error::NodeNotResolved(self.digest_at(id))); + } + match &self.nodes[id as usize] { + Node::Null => return Ok(false), + Node::Branch(children) => { + let Some((i, tail)) = key_nibs.split_first() else { + return Err(Error::ValueInBranch); + }; + let child = children[*i as usize]; + if child == NONE || !self.delete_internal(child, tail)? { + return Ok(false); + } + let i = *i as usize; + if matches!(self.nodes[child as usize], Node::Null) { + if let Node::Branch(children) = &mut self.nodes[id as usize] { + children[i] = NONE; + } + } + let Node::Branch(children) = &self.nodes[id as usize] else { unreachable!() }; + let mut remaining = children.iter().enumerate().filter(|(_, c)| **c != NONE); + // there is always at least one child left + let (index, orphan) = remaining.next().map(|(i, c)| (i, *c)).unwrap(); + if remaining.next().is_none() { + // one child left: the branch collapses into it + let new = if Self::is_digest(orphan) { + // a digest slot has no node: the branch becomes an + // extension to the digest + Node::Extension(to_encoded_path(&[index as u8], false).into(), orphan) + } else { + match mem::replace(&mut self.nodes[orphan as usize], Node::Null) { + Node::Leaf(prefix, value) => { + let mut nibs = vec![index as u8]; + nibs.extend(prefix_nibs(&prefix)); + Node::Leaf(to_encoded_path(&nibs, true).into(), value) + } + Node::Extension(prefix, child) => { + let mut nibs = vec![index as u8]; + nibs.extend(prefix_nibs(&prefix)); + Node::Extension(to_encoded_path(&nibs, false).into(), child) + } + node @ (Node::Branch(_) | Node::Digest(_)) => { + // the orphan keeps its slot; the branch becomes an extension to it + self.nodes[orphan as usize] = node; + Node::Extension( + to_encoded_path(&[index as u8], false).into(), + orphan, + ) + } + Node::Null => unreachable!(), + } + }; + self.nodes[id as usize] = new; + } + } + Node::Leaf(prefix, _) => { + if strip_prefix_nibs(key_nibs, prefix) != Some(&[][..]) { + return Ok(false); + } + self.nodes[id as usize] = Node::Null; + } + Node::Extension(prefix, child) => { + let child = *child; + let mut self_nibs = prefix_nibs(prefix); + let Some(tail) = strip_prefix_nibs(key_nibs, prefix) else { return Ok(false) }; + if !self.delete_internal(child, tail)? { + return Ok(false); + } + // an extension points to a branch or digest; re-establish that + let new = match mem::replace(&mut self.nodes[child as usize], Node::Null) { + Node::Null => Some(Node::Null), + Node::Leaf(prefix, value) => { + self_nibs.extend(prefix_nibs(&prefix)); + Some(Node::Leaf(to_encoded_path(&self_nibs, true).into(), value)) + } + Node::Extension(prefix, grandchild) => { + self_nibs.extend(prefix_nibs(&prefix)); + Some(Node::Extension(to_encoded_path(&self_nibs, false).into(), grandchild)) + } + node @ (Node::Branch(_) | Node::Digest(_)) => { + self.nodes[child as usize] = node; + None + } + }; + if let Some(new) = new { + self.nodes[id as usize] = new; + } + } + Node::Digest(digest) => return Err(Error::NodeNotResolved(*digest)), + } + self.refs[id as usize] = None; + Ok(true) + } +} + +/// 32-byte equality as eight word compares: the generic `memcmp` takes the +/// byte loop for these stack arrays. +#[inline] +fn eq32(a: &[u8; 32], b: &[u8; 32]) -> bool { + let mut acc = 0u32; + for i in (0..32).step_by(4) { + acc |= u32::from_ne_bytes([a[i], a[i + 1], a[i + 2], a[i + 3]]) ^ + u32::from_ne_bytes([b[i], b[i + 1], b[i + 2], b[i + 3]]); + } + acc == 0 +} + +/// The nibbles of `key` in a stack buffer, and how many: keys are 32-byte +/// hashes, so the buffer needs no allocation. +/// +/// # Panics +/// Panics if `key` is longer than 64 bytes. +#[inline] +fn nibbles(key: &[u8]) -> ([u8; 128], usize) { + assert!(key.len() <= 64, "key too long"); + let mut out = [0u8; 128]; + for (i, b) in key.iter().enumerate() { + out[2 * i] = b >> 4; + out[2 * i + 1] = b & 0xf; + } + (out, 2 * key.len()) +} + +/// `key_nibs` with a compact-encoded `prefix` stripped off the front, without +/// materialising the prefix's nibbles. +fn strip_prefix_nibs<'a>(key_nibs: &'a [u8], prefix: &[u8]) -> Option<&'a [u8]> { + let (first, tail) = prefix.split_first()?; + let mut rest = key_nibs; + if first & 0x10 != 0 { + let (k, r) = rest.split_first()?; + if *k != first & 0xf { + return None; + } + rest = r; + } + for byte in tail { + let (k, r) = rest.split_first_chunk::<2>()?; + if k[0] != byte >> 4 || k[1] != byte & 0xf { + return None; + } + rest = r; + } + Some(rest) +} + +// --------------------------------------------------------------------------- +// The guest's state: arena tries + the update logic of `EthereumState` +// --------------------------------------------------------------------------- + +/// State and storage tries materialised from a [`WitnessState`]. +#[derive(Debug, Clone, Default)] +pub struct ArenaState { + pub state_trie: ArenaTrie, + pub storage_tries: HashMap, +} + +impl ArenaState { + /// Build every trie, checking each node against the digest that references + /// it and each trie against its root; the state root is checked against + /// `witness.state_root`, the storage roots against the account leaves. + pub fn from_witness(witness: &WitnessState) -> Result { + let state_trie = ArenaTrie::from_stream(witness.state_root, witness.state_nodes.clone())?; + let mut storage_tries = + HashMap::with_capacity_and_hasher(witness.storage.len(), Default::default()); + for StorageWitness { hashed_address, root, nodes } in &witness.storage { + let expected = state_trie + .get_rlp::(hashed_address.as_slice())? + .map_or(EMPTY_ROOT_HASH, |a| a.storage_root); + if *root != expected { + return Err(Error::WitnessNodeMismatch(expected)); + } + storage_tries.insert(*hashed_address, ArenaTrie::from_stream(*root, nodes.clone())?); + } + Ok(Self { state_trie, storage_tries }) + } + + /// The account under `hashed_address`, if any. + pub fn account(&self, hashed_address: &[u8]) -> Result, Error> { + self.state_trie.get_rlp::(hashed_address) + } + + /// The storage slot `hashed_slot` of `hashed_address`, if set. + /// + /// A witness may omit the storage trie of an absent account or of one + /// whose authenticated storage root is empty; their slots are zero. Any + /// other missing trie is an unresolved storage root, never a zero. + pub fn storage( + &self, + hashed_address: &B256, + hashed_slot: &[u8], + ) -> Result, Error> { + match self.storage_tries.get(hashed_address) { + Some(trie) => trie.get_rlp::(hashed_slot), + None => { + let root = self + .account(hashed_address.as_slice())? + .map_or(EMPTY_ROOT_HASH, |account| account.storage_root); + if root == EMPTY_ROOT_HASH { + Ok(None) + } else { + Err(Error::NodeNotResolved(root)) + } + } + } + } + + /// Apply the post-state diff (same semantics as `EthereumState::update`). + pub fn update(&mut self, post_state: &HashedPostState) { + let no_storage = HashedStorage::new(false); + for (hashed_address, account) in post_state.accounts.iter() { + match account { + Some(account) => { + let state_storage = + post_state.storages.get(hashed_address).unwrap_or(&no_storage); + let storage_root = + self.storage_root_after_update(*hashed_address, state_storage); + + if account.is_empty() && storage_root == EMPTY_ROOT_HASH { + self.state_trie.delete(hashed_address.as_slice()).unwrap(); + self.storage_tries.remove(hashed_address); + continue; + } + + let state_account = TrieAccount { + nonce: account.nonce, + balance: account.balance, + storage_root, + code_hash: account.get_bytecode_hash(), + }; + self.state_trie.insert_rlp(hashed_address.as_slice(), state_account).unwrap(); + } + None => { + self.state_trie.delete(hashed_address.as_slice()).unwrap(); + self.storage_tries.remove(hashed_address); + } + } + } + } + + fn storage_root_after_update( + &mut self, + hashed_address: B256, + state_storage: &HashedStorage, + ) -> B256 { + if state_storage.is_empty() { + if let Some(storage_trie) = self.storage_tries.get_mut(&hashed_address) { + return storage_trie.hash(); + } + return self + .state_trie + .get_rlp::(hashed_address.as_slice()) + .unwrap() + .map(|account| account.storage_root) + .unwrap_or(EMPTY_ROOT_HASH); + } + + let storage_trie = self.storage_tries.entry(hashed_address).or_default(); + if state_storage.wiped { + storage_trie.clear(); + } + for (key, value) in state_storage.storage.iter() { + let key = key.as_slice(); + if value.is_zero() { + storage_trie.delete(key).unwrap(); + } else { + storage_trie.insert_rlp(key, *value).unwrap(); + } + } + storage_trie.hash() + } + + /// The state root. + pub fn state_root(&mut self) -> B256 { + self.state_trie.hash() + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::EthereumState; + use alloy_primitives::{keccak256, U256}; + use reth_trie::Nibbles; + + fn state_with(account: Option<(B256, TrieAccount)>) -> ArenaState { + let mut state = ArenaState::default(); + if let Some((hashed_address, account)) = account { + state.state_trie.insert_rlp(hashed_address.as_slice(), account).unwrap(); + } + state + } + + #[test] + fn omitted_storage_for_absent_account_is_zero() { + let state = state_with(None); + let slot = keccak256(U256::from(7).to_be_bytes::<32>()); + assert_eq!(state.storage(&B256::repeat_byte(1), slot.as_slice()).unwrap(), None); + } + + #[test] + fn omitted_storage_with_authenticated_empty_root_is_zero() { + let hashed_address = B256::repeat_byte(2); + let state = state_with(Some((hashed_address, TrieAccount::default()))); + let slot = keccak256(U256::from(7).to_be_bytes::<32>()); + assert_eq!(state.storage(&hashed_address, slot.as_slice()).unwrap(), None); + } + + #[test] + fn omitted_non_empty_storage_is_rejected() { + let hashed_address = B256::repeat_byte(3); + let account = TrieAccount { storage_root: B256::repeat_byte(4), ..Default::default() }; + let state = state_with(Some((hashed_address, account))); + let slot = keccak256(U256::from(7).to_be_bytes::<32>()); + assert!(state.storage(&hashed_address, slot.as_slice()).is_err()); + } + + fn key(i: u64) -> B256 { + keccak256(i.to_be_bytes()) + } + + fn rng(state: &mut u64) -> u64 { + *state ^= *state << 13; + *state ^= *state >> 7; + *state ^= *state << 17; + *state + } + + fn oracle_trie(n: u64, seed: u64) -> MptNode { + let mut trie = MptNode::default(); + let mut s = seed | 1; + for i in 0..n { + trie.insert_rlp(key(i).as_slice(), U256::from(rng(&mut s))).unwrap(); + } + trie + } + + fn arena_of(trie: &MptNode) -> ArenaTrie { + ArenaTrie::from_stream(trie.hash(), witness_stream(trie)).unwrap() + } + + #[test] + fn stream_roundtrip_matches_oracle() { + for &n in &[0u64, 1, 2, 3, 17, 300, 2000] { + let oracle = oracle_trie(n, 7 + n); + let mut arena = arena_of(&oracle); + assert_eq!(arena.hash(), oracle.hash(), "n={n}"); + for i in 0..n + 50 { + let k = key(i); + assert_eq!( + arena.get(k.as_slice()).unwrap(), + oracle.get(k.as_slice()).unwrap(), + "n={n} key {i}" + ); + } + } + } + + #[test] + fn mutations_match_oracle() { + let mut oracle = oracle_trie(400, 99); + let mut arena = arena_of(&oracle); + let mut s = 12345u64; + for step in 0..3000u64 { + let r = rng(&mut s); + let i = r % 700; // hits existing (0..400) and fresh keys + let k = key(i); + match r % 5 { + 0 | 1 => { + let v = U256::from(rng(&mut s)); + let a = arena.insert_rlp(k.as_slice(), v).unwrap(); + let b = oracle.insert_rlp(k.as_slice(), v).unwrap(); + assert_eq!(a, b, "insert step {step}"); + } + 2 | 3 => { + let a = arena.delete(k.as_slice()).unwrap(); + let b = oracle.delete(k.as_slice()).unwrap(); + assert_eq!(a, b, "delete step {step}"); + } + _ => { + assert_eq!(arena.get(k.as_slice()).unwrap(), oracle.get(k.as_slice()).unwrap()); + } + } + if step % 97 == 0 { + assert_eq!(arena.hash(), oracle.hash(), "root after step {step}"); + } + } + assert_eq!(arena.hash(), oracle.hash()); + assert_eq!(arena.is_empty(), oracle.is_empty()); + } + + /// Replace the child at `nibble` of the root branch (after descending any + /// root extension) with an unresolved digest, like a partial witness. + fn plant_digest(trie: &mut MptNode, nibble: usize) -> bool { + let mut node = trie; + loop { + match node.data_mut() { + MptNodeData::Extension(_, child) => node = child, + MptNodeData::Branch(children) => { + return match &mut children[nibble] { + Some(child) => { + let h = child.hash(); + *child.data_mut() = MptNodeData::Digest(h); + true + } + None => false, + } + } + _ => return false, + } + } + } + + #[test] + fn unresolved_subtrees_match_oracle() { + let mut oracle = oracle_trie(600, 5); + let full_root = oracle.hash(); + assert!(plant_digest(&mut oracle, 3)); + assert!(plant_digest(&mut oracle, 11)); + assert_eq!(oracle.hash(), full_root, "digest planting keeps the root"); + let mut arena = arena_of(&oracle); + assert_eq!(arena.hash(), full_root); + let mut resolved = 0; + let mut unresolved = 0; + for i in 0..600u64 { + let k = key(i); + match (arena.get(k.as_slice()), oracle.get(k.as_slice())) { + (Ok(a), Ok(b)) => { + assert_eq!(a, b); + resolved += 1; + } + (Err(Error::NodeNotResolved(a)), Err(Error::NodeNotResolved(b))) => { + assert_eq!(a, b); + unresolved += 1; + } + (a, b) => panic!("key {i}: {a:?} vs {b:?}"), + } + } + assert!(resolved > 0 && unresolved > 0, "{resolved} {unresolved}"); + // mutations on resolved paths still agree + for i in 0..600u64 { + let k = key(i); + if arena.get(k.as_slice()).is_ok() { + let v = U256::from(i * 31 + 7); + arena.insert_rlp(k.as_slice(), v).unwrap(); + oracle.insert_rlp(k.as_slice(), v).unwrap(); + } + } + assert_eq!(arena.hash(), oracle.hash()); + } + + #[test] + fn tampered_node_is_rejected() { + let oracle = oracle_trie(50, 3); + let mut stream = witness_stream(&oracle).to_vec(); + // flip a byte inside the first node's payload + let last = stream.len() - 1; + stream[last] ^= 1; + assert!(matches!( + ArenaTrie::from_stream(oracle.hash(), Bytes::from(stream.clone())), + Err(Error::WitnessNodeMismatch(_)) + )); + assert!(ArenaTrie::from_stream(B256::ZERO, witness_stream(&oracle)).is_err()); + } + + #[test] + fn state_update_matches_oracle() { + use reth_primitives_traits::Account; + let mut s = 777u64; + let mut eager = EthereumState::default(); + for i in 0..120u64 { + let addr = key(i); + let mut storage = MptNode::default(); + for j in 0..(i % 9) { + storage + .insert_rlp(key(1000 + i * 10 + j).as_slice(), U256::from(rng(&mut s))) + .unwrap(); + } + let account = TrieAccount { + nonce: i, + balance: U256::from(rng(&mut s)), + storage_root: storage.hash(), + code_hash: key(5000 + i), + }; + eager.state_trie.insert_rlp(addr.as_slice(), account).unwrap(); + eager.storage_tries.insert(addr, storage); + } + let witness = eager.to_witness_state(); + let mut arena = ArenaState::from_witness(&witness).unwrap(); + assert_eq!(arena.state_root(), eager.state_root()); + + let mut post = HashedPostState::default(); + for i in 0..120u64 { + let addr = key(i); + match i % 4 { + 0 => { + post.accounts.insert(addr, None); + } + 1 => { + post.accounts.insert( + addr, + Some(Account { + nonce: i + 1, + balance: U256::from(rng(&mut s)), + bytecode_hash: Some(key(5000 + i)), + }), + ); + let mut hs = HashedStorage::new(false); + for j in 0..6u64 { + let v = if j % 2 == 0 { U256::ZERO } else { U256::from(rng(&mut s)) }; + hs.storage.insert(key(1000 + i * 10 + j), v); + } + post.storages.insert(addr, hs); + } + 2 => { + post.accounts.insert( + addr, + Some(Account { nonce: 0, balance: U256::ZERO, bytecode_hash: None }), + ); + post.storages.insert(addr, HashedStorage::new(true)); + } + _ => { + post.accounts.insert( + key(9000 + i), + Some(Account { nonce: 1, balance: U256::from(5), bytecode_hash: None }), + ); + } + } + } + eager.update(&post); + arena.update(&post); + assert_eq!(arena.state_root(), eager.state_root()); + let _ = Nibbles::default(); + } +} diff --git a/crates/mpt/src/lib.rs b/crates/mpt/src/lib.rs index d9f9d1d..45a77e4 100644 --- a/crates/mpt/src/lib.rs +++ b/crates/mpt/src/lib.rs @@ -2,22 +2,25 @@ use alloy_primitives::{keccak256, map::HashMap, Address, B256}; use alloy_rpc_types::EIP1186AccountProofResponse; -use reth_trie::{AccountProof, HashedPostState, HashedStorage, TrieAccount}; +use reth_trie::{AccountProof, HashedPostState, HashedStorage, TrieAccount, EMPTY_ROOT_HASH}; use serde::{Deserialize, Serialize}; #[cfg(feature = "execution-witness")] mod execution_witness; +/// Arena-backed trie built from a preorder RLP witness stream (the guest's form). +mod arena; /// Module containing MPT code adapted from `zeth`. mod mpt; +pub use arena::{input_bytes, witness_stream, ArenaState, ArenaTrie, StorageWitness, WitnessState}; pub use mpt::Error; use mpt::{ - mpt_from_proof, parse_proof, proofs_to_tries, resolve_nodes, transition_proofs_to_tries, - MptNode, + extend_trie_from_proof, mpt_from_proof, node_from_digest, parse_proof, proofs_to_tries, + resolve_nodes, transition_proofs_to_tries, MptNode, }; /// Ethereum state trie and account storage tries. -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] pub struct EthereumState { pub state_trie: MptNode, pub storage_tries: HashMap, @@ -72,6 +75,25 @@ impl EthereumState { Ok(state) } + /// Resolves missing account trie nodes from an EIP-1186 account proof. + pub fn extend_from_account_proof( + &mut self, + proof: &EIP1186AccountProofResponse, + ) -> Result<(), FromProofError> { + self.state_trie = extend_trie_from_proof(&self.state_trie, &proof.account_proof)?; + let hashed_address = keccak256(proof.address); + for storage_proof in &proof.storage_proof { + let storage_trie = self + .storage_tries + .entry(hashed_address) + .or_insert_with(|| node_from_digest(proof.storage_hash)); + if !storage_proof.proof.is_empty() { + *storage_trie = extend_trie_from_proof(storage_trie, &storage_proof.proof)?; + } + } + Ok(()) + } + #[cfg(feature = "execution-witness")] pub fn from_execution_witness( witness: &alloy_rpc_types_debug::ExecutionWitness, @@ -93,24 +115,14 @@ impl EthereumState { .get(hashed_address) .cloned() .unwrap_or_else(|| HashedStorage::new(false)); - let storage_root = { - let storage_trie = self.storage_tries.entry(*hashed_address).or_default(); - - if state_storage.wiped { - storage_trie.clear(); - } - - for (key, value) in state_storage.storage.iter() { - let key = key.as_slice(); - if value.is_zero() { - storage_trie.delete(key).unwrap(); - } else { - storage_trie.insert_rlp(key, *value).unwrap(); - } - } - - storage_trie.hash() - }; + let storage_root = + self.storage_root_after_update(*hashed_address, state_storage); + + if account.is_empty() && storage_root == EMPTY_ROOT_HASH { + self.state_trie.delete(hashed_address.as_slice()).unwrap(); + self.storage_tries.remove(hashed_address); + continue; + } let state_account = TrieAccount { nonce: account.nonce, @@ -122,15 +134,73 @@ impl EthereumState { } None => { self.state_trie.delete(hashed_address.as_slice()).unwrap(); + self.storage_tries.remove(hashed_address); } } } } + fn storage_root_after_update( + &mut self, + hashed_address: B256, + state_storage: &HashedStorage, + ) -> B256 { + if state_storage.is_empty() { + if let Some(storage_trie) = self.storage_tries.get(&hashed_address) { + return storage_trie.hash() + } + + return self + .state_trie + .get_rlp::(hashed_address.as_slice()) + .unwrap() + .map(|account| account.storage_root) + .unwrap_or(EMPTY_ROOT_HASH) + } + + let storage_trie = self.storage_tries.entry(hashed_address).or_default(); + + if state_storage.wiped { + storage_trie.clear(); + } + + for (key, value) in state_storage.storage.iter() { + let key = key.as_slice(); + if value.is_zero() { + storage_trie.delete(key).unwrap(); + } else { + storage_trie.insert_rlp(key, *value).unwrap(); + } + } + + storage_trie.hash() + } + /// Computes the state root. pub fn state_root(&self) -> B256 { self.state_trie.hash() } + + /// The witness form the guest consumes: root hashes plus preorder streams + /// of raw RLP nodes for the state trie and every storage trie (sorted by + /// hashed address so the bytes are reproducible). + pub fn to_witness_state(&self) -> WitnessState { + let mut storage: Vec = self + .storage_tries + .iter() + .map(|(addr, trie)| StorageWitness { + hashed_address: *addr, + root: trie.hash(), + nodes: witness_stream(trie), + }) + .collect(); + storage.sort_by(|a, b| a.hashed_address.cmp(&b.hashed_address)); + WitnessState { + state_root: self.state_trie.hash(), + state_nodes: witness_stream(&self.state_trie), + storage, + } + } } #[derive(Debug, thiserror::Error)] @@ -149,3 +219,58 @@ pub enum FromProofError { #[error("Error decoding proofs from bytes, {}", .0)] DecodingError(#[from] Error), } + +#[cfg(test)] +mod tests { + use alloy_primitives::{b256, U256}; + use reth_primitives_traits::Account; + + use super::*; + + #[test] + fn update_removes_empty_account_with_empty_storage_root() { + let hashed_address = B256::repeat_byte(0x11); + let post_state = + HashedPostState::default().with_accounts([(hashed_address, Some(Default::default()))]); + let mut state = + EthereumState { state_trie: MptNode::default(), storage_tries: HashMap::default() }; + + state.update(&post_state); + + assert!(state.state_trie.get(hashed_address.as_slice()).unwrap().is_none()); + assert_eq!(state.state_root(), EMPTY_ROOT_HASH); + assert!(!state.storage_tries.contains_key(&hashed_address)); + } + + #[test] + fn update_preserves_storage_root_when_storage_trie_is_not_revealed() { + let hashed_address = B256::repeat_byte(0x22); + let storage_root = + b256!("3333333333333333333333333333333333333333333333333333333333333333"); + let mut state = + EthereumState { state_trie: MptNode::default(), storage_tries: HashMap::default() }; + state + .state_trie + .insert_rlp( + hashed_address.as_slice(), + TrieAccount { + nonce: 0, + balance: U256::from(1), + storage_root, + code_hash: TrieAccount::default().code_hash, + }, + ) + .unwrap(); + let post_state = HashedPostState::default().with_accounts([( + hashed_address, + Some(Account { nonce: 0, balance: U256::from(2), bytecode_hash: None }), + )]); + + state.update(&post_state); + + let account = + state.state_trie.get_rlp::(hashed_address.as_slice()).unwrap().unwrap(); + assert_eq!(account.balance, U256::from(2)); + assert_eq!(account.storage_root, storage_root); + } +} diff --git a/crates/mpt/src/mpt.rs b/crates/mpt/src/mpt.rs index 39ed00a..5b3a577 100644 --- a/crates/mpt/src/mpt.rs +++ b/crates/mpt/src/mpt.rs @@ -141,6 +141,12 @@ pub enum Error { /// value provides details about the unresolved node. #[error("reached an unresolved node: {0:#}")] NodeNotResolved(B256), + /// A witness node's keccak does not match the digest that references it. + #[error("witness node does not match digest {0}")] + WitnessNodeMismatch(B256), + /// The witness node stream is malformed. + #[error("malformed witness stream: {0}")] + WitnessFormat(&'static str), /// Occurs when a value is unexpectedly found in a branch node. #[error("branch node with value")] ValueInBranch, @@ -339,6 +345,12 @@ impl MptNode { rlp::decode(bytes.as_ref()).map_err(Error::from) } + /// Mutable access to the node data (tests plant unresolved digests with it). + pub(crate) fn data_mut(&mut self) -> &mut MptNodeData { + self.invalidate_ref_cache(); + &mut self.data + } + /// Retrieves the underlying data of the node. /// /// This method provides a reference to the node's data, allowing for inspection and @@ -770,7 +782,7 @@ impl MptNode { Ok(true) } - fn invalidate_ref_cache(&mut self) { + pub(crate) fn invalidate_ref_cache(&mut self) { self.cached_reference.lock().unwrap().take(); } @@ -879,7 +891,7 @@ pub fn to_encoded_path(mut nibs: &[u8], is_leaf: bool) -> Vec { } /// Returns the length of the common prefix. -fn lcp(a: &[u8], b: &[u8]) -> usize { +pub(crate) fn lcp(a: &[u8], b: &[u8]) -> usize { for (i, (a, b)) in iter::zip(a, b).enumerate() { if a != b { return i; @@ -888,7 +900,7 @@ fn lcp(a: &[u8], b: &[u8]) -> usize { cmp::min(a.len(), b.len()) } -fn prefix_nibs(prefix: &[u8]) -> Vec { +pub(crate) fn prefix_nibs(prefix: &[u8]) -> Vec { let (extension, tail) = prefix.split_first().unwrap(); // the first bit of the first nibble denotes the parity let is_odd = extension & (1 << 4) != 0; @@ -993,6 +1005,24 @@ pub fn resolve_nodes(root: &MptNode, node_store: &HashMap], +) -> Result { + let proof_nodes = parse_proof(proof)?; + let proof_trie = mpt_from_proof(&proof_nodes)?; + if proof_trie.hash() != root.hash() { + return Err(FromProofError::MismatchedStateRoot(proof_trie.hash(), root.hash())) + } + + let mut node_store = HashMap::with_hasher(Default::default()); + proof_nodes.into_iter().for_each(|node| { + node_store.insert(node.reference(), node); + }); + + Ok(resolve_nodes(root, &node_store)) +} + /// 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 @@ -1203,7 +1233,7 @@ fn add_orphaned_leafs( } /// Creates a new MPT node from a digest. -fn node_from_digest(digest: B256) -> MptNode { +pub(crate) fn node_from_digest(digest: B256) -> MptNode { match digest { EMPTY_ROOT | B256::ZERO => MptNode::default(), _ => MptNodeData::Digest(digest).into(), @@ -1344,6 +1374,32 @@ mod tests { trie.get(b"a0").unwrap_err(); } + #[test] + pub fn test_extend_trie_from_proof_resolves_digest_child() { + let mut full_trie = MptNode::default(); + full_trie.insert_rlp(b"aa", 0u8).unwrap(); + full_trie.insert_rlp(b"ab", 1u8).unwrap(); + full_trie.insert_rlp(b"ba", 2u8).unwrap(); + + let expected_hash = full_trie.hash(); + let mut partial_trie = full_trie.clone(); + let MptNodeData::Extension(_, node) = &mut partial_trie.data else { + panic!("extension expected") + }; + let missing_node = (**node).clone(); + **node = MptNodeData::Digest(missing_node.hash()).into(); + + partial_trie.get(b"aa").unwrap_err(); + + let proof = vec![full_trie.to_rlp(), missing_node.to_rlp()]; + let resolved_trie = extend_trie_from_proof(&partial_trie, &proof).unwrap(); + + assert_eq!(resolved_trie.hash(), expected_hash); + assert_eq!(resolved_trie.get_rlp::(b"aa").unwrap(), Some(0)); + assert_eq!(resolved_trie.get_rlp::(b"ab").unwrap(), Some(1)); + assert_eq!(resolved_trie.get_rlp::(b"ba").unwrap(), Some(2)); + } + #[test] pub fn test_branch_value() { let mut trie = MptNode::default(); diff --git a/crates/provider/Cargo.toml b/crates/provider/Cargo.toml index 9ca4a47..623a66f 100644 --- a/crates/provider/Cargo.toml +++ b/crates/provider/Cargo.toml @@ -9,9 +9,11 @@ workspace = true [dependencies] url.workspace = true +# Alloy shares this client; decode gzip responses for large execution witnesses. +reqwest = { workspace = true, features = ["gzip"] } # alloy alloy-provider.workspace = true alloy-json-rpc.workspace = true alloy-rpc-client.workspace = true -alloy-transport.workspace = true \ No newline at end of file +alloy-transport.workspace = true diff --git a/crates/storage/rpc-db/Cargo.toml b/crates/storage/rpc-db/Cargo.toml index 4f098c8..3d27261 100644 --- a/crates/storage/rpc-db/Cargo.toml +++ b/crates/storage/rpc-db/Cargo.toml @@ -21,20 +21,32 @@ revm-state.workspace = true # alloy alloy-consensus = { workspace = true, optional = true } +alloy-eips = { workspace = true, optional = true } alloy-primitives.workspace = true alloy-provider.workspace = true +alloy-rpc-types = { workspace = true, optional = true } +alloy-rpc-types-debug = { workspace = true, optional = true } alloy-transport.workspace = true alloy-rlp = { workspace = true, optional = true } alloy-trie = { workspace = true, optional = true, features = ["ethereum"] } +serde = { workspace = true, optional = true } + mpt.workspace = true primitives.workspace = true +[dev-dependencies] +serde_json.workspace = true + [features] default = ["execution-witness"] execution-witness = [ - "dep:alloy-consensus", + "dep:alloy-consensus", + "dep:alloy-eips", + "dep:alloy-rpc-types", + "dep:alloy-rpc-types-debug", "dep:alloy-rlp", "dep:alloy-trie", + "dep:serde", "alloy-provider/debug-api" ] diff --git a/crates/storage/rpc-db/src/execution_witness.rs b/crates/storage/rpc-db/src/execution_witness.rs index 60c24c1..db45dab 100644 --- a/crates/storage/rpc-db/src/execution_witness.rs +++ b/crates/storage/rpc-db/src/execution_witness.rs @@ -1,16 +1,24 @@ -use std::{collections::BTreeMap, marker::PhantomData}; +use std::{ + collections::BTreeMap, + marker::PhantomData, + sync::{Arc, RwLock}, +}; use alloy_consensus::Header; +use alloy_eips::BlockNumberOrTag; use alloy_primitives::{map::HashMap, Address, B256}; -use alloy_provider::{ext::DebugApi, Network, Provider}; -use alloy_rlp::Decodable; -use alloy_trie::TrieAccount; +use alloy_provider::{Network, Provider}; +use alloy_rlp::{Decodable, Encodable}; +use alloy_rpc_types::Header as RpcHeader; +use alloy_rpc_types_debug::ExecutionWitness; +use alloy_trie::{TrieAccount, EMPTY_ROOT_HASH}; use async_trait::async_trait; use mpt::EthereumState; -use reth_storage_errors::ProviderError; +use reth_storage_errors::{db::DatabaseError, ProviderError}; use revm_database::{BundleState, DatabaseRef}; -use revm_primitives::{keccak256, ruint::aliases::U256, StorageKey, StorageValue}; +use revm_primitives::{keccak256, ruint::aliases::U256, StorageKey, StorageValue, KECCAK_EMPTY}; use revm_state::{AccountInfo, Bytecode}; +use serde::Deserialize; use crate::{RpcDb, RpcDbError}; @@ -18,10 +26,12 @@ use crate::{RpcDb, RpcDbError}; pub struct ExecutionWitnessRpcDb { /// The provider which fetches data. pub provider: P, + /// The block to fetch missing pre-state proofs from. + pub state_block_number: u64, /// The cached state. - pub state: EthereumState, + pub state: Arc>, /// The cached bytecodes. - pub codes: HashMap, + pub codes: Arc>>, pub ancestor_headers: BTreeMap, @@ -31,10 +41,31 @@ pub struct ExecutionWitnessRpcDb { impl + Clone, N: Network> ExecutionWitnessRpcDb { /// Create a new [`ExecutionWitnessRpcDb`]. pub async fn new(provider: P, block_number: u64, state_root: B256) -> Result { + let execution_witness = Self::fetch_witness(&provider, block_number).await?; + Ok(Self::from_witness(provider, block_number, state_root, execution_witness)) + } + + /// Fetch the execution witness on its own. It depends only on the block + /// number, so the host can run it concurrently with the block fetches + /// and pass the result to [`Self::from_witness`] once the parent's state + /// root is known — the three RPC round trips were strictly serial before. + pub async fn fetch_witness( + provider: &P, + block_number: u64, + ) -> Result { tracing::info!("Fetching execution witness for block {}", block_number); - let execution_witness = provider.debug_execution_witness(block_number.into()).await?; + let execution_witness = fetch_execution_witness(provider, block_number).await?; tracing::info!("Fetched execution witness for block done {}", block_number); + Ok(execution_witness) + } + /// Build the database from an already-fetched witness. + pub fn from_witness( + provider: P, + block_number: u64, + state_root: B256, + execution_witness: ExecutionWitness, + ) -> Self { let state = EthereumState::from_execution_witness(&execution_witness, state_root); let codes = execution_witness @@ -50,15 +81,355 @@ impl + Clone, N: Network> ExecutionWitnessRpcDb { .map(|h| (h.number, h)) .collect(); - let db = Self { provider, state, codes, ancestor_headers, phantom: PhantomData }; + let db = Self { + provider, + state_block_number: block_number.saturating_sub(1), + state: Arc::new(RwLock::new(state)), + codes: Arc::new(RwLock::new(codes)), + ancestor_headers, + phantom: PhantomData, + }; + + db + } + + /// Fetches and merges a missing account proof into the cached pre-state trie. + async fn fetch_missing_account_proof(&self, address: Address) -> Result<(), RpcDbError> { + tracing::warn!( + "Fetching missing account proof for address {} at block {}", + address, + self.state_block_number + ); + let proof = self + .provider + .get_proof(address, vec![]) + .number(self.state_block_number) + .await + .map_err(|err| RpcDbError::GetProofError(address, err.to_string()))?; + + self.state.write().map_err(|_| RpcDbError::Poisoned)?.extend_from_account_proof(&proof)?; + + Ok(()) + } - Ok(db) + /// Fetches and merges a missing storage proof into the cached pre-state trie. + async fn fetch_missing_storage_proof( + &self, + address: Address, + index: StorageKey, + ) -> Result<(), RpcDbError> { + tracing::warn!( + "Fetching missing storage proof for address {} slot {} at block {}", + address, + B256::from(index), + self.state_block_number + ); + let proof = self + .provider + .get_proof(address, vec![B256::from(index)]) + .number(self.state_block_number) + .await + .map_err(|err| RpcDbError::GetProofError(address, err.to_string()))?; + + self.state.write().map_err(|_| RpcDbError::Poisoned)?.extend_from_account_proof(&proof)?; + + Ok(()) + } + + fn fetch_missing_account_proof_blocking(&self, address: Address) -> Result<(), ProviderError> { + let handle = tokio::runtime::Handle::try_current().map_err(|_| { + ProviderError::Database(DatabaseError::Other("no tokio runtime found".to_string())) + })?; + tokio::task::block_in_place(|| handle.block_on(self.fetch_missing_account_proof(address))) + .map_err(|err| ProviderError::Database(DatabaseError::Other(err.to_string()))) + } + + fn fetch_missing_storage_proof_blocking( + &self, + address: Address, + index: StorageKey, + ) -> Result<(), ProviderError> { + let handle = tokio::runtime::Handle::try_current().map_err(|_| { + ProviderError::Database(DatabaseError::Other("no tokio runtime found".to_string())) + })?; + tokio::task::block_in_place(|| { + handle.block_on(self.fetch_missing_storage_proof(address, index)) + }) + .map_err(|err| ProviderError::Database(DatabaseError::Other(err.to_string()))) + } + + async fn fetch_account_code(&self, address: Address) -> Result { + let code = self + .provider + .get_code_at(address) + .number(self.state_block_number) + .await + .map_err(|err| RpcDbError::GetCodeError(address, err.to_string()))?; + + Ok(Bytecode::new_raw(code)) + } + + fn fetch_account_code_blocking( + &self, + address: Address, + expected_hash: B256, + ) -> Result { + let handle = tokio::runtime::Handle::try_current().map_err(|_| { + ProviderError::Database(DatabaseError::Other("no tokio runtime found".to_string())) + })?; + let bytecode = + tokio::task::block_in_place(|| handle.block_on(self.fetch_account_code(address))) + .map_err(|err| ProviderError::Database(DatabaseError::Other(err.to_string())))?; + + cache_verified_code(&self.codes, address, expected_hash, bytecode) + } + + fn complete_account_code( + &self, + address: Address, + account: Option, + ) -> Result, ProviderError> { + let Some(mut account) = account else { return Ok(None) }; + + if account.code.is_none() && should_fetch_code(account.code_hash) { + if let Some(code) = cached_code(&self.codes, account.code_hash)? { + account.code = Some(code); + } else { + tracing::warn!( + "Code {} not found in execution witness for address {}; fetching fallback code", + account.code_hash, + address + ); + account.code = Some(self.fetch_account_code_blocking(address, account.code_hash)?); + } + } + + Ok(Some(account)) + } + + fn ensure_empty_storage_trie(&self, hashed_address: B256) -> Result<(), ProviderError> { + self.state + .write() + .map_err(|_| poisoned_provider_error())? + .storage_tries + .entry(hashed_address) + .or_default(); + Ok(()) + } +} + +async fn fetch_execution_witness( + provider: &P, + block_number: u64, +) -> Result +where + P: Provider, + N: Network, +{ + let witness = provider + .client() + .request("debug_executionWitness", (BlockNumberOrTag::Number(block_number),)) + .await?; + + Ok(FlexibleExecutionWitness::into_execution_witness(witness)) +} + +#[derive(Debug, Deserialize)] +struct FlexibleExecutionWitness { + state: Vec, + codes: Vec, + #[serde(default)] + keys: Option>, + headers: Vec, +} + +impl FlexibleExecutionWitness { + fn into_execution_witness(self) -> ExecutionWitness { + ExecutionWitness { + state: self.state, + codes: self.codes, + keys: self.keys.unwrap_or_default(), + headers: self + .headers + .into_iter() + .map(FlexibleExecutionWitnessHeader::into_rlp_bytes) + .collect(), + } + } +} + +#[derive(Debug, Deserialize)] +#[serde(untagged)] +enum FlexibleExecutionWitnessHeader { + Rlp(alloy_primitives::Bytes), + Rpc(RpcHeader

), +} + +impl FlexibleExecutionWitnessHeader { + fn into_rlp_bytes(self) -> alloy_primitives::Bytes { + match self { + Self::Rlp(bytes) => bytes, + Self::Rpc(header) => { + let mut out = Vec::new(); + header.into_consensus().encode(&mut out); + out.into() + } + } } } const SYSTEM_ADDRESS: Address = alloy_primitives::address!("0xfffffffffffffffffffffffffffffffffffffffe"); +#[derive(Debug)] +enum AccountReadError { + Trie(mpt::Error), + Provider(ProviderError), +} + +impl AccountReadError { + fn unresolved_node(&self) -> Option { + match self { + Self::Trie(mpt::Error::NodeNotResolved(digest)) => Some(*digest), + Self::Trie(_) | Self::Provider(_) => None, + } + } + + fn into_provider_error(self) -> ProviderError { + match self { + Self::Trie(err) => ProviderError::TrieWitnessError(err.to_string()), + Self::Provider(err) => err, + } + } +} + +fn read_account_info_from_state( + state: &EthereumState, + address_hash: B256, + codes: &HashMap, +) -> Result, AccountReadError> { + if let Some(mut bytes) = + state.state_trie.get(address_hash.as_ref()).map_err(AccountReadError::Trie)? + { + let account = TrieAccount::decode(&mut bytes) + .map_err(ProviderError::from) + .map_err(AccountReadError::Provider)?; + let account_info = + account_info_from_trie_account(codes, account).map_err(AccountReadError::Provider)?; + + Ok(Some(account_info)) + } else { + Ok(None) + } +} + +fn account_info_from_trie_account( + codes: &HashMap, + account: TrieAccount, +) -> Result { + Ok(AccountInfo { + balance: account.balance, + nonce: account.nonce, + code_hash: account.code_hash, + code: codes.get(&account.code_hash).cloned(), + }) +} + +fn cached_code( + codes: &RwLock>, + code_hash: B256, +) -> Result, ProviderError> { + Ok(codes.read().map_err(|_| poisoned_provider_error())?.get(&code_hash).cloned()) +} + +fn cache_verified_code( + codes: &RwLock>, + address: Address, + expected_hash: B256, + bytecode: Bytecode, +) -> Result { + let actual_hash = bytecode.hash_slow(); + if actual_hash != expected_hash { + return Err(ProviderError::TrieWitnessError(format!( + "Fetched code hash mismatch for {address}: expected {expected_hash}, got {actual_hash}" + ))) + } + codes.write().map_err(|_| poisoned_provider_error())?.insert(expected_hash, bytecode.clone()); + + Ok(bytecode) +} + +fn should_fetch_code(code_hash: B256) -> bool { + code_hash != KECCAK_EMPTY && code_hash != B256::ZERO +} + +#[derive(Debug)] +enum StorageRead { + Value(StorageValue), + MissingEmptyTrie, +} + +#[derive(Debug)] +enum StorageReadError { + Trie(mpt::Error), + Provider(ProviderError), + MissingTrie { storage_root: B256 }, +} + +impl StorageReadError { + fn unresolved_node(&self) -> Option { + match self { + Self::Trie(mpt::Error::NodeNotResolved(digest)) => Some(*digest), + Self::Trie(_) | Self::Provider(_) | Self::MissingTrie { .. } => None, + } + } + + fn into_provider_error(self) -> ProviderError { + match self { + Self::Trie(err) => ProviderError::TrieWitnessError(err.to_string()), + Self::Provider(err) => err, + Self::MissingTrie { storage_root } => ProviderError::TrieWitnessError(format!( + "storage trie not found for root {storage_root}" + )), + } + } +} + +fn read_storage_from_state( + state: &EthereumState, + hashed_address: B256, + hashed_slot: B256, +) -> Result { + if let Some(storage_trie) = state.storage_tries.get(&hashed_address) { + if let Some(mut value) = + storage_trie.get(hashed_slot.as_slice()).map_err(StorageReadError::Trie)? + { + return U256::decode(&mut value) + .map(StorageRead::Value) + .map_err(ProviderError::from) + .map_err(StorageReadError::Provider) + } + + return Ok(StorageRead::Value(U256::ZERO)) + } + + let storage_root = state + .state_trie + .get_rlp::(hashed_address.as_slice()) + .map_err(StorageReadError::Trie)? + .map_or(EMPTY_ROOT_HASH, |account| account.storage_root); + + if storage_root == EMPTY_ROOT_HASH || storage_root == B256::ZERO { + Ok(StorageRead::MissingEmptyTrie) + } else { + Err(StorageReadError::MissingTrie { storage_root }) + } +} + +fn poisoned_provider_error() -> ProviderError { + ProviderError::Database(DatabaseError::Other("poisoned lock".to_string())) +} + impl + Clone, N: Network> DatabaseRef for ExecutionWitnessRpcDb { type Error = ProviderError; @@ -68,28 +439,41 @@ impl + Clone, N: Network> DatabaseRef for ExecutionWitnessRpcDb

self.complete_account_code(address, account), + Err(err) => { + let Some(digest) = err.unresolved_node() else { + return Err(err.into_provider_error()) + }; + + tracing::warn!( + "Account trie reached unresolved node {} for address {}; fetching fallback proof", + digest, + address + ); + self.fetch_missing_account_proof_blocking(address)?; + + let account = { + let state = self.state.read().map_err(|_| poisoned_provider_error())?; + let codes = self.codes.read().map_err(|_| poisoned_provider_error())?; + read_account_info_from_state(&state, hash, &codes) + .map_err(AccountReadError::into_provider_error)? + }; + self.complete_account_code(address, account) + } } } fn code_by_hash_ref(&self, code_hash: B256) -> Result { self.codes + .read() + .map_err(|_| poisoned_provider_error())? .get(&code_hash) .ok_or_else(|| { ProviderError::TrieWitnessError(format!("Code not found for {code_hash}")) @@ -105,15 +489,51 @@ impl + Clone, N: Network> DatabaseRef for ExecutionWitnessRpcDb

Ok(value), + Ok(StorageRead::MissingEmptyTrie) => { + self.ensure_empty_storage_trie(hashed_address)?; + Ok(U256::ZERO) + } + Err(err) => { + if let Some(digest) = err.unresolved_node() { + tracing::warn!( + "Storage trie reached unresolved node {} for address {} slot {}; fetching fallback proof", + digest, + address, + slot + ); + } else if let StorageReadError::MissingTrie { storage_root } = err { + tracing::warn!( + "Storage trie with root {} is missing for address {} slot {}; fetching fallback proof", + storage_root, + address, + slot + ); + } else { + return Err(err.into_provider_error()) + } + + self.fetch_missing_storage_proof_blocking(address, index)?; + + let state = self.state.read().map_err(|_| poisoned_provider_error())?; + match read_storage_from_state(&state, hashed_address, hashed_slot) + .map_err(StorageReadError::into_provider_error)? + { + StorageRead::Value(value) => Ok(value), + StorageRead::MissingEmptyTrie => { + drop(state); + self.ensure_empty_storage_trie(hashed_address)?; + Ok(U256::ZERO) + } + } + } } } @@ -133,14 +553,84 @@ where N: Network, { async fn state(&self, _bundle_state: &BundleState) -> Result { - Ok(self.state.clone()) + Ok(self.state.read().map_err(|_| RpcDbError::Poisoned)?.clone()) } fn bytecodes(&self) -> Vec { - self.codes.values().cloned().collect() + self.codes.read().expect("codes lock poisoned").values().cloned().collect() } async fn ancestor_headers(&self) -> Result, RpcDbError> { Ok(self.ancestor_headers.values().cloned().collect()) } } + +#[cfg(test)] +mod tests { + use alloy_consensus::Header; + use alloy_primitives::hex::FromHex; + use alloy_rlp::Decodable; + + use super::*; + + #[test] + fn execution_witness_accepts_rpc_header_objects_and_null_keys() { + let json = r#"{ + "headers": [{ + "parentHash": "0xddcb9640c370c7914ccf303924421b257f05a676fc8d3c9c33ef8476194d98bd", + "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347", + "miner": "0x4838b106fce9647bdf1e7877bf73ce8b0bad5f97", + "stateRoot": "0x043ef1fafb089e28e171f777d22845c2bdbf89e6b767857b02dcf9308de92b5c", + "transactionsRoot": "0x751ee8f2d2893940e2b8287a72fb451ca382e5e515e8de266686e057f8cb41a7", + "receiptsRoot": "0xc0bf6c67ff3ab702758b903204bf3f054ce68ca48dc55f8fd40e5e912b34f782", + "logsBloom": "0xdc7d77b6e8cfcb93b6be74bdc368dba1dfecc4fdef2447324c1d84facd5cdeb2fd5e0196e6fdd5bdff93e3f9ea46adcf76bf89f8bf0e6141b5de26c0bbbf14f7cdbeb0abfedaebf95b7e7a48a5e877fd5c7ef11fb8cc9baa83445c55b8e5ffc8dee2fb19ab7e61dbcc1b9357fe0aecee5e1f7769d396fed9fef5c455bf2fff4de072397a939a5768bd69a73b3587832ab8b3c7ef653dc1de147b3973fbbb8fbfcf157d67a4d5ee5c7df5cd87dcc017a8ffd58b4d9f4c71d85dee3b2e6a1f69ffdfa75f0ef9e83edbbfe32ab7d274eedbd8cc71ff8f7e689bede5331bb0626bd6f4dde9cac72714b43eefb36df28baee2ffe36e2967fd02e2573ef7995503e7cf", + "difficulty": "0x0", + "number": "0x17e8a77", + "gasLimit": "0x3938700", + "gasUsed": "0x19aacd0", + "timestamp": "0x6a017d13", + "extraData": "0x546974616e2028746974616e6275696c6465722e78797a29", + "mixHash": "0xd0d37c7118b2221b8ec1c4940be1689108309c9837a0359d41be16acdc7e546e", + "nonce": "0x0000000000000000", + "baseFeePerGas": "0x115394a1", + "withdrawalsRoot": "0x978b9471e9087c6f967aaa08f757abd7280dbb7aa3310320cdd4d3fb4ecb9e5e", + "blobGasUsed": "0x0", + "excessBlobGas": "0xb503bd8", + "parentBeaconBlockRoot": "0xc2b892804ed1f1f3cfeefbbc0fffd0e298bab43a7773409154a0e6ea306b794a", + "requestsHash": "0xe3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", + "slotNumber": null, + "hash": "0x190299f2eee1493723cc749ff9148663c5202f9b3479ed0da8d99ba62f882c23" + }], + "codes": ["0x6000"], + "state": ["0x80"], + "keys": null + }"#; + + let witness = serde_json::from_str::(json) + .unwrap() + .into_execution_witness(); + let header = Header::decode(&mut witness.headers[0].as_ref()).unwrap(); + + assert_eq!(header.number, 25_070_199); + assert_eq!(witness.codes.len(), 1); + assert_eq!(witness.state.len(), 1); + assert!(witness.keys.is_empty()); + } + + #[test] + fn execution_witness_preserves_rlp_header_bytes_and_keys() { + let json = r#"{ + "headers": ["0x010203"], + "codes": [], + "state": [], + "keys": ["0x04"] + }"#; + + let witness = serde_json::from_str::(json) + .unwrap() + .into_execution_witness(); + + assert_eq!(witness.headers[0].as_ref(), Vec::::from_hex("010203").unwrap()); + assert_eq!(witness.keys[0].as_ref(), Vec::::from_hex("04").unwrap()); + } +}