diff --git a/Cargo.lock b/Cargo.lock index 9e8d52a102..8b9d736e44 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -106,9 +106,9 @@ checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" [[package]] name = "alloy-chains" -version = "0.2.24" +version = "0.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b163ff4acf0eac29af05a911397cc418a76e153467b859398adc26cb9335a611" +checksum = "25db5bcdd086f0b1b9610140a12c59b757397be90bd130d8d836fc8da0815a34" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -448,7 +448,7 @@ dependencies = [ "foldhash 0.2.0", "getrandom 0.3.4", "hashbrown 0.16.1", - "indexmap 2.12.1", + "indexmap 2.13.0", "itoa", "k256", "keccak-asm", @@ -550,7 +550,7 @@ checksum = "64b728d511962dda67c1bc7ea7c03736ec275ed2cf4c35d9585298ac9ccf3b73" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -800,7 +800,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -812,11 +812,11 @@ dependencies = [ "alloy-sol-macro-input", "const-hex", "heck", - "indexmap 2.12.1", + "indexmap 2.13.0", "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", "syn-solidity", "tiny-keccak", ] @@ -833,7 +833,7 @@ dependencies = [ "macro-string", "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", "syn-solidity", ] @@ -936,9 +936,9 @@ dependencies = [ [[package]] name = "alloy-trie" -version = "0.9.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b77b56af09ead281337d06b1d036c88e2dc8a2e45da512a532476dbee94912b" +checksum = "428aa0f0e0658ff091f8f667c406e034b431cb10abd39de4f507520968acc499" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -963,7 +963,7 @@ dependencies = [ "darling 0.21.3", "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -1048,7 +1048,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -1190,7 +1190,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" dependencies = [ "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -1228,7 +1228,7 @@ dependencies = [ "num-traits", "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -1317,7 +1317,7 @@ checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -1390,13 +1390,12 @@ dependencies = [ [[package]] name = "async-compression" -version = "0.4.36" +version = "0.4.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98ec5f6c2f8bc326c994cb9e241cc257ddaba9afa8555a43cffbb5dd86efaa37" +checksum = "d10e4f991a553474232bc0a31799f6d24b034a84c0971d80d2e2f78b2e576e40" dependencies = [ "compression-codecs", "compression-core", - "futures-core", "pin-project-lite", "tokio", ] @@ -1434,7 +1433,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -1445,7 +1444,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -1483,7 +1482,7 @@ checksum = "ffdcb70bdbc4d478427380519163274ac86e52916e10f0a8889adf0f96d3fee7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -1565,9 +1564,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" -version = "1.8.2" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d809780667f4410e7c41b07f52439b94d2bdf8528eeedc287fa38d3b7f95d82" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" [[package]] name = "bech32" @@ -1625,7 +1624,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -1643,7 +1642,7 @@ dependencies = [ "regex", "rustc-hash", "shlex", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -1755,7 +1754,7 @@ dependencies = [ "boa_interner", "boa_macros", "boa_string", - "indexmap 2.12.1", + "indexmap 2.13.0", "num-bigint", "rustc-hash", ] @@ -1787,7 +1786,7 @@ dependencies = [ "futures-lite 2.6.1", "hashbrown 0.16.1", "icu_normalizer", - "indexmap 2.12.1", + "indexmap 2.13.0", "intrusive-collections", "itertools 0.14.0", "num-bigint", @@ -1833,7 +1832,7 @@ dependencies = [ "boa_gc", "boa_macros", "hashbrown 0.16.1", - "indexmap 2.12.1", + "indexmap 2.13.0", "once_cell", "phf", "rustc-hash", @@ -1850,7 +1849,7 @@ dependencies = [ "cow-utils", "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", "synstructure", ] @@ -1906,7 +1905,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -1995,7 +1994,7 @@ checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -2107,10 +2106,11 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.15" +version = "1.2.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c736e259eea577f443d5c86c304f9f4ae0295c43f3ba05c21f1d66b5f06001af" +checksum = "cd4932aefd12402b36c60956a4fe0035421f544799057659ff86f923657aada3" dependencies = [ + "find-msvc-tools", "jobserver", "libc", "shlex", @@ -2145,9 +2145,9 @@ checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chrono" -version = "0.4.42" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" +checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118" dependencies = [ "iana-time-zone", "js-sys", @@ -2236,20 +2236,20 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] name = "clap_lex" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" +checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32" [[package]] name = "cmake" -version = "0.1.54" +version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7caa3f9de89ddbe2c607f4101924c5abec803763ae9534e4f4d7d8f84aa81f0" +checksum = "75443c44cd6b379beb8c5b45d85d0773baf31cce901fe7bb252f4eff3008ef7d" dependencies = [ "cc", ] @@ -2415,9 +2415,9 @@ dependencies = [ [[package]] name = "comfy-table" -version = "7.2.1" +version = "7.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b03b7db8e0b4b2fdad6c551e634134e99ec000e5c8c3b6856c65e8bbaded7a3b" +checksum = "958c5d6ecf1f214b4c2bbbbf6ab9523a864bd136dcf71a7e8904799acfe1ad47" dependencies = [ "crossterm 0.29.0", "unicode-segmentation", @@ -2440,9 +2440,9 @@ dependencies = [ [[package]] name = "compression-codecs" -version = "0.4.35" +version = "0.4.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0f7ac3e5b97fdce45e8922fb05cae2c37f7bbd63d30dd94821dacfd8f3f2bf2" +checksum = "00828ba6fd27b45a448e57dbfe84f1029d4c9f26b368157e9a448a5f49a2ec2a" dependencies = [ "brotli", "compression-core", @@ -2541,16 +2541,6 @@ dependencies = [ "unicode-segmentation", ] -[[package]] -name = "cordyceps" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "688d7fbb8092b8de775ef2536f36c8c31f2bc4006ece2e8d8ad2d17d00ce0a2a" -dependencies = [ - "loom", - "tracing", -] - [[package]] name = "core-foundation" version = "0.10.1" @@ -2798,7 +2788,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -2855,7 +2845,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -2870,7 +2860,7 @@ dependencies = [ "quote", "serde", "strsim", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -2883,7 +2873,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -2894,7 +2884,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core 0.20.11", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -2905,7 +2895,7 @@ checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" dependencies = [ "darling_core 0.21.3", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -2916,7 +2906,7 @@ checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" dependencies = [ "darling_core 0.23.0", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -2948,15 +2938,15 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.9.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" +checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" [[package]] name = "data-encoding-macro" -version = "0.1.18" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47ce6c96ea0102f01122a185683611bd5ac8d99e62bc59dd12e6bda344ee673d" +checksum = "8142a83c17aa9461d637e649271eae18bf2edd00e91f2e105df36c3c16355bdb" dependencies = [ "data-encoding", "data-encoding-macro-internal", @@ -2964,12 +2954,12 @@ dependencies = [ [[package]] name = "data-encoding-macro-internal" -version = "0.1.16" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d162beedaa69905488a8da94f5ac3edb4dd4788b732fadb7bd120b2625c1976" +checksum = "7ab67060fc6b8ef687992d439ca0fa36e7ed17e9a0b16b25b601e8757df720de" dependencies = [ "data-encoding", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -3028,7 +3018,7 @@ checksum = "ef941ded77d15ca19b40374869ac6000af1c9f2a4c0f3d4c70926287e6364a8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -3039,7 +3029,7 @@ checksum = "1e567bd82dcff979e4b03460c307b3cdc9e96fde3d73bed1496d2bc75d9dd62a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -3060,7 +3050,7 @@ dependencies = [ "darling 0.20.11", "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -3070,7 +3060,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -3092,16 +3082,10 @@ dependencies = [ "proc-macro2", "quote", "rustc_version 0.4.1", - "syn 2.0.113", + "syn 2.0.114", "unicode-xid", ] -[[package]] -name = "diatomic-waker" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab03c107fafeb3ee9f5925686dbb7a73bc76e3932abb0d2b365cb64b169cf04c" - [[package]] name = "diff" version = "0.1.13" @@ -3224,7 +3208,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -3271,7 +3255,7 @@ checksum = "1ec431cd708430d5029356535259c5d645d60edd3d39c54e5eea9782d46caa7d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -3323,7 +3307,7 @@ dependencies = [ "enum-ordinalize", "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -3431,7 +3415,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -3451,7 +3435,7 @@ checksum = "8ca9601fb2d62598ee17836250842873a413586e5d7ed88b356e38ddbb0ec631" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -3471,7 +3455,7 @@ checksum = "44f23cf4b44bfce11a86ace86f8a73ffdec849c9fd00a386a53d278bd9e81fb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -3547,7 +3531,7 @@ dependencies = [ "darling 0.20.11", "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -4071,10 +4055,16 @@ dependencies = [ ] [[package]] -name = "fixed-cache" -version = "0.1.3" +name = "find-msvc-tools" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba59b6c98ba422a13f17ee1305c995cb5742bba7997f5b4d9af61b2ff0ffb213" +checksum = "f449e6c6c08c865631d4890cfacf252b3d396c9bcc83adb6623cdb02a8336c41" + +[[package]] +name = "fixed-cache" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25d3af83468398d500e9bc19e001812dcb1a11e4d3d6a5956c789aa3c11a8cb5" dependencies = [ "equivalent", ] @@ -4109,7 +4099,7 @@ checksum = "6dc7a9cb3326bafb80642c5ce99b39a2c0702d4bfa8ee8a3e773791a6cbe2407" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -4120,9 +4110,9 @@ checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" [[package]] name = "flate2" -version = "1.1.5" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb" +checksum = "b375d6465b98090a5f25b1c7703f3859783755aa9a80433b36e0379a3ec2f369" dependencies = [ "crc32fast", "miniz_oxide", @@ -4195,19 +4185,6 @@ dependencies = [ "futures-util", ] -[[package]] -name = "futures-buffered" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8e0e1f38ec07ba4abbde21eed377082f17ccb988be9d988a5adbf4bafc118fd" -dependencies = [ - "cordyceps", - "diatomic-waker", - "futures-core", - "pin-project-lite", - "spin", -] - [[package]] name = "futures-channel" version = "0.3.31" @@ -4220,16 +4197,14 @@ dependencies = [ [[package]] name = "futures-concurrency" -version = "7.6.3" +version = "7.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eb68017df91f2e477ed4bea586c59eaecaa47ed885a770d0444e21e62572cd2" +checksum = "69a9561702beff46b705a8ac9c0803ec4c7fc5d01330a99b1feaf86e206e92ba" dependencies = [ "fixedbitset", - "futures-buffered", "futures-core", "futures-lite 2.6.1", "pin-project", - "slab", "smallvec", ] @@ -4292,7 +4267,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -4380,9 +4355,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", "js-sys", @@ -4509,9 +4484,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" +checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" dependencies = [ "atomic-waker", "bytes", @@ -4519,7 +4494,7 @@ dependencies = [ "futures-core", "futures-sink", "http", - "indexmap 2.12.1", + "indexmap 2.13.0", "slab", "tokio", "tokio-util", @@ -5039,7 +5014,7 @@ checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -5080,9 +5055,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.12.1" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" dependencies = [ "arbitrary", "equivalent", @@ -5158,7 +5133,7 @@ dependencies = [ "indoc", "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -5435,7 +5410,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -5580,9 +5555,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.179" +version = "0.2.180" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5a2d376baa530d1238d133232d15e239abad80d05838b4b59354e5268af431f" +checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" [[package]] name = "libgit2-sys" @@ -5816,7 +5791,7 @@ checksum = "1b27834086c65ec3f9387b096d66e99f221cf081c2b738042aa252bcd41204e3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -5834,13 +5809,13 @@ dependencies = [ [[package]] name = "match-lookup" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1265724d8cb29dbbc2b0f06fffb8bf1a8c0cf73a78eede9ba73a4a66c52a981e" +checksum = "757aee279b8bdbb9f9e676796fd459e4207a1f986e87886700abf589f5abf771" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.114", ] [[package]] @@ -5895,7 +5870,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -5905,7 +5880,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3589659543c04c7dc5526ec858591015b87cd8746583b51b48ef4353f99dbcda" dependencies = [ "base64 0.22.1", - "indexmap 2.12.1", + "indexmap 2.13.0", "metrics", "metrics-util", "quanta", @@ -5937,7 +5912,7 @@ dependencies = [ "crossbeam-epoch", "crossbeam-utils", "hashbrown 0.16.1", - "indexmap 2.12.1", + "indexmap 2.13.0", "metrics", "ordered-float", "quanta", @@ -6297,7 +6272,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -6311,9 +6286,9 @@ dependencies = [ [[package]] name = "nybbles" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c4b5ecbd0beec843101bffe848217f770e8b8da81d8355b7d6e226f2199b3dc" +checksum = "7b5676b5c379cf5b03da1df2b3061c4a4e2aa691086a56ac923e08c143f53f59" dependencies = [ "alloy-rlp", "arbitrary", @@ -6584,7 +6559,7 @@ dependencies = [ "opentelemetry-http", "opentelemetry-proto", "opentelemetry_sdk", - "prost 0.14.1", + "prost 0.14.3", "reqwest", "thiserror 2.0.17", "tokio", @@ -6600,7 +6575,7 @@ checksum = "a7175df06de5eaee9909d4805a3d07e28bb752c34cab57fa9cff549da596b30f" dependencies = [ "opentelemetry", "opentelemetry_sdk", - "prost 0.14.1", + "prost 0.14.3", "tonic", "tonic-prost", ] @@ -6696,7 +6671,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -6811,7 +6786,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -6840,7 +6815,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -6981,7 +6956,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -7032,14 +7007,14 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] name = "proc-macro2" -version = "1.0.104" +version = "1.0.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9695f8df41bb4f3d222c95a67532365f569318332d03d5f3f67f37b20e6ebdf0" +checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7" dependencies = [ "unicode-ident", ] @@ -7127,7 +7102,7 @@ checksum = "4ee1c9ac207483d5e7db4940700de86a9aae46ef90c48b57f99fe7edb8345e49" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -7138,7 +7113,7 @@ checksum = "095a99f75c69734802359b682be8daaf8980296731f6470434ea2c652af1dd30" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -7153,12 +7128,12 @@ dependencies = [ [[package]] name = "prost" -version = "0.14.1" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7231bd9b3d3d33c86b58adbac74b5ec0ad9f496b19d22801d773636feaa95f3d" +checksum = "d2ea70524a2f82d518bce41317d0fae74151505651af45faf1ffbd6fd33f0568" dependencies = [ "bytes", - "prost-derive 0.14.1", + "prost-derive 0.14.3", ] [[package]] @@ -7171,20 +7146,20 @@ dependencies = [ "itertools 0.14.0", "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] name = "prost-derive" -version = "0.14.1" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9120690fafc389a67ba3803df527d0ec9cbbc9cc45e4cc20b332996dfb672425" +checksum = "27c6023962132f4b30eb4c172c91ce92d933da334c59c23cddee82358ddafb0b" dependencies = [ "anyhow", "itertools 0.14.0", "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -7285,9 +7260,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.42" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" +checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a" dependencies = [ "proc-macro2", ] @@ -7336,7 +7311,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ "rand_chacha 0.9.0", - "rand_core 0.9.3", + "rand_core 0.9.5", "serde", ] @@ -7367,7 +7342,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] @@ -7385,14 +7360,14 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.16", + "getrandom 0.2.17", ] [[package]] name = "rand_core" -version = "0.9.3" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" dependencies = [ "getrandom 0.3.4", "serde", @@ -7413,7 +7388,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" dependencies = [ - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] @@ -7422,14 +7397,14 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f703f4665700daf5512dcca5f43afa6af89f09db47fb56be587f80636bda2d41" dependencies = [ - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] name = "rapidhash" -version = "4.2.0" +version = "4.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2988730ee014541157f48ce4dcc603940e00915edc3c7f9a8d78092256bb2493" +checksum = "5d8b5b858a440a0bc02625b62dd95131b9201aa9f69f411195dd4a7cfb1de3d7" dependencies = [ "rand 0.9.2", "rustversion", @@ -7515,7 +7490,7 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ - "getrandom 0.2.16", + "getrandom 0.2.17", "libredox", "thiserror 1.0.69", ] @@ -7526,7 +7501,7 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" dependencies = [ - "getrandom 0.2.16", + "getrandom 0.2.17", "libredox", "thiserror 2.0.17", ] @@ -7548,7 +7523,7 @@ checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -7719,6 +7694,7 @@ dependencies = [ name = "reth-bench" version = "1.10.0" dependencies = [ + "alloy-consensus", "alloy-eips", "alloy-json-rpc", "alloy-network", @@ -7741,13 +7717,16 @@ dependencies = [ "op-alloy-consensus", "op-alloy-rpc-types-engine", "reqwest", + "reth-chainspec", "reth-cli-runner", "reth-cli-util", "reth-engine-primitives", + "reth-ethereum-primitives", "reth-fs-util", "reth-node-api", "reth-node-core", "reth-primitives-traits", + "reth-rpc-api", "reth-tracing", "serde", "serde_json", @@ -7997,7 +7976,7 @@ dependencies = [ "proc-macro2", "quote", "similar-asserts", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -10493,7 +10472,6 @@ dependencies = [ "reth-network-peers", "reth-rpc-eth-api", "reth-trie-common", - "serde", "serde_json", "tokio", ] @@ -11564,7 +11542,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.16", + "getrandom 0.2.17", "libc", "untrusted", "windows-sys 0.52.0", @@ -11684,7 +11662,7 @@ dependencies = [ "regex", "relative-path", "rustc_version 0.4.1", - "syn 2.0.113", + "syn 2.0.114", "unicode-ident", ] @@ -11811,9 +11789,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.35" +version = "0.23.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f" +checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b" dependencies = [ "log", "once_cell", @@ -12149,16 +12127,16 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] name = "serde_json" -version = "1.0.148" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3084b546a1dd6289475996f182a22aba973866ea8e8b02c51d9f46b1336a22da" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ - "indexmap 2.12.1", + "indexmap 2.13.0", "itoa", "memchr", "serde", @@ -12208,7 +12186,7 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.12.1", + "indexmap 2.13.0", "schemars 0.9.0", "schemars 1.2.0", "serde_core", @@ -12226,7 +12204,7 @@ dependencies = [ "darling 0.21.3", "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -12498,12 +12476,6 @@ dependencies = [ "sha1", ] -[[package]] -name = "spin" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5fe4ccb98d9c292d56fec89a5e07da7fc4cf0dc11e156b41793132775d3e591" - [[package]] name = "spki" version = "0.7.3" @@ -12560,7 +12532,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -12572,7 +12544,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -12594,9 +12566,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.113" +version = "2.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "678faa00651c9eb72dd2020cbdf275d92eccb2400d568e419efdd64838145cb4" +checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" dependencies = [ "proc-macro2", "quote", @@ -12612,7 +12584,7 @@ dependencies = [ "paste", "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -12632,7 +12604,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -12719,7 +12691,7 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -12730,7 +12702,7 @@ checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", "test-case-core", ] @@ -12770,7 +12742,7 @@ dependencies = [ "prettyplease", "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -12818,7 +12790,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -12829,7 +12801,7 @@ checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -12883,9 +12855,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.44" +version = "0.3.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" +checksum = "f9e442fc33d7fdb45aa9bfeb312c095964abdf596f7567261062b2a7107aaabd" dependencies = [ "deranged", "itoa", @@ -12894,22 +12866,22 @@ dependencies = [ "num-conv", "num_threads", "powerfmt", - "serde", + "serde_core", "time-core", "time-macros", ] [[package]] name = "time-core" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" +checksum = "8b36ee98fd31ec7426d599183e8fe26932a8dc1fb76ddb6214d05493377d34ca" [[package]] name = "time-macros" -version = "0.2.24" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" +checksum = "71e552d1249bf61ac2a52db88179fd0673def1e1ad8243a00d9ec9ed71fee3dd" dependencies = [ "num-conv", "time-core", @@ -12985,7 +12957,7 @@ checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -13000,9 +12972,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" +checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" dependencies = [ "futures-core", "pin-project-lite", @@ -13029,9 +13001,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.17" +version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" dependencies = [ "bytes", "futures-core", @@ -13078,7 +13050,7 @@ version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ - "indexmap 2.12.1", + "indexmap 2.13.0", "serde", "serde_spanned", "toml_datetime 0.6.11", @@ -13092,7 +13064,7 @@ version = "0.23.10+spec-1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" dependencies = [ - "indexmap 2.12.1", + "indexmap 2.13.0", "toml_datetime 0.7.5+spec-1.1.0", "toml_parser", "winnow", @@ -13146,20 +13118,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "66bd50ad6ce1252d87ef024b3d64fe4c3cf54a86fb9ef4c631fdd0ded7aeaa67" dependencies = [ "bytes", - "prost 0.14.1", + "prost 0.14.3", "tonic", ] [[package]] name = "tower" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" dependencies = [ "futures-core", "futures-util", "hdrhistogram", - "indexmap 2.12.1", + "indexmap 2.13.0", "pin-project-lite", "slab", "sync_wrapper", @@ -13245,7 +13217,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -13314,16 +13286,13 @@ dependencies = [ [[package]] name = "tracing-opentelemetry" -version = "0.32.0" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e6e5658463dd88089aba75c7791e1d3120633b1bfde22478b28f625a9bb1b8e" +checksum = "1ac28f2d093c6c477eaa76b23525478f38de514fa9aeb1285738d4b97a9552fc" dependencies = [ "js-sys", "opentelemetry", - "opentelemetry_sdk", - "rustversion", "smallvec", - "thiserror 2.0.17", "tracing", "tracing-core", "tracing-log", @@ -13400,9 +13369,9 @@ dependencies = [ [[package]] name = "tracy-client" -version = "0.18.3" +version = "0.18.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91d722a05fe49b31fef971c4732a7d4aa6a18283d9ba46abddab35f484872947" +checksum = "a4f6fc3baeac5d86ab90c772e9e30620fc653bf1864295029921a15ef478e6a5" dependencies = [ "loom", "once_cell", @@ -13412,9 +13381,9 @@ dependencies = [ [[package]] name = "tracy-client-sys" -version = "0.27.0" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fb391ac70462b3097a755618fbf9c8f95ecc1eb379a414f7b46f202ed10db1f" +checksum = "c5f7c95348f20c1c913d72157b3c6dee6ea3e30b3d19502c5a7f6d3f160dacbf" dependencies = [ "cc", "windows-targets 0.52.6", @@ -13442,7 +13411,7 @@ dependencies = [ "darling 0.20.11", "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -13530,9 +13499,9 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicase" -version = "2.8.1" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" +checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" [[package]] name = "unicode-ident" @@ -13605,14 +13574,15 @@ checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae" [[package]] name = "url" -version = "2.5.7" +version = "2.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" dependencies = [ "form_urlencoded", "idna", "percent-encoding", "serde", + "serde_derive", ] [[package]] @@ -13723,7 +13693,7 @@ checksum = "d674d135b4a8c1d7e813e2f8d1c9a58308aee4a680323066025e53132218bd91" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -13826,7 +13796,7 @@ dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", "wasm-bindgen-shared", ] @@ -14034,7 +14004,7 @@ checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -14045,7 +14015,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -14056,7 +14026,7 @@ checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -14067,7 +14037,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -14525,28 +14495,28 @@ checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", "synstructure", ] [[package]] name = "zerocopy" -version = "0.8.31" +version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3" +checksum = "668f5168d10b9ee831de31933dc111a459c97ec93225beb307aed970d1372dfd" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.31" +version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a" +checksum = "2c7962b26b0a8685668b671ee4b54d007a67d4eaf05fda79ac0ecf41e32270f1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -14566,7 +14536,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", "synstructure", ] @@ -14587,7 +14557,7 @@ checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] @@ -14621,14 +14591,14 @@ checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.113", + "syn 2.0.114", ] [[package]] name = "zmij" -version = "1.0.9" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ee2a72b10d087f75fb2e1c2c7343e308fe6970527c22a41caf8372e165ff5c1" +checksum = "bd8f3f50b848df28f887acb68e41201b5aea6bc8a8dacc00fb40635ff9a72fea" [[package]] name = "zstd" diff --git a/bin/reth-bench/Cargo.toml b/bin/reth-bench/Cargo.toml index bfc0051fab..52bb9b036f 100644 --- a/bin/reth-bench/Cargo.toml +++ b/bin/reth-bench/Cargo.toml @@ -17,21 +17,26 @@ workspace = true reth-cli-runner.workspace = true reth-cli-util.workspace = true reth-engine-primitives.workspace = true +reth-ethereum-primitives.workspace = true reth-fs-util.workspace = true reth-node-api.workspace = true reth-node-core.workspace = true reth-primitives-traits.workspace = true +reth-rpc-api.workspace = true + reth-tracing.workspace = true +reth-chainspec.workspace = true # alloy alloy-eips.workspace = true alloy-json-rpc.workspace = true +alloy-consensus.workspace = true alloy-network.workspace = true alloy-primitives.workspace = true alloy-provider = { workspace = true, features = ["engine-api", "pubsub", "reqwest-rustls-tls"], default-features = false } alloy-pubsub.workspace = true alloy-rpc-client = { workspace = true, features = ["pubsub"] } -alloy-rpc-types-engine.workspace = true +alloy-rpc-types-engine = { workspace = true, features = ["kzg"] } alloy-transport-http.workspace = true alloy-transport-ipc.workspace = true alloy-transport-ws.workspace = true diff --git a/bin/reth-bench/src/bench/gas_limit_ramp.rs b/bin/reth-bench/src/bench/gas_limit_ramp.rs new file mode 100644 index 0000000000..4f0d58dbd9 --- /dev/null +++ b/bin/reth-bench/src/bench/gas_limit_ramp.rs @@ -0,0 +1,160 @@ +//! Benchmarks empty block processing by ramping the block gas limit. + +use crate::{ + authenticated_transport::AuthenticatedTransportConnect, + bench::{ + helpers::{build_payload, prepare_payload_request, rpc_block_to_header}, + output::GasRampPayloadFile, + }, + valid_payload::{call_forkchoice_updated, call_new_payload, payload_to_new_payload}, +}; +use alloy_eips::BlockNumberOrTag; +use alloy_provider::{network::AnyNetwork, Provider, RootProvider}; +use alloy_rpc_client::ClientBuilder; +use alloy_rpc_types_engine::{ExecutionPayload, ForkchoiceState, JwtSecret}; + +use clap::Parser; +use reqwest::Url; +use reth_chainspec::ChainSpec; +use reth_cli_runner::CliContext; +use reth_ethereum_primitives::TransactionSigned; +use reth_primitives_traits::constants::{GAS_LIMIT_BOUND_DIVISOR, MAXIMUM_GAS_LIMIT_BLOCK}; +use std::{path::PathBuf, time::Instant}; +use tracing::info; + +/// `reth benchmark gas-limit-ramp` command. +#[derive(Debug, Parser)] +pub struct Command { + /// Number of blocks to generate. + #[arg(long, value_name = "BLOCKS")] + blocks: u64, + + /// The Engine API RPC URL. + #[arg(long = "engine-rpc-url", value_name = "ENGINE_RPC_URL")] + engine_rpc_url: String, + + /// Path to the JWT secret for Engine API authentication. + #[arg(long = "jwt-secret", value_name = "JWT_SECRET")] + jwt_secret: PathBuf, + + /// Output directory for benchmark results and generated payloads. + #[arg(long, value_name = "OUTPUT")] + output: PathBuf, +} + +impl Command { + /// Execute `benchmark gas-limit-ramp` command. + pub async fn execute(self, _ctx: CliContext) -> eyre::Result<()> { + if self.blocks == 0 { + return Err(eyre::eyre!("--blocks must be greater than 0")); + } + + // Ensure output directory exists + if self.output.is_file() { + return Err(eyre::eyre!("Output path must be a directory")); + } + if !self.output.exists() { + std::fs::create_dir_all(&self.output)?; + info!("Created output directory: {:?}", self.output); + } + + // Set up authenticated provider (used for both Engine API and eth_ methods) + let jwt = std::fs::read_to_string(&self.jwt_secret)?; + let jwt = JwtSecret::from_hex(jwt)?; + let auth_url = Url::parse(&self.engine_rpc_url)?; + + info!("Connecting to Engine RPC at {}", auth_url); + let auth_transport = AuthenticatedTransportConnect::new(auth_url, jwt); + let client = ClientBuilder::default().connect_with(auth_transport).await?; + let provider = RootProvider::::new(client); + + // Get chain spec - required for fork detection + let chain_id = provider.get_chain_id().await?; + let chain_spec = ChainSpec::from_chain_id(chain_id) + .ok_or_else(|| eyre::eyre!("Unsupported chain id: {chain_id}"))?; + + // Fetch the current head block as parent + let parent_block = provider + .get_block_by_number(BlockNumberOrTag::Latest) + .full() + .await? + .ok_or_else(|| eyre::eyre!("Failed to fetch latest block"))?; + + let (mut parent_header, mut parent_hash) = rpc_block_to_header(parent_block); + + let canonical_parent = parent_header.number; + let start_block = canonical_parent + 1; + let end_block = start_block + self.blocks - 1; + + info!(canonical_parent, start_block, end_block, "Starting gas limit ramp benchmark"); + + let mut next_block_number = start_block; + let total_benchmark_duration = Instant::now(); + + while next_block_number <= end_block { + let timestamp = parent_header.timestamp.saturating_add(1); + + let request = prepare_payload_request(&chain_spec, timestamp, parent_hash); + let new_payload_version = request.new_payload_version; + + let (payload, sidecar) = build_payload(&provider, request).await?; + + let mut block = + payload.clone().try_into_block_with_sidecar::(&sidecar)?; + + let max_increase = max_gas_limit_increase(parent_header.gas_limit); + let gas_limit = + parent_header.gas_limit.saturating_add(max_increase).min(MAXIMUM_GAS_LIMIT_BLOCK); + + block.header.gas_limit = gas_limit; + + let block_hash = block.header.hash_slow(); + // Regenerate the payload from the modified block, but keep the original sidecar + // which contains the actual execution requests data (not just the hash) + let (payload, _) = ExecutionPayload::from_block_unchecked(block_hash, &block); + let (version, params) = payload_to_new_payload( + payload, + sidecar, + false, + block.header.withdrawals_root, + Some(new_payload_version), + )?; + + // Save payload to file with version info for replay + let payload_path = + self.output.join(format!("payload_block_{}.json", block.header.number)); + let file = + GasRampPayloadFile { version: version as u8, block_hash, params: params.clone() }; + let payload_json = serde_json::to_string_pretty(&file)?; + std::fs::write(&payload_path, &payload_json)?; + info!(block_number = block.header.number, path = %payload_path.display(), "Saved payload"); + + call_new_payload(&provider, version, params).await?; + + let forkchoice_state = ForkchoiceState { + head_block_hash: block_hash, + safe_block_hash: block_hash, + finalized_block_hash: block_hash, + }; + call_forkchoice_updated(&provider, version, forkchoice_state, None).await?; + + parent_header = block.header; + parent_hash = block_hash; + next_block_number += 1; + } + + let final_gas_limit = parent_header.gas_limit; + info!( + total_duration=?total_benchmark_duration.elapsed(), + blocks_processed = self.blocks, + final_gas_limit, + "Benchmark complete" + ); + + Ok(()) + } +} + +const fn max_gas_limit_increase(parent_gas_limit: u64) -> u64 { + (parent_gas_limit / GAS_LIMIT_BOUND_DIVISOR).saturating_sub(1) +} diff --git a/bin/reth-bench/src/bench/generate_big_block.rs b/bin/reth-bench/src/bench/generate_big_block.rs new file mode 100644 index 0000000000..7ddab1125e --- /dev/null +++ b/bin/reth-bench/src/bench/generate_big_block.rs @@ -0,0 +1,617 @@ +//! Command for generating large blocks by packing transactions from real blocks. +//! +//! This command fetches transactions from existing blocks and packs them into a single +//! large block using the `testing_buildBlockV1` RPC endpoint. + +use crate::authenticated_transport::AuthenticatedTransportConnect; +use alloy_eips::{BlockNumberOrTag, Typed2718}; +use alloy_primitives::{Bytes, B256}; +use alloy_provider::{ext::EngineApi, network::AnyNetwork, Provider, RootProvider}; +use alloy_rpc_client::ClientBuilder; +use alloy_rpc_types_engine::{ + ExecutionPayloadEnvelopeV4, ExecutionPayloadEnvelopeV5, ForkchoiceState, JwtSecret, + PayloadAttributes, +}; +use alloy_transport::layers::RetryBackoffLayer; +use clap::Parser; +use eyre::Context; +use reqwest::Url; +use reth_cli_runner::CliContext; +use reth_rpc_api::TestingBuildBlockRequestV1; +use std::future::Future; +use tokio::sync::mpsc; +use tracing::{info, warn}; + +/// A single transaction with its gas used and raw encoded bytes. +#[derive(Debug, Clone)] +pub struct RawTransaction { + /// The actual gas used by the transaction (from receipt). + pub gas_used: u64, + /// The transaction type (e.g., 3 for EIP-4844 blob txs). + pub tx_type: u8, + /// The raw RLP-encoded transaction bytes. + pub raw: Bytes, +} + +/// Abstraction over sources of transactions for big block generation. +/// +/// Implementors provide transactions from different sources (RPC, database, files, etc.) +pub trait TransactionSource { + /// Fetch transactions from a specific block number. + /// + /// Returns `Ok(None)` if the block doesn't exist. + /// Returns `Ok(Some((transactions, gas_used)))` with the block's transactions and total gas. + fn fetch_block_transactions( + &self, + block_number: u64, + ) -> impl Future, u64)>>> + Send; +} + +/// RPC-based transaction source that fetches from a remote node. +#[derive(Debug)] +pub struct RpcTransactionSource { + provider: RootProvider, +} + +impl RpcTransactionSource { + /// Create a new RPC transaction source. + pub const fn new(provider: RootProvider) -> Self { + Self { provider } + } + + /// Create from an RPC URL with retry backoff. + pub fn from_url(rpc_url: &str) -> eyre::Result { + let client = ClientBuilder::default() + .layer(RetryBackoffLayer::new(10, 800, u64::MAX)) + .http(rpc_url.parse()?); + let provider = RootProvider::::new(client); + Ok(Self { provider }) + } +} + +impl TransactionSource for RpcTransactionSource { + async fn fetch_block_transactions( + &self, + block_number: u64, + ) -> eyre::Result, u64)>> { + // Fetch block and receipts in parallel + let (block, receipts) = tokio::try_join!( + self.provider.get_block_by_number(block_number.into()).full(), + self.provider.get_block_receipts(block_number.into()) + )?; + + let Some(block) = block else { + return Ok(None); + }; + + let Some(receipts) = receipts else { + return Err(eyre::eyre!("Receipts not found for block {}", block_number)); + }; + + let block_gas_used = block.header.gas_used; + + // Convert cumulative gas from receipts to per-tx gas_used + let mut prev_cumulative = 0u64; + let transactions: Vec = block + .transactions + .txns() + .zip(receipts.iter()) + .map(|(tx, receipt)| { + let cumulative = receipt.inner.inner.inner.receipt.cumulative_gas_used; + let gas_used = cumulative - prev_cumulative; + prev_cumulative = cumulative; + + let with_encoded = tx.inner.inner.clone().into_encoded(); + RawTransaction { + gas_used, + tx_type: tx.inner.ty(), + raw: with_encoded.encoded_bytes().clone(), + } + }) + .collect(); + + Ok(Some((transactions, block_gas_used))) + } +} + +/// Collects transactions from a source up to a target gas usage. +#[derive(Debug)] +pub struct TransactionCollector { + source: S, + target_gas: u64, +} + +impl TransactionCollector { + /// Create a new transaction collector. + pub const fn new(source: S, target_gas: u64) -> Self { + Self { source, target_gas } + } + + /// Collect transactions starting from the given block number. + /// + /// Skips blob transactions (type 3) and collects until target gas is reached. + /// Returns the collected raw transaction bytes, total gas used, and the next block number. + pub async fn collect(&self, start_block: u64) -> eyre::Result<(Vec, u64, u64)> { + let mut transactions: Vec = Vec::new(); + let mut total_gas: u64 = 0; + let mut current_block = start_block; + + while total_gas < self.target_gas { + let Some((block_txs, _)) = self.source.fetch_block_transactions(current_block).await? + else { + warn!(block = current_block, "Block not found, stopping"); + break; + }; + + for tx in block_txs { + // Skip blob transactions (EIP-4844, type 3) + if tx.tx_type == 3 { + continue; + } + + if total_gas + tx.gas_used <= self.target_gas { + transactions.push(tx.raw); + total_gas += tx.gas_used; + } + + if total_gas >= self.target_gas { + break; + } + } + + current_block += 1; + + // Stop early if remaining gas is under 1M (close enough to target) + let remaining_gas = self.target_gas.saturating_sub(total_gas); + if remaining_gas < 1_000_000 { + break; + } + } + + info!( + total_txs = transactions.len(), + total_gas, + next_block = current_block, + "Finished collecting transactions" + ); + + Ok((transactions, total_gas, current_block)) + } +} + +/// `reth bench generate-big-block` command +/// +/// Generates a large block by fetching transactions from existing blocks and packing them +/// into a single block using the `testing_buildBlockV1` RPC endpoint. +#[derive(Debug, Parser)] +pub struct Command { + /// The RPC URL to use for fetching blocks (can be an external archive node). + #[arg(long, value_name = "RPC_URL")] + rpc_url: String, + + /// The engine RPC URL (with JWT authentication). + #[arg(long, value_name = "ENGINE_RPC_URL", default_value = "http://localhost:8551")] + engine_rpc_url: String, + + /// The RPC URL for `testing_buildBlockV1` calls (same node as engine, regular RPC port). + #[arg(long, value_name = "TESTING_RPC_URL", default_value = "http://localhost:8545")] + testing_rpc_url: String, + + /// Path to the JWT secret file for engine API authentication. + #[arg(long, value_name = "JWT_SECRET")] + jwt_secret: std::path::PathBuf, + + /// Target gas to pack into the block. + #[arg(long, value_name = "TARGET_GAS", default_value = "30000000")] + target_gas: u64, + + /// Starting block number to fetch transactions from. + /// If not specified, starts from the engine's latest block. + #[arg(long, value_name = "FROM_BLOCK")] + from_block: Option, + + /// Execute the payload (call newPayload + forkchoiceUpdated). + /// If false, only builds the payload and prints it. + #[arg(long, default_value = "false")] + execute: bool, + + /// Number of payloads to generate. Each payload uses the previous as parent. + /// When count == 1, the payload is only generated and saved, not executed. + /// When count > 1, each payload is executed before building the next. + #[arg(long, default_value = "1")] + count: u64, + + /// Number of transaction batches to prefetch in background when count > 1. + /// Higher values reduce latency but use more memory. + #[arg(long, default_value = "4")] + prefetch_buffer: usize, + + /// Output directory for generated payloads. Each payload is saved as `payload_block_N.json`. + #[arg(long, value_name = "OUTPUT_DIR")] + output_dir: std::path::PathBuf, +} + +/// A built payload ready for execution. +struct BuiltPayload { + block_number: u64, + envelope: ExecutionPayloadEnvelopeV4, + block_hash: B256, + timestamp: u64, +} + +impl Command { + /// Execute the `generate-big-block` command + pub async fn execute(self, _ctx: CliContext) -> eyre::Result<()> { + info!(target_gas = self.target_gas, count = self.count, "Generating big block(s)"); + + // Set up authenticated engine provider + let jwt = + std::fs::read_to_string(&self.jwt_secret).wrap_err("Failed to read JWT secret file")?; + let jwt = JwtSecret::from_hex(jwt.trim())?; + let auth_url = Url::parse(&self.engine_rpc_url)?; + + info!("Connecting to Engine RPC at {}", auth_url); + let auth_transport = AuthenticatedTransportConnect::new(auth_url.clone(), jwt); + let auth_client = ClientBuilder::default().connect_with(auth_transport).await?; + let auth_provider = RootProvider::::new(auth_client); + + // Set up testing RPC provider (for testing_buildBlockV1) + info!("Connecting to Testing RPC at {}", self.testing_rpc_url); + let testing_client = ClientBuilder::default() + .layer(RetryBackoffLayer::new(10, 800, u64::MAX)) + .http(self.testing_rpc_url.parse()?); + let testing_provider = RootProvider::::new(testing_client); + + // Get the parent block (latest canonical block) + info!(endpoint = "engine", method = "eth_getBlockByNumber", block = "latest", "RPC call"); + let parent_block = auth_provider + .get_block_by_number(BlockNumberOrTag::Latest) + .await? + .ok_or_else(|| eyre::eyre!("Failed to fetch latest block"))?; + + let parent_hash = parent_block.header.hash; + let parent_number = parent_block.header.number; + let parent_timestamp = parent_block.header.timestamp; + + info!( + parent_hash = %parent_hash, + parent_number = parent_number, + "Using initial parent block" + ); + + // Create output directory + std::fs::create_dir_all(&self.output_dir).wrap_err_with(|| { + format!("Failed to create output directory: {:?}", self.output_dir) + })?; + + let start_block = self.from_block.unwrap_or(parent_number); + + // Use pipelined execution when generating multiple payloads + if self.count > 1 { + self.execute_pipelined( + &auth_provider, + &testing_provider, + start_block, + parent_hash, + parent_timestamp, + ) + .await?; + } else { + // Single payload - collect transactions and build + let tx_source = RpcTransactionSource::from_url(&self.rpc_url)?; + let collector = TransactionCollector::new(tx_source, self.target_gas); + let (transactions, _total_gas, _next_block) = collector.collect(start_block).await?; + + if transactions.is_empty() { + return Err(eyre::eyre!("No transactions collected")); + } + + self.execute_sequential( + &auth_provider, + &testing_provider, + transactions, + parent_hash, + parent_timestamp, + ) + .await?; + } + + info!(count = self.count, output_dir = %self.output_dir.display(), "All payloads generated"); + Ok(()) + } + + /// Sequential execution path for single payload or no-execute mode. + async fn execute_sequential( + &self, + auth_provider: &RootProvider, + testing_provider: &RootProvider, + transactions: Vec, + mut parent_hash: B256, + mut parent_timestamp: u64, + ) -> eyre::Result<()> { + for i in 0..self.count { + info!( + payload = i + 1, + total = self.count, + parent_hash = %parent_hash, + parent_timestamp = parent_timestamp, + "Building payload via testing_buildBlockV1" + ); + + let built = self + .build_payload(testing_provider, &transactions, i, parent_hash, parent_timestamp) + .await?; + + self.save_payload(&built)?; + + if self.execute || self.count > 1 { + info!(payload = i + 1, block_hash = %built.block_hash, "Executing payload (newPayload + FCU)"); + self.execute_payload_v4(auth_provider, built.envelope, parent_hash).await?; + info!(payload = i + 1, "Payload executed successfully"); + } + + parent_hash = built.block_hash; + parent_timestamp = built.timestamp; + } + Ok(()) + } + + /// Pipelined execution - fetches transactions and builds payloads in background. + async fn execute_pipelined( + &self, + auth_provider: &RootProvider, + testing_provider: &RootProvider, + start_block: u64, + initial_parent_hash: B256, + initial_parent_timestamp: u64, + ) -> eyre::Result<()> { + // Create channel for transaction batches (one batch per payload) + let (tx_sender, mut tx_receiver) = mpsc::channel::>(self.prefetch_buffer); + + // Spawn background task to continuously fetch transaction batches + let rpc_url = self.rpc_url.clone(); + let target_gas = self.target_gas; + let count = self.count; + + let fetcher_handle = tokio::spawn(async move { + let tx_source = match RpcTransactionSource::from_url(&rpc_url) { + Ok(source) => source, + Err(e) => { + warn!(error = %e, "Failed to create transaction source"); + return; + } + }; + + let collector = TransactionCollector::new(tx_source, target_gas); + let mut current_block = start_block; + + for payload_idx in 0..count { + match collector.collect(current_block).await { + Ok((transactions, total_gas, next_block)) => { + info!( + payload = payload_idx + 1, + tx_count = transactions.len(), + total_gas, + blocks = format!("{}..{}", current_block, next_block), + "Fetched transactions" + ); + current_block = next_block; + + if tx_sender.send(transactions).await.is_err() { + break; + } + } + Err(e) => { + warn!(payload = payload_idx + 1, error = %e, "Failed to fetch transactions"); + break; + } + } + } + }); + + let mut parent_hash = initial_parent_hash; + let mut parent_timestamp = initial_parent_timestamp; + let mut pending_build: Option>> = None; + + for i in 0..self.count { + let is_last = i == self.count - 1; + + // Get current payload (either from pending build or build now) + let current_payload = if let Some(handle) = pending_build.take() { + handle.await?? + } else { + // First payload - wait for transactions and build synchronously + let transactions = tx_receiver + .recv() + .await + .ok_or_else(|| eyre::eyre!("Transaction fetcher stopped unexpectedly"))?; + + if transactions.is_empty() { + return Err(eyre::eyre!("No transactions collected for payload {}", i + 1)); + } + + info!( + payload = i + 1, + total = self.count, + parent_hash = %parent_hash, + parent_timestamp = parent_timestamp, + tx_count = transactions.len(), + "Building payload via testing_buildBlockV1" + ); + self.build_payload( + testing_provider, + &transactions, + i, + parent_hash, + parent_timestamp, + ) + .await? + }; + + self.save_payload(¤t_payload)?; + + let current_block_hash = current_payload.block_hash; + let current_timestamp = current_payload.timestamp; + + // Execute current payload first + info!(payload = i + 1, block_hash = %current_block_hash, "Executing payload (newPayload + FCU)"); + self.execute_payload_v4(auth_provider, current_payload.envelope, parent_hash).await?; + info!(payload = i + 1, "Payload executed successfully"); + + // Start building next payload in background (if not last) - AFTER execution + if !is_last { + // Get transactions for next payload (should already be fetched or fetching) + let next_transactions = tx_receiver + .recv() + .await + .ok_or_else(|| eyre::eyre!("Transaction fetcher stopped unexpectedly"))?; + + if next_transactions.is_empty() { + return Err(eyre::eyre!("No transactions collected for payload {}", i + 2)); + } + + let testing_provider = testing_provider.clone(); + let next_index = i + 1; + let total = self.count; + + pending_build = Some(tokio::spawn(async move { + info!( + payload = next_index + 1, + total = total, + parent_hash = %current_block_hash, + parent_timestamp = current_timestamp, + tx_count = next_transactions.len(), + "Building payload via testing_buildBlockV1" + ); + + Self::build_payload_static( + &testing_provider, + &next_transactions, + next_index, + current_block_hash, + current_timestamp, + ) + .await + })); + } + + parent_hash = current_block_hash; + parent_timestamp = current_timestamp; + } + + // Clean up the fetcher task + drop(tx_receiver); + let _ = fetcher_handle.await; + + Ok(()) + } + + /// Build a single payload via `testing_buildBlockV1`. + async fn build_payload( + &self, + testing_provider: &RootProvider, + transactions: &[Bytes], + index: u64, + parent_hash: B256, + parent_timestamp: u64, + ) -> eyre::Result { + Self::build_payload_static( + testing_provider, + transactions, + index, + parent_hash, + parent_timestamp, + ) + .await + } + + /// Static version for use in spawned tasks. + async fn build_payload_static( + testing_provider: &RootProvider, + transactions: &[Bytes], + index: u64, + parent_hash: B256, + parent_timestamp: u64, + ) -> eyre::Result { + let request = TestingBuildBlockRequestV1 { + parent_block_hash: parent_hash, + payload_attributes: PayloadAttributes { + timestamp: parent_timestamp + 12, + prev_randao: B256::ZERO, + suggested_fee_recipient: alloy_primitives::Address::ZERO, + withdrawals: Some(vec![]), + parent_beacon_block_root: Some(B256::ZERO), + }, + transactions: transactions.to_vec(), + extra_data: None, + }; + + let total_tx_bytes: usize = transactions.iter().map(|tx| tx.len()).sum(); + info!( + payload = index + 1, + tx_count = transactions.len(), + total_tx_bytes = total_tx_bytes, + parent_hash = %parent_hash, + "Sending to testing_buildBlockV1" + ); + let envelope: ExecutionPayloadEnvelopeV5 = + testing_provider.client().request("testing_buildBlockV1", [request]).await?; + + let v4_envelope = envelope.try_into_v4()?; + + let inner = &v4_envelope.envelope_inner.execution_payload.payload_inner.payload_inner; + let block_hash = inner.block_hash; + let block_number = inner.block_number; + let timestamp = inner.timestamp; + + Ok(BuiltPayload { block_number, envelope: v4_envelope, block_hash, timestamp }) + } + + /// Save a payload to disk. + fn save_payload(&self, payload: &BuiltPayload) -> eyre::Result<()> { + let filename = format!("payload_block_{}.json", payload.block_number); + let filepath = self.output_dir.join(&filename); + let json = serde_json::to_string_pretty(&payload.envelope)?; + std::fs::write(&filepath, &json) + .wrap_err_with(|| format!("Failed to write payload to {:?}", filepath))?; + info!(block_number = payload.block_number, block_hash = %payload.block_hash, path = %filepath.display(), "Payload saved"); + Ok(()) + } + + async fn execute_payload_v4( + &self, + provider: &RootProvider, + envelope: ExecutionPayloadEnvelopeV4, + parent_hash: B256, + ) -> eyre::Result<()> { + let block_hash = + envelope.envelope_inner.execution_payload.payload_inner.payload_inner.block_hash; + + let status = provider + .new_payload_v4( + envelope.envelope_inner.execution_payload, + vec![], + B256::ZERO, + envelope.execution_requests.to_vec(), + ) + .await?; + + if !status.is_valid() { + return Err(eyre::eyre!("Payload rejected: {:?}", status)); + } + + let fcu_state = ForkchoiceState { + head_block_hash: block_hash, + safe_block_hash: parent_hash, + finalized_block_hash: parent_hash, + }; + + let fcu_result = provider.fork_choice_updated_v3(fcu_state, None).await?; + + if !fcu_result.is_valid() { + return Err(eyre::eyre!("FCU rejected: {:?}", fcu_result)); + } + + Ok(()) + } +} diff --git a/bin/reth-bench/src/bench/helpers.rs b/bin/reth-bench/src/bench/helpers.rs new file mode 100644 index 0000000000..f367fd69a1 --- /dev/null +++ b/bin/reth-bench/src/bench/helpers.rs @@ -0,0 +1,196 @@ +//! Common helpers for reth-bench commands. + +use crate::valid_payload::call_forkchoice_updated; +use alloy_consensus::Header; +use alloy_eips::eip4844::kzg_to_versioned_hash; +use alloy_primitives::{Address, B256}; +use alloy_provider::{ext::EngineApi, network::AnyNetwork, RootProvider}; +use alloy_rpc_types_engine::{ + CancunPayloadFields, ExecutionPayload, ExecutionPayloadSidecar, ForkchoiceState, + PayloadAttributes, PayloadId, PraguePayloadFields, +}; +use eyre::OptionExt; +use reth_chainspec::{ChainSpec, EthereumHardforks}; +use reth_node_api::EngineApiMessageVersion; +use tracing::debug; + +/// Prepared payload request data for triggering block building. +pub(crate) struct PayloadRequest { + /// The payload attributes for the new block. + pub(crate) attributes: PayloadAttributes, + /// The forkchoice state pointing to the parent block. + pub(crate) forkchoice_state: ForkchoiceState, + /// The engine API version for FCU calls. + pub(crate) fcu_version: EngineApiMessageVersion, + /// The getPayload version to use (1-5). + pub(crate) get_payload_version: u8, + /// The newPayload version to use. + pub(crate) new_payload_version: EngineApiMessageVersion, +} + +/// Prepare payload attributes and forkchoice state for a new block. +pub(crate) fn prepare_payload_request( + chain_spec: &ChainSpec, + timestamp: u64, + parent_hash: B256, +) -> PayloadRequest { + let shanghai_active = chain_spec.is_shanghai_active_at_timestamp(timestamp); + let cancun_active = chain_spec.is_cancun_active_at_timestamp(timestamp); + let prague_active = chain_spec.is_prague_active_at_timestamp(timestamp); + let osaka_active = chain_spec.is_osaka_active_at_timestamp(timestamp); + + // FCU version: V3 for Cancun+Prague+Osaka, V2 for Shanghai, V1 otherwise + let fcu_version = if cancun_active { + EngineApiMessageVersion::V3 + } else if shanghai_active { + EngineApiMessageVersion::V2 + } else { + EngineApiMessageVersion::V1 + }; + + // getPayload version: 5 for Osaka, 4 for Prague, 3 for Cancun, 2 for Shanghai, 1 otherwise + // newPayload version: 4 for Prague+Osaka (no V5), 3 for Cancun, 2 for Shanghai, 1 otherwise + let (get_payload_version, new_payload_version) = if osaka_active { + (5, EngineApiMessageVersion::V4) // Osaka uses getPayloadV5 but newPayloadV4 + } else if prague_active { + (4, EngineApiMessageVersion::V4) + } else if cancun_active { + (3, EngineApiMessageVersion::V3) + } else if shanghai_active { + (2, EngineApiMessageVersion::V2) + } else { + (1, EngineApiMessageVersion::V1) + }; + + PayloadRequest { + attributes: PayloadAttributes { + timestamp, + prev_randao: B256::ZERO, + suggested_fee_recipient: Address::ZERO, + withdrawals: shanghai_active.then(Vec::new), + parent_beacon_block_root: cancun_active.then_some(B256::ZERO), + }, + forkchoice_state: ForkchoiceState { + head_block_hash: parent_hash, + safe_block_hash: parent_hash, + finalized_block_hash: parent_hash, + }, + fcu_version, + get_payload_version, + new_payload_version, + } +} + +/// Trigger payload building via FCU and retrieve the built payload. +/// +/// This sends a forkchoiceUpdated with payload attributes to start building, +/// then calls getPayload to retrieve the result. +pub(crate) async fn build_payload( + provider: &RootProvider, + request: PayloadRequest, +) -> eyre::Result<(ExecutionPayload, ExecutionPayloadSidecar)> { + let fcu_result = call_forkchoice_updated( + provider, + request.fcu_version, + request.forkchoice_state, + Some(request.attributes.clone()), + ) + .await?; + + let payload_id = + fcu_result.payload_id.ok_or_eyre("Payload builder did not return a payload id")?; + + get_payload_with_sidecar( + provider, + request.get_payload_version, + payload_id, + request.attributes.parent_beacon_block_root, + ) + .await +} + +/// Convert an RPC block to a consensus header and block hash. +pub(crate) fn rpc_block_to_header(block: alloy_provider::network::AnyRpcBlock) -> (Header, B256) { + let block_hash = block.header.hash; + let header = block.header.inner.clone().into_header_with_defaults(); + (header, block_hash) +} + +/// Compute versioned hashes from KZG commitments. +fn versioned_hashes_from_commitments( + commitments: &[alloy_primitives::FixedBytes<48>], +) -> Vec { + commitments.iter().map(|c| kzg_to_versioned_hash(c.as_ref())).collect() +} + +/// Fetch an execution payload using the appropriate engine API version. +pub(crate) async fn get_payload_with_sidecar( + provider: &RootProvider, + version: u8, + payload_id: PayloadId, + parent_beacon_block_root: Option, +) -> eyre::Result<(ExecutionPayload, ExecutionPayloadSidecar)> { + debug!(get_payload_version = ?version, ?payload_id, "Sending getPayload"); + + match version { + 1 => { + let payload = provider.get_payload_v1(payload_id).await?; + Ok((ExecutionPayload::V1(payload), ExecutionPayloadSidecar::none())) + } + 2 => { + let envelope = provider.get_payload_v2(payload_id).await?; + let payload = match envelope.execution_payload { + alloy_rpc_types_engine::ExecutionPayloadFieldV2::V1(p) => ExecutionPayload::V1(p), + alloy_rpc_types_engine::ExecutionPayloadFieldV2::V2(p) => ExecutionPayload::V2(p), + }; + Ok((payload, ExecutionPayloadSidecar::none())) + } + 3 => { + let envelope = provider.get_payload_v3(payload_id).await?; + let versioned_hashes = + versioned_hashes_from_commitments(&envelope.blobs_bundle.commitments); + let cancun_fields = CancunPayloadFields { + parent_beacon_block_root: parent_beacon_block_root + .ok_or_eyre("parent_beacon_block_root required for V3")?, + versioned_hashes, + }; + Ok(( + ExecutionPayload::V3(envelope.execution_payload), + ExecutionPayloadSidecar::v3(cancun_fields), + )) + } + 4 => { + let envelope = provider.get_payload_v4(payload_id).await?; + let versioned_hashes = versioned_hashes_from_commitments( + &envelope.envelope_inner.blobs_bundle.commitments, + ); + let cancun_fields = CancunPayloadFields { + parent_beacon_block_root: parent_beacon_block_root + .ok_or_eyre("parent_beacon_block_root required for V4")?, + versioned_hashes, + }; + let prague_fields = PraguePayloadFields::new(envelope.execution_requests); + Ok(( + ExecutionPayload::V3(envelope.envelope_inner.execution_payload), + ExecutionPayloadSidecar::v4(cancun_fields, prague_fields), + )) + } + 5 => { + // V5 (Osaka) - use raw request since alloy doesn't have get_payload_v5 yet + let envelope = provider.get_payload_v5(payload_id).await?; + let versioned_hashes = + versioned_hashes_from_commitments(&envelope.blobs_bundle.commitments); + let cancun_fields = CancunPayloadFields { + parent_beacon_block_root: parent_beacon_block_root + .ok_or_eyre("parent_beacon_block_root required for V5")?, + versioned_hashes, + }; + let prague_fields = PraguePayloadFields::new(envelope.execution_requests); + Ok(( + ExecutionPayload::V3(envelope.execution_payload), + ExecutionPayloadSidecar::v4(cancun_fields, prague_fields), + )) + } + _ => panic!("This tool does not support getPayload versions past v5"), + } +} diff --git a/bin/reth-bench/src/bench/mod.rs b/bin/reth-bench/src/bench/mod.rs index da3ccb1a8b..fd1d0cccd3 100644 --- a/bin/reth-bench/src/bench/mod.rs +++ b/bin/reth-bench/src/bench/mod.rs @@ -6,9 +6,16 @@ use reth_node_core::args::LogArgs; use reth_tracing::FileWorkerGuard; mod context; +mod gas_limit_ramp; +mod generate_big_block; +pub(crate) mod helpers; +pub use generate_big_block::{ + RawTransaction, RpcTransactionSource, TransactionCollector, TransactionSource, +}; mod new_payload_fcu; mod new_payload_only; mod output; +mod replay_payloads; mod send_payload; /// `reth bench` command @@ -27,6 +34,9 @@ pub enum Subcommands { /// Benchmark which calls `newPayload`, then `forkchoiceUpdated`. NewPayloadFcu(new_payload_fcu::Command), + /// Benchmark which builds empty blocks with a ramped gas limit. + GasLimitRamp(gas_limit_ramp::Command), + /// Benchmark which only calls subsequent `newPayload` calls. NewPayloadOnly(new_payload_only::Command), @@ -41,6 +51,29 @@ pub enum Subcommands { /// `cast block latest --full --json | reth-bench send-payload --rpc-url localhost:5000 /// --jwt-secret $(cat ~/.local/share/reth/mainnet/jwt.hex)` SendPayload(send_payload::Command), + + /// Generate a large block by packing transactions from existing blocks. + /// + /// This command fetches transactions from real blocks and packs them into a single + /// block using the `testing_buildBlockV1` RPC endpoint. + /// + /// Example: + /// + /// `reth-bench generate-big-block --rpc-url http://localhost:8545 --engine-rpc-url + /// http://localhost:8551 --jwt-secret ~/.local/share/reth/mainnet/jwt.hex --target-gas + /// 30000000` + GenerateBigBlock(generate_big_block::Command), + + /// Replay pre-generated payloads from a directory. + /// + /// This command reads payload files from a previous `generate-big-block` run and replays + /// them in sequence using `newPayload` followed by `forkchoiceUpdated`. + /// + /// Example: + /// + /// `reth-bench replay-payloads --payload-dir ./payloads --engine-rpc-url + /// http://localhost:8551 --jwt-secret ~/.local/share/reth/mainnet/jwt.hex` + ReplayPayloads(replay_payloads::Command), } impl BenchmarkCommand { @@ -51,8 +84,11 @@ impl BenchmarkCommand { match self.command { Subcommands::NewPayloadFcu(command) => command.execute(ctx).await, + Subcommands::GasLimitRamp(command) => command.execute(ctx).await, Subcommands::NewPayloadOnly(command) => command.execute(ctx).await, Subcommands::SendPayload(command) => command.execute(ctx).await, + Subcommands::GenerateBigBlock(command) => command.execute(ctx).await, + Subcommands::ReplayPayloads(command) => command.execute(ctx).await, } } diff --git a/bin/reth-bench/src/bench/new_payload_fcu.rs b/bin/reth-bench/src/bench/new_payload_fcu.rs index 5c7f385199..62e0aef259 100644 --- a/bin/reth-bench/src/bench/new_payload_fcu.rs +++ b/bin/reth-bench/src/bench/new_payload_fcu.rs @@ -13,8 +13,7 @@ use crate::{ bench::{ context::BenchContext, output::{ - CombinedResult, NewPayloadResult, TotalGasOutput, TotalGasRow, COMBINED_OUTPUT_SUFFIX, - GAS_OUTPUT_SUFFIX, + write_benchmark_results, CombinedResult, NewPayloadResult, TotalGasOutput, TotalGasRow, }, }, valid_payload::{block_to_new_payload, call_forkchoice_updated, call_new_payload}, @@ -27,7 +26,6 @@ use alloy_rpc_client::RpcClient; use alloy_rpc_types_engine::ForkchoiceState; use alloy_transport_ws::WsConnect; use clap::Parser; -use csv::Writer; use eyre::{Context, OptionExt}; use futures::StreamExt; use humantime::parse_duration; @@ -123,6 +121,7 @@ impl Command { auth_provider, mut next_block, is_optimism, + .. } = BenchContext::new(&self.benchmark, self.rpc_url).await?; let buffer_size = self.rpc_block_buffer_size; @@ -188,6 +187,7 @@ impl Command { result } { let gas_used = block.header.gas_used; + let gas_limit = block.header.gas_limit; let block_number = block.header.number; let transaction_count = block.transactions.len() as u64; @@ -211,6 +211,7 @@ impl Command { let fcu_latency = total_latency - new_payload_result.latency; let combined_result = CombinedResult { block_number, + gas_limit, transaction_count, new_payload_result, fcu_latency, @@ -240,28 +241,11 @@ impl Command { // since the benchmark goal is measuring Ggas/s of newPayload/FCU, not persistence. drop(waiter); - let (gas_output_results, combined_results): (_, Vec) = + let (gas_output_results, combined_results): (Vec, Vec) = results.into_iter().unzip(); - // Write CSV output files if let Some(ref path) = self.benchmark.output { - let output_path = path.join(COMBINED_OUTPUT_SUFFIX); - info!("Writing engine api call latency output to file: {:?}", output_path); - let mut writer = Writer::from_path(&output_path)?; - for result in combined_results { - writer.serialize(result)?; - } - writer.flush()?; - - let output_path = path.join(GAS_OUTPUT_SUFFIX); - info!("Writing total gas output to file: {:?}", output_path); - let mut writer = Writer::from_path(&output_path)?; - for row in &gas_output_results { - writer.serialize(row)?; - } - writer.flush()?; - - info!("Finished writing benchmark output files to {:?}.", path); + write_benchmark_results(path, &gas_output_results, combined_results)?; } let gas_output = TotalGasOutput::new(gas_output_results)?; diff --git a/bin/reth-bench/src/bench/new_payload_only.rs b/bin/reth-bench/src/bench/new_payload_only.rs index 748ac999a9..c642f8b23b 100644 --- a/bin/reth-bench/src/bench/new_payload_only.rs +++ b/bin/reth-bench/src/bench/new_payload_only.rs @@ -49,6 +49,7 @@ impl Command { auth_provider, mut next_block, is_optimism, + .. } = BenchContext::new(&self.benchmark, self.rpc_url).await?; let buffer_size = self.rpc_block_buffer_size; @@ -96,11 +97,7 @@ impl Command { let transaction_count = block.transactions.len() as u64; let gas_used = block.header.gas_used; - debug!( - target: "reth-bench", - number=?block.header.number, - "Sending payload to engine", - ); + debug!(number=?block.header.number, "Sending payload to engine"); let (version, params) = block_to_new_payload(block, is_optimism)?; diff --git a/bin/reth-bench/src/bench/output.rs b/bin/reth-bench/src/bench/output.rs index 17e9ad4a7a..25a1deaf22 100644 --- a/bin/reth-bench/src/bench/output.rs +++ b/bin/reth-bench/src/bench/output.rs @@ -1,10 +1,13 @@ //! Contains various benchmark output formats, either for logging or for //! serialization to / from files. +use alloy_primitives::B256; +use csv::Writer; use eyre::OptionExt; use reth_primitives_traits::constants::GIGAGAS; -use serde::{ser::SerializeStruct, Serialize}; -use std::time::Duration; +use serde::{ser::SerializeStruct, Deserialize, Serialize}; +use std::{path::Path, time::Duration}; +use tracing::info; /// This is the suffix for gas output csv files. pub(crate) const GAS_OUTPUT_SUFFIX: &str = "total_gas.csv"; @@ -15,6 +18,17 @@ pub(crate) const COMBINED_OUTPUT_SUFFIX: &str = "combined_latency.csv"; /// This is the suffix for new payload output csv files. pub(crate) const NEW_PAYLOAD_OUTPUT_SUFFIX: &str = "new_payload_latency.csv"; +/// Serialized format for gas ramp payloads on disk. +#[derive(Debug, Serialize, Deserialize)] +pub(crate) struct GasRampPayloadFile { + /// Engine API version (1-5). + pub(crate) version: u8, + /// The block hash for FCU. + pub(crate) block_hash: B256, + /// The params to pass to newPayload. + pub(crate) params: serde_json::Value, +} + /// This represents the results of a single `newPayload` call in the benchmark, containing the gas /// used and the `newPayload` latency. #[derive(Debug)] @@ -67,6 +81,8 @@ impl Serialize for NewPayloadResult { pub(crate) struct CombinedResult { /// The block number of the block being processed. pub(crate) block_number: u64, + /// The gas limit of the block. + pub(crate) gas_limit: u64, /// The number of transactions in the block. pub(crate) transaction_count: u64, /// The `newPayload` result. @@ -88,7 +104,7 @@ impl std::fmt::Display for CombinedResult { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( f, - "Payload {} processed at {:.4} Ggas/s, used {} total gas. Combined gas per second: {:.4} Ggas/s. fcu latency: {:?}, newPayload latency: {:?}", + "Block {} processed at {:.4} Ggas/s, used {} total gas. Combined: {:.4} Ggas/s. fcu: {:?}, newPayload: {:?}", self.block_number, self.new_payload_result.gas_per_second() / GIGAGAS as f64, self.new_payload_result.gas_used, @@ -110,10 +126,11 @@ impl Serialize for CombinedResult { let fcu_latency = self.fcu_latency.as_micros(); let new_payload_latency = self.new_payload_result.latency.as_micros(); let total_latency = self.total_latency.as_micros(); - let mut state = serializer.serialize_struct("CombinedResult", 6)?; + let mut state = serializer.serialize_struct("CombinedResult", 7)?; // flatten the new payload result because this is meant for CSV writing state.serialize_field("block_number", &self.block_number)?; + state.serialize_field("gas_limit", &self.gas_limit)?; state.serialize_field("transaction_count", &self.transaction_count)?; state.serialize_field("gas_used", &self.new_payload_result.gas_used)?; state.serialize_field("new_payload_latency", &new_payload_latency)?; @@ -167,6 +184,36 @@ impl TotalGasOutput { } } +/// Write benchmark results to CSV files. +/// +/// Writes two files to the output directory: +/// - `combined_latency.csv`: Per-block latency results +/// - `total_gas.csv`: Per-block gas usage over time +pub(crate) fn write_benchmark_results( + output_dir: &Path, + gas_results: &[TotalGasRow], + combined_results: Vec, +) -> eyre::Result<()> { + let output_path = output_dir.join(COMBINED_OUTPUT_SUFFIX); + info!("Writing engine api call latency output to file: {:?}", output_path); + let mut writer = Writer::from_path(&output_path)?; + for result in combined_results { + writer.serialize(result)?; + } + writer.flush()?; + + let output_path = output_dir.join(GAS_OUTPUT_SUFFIX); + info!("Writing total gas output to file: {:?}", output_path); + let mut writer = Writer::from_path(&output_path)?; + for row in gas_results { + writer.serialize(row)?; + } + writer.flush()?; + + info!("Finished writing benchmark output files to {:?}.", output_dir); + Ok(()) +} + /// This serializes the `time` field of the [`TotalGasRow`] to microseconds. /// /// This is essentially just for the csv writer, which would have headers diff --git a/bin/reth-bench/src/bench/replay_payloads.rs b/bin/reth-bench/src/bench/replay_payloads.rs new file mode 100644 index 0000000000..a2595f81f3 --- /dev/null +++ b/bin/reth-bench/src/bench/replay_payloads.rs @@ -0,0 +1,332 @@ +//! Command for replaying pre-generated payloads from disk. +//! +//! This command reads `ExecutionPayloadEnvelopeV4` files from a directory and replays them +//! in sequence using `newPayload` followed by `forkchoiceUpdated`. + +use crate::{ + authenticated_transport::AuthenticatedTransportConnect, + bench::output::GasRampPayloadFile, + valid_payload::{call_forkchoice_updated, call_new_payload}, +}; +use alloy_primitives::B256; +use alloy_provider::{ext::EngineApi, network::AnyNetwork, Provider, RootProvider}; +use alloy_rpc_client::ClientBuilder; +use alloy_rpc_types_engine::{ExecutionPayloadEnvelopeV4, ForkchoiceState, JwtSecret}; +use clap::Parser; +use eyre::Context; +use reqwest::Url; +use reth_cli_runner::CliContext; +use reth_node_api::EngineApiMessageVersion; +use std::path::PathBuf; +use tracing::{debug, info}; + +/// `reth bench replay-payloads` command +/// +/// Replays pre-generated payloads from a directory by calling `newPayload` followed by +/// `forkchoiceUpdated` for each payload in sequence. +#[derive(Debug, Parser)] +pub struct Command { + /// The engine RPC URL (with JWT authentication). + #[arg(long, value_name = "ENGINE_RPC_URL", default_value = "http://localhost:8551")] + engine_rpc_url: String, + + /// Path to the JWT secret file for engine API authentication. + #[arg(long, value_name = "JWT_SECRET")] + jwt_secret: PathBuf, + + /// Directory containing payload files (`payload_block_N.json`). + #[arg(long, value_name = "PAYLOAD_DIR")] + payload_dir: PathBuf, + + /// Optional limit on the number of payloads to replay. + /// If not specified, replays all payloads in the directory. + #[arg(long, value_name = "COUNT")] + count: Option, + + /// Skip the first N payloads. + #[arg(long, value_name = "SKIP", default_value = "0")] + skip: usize, + + /// Optional directory containing gas ramp payloads to replay first. + /// These are replayed before the main payloads to warm up the gas limit. + #[arg(long, value_name = "GAS_RAMP_DIR")] + gas_ramp_dir: Option, +} + +/// A loaded payload ready for execution. +struct LoadedPayload { + /// The index (from filename). + index: u64, + /// The payload envelope. + envelope: ExecutionPayloadEnvelopeV4, + /// The block hash. + block_hash: B256, +} + +/// A gas ramp payload loaded from disk. +struct GasRampPayload { + /// Block number from filename. + block_number: u64, + /// Engine API version for newPayload. + version: EngineApiMessageVersion, + /// The file contents. + file: GasRampPayloadFile, +} + +impl Command { + /// Execute the `replay-payloads` command. + pub async fn execute(self, _ctx: CliContext) -> eyre::Result<()> { + info!(payload_dir = %self.payload_dir.display(), "Replaying payloads"); + + // Set up authenticated engine provider + let jwt = + std::fs::read_to_string(&self.jwt_secret).wrap_err("Failed to read JWT secret file")?; + let jwt = JwtSecret::from_hex(jwt.trim())?; + let auth_url = Url::parse(&self.engine_rpc_url)?; + + info!("Connecting to Engine RPC at {}", auth_url); + let auth_transport = AuthenticatedTransportConnect::new(auth_url.clone(), jwt); + let auth_client = ClientBuilder::default().connect_with(auth_transport).await?; + let auth_provider = RootProvider::::new(auth_client); + + // Get parent block (latest canonical block) - we need this for the first FCU + let parent_block = auth_provider + .get_block_by_number(alloy_eips::BlockNumberOrTag::Latest) + .await? + .ok_or_else(|| eyre::eyre!("Failed to fetch latest block"))?; + + let initial_parent_hash = parent_block.header.hash; + let initial_parent_number = parent_block.header.number; + + info!( + parent_hash = %initial_parent_hash, + parent_number = initial_parent_number, + "Using initial parent block" + ); + + // Load all payloads upfront to avoid I/O delays between phases + let gas_ramp_payloads = if let Some(ref gas_ramp_dir) = self.gas_ramp_dir { + let payloads = self.load_gas_ramp_payloads(gas_ramp_dir)?; + if payloads.is_empty() { + return Err(eyre::eyre!("No gas ramp payload files found in {:?}", gas_ramp_dir)); + } + info!(count = payloads.len(), "Loaded gas ramp payloads from disk"); + payloads + } else { + Vec::new() + }; + + let payloads = self.load_payloads()?; + if payloads.is_empty() { + return Err(eyre::eyre!("No payload files found in {:?}", self.payload_dir)); + } + info!(count = payloads.len(), "Loaded main payloads from disk"); + + let mut parent_hash = initial_parent_hash; + + // Replay gas ramp payloads first + for (i, payload) in gas_ramp_payloads.iter().enumerate() { + info!( + gas_ramp_payload = i + 1, + total = gas_ramp_payloads.len(), + block_number = payload.block_number, + block_hash = %payload.file.block_hash, + "Executing gas ramp payload (newPayload + FCU)" + ); + + call_new_payload(&auth_provider, payload.version, payload.file.params.clone()).await?; + + let fcu_state = ForkchoiceState { + head_block_hash: payload.file.block_hash, + safe_block_hash: parent_hash, + finalized_block_hash: parent_hash, + }; + call_forkchoice_updated(&auth_provider, payload.version, fcu_state, None).await?; + + info!(gas_ramp_payload = i + 1, "Gas ramp payload executed successfully"); + parent_hash = payload.file.block_hash; + } + + if !gas_ramp_payloads.is_empty() { + info!(count = gas_ramp_payloads.len(), "All gas ramp payloads replayed"); + } + + for (i, payload) in payloads.iter().enumerate() { + info!( + payload = i + 1, + total = payloads.len(), + index = payload.index, + block_hash = %payload.block_hash, + "Executing payload (newPayload + FCU)" + ); + + self.execute_payload_v4(&auth_provider, &payload.envelope, parent_hash).await?; + + info!(payload = i + 1, "Payload executed successfully"); + parent_hash = payload.block_hash; + } + + info!(count = payloads.len(), "All payloads replayed successfully"); + Ok(()) + } + + /// Load and parse all payload files from the directory. + fn load_payloads(&self) -> eyre::Result> { + let mut payloads = Vec::new(); + + // Read directory entries + let entries: Vec<_> = std::fs::read_dir(&self.payload_dir) + .wrap_err_with(|| format!("Failed to read directory {:?}", self.payload_dir))? + .filter_map(|e| e.ok()) + .filter(|e| { + e.path().extension().and_then(|s| s.to_str()) == Some("json") && + e.file_name().to_string_lossy().starts_with("payload_") + }) + .collect(); + + // Parse filenames to get indices and sort + let mut indexed_paths: Vec<(u64, PathBuf)> = entries + .into_iter() + .filter_map(|e| { + let name = e.file_name(); + let name_str = name.to_string_lossy(); + // Extract index from "payload_NNN.json" + let index_str = name_str.strip_prefix("payload_")?.strip_suffix(".json")?; + let index: u64 = index_str.parse().ok()?; + Some((index, e.path())) + }) + .collect(); + + indexed_paths.sort_by_key(|(idx, _)| *idx); + + // Apply skip and count + let indexed_paths: Vec<_> = indexed_paths.into_iter().skip(self.skip).collect(); + let indexed_paths: Vec<_> = match self.count { + Some(count) => indexed_paths.into_iter().take(count).collect(), + None => indexed_paths, + }; + + // Load each payload + for (index, path) in indexed_paths { + let content = std::fs::read_to_string(&path) + .wrap_err_with(|| format!("Failed to read {:?}", path))?; + let envelope: ExecutionPayloadEnvelopeV4 = serde_json::from_str(&content) + .wrap_err_with(|| format!("Failed to parse {:?}", path))?; + + let block_hash = + envelope.envelope_inner.execution_payload.payload_inner.payload_inner.block_hash; + + info!( + index = index, + block_hash = %block_hash, + path = %path.display(), + "Loaded payload" + ); + + payloads.push(LoadedPayload { index, envelope, block_hash }); + } + + Ok(payloads) + } + + /// Load and parse gas ramp payload files from a directory. + fn load_gas_ramp_payloads(&self, dir: &PathBuf) -> eyre::Result> { + let mut payloads = Vec::new(); + + let entries: Vec<_> = std::fs::read_dir(dir) + .wrap_err_with(|| format!("Failed to read directory {:?}", dir))? + .filter_map(|e| e.ok()) + .filter(|e| { + e.path().extension().and_then(|s| s.to_str()) == Some("json") && + e.file_name().to_string_lossy().starts_with("payload_block_") + }) + .collect(); + + // Parse filenames to get block numbers and sort + let mut indexed_paths: Vec<(u64, PathBuf)> = entries + .into_iter() + .filter_map(|e| { + let name = e.file_name(); + let name_str = name.to_string_lossy(); + // Extract block number from "payload_block_NNN.json" + let block_str = name_str.strip_prefix("payload_block_")?.strip_suffix(".json")?; + let block_number: u64 = block_str.parse().ok()?; + Some((block_number, e.path())) + }) + .collect(); + + indexed_paths.sort_by_key(|(num, _)| *num); + + for (block_number, path) in indexed_paths { + let content = std::fs::read_to_string(&path) + .wrap_err_with(|| format!("Failed to read {:?}", path))?; + let file: GasRampPayloadFile = serde_json::from_str(&content) + .wrap_err_with(|| format!("Failed to parse {:?}", path))?; + + let version = match file.version { + 1 => EngineApiMessageVersion::V1, + 2 => EngineApiMessageVersion::V2, + 3 => EngineApiMessageVersion::V3, + 4 => EngineApiMessageVersion::V4, + 5 => EngineApiMessageVersion::V5, + v => return Err(eyre::eyre!("Invalid version {} in {:?}", v, path)), + }; + + info!( + block_number, + block_hash = %file.block_hash, + path = %path.display(), + "Loaded gas ramp payload" + ); + + payloads.push(GasRampPayload { block_number, version, file }); + } + + Ok(payloads) + } + + async fn execute_payload_v4( + &self, + provider: &RootProvider, + envelope: &ExecutionPayloadEnvelopeV4, + parent_hash: B256, + ) -> eyre::Result<()> { + let block_hash = + envelope.envelope_inner.execution_payload.payload_inner.payload_inner.block_hash; + + debug!( + method = "engine_newPayloadV4", + block_hash = %block_hash, + "Sending newPayload" + ); + + let status = provider + .new_payload_v4( + envelope.envelope_inner.execution_payload.clone(), + vec![], + B256::ZERO, + envelope.execution_requests.to_vec(), + ) + .await?; + + info!(?status, "newPayloadV4 response"); + + if !status.is_valid() { + return Err(eyre::eyre!("Payload rejected: {:?}", status)); + } + + let fcu_state = ForkchoiceState { + head_block_hash: block_hash, + safe_block_hash: parent_hash, + finalized_block_hash: parent_hash, + }; + + debug!(method = "engine_forkchoiceUpdatedV3", ?fcu_state, "Sending forkchoiceUpdated"); + + let fcu_result = provider.fork_choice_updated_v3(fcu_state, None).await?; + + info!(?fcu_result, "forkchoiceUpdatedV3 response"); + + Ok(()) + } +} diff --git a/bin/reth-bench/src/valid_payload.rs b/bin/reth-bench/src/valid_payload.rs index d253506b22..76d562f7f4 100644 --- a/bin/reth-bench/src/valid_payload.rs +++ b/bin/reth-bench/src/valid_payload.rs @@ -3,15 +3,16 @@ //! before sending additional calls. use alloy_eips::eip7685::Requests; +use alloy_primitives::B256; use alloy_provider::{ext::EngineApi, network::AnyRpcBlock, Network, Provider}; use alloy_rpc_types_engine::{ - ExecutionPayload, ExecutionPayloadInputV2, ForkchoiceState, ForkchoiceUpdated, - PayloadAttributes, PayloadStatus, + ExecutionPayload, ExecutionPayloadInputV2, ExecutionPayloadSidecar, ForkchoiceState, + ForkchoiceUpdated, PayloadAttributes, PayloadStatus, }; use alloy_transport::TransportResult; use op_alloy_rpc_types_engine::OpExecutionPayloadV4; use reth_node_api::EngineApiMessageVersion; -use tracing::error; +use tracing::{debug, error}; /// An extension trait for providers that implement the engine API, to wait for a VALID response. #[async_trait::async_trait] @@ -52,6 +53,13 @@ where fork_choice_state: ForkchoiceState, payload_attributes: Option, ) -> TransportResult { + debug!( + method = "engine_forkchoiceUpdatedV1", + ?fork_choice_state, + ?payload_attributes, + "Sending forkchoiceUpdated" + ); + let mut status = self.fork_choice_updated_v1(fork_choice_state, payload_attributes.clone()).await?; @@ -82,6 +90,13 @@ where fork_choice_state: ForkchoiceState, payload_attributes: Option, ) -> TransportResult { + debug!( + method = "engine_forkchoiceUpdatedV2", + ?fork_choice_state, + ?payload_attributes, + "Sending forkchoiceUpdated" + ); + let mut status = self.fork_choice_updated_v2(fork_choice_state, payload_attributes.clone()).await?; @@ -112,6 +127,13 @@ where fork_choice_state: ForkchoiceState, payload_attributes: Option, ) -> TransportResult { + debug!( + method = "engine_forkchoiceUpdatedV3", + ?fork_choice_state, + ?payload_attributes, + "Sending forkchoiceUpdated" + ); + let mut status = self.fork_choice_updated_v3(fork_choice_state, payload_attributes.clone()).await?; @@ -148,33 +170,51 @@ pub(crate) fn block_to_new_payload( // Convert to execution payload let (payload, sidecar) = ExecutionPayload::from_block_slow(&block); + payload_to_new_payload(payload, sidecar, is_optimism, block.withdrawals_root, None) +} +pub(crate) fn payload_to_new_payload( + payload: ExecutionPayload, + sidecar: ExecutionPayloadSidecar, + is_optimism: bool, + withdrawals_root: Option, + target_version: Option, +) -> eyre::Result<(EngineApiMessageVersion, serde_json::Value)> { let (version, params) = match payload { ExecutionPayload::V3(payload) => { let cancun = sidecar.cancun().unwrap(); if let Some(prague) = sidecar.prague() { + // Use target version if provided (for Osaka), otherwise default to V4 + let version = target_version.unwrap_or(EngineApiMessageVersion::V4); + if is_optimism { + let withdrawals_root = withdrawals_root.ok_or_else(|| { + eyre::eyre!("Missing withdrawals root for Optimism payload") + })?; ( - EngineApiMessageVersion::V4, + version, serde_json::to_value(( - OpExecutionPayloadV4 { - payload_inner: payload, - withdrawals_root: block.withdrawals_root.unwrap(), - }, + OpExecutionPayloadV4 { payload_inner: payload, withdrawals_root }, cancun.versioned_hashes.clone(), cancun.parent_beacon_block_root, Requests::default(), ))?, ) } else { + // Extract actual Requests from RequestsOrHash + let requests = prague + .requests + .requests() + .cloned() + .ok_or_else(|| eyre::eyre!("Prague sidecar has hash, not requests"))?; ( - EngineApiMessageVersion::V4, + version, serde_json::to_value(( payload, cancun.versioned_hashes.clone(), cancun.parent_beacon_block_root, - prague.requests.requests_hash(), + requests, ))?, ) } @@ -217,6 +257,8 @@ pub(crate) async fn call_new_payload>( ) -> TransportResult<()> { let method = version.method_name(); + debug!(method, "Sending newPayload"); + let mut status: PayloadStatus = provider.client().request(method, ¶ms).await?; while !status.is_valid() { @@ -237,12 +279,15 @@ pub(crate) async fn call_new_payload>( /// Calls the correct `engine_forkchoiceUpdated` method depending on the given /// `EngineApiMessageVersion`, using the provided forkchoice state and payload attributes for the /// actual engine api message call. +/// +/// Note: For Prague (V4), we still use forkchoiceUpdatedV3 as there is no V4. pub(crate) async fn call_forkchoice_updated>( provider: P, message_version: EngineApiMessageVersion, forkchoice_state: ForkchoiceState, payload_attributes: Option, ) -> TransportResult { + // FCU V3 is used for both Cancun and Prague (there is no FCU V4) match message_version { EngineApiMessageVersion::V3 | EngineApiMessageVersion::V4 | EngineApiMessageVersion::V5 => { provider.fork_choice_updated_v3_wait(forkchoice_state, payload_attributes).await diff --git a/crates/chainspec/src/spec.rs b/crates/chainspec/src/spec.rs index 65144a9571..5927c262c9 100644 --- a/crates/chainspec/src/spec.rs +++ b/crates/chainspec/src/spec.rs @@ -460,6 +460,18 @@ impl ChainSpec { pub fn builder() -> ChainSpecBuilder { ChainSpecBuilder::default() } + + /// Map a chain ID to a known chain spec, if available. + pub fn from_chain_id(chain_id: u64) -> Option> { + match NamedChain::try_from(chain_id).ok()? { + NamedChain::Mainnet => Some(MAINNET.clone()), + NamedChain::Sepolia => Some(SEPOLIA.clone()), + NamedChain::Holesky => Some(HOLESKY.clone()), + NamedChain::Hoodi => Some(HOODI.clone()), + NamedChain::Dev => Some(DEV.clone()), + _ => None, + } + } } impl ChainSpec { diff --git a/crates/ethereum/payload/Cargo.toml b/crates/ethereum/payload/Cargo.toml index 4326d9b193..afdb88e6bb 100644 --- a/crates/ethereum/payload/Cargo.toml +++ b/crates/ethereum/payload/Cargo.toml @@ -31,8 +31,8 @@ reth-payload-validator.workspace = true # ethereum alloy-rlp.workspace = true -revm.workspace = true alloy-rpc-types-engine.workspace = true +revm.workspace = true # alloy alloy-eips.workspace = true diff --git a/crates/rpc/rpc-api/Cargo.toml b/crates/rpc/rpc-api/Cargo.toml index 786ea15ab0..9287c17465 100644 --- a/crates/rpc/rpc-api/Cargo.toml +++ b/crates/rpc/rpc-api/Cargo.toml @@ -36,7 +36,6 @@ alloy-serde.workspace = true alloy-rpc-types-beacon.workspace = true alloy-rpc-types-engine.workspace = true alloy-genesis.workspace = true -serde = { workspace = true, features = ["derive"] } # misc jsonrpsee = { workspace = true, features = ["server", "macros"] } diff --git a/crates/rpc/rpc-api/src/testing.rs b/crates/rpc/rpc-api/src/testing.rs index f49380058e..e7dbeb853d 100644 --- a/crates/rpc/rpc-api/src/testing.rs +++ b/crates/rpc/rpc-api/src/testing.rs @@ -5,32 +5,24 @@ //! disabled by default and never be exposed on public-facing RPC without an //! explicit operator flag. -use alloy_primitives::{Bytes, B256}; -use alloy_rpc_types_engine::{ - ExecutionPayloadEnvelopeV5, PayloadAttributes as EthPayloadAttributes, -}; +use alloy_rpc_types_engine::ExecutionPayloadEnvelopeV5; use jsonrpsee::proc_macros::rpc; -use serde::{Deserialize, Serialize}; -/// Capability string for `testing_buildBlockV1`. -pub const TESTING_BUILD_BLOCK_V1: &str = "testing_buildBlockV1"; - -/// Request payload for `testing_buildBlockV1`. -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct TestingBuildBlockRequestV1 { - /// Parent block hash of the block to build. - pub parent_block_hash: B256, - /// Payload attributes (Cancun version). - pub payload_attributes: EthPayloadAttributes, - /// Raw signed transactions to force-include in order. - pub transactions: Vec, - /// Optional extra data for the block header. - #[serde(default, skip_serializing_if = "Option::is_none")] - pub extra_data: Option, -} +pub use alloy_rpc_types_engine::{TestingBuildBlockRequestV1, TESTING_BUILD_BLOCK_V1}; /// Testing RPC interface for building a block in a single call. +/// +/// # Enabling +/// +/// This namespace is disabled by default for security reasons. To enable it, +/// add `testing` to the `--http.api` flag: +/// +/// ```sh +/// reth node --http --http.api eth,testing +/// ``` +/// +/// **Warning:** Never expose this on public-facing RPC endpoints without proper +/// authentication. #[cfg_attr(not(feature = "client"), rpc(server, namespace = "testing"))] #[cfg_attr(feature = "client", rpc(server, client, namespace = "testing"))] pub trait TestingApi { diff --git a/crates/rpc/rpc/src/testing.rs b/crates/rpc/rpc/src/testing.rs index c1c8a65d1c..dfaea2bb54 100644 --- a/crates/rpc/rpc/src/testing.rs +++ b/crates/rpc/rpc/src/testing.rs @@ -1,6 +1,18 @@ //! Implementation of the `testing` namespace. //! //! This exposes `testing_buildBlockV1`, intended for non-production/debug use. +//! +//! # Enabling the testing namespace +//! +//! The `testing_` namespace is disabled by default for security reasons. +//! To enable it, add `testing` to the `--http.api` flag when starting the node: +//! +//! ```sh +//! reth node --http --http.api eth,testing +//! ``` +//! +//! **Warning:** This namespace allows building arbitrary blocks. Never expose it +//! on public-facing RPC endpoints without proper authentication. use alloy_consensus::{Header, Transaction}; use alloy_evm::Evm; @@ -94,8 +106,8 @@ where let mut invalid_senders: HashSet = HashSet::default(); - for tx in request.transactions { - let tx: Recovered> = recover_raw_transaction(&tx)?; + for (idx, tx) in request.transactions.iter().enumerate() { + let tx: Recovered> = recover_raw_transaction(tx)?; let sender = tx.signer(); if skip_invalid_transactions && invalid_senders.contains(&sender) { @@ -109,6 +121,7 @@ where if skip_invalid_transactions { debug!( target: "rpc::testing", + tx_idx = idx, ?sender, error = ?err, "Skipping invalid transaction" @@ -116,6 +129,13 @@ where invalid_senders.insert(sender); continue; } + debug!( + target: "rpc::testing", + tx_idx = idx, + ?sender, + error = ?err, + "Transaction execution failed" + ); return Err(Eth::Error::from_eth_err(err)); } };