diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 7011b9555b..ffcb7f239a 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -72,7 +72,7 @@ jobs: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@master with: - toolchain: "1.76" # MSRV + toolchain: "1.79" # MSRV - uses: Swatinem/rust-cache@v2 with: cache-on-failure: true @@ -115,7 +115,7 @@ jobs: - uses: actions/checkout@v4 - uses: dtolnay/rust-toolchain@master with: - toolchain: "1.76" # MSRV + toolchain: "1.79" # MSRV - uses: Swatinem/rust-cache@v2 with: cache-on-failure: true diff --git a/Cargo.lock b/Cargo.lock index 872ef28264..90c14bb415 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -109,9 +109,9 @@ checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" [[package]] name = "alloy-chains" -version = "0.1.19" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24ceb48af11349cd7fbd12aa739800be3c4b3965f640b7ae26666907f3bdf091" +checksum = "d2feb5f466b3a786d5a622d8926418bc6a0d38bf632909f6ee9298a4a1d8c6e0" dependencies = [ "alloy-rlp", "arbitrary", @@ -124,12 +124,12 @@ dependencies = [ [[package]] name = "alloy-consensus" version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy?rev=14ed25d#14ed25d8ab485fc0d313fd1e055862c9d20ef273" +source = "git+https://github.com/alloy-rs/alloy?rev=00d81d7#00d81d7882a0bee4720d6d6a1db4c8f164ebb9d0" dependencies = [ - "alloy-eips 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", + "alloy-eips 0.1.0", "alloy-primitives", "alloy-rlp", - "alloy-serde 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", + "alloy-serde 0.1.0", "arbitrary", "c-kzg", "proptest", @@ -139,13 +139,13 @@ dependencies = [ [[package]] name = "alloy-consensus" -version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy#b000e16f06161c15b42a4c59f27cb3feb23b3c14" +version = "0.1.1" +source = "git+https://github.com/alloy-rs/alloy#30317d9262be3aa93c4fd31ec3ea819b962c2448" dependencies = [ - "alloy-eips 0.1.0 (git+https://github.com/alloy-rs/alloy)", + "alloy-eips 0.1.1", "alloy-primitives", "alloy-rlp", - "alloy-serde 0.1.0 (git+https://github.com/alloy-rs/alloy)", + "alloy-serde 0.1.1", "c-kzg", "serde", ] @@ -171,11 +171,11 @@ dependencies = [ [[package]] name = "alloy-eips" version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy?rev=14ed25d#14ed25d8ab485fc0d313fd1e055862c9d20ef273" +source = "git+https://github.com/alloy-rs/alloy?rev=00d81d7#00d81d7882a0bee4720d6d6a1db4c8f164ebb9d0" dependencies = [ "alloy-primitives", "alloy-rlp", - "alloy-serde 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", + "alloy-serde 0.1.0", "arbitrary", "c-kzg", "derive_more", @@ -188,12 +188,12 @@ dependencies = [ [[package]] name = "alloy-eips" -version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy#b000e16f06161c15b42a4c59f27cb3feb23b3c14" +version = "0.1.1" +source = "git+https://github.com/alloy-rs/alloy#30317d9262be3aa93c4fd31ec3ea819b962c2448" dependencies = [ "alloy-primitives", "alloy-rlp", - "alloy-serde 0.1.0 (git+https://github.com/alloy-rs/alloy)", + "alloy-serde 0.1.1", "c-kzg", "once_cell", "serde", @@ -203,21 +203,10 @@ dependencies = [ [[package]] name = "alloy-genesis" version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy?rev=14ed25d#14ed25d8ab485fc0d313fd1e055862c9d20ef273" +source = "git+https://github.com/alloy-rs/alloy?rev=00d81d7#00d81d7882a0bee4720d6d6a1db4c8f164ebb9d0" dependencies = [ "alloy-primitives", - "alloy-serde 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", - "serde", - "serde_json", -] - -[[package]] -name = "alloy-genesis" -version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy#b000e16f06161c15b42a4c59f27cb3feb23b3c14" -dependencies = [ - "alloy-primitives", - "alloy-serde 0.1.0 (git+https://github.com/alloy-rs/alloy)", + "alloy-serde 0.1.0", "serde", "serde_json", ] @@ -237,7 +226,7 @@ dependencies = [ [[package]] name = "alloy-json-rpc" version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy?rev=14ed25d#14ed25d8ab485fc0d313fd1e055862c9d20ef273" +source = "git+https://github.com/alloy-rs/alloy?rev=00d81d7#00d81d7882a0bee4720d6d6a1db4c8f164ebb9d0" dependencies = [ "alloy-primitives", "serde", @@ -249,13 +238,13 @@ dependencies = [ [[package]] name = "alloy-network" version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy?rev=14ed25d#14ed25d8ab485fc0d313fd1e055862c9d20ef273" +source = "git+https://github.com/alloy-rs/alloy?rev=00d81d7#00d81d7882a0bee4720d6d6a1db4c8f164ebb9d0" dependencies = [ - "alloy-consensus 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", - "alloy-eips 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", + "alloy-consensus 0.1.0", + "alloy-eips 0.1.0", "alloy-json-rpc", "alloy-primitives", - "alloy-rpc-types-eth 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", + "alloy-rpc-types-eth 0.1.0", "alloy-signer", "alloy-sol-types", "async-trait", @@ -267,9 +256,9 @@ dependencies = [ [[package]] name = "alloy-node-bindings" version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy?rev=14ed25d#14ed25d8ab485fc0d313fd1e055862c9d20ef273" +source = "git+https://github.com/alloy-rs/alloy?rev=00d81d7#00d81d7882a0bee4720d6d6a1db4c8f164ebb9d0" dependencies = [ - "alloy-genesis 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", + "alloy-genesis", "alloy-primitives", "k256", "serde_json", @@ -309,18 +298,18 @@ dependencies = [ [[package]] name = "alloy-provider" version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy?rev=14ed25d#14ed25d8ab485fc0d313fd1e055862c9d20ef273" +source = "git+https://github.com/alloy-rs/alloy?rev=00d81d7#00d81d7882a0bee4720d6d6a1db4c8f164ebb9d0" dependencies = [ "alloy-chains", - "alloy-consensus 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", - "alloy-eips 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", + "alloy-consensus 0.1.0", + "alloy-eips 0.1.0", "alloy-json-rpc", "alloy-network", "alloy-primitives", "alloy-pubsub", "alloy-rpc-client", "alloy-rpc-types-engine", - "alloy-rpc-types-eth 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", + "alloy-rpc-types-eth 0.1.0", "alloy-rpc-types-trace", "alloy-transport", "alloy-transport-http", @@ -344,7 +333,7 @@ dependencies = [ [[package]] name = "alloy-pubsub" version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy?rev=14ed25d#14ed25d8ab485fc0d313fd1e055862c9d20ef273" +source = "git+https://github.com/alloy-rs/alloy?rev=00d81d7#00d81d7882a0bee4720d6d6a1db4c8f164ebb9d0" dependencies = [ "alloy-json-rpc", "alloy-primitives", @@ -384,7 +373,7 @@ dependencies = [ [[package]] name = "alloy-rpc-client" version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy?rev=14ed25d#14ed25d8ab485fc0d313fd1e055862c9d20ef273" +source = "git+https://github.com/alloy-rs/alloy?rev=00d81d7#00d81d7882a0bee4720d6d6a1db4c8f164ebb9d0" dependencies = [ "alloy-json-rpc", "alloy-primitives", @@ -407,38 +396,39 @@ dependencies = [ [[package]] name = "alloy-rpc-types" version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy?rev=14ed25d#14ed25d8ab485fc0d313fd1e055862c9d20ef273" +source = "git+https://github.com/alloy-rs/alloy?rev=00d81d7#00d81d7882a0bee4720d6d6a1db4c8f164ebb9d0" dependencies = [ "alloy-rpc-types-engine", - "alloy-rpc-types-eth 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", - "alloy-serde 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", + "alloy-rpc-types-eth 0.1.0", + "alloy-rpc-types-trace", + "alloy-serde 0.1.0", ] [[package]] name = "alloy-rpc-types" -version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy#b000e16f06161c15b42a4c59f27cb3feb23b3c14" +version = "0.1.1" +source = "git+https://github.com/alloy-rs/alloy#30317d9262be3aa93c4fd31ec3ea819b962c2448" dependencies = [ - "alloy-rpc-types-eth 0.1.0 (git+https://github.com/alloy-rs/alloy)", - "alloy-serde 0.1.0 (git+https://github.com/alloy-rs/alloy)", + "alloy-rpc-types-eth 0.1.1", + "alloy-serde 0.1.1", ] [[package]] name = "alloy-rpc-types-anvil" version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy?rev=14ed25d#14ed25d8ab485fc0d313fd1e055862c9d20ef273" +source = "git+https://github.com/alloy-rs/alloy?rev=00d81d7#00d81d7882a0bee4720d6d6a1db4c8f164ebb9d0" dependencies = [ "alloy-primitives", - "alloy-serde 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", + "alloy-serde 0.1.0", "serde", ] [[package]] name = "alloy-rpc-types-beacon" version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy?rev=14ed25d#14ed25d8ab485fc0d313fd1e055862c9d20ef273" +source = "git+https://github.com/alloy-rs/alloy?rev=00d81d7#00d81d7882a0bee4720d6d6a1db4c8f164ebb9d0" dependencies = [ - "alloy-eips 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", + "alloy-eips 0.1.0", "alloy-primitives", "alloy-rpc-types-engine", "serde", @@ -449,16 +439,16 @@ dependencies = [ [[package]] name = "alloy-rpc-types-engine" version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy?rev=14ed25d#14ed25d8ab485fc0d313fd1e055862c9d20ef273" +source = "git+https://github.com/alloy-rs/alloy?rev=00d81d7#00d81d7882a0bee4720d6d6a1db4c8f164ebb9d0" dependencies = [ - "alloy-consensus 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", - "alloy-eips 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", + "alloy-consensus 0.1.0", + "alloy-eips 0.1.0", "alloy-primitives", "alloy-rlp", - "alloy-rpc-types-eth 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", - "alloy-serde 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", + "alloy-rpc-types-eth 0.1.0", + "alloy-serde 0.1.0", "jsonrpsee-types", - "jsonwebtoken 9.3.0", + "jsonwebtoken", "rand 0.8.5", "serde", "thiserror", @@ -467,14 +457,14 @@ dependencies = [ [[package]] name = "alloy-rpc-types-eth" version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy?rev=14ed25d#14ed25d8ab485fc0d313fd1e055862c9d20ef273" +source = "git+https://github.com/alloy-rs/alloy?rev=00d81d7#00d81d7882a0bee4720d6d6a1db4c8f164ebb9d0" dependencies = [ - "alloy-consensus 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", - "alloy-eips 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", - "alloy-genesis 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", + "alloy-consensus 0.1.0", + "alloy-eips 0.1.0", + "alloy-genesis", "alloy-primitives", "alloy-rlp", - "alloy-serde 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", + "alloy-serde 0.1.0", "alloy-sol-types", "arbitrary", "itertools 0.13.0", @@ -488,15 +478,14 @@ dependencies = [ [[package]] name = "alloy-rpc-types-eth" -version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy#b000e16f06161c15b42a4c59f27cb3feb23b3c14" +version = "0.1.1" +source = "git+https://github.com/alloy-rs/alloy#30317d9262be3aa93c4fd31ec3ea819b962c2448" dependencies = [ - "alloy-consensus 0.1.0 (git+https://github.com/alloy-rs/alloy)", - "alloy-eips 0.1.0 (git+https://github.com/alloy-rs/alloy)", - "alloy-genesis 0.1.0 (git+https://github.com/alloy-rs/alloy)", + "alloy-consensus 0.1.1", + "alloy-eips 0.1.1", "alloy-primitives", "alloy-rlp", - "alloy-serde 0.1.0 (git+https://github.com/alloy-rs/alloy)", + "alloy-serde 0.1.1", "alloy-sol-types", "itertools 0.13.0", "serde", @@ -507,11 +496,11 @@ dependencies = [ [[package]] name = "alloy-rpc-types-trace" version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy?rev=14ed25d#14ed25d8ab485fc0d313fd1e055862c9d20ef273" +source = "git+https://github.com/alloy-rs/alloy?rev=00d81d7#00d81d7882a0bee4720d6d6a1db4c8f164ebb9d0" dependencies = [ "alloy-primitives", - "alloy-rpc-types-eth 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", - "alloy-serde 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", + "alloy-rpc-types-eth 0.1.0", + "alloy-serde 0.1.0", "serde", "serde_json", ] @@ -519,7 +508,7 @@ dependencies = [ [[package]] name = "alloy-serde" version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy?rev=14ed25d#14ed25d8ab485fc0d313fd1e055862c9d20ef273" +source = "git+https://github.com/alloy-rs/alloy?rev=00d81d7#00d81d7882a0bee4720d6d6a1db4c8f164ebb9d0" dependencies = [ "alloy-primitives", "serde", @@ -528,8 +517,8 @@ dependencies = [ [[package]] name = "alloy-serde" -version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy#b000e16f06161c15b42a4c59f27cb3feb23b3c14" +version = "0.1.1" +source = "git+https://github.com/alloy-rs/alloy#30317d9262be3aa93c4fd31ec3ea819b962c2448" dependencies = [ "alloy-primitives", "serde", @@ -539,7 +528,7 @@ dependencies = [ [[package]] name = "alloy-signer" version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy?rev=14ed25d#14ed25d8ab485fc0d313fd1e055862c9d20ef273" +source = "git+https://github.com/alloy-rs/alloy?rev=00d81d7#00d81d7882a0bee4720d6d6a1db4c8f164ebb9d0" dependencies = [ "alloy-primitives", "async-trait", @@ -552,9 +541,9 @@ dependencies = [ [[package]] name = "alloy-signer-wallet" version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy?rev=14ed25d#14ed25d8ab485fc0d313fd1e055862c9d20ef273" +source = "git+https://github.com/alloy-rs/alloy?rev=00d81d7#00d81d7882a0bee4720d6d6a1db4c8f164ebb9d0" dependencies = [ - "alloy-consensus 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", + "alloy-consensus 0.1.0", "alloy-network", "alloy-primitives", "alloy-signer", @@ -641,7 +630,7 @@ dependencies = [ [[package]] name = "alloy-transport" version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy?rev=14ed25d#14ed25d8ab485fc0d313fd1e055862c9d20ef273" +source = "git+https://github.com/alloy-rs/alloy?rev=00d81d7#00d81d7882a0bee4720d6d6a1db4c8f164ebb9d0" dependencies = [ "alloy-json-rpc", "base64 0.22.1", @@ -658,7 +647,7 @@ dependencies = [ [[package]] name = "alloy-transport-http" version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy?rev=14ed25d#14ed25d8ab485fc0d313fd1e055862c9d20ef273" +source = "git+https://github.com/alloy-rs/alloy?rev=00d81d7#00d81d7882a0bee4720d6d6a1db4c8f164ebb9d0" dependencies = [ "alloy-json-rpc", "alloy-transport", @@ -672,7 +661,7 @@ dependencies = [ [[package]] name = "alloy-transport-ipc" version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy?rev=14ed25d#14ed25d8ab485fc0d313fd1e055862c9d20ef273" +source = "git+https://github.com/alloy-rs/alloy?rev=00d81d7#00d81d7882a0bee4720d6d6a1db4c8f164ebb9d0" dependencies = [ "alloy-json-rpc", "alloy-pubsub", @@ -690,12 +679,13 @@ dependencies = [ [[package]] name = "alloy-transport-ws" version = "0.1.0" -source = "git+https://github.com/alloy-rs/alloy?rev=14ed25d#14ed25d8ab485fc0d313fd1e055862c9d20ef273" +source = "git+https://github.com/alloy-rs/alloy?rev=00d81d7#00d81d7882a0bee4720d6d6a1db4c8f164ebb9d0" dependencies = [ "alloy-pubsub", "alloy-transport", "futures", "http 1.1.0", + "rustls 0.23.10", "serde_json", "tokio", "tokio-tungstenite", @@ -2516,15 +2506,15 @@ dependencies = [ [[package]] name = "derive_more" -version = "0.99.17" +version = "0.99.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +checksum = "5f33878137e4dafd7fa914ad4e259e18a4e8e532b9617a2d0150262bf53abfce" dependencies = [ "convert_case 0.4.0", "proc-macro2", "quote", "rustc_version 0.4.0", - "syn 1.0.109", + "syn 2.0.66", ] [[package]] @@ -2710,18 +2700,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "educe" -version = "0.4.23" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f0042ff8246a363dbe77d2ceedb073339e85a804b9a47636c6e016a9a32c05f" -dependencies = [ - "enum-ordinalize", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "ef-tests" version = "1.0.0-rc.1" @@ -2779,9 +2757,9 @@ checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" [[package]] name = "enr" -version = "0.12.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ab656b89cdd15051d92d0931888103508de14ef9e51177c86d478dfa551ce0f" +checksum = "972070166c68827e64bd1ebc8159dd8e32d9bc2da7ebe8f20b61308f7974ad30" dependencies = [ "alloy-rlp", "base64 0.21.7", @@ -2791,7 +2769,7 @@ dependencies = [ "k256", "log", "rand 0.8.5", - "secp256k1 0.28.2", + "secp256k1 0.29.0", "serde", "sha3", "zeroize", @@ -2809,19 +2787,6 @@ dependencies = [ "syn 2.0.66", ] -[[package]] -name = "enum-ordinalize" -version = "3.1.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bf1fa3f06bbff1ea5b1a9c7b14aa992a39657db60a2759457328d7e058f49ee" -dependencies = [ - "num-bigint", - "num-traits", - "proc-macro2", - "quote", - "syn 2.0.66", -] - [[package]] name = "enumn" version = "0.1.13" @@ -2970,7 +2935,7 @@ dependencies = [ name = "exex-rollup" version = "0.0.0" dependencies = [ - "alloy-consensus 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", + "alloy-consensus 0.1.0", "alloy-rlp", "alloy-sol-types", "eyre", @@ -3128,10 +3093,10 @@ version = "0.1.0" source = "git+https://github.com/foundry-rs/block-explorers#af29524f4fc7dc25f59e8ae38652022f47ebee9b" dependencies = [ "alloy-chains", - "alloy-eips 0.1.0 (git+https://github.com/alloy-rs/alloy)", + "alloy-eips 0.1.1", "alloy-primitives", - "alloy-rpc-types 0.1.0 (git+https://github.com/alloy-rs/alloy)", - "alloy-serde 0.1.0 (git+https://github.com/alloy-rs/alloy)", + "alloy-rpc-types 0.1.1", + "alloy-serde 0.1.1", "chrono", "reqwest", "serde", @@ -4427,20 +4392,6 @@ dependencies = [ "url", ] -[[package]] -name = "jsonwebtoken" -version = "8.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6971da4d9c3aa03c3d8f3ff0f4155b534aad021292003895a469716b2a230378" -dependencies = [ - "base64 0.21.7", - "pem 1.1.1", - "ring 0.16.20", - "serde", - "serde_json", - "simple_asn1", -] - [[package]] name = "jsonwebtoken" version = "9.3.0" @@ -4449,8 +4400,8 @@ checksum = "b9ae10193d25051e74945f1ea2d0b42e03cc3b890f7e4cc5faa44997d808193f" dependencies = [ "base64 0.21.7", "js-sys", - "pem 3.0.4", - "ring 0.17.8", + "pem", + "ring", "serde", "serde_json", "simple_asn1", @@ -4833,9 +4784,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.2" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memmap2" @@ -5481,7 +5432,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.5.1", + "redox_syscall 0.5.2", "smallvec", "windows-targets 0.52.5", ] @@ -5502,15 +5453,6 @@ dependencies = [ "hmac 0.12.1", ] -[[package]] -name = "pem" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" -dependencies = [ - "base64 0.13.1", -] - [[package]] name = "pem" version = "3.0.4" @@ -6145,9 +6087,9 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" +checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd" dependencies = [ "bitflags 2.5.0", ] @@ -6342,6 +6284,7 @@ dependencies = [ "reth-rpc-types-compat", "reth-stages", "reth-static-file", + "reth-static-file-types", "reth-tasks", "reth-tracing", "reth-transaction-pool", @@ -6454,8 +6397,8 @@ dependencies = [ name = "reth-bench" version = "1.0.0-rc.1" dependencies = [ - "alloy-consensus 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", - "alloy-eips 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", + "alloy-consensus 0.1.0", + "alloy-eips 0.1.0", "alloy-json-rpc", "alloy-provider", "alloy-pubsub", @@ -6546,9 +6489,9 @@ dependencies = [ name = "reth-codecs" version = "1.0.0-rc.1" dependencies = [ - "alloy-consensus 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", - "alloy-eips 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", - "alloy-genesis 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", + "alloy-consensus 0.1.0", + "alloy-eips 0.1.0", + "alloy-genesis", "alloy-primitives", "arbitrary", "bytes", @@ -6609,8 +6552,8 @@ dependencies = [ name = "reth-consensus-debug-client" version = "1.0.0-rc.1" dependencies = [ - "alloy-consensus 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", - "alloy-eips 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", + "alloy-consensus 0.1.0", + "alloy-eips 0.1.0", "alloy-provider", "auto_impl", "eyre", @@ -6654,7 +6597,7 @@ dependencies = [ "reth-stages-types", "reth-storage-errors", "reth-tracing", - "reth-trie-types", + "reth-trie-common", "rustc-hash", "serde", "serde_json", @@ -6688,7 +6631,7 @@ dependencies = [ "reth-prune-types", "reth-stages-types", "reth-storage-errors", - "reth-trie-types", + "reth-trie-common", "serde", "serde_json", "test-fuzz", @@ -6718,6 +6661,7 @@ dependencies = [ name = "reth-discv4" version = "1.0.0-rc.1" dependencies = [ + "alloy-primitives", "alloy-rlp", "assert_matches", "discv5", @@ -6725,6 +6669,7 @@ dependencies = [ "generic-array", "parking_lot 0.12.3", "rand 0.8.5", + "reth-ethereum-forks", "reth-net-common", "reth-net-nat", "reth-network-peers", @@ -6767,12 +6712,15 @@ dependencies = [ name = "reth-dns-discovery" version = "1.0.0-rc.1" dependencies = [ + "alloy-chains", + "alloy-primitives", "alloy-rlp", "data-encoding", "enr", "linked_hash_set", "parking_lot 0.12.3", "rand 0.8.5", + "reth-ethereum-forks", "reth-net-common", "reth-network-peers", "reth-primitives", @@ -6825,9 +6773,9 @@ dependencies = [ name = "reth-e2e-test-utils" version = "1.0.0-rc.1" dependencies = [ - "alloy-consensus 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", + "alloy-consensus 0.1.0", "alloy-network", - "alloy-rpc-types 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", + "alloy-rpc-types 0.1.0", "alloy-signer", "alloy-signer-wallet", "eyre", @@ -6855,6 +6803,7 @@ name = "reth-ecies" version = "1.0.0-rc.1" dependencies = [ "aes 0.8.4", + "alloy-primitives", "alloy-rlp", "block-padding", "byteorder", @@ -6862,15 +6811,12 @@ dependencies = [ "concat-kdf", "ctr 0.9.2", "digest 0.10.7", - "educe", "futures", "generic-array", "hmac 0.12.1", "pin-project", "rand 0.8.5", - "reth-net-common", "reth-network-peers", - "reth-primitives", "secp256k1 0.28.2", "sha2 0.10.8", "sha3", @@ -7047,7 +6993,7 @@ dependencies = [ name = "reth-evm-ethereum" version = "1.0.0-rc.1" dependencies = [ - "alloy-eips 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", + "alloy-eips 0.1.0", "alloy-sol-types", "reth-ethereum-consensus", "reth-evm", @@ -7083,7 +7029,7 @@ dependencies = [ name = "reth-execution-errors" version = "1.0.0-rc.1" dependencies = [ - "alloy-eips 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", + "alloy-eips 0.1.0", "alloy-primitives", "reth-consensus", "reth-prune-types", @@ -7096,7 +7042,7 @@ dependencies = [ name = "reth-execution-types" version = "1.0.0-rc.1" dependencies = [ - "alloy-eips 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", + "alloy-eips 0.1.0", "alloy-primitives", "reth-execution-errors", "reth-primitives", @@ -7200,7 +7146,6 @@ dependencies = [ "dashmap", "derive_more", "indexmap 2.2.6", - "libc", "parking_lot 0.12.3", "pprof", "rand 0.8.5", @@ -7217,7 +7162,6 @@ version = "1.0.0-rc.1" dependencies = [ "bindgen", "cc", - "libc", ] [[package]] @@ -7551,6 +7495,7 @@ dependencies = [ name = "reth-node-events" version = "1.0.0-rc.1" dependencies = [ + "alloy-rpc-types-engine", "futures", "humantime", "pin-project", @@ -7561,7 +7506,6 @@ dependencies = [ "reth-primitives", "reth-provider", "reth-prune", - "reth-rpc-types", "reth-stages", "reth-static-file", "tokio", @@ -7717,12 +7661,12 @@ name = "reth-primitives" version = "1.0.0-rc.1" dependencies = [ "alloy-chains", - "alloy-consensus 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", - "alloy-eips 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", - "alloy-genesis 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", + "alloy-consensus 0.1.0", + "alloy-eips 0.1.0", + "alloy-genesis", "alloy-primitives", "alloy-rlp", - "alloy-rpc-types 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", + "alloy-rpc-types 0.1.0", "alloy-trie", "arbitrary", "assert_matches", @@ -7731,12 +7675,9 @@ dependencies = [ "c-kzg", "criterion", "derive_more", - "hash-db", - "itertools 0.12.1", "modular-bitfield", "nybbles", "once_cell", - "plain_hasher", "pprof", "proptest", "proptest-derive", @@ -7747,7 +7688,7 @@ dependencies = [ "reth-network-peers", "reth-primitives-traits", "reth-static-file-types", - "reth-trie-types", + "reth-trie-common", "revm", "revm-primitives", "roaring", @@ -7757,7 +7698,7 @@ dependencies = [ "sucds", "tempfile", "test-fuzz", - "thiserror", + "thiserror-no-std", "toml", "triehash", "zstd", @@ -7767,15 +7708,21 @@ dependencies = [ name = "reth-primitives-traits" version = "1.0.0-rc.1" dependencies = [ - "alloy-consensus 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", - "alloy-genesis 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", + "alloy-consensus 0.1.0", + "alloy-eips 0.1.0", + "alloy-genesis", "alloy-primitives", + "alloy-rlp", + "alloy-rpc-types-eth 0.1.0", "arbitrary", "bytes", + "derive_more", "modular-bitfield", "proptest", "proptest-derive", + "rand 0.8.5", "reth-codecs", + "revm-primitives", "serde", "test-fuzz", ] @@ -7872,7 +7819,7 @@ dependencies = [ name = "reth-revm" version = "1.0.0-rc.1" dependencies = [ - "alloy-eips 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", + "alloy-eips 0.1.0", "alloy-rlp", "reth-consensus-common", "reth-execution-errors", @@ -7903,7 +7850,7 @@ dependencies = [ "http-body", "hyper", "jsonrpsee", - "jsonwebtoken 8.3.0", + "jsonwebtoken", "metrics", "parking_lot 0.12.3", "pin-project", @@ -7947,6 +7894,7 @@ dependencies = [ name = "reth-rpc-api" version = "1.0.0-rc.1" dependencies = [ + "alloy-dyn-abi", "jsonrpsee", "reth-engine-primitives", "reth-network-peers", @@ -8074,7 +8022,7 @@ name = "reth-rpc-types" version = "1.0.0-rc.1" dependencies = [ "alloy-primitives", - "alloy-rpc-types 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", + "alloy-rpc-types 0.1.0", "alloy-rpc-types-anvil", "alloy-rpc-types-beacon", "alloy-rpc-types-engine", @@ -8095,9 +8043,10 @@ name = "reth-rpc-types-compat" version = "1.0.0-rc.1" dependencies = [ "alloy-rlp", - "alloy-rpc-types 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", + "alloy-rpc-types 0.1.0", "reth-primitives", "reth-rpc-types", + "reth-trie-common", "serde_json", ] @@ -8183,7 +8132,7 @@ dependencies = [ "proptest-derive", "rand 0.8.5", "reth-codecs", - "reth-trie-types", + "reth-trie-common", "serde", "test-fuzz", ] @@ -8265,7 +8214,7 @@ dependencies = [ name = "reth-testing-utils" version = "1.0.0-rc.1" dependencies = [ - "alloy-genesis 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", + "alloy-genesis", "rand 0.8.5", "reth-primitives", "secp256k1 0.28.2", @@ -8351,7 +8300,7 @@ dependencies = [ "reth-provider", "reth-stages-types", "reth-storage-errors", - "reth-trie-types", + "reth-trie-common", "revm", "serde_json", "similar-asserts", @@ -8361,6 +8310,34 @@ dependencies = [ "triehash", ] +[[package]] +name = "reth-trie-common" +version = "1.0.0-rc.1" +dependencies = [ + "alloy-consensus 0.1.0", + "alloy-genesis", + "alloy-primitives", + "alloy-rlp", + "alloy-trie", + "arbitrary", + "assert_matches", + "bytes", + "derive_more", + "hash-db", + "itertools 0.12.1", + "nybbles", + "plain_hasher", + "proptest", + "proptest-derive", + "reth-codecs", + "reth-primitives-traits", + "revm-primitives", + "serde", + "serde_json", + "test-fuzz", + "toml", +] + [[package]] name = "reth-trie-parallel" version = "1.0.0-rc.1" @@ -8386,31 +8363,10 @@ dependencies = [ "tracing", ] -[[package]] -name = "reth-trie-types" -version = "1.0.0-rc.1" -dependencies = [ - "alloy-primitives", - "alloy-rlp", - "alloy-trie", - "arbitrary", - "assert_matches", - "bytes", - "derive_more", - "nybbles", - "proptest", - "proptest-derive", - "reth-codecs", - "serde", - "serde_json", - "test-fuzz", - "toml", -] - [[package]] name = "revm" version = "9.0.0" -source = "git+https://github.com/bluealloy/revm?rev=a28a543#a28a5439b9cfb7494cbd670da10cbedcfe6c5854" +source = "git+https://github.com/bluealloy/revm.git?rev=8f4c153#8f4c153a02d94d9e1e9275ba3cf73f599e23c6b6" dependencies = [ "auto_impl", "cfg-if", @@ -8424,11 +8380,10 @@ dependencies = [ [[package]] name = "revm-inspectors" version = "0.1.0" -source = "git+https://github.com/paradigmxyz/revm-inspectors?rev=5e3058a#5e3058a87caa24df748e090083ef76518d082c10" +source = "git+https://github.com/paradigmxyz/revm-inspectors?rev=52f632e#52f632e66404b9d6bfd474eeef3ff65d58167f2e" dependencies = [ "alloy-primitives", - "alloy-rpc-types 0.1.0 (git+https://github.com/alloy-rs/alloy?rev=14ed25d)", - "alloy-rpc-types-trace", + "alloy-rpc-types 0.1.0", "alloy-sol-types", "anstyle", "boa_engine", @@ -8442,7 +8397,7 @@ dependencies = [ [[package]] name = "revm-interpreter" version = "5.0.0" -source = "git+https://github.com/bluealloy/revm?rev=a28a543#a28a5439b9cfb7494cbd670da10cbedcfe6c5854" +source = "git+https://github.com/bluealloy/revm.git?rev=8f4c153#8f4c153a02d94d9e1e9275ba3cf73f599e23c6b6" dependencies = [ "revm-primitives", "serde", @@ -8451,7 +8406,7 @@ dependencies = [ [[package]] name = "revm-precompile" version = "7.0.0" -source = "git+https://github.com/bluealloy/revm?rev=a28a543#a28a5439b9cfb7494cbd670da10cbedcfe6c5854" +source = "git+https://github.com/bluealloy/revm.git?rev=8f4c153#8f4c153a02d94d9e1e9275ba3cf73f599e23c6b6" dependencies = [ "aurora-engine-modexp", "blst", @@ -8469,7 +8424,7 @@ dependencies = [ [[package]] name = "revm-primitives" version = "4.0.0" -source = "git+https://github.com/bluealloy/revm?rev=a28a543#a28a5439b9cfb7494cbd670da10cbedcfe6c5854" +source = "git+https://github.com/bluealloy/revm.git?rev=8f4c153#8f4c153a02d94d9e1e9275ba3cf73f599e23c6b6" dependencies = [ "alloy-primitives", "auto_impl", @@ -8505,21 +8460,6 @@ dependencies = [ "bytemuck", ] -[[package]] -name = "ring" -version = "0.16.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" -dependencies = [ - "cc", - "libc", - "once_cell", - "spin 0.5.2", - "untrusted 0.7.1", - "web-sys", - "winapi", -] - [[package]] name = "ring" version = "0.17.8" @@ -8531,7 +8471,7 @@ dependencies = [ "getrandom 0.2.15", "libc", "spin 0.9.8", - "untrusted 0.9.0", + "untrusted", "windows-sys 0.52.0", ] @@ -8709,7 +8649,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bf4ef73721ac7bcd79b2b315da7779d8fc09718c6b3d2d1b2d94850eb8c18432" dependencies = [ "log", - "ring 0.17.8", + "ring", "rustls-pki-types", "rustls-webpki", "subtle", @@ -8724,7 +8664,7 @@ checksum = "05cff451f60db80f490f3c182b77c35260baace73209e9cdbbe526bfe3a4d402" dependencies = [ "log", "once_cell", - "ring 0.17.8", + "ring", "rustls-pki-types", "rustls-webpki", "subtle", @@ -8793,9 +8733,9 @@ version = "0.102.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff448f7e92e913c4b7d4c6d8e4540a1724b319b4152b8aef6d4cf8339712b33e" dependencies = [ - "ring 0.17.8", + "ring", "rustls-pki-types", - "untrusted 0.9.0", + "untrusted", ] [[package]] @@ -9897,9 +9837,9 @@ dependencies = [ [[package]] name = "tokio-tungstenite" -version = "0.23.0" +version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "becd34a233e7e31a3dbf7c7241b38320f57393dcae8e7324b0167d21b8e320b0" +checksum = "c6989540ced10490aaf14e6bad2e3d33728a2813310a0c71d1574304c49631cd" dependencies = [ "futures-util", "log", @@ -10366,12 +10306,6 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb066959b24b5196ae73cb057f45598450d2c5f71460e98c49b738086eff9c06" -[[package]] -name = "untrusted" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" - [[package]] name = "untrusted" version = "0.9.0" diff --git a/Cargo.toml b/Cargo.toml index 3ee6f0a2e5..2204e95791 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [workspace.package] version = "1.0.0-rc.1" edition = "2021" -rust-version = "1.76" +rust-version = "1.79" license = "MIT OR Apache-2.0" homepage = "https://paradigmxyz.github.io/reth" repository = "https://github.com/paradigmxyz/reth" @@ -100,9 +100,9 @@ members = [ "crates/tokio-util/", "crates/tracing/", "crates/transaction-pool/", + "crates/trie/common", "crates/trie/parallel/", "crates/trie/trie", - "crates/trie/types", "examples/beacon-api-sidecar-fetcher/", "examples/beacon-api-sse/", "examples/bsc-p2p", @@ -334,8 +334,8 @@ reth-tokio-util = { path = "crates/tokio-util" } reth-tracing = { path = "crates/tracing" } reth-transaction-pool = { path = "crates/transaction-pool" } reth-trie = { path = "crates/trie/trie" } +reth-trie-common = { path = "crates/trie/common" } reth-trie-parallel = { path = "crates/trie/parallel" } -reth-trie-types = { path = "crates/trie/types" } # revm revm = { version = "9.0.0", features = [ @@ -346,7 +346,7 @@ revm = { version = "9.0.0", features = [ revm-primitives = { version = "4.0.0", features = [ "std", ], default-features = false } -revm-inspectors = { git = "https://github.com/paradigmxyz/revm-inspectors", rev = "5e3058a" } +revm-inspectors = { git = "https://github.com/paradigmxyz/revm-inspectors", rev = "52f632e" } # eth alloy-chains = "0.1.15" @@ -355,28 +355,33 @@ alloy-dyn-abi = "0.7.2" alloy-sol-types = "0.7.2" alloy-rlp = "0.3.4" alloy-trie = "0.4" -alloy-rpc-types = { git = "https://github.com/alloy-rs/alloy", rev = "14ed25d" } -alloy-rpc-types-anvil = { git = "https://github.com/alloy-rs/alloy", rev = "14ed25d" } -alloy-rpc-types-trace = { git = "https://github.com/alloy-rs/alloy", rev = "14ed25d" } -alloy-rpc-types-engine = { git = "https://github.com/alloy-rs/alloy", rev = "14ed25d" } -alloy-rpc-types-beacon = { git = "https://github.com/alloy-rs/alloy", rev = "14ed25d" } -alloy-genesis = { git = "https://github.com/alloy-rs/alloy", rev = "14ed25d" } -alloy-node-bindings = { git = "https://github.com/alloy-rs/alloy", rev = "14ed25d" } -alloy-provider = { git = "https://github.com/alloy-rs/alloy", rev = "14ed25d", default-features = false, features = [ +alloy-rpc-types = { git = "https://github.com/alloy-rs/alloy", rev = "00d81d7", default-features = false, features = [ + "eth", +] } +alloy-rpc-types-anvil = { git = "https://github.com/alloy-rs/alloy", rev = "00d81d7", default-features = false } +alloy-rpc-types-beacon = { git = "https://github.com/alloy-rs/alloy", rev = "00d81d7", default-features = false } +alloy-rpc-types-engine = { git = "https://github.com/alloy-rs/alloy", rev = "00d81d7", default-features = false } +alloy-rpc-types-eth = { git = "https://github.com/alloy-rs/alloy", rev = "00d81d7", default-features = false } +alloy-rpc-types-trace = { git = "https://github.com/alloy-rs/alloy", rev = "00d81d7", default-features = false } +alloy-genesis = { git = "https://github.com/alloy-rs/alloy", rev = "00d81d7", default-features = false } +alloy-node-bindings = { git = "https://github.com/alloy-rs/alloy", rev = "00d81d7", default-features = false } +alloy-provider = { git = "https://github.com/alloy-rs/alloy", rev = "00d81d7", default-features = false, features = [ "reqwest", ] } -alloy-eips = { git = "https://github.com/alloy-rs/alloy", default-features = false, rev = "14ed25d" } -alloy-signer = { git = "https://github.com/alloy-rs/alloy", rev = "14ed25d" } -alloy-signer-wallet = { git = "https://github.com/alloy-rs/alloy", rev = "14ed25d" } -alloy-network = { git = "https://github.com/alloy-rs/alloy", rev = "14ed25d" } -alloy-consensus = { git = "https://github.com/alloy-rs/alloy", rev = "14ed25d" } -alloy-transport = { git = "https://github.com/alloy-rs/alloy", rev = "14ed25d" } -alloy-transport-http = { git = "https://github.com/alloy-rs/alloy", rev = "14ed25d", features = ["reqwest-rustls-tls"], default-features = false } -alloy-transport-ws = { git = "https://github.com/alloy-rs/alloy", rev = "14ed25d" } -alloy-transport-ipc = { git = "https://github.com/alloy-rs/alloy", rev = "14ed25d" } -alloy-pubsub = { git = "https://github.com/alloy-rs/alloy", rev = "14ed25d" } -alloy-json-rpc = { git = "https://github.com/alloy-rs/alloy", rev = "14ed25d" } -alloy-rpc-client = { git = "https://github.com/alloy-rs/alloy", rev = "14ed25d" } +alloy-eips = { git = "https://github.com/alloy-rs/alloy", default-features = false, rev = "00d81d7" } +alloy-signer = { git = "https://github.com/alloy-rs/alloy", rev = "00d81d7", default-features = false } +alloy-signer-wallet = { git = "https://github.com/alloy-rs/alloy", rev = "00d81d7", default-features = false } +alloy-network = { git = "https://github.com/alloy-rs/alloy", rev = "00d81d7", default-features = false } +alloy-consensus = { git = "https://github.com/alloy-rs/alloy", rev = "00d81d7", default-features = false } +alloy-transport = { git = "https://github.com/alloy-rs/alloy", rev = "00d81d7" } +alloy-transport-http = { git = "https://github.com/alloy-rs/alloy", rev = "00d81d7", features = [ + "reqwest-rustls-tls", +], default-features = false } +alloy-transport-ws = { git = "https://github.com/alloy-rs/alloy", rev = "00d81d7", default-features = false } +alloy-transport-ipc = { git = "https://github.com/alloy-rs/alloy", rev = "00d81d7", default-features = false } +alloy-pubsub = { git = "https://github.com/alloy-rs/alloy", rev = "00d81d7", default-features = false } +alloy-json-rpc = { git = "https://github.com/alloy-rs/alloy", rev = "00d81d7", default-features = false } +alloy-rpc-client = { git = "https://github.com/alloy-rs/alloy", rev = "00d81d7", default-features = false } # misc auto_impl = "1" @@ -389,6 +394,7 @@ derive_more = "0.99.17" fdlimit = "0.3.0" eyre = "0.6" generic-array = "0.14" +linked_hash_set = "0.1" tracing = "0.1.0" tracing-appender = "0.2" thiserror = "1.0" @@ -434,9 +440,10 @@ tokio-util = { version = "0.7.4", features = ["codec"] } # async async-stream = "0.3" async-trait = "0.1.68" -futures = "0.3.26" +futures = "0.3" +futures-util = "0.3" +futures-core = "0.3" pin-project = "1.0.12" -futures-util = "0.3.25" hyper = "1.3" hyper-util = "0.1.5" reqwest = { version = "0.12", default-features = false } @@ -456,6 +463,7 @@ jsonrpsee-http-client = "0.23" # http http = "1.0" http-body = "1.0" +jsonwebtoken = "9" # crypto secp256k1 = { version = "0.28", default-features = false, features = [ @@ -488,7 +496,7 @@ similar-asserts = "1.5.0" test-fuzz = "5" [patch.crates-io] -revm = { git = "https://github.com/bluealloy/revm", rev = "a28a543" } -revm-interpreter = { git = "https://github.com/bluealloy/revm", rev = "a28a543" } -revm-precompile = { git = "https://github.com/bluealloy/revm", rev = "a28a543" } -revm-primitives = { git = "https://github.com/bluealloy/revm", rev = "a28a543" } +revm = { git = "https://github.com/bluealloy/revm.git", rev = "8f4c153" } +revm-interpreter = { git = "https://github.com/bluealloy/revm.git", rev = "8f4c153" } +revm-precompile = { git = "https://github.com/bluealloy/revm.git", rev = "8f4c153" } +revm-primitives = { git = "https://github.com/bluealloy/revm.git", rev = "8f4c153" } \ No newline at end of file diff --git a/README.md b/README.md index 7862ac03f4..00b575a798 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,7 @@ When updating this, also update: - .github/workflows/lint.yml --> -The Minimum Supported Rust Version (MSRV) of this project is [1.76.0](https://blog.rust-lang.org/2024/02/08/Rust-1.76.0.html). +The Minimum Supported Rust Version (MSRV) of this project is [1.79.0](https://blog.rust-lang.org/2024/06/13/Rust-1.79.0.html). See the book for detailed instructions on how to [build from source](https://paradigmxyz.github.io/reth/installation/source.html). diff --git a/bin/reth-bench/Cargo.toml b/bin/reth-bench/Cargo.toml index bca2cf4f8d..a0bf299f19 100644 --- a/bin/reth-bench/Cargo.toml +++ b/bin/reth-bench/Cargo.toml @@ -21,7 +21,7 @@ reth-node-core.workspace = true reth-node-api.workspace = true reth-rpc-types.workspace = true reth-rpc-types-compat.workspace = true -reth-primitives = { workspace = true, features = ["clap", "alloy-compat"] } +reth-primitives = { workspace = true, features = ["alloy-compat"] } reth-tracing.workspace = true # alloy diff --git a/bin/reth-bench/src/bench/output.rs b/bin/reth-bench/src/bench/output.rs index f976b5d284..83103418d9 100644 --- a/bin/reth-bench/src/bench/output.rs +++ b/bin/reth-bench/src/bench/output.rs @@ -1,20 +1,10 @@ //! Contains various benchmark output formats, either for logging or for //! serialization to / from files. -//! -//! This also contains common constants for units, for example [GIGAGAS]. +use reth_primitives::constants::gas_units::GIGAGAS; use serde::{ser::SerializeStruct, Serialize}; use std::time::Duration; -/// Represents one Kilogas, or `1_000` gas. -const KILOGAS: u64 = 1_000; - -/// Represents one Megagas, or `1_000_000` gas. -const MEGAGAS: u64 = KILOGAS * 1_000; - -/// Represents one Gigagas, or `1_000_000_000` gas. -const GIGAGAS: u64 = MEGAGAS * 1_000; - /// This is the suffix for gas output csv files. pub(crate) const GAS_OUTPUT_SUFFIX: &str = "total_gas.csv"; diff --git a/bin/reth-bench/src/valid_payload.rs b/bin/reth-bench/src/valid_payload.rs index 67bd1bc1e3..4c96c43b18 100644 --- a/bin/reth-bench/src/valid_payload.rs +++ b/bin/reth-bench/src/valid_payload.rs @@ -5,7 +5,6 @@ use alloy_provider::{ext::EngineApi, Network}; use alloy_rpc_types_engine::{ ExecutionPayloadInputV2, ForkchoiceState, ForkchoiceUpdated, PayloadAttributes, PayloadStatus, - PayloadStatusEnum, }; use alloy_transport::{Transport, TransportResult}; use reth_node_api::EngineApiMessageVersion; @@ -76,8 +75,8 @@ where payload: ExecutionPayloadV1, ) -> TransportResult { let mut status = self.new_payload_v1(payload.clone()).await?; - while status.status != PayloadStatusEnum::Valid { - if status.status.is_invalid() { + while !status.is_valid() { + if status.is_invalid() { error!(?status, ?payload, "Invalid newPayloadV1",); panic!("Invalid newPayloadV1: {status:?}"); } @@ -91,8 +90,8 @@ where payload: ExecutionPayloadInputV2, ) -> TransportResult { let mut status = self.new_payload_v2(payload.clone()).await?; - while status.status != PayloadStatusEnum::Valid { - if status.status.is_invalid() { + while !status.is_valid() { + if status.is_invalid() { error!(?status, ?payload, "Invalid newPayloadV2",); panic!("Invalid newPayloadV2: {status:?}"); } @@ -110,8 +109,8 @@ where let mut status = self .new_payload_v3(payload.clone(), versioned_hashes.clone(), parent_beacon_block_root) .await?; - while status.status != PayloadStatusEnum::Valid { - if status.status.is_invalid() { + while !status.is_valid() { + if status.is_invalid() { error!( ?status, ?payload, @@ -136,8 +135,8 @@ where let mut status = self.fork_choice_updated_v1(fork_choice_state, payload_attributes.clone()).await?; - while status.payload_status.status != PayloadStatusEnum::Valid { - if status.payload_status.status.is_invalid() { + while !status.is_valid() { + if status.is_invalid() { error!( ?status, ?fork_choice_state, @@ -161,8 +160,8 @@ where let mut status = self.fork_choice_updated_v2(fork_choice_state, payload_attributes.clone()).await?; - while status.payload_status.status != PayloadStatusEnum::Valid { - if status.payload_status.status.is_invalid() { + while !status.is_valid() { + if status.is_invalid() { error!( ?status, ?fork_choice_state, @@ -186,8 +185,8 @@ where let mut status = self.fork_choice_updated_v3(fork_choice_state, payload_attributes.clone()).await?; - while status.payload_status.status != PayloadStatusEnum::Valid { - if status.payload_status.status.is_invalid() { + while !status.is_valid() { + if status.is_invalid() { error!( ?status, ?fork_choice_state, diff --git a/bin/reth/Cargo.toml b/bin/reth/Cargo.toml index 38410737ec..f6ec9bd7d4 100644 --- a/bin/reth/Cargo.toml +++ b/bin/reth/Cargo.toml @@ -15,7 +15,7 @@ workspace = true [dependencies] # reth reth-config.workspace = true -reth-primitives = { workspace = true, features = ["arbitrary", "clap"] } +reth-primitives.workspace = true reth-fs-util.workspace = true reth-db = { workspace = true, features = ["mdbx"] } reth-db-api.workspace = true @@ -49,7 +49,8 @@ reth-payload-validator.workspace = true reth-basic-payload-builder.workspace = true reth-discv4.workspace = true reth-discv5.workspace = true -reth-static-file = { workspace = true } +reth-static-file.workspace = true +reth-static-file-types = { workspace = true, features = ["clap"] } reth-trie = { workspace = true, features = ["metrics"] } reth-nippy-jar.workspace = true reth-node-api.workspace = true diff --git a/book/SUMMARY.md b/book/SUMMARY.md index 1a39a0d875..e7fa1ea680 100644 --- a/book/SUMMARY.md +++ b/book/SUMMARY.md @@ -76,4 +76,5 @@ - [Execution Extensions](./developers/exex/exex.md) - [How do ExExes work?](./developers/exex/how-it-works.md) - [Hello World](./developers/exex/hello-world.md) + - [Remote](./developers/exex/remote.md) - [Contribute](./developers/contribute.md) diff --git a/book/developers/exex/exex.md b/book/developers/exex/exex.md index 0c3199bc87..f0cd08d4a5 100644 --- a/book/developers/exex/exex.md +++ b/book/developers/exex/exex.md @@ -2,17 +2,27 @@ ## What are Execution Extensions? -Execution Extensions allow developers to build their own infrastructure that relies on Reth +Execution Extensions (or ExExes, for short) allow developers to build their own infrastructure that relies on Reth as a base for driving the chain (be it [Ethereum](../../run/mainnet.md) or [OP Stack](../../run/optimism.md)) forward. An Execution Extension is a task that derives its state from changes in Reth's state. Some examples of such state derivations are rollups, bridges, and indexers. +They are called Execution Extensions because the main trigger for them is the execution of new blocks (or reorgs of old blocks) +initiated by Reth. + Read more about things you can build with Execution Extensions in the [Paradigm blog](https://www.paradigm.xyz/2024/05/reth-exex). +## What Execution Extensions are not + +Execution Extensions are not separate processes that connect to the main Reth node process. +Instead, ExExes are compiled into the same binary as Reth, and run alongside it, using shared memory for communication. + +If you want to build an Execution Extension that sends data into a separate process, check out the [Remote](./remote.md) chapter. + ## How do I build an Execution Extension? -Let's dive into how to build our own ExEx (short for Execution Extension) from scratch, add tests for it, +Let's dive into how to build our own ExEx from scratch, add tests for it, and run it on the Holesky testnet. 1. [How do ExExes work?](./how-it-works.md) diff --git a/book/developers/exex/remote.md b/book/developers/exex/remote.md new file mode 100644 index 0000000000..a3ac9ff2e8 --- /dev/null +++ b/book/developers/exex/remote.md @@ -0,0 +1,3 @@ +# Remote Execution Extensions + +WIP diff --git a/book/run/optimism.md b/book/run/optimism.md index a44d0b603f..b16a7e4b9f 100644 --- a/book/run/optimism.md +++ b/book/run/optimism.md @@ -101,7 +101,7 @@ op-node \ [l1-el-spec]: https://github.com/ethereum/execution-specs [rollup-node-spec]: https://github.com/ethereum-optimism/specs/blob/main/specs/protocol/rollup-node.md [op-geth-forkdiff]: https://op-geth.optimism.io -[sequencer]: https://github.com/ethereum-optimism/specs/blob/main/specs/introduction.md#sequencers +[sequencer]: https://github.com/ethereum-optimism/specs/blob/main/specs/background.md#sequencers [op-stack-spec]: https://github.com/ethereum-optimism/specs/blob/main/specs [l2-el-spec]: https://github.com/ethereum-optimism/specs/blob/main/specs/protocol/exec-engine.md [deposit-spec]: https://github.com/ethereum-optimism/specs/blob/main/specs/protocol/deposits.md diff --git a/clippy.toml b/clippy.toml index 7e606c3f1f..865dfc7c95 100644 --- a/clippy.toml +++ b/clippy.toml @@ -1,2 +1,2 @@ -msrv = "1.76" +msrv = "1.79" too-large-for-stack = 128 diff --git a/crates/blockchain-tree/Cargo.toml b/crates/blockchain-tree/Cargo.toml index 6479693961..16f84c6599 100644 --- a/crates/blockchain-tree/Cargo.toml +++ b/crates/blockchain-tree/Cargo.toml @@ -39,7 +39,7 @@ metrics.workspace = true # misc aquamarine.workspace = true -linked_hash_set = "0.1.4" +linked_hash_set.workspace = true [dev-dependencies] reth-db = { workspace = true, features = ["test-utils"] } diff --git a/crates/blockchain-tree/src/blockchain_tree.rs b/crates/blockchain-tree/src/blockchain_tree.rs index 5c8ee5623d..5359212d17 100644 --- a/crates/blockchain-tree/src/blockchain_tree.rs +++ b/crates/blockchain-tree/src/blockchain_tree.rs @@ -1383,7 +1383,7 @@ mod tests { use reth_primitives::{ constants::{EIP1559_INITIAL_BASE_FEE, EMPTY_ROOT_HASH, ETHEREUM_BLOCK_GAS_LIMIT}, keccak256, - proofs::{calculate_transaction_root, state_root_unhashed}, + proofs::calculate_transaction_root, revm_primitives::AccountInfo, Account, Address, ChainSpecBuilder, Genesis, GenesisAccount, Header, Signature, Transaction, TransactionSigned, TransactionSignedEcRecovered, TxEip1559, Withdrawals, B256, @@ -1394,7 +1394,7 @@ mod tests { ProviderFactory, }; use reth_stages_api::StageCheckpoint; - use reth_trie::StateRoot; + use reth_trie::{root::state_root_unhashed, StateRoot}; use std::collections::HashMap; fn setup_externals( diff --git a/crates/blockchain-tree/src/canonical_chain.rs b/crates/blockchain-tree/src/canonical_chain.rs index ab91ee5476..8a9893a180 100644 --- a/crates/blockchain-tree/src/canonical_chain.rs +++ b/crates/blockchain-tree/src/canonical_chain.rs @@ -12,7 +12,7 @@ pub(crate) struct CanonicalChain { } impl CanonicalChain { - pub(crate) fn new(chain: BTreeMap) -> Self { + pub(crate) const fn new(chain: BTreeMap) -> Self { Self { chain } } diff --git a/crates/blockchain-tree/src/noop.rs b/crates/blockchain-tree/src/noop.rs index 3ff14ca04f..d92131dc8a 100644 --- a/crates/blockchain-tree/src/noop.rs +++ b/crates/blockchain-tree/src/noop.rs @@ -27,7 +27,7 @@ pub struct NoopBlockchainTree { impl NoopBlockchainTree { /// Create a new `NoopBlockchainTree` with a canon state notification sender. - pub fn with_canon_state_notifications( + pub const fn with_canon_state_notifications( canon_state_notification_sender: CanonStateNotificationSender, ) -> Self { Self { canon_state_notification_sender: Some(canon_state_notification_sender) } diff --git a/crates/consensus/auto-seal/src/lib.rs b/crates/consensus/auto-seal/src/lib.rs index ada2936ff1..d95d96770a 100644 --- a/crates/consensus/auto-seal/src/lib.rs +++ b/crates/consensus/auto-seal/src/lib.rs @@ -56,7 +56,7 @@ pub struct AutoSealConsensus { impl AutoSealConsensus { /// Create a new instance of [`AutoSealConsensus`] - pub fn new(chain_spec: Arc) -> Self { + pub const fn new(chain_spec: Arc) -> Self { Self { chain_spec } } } diff --git a/crates/consensus/beacon/src/engine/message.rs b/crates/consensus/beacon/src/engine/message.rs index 4dac975837..052b275c18 100644 --- a/crates/consensus/beacon/src/engine/message.rs +++ b/crates/consensus/beacon/src/engine/message.rs @@ -86,7 +86,7 @@ impl OnForkChoiceUpdated { } /// If the forkchoice update was successful and no payload attributes were provided, this method - pub(crate) fn updated_with_pending_payload_id( + pub(crate) const fn updated_with_pending_payload_id( payload_status: PayloadStatus, pending_payload_id: oneshot::Receiver>, ) -> Self { diff --git a/crates/consensus/beacon/src/engine/sync.rs b/crates/consensus/beacon/src/engine/sync.rs index 5299a972f9..5ab3ab3dbd 100644 --- a/crates/consensus/beacon/src/engine/sync.rs +++ b/crates/consensus/beacon/src/engine/sync.rs @@ -438,7 +438,7 @@ mod tests { impl TestPipelineBuilder { /// Create a new [`TestPipelineBuilder`]. - fn new() -> Self { + const fn new() -> Self { Self { pipeline_exec_outputs: VecDeque::new(), executor_results: Vec::new(), diff --git a/crates/consensus/beacon/src/engine/test_utils.rs b/crates/consensus/beacon/src/engine/test_utils.rs index b040f87d4b..8158a35f31 100644 --- a/crates/consensus/beacon/src/engine/test_utils.rs +++ b/crates/consensus/beacon/src/engine/test_utils.rs @@ -57,7 +57,7 @@ pub struct TestEnv { } impl TestEnv { - fn new( + const fn new( db: DB, tip_rx: watch::Receiver, engine_handle: BeaconConsensusEngineHandle, diff --git a/crates/consensus/common/src/validation.rs b/crates/consensus/common/src/validation.rs index e06cceec91..9cac6b2f9f 100644 --- a/crates/consensus/common/src/validation.rs +++ b/crates/consensus/common/src/validation.rs @@ -6,59 +6,33 @@ use reth_primitives::{ eip4844::{DATA_GAS_PER_BLOB, MAX_DATA_GAS_PER_BLOCK}, MAXIMUM_EXTRA_DATA_SIZE, }, + eip4844::calculate_excess_blob_gas, ChainSpec, GotExpected, Hardfork, Header, SealedBlock, SealedHeader, }; -/// Validate header standalone -pub fn validate_header_standalone( - header: &SealedHeader, - chain_spec: &ChainSpec, -) -> Result<(), ConsensusError> { - // Gas used needs to be less than gas limit. Gas used is going to be checked after execution. +/// Gas used needs to be less than gas limit. Gas used is going to be checked after execution. +#[inline] +pub fn validate_header_gas(header: &SealedHeader) -> Result<(), ConsensusError> { if header.gas_used > header.gas_limit { return Err(ConsensusError::HeaderGasUsedExceedsGasLimit { gas_used: header.gas_used, gas_limit: header.gas_limit, }) } + Ok(()) +} - // Check if base fee is set. +/// Ensure the EIP-1559 base fee is set if the London hardfork is active. +#[inline] +pub fn validate_header_base_fee( + header: &SealedHeader, + chain_spec: &ChainSpec, +) -> Result<(), ConsensusError> { if chain_spec.fork(Hardfork::London).active_at_block(header.number) && header.base_fee_per_gas.is_none() { return Err(ConsensusError::BaseFeeMissing) } - - let wd_root_missing = header.withdrawals_root.is_none() && !chain_spec.is_optimism(); - - // EIP-4895: Beacon chain push withdrawals as operations - if chain_spec.is_shanghai_active_at_timestamp(header.timestamp) && wd_root_missing { - return Err(ConsensusError::WithdrawalsRootMissing) - } else if !chain_spec.is_shanghai_active_at_timestamp(header.timestamp) && - header.withdrawals_root.is_some() - { - return Err(ConsensusError::WithdrawalsRootUnexpected) - } - - // Ensures that EIP-4844 fields are valid once cancun is active. - if chain_spec.is_cancun_active_at_timestamp(header.timestamp) { - validate_4844_header_standalone(header)?; - } else if header.blob_gas_used.is_some() { - return Err(ConsensusError::BlobGasUsedUnexpected) - } else if header.excess_blob_gas.is_some() { - return Err(ConsensusError::ExcessBlobGasUnexpected) - } else if header.parent_beacon_block_root.is_some() { - return Err(ConsensusError::ParentBeaconBlockRootUnexpected) - } - - if chain_spec.is_prague_active_at_timestamp(header.timestamp) { - if header.requests_root.is_none() { - return Err(ConsensusError::RequestsRootMissing) - } - } else if header.requests_root.is_some() { - return Err(ConsensusError::RequestsRootUnexpected) - } - Ok(()) } @@ -175,6 +149,7 @@ pub fn validate_4844_header_standalone(header: &SealedHeader) -> Result<(), Cons /// /// From yellow paper: extraData: An arbitrary byte array containing data relevant to this block. /// This must be 32 bytes or fewer; formally Hx. +#[inline] pub fn validate_header_extradata(header: &Header) -> Result<(), ConsensusError> { if header.extra_data.len() > MAXIMUM_EXTRA_DATA_SIZE { Err(ConsensusError::ExtraDataExceedsMax { len: header.extra_data.len() }) @@ -183,6 +158,113 @@ pub fn validate_header_extradata(header: &Header) -> Result<(), ConsensusError> } } +/// Validates against the parent hash and number. +/// +/// This function ensures that the header block number is sequential and that the hash of the parent +/// header matches the parent hash in the header. +#[inline] +pub fn validate_against_parent_hash_number( + header: &SealedHeader, + parent: &SealedHeader, +) -> Result<(), ConsensusError> { + // Parent number is consistent. + if parent.number + 1 != header.number { + return Err(ConsensusError::ParentBlockNumberMismatch { + parent_block_number: parent.number, + block_number: header.number, + }) + } + + if parent.hash() != header.parent_hash { + return Err(ConsensusError::ParentHashMismatch( + GotExpected { got: header.parent_hash, expected: parent.hash() }.into(), + )) + } + + Ok(()) +} + +/// Validates the base fee against the parent and EIP-1559 rules. +#[inline] +pub fn validate_against_parent_eip1559_base_fee( + header: &SealedHeader, + parent: &SealedHeader, + chain_spec: &ChainSpec, +) -> Result<(), ConsensusError> { + if chain_spec.fork(Hardfork::London).active_at_block(header.number) { + let base_fee = header.base_fee_per_gas.ok_or(ConsensusError::BaseFeeMissing)?; + + let expected_base_fee = + if chain_spec.fork(Hardfork::London).transitions_at_block(header.number) { + reth_primitives::constants::EIP1559_INITIAL_BASE_FEE + } else { + // This BaseFeeMissing will not happen as previous blocks are checked to have + // them. + parent + .next_block_base_fee(chain_spec.base_fee_params_at_timestamp(header.timestamp)) + .ok_or(ConsensusError::BaseFeeMissing)? + }; + if expected_base_fee != base_fee { + return Err(ConsensusError::BaseFeeDiff(GotExpected { + expected: expected_base_fee, + got: base_fee, + })) + } + } + + Ok(()) +} + +/// Validates the timestamp against the parent to make sure it is in the past. +#[inline] +pub fn validate_against_parent_timestamp( + header: &SealedHeader, + parent: &SealedHeader, +) -> Result<(), ConsensusError> { + if header.is_timestamp_in_past(parent.timestamp) { + return Err(ConsensusError::TimestampIsInPast { + parent_timestamp: parent.timestamp, + timestamp: header.timestamp, + }) + } + Ok(()) +} + +/// Validates that the EIP-4844 header fields are correct with respect to the parent block. This +/// ensures that the `blob_gas_used` and `excess_blob_gas` fields exist in the child header, and +/// that the `excess_blob_gas` field matches the expected `excess_blob_gas` calculated from the +/// parent header fields. +pub fn validate_against_parent_4844( + header: &SealedHeader, + parent: &SealedHeader, +) -> Result<(), ConsensusError> { + // From [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844#header-extension): + // + // > For the first post-fork block, both parent.blob_gas_used and parent.excess_blob_gas + // > are evaluated as 0. + // + // This means in the first post-fork block, calculate_excess_blob_gas will return 0. + let parent_blob_gas_used = parent.blob_gas_used.unwrap_or(0); + let parent_excess_blob_gas = parent.excess_blob_gas.unwrap_or(0); + + if header.blob_gas_used.is_none() { + return Err(ConsensusError::BlobGasUsedMissing) + } + let excess_blob_gas = header.excess_blob_gas.ok_or(ConsensusError::ExcessBlobGasMissing)?; + + let expected_excess_blob_gas = + calculate_excess_blob_gas(parent_excess_blob_gas, parent_blob_gas_used); + if expected_excess_blob_gas != excess_blob_gas { + return Err(ConsensusError::ExcessBlobGasDiff { + diff: GotExpected { got: excess_blob_gas, expected: expected_excess_blob_gas }, + parent_excess_blob_gas, + parent_blob_gas_used, + }) + } + + Ok(()) +} + #[cfg(test)] mod tests { use super::*; @@ -410,22 +492,6 @@ mod tests { .return_const(Ok(Some(Withdrawal { index: 2, ..Default::default() }))); } - #[test] - fn shanghai_block_zero_withdrawals() { - // ensures that if shanghai is activated, and we include a block with a withdrawals root, - // that the header is valid - let chain_spec = ChainSpecBuilder::mainnet().shanghai_activated().build(); - - let header = Header { - base_fee_per_gas: Some(1337u64), - withdrawals_root: Some(proofs::calculate_withdrawals_root(&[])), - ..Default::default() - } - .seal_slow(); - - assert_eq!(validate_header_standalone(&header, &chain_spec), Ok(())); - } - #[test] fn cancun_block_incorrect_blob_gas_used() { let chain_spec = ChainSpecBuilder::mainnet().cancun_activated().build(); diff --git a/crates/consensus/consensus/src/lib.rs b/crates/consensus/consensus/src/lib.rs index 5768fee46f..7aee9f15e7 100644 --- a/crates/consensus/consensus/src/lib.rs +++ b/crates/consensus/consensus/src/lib.rs @@ -10,8 +10,8 @@ #![cfg_attr(not(feature = "std"), no_std)] use reth_primitives::{ - BlockHash, BlockNumber, BlockWithSenders, Bloom, GotExpected, GotExpectedBoxed, Header, - HeaderValidationError, InvalidTransactionError, Receipt, Request, SealedBlock, SealedHeader, + constants::MINIMUM_GAS_LIMIT, BlockHash, BlockNumber, BlockWithSenders, Bloom, GotExpected, + GotExpectedBoxed, Header, InvalidTransactionError, Receipt, Request, SealedBlock, SealedHeader, B256, U256, }; @@ -206,6 +206,10 @@ pub enum ConsensusError { block_number: BlockNumber, }, + /// Error when the parent hash does not match the expected parent hash. + #[error("mismatched parent hash: {0}")] + ParentHashMismatch(GotExpectedBoxed), + /// Error when the block timestamp is in the future compared to our clock time. #[error("block timestamp {timestamp} is in the future compared to our clock time {present_timestamp}")] TimestampIsInFuture { @@ -329,9 +333,60 @@ pub enum ConsensusError { #[error(transparent)] InvalidTransaction(#[from] InvalidTransactionError), - /// Error type transparently wrapping `HeaderValidationError`. - #[error(transparent)] - HeaderValidationError(#[from] HeaderValidationError), + /// Error when the block's base fee is different from the expected base fee. + #[error("block base fee mismatch: {0}")] + BaseFeeDiff(GotExpected), + + /// Error when there is an invalid excess blob gas. + #[error( + "invalid excess blob gas: {diff}; \ + parent excess blob gas: {parent_excess_blob_gas}, \ + parent blob gas used: {parent_blob_gas_used}" + )] + ExcessBlobGasDiff { + /// The excess blob gas diff. + diff: GotExpected, + /// The parent excess blob gas. + parent_excess_blob_gas: u64, + /// The parent blob gas used. + parent_blob_gas_used: u64, + }, + + /// Error when the child gas limit exceeds the maximum allowed increase. + #[error("child gas_limit {child_gas_limit} max increase is {parent_gas_limit}/1024")] + GasLimitInvalidIncrease { + /// The parent gas limit. + parent_gas_limit: u64, + /// The child gas limit. + child_gas_limit: u64, + }, + + /// Error indicating that the child gas limit is below the minimum allowed limit. + /// + /// This error occurs when the child gas limit is less than the specified minimum gas limit. + #[error("child gas limit {child_gas_limit} is below the minimum allowed limit ({MINIMUM_GAS_LIMIT})")] + GasLimitInvalidMinimum { + /// The child gas limit. + child_gas_limit: u64, + }, + + /// Error when the child gas limit exceeds the maximum allowed decrease. + #[error("child gas_limit {child_gas_limit} max decrease is {parent_gas_limit}/1024")] + GasLimitInvalidDecrease { + /// The parent gas limit. + parent_gas_limit: u64, + /// The child gas limit. + child_gas_limit: u64, + }, + + /// Error when the block timestamp is in the past compared to the parent timestamp. + #[error("block timestamp {timestamp} is in the past compared to the parent timestamp {parent_timestamp}")] + TimestampIsInPast { + /// The parent block's timestamp. + parent_timestamp: u64, + /// The block's timestamp. + timestamp: u64, + }, } impl ConsensusError { diff --git a/crates/engine-primitives/src/lib.rs b/crates/engine-primitives/src/lib.rs index fd64030fc1..819584fc37 100644 --- a/crates/engine-primitives/src/lib.rs +++ b/crates/engine-primitives/src/lib.rs @@ -9,14 +9,17 @@ #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] use core::fmt; -use reth_payload_primitives::{ +pub use reth_payload_primitives::{ BuiltPayload, EngineApiMessageVersion, EngineObjectValidationError, PayloadOrAttributes, PayloadTypes, }; use reth_primitives::ChainSpec; use serde::{de::DeserializeOwned, ser::Serialize}; -/// The types that are used by the engine API. +/// This type defines the versioned types of the engine API. +/// +/// This includes the execution payload types and payload attributes that are used to trigger a +/// payload job. Hence this trait is also [`PayloadTypes`]. pub trait EngineTypes: PayloadTypes + DeserializeOwned + Serialize + fmt::Debug + Unpin + Send + Sync + Clone { diff --git a/crates/ethereum/consensus/src/lib.rs b/crates/ethereum/consensus/src/lib.rs index 2772bd8f0f..33f2b3b194 100644 --- a/crates/ethereum/consensus/src/lib.rs +++ b/crates/ethereum/consensus/src/lib.rs @@ -10,11 +10,14 @@ use reth_consensus::{Consensus, ConsensusError, PostExecutionInput}; use reth_consensus_common::validation::{ - validate_block_pre_execution, validate_header_extradata, validate_header_standalone, + validate_4844_header_standalone, validate_against_parent_4844, + validate_against_parent_eip1559_base_fee, validate_against_parent_hash_number, + validate_against_parent_timestamp, validate_block_pre_execution, validate_header_base_fee, + validate_header_extradata, validate_header_gas, }; use reth_primitives::{ - BlockWithSenders, Chain, ChainSpec, Hardfork, Header, SealedBlock, SealedHeader, - EMPTY_OMMER_ROOT_HASH, U256, + constants::MINIMUM_GAS_LIMIT, BlockWithSenders, Chain, ChainSpec, Hardfork, Header, + SealedBlock, SealedHeader, EMPTY_OMMER_ROOT_HASH, U256, }; use std::{sync::Arc, time::SystemTime}; @@ -32,14 +35,90 @@ pub struct EthBeaconConsensus { impl EthBeaconConsensus { /// Create a new instance of [`EthBeaconConsensus`] - pub fn new(chain_spec: Arc) -> Self { + pub const fn new(chain_spec: Arc) -> Self { Self { chain_spec } } + + /// Checks the gas limit for consistency between parent and self headers. + /// + /// The maximum allowable difference between self and parent gas limits is determined by the + /// parent's gas limit divided by the elasticity multiplier (1024). + fn validate_against_parent_gas_limit( + &self, + header: &SealedHeader, + parent: &SealedHeader, + ) -> Result<(), ConsensusError> { + // Determine the parent gas limit, considering elasticity multiplier on the London fork. + let parent_gas_limit = + if self.chain_spec.fork(Hardfork::London).transitions_at_block(header.number) { + parent.gas_limit * + self.chain_spec + .base_fee_params_at_timestamp(header.timestamp) + .elasticity_multiplier as u64 + } else { + parent.gas_limit + }; + + // Check for an increase in gas limit beyond the allowed threshold. + if header.gas_limit > parent_gas_limit { + if header.gas_limit - parent_gas_limit >= parent_gas_limit / 1024 { + return Err(ConsensusError::GasLimitInvalidIncrease { + parent_gas_limit, + child_gas_limit: header.gas_limit, + }) + } + } + // Check for a decrease in gas limit beyond the allowed threshold. + else if parent_gas_limit - header.gas_limit >= parent_gas_limit / 1024 { + return Err(ConsensusError::GasLimitInvalidDecrease { + parent_gas_limit, + child_gas_limit: header.gas_limit, + }) + } + // Check if the self gas limit is below the minimum required limit. + else if header.gas_limit < MINIMUM_GAS_LIMIT { + return Err(ConsensusError::GasLimitInvalidMinimum { child_gas_limit: header.gas_limit }) + } + + Ok(()) + } } impl Consensus for EthBeaconConsensus { fn validate_header(&self, header: &SealedHeader) -> Result<(), ConsensusError> { - validate_header_standalone(header, &self.chain_spec)?; + validate_header_gas(header)?; + validate_header_base_fee(header, &self.chain_spec)?; + + // EIP-4895: Beacon chain push withdrawals as operations + if self.chain_spec.is_shanghai_active_at_timestamp(header.timestamp) && + header.withdrawals_root.is_none() + { + return Err(ConsensusError::WithdrawalsRootMissing) + } else if !self.chain_spec.is_shanghai_active_at_timestamp(header.timestamp) && + header.withdrawals_root.is_some() + { + return Err(ConsensusError::WithdrawalsRootUnexpected) + } + + // Ensures that EIP-4844 fields are valid once cancun is active. + if self.chain_spec.is_cancun_active_at_timestamp(header.timestamp) { + validate_4844_header_standalone(header)?; + } else if header.blob_gas_used.is_some() { + return Err(ConsensusError::BlobGasUsedUnexpected) + } else if header.excess_blob_gas.is_some() { + return Err(ConsensusError::ExcessBlobGasUnexpected) + } else if header.parent_beacon_block_root.is_some() { + return Err(ConsensusError::ParentBeaconBlockRootUnexpected) + } + + if self.chain_spec.is_prague_active_at_timestamp(header.timestamp) { + if header.requests_root.is_none() { + return Err(ConsensusError::RequestsRootMissing) + } + } else if header.requests_root.is_some() { + return Err(ConsensusError::RequestsRootUnexpected) + } + Ok(()) } @@ -48,7 +127,21 @@ impl Consensus for EthBeaconConsensus { header: &SealedHeader, parent: &SealedHeader, ) -> Result<(), ConsensusError> { - header.validate_against_parent(parent, &self.chain_spec).map_err(ConsensusError::from)?; + validate_against_parent_hash_number(header, parent)?; + + validate_against_parent_timestamp(header, parent)?; + + // TODO Check difficulty increment between parent and self + // Ace age did increment it by some formula that we need to follow. + self.validate_against_parent_gas_limit(header, parent)?; + + validate_against_parent_eip1559_base_fee(header, parent, &self.chain_spec)?; + + // ensure that the blob gas fields for this block + if self.chain_spec.is_cancun_active_at_timestamp(header.timestamp) { + validate_against_parent_4844(header, parent)?; + } + Ok(()) } @@ -127,3 +220,97 @@ impl Consensus for EthBeaconConsensus { validate_block_post_execution(block, &self.chain_spec, input.receipts, input.requests) } } + +#[cfg(test)] +mod tests { + use reth_primitives::{proofs, ChainSpecBuilder, B256}; + + use super::*; + + fn header_with_gas_limit(gas_limit: u64) -> SealedHeader { + let header = Header { gas_limit, ..Default::default() }; + header.seal(B256::ZERO) + } + + #[test] + fn test_valid_gas_limit_increase() { + let parent = header_with_gas_limit(1024 * 10); + let child = header_with_gas_limit(parent.gas_limit + 5); + + assert_eq!( + EthBeaconConsensus::new(Arc::new(ChainSpec::default())) + .validate_against_parent_gas_limit(&child, &parent), + Ok(()) + ); + } + + #[test] + fn test_gas_limit_below_minimum() { + let parent = header_with_gas_limit(MINIMUM_GAS_LIMIT); + let child = header_with_gas_limit(MINIMUM_GAS_LIMIT - 1); + + assert_eq!( + EthBeaconConsensus::new(Arc::new(ChainSpec::default())) + .validate_against_parent_gas_limit(&child, &parent), + Err(ConsensusError::GasLimitInvalidMinimum { child_gas_limit: child.gas_limit }) + ); + } + + #[test] + fn test_invalid_gas_limit_increase_exceeding_limit() { + let parent = header_with_gas_limit(1024 * 10); + let child = header_with_gas_limit(parent.gas_limit + parent.gas_limit / 1024 + 1); + + assert_eq!( + EthBeaconConsensus::new(Arc::new(ChainSpec::default())) + .validate_against_parent_gas_limit(&child, &parent), + Err(ConsensusError::GasLimitInvalidIncrease { + parent_gas_limit: parent.gas_limit, + child_gas_limit: child.gas_limit, + }) + ); + } + + #[test] + fn test_valid_gas_limit_decrease_within_limit() { + let parent = header_with_gas_limit(1024 * 10); + let child = header_with_gas_limit(parent.gas_limit - 5); + + assert_eq!( + EthBeaconConsensus::new(Arc::new(ChainSpec::default())) + .validate_against_parent_gas_limit(&child, &parent), + Ok(()) + ); + } + + #[test] + fn test_invalid_gas_limit_decrease_exceeding_limit() { + let parent = header_with_gas_limit(1024 * 10); + let child = header_with_gas_limit(parent.gas_limit - parent.gas_limit / 1024 - 1); + + assert_eq!( + EthBeaconConsensus::new(Arc::new(ChainSpec::default())) + .validate_against_parent_gas_limit(&child, &parent), + Err(ConsensusError::GasLimitInvalidDecrease { + parent_gas_limit: parent.gas_limit, + child_gas_limit: child.gas_limit, + }) + ); + } + + #[test] + fn shanghai_block_zero_withdrawals() { + // ensures that if shanghai is activated, and we include a block with a withdrawals root, + // that the header is valid + let chain_spec = Arc::new(ChainSpecBuilder::mainnet().shanghai_activated().build()); + + let header = Header { + base_fee_per_gas: Some(1337u64), + withdrawals_root: Some(proofs::calculate_withdrawals_root(&[])), + ..Default::default() + } + .seal_slow(); + + assert_eq!(EthBeaconConsensus::new(chain_spec).validate_header(&header), Ok(())); + } +} diff --git a/crates/ethereum/engine-primitives/src/payload.rs b/crates/ethereum/engine-primitives/src/payload.rs index a802622002..e68630f4c2 100644 --- a/crates/ethereum/engine-primitives/src/payload.rs +++ b/crates/ethereum/engine-primitives/src/payload.rs @@ -39,7 +39,7 @@ pub struct EthBuiltPayload { impl EthBuiltPayload { /// Initializes the payload with the given initial block. - pub fn new(id: PayloadId, block: SealedBlock, fees: U256) -> Self { + pub const fn new(id: PayloadId, block: SealedBlock, fees: U256) -> Self { Self { id, block, fees, sidecars: Vec::new() } } diff --git a/crates/ethereum/evm/src/execute.rs b/crates/ethereum/evm/src/execute.rs index 711cee001b..bdd95851a2 100644 --- a/crates/ethereum/evm/src/execute.rs +++ b/crates/ethereum/evm/src/execute.rs @@ -54,7 +54,7 @@ impl EthExecutorProvider { impl EthExecutorProvider { /// Creates a new executor provider. - pub fn new(chain_spec: Arc, evm_config: EvmConfig) -> Self { + pub const fn new(chain_spec: Arc, evm_config: EvmConfig) -> Self { Self { chain_spec, evm_config } } } @@ -236,7 +236,7 @@ pub struct EthBlockExecutor { impl EthBlockExecutor { /// Creates a new Ethereum block executor. - pub fn new(chain_spec: Arc, evm_config: EvmConfig, state: State) -> Self { + pub const fn new(chain_spec: Arc, evm_config: EvmConfig, state: State) -> Self { Self { executor: EthEvmExecutor { chain_spec, evm_config }, state } } diff --git a/crates/evm/execution-types/src/chain.rs b/crates/evm/execution-types/src/chain.rs index 800d34f106..97bd6fcf30 100644 --- a/crates/evm/execution-types/src/chain.rs +++ b/crates/evm/execution-types/src/chain.rs @@ -488,7 +488,7 @@ pub enum ChainSplit { #[cfg(test)] mod tests { use super::*; - use reth_primitives::B256; + use reth_primitives::{Receipt, Receipts, TxType, B256}; use revm::primitives::{AccountInfo, HashMap}; #[test] @@ -625,4 +625,84 @@ mod tests { ChainSplit::NoSplitPending(chain) ); } + + #[test] + fn receipts_by_block_hash() { + // Create a default SealedBlockWithSenders object + let block: SealedBlockWithSenders = SealedBlockWithSenders::default(); + + // Define block hashes for block1 and block2 + let block1_hash = B256::new([0x01; 32]); + let block2_hash = B256::new([0x02; 32]); + + // Clone the default block into block1 and block2 + let mut block1 = block.clone(); + let mut block2 = block; + + // Set the hashes of block1 and block2 + block1.block.header.set_hash(block1_hash); + block2.block.header.set_hash(block2_hash); + + // Create a random receipt object, receipt1 + let receipt1 = Receipt { + tx_type: TxType::Legacy, + cumulative_gas_used: 46913, + logs: vec![], + success: true, + #[cfg(feature = "optimism")] + deposit_nonce: Some(18), + #[cfg(feature = "optimism")] + deposit_receipt_version: Some(34), + }; + + // Create another random receipt object, receipt2 + let receipt2 = Receipt { + tx_type: TxType::Legacy, + cumulative_gas_used: 1325345, + logs: vec![], + success: true, + #[cfg(feature = "optimism")] + deposit_nonce: Some(18), + #[cfg(feature = "optimism")] + deposit_receipt_version: Some(34), + }; + + // Create a Receipts object with a vector of receipt vectors + let receipts = + Receipts { receipt_vec: vec![vec![Some(receipt1.clone())], vec![Some(receipt2)]] }; + + // Create an ExecutionOutcome object with the created bundle, receipts, an empty requests + // vector, and first_block set to 10 + let execution_outcome = ExecutionOutcome { + bundle: Default::default(), + receipts, + requests: vec![], + first_block: 10, + }; + + // Create a Chain object with a BTreeMap of blocks mapped to their block numbers, + // including block1_hash and block2_hash, and the execution_outcome + let chain = Chain { + blocks: BTreeMap::from([(10, block1), (11, block2)]), + execution_outcome: execution_outcome.clone(), + ..Default::default() + }; + + // Assert that the proper receipt vector is returned for block1_hash + assert_eq!(chain.receipts_by_block_hash(block1_hash), Some(vec![&receipt1])); + + // Create an ExecutionOutcome object with a single receipt vector containing receipt1 + let execution_outcome1 = ExecutionOutcome { + bundle: Default::default(), + receipts: Receipts { receipt_vec: vec![vec![Some(receipt1)]] }, + requests: vec![], + first_block: 10, + }; + + // Assert that the execution outcome at the first block contains only the first receipt + assert_eq!(chain.execution_outcome_at_block(10), Some(execution_outcome1)); + + // Assert that the execution outcome at the tip block contains the whole execution outcome + assert_eq!(chain.execution_outcome_at_block(11), Some(execution_outcome)); + } } diff --git a/crates/evm/execution-types/src/bundle.rs b/crates/evm/execution-types/src/execution_outcome.rs similarity index 84% rename from crates/evm/execution-types/src/bundle.rs rename to crates/evm/execution-types/src/execution_outcome.rs index 6f1e5995da..aebc8d45b5 100644 --- a/crates/evm/execution-types/src/bundle.rs +++ b/crates/evm/execution-types/src/execution_outcome.rs @@ -216,17 +216,17 @@ impl ExecutionOutcome { &self.receipts[index] } - /// Is bundle state empty of blocks. + /// Is execution outcome empty. pub fn is_empty(&self) -> bool { self.len() == 0 } - /// Number of blocks in bundle state. + /// Number of blocks in the execution outcome. pub fn len(&self) -> usize { self.receipts.len() } - /// Return first block of the bundle + /// Return first block of the execution outcome pub const fn first_block(&self) -> BlockNumber { self.first_block } @@ -247,6 +247,8 @@ impl ExecutionOutcome { // remove receipts self.receipts.truncate(new_len); + // remove requests + self.requests.truncate(new_len); // Revert last n reverts. self.bundle.revert(rm_trx); @@ -274,6 +276,11 @@ impl ExecutionOutcome { // Truncate higher state to [at..]. let at_idx = higher_state.block_number_to_index(at).unwrap(); higher_state.receipts = higher_state.receipts.split_off(at_idx).into(); + // Ensure that there are enough requests to truncate. + // Sometimes we just have receipts and no requests. + if at_idx < higher_state.requests.len() { + higher_state.requests = higher_state.requests.split_off(at_idx); + } higher_state.bundle.take_n_reverts(at_idx); higher_state.first_block = at; @@ -595,37 +602,51 @@ mod tests { #[test] fn test_revert_to() { + // Create a random receipt object + let receipt = Receipt { + tx_type: TxType::Legacy, + cumulative_gas_used: 46913, + logs: vec![], + success: true, + #[cfg(feature = "optimism")] + deposit_nonce: Some(18), + #[cfg(feature = "optimism")] + deposit_receipt_version: Some(34), + }; + // Create a Receipts object with a vector of receipt vectors let receipts = Receipts { - receipt_vec: vec![vec![Some(Receipt { - tx_type: TxType::Legacy, - cumulative_gas_used: 46913, - logs: vec![], - success: true, - #[cfg(feature = "optimism")] - deposit_nonce: Some(18), - #[cfg(feature = "optimism")] - deposit_receipt_version: Some(34), - })]], + receipt_vec: vec![vec![Some(receipt.clone())], vec![Some(receipt.clone())]], }; // Define the first block number let first_block = 123; + // Create a DepositRequest object with specific attributes. + let request = Request::DepositRequest(DepositRequest { + pubkey: FixedBytes::<48>::from([1; 48]), + withdrawal_credentials: B256::from([0; 32]), + amount: 1111, + signature: FixedBytes::<96>::from([2; 96]), + index: 222, + }); + + // Create a vector of Requests containing the request. + let requests = vec![Requests(vec![request]), Requests(vec![request])]; + // Create a ExecutionOutcome object with the created bundle, receipts, requests, and // first_block - let mut exec_res = ExecutionOutcome { - bundle: Default::default(), - receipts: receipts.clone(), - requests: vec![], - first_block, - }; + let mut exec_res = + ExecutionOutcome { bundle: Default::default(), receipts, requests, first_block }; // Assert that the revert_to method returns true when reverting to the initial block number. assert!(exec_res.revert_to(123)); - // Assert that the receipts remain unchanged after reverting to the initial block number. - assert_eq!(exec_res.receipts, receipts); + // Assert that the receipts are properly cut after reverting to the initial block number. + assert_eq!(exec_res.receipts, Receipts { receipt_vec: vec![vec![Some(receipt)]] }); + + // Assert that the requests are properly cut after reverting to the initial block number. + assert_eq!(exec_res.requests, vec![Requests(vec![request])]); // Assert that the revert_to method returns false when attempting to revert to a block // number greater than the initial block number. @@ -688,4 +709,77 @@ mod tests { } ); } + + #[test] + fn test_split_at_execution_outcome() { + // Create a random receipt object + let receipt = Receipt { + tx_type: TxType::Legacy, + cumulative_gas_used: 46913, + logs: vec![], + success: true, + #[cfg(feature = "optimism")] + deposit_nonce: Some(18), + #[cfg(feature = "optimism")] + deposit_receipt_version: Some(34), + }; + + // Create a Receipts object with a vector of receipt vectors + let receipts = Receipts { + receipt_vec: vec![ + vec![Some(receipt.clone())], + vec![Some(receipt.clone())], + vec![Some(receipt.clone())], + ], + }; + + // Define the first block number + let first_block = 123; + + // Create a DepositRequest object with specific attributes. + let request = Request::DepositRequest(DepositRequest { + pubkey: FixedBytes::<48>::from([1; 48]), + withdrawal_credentials: B256::from([0; 32]), + amount: 1111, + signature: FixedBytes::<96>::from([2; 96]), + index: 222, + }); + + // Create a vector of Requests containing the request. + let requests = + vec![Requests(vec![request]), Requests(vec![request]), Requests(vec![request])]; + + // Create a ExecutionOutcome object with the created bundle, receipts, requests, and + // first_block + let exec_res = + ExecutionOutcome { bundle: Default::default(), receipts, requests, first_block }; + + // Split the ExecutionOutcome at block number 124 + let result = exec_res.clone().split_at(124); + + // Define the expected lower ExecutionOutcome after splitting + let lower_execution_outcome = ExecutionOutcome { + bundle: Default::default(), + receipts: Receipts { receipt_vec: vec![vec![Some(receipt.clone())]] }, + requests: vec![Requests(vec![request])], + first_block, + }; + + // Define the expected higher ExecutionOutcome after splitting + let higher_execution_outcome = ExecutionOutcome { + bundle: Default::default(), + receipts: Receipts { + receipt_vec: vec![vec![Some(receipt.clone())], vec![Some(receipt)]], + }, + requests: vec![Requests(vec![request]), Requests(vec![request])], + first_block: 124, + }; + + // Assert that the split result matches the expected lower and higher outcomes + assert_eq!(result.0, Some(lower_execution_outcome)); + assert_eq!(result.1, higher_execution_outcome); + + // Assert that splitting at the first block number returns None for the lower outcome + assert_eq!(exec_res.clone().split_at(123), (None, exec_res)); + } } diff --git a/crates/evm/execution-types/src/lib.rs b/crates/evm/execution-types/src/lib.rs index 7680e70852..0692fa57eb 100644 --- a/crates/evm/execution-types/src/lib.rs +++ b/crates/evm/execution-types/src/lib.rs @@ -8,8 +8,8 @@ #![cfg_attr(not(test), warn(unused_crate_dependencies))] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] -mod bundle; -pub use bundle::*; +mod execution_outcome; +pub use execution_outcome::*; mod chain; pub use chain::*; diff --git a/crates/net/common/Cargo.toml b/crates/net/common/Cargo.toml index c477725b55..975c2bdecc 100644 --- a/crates/net/common/Cargo.toml +++ b/crates/net/common/Cargo.toml @@ -16,4 +16,4 @@ workspace = true alloy-primitives.workspace = true # async -tokio = { workspace = true, features = ["full"] } +tokio = { workspace = true, features = ["time"] } diff --git a/crates/net/common/src/lib.rs b/crates/net/common/src/lib.rs index 9706d36620..3020abf26d 100644 --- a/crates/net/common/src/lib.rs +++ b/crates/net/common/src/lib.rs @@ -10,7 +10,4 @@ pub mod ban_list; -/// Traits related to tokio streams -pub mod stream; - pub mod ratelimit; diff --git a/crates/net/common/src/stream.rs b/crates/net/common/src/stream.rs deleted file mode 100644 index 4cf6f12bb1..0000000000 --- a/crates/net/common/src/stream.rs +++ /dev/null @@ -1,13 +0,0 @@ -use std::net::SocketAddr; -use tokio::net::TcpStream; -/// This trait is for instrumenting a `TCPStream` with a socket addr -pub trait HasRemoteAddr { - /// Maybe returns a [`SocketAddr`] - fn remote_addr(&self) -> Option; -} - -impl HasRemoteAddr for TcpStream { - fn remote_addr(&self) -> Option { - self.peer_addr().ok() - } -} diff --git a/crates/net/discv4/Cargo.toml b/crates/net/discv4/Cargo.toml index fa6a396cbb..39b19d5427 100644 --- a/crates/net/discv4/Cargo.toml +++ b/crates/net/discv4/Cargo.toml @@ -13,12 +13,13 @@ workspace = true [dependencies] # reth -reth-primitives.workspace = true reth-net-common.workspace = true +reth-ethereum-forks.workspace = true reth-net-nat.workspace = true reth-network-peers = { workspace = true, features = ["secp256k1"] } # ethereum +alloy-primitives.workspace = true alloy-rlp = { workspace = true, features = ["derive"] } discv5.workspace = true secp256k1 = { workspace = true, features = [ @@ -28,6 +29,7 @@ secp256k1 = { workspace = true, features = [ "serde", ] } enr.workspace = true + # async/futures tokio = { workspace = true, features = ["io-util", "net", "time"] } tokio-stream.workspace = true @@ -42,6 +44,7 @@ generic-array.workspace = true serde = { workspace = true, optional = true } [dev-dependencies] +reth-primitives.workspace = true assert_matches.workspace = true rand.workspace = true tokio = { workspace = true, features = ["macros"] } diff --git a/crates/net/discv4/src/config.rs b/crates/net/discv4/src/config.rs index 43030e70a3..174514d98c 100644 --- a/crates/net/discv4/src/config.rs +++ b/crates/net/discv4/src/config.rs @@ -3,10 +3,11 @@ //! This basis of this file has been taken from the discv5 codebase: //! +use alloy_primitives::bytes::Bytes; use alloy_rlp::Encodable; use reth_net_common::ban_list::BanList; use reth_net_nat::{NatResolver, ResolveNatInterval}; -use reth_primitives::{bytes::Bytes, NodeRecord}; +use reth_network_peers::NodeRecord; #[cfg(feature = "serde")] use serde::{Deserialize, Serialize}; use std::{ diff --git a/crates/net/discv4/src/lib.rs b/crates/net/discv4/src/lib.rs index f0f7a9b0a1..52e388a0ab 100644 --- a/crates/net/discv4/src/lib.rs +++ b/crates/net/discv4/src/lib.rs @@ -28,6 +28,7 @@ use crate::{ error::{DecodePacketError, Discv4Error}, proto::{FindNode, Message, Neighbours, Packet, Ping, Pong}, }; +use alloy_primitives::{bytes::Bytes, hex, B256}; use discv5::{ kbucket, kbucket::{ @@ -39,8 +40,8 @@ use discv5::{ use enr::Enr; use parking_lot::Mutex; use proto::{EnrRequest, EnrResponse}; +use reth_ethereum_forks::ForkId; use reth_network_peers::{pk2id, PeerId}; -use reth_primitives::{bytes::Bytes, hex, ForkId, B256}; use secp256k1::SecretKey; use std::{ cell::RefCell, @@ -76,7 +77,7 @@ use node::{kad_key, NodeKey}; mod table; // reexport NodeRecord primitive -pub use reth_primitives::NodeRecord; +pub use reth_network_peers::NodeRecord; #[cfg(any(test, feature = "test-utils"))] pub mod test_utils; diff --git a/crates/net/discv4/src/node.rs b/crates/net/discv4/src/node.rs index 0a8f436c3f..242c388322 100644 --- a/crates/net/discv4/src/node.rs +++ b/crates/net/discv4/src/node.rs @@ -1,6 +1,6 @@ +use alloy_primitives::keccak256; use generic_array::GenericArray; -use reth_network_peers::PeerId; -use reth_primitives::{keccak256, NodeRecord}; +use reth_network_peers::{NodeRecord, PeerId}; /// The key type for the table. #[derive(Debug, Copy, Clone, Eq, PartialEq)] diff --git a/crates/net/discv4/src/proto.rs b/crates/net/discv4/src/proto.rs index c319b164e0..610628d56b 100644 --- a/crates/net/discv4/src/proto.rs +++ b/crates/net/discv4/src/proto.rs @@ -1,13 +1,14 @@ //! Discovery v4 protocol implementation. use crate::{error::DecodePacketError, MAX_PACKET_SIZE, MIN_PACKET_SIZE}; +use alloy_primitives::{ + bytes::{Buf, BufMut, Bytes, BytesMut}, + keccak256, B256, +}; use alloy_rlp::{Decodable, Encodable, Error as RlpError, Header, RlpDecodable, RlpEncodable}; use enr::Enr; -use reth_network_peers::{pk2id, PeerId}; -use reth_primitives::{ - bytes::{Buf, BufMut, Bytes, BytesMut}, - keccak256, EnrForkIdEntry, ForkId, NodeRecord, B256, -}; +use reth_ethereum_forks::{EnrForkIdEntry, ForkId}; +use reth_network_peers::{pk2id, NodeRecord, PeerId}; use secp256k1::{ ecdsa::{RecoverableSignature, RecoveryId}, SecretKey, SECP256K1, diff --git a/crates/net/discv4/src/test_utils.rs b/crates/net/discv4/src/test_utils.rs index 49521ec694..06133dba67 100644 --- a/crates/net/discv4/src/test_utils.rs +++ b/crates/net/discv4/src/test_utils.rs @@ -5,9 +5,10 @@ use crate::{ receive_loop, send_loop, Discv4, Discv4Config, Discv4Service, EgressSender, IngressEvent, IngressReceiver, PeerId, SAFE_MAX_DATAGRAM_NEIGHBOUR_RECORDS, }; +use alloy_primitives::{hex, B256}; use rand::{thread_rng, Rng, RngCore}; -use reth_network_peers::pk2id; -use reth_primitives::{hex, ForkHash, ForkId, NodeRecord, B256}; +use reth_ethereum_forks::{ForkHash, ForkId}; +use reth_network_peers::{pk2id, NodeRecord}; use secp256k1::{SecretKey, SECP256K1}; use std::{ collections::{HashMap, HashSet}, diff --git a/crates/net/dns/Cargo.toml b/crates/net/dns/Cargo.toml index 7859383014..5b4b75c2f1 100644 --- a/crates/net/dns/Cargo.toml +++ b/crates/net/dns/Cargo.toml @@ -13,11 +13,12 @@ workspace = true [dependencies] # reth -reth-primitives.workspace = true +reth-ethereum-forks.workspace = true reth-net-common.workspace = true reth-network-peers = { workspace = true, features = ["secp256k1"] } # ethereum +alloy-primitives.workspace = true secp256k1 = { workspace = true, features = ["global-context", "rand-std", "recovery", "serde"] } enr.workspace = true @@ -30,16 +31,18 @@ trust-dns-resolver = "0.23" # misc data-encoding = "2" -linked_hash_set = "0.1" +linked_hash_set.workspace = true schnellru.workspace = true thiserror.workspace = true tracing.workspace = true parking_lot.workspace = true serde = { workspace = true, optional = true } -serde_with = { version = "3.3.0", optional = true } +serde_with = { workspace = true, optional = true } [dev-dependencies] +reth-primitives.workspace = true alloy-rlp.workspace = true +alloy-chains.workspace = true tokio = { workspace = true, features = ["sync", "rt", "rt-multi-thread"] } reth-tracing.workspace = true rand.workspace = true diff --git a/crates/net/dns/src/lib.rs b/crates/net/dns/src/lib.rs index 4edcdbeb31..432cef4518 100644 --- a/crates/net/dns/src/lib.rs +++ b/crates/net/dns/src/lib.rs @@ -22,8 +22,8 @@ use crate::{ pub use config::DnsDiscoveryConfig; use enr::Enr; use error::ParseDnsEntryError; -use reth_network_peers::pk2id; -use reth_primitives::{EnrForkIdEntry, ForkId, NodeRecord}; +use reth_ethereum_forks::{EnrForkIdEntry, ForkId}; +use reth_network_peers::{pk2id, NodeRecord}; use schnellru::{ByLength, LruMap}; use secp256k1::SecretKey; use std::{ @@ -411,9 +411,11 @@ fn convert_enr_node_record(enr: &Enr) -> Option mod tests { use super::*; use crate::tree::TreeRootEntry; + use alloy_chains::Chain; use alloy_rlp::{Decodable, Encodable}; use enr::EnrKey; - use reth_primitives::{Chain, ForkHash, Hardfork, MAINNET}; + use reth_ethereum_forks::{ForkHash, Hardfork}; + use reth_primitives::MAINNET; use secp256k1::rand::thread_rng; use std::{future::poll_fn, net::Ipv4Addr}; diff --git a/crates/net/dns/src/tree.rs b/crates/net/dns/src/tree.rs index 0491be4231..80182b694f 100644 --- a/crates/net/dns/src/tree.rs +++ b/crates/net/dns/src/tree.rs @@ -21,9 +21,9 @@ use crate::error::{ ParseDnsEntryError::{FieldNotFound, UnknownEntry}, ParseEntryResult, }; +use alloy_primitives::{hex, Bytes}; use data_encoding::{BASE32_NOPAD, BASE64URL_NOPAD}; use enr::{Enr, EnrKey, EnrKeyUnambiguous, EnrPublicKey, Error as EnrError}; -use reth_primitives::{hex, Bytes}; use secp256k1::SecretKey; #[cfg(feature = "serde")] use serde_with::{DeserializeFromStr, SerializeDisplay}; diff --git a/crates/net/ecies/Cargo.toml b/crates/net/ecies/Cargo.toml index c4dc29df9e..eb2a0b023b 100644 --- a/crates/net/ecies/Cargo.toml +++ b/crates/net/ecies/Cargo.toml @@ -11,19 +11,18 @@ repository.workspace = true workspace = true [dependencies] -reth-primitives.workspace = true -reth-net-common.workspace = true reth-network-peers = { workspace = true, features = ["secp256k1"] } -alloy-rlp = { workspace = true, features = ["derive"] } +alloy-primitives = { workspace = true, features = ["rand", "rlp"] } +alloy-rlp = { workspace = true, features = ["derive", "arrayvec"] } + futures.workspace = true thiserror.workspace = true -tokio = { workspace = true, features = ["full"] } +tokio = { workspace = true, features = ["time"] } tokio-stream.workspace = true tokio-util = { workspace = true, features = ["codec"] } pin-project.workspace = true -educe = "0.4.19" tracing.workspace = true # HeaderBytes @@ -37,7 +36,7 @@ ctr = "0.9.2" digest = "0.10.5" secp256k1 = { workspace = true, features = ["global-context", "rand-std", "recovery"] } concat-kdf = "0.1.0" -sha2 = "0.10.6" +sha2.workspace = true sha3 = "0.10.5" aes = "0.8.1" hmac = "0.12.1" diff --git a/crates/net/ecies/src/algorithm.rs b/crates/net/ecies/src/algorithm.rs index d76502457d..83dcc657bc 100644 --- a/crates/net/ecies/src/algorithm.rs +++ b/crates/net/ecies/src/algorithm.rs @@ -7,17 +7,16 @@ use crate::{ ECIESError, }; use aes::{cipher::StreamCipher, Aes128, Aes256}; +use alloy_primitives::{ + bytes::{BufMut, Bytes, BytesMut}, + B128, B256, B512 as PeerId, +}; use alloy_rlp::{Encodable, Rlp, RlpEncodable, RlpMaxEncodedLen}; use byteorder::{BigEndian, ByteOrder, ReadBytesExt}; use ctr::Ctr64BE; use digest::{crypto_common::KeyIvInit, Digest}; -use educe::Educe; use rand::{thread_rng, Rng}; use reth_network_peers::{id2pk, pk2id}; -use reth_primitives::{ - bytes::{BufMut, Bytes, BytesMut}, - B128, B256, B512 as PeerId, -}; use secp256k1::{ ecdsa::{RecoverableSignature, RecoveryId}, PublicKey, SecretKey, SECP256K1, @@ -51,17 +50,13 @@ fn kdf(secret: B256, s1: &[u8], dest: &mut [u8]) { concat_kdf::derive_key_into::(secret.as_slice(), s1, dest).unwrap(); } -#[derive(Educe)] -#[educe(Debug)] pub struct ECIES { - #[educe(Debug(ignore))] secret_key: SecretKey, public_key: PublicKey, remote_public_key: Option, pub(crate) remote_id: Option, - #[educe(Debug(ignore))] ephemeral_secret_key: SecretKey, ephemeral_public_key: PublicKey, ephemeral_shared_secret: Option, @@ -70,9 +65,7 @@ pub struct ECIES { nonce: B256, remote_nonce: Option, - #[educe(Debug(ignore))] ingress_aes: Option>, - #[educe(Debug(ignore))] egress_aes: Option>, ingress_mac: Option, egress_mac: Option, @@ -83,6 +76,27 @@ pub struct ECIES { body_size: Option, } +impl core::fmt::Debug for ECIES { + #[inline] + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("ECIES") + .field("public_key", &self.public_key) + .field("remote_public_key", &self.remote_public_key) + .field("remote_id", &self.remote_id) + .field("ephemeral_public_key", &self.ephemeral_public_key) + .field("ephemeral_shared_secret", &self.ephemeral_shared_secret) + .field("remote_ephemeral_public_key", &self.remote_ephemeral_public_key) + .field("nonce", &self.nonce) + .field("remote_nonce", &self.remote_nonce) + .field("ingress_mac", &self.ingress_mac) + .field("egress_mac", &self.egress_mac) + .field("init_msg", &self.init_msg) + .field("remote_init_msg", &self.remote_init_msg) + .field("body_size", &self.body_size) + .finish() + } +} + fn split_at_mut(arr: &mut [T], idx: usize) -> Result<(&mut [T], &mut [T]), ECIESError> { if idx > arr.len() { return Err(ECIESErrorImpl::OutOfBounds { idx, len: arr.len() }.into()) @@ -721,7 +735,7 @@ impl ECIES { #[cfg(test)] mod tests { use super::*; - use reth_primitives::{b256, hex}; + use alloy_primitives::{b256, hex}; #[test] fn ecdh() { diff --git a/crates/net/ecies/src/codec.rs b/crates/net/ecies/src/codec.rs index 890113fd69..7ad30d38d0 100644 --- a/crates/net/ecies/src/codec.rs +++ b/crates/net/ecies/src/codec.rs @@ -1,5 +1,5 @@ use crate::{algorithm::ECIES, ECIESError, EgressECIESValue, IngressECIESValue}; -use reth_primitives::{BytesMut, B512 as PeerId}; +use alloy_primitives::{bytes::BytesMut, B512 as PeerId}; use secp256k1::SecretKey; use std::{fmt::Debug, io}; use tokio_util::codec::{Decoder, Encoder}; diff --git a/crates/net/ecies/src/lib.rs b/crates/net/ecies/src/lib.rs index 07fb044c5c..378398d6ba 100644 --- a/crates/net/ecies/src/lib.rs +++ b/crates/net/ecies/src/lib.rs @@ -18,7 +18,7 @@ pub use error::ECIESError; mod codec; -use reth_primitives::{ +use alloy_primitives::{ bytes::{Bytes, BytesMut}, B512 as PeerId, }; diff --git a/crates/net/ecies/src/mac.rs b/crates/net/ecies/src/mac.rs index 30baa298c9..03847d091e 100644 --- a/crates/net/ecies/src/mac.rs +++ b/crates/net/ecies/src/mac.rs @@ -10,11 +10,11 @@ //! For more information, refer to the [Ethereum MAC specification](https://github.com/ethereum/devp2p/blob/master/rlpx.md#mac). use aes::Aes256Enc; +use alloy_primitives::{B128, B256}; use block_padding::NoPadding; use cipher::BlockEncrypt; use digest::KeyInit; use generic_array::GenericArray; -use reth_primitives::{B128, B256}; use sha3::{Digest, Keccak256}; use typenum::U16; diff --git a/crates/net/ecies/src/stream.rs b/crates/net/ecies/src/stream.rs index 02c834fe0d..dbd7577a35 100644 --- a/crates/net/ecies/src/stream.rs +++ b/crates/net/ecies/src/stream.rs @@ -3,12 +3,11 @@ use crate::{ codec::ECIESCodec, error::ECIESErrorImpl, ECIESError, EgressECIESValue, IngressECIESValue, }; -use futures::{ready, Sink, SinkExt}; -use reth_net_common::stream::HasRemoteAddr; -use reth_primitives::{ +use alloy_primitives::{ bytes::{Bytes, BytesMut}, B512 as PeerId, }; +use futures::{ready, Sink, SinkExt}; use secp256k1::SecretKey; use std::{ fmt::Debug, @@ -38,10 +37,10 @@ pub struct ECIESStream { impl ECIESStream where - Io: AsyncRead + AsyncWrite + Unpin + HasRemoteAddr, + Io: AsyncRead + AsyncWrite + Unpin, { /// Connect to an `ECIES` server - #[instrument(skip(transport, secret_key), fields(peer=&*format!("{:?}", transport.remote_addr())))] + #[instrument(skip(transport, secret_key))] pub async fn connect( transport: Io, secret_key: SecretKey, @@ -98,7 +97,6 @@ where } /// Listen on a just connected ECIES client - #[instrument(skip_all, fields(peer=&*format!("{:?}", transport.remote_addr())))] pub async fn incoming(transport: Io, secret_key: SecretKey) -> Result { let ecies = ECIESCodec::new_server(secret_key)?; diff --git a/crates/net/ecies/src/util.rs b/crates/net/ecies/src/util.rs index f6b30288a4..cffd1f19de 100644 --- a/crates/net/ecies/src/util.rs +++ b/crates/net/ecies/src/util.rs @@ -1,7 +1,7 @@ //! Utility functions for hashing and encoding. +use alloy_primitives::B256; use hmac::{Hmac, Mac}; -use reth_primitives::B256; use sha2::{Digest, Sha256}; /// Hashes the input data with SHA256. diff --git a/crates/net/network/src/discovery.rs b/crates/net/network/src/discovery.rs index 38346ec1d0..07d24859ed 100644 --- a/crates/net/network/src/discovery.rs +++ b/crates/net/network/src/discovery.rs @@ -71,14 +71,17 @@ impl Discovery { /// This will spawn the [`reth_discv4::Discv4Service`] onto a new task and establish a listener /// channel to receive all discovered nodes. pub async fn new( + tcp_addr: SocketAddr, discovery_v4_addr: SocketAddr, sk: SecretKey, discv4_config: Option, discv5_config: Option, // contains discv5 listen address dns_discovery_config: Option, ) -> Result { - // setup discv4 - let local_enr = NodeRecord::from_secret_key(discovery_v4_addr, &sk); + // setup discv4 with the discovery address and tcp port + let local_enr = + NodeRecord::from_secret_key(discovery_v4_addr, &sk).with_tcp_port(tcp_addr.port()); + let discv4_future = async { let Some(disc_config) = discv4_config else { return Ok((None, None, None)) }; let (discv4, mut discv4_service) = @@ -342,6 +345,7 @@ mod tests { let (secret_key, _) = SECP256K1.generate_keypair(&mut rng); let discovery_addr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, 0)); let _discovery = Discovery::new( + discovery_addr, discovery_addr, secret_key, Default::default(), @@ -370,9 +374,16 @@ mod tests { .discv5_config(discv5::ConfigBuilder::new(discv5_listen_config).build()) .build(); - Discovery::new(discv4_addr, secret_key, Some(discv4_config), Some(discv5_config), None) - .await - .expect("should build discv5 with discv4 downgrade") + Discovery::new( + discv4_addr, + discv4_addr, + secret_key, + Some(discv4_config), + Some(discv5_config), + None, + ) + .await + .expect("should build discv5 with discv4 downgrade") } #[tokio::test(flavor = "multi_thread")] diff --git a/crates/net/network/src/listener.rs b/crates/net/network/src/listener.rs index d0654042ab..9fcc15a104 100644 --- a/crates/net/network/src/listener.rs +++ b/crates/net/network/src/listener.rs @@ -1,7 +1,6 @@ //! Contains connection-oriented interfaces. use futures::{ready, Stream}; - use std::{ io, net::SocketAddr, diff --git a/crates/net/network/src/manager.rs b/crates/net/network/src/manager.rs index a3fdefffab..7a4092d4a4 100644 --- a/crates/net/network/src/manager.rs +++ b/crates/net/network/src/manager.rs @@ -197,7 +197,9 @@ where let incoming = ConnectionListener::bind(listener_addr).await.map_err(|err| { NetworkError::from_io_error(err, ServiceKind::Listener(listener_addr)) })?; - let listener_address = Arc::new(Mutex::new(incoming.local_address())); + + // retrieve the tcp address of the socket + let listener_addr = incoming.local_address(); // resolve boot nodes let mut resolved_boot_nodes = vec![]; @@ -214,6 +216,7 @@ where }); let discovery = Discovery::new( + listener_addr, discovery_v4_addr, secret_key, discovery_v4_config, @@ -248,7 +251,7 @@ where let handle = NetworkHandle::new( Arc::clone(&num_active_peers), - listener_address, + Arc::new(Mutex::new(listener_addr)), to_manager_tx, secret_key, local_peer_id, @@ -314,7 +317,7 @@ where NetworkBuilder { network: self, transactions: (), request_handler: () } } - /// Returns the [`SocketAddr`] that listens for incoming connections. + /// Returns the [`SocketAddr`] that listens for incoming tcp connections. pub const fn local_addr(&self) -> SocketAddr { self.swarm.listener().local_address() } diff --git a/crates/net/network/src/session/mod.rs b/crates/net/network/src/session/mod.rs index ab5a9634cf..4f6be86317 100644 --- a/crates/net/network/src/session/mod.rs +++ b/crates/net/network/src/session/mod.rs @@ -15,7 +15,6 @@ use reth_eth_wire::{ UnauthedP2PStream, }; use reth_metrics::common::mpsc::MeteredPollSender; -use reth_net_common::stream::HasRemoteAddr; use reth_network_peers::PeerId; use reth_primitives::{ForkFilter, ForkId, ForkTransition, Head}; use reth_tasks::TaskSpawner; @@ -927,7 +926,7 @@ async fn authenticate( /// Returns an [`ECIESStream`] if it can be built. If not, send a /// [`PendingSessionEvent::EciesAuthError`] and returns `None` -async fn get_eciess_stream( +async fn get_eciess_stream( stream: Io, secret_key: SecretKey, direction: Direction, diff --git a/crates/net/network/src/transactions/fetcher.rs b/crates/net/network/src/transactions/fetcher.rs index e1f89a6a4c..41081b1915 100644 --- a/crates/net/network/src/transactions/fetcher.rs +++ b/crates/net/network/src/transactions/fetcher.rs @@ -1152,7 +1152,7 @@ pub struct GetPooledTxRequestFut { impl GetPooledTxRequestFut { #[inline] - fn new( + const fn new( peer_id: PeerId, requested_hashes: RequestTxHashes, response: oneshot::Receiver>, diff --git a/crates/net/network/tests/it/startup.rs b/crates/net/network/tests/it/startup.rs index 0bef94e08c..e924d322d1 100644 --- a/crates/net/network/tests/it/startup.rs +++ b/crates/net/network/tests/it/startup.rs @@ -3,7 +3,7 @@ use reth_network::{ error::{NetworkError, ServiceKind}, Discovery, NetworkConfigBuilder, NetworkManager, }; -use reth_network_api::NetworkInfo; +use reth_network_api::{NetworkInfo, PeersInfo}; use reth_provider::test_utils::NoopProvider; use secp256k1::SecretKey; use std::{ @@ -59,8 +59,46 @@ async fn test_discovery_addr_in_use() { let any_port_listener = TcpListener::bind(addr).await.unwrap(); let port = any_port_listener.local_addr().unwrap().port(); let addr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, port)); - let _discovery = Discovery::new(addr, secret_key, Some(disc_config), None, None).await.unwrap(); + let _discovery = + Discovery::new(addr, addr, secret_key, Some(disc_config), None, None).await.unwrap(); let disc_config = Discv4Config::default(); - let result = Discovery::new(addr, secret_key, Some(disc_config), None, None).await; + let result = Discovery::new(addr, addr, secret_key, Some(disc_config), None, None).await; assert!(is_addr_in_use_kind(&result.err().unwrap(), ServiceKind::Discovery(addr))); } + +// +#[tokio::test(flavor = "multi_thread")] +async fn test_tcp_port_node_record_no_discovery() { + let secret_key = SecretKey::new(&mut rand::thread_rng()); + let config = NetworkConfigBuilder::new(secret_key) + .listener_port(0) + .disable_discovery() + .build_with_noop_provider(); + let network = NetworkManager::new(config).await.unwrap(); + + let local_addr = network.local_addr(); + // ensure we retrieved the port the OS chose + assert_ne!(local_addr.port(), 0); + + let record = network.handle().local_node_record(); + assert_eq!(record.tcp_port, local_addr.port()); +} + +// +#[tokio::test(flavor = "multi_thread")] +async fn test_tcp_port_node_record_discovery() { + let secret_key = SecretKey::new(&mut rand::thread_rng()); + let config = NetworkConfigBuilder::new(secret_key) + .listener_port(0) + .discovery_port(0) + .build_with_noop_provider(); + let network = NetworkManager::new(config).await.unwrap(); + + let local_addr = network.local_addr(); + // ensure we retrieved the port the OS chose + assert_ne!(local_addr.port(), 0); + + let record = network.handle().local_node_record(); + assert_eq!(record.tcp_port, local_addr.port()); + assert_ne!(record.udp_port, 0); +} diff --git a/crates/net/p2p/src/test_utils/headers.rs b/crates/net/p2p/src/test_utils/headers.rs index 706ceded99..73dd04849d 100644 --- a/crates/net/p2p/src/test_utils/headers.rs +++ b/crates/net/p2p/src/test_utils/headers.rs @@ -38,7 +38,7 @@ pub struct TestHeaderDownloader { impl TestHeaderDownloader { /// Instantiates the downloader with the mock responses - pub fn new( + pub const fn new( client: TestHeadersClient, consensus: Arc, limit: u64, diff --git a/crates/net/peers/src/node_record.rs b/crates/net/peers/src/node_record.rs index 99ca74b569..3b6c38170d 100644 --- a/crates/net/peers/src/node_record.rs +++ b/crates/net/peers/src/node_record.rs @@ -42,8 +42,10 @@ pub struct NodeRecord { } impl NodeRecord { + /// Derive the [`NodeRecord`] from the secret key and addr. + /// + /// Note: this will set both the TCP and UDP ports to the port of the addr. #[cfg(feature = "secp256k1")] - /// Derive the [`NodeRecord`] from the secret key and addr pub fn from_secret_key(addr: SocketAddr, sk: &secp256k1::SecretKey) -> Self { let pk = secp256k1::PublicKey::from_secret_key(secp256k1::SECP256K1, sk); let id = PeerId::from_slice(&pk.serialize_uncompressed()[1..]); @@ -73,8 +75,19 @@ impl NodeRecord { self } + /// Sets the tcp port + pub const fn with_tcp_port(mut self, port: u16) -> Self { + self.tcp_port = port; + self + } + + /// Sets the udp port + pub const fn with_udp_port(mut self, port: u16) -> Self { + self.udp_port = port; + self + } + /// Creates a new record from a socket addr and peer id. - #[allow(dead_code)] pub const fn new(addr: SocketAddr, id: PeerId) -> Self { Self { address: addr.ip(), tcp_port: addr.port(), udp_port: addr.port(), id } } diff --git a/crates/node-core/src/args/network.rs b/crates/node-core/src/args/network.rs index 93e4d8db1b..c91e864048 100644 --- a/crates/node-core/src/args/network.rs +++ b/crates/node-core/src/args/network.rs @@ -205,7 +205,7 @@ impl NetworkArgs { /// Sets the p2p and discovery ports to zero, allowing the OD to assign a random unused port /// when network components bind to sockets. - pub fn with_unused_ports(mut self) -> Self { + pub const fn with_unused_ports(mut self) -> Self { self = self.with_unused_p2p_port(); self.discovery = self.discovery.with_unused_discovery_port(); self diff --git a/crates/node-core/src/engine/engine_store.rs b/crates/node-core/src/engine/engine_store.rs index 21e3c370a8..c6e2b65c5b 100644 --- a/crates/node-core/src/engine/engine_store.rs +++ b/crates/node-core/src/engine/engine_store.rs @@ -129,7 +129,7 @@ pub struct EngineStoreStream { impl EngineStoreStream { /// Create new engine store stream wrapper. - pub fn new(stream: S, path: PathBuf) -> Self { + pub const fn new(stream: S, path: PathBuf) -> Self { Self { stream, store: EngineMessageStore::new(path) } } } diff --git a/crates/node-core/src/exit.rs b/crates/node-core/src/exit.rs index 85adf6cb66..7957af1854 100644 --- a/crates/node-core/src/exit.rs +++ b/crates/node-core/src/exit.rs @@ -22,7 +22,7 @@ pub struct NodeExitFuture { impl NodeExitFuture { /// Create a new `NodeExitFuture`. - pub fn new( + pub const fn new( consensus_engine_rx: oneshot::Receiver>, terminate: bool, ) -> Self { diff --git a/crates/node/builder/src/builder/states.rs b/crates/node/builder/src/builder/states.rs index a20f7eaa71..8f09d5edd9 100644 --- a/crates/node/builder/src/builder/states.rs +++ b/crates/node/builder/src/builder/states.rs @@ -31,7 +31,7 @@ pub struct NodeBuilderWithTypes { impl NodeBuilderWithTypes { /// Creates a new instance of the node builder with the given configuration and types. - pub fn new(config: NodeConfig, database: T::DB) -> Self { + pub const fn new(config: NodeConfig, database: T::DB) -> Self { Self { config, adapter: NodeTypesAdapter::new(database) } } diff --git a/crates/node/events/Cargo.toml b/crates/node/events/Cargo.toml index 4ae2a6f768..1b14c74de5 100644 --- a/crates/node/events/Cargo.toml +++ b/crates/node/events/Cargo.toml @@ -20,7 +20,9 @@ reth-prune.workspace = true reth-static-file.workspace = true reth-db-api.workspace = true reth-primitives.workspace = true -reth-rpc-types.workspace = true + +# alloy +alloy-rpc-types-engine.workspace = true # async tokio.workspace = true diff --git a/crates/node/events/src/node.rs b/crates/node/events/src/node.rs index 1fc62a9b61..8a25c37003 100644 --- a/crates/node/events/src/node.rs +++ b/crates/node/events/src/node.rs @@ -1,6 +1,7 @@ //! Support for handling events emitted by node components. use crate::cl::ConsensusLayerHealthEvent; +use alloy_rpc_types_engine::ForkchoiceState; use futures::Stream; use reth_beacon_consensus::{ BeaconConsensusEngineEvent, ConsensusEngineLiveSyncProgress, ForkchoiceStatus, @@ -10,7 +11,6 @@ use reth_network::{NetworkEvent, NetworkHandle}; use reth_network_api::PeersInfo; use reth_primitives::{constants, BlockNumber, B256}; use reth_prune::PrunerEvent; -use reth_rpc_types::engine::ForkchoiceState; use reth_stages::{EntitiesCheckpoint, ExecOutput, PipelineEvent, StageCheckpoint, StageId}; use reth_static_file::StaticFileProducerEvent; use std::{ diff --git a/crates/optimism/consensus/src/lib.rs b/crates/optimism/consensus/src/lib.rs index 5ac9cf924f..691ab58c77 100644 --- a/crates/optimism/consensus/src/lib.rs +++ b/crates/optimism/consensus/src/lib.rs @@ -11,7 +11,10 @@ use reth_consensus::{Consensus, ConsensusError, PostExecutionInput}; use reth_consensus_common::validation::{ - validate_block_pre_execution, validate_header_extradata, validate_header_standalone, + validate_against_parent_4844, validate_against_parent_eip1559_base_fee, + validate_against_parent_hash_number, validate_against_parent_timestamp, + validate_block_pre_execution, validate_header_base_fee, validate_header_extradata, + validate_header_gas, }; use reth_primitives::{ BlockWithSenders, ChainSpec, Header, SealedBlock, SealedHeader, EMPTY_OMMER_ROOT_HASH, U256, @@ -44,8 +47,8 @@ impl OptimismBeaconConsensus { impl Consensus for OptimismBeaconConsensus { fn validate_header(&self, header: &SealedHeader) -> Result<(), ConsensusError> { - validate_header_standalone(header, &self.chain_spec)?; - Ok(()) + validate_header_gas(header)?; + validate_header_base_fee(header, &self.chain_spec) } fn validate_header_against_parent( @@ -53,7 +56,19 @@ impl Consensus for OptimismBeaconConsensus { header: &SealedHeader, parent: &SealedHeader, ) -> Result<(), ConsensusError> { - header.validate_against_parent(parent, &self.chain_spec).map_err(ConsensusError::from)?; + validate_against_parent_hash_number(header, parent)?; + + if self.chain_spec.is_bedrock_active_at_block(header.number) { + validate_against_parent_timestamp(header, parent)?; + } + + validate_against_parent_eip1559_base_fee(header, parent, &self.chain_spec)?; + + // ensure that the blob gas fields for this block + if self.chain_spec.is_cancun_active_at_timestamp(header.timestamp) { + validate_against_parent_4844(header, parent)?; + } + Ok(()) } diff --git a/crates/optimism/evm/src/execute.rs b/crates/optimism/evm/src/execute.rs index ee6d2e67d7..45a9b9e4d0 100644 --- a/crates/optimism/evm/src/execute.rs +++ b/crates/optimism/evm/src/execute.rs @@ -44,7 +44,7 @@ impl OpExecutorProvider { impl OpExecutorProvider { /// Creates a new executor provider. - pub fn new(chain_spec: Arc, evm_config: EvmConfig) -> Self { + pub const fn new(chain_spec: Arc, evm_config: EvmConfig) -> Self { Self { chain_spec, evm_config } } } @@ -236,7 +236,7 @@ pub struct OpBlockExecutor { impl OpBlockExecutor { /// Creates a new Ethereum block executor. - pub fn new(chain_spec: Arc, evm_config: EvmConfig, state: State) -> Self { + pub const fn new(chain_spec: Arc, evm_config: EvmConfig, state: State) -> Self { Self { executor: OpEvmExecutor { chain_spec, evm_config }, state } } diff --git a/crates/optimism/payload/src/payload.rs b/crates/optimism/payload/src/payload.rs index 7f9bd1ce78..b969c14d5f 100644 --- a/crates/optimism/payload/src/payload.rs +++ b/crates/optimism/payload/src/payload.rs @@ -179,7 +179,7 @@ pub struct OptimismBuiltPayload { impl OptimismBuiltPayload { /// Initializes the payload with the given initial block. - pub fn new( + pub const fn new( id: PayloadId, block: SealedBlock, fees: U256, diff --git a/crates/payload/basic/Cargo.toml b/crates/payload/basic/Cargo.toml index 68464d7f45..af64966ee4 100644 --- a/crates/payload/basic/Cargo.toml +++ b/crates/payload/basic/Cargo.toml @@ -27,7 +27,7 @@ revm.workspace = true # async tokio = { workspace = true, features = ["sync", "time"] } -futures-core = "0.3" +futures-core.workspace = true futures-util.workspace = true # metrics diff --git a/crates/payload/basic/src/lib.rs b/crates/payload/basic/src/lib.rs index d74bf1d77c..c31a6f0ec7 100644 --- a/crates/payload/basic/src/lib.rs +++ b/crates/payload/basic/src/lib.rs @@ -636,7 +636,7 @@ pub struct PendingPayload

{ impl

PendingPayload

{ /// Constructs a `PendingPayload` future. - pub fn new( + pub const fn new( cancel: Cancelled, payload: oneshot::Receiver, PayloadBuilderError>>, ) -> Self { @@ -773,7 +773,7 @@ pub struct BuildArguments { impl BuildArguments { /// Create new build arguments. - pub fn new( + pub const fn new( client: Client, pool: Pool, cached_reads: CachedReads, diff --git a/crates/payload/validator/src/lib.rs b/crates/payload/validator/src/lib.rs index eced6a4814..d63d0f3085 100644 --- a/crates/payload/validator/src/lib.rs +++ b/crates/payload/validator/src/lib.rs @@ -22,7 +22,7 @@ pub struct ExecutionPayloadValidator { impl ExecutionPayloadValidator { /// Create a new validator. - pub fn new(chain_spec: Arc) -> Self { + pub const fn new(chain_spec: Arc) -> Self { Self { chain_spec } } diff --git a/crates/primitives-traits/Cargo.toml b/crates/primitives-traits/Cargo.toml index 50c5f3c249..11f714779f 100644 --- a/crates/primitives-traits/Cargo.toml +++ b/crates/primitives-traits/Cargo.toml @@ -14,9 +14,15 @@ workspace = true [dependencies] reth-codecs.workspace = true +alloy-consensus.workspace = true +alloy-eips.workspace = true alloy-genesis.workspace = true alloy-primitives.workspace = true -alloy-consensus.workspace = true +alloy-rlp.workspace = true +alloy-rpc-types-eth = { workspace = true, optional = true } + +derive_more.workspace = true +revm-primitives.workspace = true # required by reth-codecs modular-bitfield.workspace = true @@ -33,11 +39,13 @@ arbitrary = { workspace = true, features = ["derive"] } proptest.workspace = true proptest-derive.workspace = true test-fuzz.workspace = true +rand.workspace = true [features] +test-utils = ["arbitrary"] arbitrary = [ "dep:arbitrary", "dep:proptest", "dep:proptest-derive" ] - +alloy-compat = ["alloy-rpc-types-eth"] \ No newline at end of file diff --git a/crates/primitives-traits/src/alloy_compat.rs b/crates/primitives-traits/src/alloy_compat.rs new file mode 100644 index 0000000000..4bf80e1f7c --- /dev/null +++ b/crates/primitives-traits/src/alloy_compat.rs @@ -0,0 +1,48 @@ +use super::Header; +use alloy_rpc_types_eth::{ConversionError, Header as RpcHeader}; + +impl TryFrom for Header { + type Error = ConversionError; + + fn try_from(header: RpcHeader) -> Result { + Ok(Self { + base_fee_per_gas: header + .base_fee_per_gas + .map(|base_fee_per_gas| { + base_fee_per_gas.try_into().map_err(ConversionError::BaseFeePerGasConversion) + }) + .transpose()?, + beneficiary: header.miner, + blob_gas_used: header + .blob_gas_used + .map(|blob_gas_used| { + blob_gas_used.try_into().map_err(ConversionError::BlobGasUsedConversion) + }) + .transpose()?, + difficulty: header.difficulty, + excess_blob_gas: header + .excess_blob_gas + .map(|excess_blob_gas| { + excess_blob_gas.try_into().map_err(ConversionError::ExcessBlobGasConversion) + }) + .transpose()?, + extra_data: header.extra_data, + gas_limit: header.gas_limit.try_into().map_err(ConversionError::GasLimitConversion)?, + gas_used: header.gas_used.try_into().map_err(ConversionError::GasUsedConversion)?, + logs_bloom: header.logs_bloom, + mix_hash: header.mix_hash.unwrap_or_default(), + nonce: u64::from_be_bytes(header.nonce.unwrap_or_default().0), + number: header.number.ok_or(ConversionError::MissingBlockNumber)?, + ommers_hash: header.uncles_hash, + parent_beacon_block_root: header.parent_beacon_block_root, + parent_hash: header.parent_hash, + receipts_root: header.receipts_root, + state_root: header.state_root, + timestamp: header.timestamp, + transactions_root: header.transactions_root, + withdrawals_root: header.withdrawals_root, + // TODO: requests_root: header.requests_root, + requests_root: None, + }) + } +} diff --git a/crates/primitives-traits/src/constants.rs b/crates/primitives-traits/src/constants.rs new file mode 100644 index 0000000000..bda6939763 --- /dev/null +++ b/crates/primitives-traits/src/constants.rs @@ -0,0 +1,170 @@ +//! Ethereum protocol-related constants + +use alloy_primitives::{b256, B256, U256}; +use std::time::Duration; + +/// The client version: `reth/v{major}.{minor}.{patch}` +pub const RETH_CLIENT_VERSION: &str = concat!("reth/v", env!("CARGO_PKG_VERSION")); + +/// The first four bytes of the call data for a function call specifies the function to be called. +pub const SELECTOR_LEN: usize = 4; + +/// Maximum extra data size in a block after genesis +pub const MAXIMUM_EXTRA_DATA_SIZE: usize = 32; + +/// An EPOCH is a series of 32 slots. +pub const EPOCH_SLOTS: u64 = 32; + +/// The duration of a slot in seconds. +/// +/// This is the time period of 12 seconds in which a randomly chosen validator has time to propose a +/// block. +pub const SLOT_DURATION: Duration = Duration::from_secs(12); + +/// An EPOCH is a series of 32 slots (~6.4min). +pub const EPOCH_DURATION: Duration = Duration::from_secs(12 * EPOCH_SLOTS); + +/// The default block nonce in the beacon consensus +pub const BEACON_NONCE: u64 = 0u64; + +/// The default Ethereum block gas limit. +// TODO: This should be a chain spec parameter. +/// See . +pub const ETHEREUM_BLOCK_GAS_LIMIT: u64 = 30_000_000; + +/// The minimum tx fee below which the txpool will reject the transaction. +/// +/// Configured to `7` WEI which is the lowest possible value of base fee under mainnet EIP-1559 +/// parameters. `BASE_FEE_MAX_CHANGE_DENOMINATOR` +/// is `8`, or 12.5%. Once the base fee has dropped to `7` WEI it cannot decrease further because +/// 12.5% of 7 is less than 1. +/// +/// Note that min base fee under different 1559 parameterizations may differ, but there's no +/// significant harm in leaving this setting as is. +pub const MIN_PROTOCOL_BASE_FEE: u64 = 7; + +/// Same as [`MIN_PROTOCOL_BASE_FEE`] but as a U256. +pub const MIN_PROTOCOL_BASE_FEE_U256: U256 = U256::from_limbs([7u64, 0, 0, 0]); + +/// Initial base fee as defined in [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559) +pub const EIP1559_INITIAL_BASE_FEE: u64 = 1_000_000_000; + +/// Base fee max change denominator as defined in [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559) +pub const EIP1559_DEFAULT_BASE_FEE_MAX_CHANGE_DENOMINATOR: u64 = 8; + +/// Elasticity multiplier as defined in [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559) +pub const EIP1559_DEFAULT_ELASTICITY_MULTIPLIER: u64 = 2; + +/// Minimum gas limit allowed for transactions. +pub const MINIMUM_GAS_LIMIT: u64 = 5000; + +/// Base fee max change denominator for Optimism Mainnet as defined in the Optimism +/// [transaction costs](https://community.optimism.io/docs/developers/build/differences/#transaction-costs) doc. +pub const OP_MAINNET_EIP1559_DEFAULT_BASE_FEE_MAX_CHANGE_DENOMINATOR: u128 = 50; + +/// Base fee max change denominator for Optimism Mainnet as defined in the Optimism Canyon +/// hardfork. +pub const OP_MAINNET_EIP1559_BASE_FEE_MAX_CHANGE_DENOMINATOR_CANYON: u128 = 250; + +/// Base fee max change denominator for Optimism Mainnet as defined in the Optimism +/// [transaction costs](https://community.optimism.io/docs/developers/build/differences/#transaction-costs) doc. +pub const OP_MAINNET_EIP1559_DEFAULT_ELASTICITY_MULTIPLIER: u128 = 6; + +/// Base fee max change denominator for Optimism Sepolia as defined in the Optimism +/// [transaction costs](https://community.optimism.io/docs/developers/build/differences/#transaction-costs) doc. +pub const OP_SEPOLIA_EIP1559_DEFAULT_BASE_FEE_MAX_CHANGE_DENOMINATOR: u128 = 50; + +/// Base fee max change denominator for Optimism Sepolia as defined in the Optimism Canyon +/// hardfork. +pub const OP_SEPOLIA_EIP1559_BASE_FEE_MAX_CHANGE_DENOMINATOR_CANYON: u128 = 250; + +/// Base fee max change denominator for Optimism Sepolia as defined in the Optimism +/// [transaction costs](https://community.optimism.io/docs/developers/build/differences/#transaction-costs) doc. +pub const OP_SEPOLIA_EIP1559_DEFAULT_ELASTICITY_MULTIPLIER: u128 = 6; + +/// Base fee max change denominator for Base Sepolia as defined in the Optimism +/// [transaction costs](https://community.optimism.io/docs/developers/build/differences/#transaction-costs) doc. +pub const BASE_SEPOLIA_EIP1559_DEFAULT_ELASTICITY_MULTIPLIER: u128 = 10; + +/// Multiplier for converting gwei to wei. +pub const GWEI_TO_WEI: u64 = 1_000_000_000; + +/// Multiplier for converting finney (milliether) to wei. +pub const FINNEY_TO_WEI: u128 = (GWEI_TO_WEI as u128) * 1_000_000; + +/// Multiplier for converting ether to wei. +pub const ETH_TO_WEI: u128 = FINNEY_TO_WEI * 1000; + +/// Multiplier for converting mgas to gas. +pub const MGAS_TO_GAS: u64 = 1_000_000u64; + +/// The Ethereum mainnet genesis hash: +/// `0x0d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3` +pub const MAINNET_GENESIS_HASH: B256 = + b256!("d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3"); + +/// Goerli genesis hash: `0xbf7e331f7f7c1dd2e05159666b3bf8bc7a8a3a9eb1d518969eab529dd9b88c1a` +pub const GOERLI_GENESIS_HASH: B256 = + b256!("bf7e331f7f7c1dd2e05159666b3bf8bc7a8a3a9eb1d518969eab529dd9b88c1a"); + +/// Sepolia genesis hash: `0x25a5cc106eea7138acab33231d7160d69cb777ee0c2c553fcddf5138993e6dd9` +pub const SEPOLIA_GENESIS_HASH: B256 = + b256!("25a5cc106eea7138acab33231d7160d69cb777ee0c2c553fcddf5138993e6dd9"); + +/// Holesky genesis hash: `0xff9006519a8ce843ac9c28549d24211420b546e12ce2d170c77a8cca7964f23d` +pub const HOLESKY_GENESIS_HASH: B256 = + b256!("ff9006519a8ce843ac9c28549d24211420b546e12ce2d170c77a8cca7964f23d"); + +/// Testnet genesis hash: `0x2f980576711e3617a5e4d83dd539548ec0f7792007d505a3d2e9674833af2d7c` +pub const DEV_GENESIS_HASH: B256 = + b256!("2f980576711e3617a5e4d83dd539548ec0f7792007d505a3d2e9674833af2d7c"); + +/// Keccak256 over empty array: `0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470` +pub const KECCAK_EMPTY: B256 = + b256!("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"); + +/// Ommer root of empty list: `0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347` +pub const EMPTY_OMMER_ROOT_HASH: B256 = + b256!("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"); + +/// Root hash of an empty trie: `0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421` +pub const EMPTY_ROOT_HASH: B256 = + b256!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"); + +/// Transactions root of empty receipts set. +pub const EMPTY_RECEIPTS: B256 = EMPTY_ROOT_HASH; + +/// Transactions root of empty transactions set. +pub const EMPTY_TRANSACTIONS: B256 = EMPTY_ROOT_HASH; + +/// Withdrawals root of empty withdrawals set. +pub const EMPTY_WITHDRAWALS: B256 = EMPTY_ROOT_HASH; + +/// The number of blocks to unwind during a reorg that already became a part of canonical chain. +/// +/// In reality, the node can end up in this particular situation very rarely. It would happen only +/// if the node process is abruptly terminated during ongoing reorg and doesn't boot back up for +/// long period of time. +/// +/// Unwind depth of `3` blocks significantly reduces the chance that the reorged block is kept in +/// the database. +pub const BEACON_CONSENSUS_REORG_UNWIND_DEPTH: u64 = 3; + +/// Max seconds from current time allowed for blocks, before they're considered future blocks. +/// +/// This is only used when checking whether or not the timestamp for pre-merge blocks is in the +/// future. +/// +/// See: +/// +pub const ALLOWED_FUTURE_BLOCK_TIME_SECONDS: u64 = 15; + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn min_protocol_sanity() { + assert_eq!(MIN_PROTOCOL_BASE_FEE_U256.to::(), MIN_PROTOCOL_BASE_FEE); + } +} diff --git a/crates/primitives-traits/src/header/error.rs b/crates/primitives-traits/src/header/error.rs new file mode 100644 index 0000000000..6161afc1a5 --- /dev/null +++ b/crates/primitives-traits/src/header/error.rs @@ -0,0 +1,8 @@ +/// Errors that can occur during header sanity checks. +#[derive(Debug, PartialEq, Eq)] +pub enum HeaderError { + /// Represents an error when the block difficulty is too large. + LargeDifficulty, + /// Represents an error when the block extradata is too large. + LargeExtraData, +} diff --git a/crates/primitives-traits/src/header/mod.rs b/crates/primitives-traits/src/header/mod.rs new file mode 100644 index 0000000000..5ec41d4145 --- /dev/null +++ b/crates/primitives-traits/src/header/mod.rs @@ -0,0 +1,509 @@ +mod sealed; +pub use sealed::SealedHeader; + +mod error; +pub use error::HeaderError; + +#[cfg(any(test, feature = "test-utils", feature = "arbitrary"))] +pub mod test_utils; + +use alloy_consensus::constants::{EMPTY_OMMER_ROOT_HASH, EMPTY_ROOT_HASH}; +use alloy_eips::{ + calc_next_block_base_fee, eip1559::BaseFeeParams, merge::ALLOWED_FUTURE_BLOCK_TIME_SECONDS, + BlockNumHash, +}; +use alloy_primitives::{keccak256, Address, BlockNumber, Bloom, Bytes, B256, B64, U256}; +use alloy_rlp::{length_of_length, Decodable, Encodable}; +use bytes::BufMut; +use reth_codecs::{main_codec, Compact}; +use revm_primitives::{calc_blob_gasprice, calc_excess_blob_gas}; +use std::mem; + +/// Block header +#[main_codec] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct Header { + /// The Keccak 256-bit hash of the parent + /// block’s header, in its entirety; formally Hp. + pub parent_hash: B256, + /// The Keccak 256-bit hash of the ommers list portion of this block; formally Ho. + pub ommers_hash: B256, + /// The 160-bit address to which all fees collected from the successful mining of this block + /// be transferred; formally Hc. + pub beneficiary: Address, + /// The Keccak 256-bit hash of the root node of the state trie, after all transactions are + /// executed and finalisations applied; formally Hr. + pub state_root: B256, + /// The Keccak 256-bit hash of the root node of the trie structure populated with each + /// transaction in the transactions list portion of the block; formally Ht. + pub transactions_root: B256, + /// The Keccak 256-bit hash of the root node of the trie structure populated with the receipts + /// of each transaction in the transactions list portion of the block; formally He. + pub receipts_root: B256, + /// The Keccak 256-bit hash of the withdrawals list portion of this block. + /// + /// See [EIP-4895](https://eips.ethereum.org/EIPS/eip-4895). + pub withdrawals_root: Option, + /// The Bloom filter composed from indexable information (logger address and log topics) + /// contained in each log entry from the receipt of each transaction in the transactions list; + /// formally Hb. + pub logs_bloom: Bloom, + /// A scalar value corresponding to the difficulty level of this block. This can be calculated + /// from the previous block’s difficulty level and the timestamp; formally Hd. + pub difficulty: U256, + /// A scalar value equal to the number of ancestor blocks. The genesis block has a number of + /// zero; formally Hi. + pub number: BlockNumber, + /// A scalar value equal to the current limit of gas expenditure per block; formally Hl. + pub gas_limit: u64, + /// A scalar value equal to the total gas used in transactions in this block; formally Hg. + pub gas_used: u64, + /// A scalar value equal to the reasonable output of Unix’s time() at this block’s inception; + /// formally Hs. + pub timestamp: u64, + /// A 256-bit hash which, combined with the + /// nonce, proves that a sufficient amount of computation has been carried out on this block; + /// formally Hm. + pub mix_hash: B256, + /// A 64-bit value which, combined with the mixhash, proves that a sufficient amount of + /// computation has been carried out on this block; formally Hn. + pub nonce: u64, + /// A scalar representing EIP1559 base fee which can move up or down each block according + /// to a formula which is a function of gas used in parent block and gas target + /// (block gas limit divided by elasticity multiplier) of parent block. + /// The algorithm results in the base fee per gas increasing when blocks are + /// above the gas target, and decreasing when blocks are below the gas target. The base fee per + /// gas is burned. + pub base_fee_per_gas: Option, + /// The total amount of blob gas consumed by the transactions within the block, added in + /// EIP-4844. + pub blob_gas_used: Option, + /// A running total of blob gas consumed in excess of the target, prior to the block. Blocks + /// with above-target blob gas consumption increase this value, blocks with below-target blob + /// gas consumption decrease it (bounded at 0). This was added in EIP-4844. + pub excess_blob_gas: Option, + /// The hash of the parent beacon block's root is included in execution blocks, as proposed by + /// EIP-4788. + /// + /// This enables trust-minimized access to consensus state, supporting staking pools, bridges, + /// and more. + /// + /// The beacon roots contract handles root storage, enhancing Ethereum's functionalities. + pub parent_beacon_block_root: Option, + /// The Keccak 256-bit hash of the root node of the trie structure populated with each + /// [EIP-7685] request in the block body. + /// + /// [EIP-7685]: https://eips.ethereum.org/EIPS/eip-7685 + pub requests_root: Option, + /// An arbitrary byte array containing data relevant to this block. This must be 32 bytes or + /// fewer; formally Hx. + pub extra_data: Bytes, +} + +impl AsRef for Header { + fn as_ref(&self) -> &Self { + self + } +} + +impl Default for Header { + fn default() -> Self { + Self { + parent_hash: Default::default(), + ommers_hash: EMPTY_OMMER_ROOT_HASH, + beneficiary: Default::default(), + state_root: EMPTY_ROOT_HASH, + transactions_root: EMPTY_ROOT_HASH, + receipts_root: EMPTY_ROOT_HASH, + logs_bloom: Default::default(), + difficulty: Default::default(), + number: 0, + gas_limit: 0, + gas_used: 0, + timestamp: 0, + extra_data: Default::default(), + mix_hash: Default::default(), + nonce: 0, + base_fee_per_gas: None, + withdrawals_root: None, + blob_gas_used: None, + excess_blob_gas: None, + parent_beacon_block_root: None, + requests_root: None, + } + } +} + +impl Header { + /// Checks if the block's difficulty is set to zero, indicating a Proof-of-Stake header. + /// + /// This function is linked to EIP-3675, proposing the consensus upgrade to Proof-of-Stake: + /// [EIP-3675](https://eips.ethereum.org/EIPS/eip-3675#replacing-difficulty-with-0) + /// + /// Verifies whether, as per the EIP, the block's difficulty is updated to zero, + /// signifying the transition to a Proof-of-Stake mechanism. + /// + /// Returns `true` if the block's difficulty matches the constant zero set by the EIP. + pub fn is_zero_difficulty(&self) -> bool { + self.difficulty.is_zero() + } + + /// Performs a sanity check on the extradata field of the header. + /// + /// # Errors + /// + /// Returns an error if the extradata size is larger than 100 KB. + pub fn ensure_extradata_valid(&self) -> Result<(), HeaderError> { + if self.extra_data.len() > 100 * 1024 { + return Err(HeaderError::LargeExtraData) + } + Ok(()) + } + + /// Performs a sanity check on the block difficulty field of the header. + /// + /// # Errors + /// + /// Returns an error if the block difficulty exceeds 80 bits. + pub fn ensure_difficulty_valid(&self) -> Result<(), HeaderError> { + if self.difficulty.bit_len() > 80 { + return Err(HeaderError::LargeDifficulty) + } + Ok(()) + } + + /// Performs combined sanity checks on multiple header fields. + /// + /// This method combines checks for block difficulty and extradata sizes. + /// + /// # Errors + /// + /// Returns an error if either the block difficulty exceeds 80 bits + /// or if the extradata size is larger than 100 KB. + pub fn ensure_well_formed(&self) -> Result<(), HeaderError> { + self.ensure_difficulty_valid()?; + self.ensure_extradata_valid()?; + Ok(()) + } + + /// Checks if the block's timestamp is in the past compared to the parent block's timestamp. + /// + /// Note: This check is relevant only pre-merge. + pub const fn is_timestamp_in_past(&self, parent_timestamp: u64) -> bool { + self.timestamp <= parent_timestamp + } + + /// Checks if the block's timestamp is in the future based on the present timestamp. + /// + /// Clock can drift but this can be consensus issue. + /// + /// Note: This check is relevant only pre-merge. + pub const fn exceeds_allowed_future_timestamp(&self, present_timestamp: u64) -> bool { + self.timestamp > present_timestamp + ALLOWED_FUTURE_BLOCK_TIME_SECONDS + } + + /// Returns the parent block's number and hash + pub const fn parent_num_hash(&self) -> BlockNumHash { + BlockNumHash { number: self.number.saturating_sub(1), hash: self.parent_hash } + } + + /// Heavy function that will calculate hash of data and will *not* save the change to metadata. + /// Use [`Header::seal`], [`SealedHeader`] and unlock if you need hash to be persistent. + pub fn hash_slow(&self) -> B256 { + keccak256(alloy_rlp::encode(self)) + } + + /// Checks if the header is empty - has no transactions and no ommers + pub fn is_empty(&self) -> bool { + self.transaction_root_is_empty() && + self.ommers_hash_is_empty() && + self.withdrawals_root.map_or(true, |root| root == EMPTY_ROOT_HASH) + } + + /// Check if the ommers hash equals to empty hash list. + pub fn ommers_hash_is_empty(&self) -> bool { + self.ommers_hash == EMPTY_OMMER_ROOT_HASH + } + + /// Check if the transaction root equals to empty root. + pub fn transaction_root_is_empty(&self) -> bool { + self.transactions_root == EMPTY_ROOT_HASH + } + + /// Returns the blob fee for _this_ block according to the EIP-4844 spec. + /// + /// Returns `None` if `excess_blob_gas` is None + pub fn blob_fee(&self) -> Option { + self.excess_blob_gas.map(calc_blob_gasprice) + } + + /// Returns the blob fee for the next block according to the EIP-4844 spec. + /// + /// Returns `None` if `excess_blob_gas` is None. + /// + /// See also [`Self::next_block_excess_blob_gas`] + pub fn next_block_blob_fee(&self) -> Option { + self.next_block_excess_blob_gas().map(calc_blob_gasprice) + } + + /// Calculate base fee for next block according to the EIP-1559 spec. + /// + /// Returns a `None` if no base fee is set, no EIP-1559 support + pub fn next_block_base_fee(&self, base_fee_params: BaseFeeParams) -> Option { + Some(calc_next_block_base_fee( + self.gas_used as u128, + self.gas_limit as u128, + self.base_fee_per_gas? as u128, + base_fee_params, + ) as u64) + } + + /// Calculate excess blob gas for the next block according to the EIP-4844 spec. + /// + /// Returns a `None` if no excess blob gas is set, no EIP-4844 support + pub fn next_block_excess_blob_gas(&self) -> Option { + Some(calc_excess_blob_gas(self.excess_blob_gas?, self.blob_gas_used?)) + } + + /// Seal the header with a known hash. + /// + /// WARNING: This method does not perform validation whether the hash is correct. + #[inline] + pub const fn seal(self, hash: B256) -> SealedHeader { + SealedHeader::new(self, hash) + } + + /// Calculate hash and seal the Header so that it can't be changed. + #[inline] + pub fn seal_slow(self) -> SealedHeader { + let hash = self.hash_slow(); + self.seal(hash) + } + + /// Calculate a heuristic for the in-memory size of the [Header]. + #[inline] + pub fn size(&self) -> usize { + mem::size_of::() + // parent hash + mem::size_of::() + // ommers hash + mem::size_of::

() + // beneficiary + mem::size_of::() + // state root + mem::size_of::() + // transactions root + mem::size_of::() + // receipts root + mem::size_of::>() + // withdrawals root + mem::size_of::() + // logs bloom + mem::size_of::() + // difficulty + mem::size_of::() + // number + mem::size_of::() + // gas limit + mem::size_of::() + // gas used + mem::size_of::() + // timestamp + mem::size_of::() + // mix hash + mem::size_of::() + // nonce + mem::size_of::>() + // base fee per gas + mem::size_of::>() + // blob gas used + mem::size_of::>() + // excess blob gas + mem::size_of::>() + // parent beacon block root + self.extra_data.len() // extra data + } + + fn header_payload_length(&self) -> usize { + let mut length = 0; + length += self.parent_hash.length(); // Hash of the previous block. + length += self.ommers_hash.length(); // Hash of uncle blocks. + length += self.beneficiary.length(); // Address that receives rewards. + length += self.state_root.length(); // Root hash of the state object. + length += self.transactions_root.length(); // Root hash of transactions in the block. + length += self.receipts_root.length(); // Hash of transaction receipts. + length += self.logs_bloom.length(); // Data structure containing event logs. + length += self.difficulty.length(); // Difficulty value of the block. + length += U256::from(self.number).length(); // Block number. + length += U256::from(self.gas_limit).length(); // Maximum gas allowed. + length += U256::from(self.gas_used).length(); // Actual gas used. + length += self.timestamp.length(); // Block timestamp. + length += self.extra_data.length(); // Additional arbitrary data. + length += self.mix_hash.length(); // Hash used for mining. + length += B64::new(self.nonce.to_be_bytes()).length(); // Nonce for mining. + + if let Some(base_fee) = self.base_fee_per_gas { + // Adding base fee length if it exists. + length += U256::from(base_fee).length(); + } + + if let Some(root) = self.withdrawals_root { + // Adding withdrawals_root length if it exists. + length += root.length(); + } + + if let Some(blob_gas_used) = self.blob_gas_used { + // Adding blob_gas_used length if it exists. + length += U256::from(blob_gas_used).length(); + } + + if let Some(excess_blob_gas) = self.excess_blob_gas { + // Adding excess_blob_gas length if it exists. + length += U256::from(excess_blob_gas).length(); + } + + if let Some(parent_beacon_block_root) = self.parent_beacon_block_root { + length += parent_beacon_block_root.length(); + } + + if let Some(requests_root) = self.requests_root { + length += requests_root.length(); + } + + length + } +} + +impl Encodable for Header { + fn encode(&self, out: &mut dyn BufMut) { + // Create a header indicating the encoded content is a list with the payload length computed + // from the header's payload calculation function. + let list_header = + alloy_rlp::Header { list: true, payload_length: self.header_payload_length() }; + list_header.encode(out); + + // Encode each header field sequentially + self.parent_hash.encode(out); // Encode parent hash. + self.ommers_hash.encode(out); // Encode ommer's hash. + self.beneficiary.encode(out); // Encode beneficiary. + self.state_root.encode(out); // Encode state root. + self.transactions_root.encode(out); // Encode transactions root. + self.receipts_root.encode(out); // Encode receipts root. + self.logs_bloom.encode(out); // Encode logs bloom. + self.difficulty.encode(out); // Encode difficulty. + U256::from(self.number).encode(out); // Encode block number. + U256::from(self.gas_limit).encode(out); // Encode gas limit. + U256::from(self.gas_used).encode(out); // Encode gas used. + self.timestamp.encode(out); // Encode timestamp. + self.extra_data.encode(out); // Encode extra data. + self.mix_hash.encode(out); // Encode mix hash. + B64::new(self.nonce.to_be_bytes()).encode(out); // Encode nonce. + + // Encode base fee. Put empty list if base fee is missing, + // but withdrawals root is present. + if let Some(ref base_fee) = self.base_fee_per_gas { + U256::from(*base_fee).encode(out); + } + + // Encode withdrawals root. Put empty string if withdrawals root is missing, + // but blob gas used is present. + if let Some(ref root) = self.withdrawals_root { + root.encode(out); + } + + // Encode blob gas used. Put empty list if blob gas used is missing, + // but excess blob gas is present. + if let Some(ref blob_gas_used) = self.blob_gas_used { + U256::from(*blob_gas_used).encode(out); + } + + // Encode excess blob gas. Put empty list if excess blob gas is missing, + // but parent beacon block root is present. + if let Some(ref excess_blob_gas) = self.excess_blob_gas { + U256::from(*excess_blob_gas).encode(out); + } + + // Encode parent beacon block root. + if let Some(ref parent_beacon_block_root) = self.parent_beacon_block_root { + parent_beacon_block_root.encode(out); + } + + // Encode EIP-7685 requests root + // + // If new fields are added, the above pattern will need to + // be repeated and placeholders added. Otherwise, it's impossible to tell _which_ + // fields are missing. This is mainly relevant for contrived cases where a header is + // created at random, for example: + // * A header is created with a withdrawals root, but no base fee. Shanghai blocks are + // post-London, so this is technically not valid. However, a tool like proptest would + // generate a block like this. + if let Some(ref requests_root) = self.requests_root { + requests_root.encode(out); + } + } + + fn length(&self) -> usize { + let mut length = 0; + length += self.header_payload_length(); + length += length_of_length(length); + length + } +} + +impl Decodable for Header { + fn decode(buf: &mut &[u8]) -> alloy_rlp::Result { + let rlp_head = alloy_rlp::Header::decode(buf)?; + if !rlp_head.list { + return Err(alloy_rlp::Error::UnexpectedString) + } + let started_len = buf.len(); + let mut this = Self { + parent_hash: Decodable::decode(buf)?, + ommers_hash: Decodable::decode(buf)?, + beneficiary: Decodable::decode(buf)?, + state_root: Decodable::decode(buf)?, + transactions_root: Decodable::decode(buf)?, + receipts_root: Decodable::decode(buf)?, + logs_bloom: Decodable::decode(buf)?, + difficulty: Decodable::decode(buf)?, + number: u64::decode(buf)?, + gas_limit: u64::decode(buf)?, + gas_used: u64::decode(buf)?, + timestamp: Decodable::decode(buf)?, + extra_data: Decodable::decode(buf)?, + mix_hash: Decodable::decode(buf)?, + nonce: u64::from_be_bytes(B64::decode(buf)?.0), + base_fee_per_gas: None, + withdrawals_root: None, + blob_gas_used: None, + excess_blob_gas: None, + parent_beacon_block_root: None, + requests_root: None, + }; + if started_len - buf.len() < rlp_head.payload_length { + this.base_fee_per_gas = Some(u64::decode(buf)?); + } + + // Withdrawals root for post-shanghai headers + if started_len - buf.len() < rlp_head.payload_length { + this.withdrawals_root = Some(Decodable::decode(buf)?); + } + + // Blob gas used and excess blob gas for post-cancun headers + if started_len - buf.len() < rlp_head.payload_length { + this.blob_gas_used = Some(u64::decode(buf)?); + } + + if started_len - buf.len() < rlp_head.payload_length { + this.excess_blob_gas = Some(u64::decode(buf)?); + } + + // Decode parent beacon block root. + if started_len - buf.len() < rlp_head.payload_length { + this.parent_beacon_block_root = Some(B256::decode(buf)?); + } + + // Decode requests root. + // + // If new fields are added, the above pattern will need to + // be repeated and placeholders decoded. Otherwise, it's impossible to tell _which_ + // fields are missing. This is mainly relevant for contrived cases where a header is + // created at random, for example: + // * A header is created with a withdrawals root, but no base fee. Shanghai blocks are + // post-London, so this is technically not valid. However, a tool like proptest would + // generate a block like this. + if started_len - buf.len() < rlp_head.payload_length { + this.requests_root = Some(B256::decode(buf)?); + } + + let consumed = started_len - buf.len(); + if consumed != rlp_head.payload_length { + return Err(alloy_rlp::Error::ListLengthMismatch { + expected: rlp_head.payload_length, + got: consumed, + }) + } + Ok(this) + } +} diff --git a/crates/primitives-traits/src/header/sealed.rs b/crates/primitives-traits/src/header/sealed.rs new file mode 100644 index 0000000000..91918b6877 --- /dev/null +++ b/crates/primitives-traits/src/header/sealed.rs @@ -0,0 +1,156 @@ +use super::Header; +use alloy_eips::BlockNumHash; +use alloy_primitives::{keccak256, BlockHash}; +#[cfg(any(test, feature = "test-utils"))] +use alloy_primitives::{BlockNumber, B256, U256}; +use alloy_rlp::{Decodable, Encodable}; +use bytes::BufMut; +use derive_more::{AsRef, Deref}; +#[cfg(any(test, feature = "arbitrary"))] +use proptest::prelude::*; +use reth_codecs::{add_arbitrary_tests, main_codec, Compact}; +use std::mem; + +/// A [`Header`] that is sealed at a precalculated hash, use [`SealedHeader::unseal()`] if you want +/// to modify header. +#[main_codec(no_arbitrary)] +#[add_arbitrary_tests(rlp, compact)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, AsRef, Deref)] +pub struct SealedHeader { + /// Locked Header hash. + hash: BlockHash, + /// Locked Header fields. + #[as_ref] + #[deref] + header: Header, +} + +impl SealedHeader { + /// Creates the sealed header with the corresponding block hash. + #[inline] + pub const fn new(header: Header, hash: BlockHash) -> Self { + Self { header, hash } + } + + /// Returns the sealed Header fields. + #[inline] + pub const fn header(&self) -> &Header { + &self.header + } + + /// Returns header/block hash. + #[inline] + pub const fn hash(&self) -> BlockHash { + self.hash + } + + /// Extract raw header that can be modified. + pub fn unseal(self) -> Header { + self.header + } + + /// This is the inverse of [`Header::seal_slow`] which returns the raw header and hash. + pub fn split(self) -> (Header, BlockHash) { + (self.header, self.hash) + } + + /// Return the number hash tuple. + pub fn num_hash(&self) -> BlockNumHash { + BlockNumHash::new(self.number, self.hash) + } + + /// Calculates a heuristic for the in-memory size of the [`SealedHeader`]. + #[inline] + pub fn size(&self) -> usize { + self.header.size() + mem::size_of::() + } +} + +impl Default for SealedHeader { + fn default() -> Self { + Header::default().seal_slow() + } +} + +impl Encodable for SealedHeader { + fn encode(&self, out: &mut dyn BufMut) { + self.header.encode(out); + } +} + +impl Decodable for SealedHeader { + fn decode(buf: &mut &[u8]) -> alloy_rlp::Result { + let b = &mut &**buf; + let started_len = buf.len(); + + // decode the header from temp buffer + let header = Header::decode(b)?; + + // hash the consumed bytes, the rlp encoded header + let consumed = started_len - b.len(); + let hash = keccak256(&buf[..consumed]); + + // update original buffer + *buf = *b; + + Ok(Self { header, hash }) + } +} + +#[cfg(any(test, feature = "test-utils"))] +impl SealedHeader { + /// Updates the block header. + pub fn set_header(&mut self, header: Header) { + self.header = header + } + + /// Updates the block hash. + pub fn set_hash(&mut self, hash: BlockHash) { + self.hash = hash + } + + /// Updates the parent block hash. + pub fn set_parent_hash(&mut self, hash: BlockHash) { + self.header.parent_hash = hash + } + + /// Updates the block number. + pub fn set_block_number(&mut self, number: BlockNumber) { + self.header.number = number; + } + + /// Updates the block state root. + pub fn set_state_root(&mut self, state_root: B256) { + self.header.state_root = state_root; + } + + /// Updates the block difficulty. + pub fn set_difficulty(&mut self, difficulty: U256) { + self.header.difficulty = difficulty; + } +} + +#[cfg(any(test, feature = "arbitrary"))] +impl proptest::arbitrary::Arbitrary for SealedHeader { + type Parameters = (); + fn arbitrary_with(_: Self::Parameters) -> Self::Strategy { + // map valid header strategy by sealing + crate::test_utils::valid_header_strategy().prop_map(|header| header.seal_slow()).boxed() + } + type Strategy = proptest::strategy::BoxedStrategy; +} + +#[cfg(any(test, feature = "arbitrary"))] +impl<'a> arbitrary::Arbitrary<'a> for SealedHeader { + fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { + let sealed_header = crate::test_utils::generate_valid_header( + u.arbitrary()?, + u.arbitrary()?, + u.arbitrary()?, + u.arbitrary()?, + u.arbitrary()?, + ) + .seal_slow(); + Ok(sealed_header) + } +} diff --git a/crates/primitives-traits/src/header/test_utils.rs b/crates/primitives-traits/src/header/test_utils.rs new file mode 100644 index 0000000000..07d00f03bb --- /dev/null +++ b/crates/primitives-traits/src/header/test_utils.rs @@ -0,0 +1,66 @@ +//! Test utilities to generate random valid headers. + +use crate::Header; +use alloy_primitives::B256; +use proptest::{arbitrary::any, prop_compose}; + +/// Generates a header which is valid __with respect to past and future forks__. This means, for +/// example, that if the withdrawals root is present, the base fee per gas is also present. +/// +/// If blob gas used were present, then the excess blob gas and parent beacon block root are also +/// present. In this example, the withdrawals root would also be present. +/// +/// This __does not, and should not guarantee__ that the header is valid with respect to __anything +/// else__. +pub const fn generate_valid_header( + mut header: Header, + eip_4844_active: bool, + blob_gas_used: u64, + excess_blob_gas: u64, + parent_beacon_block_root: B256, +) -> Header { + // EIP-1559 logic + if header.base_fee_per_gas.is_none() { + // If EIP-1559 is not active, clear related fields + header.withdrawals_root = None; + header.blob_gas_used = None; + header.excess_blob_gas = None; + header.parent_beacon_block_root = None; + } else if header.withdrawals_root.is_none() { + // If EIP-4895 is not active, clear related fields + header.blob_gas_used = None; + header.excess_blob_gas = None; + header.parent_beacon_block_root = None; + } else if eip_4844_active { + // Set fields based on EIP-4844 being active + header.blob_gas_used = Some(blob_gas_used); + header.excess_blob_gas = Some(excess_blob_gas); + header.parent_beacon_block_root = Some(parent_beacon_block_root); + } else { + // If EIP-4844 is not active, clear related fields + header.blob_gas_used = None; + header.excess_blob_gas = None; + header.parent_beacon_block_root = None; + } + + // todo(onbjerg): adjust this for eip-7589 + header.requests_root = None; + + header +} + +prop_compose! { + /// Generates a proptest strategy for constructing an instance of a header which is valid __with + /// respect to past and future forks__. + /// + /// See docs for [generate_valid_header] for more information. + pub fn valid_header_strategy()( + header in any::
(), + eip_4844_active in any::(), + blob_gas_used in any::(), + excess_blob_gas in any::(), + parent_beacon_block_root in any::() + ) -> Header { + generate_valid_header(header, eip_4844_active, blob_gas_used, excess_blob_gas, parent_beacon_block_root) + } +} diff --git a/crates/primitives-traits/src/lib.rs b/crates/primitives-traits/src/lib.rs index af8918de19..68161709cd 100644 --- a/crates/primitives-traits/src/lib.rs +++ b/crates/primitives-traits/src/lib.rs @@ -10,6 +10,18 @@ #![allow(unknown_lints, non_local_definitions)] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] +#[cfg(feature = "alloy-compat")] +mod alloy_compat; + +/// Common constants. +pub mod constants; + /// Minimal account pub mod account; pub use account::Account; + +/// Common header types +pub mod header; +#[cfg(any(test, feature = "arbitrary", feature = "test-utils"))] +pub use header::test_utils; +pub use header::{Header, HeaderError, SealedHeader}; diff --git a/crates/primitives/Cargo.toml b/crates/primitives/Cargo.toml index 0add202763..90fdb0e3eb 100644 --- a/crates/primitives/Cargo.toml +++ b/crates/primitives/Cargo.toml @@ -18,16 +18,15 @@ reth-codecs.workspace = true reth-ethereum-forks.workspace = true reth-network-peers.workspace = true reth-static-file-types.workspace = true -reth-trie-types.workspace = true +reth-trie-common.workspace = true revm.workspace = true revm-primitives = { workspace = true, features = ["serde"] } # ethereum alloy-chains = { workspace = true, features = ["serde", "rlp"] } -alloy-consensus = { workspace = true, features = ["arbitrary", "serde"] } +alloy-consensus = { workspace = true, features = ["serde"] } alloy-primitives = { workspace = true, features = ["rand", "rlp"] } alloy-rlp = { workspace = true, features = ["arrayvec"] } -alloy-trie = { workspace = true, features = ["serde"] } alloy-rpc-types = { workspace = true, optional = true } alloy-genesis.workspace = true alloy-eips = { workspace = true, features = ["serde"] } @@ -45,21 +44,16 @@ c-kzg = { workspace = true, features = ["serde"], optional = true } bytes.workspace = true byteorder = "1" derive_more.workspace = true -itertools.workspace = true modular-bitfield.workspace = true once_cell.workspace = true rayon.workspace = true serde.workspace = true serde_json.workspace = true tempfile = { workspace = true, optional = true } -thiserror.workspace = true +thiserror-no-std = { workspace = true , default-features = false } zstd = { version = "0.13", features = ["experimental"], optional = true } roaring = "0.10.2" -# `test-utils` feature -hash-db = { version = "~0.15", optional = true } -plain_hasher = { version = "0.2", optional = true } - # arbitrary utils arbitrary = { workspace = true, features = ["derive"], optional = true } proptest = { workspace = true, optional = true } @@ -82,9 +76,6 @@ test-fuzz.workspace = true toml.workspace = true triehash = "0.8" -hash-db = "~0.15" -plain_hasher = "0.2" - sucds = "0.8.1" criterion.workspace = true @@ -96,7 +87,7 @@ pprof = { workspace = true, features = [ secp256k1.workspace = true [features] -default = ["c-kzg", "zstd-codec", "alloy-compat"] +default = ["c-kzg", "zstd-codec", "alloy-compat", "std"] asm-keccak = ["alloy-primitives/asm-keccak"] arbitrary = [ "reth-primitives-traits/arbitrary", @@ -105,6 +96,7 @@ arbitrary = [ "nybbles/arbitrary", "alloy-trie/arbitrary", "alloy-chains/arbitrary", + "alloy-consensus/arbitrary", "alloy-eips/arbitrary", "dep:arbitrary", "dep:proptest", @@ -119,14 +111,17 @@ c-kzg = [ "alloy-eips/kzg", ] zstd-codec = ["dep:zstd"] -clap = ["reth-static-file-types/clap"] optimism = [ "reth-codecs/optimism", "reth-ethereum-forks/optimism", "revm/optimism", ] -alloy-compat = ["alloy-rpc-types"] -test-utils = ["dep:plain_hasher", "dep:hash-db"] +alloy-compat = [ + "reth-primitives-traits/alloy-compat", + "alloy-rpc-types", +] +std = ["thiserror-no-std/std"] +test-utils = ["reth-primitives-traits/test-utils"] [[bench]] name = "recover_ecdsa_crit" @@ -137,11 +132,6 @@ name = "validate_blob_tx" required-features = ["arbitrary", "c-kzg"] harness = false -[[bench]] -name = "trie_root" -required-features = ["arbitrary", "test-utils"] -harness = false - [[bench]] name = "integer_list" harness = false diff --git a/crates/primitives/benches/integer_list.rs b/crates/primitives/benches/integer_list.rs index 6dcec91397..097280748e 100644 --- a/crates/primitives/benches/integer_list.rs +++ b/crates/primitives/benches/integer_list.rs @@ -89,20 +89,13 @@ criterion_main!(benches); /// adapted to work with `sucds = "0.8.1"` #[allow(unused, unreachable_pub)] mod elias_fano { + use derive_more::Deref; use std::{fmt, ops::Deref}; use sucds::{mii_sequences::EliasFano, Serializable}; - #[derive(Clone, PartialEq, Eq, Default)] + #[derive(Clone, PartialEq, Eq, Default, Deref)] pub struct IntegerList(pub EliasFano); - impl Deref for IntegerList { - type Target = EliasFano; - - fn deref(&self) -> &Self::Target { - &self.0 - } - } - impl fmt::Debug for IntegerList { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let vec: Vec = self.0.iter(0).collect(); @@ -239,7 +232,7 @@ mod elias_fano { } /// Primitives error type. - #[derive(Debug, thiserror::Error)] + #[derive(Debug, thiserror_no_std::Error)] pub enum EliasFanoError { /// The provided input is invalid. #[error("{0}")] diff --git a/crates/primitives/src/account.rs b/crates/primitives/src/account.rs index fead77789f..0fa55108e7 100644 --- a/crates/primitives/src/account.rs +++ b/crates/primitives/src/account.rs @@ -1,17 +1,17 @@ use crate::revm_primitives::{Bytecode as RevmBytecode, Bytes}; use byteorder::{BigEndian, ReadBytesExt}; use bytes::Buf; +use derive_more::Deref; use reth_codecs::Compact; use revm_primitives::JumpTable; use serde::{Deserialize, Serialize}; -use std::ops::Deref; pub use reth_primitives_traits::Account; /// Bytecode for an account. /// /// A wrapper around [`revm::primitives::Bytecode`][RevmBytecode] with encoding/decoding support. -#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize, Deref)] pub struct Bytecode(pub RevmBytecode); impl Bytecode { @@ -23,14 +23,6 @@ impl Bytecode { } } -impl Deref for Bytecode { - type Target = RevmBytecode; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - impl Compact for Bytecode { fn to_compact(self, buf: &mut B) -> usize where diff --git a/crates/primitives/src/alloy_compat.rs b/crates/primitives/src/alloy_compat.rs index 492bb15337..d193b787fd 100644 --- a/crates/primitives/src/alloy_compat.rs +++ b/crates/primitives/src/alloy_compat.rs @@ -1,13 +1,16 @@ //! Common conversions from alloy types. use crate::{ - constants::EMPTY_TRANSACTIONS, transaction::extract_chain_id, Block, Header, Signature, - Transaction, TransactionSigned, TransactionSignedEcRecovered, TxEip1559, TxEip2930, TxEip4844, - TxLegacy, TxType, + constants::EMPTY_TRANSACTIONS, transaction::extract_chain_id, Block, Signature, Transaction, + TransactionSigned, TransactionSignedEcRecovered, TxEip1559, TxEip2930, TxEip4844, TxLegacy, + TxType, }; use alloy_primitives::TxKind; use alloy_rlp::Error as RlpError; +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; + impl TryFrom for Block { type Error = alloy_rpc_types::ConversionError; @@ -61,54 +64,6 @@ impl TryFrom for Block { } } -impl TryFrom for Header { - type Error = alloy_rpc_types::ConversionError; - - fn try_from(header: alloy_rpc_types::Header) -> Result { - use alloy_rpc_types::ConversionError; - - Ok(Self { - base_fee_per_gas: header - .base_fee_per_gas - .map(|base_fee_per_gas| { - base_fee_per_gas.try_into().map_err(ConversionError::BaseFeePerGasConversion) - }) - .transpose()?, - beneficiary: header.miner, - blob_gas_used: header - .blob_gas_used - .map(|blob_gas_used| { - blob_gas_used.try_into().map_err(ConversionError::BlobGasUsedConversion) - }) - .transpose()?, - difficulty: header.difficulty, - excess_blob_gas: header - .excess_blob_gas - .map(|excess_blob_gas| { - excess_blob_gas.try_into().map_err(ConversionError::ExcessBlobGasConversion) - }) - .transpose()?, - extra_data: header.extra_data, - gas_limit: header.gas_limit.try_into().map_err(ConversionError::GasLimitConversion)?, - gas_used: header.gas_used.try_into().map_err(ConversionError::GasUsedConversion)?, - logs_bloom: header.logs_bloom, - mix_hash: header.mix_hash.unwrap_or_default(), - nonce: u64::from_be_bytes(header.nonce.unwrap_or_default().0), - number: header.number.ok_or(ConversionError::MissingBlockNumber)?, - ommers_hash: header.uncles_hash, - parent_beacon_block_root: header.parent_beacon_block_root, - parent_hash: header.parent_hash, - receipts_root: header.receipts_root, - state_root: header.state_root, - timestamp: header.timestamp, - transactions_root: header.transactions_root, - withdrawals_root: header.withdrawals_root, - // TODO: requests_root: header.requests_root, - requests_root: None, - }) - } -} - impl TryFrom for Transaction { type Error = alloy_rpc_types::ConversionError; diff --git a/crates/primitives/src/block.rs b/crates/primitives/src/block.rs index af0e2680ca..1e14392bff 100644 --- a/crates/primitives/src/block.rs +++ b/crates/primitives/src/block.rs @@ -2,16 +2,20 @@ use crate::{ Address, Bytes, GotExpected, Header, Requests, SealedHeader, TransactionSigned, TransactionSignedEcRecovered, Withdrawals, B256, }; -use alloy_rlp::{RlpDecodable, RlpEncodable}; -#[cfg(any(test, feature = "arbitrary"))] -use proptest::prelude::{any, prop_compose}; -use reth_codecs::derive_arbitrary; -use serde::{Deserialize, Serialize}; -use std::ops::Deref; - pub use alloy_eips::eip1898::{ BlockHashOrNumber, BlockId, BlockNumHash, BlockNumberOrTag, ForkBlock, RpcBlockHash, }; +use alloy_rlp::{RlpDecodable, RlpEncodable}; +use derive_more::{Deref, DerefMut}; +#[cfg(any(test, feature = "arbitrary"))] +use proptest::prelude::prop_compose; +use reth_codecs::derive_arbitrary; +#[cfg(any(test, feature = "arbitrary"))] +pub use reth_primitives_traits::test_utils::{generate_valid_header, valid_header_strategy}; +use serde::{Deserialize, Serialize}; + +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; // HACK(onbjerg): we need this to always set `requests` to `None` since we might otherwise generate // a block with `None` withdrawals and `Some` requests, in which case we end up trying to decode the @@ -28,12 +32,13 @@ prop_compose! { /// Withdrawals can be optionally included at the end of the RLP encoded message. #[derive_arbitrary(rlp, 25)] #[derive( - Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize, RlpEncodable, RlpDecodable, + Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize, Deref, RlpEncodable, RlpDecodable, )] #[rlp(trailing)] pub struct Block { /// Block header. #[cfg_attr(any(test, feature = "arbitrary"), proptest(strategy = "valid_header_strategy()"))] + #[deref] pub header: Header, /// Transactions in this block. #[cfg_attr( @@ -175,23 +180,18 @@ impl Block { pub fn size(&self) -> usize { self.header.size() + // take into account capacity - self.body.iter().map(TransactionSigned::size).sum::() + self.body.capacity() * std::mem::size_of::() + - self.ommers.iter().map(Header::size).sum::() + self.ommers.capacity() * std::mem::size_of::
() + - self.withdrawals.as_ref().map_or(std::mem::size_of::>(), Withdrawals::total_size) - } -} - -impl Deref for Block { - type Target = Header; - fn deref(&self) -> &Self::Target { - &self.header + self.body.iter().map(TransactionSigned::size).sum::() + self.body.capacity() * core::mem::size_of::() + + self.ommers.iter().map(Header::size).sum::() + self.ommers.capacity() * core::mem::size_of::
() + + self.withdrawals.as_ref().map_or(core::mem::size_of::>(), Withdrawals::total_size) } } /// Sealed block with senders recovered from transactions. -#[derive(Debug, Clone, PartialEq, Eq, Default)] +#[derive(Debug, Clone, PartialEq, Eq, Default, Deref, DerefMut)] pub struct BlockWithSenders { /// Block + #[deref] + #[deref_mut] pub block: Block, /// List of senders that match the transactions in the block pub senders: Vec
, @@ -253,30 +253,28 @@ impl BlockWithSenders { } } -impl Deref for BlockWithSenders { - type Target = Block; - fn deref(&self) -> &Self::Target { - &self.block - } -} - -#[cfg(any(test, feature = "test-utils"))] -impl std::ops::DerefMut for BlockWithSenders { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.block - } -} - /// Sealed Ethereum full block. /// /// Withdrawals can be optionally included at the end of the RLP encoded message. #[derive_arbitrary(rlp)] #[derive( - Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize, RlpEncodable, RlpDecodable, + Debug, + Clone, + PartialEq, + Eq, + Default, + Serialize, + Deserialize, + Deref, + DerefMut, + RlpEncodable, + RlpDecodable, )] #[rlp(trailing)] pub struct SealedBlock { /// Locked block header. + #[deref] + #[deref_mut] pub header: SealedHeader, /// Transactions with signatures. #[cfg_attr( @@ -397,9 +395,9 @@ impl SealedBlock { pub fn size(&self) -> usize { self.header.size() + // take into account capacity - self.body.iter().map(TransactionSigned::size).sum::() + self.body.capacity() * std::mem::size_of::() + - self.ommers.iter().map(Header::size).sum::() + self.ommers.capacity() * std::mem::size_of::
() + - self.withdrawals.as_ref().map_or(std::mem::size_of::>(), Withdrawals::total_size) + self.body.iter().map(TransactionSigned::size).sum::() + self.body.capacity() * core::mem::size_of::() + + self.ommers.iter().map(Header::size).sum::() + self.ommers.capacity() * core::mem::size_of::
() + + self.withdrawals.as_ref().map_or(core::mem::size_of::>(), Withdrawals::total_size) } /// Calculates the total gas used by blob transactions in the sealed block. @@ -450,24 +448,12 @@ impl From for Block { } } -impl Deref for SealedBlock { - type Target = SealedHeader; - fn deref(&self) -> &Self::Target { - &self.header - } -} - -#[cfg(any(test, feature = "test-utils"))] -impl std::ops::DerefMut for SealedBlock { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.header - } -} - /// Sealed block with senders recovered from transactions. -#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize)] +#[derive(Debug, Clone, PartialEq, Eq, Default, Serialize, Deserialize, Deref, DerefMut)] pub struct SealedBlockWithSenders { /// Sealed block + #[deref] + #[deref_mut] pub block: SealedBlock, /// List of senders that match transactions from block. pub senders: Vec
, @@ -521,20 +507,6 @@ impl SealedBlockWithSenders { } } -impl Deref for SealedBlockWithSenders { - type Target = SealedBlock; - fn deref(&self) -> &Self::Target { - &self.block - } -} - -#[cfg(any(test, feature = "test-utils"))] -impl std::ops::DerefMut for SealedBlockWithSenders { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.block - } -} - /// A response to `GetBlockBodies`, containing bodies if any bodies were found. /// /// Withdrawals can be optionally included at the end of the RLP encoded message. @@ -604,12 +576,12 @@ impl BlockBody { #[inline] pub fn size(&self) -> usize { self.transactions.iter().map(TransactionSigned::size).sum::() + - self.transactions.capacity() * std::mem::size_of::() + + self.transactions.capacity() * core::mem::size_of::() + self.ommers.iter().map(Header::size).sum::() + - self.ommers.capacity() * std::mem::size_of::
() + + self.ommers.capacity() * core::mem::size_of::
() + self.withdrawals .as_ref() - .map_or(std::mem::size_of::>(), Withdrawals::total_size) + .map_or(core::mem::size_of::>(), Withdrawals::total_size) } } @@ -624,69 +596,6 @@ impl From for BlockBody { } } -/// Generates a header which is valid __with respect to past and future forks__. This means, for -/// example, that if the withdrawals root is present, the base fee per gas is also present. -/// -/// If blob gas used were present, then the excess blob gas and parent beacon block root are also -/// present. In this example, the withdrawals root would also be present. -/// -/// This __does not, and should not guarantee__ that the header is valid with respect to __anything -/// else__. -#[cfg(any(test, feature = "arbitrary"))] -pub fn generate_valid_header( - mut header: Header, - eip_4844_active: bool, - blob_gas_used: u64, - excess_blob_gas: u64, - parent_beacon_block_root: B256, -) -> Header { - // EIP-1559 logic - if header.base_fee_per_gas.is_none() { - // If EIP-1559 is not active, clear related fields - header.withdrawals_root = None; - header.blob_gas_used = None; - header.excess_blob_gas = None; - header.parent_beacon_block_root = None; - } else if header.withdrawals_root.is_none() { - // If EIP-4895 is not active, clear related fields - header.blob_gas_used = None; - header.excess_blob_gas = None; - header.parent_beacon_block_root = None; - } else if eip_4844_active { - // Set fields based on EIP-4844 being active - header.blob_gas_used = Some(blob_gas_used); - header.excess_blob_gas = Some(excess_blob_gas); - header.parent_beacon_block_root = Some(parent_beacon_block_root); - } else { - // If EIP-4844 is not active, clear related fields - header.blob_gas_used = None; - header.excess_blob_gas = None; - header.parent_beacon_block_root = None; - } - - // todo(onbjerg): adjust this for eip-7589 - header.requests_root = None; - - header -} - -#[cfg(any(test, feature = "arbitrary"))] -prop_compose! { - /// Generates a proptest strategy for constructing an instance of a header which is valid __with - /// respect to past and future forks__. - /// - /// See docs for [generate_valid_header] for more information. - pub fn valid_header_strategy()( - header in any::
(), - eip_4844_active in any::(), - blob_gas_used in any::(), - excess_blob_gas in any::(), - parent_beacon_block_root in any::() - ) -> Header { - generate_valid_header(header, eip_4844_active, blob_gas_used, excess_blob_gas, parent_beacon_block_root) - } -} - #[cfg(test)] mod tests { use super::{BlockNumberOrTag::*, *}; diff --git a/crates/primitives/src/chain/spec.rs b/crates/primitives/src/chain/spec.rs index 5bdc5d9c22..788acf7b19 100644 --- a/crates/primitives/src/chain/spec.rs +++ b/crates/primitives/src/chain/spec.rs @@ -5,19 +5,30 @@ use crate::{ }, holesky_nodes, net::{goerli_nodes, mainnet_nodes, sepolia_nodes}, - proofs::state_root_ref_unhashed, revm_primitives::{address, b256}, Address, BlockNumber, Chain, ChainKind, ForkFilter, ForkFilterKey, ForkHash, ForkId, Genesis, Hardfork, Head, Header, NamedChain, NodeRecord, SealedHeader, B256, EMPTY_OMMER_ROOT_HASH, MAINNET_DEPOSIT_CONTRACT, U256, }; -use once_cell::sync::Lazy; -use serde::{Deserialize, Serialize}; -use std::{ - collections::BTreeMap, +use core::{ + fmt, fmt::{Display, Formatter}, - sync::Arc, }; +use derive_more::From; +use once_cell::sync::Lazy; +use reth_trie_common::root::state_root_ref_unhashed; +use serde::{Deserialize, Serialize}; + +#[cfg(not(feature = "std"))] +use alloc::{ + collections::BTreeMap, + format, + string::{String, ToString}, + sync::Arc, + vec::Vec, +}; +#[cfg(feature = "std")] +use std::{collections::BTreeMap, sync::Arc}; pub use alloy_eips::eip1559::BaseFeeParams; @@ -484,15 +495,9 @@ impl From for BaseFeeParamsKind { /// A type alias to a vector of tuples of [Hardfork] and [`BaseFeeParams`], sorted by [Hardfork] /// activation order. This is used to specify dynamic EIP-1559 parameters for chains like Optimism. -#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] +#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, From)] pub struct ForkBaseFeeParams(Vec<(Hardfork, BaseFeeParams)>); -impl From> for ForkBaseFeeParams { - fn from(params: Vec<(Hardfork, BaseFeeParams)>) -> Self { - Self(params) - } -} - /// An Ethereum chain specification. /// /// A chain specification describes: @@ -847,6 +852,12 @@ impl ChainSpec { self.fork(Hardfork::Homestead).active_at_block(block_number) } + /// The Paris hardfork (merge) is activated via ttd, if we know the block is known then this + /// returns true if the block number is greater than or equal to the Paris (merge) block. + pub fn is_paris_active_at_block(&self, block_number: u64) -> Option { + self.paris_block_and_final_difficulty.map(|(paris_block, _)| block_number >= paris_block) + } + /// Convenience method to check if [`Hardfork::Bedrock`] is active at a given block number. #[cfg(feature = "optimism")] #[inline] @@ -1476,7 +1487,7 @@ struct DisplayFork { } impl Display for DisplayFork { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { let name_with_eip = if let Some(eip) = &self.eip { format!("{} ({})", self.name, eip) } else { @@ -1550,13 +1561,13 @@ pub struct DisplayHardforks { } impl Display for DisplayHardforks { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn format( header: &str, forks: &[DisplayFork], next_is_empty: bool, f: &mut Formatter<'_>, - ) -> std::fmt::Result { + ) -> fmt::Result { writeln!(f, "{header}:")?; let mut iter = forks.iter().peekable(); while let Some(fork) = iter.next() { @@ -1726,8 +1737,10 @@ impl OptimismGenesisInfo { #[cfg(test)] mod tests { + use reth_trie_common::TrieAccount; + use super::*; - use crate::{b256, hex, proofs::IntoTrieAccount, ChainConfig, GenesisAccount}; + use crate::{b256, hex, ChainConfig, GenesisAccount}; use std::{collections::HashMap, str::FromStr}; fn test_fork_ids(spec: &ChainSpec, cases: &[(Head, ForkId)]) { for (block, expected_id) in cases { @@ -2829,10 +2842,7 @@ Post-merge hard forks (timestamp based): for (key, expected_rlp) in key_rlp { let account = chainspec.genesis.alloc.get(&key).expect("account should exist"); - assert_eq!( - &alloy_rlp::encode(IntoTrieAccount::to_trie_account(account.clone())), - expected_rlp - ); + assert_eq!(&alloy_rlp::encode(TrieAccount::from(account.clone())), expected_rlp); } assert_eq!(chainspec.genesis_hash, None); diff --git a/crates/primitives/src/compression/mod.rs b/crates/primitives/src/compression/mod.rs index 91bb544fea..f7af0acbe4 100644 --- a/crates/primitives/src/compression/mod.rs +++ b/crates/primitives/src/compression/mod.rs @@ -1,6 +1,9 @@ use std::{cell::RefCell, thread_local}; use zstd::bulk::{Compressor, Decompressor}; +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; + /// Compression/Decompression dictionary for `Receipt`. pub static RECEIPT_DICTIONARY: &[u8] = include_bytes!("./receipt_dictionary.bin"); /// Compression/Decompression dictionary for `Transaction`. diff --git a/crates/primitives/src/constants/eip4844.rs b/crates/primitives/src/constants/eip4844.rs index 3379a9e48e..c1748edf74 100644 --- a/crates/primitives/src/constants/eip4844.rs +++ b/crates/primitives/src/constants/eip4844.rs @@ -38,7 +38,7 @@ mod trusted_setup { } /// Error type for loading the trusted setup. - #[derive(Debug, thiserror::Error)] + #[derive(Debug, thiserror_no_std::Error)] pub enum LoadKzgSettingsError { /// Failed to create temp file to store bytes for loading [`KzgSettings`] via /// [`KzgSettings::load_trusted_setup_file`]. diff --git a/crates/primitives/src/constants/gas_units.rs b/crates/primitives/src/constants/gas_units.rs new file mode 100644 index 0000000000..9916de864a --- /dev/null +++ b/crates/primitives/src/constants/gas_units.rs @@ -0,0 +1,8 @@ +/// Represents one Kilogas, or `1_000` gas. +pub const KILOGAS: u64 = 1_000; + +/// Represents one Megagas, or `1_000_000` gas. +pub const MEGAGAS: u64 = KILOGAS * 1_000; + +/// Represents one Gigagas, or `1_000_000_000` gas. +pub const GIGAGAS: u64 = MEGAGAS * 1_000; diff --git a/crates/primitives/src/constants/mod.rs b/crates/primitives/src/constants/mod.rs index be8ca1564b..41a26d609e 100644 --- a/crates/primitives/src/constants/mod.rs +++ b/crates/primitives/src/constants/mod.rs @@ -3,113 +3,26 @@ use crate::{ chain::DepositContract, revm_primitives::{address, b256}, - B256, U256, }; -use std::time::Duration; + +pub use reth_primitives_traits::constants::*; #[cfg(feature = "optimism")] use crate::chain::BaseFeeParams; +/// Gas units, for example [`GIGAGAS`](gas_units::GIGAGAS). +pub mod gas_units; + /// [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844#parameters) constants. pub mod eip4844; -/// The client version: `reth/v{major}.{minor}.{patch}` -pub const RETH_CLIENT_VERSION: &str = concat!("reth/v", env!("CARGO_PKG_VERSION")); - -/// The first four bytes of the call data for a function call specifies the function to be called. -pub const SELECTOR_LEN: usize = 4; - -/// Maximum extra data size in a block after genesis -pub const MAXIMUM_EXTRA_DATA_SIZE: usize = 32; - -/// An EPOCH is a series of 32 slots. -pub const EPOCH_SLOTS: u64 = 32; - -/// The duration of a slot in seconds. -/// -/// This is the time period of 12 seconds in which a randomly chosen validator has time to propose a -/// block. -pub const SLOT_DURATION: Duration = Duration::from_secs(12); - -/// An EPOCH is a series of 32 slots (~6.4min). -pub const EPOCH_DURATION: Duration = Duration::from_secs(12 * EPOCH_SLOTS); - -/// The default block nonce in the beacon consensus -pub const BEACON_NONCE: u64 = 0u64; - -/// The default Ethereum block gas limit. -// TODO: This should be a chain spec parameter. -/// See . -pub const ETHEREUM_BLOCK_GAS_LIMIT: u64 = 30_000_000; - -/// The minimum tx fee below which the txpool will reject the transaction. -/// -/// Configured to `7` WEI which is the lowest possible value of base fee under mainnet EIP-1559 -/// parameters. `BASE_FEE_MAX_CHANGE_DENOMINATOR` -/// is `8`, or 12.5%. Once the base fee has dropped to `7` WEI it cannot decrease further because -/// 12.5% of 7 is less than 1. -/// -/// Note that min base fee under different 1559 parameterizations may differ, but there's no -/// significant harm in leaving this setting as is. -pub const MIN_PROTOCOL_BASE_FEE: u64 = 7; - -/// Same as [`MIN_PROTOCOL_BASE_FEE`] but as a U256. -pub const MIN_PROTOCOL_BASE_FEE_U256: U256 = U256::from_limbs([7u64, 0, 0, 0]); - -/// Initial base fee as defined in [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559) -pub const EIP1559_INITIAL_BASE_FEE: u64 = 1_000_000_000; - -/// Base fee max change denominator as defined in [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559) -pub const EIP1559_DEFAULT_BASE_FEE_MAX_CHANGE_DENOMINATOR: u64 = 8; - -/// Elasticity multiplier as defined in [EIP-1559](https://eips.ethereum.org/EIPS/eip-1559) -pub const EIP1559_DEFAULT_ELASTICITY_MULTIPLIER: u64 = 2; - -/// Minimum gas limit allowed for transactions. -pub const MINIMUM_GAS_LIMIT: u64 = 5000; - -/// Deposit contract address +/// Deposit contract address: `0x00000000219ab540356cbb839cbe05303d7705fa` pub const MAINNET_DEPOSIT_CONTRACT: DepositContract = DepositContract::new( address!("00000000219ab540356cbb839cbe05303d7705fa"), 11052984, b256!("649bbc62d0e31342afea4e5cd82d4049e7e1ee912fc0889aa790803be39038c5"), ); -/// Base fee max change denominator for Optimism Mainnet as defined in the Optimism -/// [transaction costs](https://community.optimism.io/docs/developers/build/differences/#transaction-costs) doc. -#[cfg(feature = "optimism")] -pub const OP_MAINNET_EIP1559_DEFAULT_BASE_FEE_MAX_CHANGE_DENOMINATOR: u128 = 50; - -/// Base fee max change denominator for Optimism Mainnet as defined in the Optimism Canyon -/// hardfork. -#[cfg(feature = "optimism")] -pub const OP_MAINNET_EIP1559_BASE_FEE_MAX_CHANGE_DENOMINATOR_CANYON: u128 = 250; - -/// Base fee max change denominator for Optimism Mainnet as defined in the Optimism -/// [transaction costs](https://community.optimism.io/docs/developers/build/differences/#transaction-costs) doc. -#[cfg(feature = "optimism")] -pub const OP_MAINNET_EIP1559_DEFAULT_ELASTICITY_MULTIPLIER: u128 = 6; - -/// Base fee max change denominator for Optimism Sepolia as defined in the Optimism -/// [transaction costs](https://community.optimism.io/docs/developers/build/differences/#transaction-costs) doc. -#[cfg(feature = "optimism")] -pub const OP_SEPOLIA_EIP1559_DEFAULT_BASE_FEE_MAX_CHANGE_DENOMINATOR: u128 = 50; - -/// Base fee max change denominator for Optimism Sepolia as defined in the Optimism Canyon -/// hardfork. -#[cfg(feature = "optimism")] -pub const OP_SEPOLIA_EIP1559_BASE_FEE_MAX_CHANGE_DENOMINATOR_CANYON: u128 = 250; - -/// Base fee max change denominator for Optimism Sepolia as defined in the Optimism -/// [transaction costs](https://community.optimism.io/docs/developers/build/differences/#transaction-costs) doc. -#[cfg(feature = "optimism")] -pub const OP_SEPOLIA_EIP1559_DEFAULT_ELASTICITY_MULTIPLIER: u128 = 6; - -/// Base fee max change denominator for Base Sepolia as defined in the Optimism -/// [transaction costs](https://community.optimism.io/docs/developers/build/differences/#transaction-costs) doc. -#[cfg(feature = "optimism")] -pub const BASE_SEPOLIA_EIP1559_DEFAULT_ELASTICITY_MULTIPLIER: u128 = 10; - /// Get the base fee parameters for Base Sepolia. #[cfg(feature = "optimism")] pub const BASE_SEPOLIA_BASE_FEE_PARAMS: BaseFeeParams = BaseFeeParams { @@ -152,78 +65,6 @@ pub const OP_CANYON_BASE_FEE_PARAMS: BaseFeeParams = BaseFeeParams { elasticity_multiplier: OP_MAINNET_EIP1559_DEFAULT_ELASTICITY_MULTIPLIER, }; -/// Multiplier for converting gwei to wei. -pub const GWEI_TO_WEI: u64 = 1_000_000_000; - -/// Multiplier for converting finney (milliether) to wei. -pub const FINNEY_TO_WEI: u128 = (GWEI_TO_WEI as u128) * 1_000_000; - -/// Multiplier for converting ether to wei. -pub const ETH_TO_WEI: u128 = FINNEY_TO_WEI * 1000; - -/// Multiplier for converting mgas to gas. -pub const MGAS_TO_GAS: u64 = 1_000_000u64; - -/// The Ethereum mainnet genesis hash. -pub const MAINNET_GENESIS_HASH: B256 = - b256!("d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3"); - -/// Goerli genesis hash. -pub const GOERLI_GENESIS_HASH: B256 = - b256!("bf7e331f7f7c1dd2e05159666b3bf8bc7a8a3a9eb1d518969eab529dd9b88c1a"); - -/// Sepolia genesis hash. -pub const SEPOLIA_GENESIS_HASH: B256 = - b256!("25a5cc106eea7138acab33231d7160d69cb777ee0c2c553fcddf5138993e6dd9"); - -/// Holesky genesis hash. -pub const HOLESKY_GENESIS_HASH: B256 = - b256!("ff9006519a8ce843ac9c28549d24211420b546e12ce2d170c77a8cca7964f23d"); - -/// Testnet genesis hash. -pub const DEV_GENESIS_HASH: B256 = - b256!("2f980576711e3617a5e4d83dd539548ec0f7792007d505a3d2e9674833af2d7c"); - -/// Keccak256 over empty array. -pub const KECCAK_EMPTY: B256 = - b256!("c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"); - -/// Ommer root of empty list. -pub const EMPTY_OMMER_ROOT_HASH: B256 = - b256!("1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347"); - -/// Root hash of an empty trie. -pub const EMPTY_ROOT_HASH: B256 = - b256!("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421"); - -/// Transactions root of empty receipts set. -pub const EMPTY_RECEIPTS: B256 = EMPTY_ROOT_HASH; - -/// Transactions root of empty transactions set. -pub const EMPTY_TRANSACTIONS: B256 = EMPTY_ROOT_HASH; - -/// Withdrawals root of empty withdrawals set. -pub const EMPTY_WITHDRAWALS: B256 = EMPTY_ROOT_HASH; - -/// The number of blocks to unwind during a reorg that already became a part of canonical chain. -/// -/// In reality, the node can end up in this particular situation very rarely. It would happen only -/// if the node process is abruptly terminated during ongoing reorg and doesn't boot back up for -/// long period of time. -/// -/// Unwind depth of `3` blocks significantly reduces the chance that the reorged block is kept in -/// the database. -pub const BEACON_CONSENSUS_REORG_UNWIND_DEPTH: u64 = 3; - -/// Max seconds from current time allowed for blocks, before they're considered future blocks. -/// -/// This is only used when checking whether or not the timestamp for pre-merge blocks is in the -/// future. -/// -/// See: -/// -pub const ALLOWED_FUTURE_BLOCK_TIME_SECONDS: u64 = 15; - #[cfg(test)] mod tests { use super::*; diff --git a/crates/primitives/src/error.rs b/crates/primitives/src/error.rs index 42257cc7ba..8ae946c242 100644 --- a/crates/primitives/src/error.rs +++ b/crates/primitives/src/error.rs @@ -1,8 +1,11 @@ -use std::{ +use core::{ fmt, ops::{Deref, DerefMut}, }; +#[cfg(not(feature = "std"))] +use alloc::boxed::Box; + /// A pair of values, one of which is expected and one of which is actual. #[derive(Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct GotExpected { @@ -18,6 +21,7 @@ impl fmt::Display for GotExpected { } } +#[cfg(feature = "std")] impl std::error::Error for GotExpected {} impl From<(T, T)> for GotExpected { @@ -55,6 +59,7 @@ impl fmt::Display for GotExpectedBoxed { } } +#[cfg(feature = "std")] impl std::error::Error for GotExpectedBoxed {} impl Deref for GotExpectedBoxed { diff --git a/crates/primitives/src/header.rs b/crates/primitives/src/header.rs index abb5e1f341..ea80328e75 100644 --- a/crates/primitives/src/header.rs +++ b/crates/primitives/src/header.rs @@ -1,958 +1,11 @@ -#[cfg(any(test, feature = "arbitrary"))] -use crate::block::{generate_valid_header, valid_header_strategy}; -use crate::{ - basefee::calc_next_block_base_fee, - constants, - constants::{ - ALLOWED_FUTURE_BLOCK_TIME_SECONDS, EMPTY_OMMER_ROOT_HASH, EMPTY_ROOT_HASH, - MINIMUM_GAS_LIMIT, - }, - eip4844::{calc_blob_gasprice, calculate_excess_blob_gas}, - keccak256, Address, BaseFeeParams, BlockHash, BlockNumHash, BlockNumber, Bloom, Bytes, - ChainSpec, GotExpected, GotExpectedBoxed, Hardfork, B256, B64, U256, -}; -use alloy_rlp::{length_of_length, Decodable, Encodable}; +//! Header types. + +use alloy_rlp::{Decodable, Encodable}; use bytes::BufMut; -#[cfg(any(test, feature = "arbitrary"))] -use proptest::prelude::*; -use reth_codecs::{add_arbitrary_tests, derive_arbitrary, main_codec, Compact}; +use reth_codecs::derive_arbitrary; use serde::{Deserialize, Serialize}; -use std::{mem, ops::Deref}; -/// Errors that can occur during header sanity checks. -#[derive(Debug, PartialEq, Eq)] -pub enum HeaderError { - /// Represents an error when the block difficulty is too large. - LargeDifficulty, - /// Represents an error when the block extradata is too large. - LargeExtraData, -} - -/// Block header -#[main_codec] -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct Header { - /// The Keccak 256-bit hash of the parent - /// block’s header, in its entirety; formally Hp. - pub parent_hash: B256, - /// The Keccak 256-bit hash of the ommers list portion of this block; formally Ho. - pub ommers_hash: B256, - /// The 160-bit address to which all fees collected from the successful mining of this block - /// be transferred; formally Hc. - pub beneficiary: Address, - /// The Keccak 256-bit hash of the root node of the state trie, after all transactions are - /// executed and finalisations applied; formally Hr. - pub state_root: B256, - /// The Keccak 256-bit hash of the root node of the trie structure populated with each - /// transaction in the transactions list portion of the block; formally Ht. - pub transactions_root: B256, - /// The Keccak 256-bit hash of the root node of the trie structure populated with the receipts - /// of each transaction in the transactions list portion of the block; formally He. - pub receipts_root: B256, - /// The Keccak 256-bit hash of the withdrawals list portion of this block. - /// - /// See [EIP-4895](https://eips.ethereum.org/EIPS/eip-4895). - pub withdrawals_root: Option, - /// The Bloom filter composed from indexable information (logger address and log topics) - /// contained in each log entry from the receipt of each transaction in the transactions list; - /// formally Hb. - pub logs_bloom: Bloom, - /// A scalar value corresponding to the difficulty level of this block. This can be calculated - /// from the previous block’s difficulty level and the timestamp; formally Hd. - pub difficulty: U256, - /// A scalar value equal to the number of ancestor blocks. The genesis block has a number of - /// zero; formally Hi. - pub number: BlockNumber, - /// A scalar value equal to the current limit of gas expenditure per block; formally Hl. - pub gas_limit: u64, - /// A scalar value equal to the total gas used in transactions in this block; formally Hg. - pub gas_used: u64, - /// A scalar value equal to the reasonable output of Unix’s time() at this block’s inception; - /// formally Hs. - pub timestamp: u64, - /// A 256-bit hash which, combined with the - /// nonce, proves that a sufficient amount of computation has been carried out on this block; - /// formally Hm. - pub mix_hash: B256, - /// A 64-bit value which, combined with the mixhash, proves that a sufficient amount of - /// computation has been carried out on this block; formally Hn. - pub nonce: u64, - /// A scalar representing EIP1559 base fee which can move up or down each block according - /// to a formula which is a function of gas used in parent block and gas target - /// (block gas limit divided by elasticity multiplier) of parent block. - /// The algorithm results in the base fee per gas increasing when blocks are - /// above the gas target, and decreasing when blocks are below the gas target. The base fee per - /// gas is burned. - pub base_fee_per_gas: Option, - /// The total amount of blob gas consumed by the transactions within the block, added in - /// EIP-4844. - pub blob_gas_used: Option, - /// A running total of blob gas consumed in excess of the target, prior to the block. Blocks - /// with above-target blob gas consumption increase this value, blocks with below-target blob - /// gas consumption decrease it (bounded at 0). This was added in EIP-4844. - pub excess_blob_gas: Option, - /// The hash of the parent beacon block's root is included in execution blocks, as proposed by - /// EIP-4788. - /// - /// This enables trust-minimized access to consensus state, supporting staking pools, bridges, - /// and more. - /// - /// The beacon roots contract handles root storage, enhancing Ethereum's functionalities. - pub parent_beacon_block_root: Option, - /// The Keccak 256-bit hash of the root node of the trie structure populated with each - /// [EIP-7685] request in the block body. - /// - /// [EIP-7685]: https://eips.ethereum.org/EIPS/eip-7685 - pub requests_root: Option, - /// An arbitrary byte array containing data relevant to this block. This must be 32 bytes or - /// fewer; formally Hx. - pub extra_data: Bytes, -} - -impl AsRef for Header { - fn as_ref(&self) -> &Self { - self - } -} - -impl Default for Header { - fn default() -> Self { - Self { - parent_hash: Default::default(), - ommers_hash: EMPTY_OMMER_ROOT_HASH, - beneficiary: Default::default(), - state_root: EMPTY_ROOT_HASH, - transactions_root: EMPTY_ROOT_HASH, - receipts_root: EMPTY_ROOT_HASH, - logs_bloom: Default::default(), - difficulty: Default::default(), - number: 0, - gas_limit: 0, - gas_used: 0, - timestamp: 0, - extra_data: Default::default(), - mix_hash: Default::default(), - nonce: 0, - base_fee_per_gas: None, - withdrawals_root: None, - blob_gas_used: None, - excess_blob_gas: None, - parent_beacon_block_root: None, - requests_root: None, - } - } -} - -impl Header { - /// Checks if the block's difficulty is set to zero, indicating a Proof-of-Stake header. - /// - /// This function is linked to EIP-3675, proposing the consensus upgrade to Proof-of-Stake: - /// [EIP-3675](https://eips.ethereum.org/EIPS/eip-3675#replacing-difficulty-with-0) - /// - /// Verifies whether, as per the EIP, the block's difficulty is updated to zero, - /// signifying the transition to a Proof-of-Stake mechanism. - /// - /// Returns `true` if the block's difficulty matches the constant zero set by the EIP. - pub fn is_zero_difficulty(&self) -> bool { - self.difficulty.is_zero() - } - - /// Performs a sanity check on the extradata field of the header. - /// - /// # Errors - /// - /// Returns an error if the extradata size is larger than 100 KB. - pub fn ensure_extradata_valid(&self) -> Result<(), HeaderError> { - if self.extra_data.len() > 100 * 1024 { - return Err(HeaderError::LargeExtraData) - } - Ok(()) - } - - /// Performs a sanity check on the block difficulty field of the header. - /// - /// # Errors - /// - /// Returns an error if the block difficulty exceeds 80 bits. - pub fn ensure_difficulty_valid(&self) -> Result<(), HeaderError> { - if self.difficulty.bit_len() > 80 { - return Err(HeaderError::LargeDifficulty) - } - Ok(()) - } - - /// Performs combined sanity checks on multiple header fields. - /// - /// This method combines checks for block difficulty and extradata sizes. - /// - /// # Errors - /// - /// Returns an error if either the block difficulty exceeds 80 bits - /// or if the extradata size is larger than 100 KB. - pub fn ensure_well_formed(&self) -> Result<(), HeaderError> { - self.ensure_difficulty_valid()?; - self.ensure_extradata_valid()?; - Ok(()) - } - - /// Checks if the block's timestamp is in the past compared to the parent block's timestamp. - /// - /// Note: This check is relevant only pre-merge. - pub const fn is_timestamp_in_past(&self, parent_timestamp: u64) -> bool { - self.timestamp <= parent_timestamp - } - - /// Checks if the block's timestamp is in the future based on the present timestamp. - /// - /// Clock can drift but this can be consensus issue. - /// - /// Note: This check is relevant only pre-merge. - pub const fn exceeds_allowed_future_timestamp(&self, present_timestamp: u64) -> bool { - self.timestamp > present_timestamp + ALLOWED_FUTURE_BLOCK_TIME_SECONDS - } - - /// Returns the parent block's number and hash - pub const fn parent_num_hash(&self) -> BlockNumHash { - BlockNumHash { number: self.number.saturating_sub(1), hash: self.parent_hash } - } - - /// Heavy function that will calculate hash of data and will *not* save the change to metadata. - /// Use [`Header::seal`], [`SealedHeader`] and unlock if you need hash to be persistent. - pub fn hash_slow(&self) -> B256 { - keccak256(alloy_rlp::encode(self)) - } - - /// Checks if the header is empty - has no transactions and no ommers - pub fn is_empty(&self) -> bool { - self.transaction_root_is_empty() && - self.ommers_hash_is_empty() && - self.withdrawals_root.map_or(true, |root| root == EMPTY_ROOT_HASH) - } - - /// Check if the ommers hash equals to empty hash list. - pub fn ommers_hash_is_empty(&self) -> bool { - self.ommers_hash == EMPTY_OMMER_ROOT_HASH - } - - /// Check if the transaction root equals to empty root. - pub fn transaction_root_is_empty(&self) -> bool { - self.transactions_root == EMPTY_ROOT_HASH - } - - /// Returns the blob fee for _this_ block according to the EIP-4844 spec. - /// - /// Returns `None` if `excess_blob_gas` is None - pub fn blob_fee(&self) -> Option { - self.excess_blob_gas.map(calc_blob_gasprice) - } - - /// Returns the blob fee for the next block according to the EIP-4844 spec. - /// - /// Returns `None` if `excess_blob_gas` is None. - /// - /// See also [`Self::next_block_excess_blob_gas`] - pub fn next_block_blob_fee(&self) -> Option { - self.next_block_excess_blob_gas().map(calc_blob_gasprice) - } - - /// Calculate base fee for next block according to the EIP-1559 spec. - /// - /// Returns a `None` if no base fee is set, no EIP-1559 support - pub fn next_block_base_fee(&self, base_fee_params: BaseFeeParams) -> Option { - Some(calc_next_block_base_fee( - self.gas_used as u128, - self.gas_limit as u128, - self.base_fee_per_gas? as u128, - base_fee_params, - ) as u64) - } - - /// Calculate excess blob gas for the next block according to the EIP-4844 spec. - /// - /// Returns a `None` if no excess blob gas is set, no EIP-4844 support - pub fn next_block_excess_blob_gas(&self) -> Option { - Some(calculate_excess_blob_gas(self.excess_blob_gas?, self.blob_gas_used?)) - } - - /// Seal the header with a known hash. - /// - /// WARNING: This method does not perform validation whether the hash is correct. - #[inline] - pub const fn seal(self, hash: B256) -> SealedHeader { - SealedHeader { header: self, hash } - } - - /// Calculate hash and seal the Header so that it can't be changed. - #[inline] - pub fn seal_slow(self) -> SealedHeader { - let hash = self.hash_slow(); - self.seal(hash) - } - - /// Calculate a heuristic for the in-memory size of the [Header]. - #[inline] - pub fn size(&self) -> usize { - mem::size_of::() + // parent hash - mem::size_of::() + // ommers hash - mem::size_of::
() + // beneficiary - mem::size_of::() + // state root - mem::size_of::() + // transactions root - mem::size_of::() + // receipts root - mem::size_of::>() + // withdrawals root - mem::size_of::() + // logs bloom - mem::size_of::() + // difficulty - mem::size_of::() + // number - mem::size_of::() + // gas limit - mem::size_of::() + // gas used - mem::size_of::() + // timestamp - mem::size_of::() + // mix hash - mem::size_of::() + // nonce - mem::size_of::>() + // base fee per gas - mem::size_of::>() + // blob gas used - mem::size_of::>() + // excess blob gas - mem::size_of::>() + // parent beacon block root - self.extra_data.len() // extra data - } - - fn header_payload_length(&self) -> usize { - let mut length = 0; - length += self.parent_hash.length(); // Hash of the previous block. - length += self.ommers_hash.length(); // Hash of uncle blocks. - length += self.beneficiary.length(); // Address that receives rewards. - length += self.state_root.length(); // Root hash of the state object. - length += self.transactions_root.length(); // Root hash of transactions in the block. - length += self.receipts_root.length(); // Hash of transaction receipts. - length += self.logs_bloom.length(); // Data structure containing event logs. - length += self.difficulty.length(); // Difficulty value of the block. - length += U256::from(self.number).length(); // Block number. - length += U256::from(self.gas_limit).length(); // Maximum gas allowed. - length += U256::from(self.gas_used).length(); // Actual gas used. - length += self.timestamp.length(); // Block timestamp. - length += self.extra_data.length(); // Additional arbitrary data. - length += self.mix_hash.length(); // Hash used for mining. - length += B64::new(self.nonce.to_be_bytes()).length(); // Nonce for mining. - - if let Some(base_fee) = self.base_fee_per_gas { - // Adding base fee length if it exists. - length += U256::from(base_fee).length(); - } - - if let Some(root) = self.withdrawals_root { - // Adding withdrawals_root length if it exists. - length += root.length(); - } - - if let Some(blob_gas_used) = self.blob_gas_used { - // Adding blob_gas_used length if it exists. - length += U256::from(blob_gas_used).length(); - } - - if let Some(excess_blob_gas) = self.excess_blob_gas { - // Adding excess_blob_gas length if it exists. - length += U256::from(excess_blob_gas).length(); - } - - if let Some(parent_beacon_block_root) = self.parent_beacon_block_root { - length += parent_beacon_block_root.length(); - } - - if let Some(requests_root) = self.requests_root { - length += requests_root.length(); - } - - length - } -} - -impl Encodable for Header { - fn encode(&self, out: &mut dyn BufMut) { - // Create a header indicating the encoded content is a list with the payload length computed - // from the header's payload calculation function. - let list_header = - alloy_rlp::Header { list: true, payload_length: self.header_payload_length() }; - list_header.encode(out); - - // Encode each header field sequentially - self.parent_hash.encode(out); // Encode parent hash. - self.ommers_hash.encode(out); // Encode ommer's hash. - self.beneficiary.encode(out); // Encode beneficiary. - self.state_root.encode(out); // Encode state root. - self.transactions_root.encode(out); // Encode transactions root. - self.receipts_root.encode(out); // Encode receipts root. - self.logs_bloom.encode(out); // Encode logs bloom. - self.difficulty.encode(out); // Encode difficulty. - U256::from(self.number).encode(out); // Encode block number. - U256::from(self.gas_limit).encode(out); // Encode gas limit. - U256::from(self.gas_used).encode(out); // Encode gas used. - self.timestamp.encode(out); // Encode timestamp. - self.extra_data.encode(out); // Encode extra data. - self.mix_hash.encode(out); // Encode mix hash. - B64::new(self.nonce.to_be_bytes()).encode(out); // Encode nonce. - - // Encode base fee. Put empty list if base fee is missing, - // but withdrawals root is present. - if let Some(ref base_fee) = self.base_fee_per_gas { - U256::from(*base_fee).encode(out); - } - - // Encode withdrawals root. Put empty string if withdrawals root is missing, - // but blob gas used is present. - if let Some(ref root) = self.withdrawals_root { - root.encode(out); - } - - // Encode blob gas used. Put empty list if blob gas used is missing, - // but excess blob gas is present. - if let Some(ref blob_gas_used) = self.blob_gas_used { - U256::from(*blob_gas_used).encode(out); - } - - // Encode excess blob gas. Put empty list if excess blob gas is missing, - // but parent beacon block root is present. - if let Some(ref excess_blob_gas) = self.excess_blob_gas { - U256::from(*excess_blob_gas).encode(out); - } - - // Encode parent beacon block root. - if let Some(ref parent_beacon_block_root) = self.parent_beacon_block_root { - parent_beacon_block_root.encode(out); - } - - // Encode EIP-7685 requests root - // - // If new fields are added, the above pattern will need to - // be repeated and placeholders added. Otherwise, it's impossible to tell _which_ - // fields are missing. This is mainly relevant for contrived cases where a header is - // created at random, for example: - // * A header is created with a withdrawals root, but no base fee. Shanghai blocks are - // post-London, so this is technically not valid. However, a tool like proptest would - // generate a block like this. - if let Some(ref requests_root) = self.requests_root { - requests_root.encode(out); - } - } - - fn length(&self) -> usize { - let mut length = 0; - length += self.header_payload_length(); - length += length_of_length(length); - length - } -} - -impl Decodable for Header { - fn decode(buf: &mut &[u8]) -> alloy_rlp::Result { - let rlp_head = alloy_rlp::Header::decode(buf)?; - if !rlp_head.list { - return Err(alloy_rlp::Error::UnexpectedString) - } - let started_len = buf.len(); - let mut this = Self { - parent_hash: Decodable::decode(buf)?, - ommers_hash: Decodable::decode(buf)?, - beneficiary: Decodable::decode(buf)?, - state_root: Decodable::decode(buf)?, - transactions_root: Decodable::decode(buf)?, - receipts_root: Decodable::decode(buf)?, - logs_bloom: Decodable::decode(buf)?, - difficulty: Decodable::decode(buf)?, - number: u64::decode(buf)?, - gas_limit: u64::decode(buf)?, - gas_used: u64::decode(buf)?, - timestamp: Decodable::decode(buf)?, - extra_data: Decodable::decode(buf)?, - mix_hash: Decodable::decode(buf)?, - nonce: u64::from_be_bytes(B64::decode(buf)?.0), - base_fee_per_gas: None, - withdrawals_root: None, - blob_gas_used: None, - excess_blob_gas: None, - parent_beacon_block_root: None, - requests_root: None, - }; - if started_len - buf.len() < rlp_head.payload_length { - this.base_fee_per_gas = Some(u64::decode(buf)?); - } - - // Withdrawals root for post-shanghai headers - if started_len - buf.len() < rlp_head.payload_length { - this.withdrawals_root = Some(Decodable::decode(buf)?); - } - - // Blob gas used and excess blob gas for post-cancun headers - if started_len - buf.len() < rlp_head.payload_length { - this.blob_gas_used = Some(u64::decode(buf)?); - } - - if started_len - buf.len() < rlp_head.payload_length { - this.excess_blob_gas = Some(u64::decode(buf)?); - } - - // Decode parent beacon block root. - if started_len - buf.len() < rlp_head.payload_length { - this.parent_beacon_block_root = Some(B256::decode(buf)?); - } - - // Decode requests root. - // - // If new fields are added, the above pattern will need to - // be repeated and placeholders decoded. Otherwise, it's impossible to tell _which_ - // fields are missing. This is mainly relevant for contrived cases where a header is - // created at random, for example: - // * A header is created with a withdrawals root, but no base fee. Shanghai blocks are - // post-London, so this is technically not valid. However, a tool like proptest would - // generate a block like this. - if started_len - buf.len() < rlp_head.payload_length { - this.requests_root = Some(B256::decode(buf)?); - } - - let consumed = started_len - buf.len(); - if consumed != rlp_head.payload_length { - return Err(alloy_rlp::Error::ListLengthMismatch { - expected: rlp_head.payload_length, - got: consumed, - }) - } - Ok(this) - } -} - -/// Errors that can occur during header sanity checks. -#[derive(thiserror::Error, Debug, PartialEq, Eq, Clone)] -pub enum HeaderValidationError { - /// Error when the block number does not match the parent block number. - #[error( - "block number {block_number} does not match parent block number {parent_block_number}" - )] - ParentBlockNumberMismatch { - /// The parent block number. - parent_block_number: BlockNumber, - /// The block number. - block_number: BlockNumber, - }, - - /// Error when the parent hash does not match the expected parent hash. - #[error("mismatched parent hash: {0}")] - ParentHashMismatch(GotExpectedBoxed), - - /// Error when the block timestamp is in the past compared to the parent timestamp. - #[error("block timestamp {timestamp} is in the past compared to the parent timestamp {parent_timestamp}")] - TimestampIsInPast { - /// The parent block's timestamp. - parent_timestamp: u64, - /// The block's timestamp. - timestamp: u64, - }, - - /// Error when the base fee is missing. - #[error("base fee missing")] - BaseFeeMissing, - - /// Error when the block's base fee is different from the expected base fee. - #[error("block base fee mismatch: {0}")] - BaseFeeDiff(GotExpected), - - /// Error when the child gas limit exceeds the maximum allowed decrease. - #[error("child gas_limit {child_gas_limit} max decrease is {parent_gas_limit}/1024")] - GasLimitInvalidDecrease { - /// The parent gas limit. - parent_gas_limit: u64, - /// The child gas limit. - child_gas_limit: u64, - }, - - /// Error when the child gas limit exceeds the maximum allowed increase. - #[error("child gas_limit {child_gas_limit} max increase is {parent_gas_limit}/1024")] - GasLimitInvalidIncrease { - /// The parent gas limit. - parent_gas_limit: u64, - /// The child gas limit. - child_gas_limit: u64, - }, - - /// Error indicating that the child gas limit is below the minimum allowed limit. - /// - /// This error occurs when the child gas limit is less than the specified minimum gas limit. - #[error("child gas limit {child_gas_limit} is below the minimum allowed limit ({MINIMUM_GAS_LIMIT})")] - GasLimitInvalidMinimum { - /// The child gas limit. - child_gas_limit: u64, - }, - - /// Error when blob gas used is missing. - #[error("missing blob gas used")] - BlobGasUsedMissing, - - /// Error when excess blob gas is missing. - #[error("missing excess blob gas")] - ExcessBlobGasMissing, - - /// Error when there is an invalid excess blob gas. - #[error( - "invalid excess blob gas: {diff}; \ - parent excess blob gas: {parent_excess_blob_gas}, \ - parent blob gas used: {parent_blob_gas_used}" - )] - ExcessBlobGasDiff { - /// The excess blob gas diff. - diff: GotExpected, - /// The parent excess blob gas. - parent_excess_blob_gas: u64, - /// The parent blob gas used. - parent_blob_gas_used: u64, - }, -} - -/// A [`Header`] that is sealed at a precalculated hash, use [`SealedHeader::unseal()`] if you want -/// to modify header. -#[main_codec(no_arbitrary)] -#[add_arbitrary_tests(rlp, compact)] -#[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct SealedHeader { - /// Locked Header hash. - hash: BlockHash, - /// Locked Header fields. - header: Header, -} - -impl SealedHeader { - /// Creates the sealed header with the corresponding block hash. - #[inline] - pub const fn new(header: Header, hash: BlockHash) -> Self { - Self { header, hash } - } - - /// Returns the sealed Header fields. - #[inline] - pub const fn header(&self) -> &Header { - &self.header - } - - /// Returns header/block hash. - #[inline] - pub const fn hash(&self) -> BlockHash { - self.hash - } - - /// Updates the block header. - #[cfg(any(test, feature = "test-utils"))] - pub fn set_header(&mut self, header: Header) { - self.header = header - } - - /// Updates the block hash. - #[cfg(any(test, feature = "test-utils"))] - pub fn set_hash(&mut self, hash: BlockHash) { - self.hash = hash - } - - /// Updates the parent block hash. - #[cfg(any(test, feature = "test-utils"))] - pub fn set_parent_hash(&mut self, hash: BlockHash) { - self.header.parent_hash = hash - } - - /// Updates the block number. - #[cfg(any(test, feature = "test-utils"))] - pub fn set_block_number(&mut self, number: BlockNumber) { - self.header.number = number; - } - - /// Updates the block state root. - #[cfg(any(test, feature = "test-utils"))] - pub fn set_state_root(&mut self, state_root: B256) { - self.header.state_root = state_root; - } - - /// Updates the block difficulty. - #[cfg(any(test, feature = "test-utils"))] - pub fn set_difficulty(&mut self, difficulty: U256) { - self.header.difficulty = difficulty; - } - - /// Checks the gas limit for consistency between parent and self headers. - /// - /// The maximum allowable difference between self and parent gas limits is determined by the - /// parent's gas limit divided by the elasticity multiplier (1024). - /// - /// This check is skipped if the Optimism flag is enabled in the chain spec, as gas limits on - /// Optimism can adjust instantly. - #[inline(always)] - fn validate_gas_limit( - &self, - parent: &Self, - chain_spec: &ChainSpec, - ) -> Result<(), HeaderValidationError> { - // Determine the parent gas limit, considering elasticity multiplier on the London fork. - let parent_gas_limit = - if chain_spec.fork(Hardfork::London).transitions_at_block(self.number) { - parent.gas_limit * - chain_spec.base_fee_params_at_timestamp(self.timestamp).elasticity_multiplier - as u64 - } else { - parent.gas_limit - }; - - // Check for an increase in gas limit beyond the allowed threshold. - if self.gas_limit > parent_gas_limit { - if self.gas_limit - parent_gas_limit >= parent_gas_limit / 1024 { - return Err(HeaderValidationError::GasLimitInvalidIncrease { - parent_gas_limit, - child_gas_limit: self.gas_limit, - }) - } - } - // Check for a decrease in gas limit beyond the allowed threshold. - else if parent_gas_limit - self.gas_limit >= parent_gas_limit / 1024 { - return Err(HeaderValidationError::GasLimitInvalidDecrease { - parent_gas_limit, - child_gas_limit: self.gas_limit, - }) - } - // Check if the self gas limit is below the minimum required limit. - else if self.gas_limit < MINIMUM_GAS_LIMIT { - return Err(HeaderValidationError::GasLimitInvalidMinimum { - child_gas_limit: self.gas_limit, - }) - } - - Ok(()) - } - - /// Validates the integrity and consistency of a sealed block header in relation to its parent - /// header. - /// - /// This function checks various properties of the sealed header against its parent header and - /// the chain specification. It ensures that the block forms a valid and secure continuation - /// of the blockchain. - /// - /// ## Arguments - /// - /// * `parent` - The sealed header of the parent block. - /// * `chain_spec` - The chain specification providing configuration parameters for the - /// blockchain. - /// - /// ## Errors - /// - /// Returns a [`HeaderValidationError`] if any validation check fails, indicating specific - /// issues with the sealed header. The possible errors include mismatched block numbers, - /// parent hash mismatches, timestamp inconsistencies, gas limit violations, base fee - /// discrepancies (for EIP-1559), and errors related to the blob gas fields (EIP-4844). - /// - /// ## Note - /// - /// Some checks, such as gas limit validation, are conditionally skipped based on the presence - /// of certain features (e.g., Optimism feature) or the activation of specific hardforks. - pub fn validate_against_parent( - &self, - parent: &Self, - chain_spec: &ChainSpec, - ) -> Result<(), HeaderValidationError> { - // Parent number is consistent. - if parent.number + 1 != self.number { - return Err(HeaderValidationError::ParentBlockNumberMismatch { - parent_block_number: parent.number, - block_number: self.number, - }) - } - - if parent.hash != self.parent_hash { - return Err(HeaderValidationError::ParentHashMismatch( - GotExpected { got: self.parent_hash, expected: parent.hash }.into(), - )) - } - - // timestamp in past check - #[cfg(feature = "optimism")] - if chain_spec.is_bedrock_active_at_block(self.header.number) && - self.header.is_timestamp_in_past(parent.timestamp) - { - return Err(HeaderValidationError::TimestampIsInPast { - parent_timestamp: parent.timestamp, - timestamp: self.timestamp, - }) - } - - #[cfg(not(feature = "optimism"))] - if self.header.is_timestamp_in_past(parent.timestamp) { - return Err(HeaderValidationError::TimestampIsInPast { - parent_timestamp: parent.timestamp, - timestamp: self.timestamp, - }) - } - - // TODO Check difficulty increment between parent and self - // Ace age did increment it by some formula that we need to follow. - - if cfg!(feature = "optimism") { - // On Optimism, the gas limit can adjust instantly, so we skip this check - // if the optimism feature is enabled in the chain spec. - if !chain_spec.is_optimism() { - self.validate_gas_limit(parent, chain_spec)?; - } - } else { - self.validate_gas_limit(parent, chain_spec)?; - } - - // EIP-1559 check base fee - if chain_spec.fork(Hardfork::London).active_at_block(self.number) { - let base_fee = self.base_fee_per_gas.ok_or(HeaderValidationError::BaseFeeMissing)?; - - let expected_base_fee = if chain_spec - .fork(Hardfork::London) - .transitions_at_block(self.number) - { - constants::EIP1559_INITIAL_BASE_FEE - } else { - // This BaseFeeMissing will not happen as previous blocks are checked to have - // them. - parent - .next_block_base_fee(chain_spec.base_fee_params_at_timestamp(self.timestamp)) - .ok_or(HeaderValidationError::BaseFeeMissing)? - }; - if expected_base_fee != base_fee { - return Err(HeaderValidationError::BaseFeeDiff(GotExpected { - expected: expected_base_fee, - got: base_fee, - })) - } - } - - // ensure that the blob gas fields for this block - if chain_spec.is_cancun_active_at_timestamp(self.timestamp) { - self.validate_4844_header_against_parent(parent)?; - } - - Ok(()) - } - - /// Validates that the EIP-4844 header fields are correct with respect to the parent block. This - /// ensures that the `blob_gas_used` and `excess_blob_gas` fields exist in the child header, and - /// that the `excess_blob_gas` field matches the expected `excess_blob_gas` calculated from the - /// parent header fields. - pub fn validate_4844_header_against_parent( - &self, - parent: &Self, - ) -> Result<(), HeaderValidationError> { - // From [EIP-4844](https://eips.ethereum.org/EIPS/eip-4844#header-extension): - // - // > For the first post-fork block, both parent.blob_gas_used and parent.excess_blob_gas - // > are evaluated as 0. - // - // This means in the first post-fork block, calculate_excess_blob_gas will return 0. - let parent_blob_gas_used = parent.blob_gas_used.unwrap_or(0); - let parent_excess_blob_gas = parent.excess_blob_gas.unwrap_or(0); - - if self.blob_gas_used.is_none() { - return Err(HeaderValidationError::BlobGasUsedMissing) - } - let excess_blob_gas = - self.excess_blob_gas.ok_or(HeaderValidationError::ExcessBlobGasMissing)?; - - let expected_excess_blob_gas = - calculate_excess_blob_gas(parent_excess_blob_gas, parent_blob_gas_used); - if expected_excess_blob_gas != excess_blob_gas { - return Err(HeaderValidationError::ExcessBlobGasDiff { - diff: GotExpected { got: excess_blob_gas, expected: expected_excess_blob_gas }, - parent_excess_blob_gas, - parent_blob_gas_used, - }) - } - - Ok(()) - } - - /// Extract raw header that can be modified. - pub fn unseal(self) -> Header { - self.header - } - - /// This is the inverse of [`Header::seal_slow`] which returns the raw header and hash. - pub fn split(self) -> (Header, BlockHash) { - (self.header, self.hash) - } - - /// Return the number hash tuple. - pub fn num_hash(&self) -> BlockNumHash { - BlockNumHash::new(self.number, self.hash) - } - - /// Calculates a heuristic for the in-memory size of the [`SealedHeader`]. - #[inline] - pub fn size(&self) -> usize { - self.header.size() + mem::size_of::() - } -} - -#[cfg(any(test, feature = "arbitrary"))] -impl proptest::arbitrary::Arbitrary for SealedHeader { - type Parameters = (); - fn arbitrary_with(_: Self::Parameters) -> Self::Strategy { - // map valid header strategy by sealing - valid_header_strategy().prop_map(|header| header.seal_slow()).boxed() - } - type Strategy = proptest::strategy::BoxedStrategy; -} - -#[cfg(any(test, feature = "arbitrary"))] -impl<'a> arbitrary::Arbitrary<'a> for SealedHeader { - fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result { - let sealed_header = generate_valid_header( - u.arbitrary()?, - u.arbitrary()?, - u.arbitrary()?, - u.arbitrary()?, - u.arbitrary()?, - ) - .seal_slow(); - Ok(sealed_header) - } -} - -impl Default for SealedHeader { - fn default() -> Self { - Header::default().seal_slow() - } -} - -impl Encodable for SealedHeader { - fn encode(&self, out: &mut dyn BufMut) { - self.header.encode(out); - } -} - -impl Decodable for SealedHeader { - fn decode(buf: &mut &[u8]) -> alloy_rlp::Result { - let b = &mut &**buf; - let started_len = buf.len(); - - // decode the header from temp buffer - let header = Header::decode(b)?; - - // hash the consumed bytes, the rlp encoded header - let consumed = started_len - b.len(); - let hash = keccak256(&buf[..consumed]); - - // update original buffer - *buf = *b; - - Ok(Self { header, hash }) - } -} - -impl AsRef
for SealedHeader { - fn as_ref(&self) -> &Header { - &self.header - } -} - -impl Deref for SealedHeader { - type Target = Header; - - fn deref(&self) -> &Self::Target { - &self.header - } -} +pub use reth_primitives_traits::{Header, HeaderError, SealedHeader}; /// Represents the direction for a headers request depending on the `reverse` field of the request. /// > The response must contain a number of block headers, of rising number when reverse is 0, @@ -1034,11 +87,10 @@ impl From for bool { #[cfg(test)] mod tests { - use super::{Bytes, Decodable, Encodable, Header, B256}; use crate::{ - address, b256, bloom, bytes, header::MINIMUM_GAS_LIMIT, hex, Address, ChainSpec, - HeaderValidationError, HeadersDirection, SealedHeader, U256, + address, b256, bloom, bytes, hex, Address, Bytes, Header, HeadersDirection, B256, U256, }; + use alloy_rlp::{Decodable, Encodable}; use std::str::FromStr; // Test vector from: https://eips.ethereum.org/EIPS/eip-2481 @@ -1301,103 +353,4 @@ mod tests { Header::decode(&mut data.as_slice()) .expect_err("blob_gas_used size should make this header decoding fail"); } - - #[test] - fn test_valid_gas_limit_increase() { - let parent = SealedHeader { - header: Header { gas_limit: 1024 * 10, ..Default::default() }, - ..Default::default() - }; - let child = SealedHeader { - header: Header { gas_limit: parent.header.gas_limit + 5, ..Default::default() }, - ..Default::default() - }; - let chain_spec = ChainSpec::default(); - - assert_eq!(child.validate_gas_limit(&parent, &chain_spec), Ok(())); - } - - #[test] - fn test_gas_limit_below_minimum() { - let parent = SealedHeader { - header: Header { gas_limit: MINIMUM_GAS_LIMIT, ..Default::default() }, - ..Default::default() - }; - let child = SealedHeader { - header: Header { gas_limit: MINIMUM_GAS_LIMIT - 1, ..Default::default() }, - ..Default::default() - }; - let chain_spec = ChainSpec::default(); - - assert_eq!( - child.validate_gas_limit(&parent, &chain_spec), - Err(HeaderValidationError::GasLimitInvalidMinimum { child_gas_limit: child.gas_limit }) - ); - } - - #[test] - fn test_invalid_gas_limit_increase_exceeding_limit() { - let gas_limit = 1024 * 10; - let parent = SealedHeader { - header: Header { gas_limit, ..Default::default() }, - ..Default::default() - }; - let child = SealedHeader { - header: Header { - gas_limit: parent.header.gas_limit + parent.header.gas_limit / 1024 + 1, - ..Default::default() - }, - ..Default::default() - }; - let chain_spec = ChainSpec::default(); - - assert_eq!( - child.validate_gas_limit(&parent, &chain_spec), - Err(HeaderValidationError::GasLimitInvalidIncrease { - parent_gas_limit: parent.header.gas_limit, - child_gas_limit: child.header.gas_limit, - }) - ); - } - - #[test] - fn test_valid_gas_limit_decrease_within_limit() { - let gas_limit = 1024 * 10; - let parent = SealedHeader { - header: Header { gas_limit, ..Default::default() }, - ..Default::default() - }; - let child = SealedHeader { - header: Header { gas_limit: parent.header.gas_limit - 5, ..Default::default() }, - ..Default::default() - }; - let chain_spec = ChainSpec::default(); - - assert_eq!(child.validate_gas_limit(&parent, &chain_spec), Ok(())); - } - - #[test] - fn test_invalid_gas_limit_decrease_exceeding_limit() { - let gas_limit = 1024 * 10; - let parent = SealedHeader { - header: Header { gas_limit, ..Default::default() }, - ..Default::default() - }; - let child = SealedHeader { - header: Header { - gas_limit: parent.header.gas_limit - parent.header.gas_limit / 1024 - 1, - ..Default::default() - }, - ..Default::default() - }; - let chain_spec = ChainSpec::default(); - - assert_eq!( - child.validate_gas_limit(&parent, &chain_spec), - Err(HeaderValidationError::GasLimitInvalidDecrease { - parent_gas_limit: parent.header.gas_limit, - child_gas_limit: child.header.gas_limit, - }) - ); - } } diff --git a/crates/primitives/src/integer_list.rs b/crates/primitives/src/integer_list.rs index 4dcb9a9bc9..8e258fd8b0 100644 --- a/crates/primitives/src/integer_list.rs +++ b/crates/primitives/src/integer_list.rs @@ -1,25 +1,21 @@ use bytes::BufMut; +use core::fmt; +use derive_more::Deref; use roaring::RoaringTreemap; use serde::{ de::{SeqAccess, Unexpected, Visitor}, ser::SerializeSeq, Deserialize, Deserializer, Serialize, Serializer, }; -use std::{fmt, ops::Deref}; + +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; /// Uses Roaring Bitmaps to hold a list of integers. It provides really good compression with the /// capability to access its elements without decoding it. -#[derive(Clone, PartialEq, Default)] +#[derive(Clone, PartialEq, Default, Deref)] pub struct IntegerList(pub RoaringTreemap); -impl Deref for IntegerList { - type Target = RoaringTreemap; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - impl fmt::Debug for IntegerList { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let vec: Vec = self.0.iter().collect(); @@ -105,7 +101,7 @@ struct IntegerListVisitor; impl<'de> Visitor<'de> for IntegerListVisitor { type Value = IntegerList; - fn expecting(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("a usize array") } @@ -144,7 +140,7 @@ impl<'a> Arbitrary<'a> for IntegerList { } /// Primitives error type. -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror_no_std::Error)] pub enum RoaringBitmapError { /// The provided input is invalid. #[error("the provided input is invalid")] diff --git a/crates/primitives/src/lib.rs b/crates/primitives/src/lib.rs index d9cb4d326e..e736708263 100644 --- a/crates/primitives/src/lib.rs +++ b/crates/primitives/src/lib.rs @@ -17,6 +17,10 @@ // TODO: remove when https://github.com/proptest-rs/proptest/pull/427 is merged #![allow(unknown_lints, non_local_definitions)] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(not(feature = "std"))] +extern crate alloc; mod account; #[cfg(feature = "alloy-compat")] @@ -30,7 +34,7 @@ pub mod constants; pub mod eip4844; mod error; pub mod genesis; -mod header; +pub mod header; mod integer_list; mod log; mod net; @@ -63,7 +67,7 @@ pub use constants::{ }; pub use error::{GotExpected, GotExpectedBoxed}; pub use genesis::{ChainConfig, Genesis, GenesisAccount}; -pub use header::{Header, HeaderValidationError, HeadersDirection, SealedHeader}; +pub use header::{Header, HeadersDirection, SealedHeader}; pub use integer_list::IntegerList; pub use log::{logs_bloom, Log}; pub use net::{ diff --git a/crates/primitives/src/net.rs b/crates/primitives/src/net.rs index 41fc6dfe69..922a7df574 100644 --- a/crates/primitives/src/net.rs +++ b/crates/primitives/src/net.rs @@ -1,5 +1,8 @@ pub use reth_network_peers::{NodeRecord, NodeRecordParseError, TrustedPeer}; +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; + // Ethereum bootnodes come from // OP bootnodes come from diff --git a/crates/primitives/src/proofs/mod.rs b/crates/primitives/src/proofs.rs similarity index 88% rename from crates/primitives/src/proofs/mod.rs rename to crates/primitives/src/proofs.rs index dbce919496..96ebf49ece 100644 --- a/crates/primitives/src/proofs/mod.rs +++ b/crates/primitives/src/proofs.rs @@ -1,58 +1,15 @@ //! Helper function for calculating Merkle proofs and hashes. use crate::{ - constants::EMPTY_OMMER_ROOT_HASH, keccak256, Address, Header, Receipt, ReceiptWithBloom, - ReceiptWithBloomRef, Request, TransactionSigned, Withdrawal, B256, U256, + constants::EMPTY_OMMER_ROOT_HASH, keccak256, Header, Receipt, ReceiptWithBloom, + ReceiptWithBloomRef, Request, TransactionSigned, Withdrawal, B256, }; -use reth_trie_types::{hash_builder::HashBuilder, Nibbles}; - -mod types; -pub use types::{AccountProof, StorageProof}; -mod traits; -pub use traits::IntoTrieAccount; +use reth_trie_common::root::{ordered_trie_root, ordered_trie_root_with_encoder}; use alloy_eips::eip7685::Encodable7685; -use alloy_rlp::Encodable; -use itertools::Itertools; -/// Adjust the index of an item for rlp encoding. -pub const fn adjust_index_for_rlp(i: usize, len: usize) -> usize { - if i > 0x7f { - i - } else if i == 0x7f || i + 1 == len { - 0 - } else { - i + 1 - } -} - -/// Compute a trie root of the collection of rlp encodable items. -pub fn ordered_trie_root(items: &[T]) -> B256 { - ordered_trie_root_with_encoder(items, |item, buf| item.encode(buf)) -} - -/// Compute a trie root of the collection of items with a custom encoder. -pub fn ordered_trie_root_with_encoder(items: &[T], mut encode: F) -> B256 -where - F: FnMut(&T, &mut Vec), -{ - let mut value_buffer = Vec::new(); - - let mut hb = HashBuilder::default(); - let items_len = items.len(); - for i in 0..items_len { - let index = adjust_index_for_rlp(i, items_len); - - let index_buffer = alloy_rlp::encode_fixed_size(&index); - - value_buffer.clear(); - encode(&items[index], &mut value_buffer); - - hb.add_leaf(Nibbles::unpack(&index_buffer), &value_buffer); - } - - hb.root() -} +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; /// Calculate a transaction root. /// @@ -175,109 +132,16 @@ pub fn calculate_ommers_root(ommers: &[Header]) -> B256 { keccak256(ommers_rlp) } -/// Hashes and sorts account keys, then proceeds to calculating the root hash of the state -/// represented as MPT. -/// See [`state_root_unsorted`] for more info. -pub fn state_root_ref_unhashed<'a, A: IntoTrieAccount + Clone + 'a>( - state: impl IntoIterator, -) -> B256 { - state_root_unsorted( - state.into_iter().map(|(address, account)| (keccak256(address), account.clone())), - ) -} - -/// Hashes and sorts account keys, then proceeds to calculating the root hash of the state -/// represented as MPT. -/// See [`state_root_unsorted`] for more info. -pub fn state_root_unhashed( - state: impl IntoIterator, -) -> B256 { - state_root_unsorted(state.into_iter().map(|(address, account)| (keccak256(address), account))) -} - -/// Sorts the hashed account keys and calculates the root hash of the state represented as MPT. -/// See [`state_root`] for more info. -pub fn state_root_unsorted(state: impl IntoIterator) -> B256 { - state_root(state.into_iter().sorted_by_key(|(key, _)| *key)) -} - -/// Calculates the root hash of the state represented as MPT. -/// Corresponds to [geth's `deriveHash`](https://github.com/ethereum/go-ethereum/blob/6c149fd4ad063f7c24d726a73bc0546badd1bc73/core/genesis.go#L119). -/// -/// # Panics -/// -/// If the items are not in sorted order. -pub fn state_root(state: impl IntoIterator) -> B256 { - let mut hb = HashBuilder::default(); - let mut account_rlp_buf = Vec::new(); - for (hashed_key, account) in state { - account_rlp_buf.clear(); - account.to_trie_account().encode(&mut account_rlp_buf); - hb.add_leaf(Nibbles::unpack(hashed_key), &account_rlp_buf); - } - hb.root() -} - -/// Hashes storage keys, sorts them and them calculates the root hash of the storage trie. -/// See [`storage_root_unsorted`] for more info. -pub fn storage_root_unhashed(storage: impl IntoIterator) -> B256 { - storage_root_unsorted(storage.into_iter().map(|(slot, value)| (keccak256(slot), value))) -} - -/// Sorts and calculates the root hash of account storage trie. -/// See [`storage_root`] for more info. -pub fn storage_root_unsorted(storage: impl IntoIterator) -> B256 { - storage_root(storage.into_iter().sorted_by_key(|(key, _)| *key)) -} - -/// Calculates the root hash of account storage trie. -/// -/// # Panics -/// -/// If the items are not in sorted order. -pub fn storage_root(storage: impl IntoIterator) -> B256 { - let mut hb = HashBuilder::default(); - for (hashed_slot, value) in storage { - hb.add_leaf(Nibbles::unpack(hashed_slot), alloy_rlp::encode_fixed_size(&value).as_ref()); - } - hb.root() -} - -/// Implementation of hasher using our keccak256 hashing function -/// for compatibility with `triehash` crate. -#[cfg(any(test, feature = "test-utils"))] -pub mod triehash { - use super::{keccak256, B256}; - use hash_db::Hasher; - use plain_hasher::PlainHasher; - - /// A [Hasher] that calculates a keccak256 hash of the given data. - #[derive(Default, Debug, Clone, PartialEq, Eq)] - #[non_exhaustive] - pub struct KeccakHasher; - - #[cfg(any(test, feature = "test-utils"))] - impl Hasher for KeccakHasher { - type Out = B256; - type StdHasher = PlainHasher; - - const LENGTH: usize = 32; - - fn hash(x: &[u8]) -> Self::Out { - keccak256(x) - } - } -} - #[cfg(test)] mod tests { use super::*; use crate::{ bloom, constants::EMPTY_ROOT_HASH, hex_literal::hex, Block, GenesisAccount, Log, TxType, - GOERLI, HOLESKY, MAINNET, SEPOLIA, + GOERLI, HOLESKY, MAINNET, SEPOLIA, U256, }; - use alloy_primitives::{b256, LogData}; + use alloy_primitives::{b256, Address, LogData}; use alloy_rlp::Decodable; + use reth_trie_common::root::{state_root_ref_unhashed, state_root_unhashed}; use std::collections::HashMap; #[test] diff --git a/crates/primitives/src/proofs/traits.rs b/crates/primitives/src/proofs/traits.rs deleted file mode 100644 index 7fef86944b..0000000000 --- a/crates/primitives/src/proofs/traits.rs +++ /dev/null @@ -1,59 +0,0 @@ -use crate::Account; -use alloy_consensus::constants::{EMPTY_ROOT_HASH, KECCAK_EMPTY}; -use alloy_genesis::GenesisAccount; -use alloy_primitives::{keccak256, B256, U256}; -use reth_trie_types::TrieAccount; -use revm_primitives::AccountInfo; - -/// Converts a type into a [`TrieAccount`]. -pub trait IntoTrieAccount { - /// Converts to this type into a [`TrieAccount`]. - fn to_trie_account(self) -> TrieAccount; -} - -impl IntoTrieAccount for GenesisAccount { - fn to_trie_account(self) -> TrieAccount { - let storage_root = self - .storage - .map(|storage| { - super::storage_root_unhashed( - storage - .into_iter() - .filter(|(_, value)| *value != B256::ZERO) - .map(|(slot, value)| (slot, U256::from_be_bytes(*value))), - ) - }) - .unwrap_or(EMPTY_ROOT_HASH); - - TrieAccount { - nonce: self.nonce.unwrap_or_default(), - balance: self.balance, - storage_root, - code_hash: self.code.map_or(KECCAK_EMPTY, keccak256), - } - } -} - -impl IntoTrieAccount for (Account, B256) { - fn to_trie_account(self) -> TrieAccount { - let (account, storage_root) = self; - TrieAccount { - nonce: account.nonce, - balance: account.balance, - storage_root, - code_hash: account.bytecode_hash.unwrap_or(KECCAK_EMPTY), - } - } -} - -impl IntoTrieAccount for (AccountInfo, B256) { - fn to_trie_account(self) -> TrieAccount { - let (account, storage_root) = self; - TrieAccount { - nonce: account.nonce, - balance: account.balance, - storage_root, - code_hash: account.code_hash, - } - } -} diff --git a/crates/primitives/src/receipt.rs b/crates/primitives/src/receipt.rs index fafbb6b5a9..56be2d0a16 100644 --- a/crates/primitives/src/receipt.rs +++ b/crates/primitives/src/receipt.rs @@ -4,15 +4,16 @@ use crate::{logs_bloom, Bloom, Bytes, TxType, B256}; use alloy_primitives::Log; use alloy_rlp::{length_of_length, Decodable, Encodable, RlpDecodable, RlpEncodable}; use bytes::{Buf, BufMut}; +use core::{cmp::Ordering, ops::Deref}; +use derive_more::{Deref, DerefMut, From, IntoIterator}; #[cfg(any(test, feature = "arbitrary"))] use proptest::strategy::Strategy; #[cfg(feature = "zstd-codec")] use reth_codecs::CompactZstd; use reth_codecs::{add_arbitrary_tests, main_codec, Compact}; -use std::{ - cmp::Ordering, - ops::{Deref, DerefMut}, -}; + +#[cfg(not(feature = "std"))] +use alloc::{vec, vec::Vec}; /// Receipt containing result of transaction execution. #[cfg_attr(feature = "zstd-codec", main_codec(no_arbitrary, zstd))] @@ -65,7 +66,7 @@ impl Receipt { } /// A collection of receipts organized as a two-dimensional vector. -#[derive(Clone, Debug, PartialEq, Eq, Default)] +#[derive(Clone, Debug, PartialEq, Eq, Default, From, Deref, DerefMut, IntoIterator)] pub struct Receipts { /// A two-dimensional vector of optional `Receipt` instances. pub receipt_vec: Vec>>, @@ -110,41 +111,12 @@ impl Receipts { } } -impl From>>> for Receipts { - fn from(receipt_vec: Vec>>) -> Self { - Self { receipt_vec } - } -} - impl From> for Receipts { fn from(block_receipts: Vec) -> Self { Self { receipt_vec: vec![block_receipts.into_iter().map(Option::Some).collect()] } } } -impl Deref for Receipts { - type Target = Vec>>; - - fn deref(&self) -> &Self::Target { - &self.receipt_vec - } -} - -impl DerefMut for Receipts { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.receipt_vec - } -} - -impl IntoIterator for Receipts { - type Item = Vec>; - type IntoIter = std::vec::IntoIter; - - fn into_iter(self) -> Self::IntoIter { - self.receipt_vec.into_iter() - } -} - impl FromIterator>> for Receipts { fn from_iter>>>(iter: I) -> Self { iter.into_iter().collect::>().into() diff --git a/crates/primitives/src/request.rs b/crates/primitives/src/request.rs index e2ccc97018..e3b5f220be 100644 --- a/crates/primitives/src/request.rs +++ b/crates/primitives/src/request.rs @@ -3,29 +3,18 @@ use crate::Request; use alloy_eips::eip7685::{Decodable7685, Encodable7685}; use alloy_rlp::{Decodable, Encodable}; +use derive_more::{Deref, DerefMut, From, IntoIterator}; use reth_codecs::{main_codec, Compact}; use revm_primitives::Bytes; +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; + /// A list of EIP-7685 requests. #[main_codec] -#[derive(Debug, Clone, PartialEq, Eq, Default, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Default, Hash, Deref, DerefMut, From, IntoIterator)] pub struct Requests(pub Vec); -impl From> for Requests { - fn from(requests: Vec) -> Self { - Self(requests) - } -} - -impl IntoIterator for Requests { - type Item = Request; - type IntoIter = std::vec::IntoIter; - - fn into_iter(self) -> Self::IntoIter { - self.0.into_iter() - } -} - impl Encodable for Requests { fn encode(&self, out: &mut dyn bytes::BufMut) { let mut h = alloy_rlp::Header { list: true, payload_length: 0 }; diff --git a/crates/primitives/src/revm/compat.rs b/crates/primitives/src/revm/compat.rs index 705fc18806..cb492e6aa1 100644 --- a/crates/primitives/src/revm/compat.rs +++ b/crates/primitives/src/revm/compat.rs @@ -1,6 +1,9 @@ use crate::{revm_primitives::AccountInfo, Account, Address, TxKind, KECCAK_EMPTY, U256}; use revm::{interpreter::gas::validate_initial_tx_gas, primitives::SpecId}; +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; + /// Converts a Revm [`AccountInfo`] into a Reth [`Account`]. /// /// Sets `bytecode_hash` to `None` if `code_hash` is [`KECCAK_EMPTY`]. diff --git a/crates/primitives/src/revm/env.rs b/crates/primitives/src/revm/env.rs index db38bb533a..0b12be6ae0 100644 --- a/crates/primitives/src/revm/env.rs +++ b/crates/primitives/src/revm/env.rs @@ -9,6 +9,9 @@ use alloy_eips::{eip4788::BEACON_ROOTS_ADDRESS, eip7002::WITHDRAWAL_REQUEST_PRED #[cfg(feature = "optimism")] use revm_primitives::OptimismFields; +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; + /// Fill block environment from Block. pub fn fill_block_env( block_env: &mut BlockEnv, @@ -73,7 +76,7 @@ pub fn block_coinbase(chain_spec: &ChainSpec, header: &Header, after_merge: bool } /// Error type for recovering Clique signer from a header. -#[derive(Debug, thiserror::Error)] +#[derive(Debug, thiserror_no_std::Error)] pub enum CliqueSignerRecoveryError { /// Header extradata is too short. #[error("Invalid extra data length")] diff --git a/crates/primitives/src/transaction/eip1559.rs b/crates/primitives/src/transaction/eip1559.rs index 92f75db6ab..878efaa4f9 100644 --- a/crates/primitives/src/transaction/eip1559.rs +++ b/crates/primitives/src/transaction/eip1559.rs @@ -2,8 +2,8 @@ use super::access_list::AccessList; use crate::{keccak256, Bytes, ChainId, Signature, TxKind, TxType, B256, U256}; use alloy_rlp::{length_of_length, Decodable, Encodable, Header}; use bytes::BytesMut; +use core::mem; use reth_codecs::{main_codec, Compact}; -use std::mem; /// A transaction with a priority fee ([EIP-1559](https://eips.ethereum.org/EIPS/eip-1559)). #[main_codec] diff --git a/crates/primitives/src/transaction/eip2930.rs b/crates/primitives/src/transaction/eip2930.rs index 9dc4618867..45bc5e67a2 100644 --- a/crates/primitives/src/transaction/eip2930.rs +++ b/crates/primitives/src/transaction/eip2930.rs @@ -2,8 +2,8 @@ use super::access_list::AccessList; use crate::{keccak256, Bytes, ChainId, Signature, TxKind, TxType, B256, U256}; use alloy_rlp::{length_of_length, Decodable, Encodable, Header}; use bytes::BytesMut; +use core::mem; use reth_codecs::{main_codec, Compact}; -use std::mem; /// Transaction with an [`AccessList`] ([EIP-2930](https://eips.ethereum.org/EIPS/eip-2930)). #[main_codec] diff --git a/crates/primitives/src/transaction/eip4844.rs b/crates/primitives/src/transaction/eip4844.rs index 214e2a5e1e..f4a2be8e2a 100644 --- a/crates/primitives/src/transaction/eip4844.rs +++ b/crates/primitives/src/transaction/eip4844.rs @@ -4,12 +4,15 @@ use crate::{ B256, U256, }; use alloy_rlp::{length_of_length, Decodable, Encodable, Header}; +use core::mem; use reth_codecs::{main_codec, Compact, CompactPlaceholder}; -use std::mem; #[cfg(feature = "c-kzg")] use crate::kzg::KzgSettings; +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; + /// [EIP-4844 Blob Transaction](https://eips.ethereum.org/EIPS/eip-4844#blob-transaction) /// /// A transaction with blob hashes and max blob fee diff --git a/crates/primitives/src/transaction/error.rs b/crates/primitives/src/transaction/error.rs index 2b17fa7181..c5199dda5d 100644 --- a/crates/primitives/src/transaction/error.rs +++ b/crates/primitives/src/transaction/error.rs @@ -2,7 +2,7 @@ use crate::{GotExpectedBoxed, U256}; /// Represents error variants that can happen when trying to validate a /// [Transaction](crate::Transaction) -#[derive(Debug, Clone, Eq, PartialEq, thiserror::Error)] +#[derive(Debug, Clone, Eq, PartialEq, thiserror_no_std::Error)] pub enum InvalidTransactionError { /// The sender does not have enough funds to cover the transaction fees #[error( @@ -55,7 +55,7 @@ pub enum InvalidTransactionError { /// Represents error variants that can happen when trying to convert a transaction to /// [`PooledTransactionsElement`](crate::PooledTransactionsElement) -#[derive(Debug, Clone, Eq, PartialEq, thiserror::Error)] +#[derive(Debug, Clone, Eq, PartialEq, thiserror_no_std::Error)] pub enum TransactionConversionError { /// This error variant is used when a transaction cannot be converted into a /// [`PooledTransactionsElement`](crate::PooledTransactionsElement) because it is not supported @@ -66,7 +66,7 @@ pub enum TransactionConversionError { /// Represents error variants than can happen when trying to convert a /// [`TransactionSignedEcRecovered`](crate::TransactionSignedEcRecovered) transaction. -#[derive(Debug, Clone, Eq, PartialEq, thiserror::Error)] +#[derive(Debug, Clone, Eq, PartialEq, thiserror_no_std::Error)] pub enum TryFromRecoveredTransactionError { /// Thrown if the transaction type is unsupported. #[error("Unsupported transaction type: {0}")] diff --git a/crates/primitives/src/transaction/legacy.rs b/crates/primitives/src/transaction/legacy.rs index d6cb4ae2ab..ebbe29a78c 100644 --- a/crates/primitives/src/transaction/legacy.rs +++ b/crates/primitives/src/transaction/legacy.rs @@ -1,8 +1,8 @@ use crate::{keccak256, Bytes, ChainId, Signature, TxKind, TxType, B256, U256}; use alloy_rlp::{length_of_length, Encodable, Header}; use bytes::BytesMut; +use core::mem; use reth_codecs::{main_codec, Compact}; -use std::mem; /// Legacy transaction. #[main_codec] diff --git a/crates/primitives/src/transaction/mod.rs b/crates/primitives/src/transaction/mod.rs index 12d6eedc57..42e420a5e9 100644 --- a/crates/primitives/src/transaction/mod.rs +++ b/crates/primitives/src/transaction/mod.rs @@ -8,12 +8,12 @@ use alloy_rlp::{ Decodable, Encodable, Error as RlpError, Header, EMPTY_LIST_CODE, EMPTY_STRING_CODE, }; use bytes::Buf; +use core::mem; use derive_more::{AsRef, Deref}; use once_cell::sync::Lazy; use rayon::prelude::{IntoParallelIterator, ParallelIterator}; use reth_codecs::{add_arbitrary_tests, derive_arbitrary, Compact}; use serde::{Deserialize, Serialize}; -use std::mem; pub use access_list::{AccessList, AccessListItem}; pub use eip1559::TxEip1559; @@ -60,6 +60,9 @@ pub use optimism::TxDeposit; #[cfg(feature = "optimism")] pub use tx_type::DEPOSIT_TX_TYPE_ID; +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; + /// Either a transaction hash or number. pub type TxHashOrNumber = BlockHashOrNumber; @@ -478,6 +481,18 @@ impl Transaction { } } + /// This sets the transaction's gas limit. + pub fn set_gas_limit(&mut self, gas_limit: u64) { + match self { + Self::Legacy(tx) => tx.gas_limit = gas_limit, + Self::Eip2930(tx) => tx.gas_limit = gas_limit, + Self::Eip1559(tx) => tx.gas_limit = gas_limit, + Self::Eip4844(tx) => tx.gas_limit = gas_limit, + #[cfg(feature = "optimism")] + Self::Deposit(tx) => tx.gas_limit = gas_limit, + } + } + /// This sets the transaction's nonce. pub fn set_nonce(&mut self, nonce: u64) { match self { diff --git a/crates/primitives/src/transaction/pooled.rs b/crates/primitives/src/transaction/pooled.rs index 23e2ad3c1c..2ca58b1797 100644 --- a/crates/primitives/src/transaction/pooled.rs +++ b/crates/primitives/src/transaction/pooled.rs @@ -13,6 +13,9 @@ use derive_more::{AsRef, Deref}; use reth_codecs::add_arbitrary_tests; use serde::{Deserialize, Serialize}; +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; + /// A response to `GetPooledTransactions`. This can include either a blob transaction, or a /// non-4844 signed transaction. #[add_arbitrary_tests] diff --git a/crates/primitives/src/transaction/sidecar.rs b/crates/primitives/src/transaction/sidecar.rs index da273db36f..c45683ce79 100644 --- a/crates/primitives/src/transaction/sidecar.rs +++ b/crates/primitives/src/transaction/sidecar.rs @@ -12,6 +12,9 @@ pub use alloy_eips::eip4844::BlobTransactionSidecar; #[cfg(feature = "c-kzg")] pub use alloy_eips::eip4844::BlobTransactionValidationError; +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; + /// A response to `GetPooledTransactions` that includes blob data, their commitments, and their /// corresponding proofs. /// diff --git a/crates/primitives/src/transaction/signature.rs b/crates/primitives/src/transaction/signature.rs index d564c58ab9..077858a3c5 100644 --- a/crates/primitives/src/transaction/signature.rs +++ b/crates/primitives/src/transaction/signature.rs @@ -193,7 +193,7 @@ impl Signature { /// Calculates a heuristic for the in-memory size of the [Signature]. #[inline] pub const fn size(&self) -> usize { - std::mem::size_of::() + core::mem::size_of::() } } diff --git a/crates/primitives/src/transaction/variant.rs b/crates/primitives/src/transaction/variant.rs index b3f7a00be9..5bff5215d7 100644 --- a/crates/primitives/src/transaction/variant.rs +++ b/crates/primitives/src/transaction/variant.rs @@ -5,7 +5,7 @@ use crate::{ Address, Transaction, TransactionSigned, TransactionSignedEcRecovered, TransactionSignedNoHash, B256, }; -use std::ops::Deref; +use core::ops::Deref; /// Represents various different transaction formats used in reth. /// diff --git a/crates/primitives/src/withdrawal.rs b/crates/primitives/src/withdrawal.rs index e4d1b37c05..cfd0de2268 100644 --- a/crates/primitives/src/withdrawal.rs +++ b/crates/primitives/src/withdrawal.rs @@ -1,8 +1,11 @@ //! [EIP-4895](https://eips.ethereum.org/EIPS/eip-4895) Withdrawal types. use alloy_rlp::{RlpDecodableWrapper, RlpEncodableWrapper}; +use derive_more::{AsRef, Deref, DerefMut, From, IntoIterator}; use reth_codecs::{main_codec, Compact}; -use std::ops::{Deref, DerefMut}; + +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; /// Re-export from `alloy_eips`. #[doc(inline)] @@ -10,34 +13,49 @@ pub use alloy_eips::eip4895::Withdrawal; /// Represents a collection of Withdrawals. #[main_codec] -#[derive(Debug, Clone, PartialEq, Eq, Default, Hash, RlpEncodableWrapper, RlpDecodableWrapper)] +#[derive( + Debug, + Clone, + PartialEq, + Eq, + Default, + Hash, + From, + AsRef, + Deref, + DerefMut, + IntoIterator, + RlpEncodableWrapper, + RlpDecodableWrapper, +)] +#[as_ref(forward)] pub struct Withdrawals(Vec); impl Withdrawals { /// Create a new Withdrawals instance. - pub fn new(withdrawals: Vec) -> Self { + pub const fn new(withdrawals: Vec) -> Self { Self(withdrawals) } /// Calculate the total size, including capacity, of the Withdrawals. #[inline] pub fn total_size(&self) -> usize { - self.capacity() * std::mem::size_of::() + self.capacity() * core::mem::size_of::() } /// Calculate a heuristic for the in-memory size of the [Withdrawals]. #[inline] pub fn size(&self) -> usize { - self.len() * std::mem::size_of::() + self.len() * core::mem::size_of::() } /// Get an iterator over the Withdrawals. - pub fn iter(&self) -> std::slice::Iter<'_, Withdrawal> { + pub fn iter(&self) -> core::slice::Iter<'_, Withdrawal> { self.0.iter() } /// Get a mutable iterator over the Withdrawals. - pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, Withdrawal> { + pub fn iter_mut(&mut self) -> core::slice::IterMut<'_, Withdrawal> { self.0.iter_mut() } @@ -47,41 +65,6 @@ impl Withdrawals { } } -impl IntoIterator for Withdrawals { - type Item = Withdrawal; - type IntoIter = std::vec::IntoIter; - - fn into_iter(self) -> Self::IntoIter { - self.0.into_iter() - } -} - -impl AsRef<[Withdrawal]> for Withdrawals { - fn as_ref(&self) -> &[Withdrawal] { - &self.0 - } -} - -impl Deref for Withdrawals { - type Target = Vec; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl DerefMut for Withdrawals { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} - -impl From> for Withdrawals { - fn from(withdrawals: Vec) -> Self { - Self(withdrawals) - } -} - #[cfg(test)] mod tests { use super::*; diff --git a/crates/revm/src/test_utils.rs b/crates/revm/src/test_utils.rs index bfab663daf..90ac4ea046 100644 --- a/crates/revm/src/test_utils.rs +++ b/crates/revm/src/test_utils.rs @@ -1,10 +1,9 @@ use reth_primitives::{ - keccak256, proofs::AccountProof, Account, Address, BlockNumber, Bytecode, Bytes, StorageKey, - B256, U256, + keccak256, Account, Address, BlockNumber, Bytecode, Bytes, StorageKey, B256, U256, }; use reth_storage_api::{AccountReader, BlockHashReader, StateProvider, StateRootProvider}; use reth_storage_errors::provider::ProviderResult; -use reth_trie::updates::TrieUpdates; +use reth_trie::{updates::TrieUpdates, AccountProof}; use revm::db::BundleState; use std::collections::HashMap; diff --git a/crates/rpc/ipc/src/server/future.rs b/crates/rpc/ipc/src/server/future.rs index 85c69c2a64..d6aa675c98 100644 --- a/crates/rpc/ipc/src/server/future.rs +++ b/crates/rpc/ipc/src/server/future.rs @@ -33,7 +33,7 @@ use tokio::sync::watch; pub(crate) struct StopHandle(watch::Receiver<()>); impl StopHandle { - pub(crate) fn new(rx: watch::Receiver<()>) -> Self { + pub(crate) const fn new(rx: watch::Receiver<()>) -> Self { Self(rx) } diff --git a/crates/rpc/rpc-api/Cargo.toml b/crates/rpc/rpc-api/Cargo.toml index 00581a1a16..5374c46e48 100644 --- a/crates/rpc/rpc-api/Cargo.toml +++ b/crates/rpc/rpc-api/Cargo.toml @@ -19,9 +19,12 @@ reth-engine-primitives.workspace = true reth-network-peers.workspace = true # misc +alloy-dyn-abi = { workspace = true, features = ["eip712"] } jsonrpsee = { workspace = true, features = ["server", "macros"] } -serde_json.workspace = true serde = { workspace = true, features = ["derive"] } +[dev-dependencies] +serde_json.workspace = true + [features] client = ["jsonrpsee/client", "jsonrpsee/async-client"] diff --git a/crates/rpc/rpc-api/src/eth.rs b/crates/rpc/rpc-api/src/eth.rs index 44b5df58a0..eb11fde824 100644 --- a/crates/rpc/rpc-api/src/eth.rs +++ b/crates/rpc/rpc-api/src/eth.rs @@ -1,3 +1,4 @@ +use alloy_dyn_abi::TypedData; use jsonrpsee::{core::RpcResult, proc_macros::rpc}; use reth_primitives::{Address, BlockId, BlockNumberOrTag, Bytes, B256, B64, U256, U64}; use reth_rpc_types::{ @@ -296,7 +297,7 @@ pub trait EthApi { /// Signs data via [EIP-712](https://github.com/ethereum/EIPs/blob/master/EIPS/eip-712.md). #[method(name = "signTypedData")] - async fn sign_typed_data(&self, address: Address, data: serde_json::Value) -> RpcResult; + async fn sign_typed_data(&self, address: Address, data: TypedData) -> RpcResult; /// Returns the account and storage values of the specified account including the Merkle-proof. /// This call can be used to verify that the data you are pulling from is not tampered with. diff --git a/crates/rpc/rpc-builder/tests/it/http.rs b/crates/rpc/rpc-builder/tests/it/http.rs index 17bd638d07..34ac352eee 100644 --- a/crates/rpc/rpc-builder/tests/it/http.rs +++ b/crates/rpc/rpc-builder/tests/it/http.rs @@ -159,6 +159,17 @@ where let transaction_request = TransactionRequest::default(); let bytes = Bytes::default(); let tx = Bytes::from(hex!("02f871018303579880850555633d1b82520894eee27662c2b8eba3cd936a23f039f3189633e4c887ad591c62bdaeb180c080a07ea72c68abfb8fca1bd964f0f99132ed9280261bdca3e549546c0205e800f7d0a05b4ef3039e9c9b9babc179a1878fb825b5aaf5aed2fa8744854150157b08d6f3")); + let typed_data = serde_json::from_str( + r#"{ + "types": { + "EIP712Domain": [] + }, + "primaryType": "EIP712Domain", + "domain": {}, + "message": {} + }"#, + ) + .unwrap(); // Implemented EthApiClient::protocol_version(client).await.unwrap(); @@ -180,9 +191,7 @@ where EthApiClient::uncle_by_block_hash_and_index(client, hash, index).await.unwrap(); EthApiClient::uncle_by_block_number_and_index(client, block_number, index).await.unwrap(); EthApiClient::sign(client, address, bytes.clone()).await.unwrap_err(); - EthApiClient::sign_typed_data(client, address, jsonrpsee::core::JsonValue::Null) - .await - .unwrap_err(); + EthApiClient::sign_typed_data(client, address, typed_data).await.unwrap_err(); EthApiClient::transaction_by_hash(client, tx_hash).await.unwrap(); EthApiClient::transaction_by_block_hash_and_index(client, hash, index).await.unwrap(); EthApiClient::transaction_by_block_number_and_index(client, block_number, index).await.unwrap(); diff --git a/crates/rpc/rpc-testing-util/Cargo.toml b/crates/rpc/rpc-testing-util/Cargo.toml index b14451969c..898fec038f 100644 --- a/crates/rpc/rpc-testing-util/Cargo.toml +++ b/crates/rpc/rpc-testing-util/Cargo.toml @@ -24,10 +24,8 @@ futures.workspace = true jsonrpsee = { workspace = true, features = ["client", "async-client"] } serde_json.workspace = true - # assertions similar-asserts.workspace = true - [dev-dependencies] tokio = { workspace = true, features = ["rt-multi-thread", "macros", "rt"] } diff --git a/crates/rpc/rpc-types-compat/Cargo.toml b/crates/rpc/rpc-types-compat/Cargo.toml index fa21f15c55..a589ef418c 100644 --- a/crates/rpc/rpc-types-compat/Cargo.toml +++ b/crates/rpc/rpc-types-compat/Cargo.toml @@ -14,6 +14,7 @@ workspace = true [dependencies] reth-primitives.workspace = true reth-rpc-types.workspace = true +reth-trie-common.workspace = true alloy-rlp.workspace = true alloy-rpc-types.workspace = true diff --git a/crates/rpc/rpc-types-compat/src/engine/payload.rs b/crates/rpc/rpc-types-compat/src/engine/payload.rs index 296fbf5d93..dacfab0641 100644 --- a/crates/rpc/rpc-types-compat/src/engine/payload.rs +++ b/crates/rpc/rpc-types-compat/src/engine/payload.rs @@ -2,7 +2,7 @@ //! Ethereum's Engine use reth_primitives::{ - constants::{EMPTY_OMMER_ROOT_HASH, MAXIMUM_EXTRA_DATA_SIZE, MIN_PROTOCOL_BASE_FEE_U256}, + constants::{EMPTY_OMMER_ROOT_HASH, MAXIMUM_EXTRA_DATA_SIZE}, proofs::{self}, Block, Header, Request, SealedBlock, TransactionSigned, UintTryTo, Withdrawals, B256, U256, }; @@ -18,7 +18,7 @@ pub fn try_payload_v1_to_block(payload: ExecutionPayloadV1) -> Result EIP1186StorageProof { diff --git a/crates/rpc/rpc-types/src/lib.rs b/crates/rpc/rpc-types/src/lib.rs index 442f00769e..a8d266648e 100644 --- a/crates/rpc/rpc-types/src/lib.rs +++ b/crates/rpc/rpc-types/src/lib.rs @@ -9,7 +9,7 @@ )] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] #![cfg_attr(not(test), warn(unused_crate_dependencies))] - +#[allow(hidden_glob_reexports)] mod eth; mod mev; mod net; diff --git a/crates/rpc/rpc-types/src/mev.rs b/crates/rpc/rpc-types/src/mev.rs index d95538d1cf..20c92f1a6c 100644 --- a/crates/rpc/rpc-types/src/mev.rs +++ b/crates/rpc/rpc-types/src/mev.rs @@ -34,12 +34,12 @@ pub struct SendBundleRequest { #[serde(rename_all = "camelCase")] pub struct Inclusion { /// The first block the bundle is valid for. - #[serde(with = "alloy_rpc_types::serde_helpers::num::u64_via_ruint")] + #[serde(with = "alloy_rpc_types::serde_helpers::quantity")] pub block: u64, /// The last block the bundle is valid for. #[serde( default, - with = "alloy_rpc_types::serde_helpers::num::u64_opt_via_ruint", + with = "alloy_rpc_types::serde_helpers::quantity::opt", skip_serializing_if = "Option::is_none" )] pub max_block: Option, @@ -104,10 +104,10 @@ pub struct Validity { #[serde(rename_all = "camelCase")] pub struct Refund { /// The index of the transaction in the bundle. - #[serde(with = "alloy_rpc_types::serde_helpers::num::u64_via_ruint")] + #[serde(with = "alloy_rpc_types::serde_helpers::quantity")] pub body_idx: u64, /// The minimum percent of the bundle's earnings to redistribute. - #[serde(with = "alloy_rpc_types::serde_helpers::num::u64_via_ruint")] + #[serde(with = "alloy_rpc_types::serde_helpers::quantity")] pub percent: u64, } @@ -119,7 +119,7 @@ pub struct RefundConfig { /// The address to refund. pub address: Address, /// The minimum percent of the bundle's earnings to redistribute. - #[serde(with = "alloy_rpc_types::serde_helpers::num::u64_via_ruint")] + #[serde(with = "alloy_rpc_types::serde_helpers::quantity")] pub percent: u64, } @@ -322,7 +322,7 @@ pub struct SimBundleOverrides { #[serde(default, skip_serializing_if = "Option::is_none")] pub parent_block: Option, /// Block number used for simulation, defaults to parentBlock.number + 1 - #[serde(default, with = "alloy_rpc_types::serde_helpers::num::u64_opt_via_ruint")] + #[serde(default, with = "alloy_rpc_types::serde_helpers::quantity::opt")] pub block_number: Option, /// Coinbase used for simulation, defaults to parentBlock.coinbase #[serde(default, skip_serializing_if = "Option::is_none")] @@ -330,28 +330,28 @@ pub struct SimBundleOverrides { /// Timestamp used for simulation, defaults to parentBlock.timestamp + 12 #[serde( default, - with = "alloy_rpc_types::serde_helpers::num::u64_opt_via_ruint", + with = "alloy_rpc_types::serde_helpers::quantity::opt", skip_serializing_if = "Option::is_none" )] pub timestamp: Option, /// Gas limit used for simulation, defaults to parentBlock.gasLimit #[serde( default, - with = "alloy_rpc_types::serde_helpers::num::u64_opt_via_ruint", + with = "alloy_rpc_types::serde_helpers::quantity::opt", skip_serializing_if = "Option::is_none" )] pub gas_limit: Option, /// Base fee used for simulation, defaults to parentBlock.baseFeePerGas #[serde( default, - with = "alloy_rpc_types::serde_helpers::num::u64_opt_via_ruint", + with = "alloy_rpc_types::serde_helpers::quantity::opt", skip_serializing_if = "Option::is_none" )] pub base_fee: Option, /// Timeout in seconds, defaults to 5 #[serde( default, - with = "alloy_rpc_types::serde_helpers::num::u64_opt_via_ruint", + with = "alloy_rpc_types::serde_helpers::quantity::opt", skip_serializing_if = "Option::is_none" )] pub timeout: Option, @@ -367,19 +367,19 @@ pub struct SimBundleResponse { #[serde(default, skip_serializing_if = "Option::is_none")] pub error: Option, /// The block number of the simulated block. - #[serde(with = "alloy_rpc_types::serde_helpers::num::u64_via_ruint")] + #[serde(with = "alloy_rpc_types::serde_helpers::quantity")] pub state_block: u64, /// The gas price of the simulated block. - #[serde(with = "alloy_rpc_types::serde_helpers::num::u64_via_ruint")] + #[serde(with = "alloy_rpc_types::serde_helpers::quantity")] pub mev_gas_price: u64, /// The profit of the simulated block. - #[serde(with = "alloy_rpc_types::serde_helpers::num::u64_via_ruint")] + #[serde(with = "alloy_rpc_types::serde_helpers::quantity")] pub profit: u64, /// The refundable value of the simulated block. - #[serde(with = "alloy_rpc_types::serde_helpers::num::u64_via_ruint")] + #[serde(with = "alloy_rpc_types::serde_helpers::quantity")] pub refundable_value: u64, /// The gas used by the simulated block. - #[serde(with = "alloy_rpc_types::serde_helpers::num::u64_via_ruint")] + #[serde(with = "alloy_rpc_types::serde_helpers::quantity")] pub gas_used: u64, /// Logs returned by `mev_simBundle`. #[serde(default, skip_serializing_if = "Option::is_none")] @@ -400,7 +400,7 @@ pub struct SimBundleLogs { impl SendBundleRequest { /// Create a new bundle request. - pub fn new( + pub const fn new( block_num: u64, max_block: Option, protocol_version: ProtocolVersion, @@ -434,7 +434,7 @@ pub struct PrivateTransactionRequest { /// be included. #[serde( default, - with = "alloy_rpc_types::serde_helpers::num::u64_opt_via_ruint", + with = "alloy_rpc_types::serde_helpers::quantity::opt", skip_serializing_if = "Option::is_none" )] pub max_block_number: Option, @@ -625,19 +625,19 @@ pub struct EthSendBundle { /// A list of hex-encoded signed transactions pub txs: Vec, /// hex-encoded block number for which this bundle is valid - #[serde(with = "alloy_rpc_types::serde_helpers::num::u64_via_ruint")] + #[serde(with = "alloy_rpc_types::serde_helpers::quantity")] pub block_number: u64, /// unix timestamp when this bundle becomes active #[serde( default, - with = "alloy_rpc_types::serde_helpers::num::u64_opt_via_ruint", + with = "alloy_rpc_types::serde_helpers::quantity::opt", skip_serializing_if = "Option::is_none" )] pub min_timestamp: Option, /// unix timestamp how long this bundle stays valid #[serde( default, - with = "alloy_rpc_types::serde_helpers::num::u64_opt_via_ruint", + with = "alloy_rpc_types::serde_helpers::quantity::opt", skip_serializing_if = "Option::is_none" )] pub max_timestamp: Option, @@ -666,14 +666,14 @@ pub struct EthCallBundle { /// A list of hex-encoded signed transactions pub txs: Vec, /// hex encoded block number for which this bundle is valid on - #[serde(with = "alloy_rpc_types::serde_helpers::num::u64_via_ruint")] + #[serde(with = "alloy_rpc_types::serde_helpers::quantity")] pub block_number: u64, /// Either a hex encoded number or a block tag for which state to base this simulation on pub state_block_number: BlockNumberOrTag, /// the timestamp to use for this bundle simulation, in seconds since the unix epoch #[serde( default, - with = "alloy_rpc_types::serde_helpers::num::u64_opt_via_ruint", + with = "alloy_rpc_types::serde_helpers::quantity::opt", skip_serializing_if = "Option::is_none" )] pub timestamp: Option, @@ -700,10 +700,10 @@ pub struct EthCallBundleResponse { /// Results of individual transactions within the bundle pub results: Vec, /// The block number used as a base for this simulation - #[serde(with = "alloy_rpc_types::serde_helpers::num::u64_via_ruint")] + #[serde(with = "alloy_rpc_types::serde_helpers::quantity")] pub state_block_number: u64, /// The total gas used by all transactions in the bundle - #[serde(with = "alloy_rpc_types::serde_helpers::num::u64_via_ruint")] + #[serde(with = "alloy_rpc_types::serde_helpers::quantity")] pub total_gas_used: u64, } @@ -726,7 +726,7 @@ pub struct EthCallBundleTransactionResult { #[serde(with = "u256_numeric_string")] pub gas_price: U256, /// The amount of gas used by the transaction - #[serde(with = "alloy_rpc_types::serde_helpers::num::u64_via_ruint")] + #[serde(with = "alloy_rpc_types::serde_helpers::quantity")] pub gas_used: u64, /// The address to which the transaction is sent (optional) pub to_address: Option
, diff --git a/crates/rpc/rpc/Cargo.toml b/crates/rpc/rpc/Cargo.toml index cab1134a23..549ed1e2e3 100644 --- a/crates/rpc/rpc/Cargo.toml +++ b/crates/rpc/rpc/Cargo.toml @@ -48,7 +48,7 @@ jsonrpsee.workspace = true http.workspace = true http-body.workspace = true hyper.workspace = true -jsonwebtoken = "8" +jsonwebtoken.workspace = true # async async-trait.workspace = true diff --git a/crates/rpc/rpc/src/admin.rs b/crates/rpc/rpc/src/admin.rs index b1b0ca7058..2ea412bb20 100644 --- a/crates/rpc/rpc/src/admin.rs +++ b/crates/rpc/rpc/src/admin.rs @@ -4,7 +4,7 @@ use async_trait::async_trait; use jsonrpsee::core::RpcResult; use reth_network_api::{NetworkInfo, PeerKind, Peers}; use reth_network_peers::AnyNode; -use reth_primitives::{ChainSpec, NodeRecord}; +use reth_primitives::{ChainConfig, ChainSpec, NodeRecord}; use reth_rpc_api::AdminApiServer; use reth_rpc_types::{ admin::{EthProtocolInfo, NodeInfo, Ports, ProtocolInfo}, @@ -24,7 +24,7 @@ pub struct AdminApi { impl AdminApi { /// Creates a new instance of `AdminApi`. - pub fn new(network: N, chain_spec: Arc) -> Self { + pub const fn new(network: N, chain_spec: Arc) -> Self { Self { network, chain_spec } } } @@ -94,7 +94,14 @@ where async fn node_info(&self) -> RpcResult { let enode = self.network.local_node_record(); let status = self.network.network_status().await.to_rpc_result()?; - let config = self.chain_spec.genesis().config.clone(); + let config = ChainConfig { + chain_id: self.chain_spec.chain.id(), + terminal_total_difficulty_passed: self + .chain_spec + .get_final_paris_total_difficulty() + .is_some(), + ..self.chain_spec.genesis().config.clone() + }; let node_info = NodeInfo { id: B256::from_slice(&enode.id.as_slice()[..32]), diff --git a/crates/rpc/rpc/src/eth/api/server.rs b/crates/rpc/rpc/src/eth/api/server.rs index e001784e31..61c214e6ed 100644 --- a/crates/rpc/rpc/src/eth/api/server.rs +++ b/crates/rpc/rpc/src/eth/api/server.rs @@ -1,6 +1,16 @@ //! Implementation of the [`jsonrpsee`] generated [`reth_rpc_api::EthApiServer`] trait //! Handles RPC requests for the `eth_` namespace. +use super::EthApiSpec; +use crate::{ + eth::{ + api::{EthApi, EthTransactions}, + error::EthApiError, + revm_utils::EvmOverrides, + }, + result::{internal_rpc_err, ToRpcResult}, +}; +use alloy_dyn_abi::TypedData; use jsonrpsee::core::RpcResult as Result; use reth_evm::ConfigureEvm; use reth_network_api::NetworkInfo; @@ -15,7 +25,6 @@ use reth_rpc_types::{ FeeHistory, Header, Index, RichBlock, StateContext, SyncStatus, TransactionRequest, Work, }; use reth_transaction_pool::TransactionPool; -use serde_json::Value; use tracing::trace; use crate::{ @@ -402,7 +411,7 @@ where } /// Handler for: `eth_signTypedData` - async fn sign_typed_data(&self, address: Address, data: Value) -> Result { + async fn sign_typed_data(&self, address: Address, data: TypedData) -> Result { trace!(target: "rpc::eth", ?address, ?data, "Serving eth_signTypedData"); Ok(EthTransactions::sign_typed_data(self, data, address)?) } diff --git a/crates/rpc/rpc/src/eth/error.rs b/crates/rpc/rpc/src/eth/error.rs index 4a9b6d0439..84c1504015 100644 --- a/crates/rpc/rpc/src/eth/error.rs +++ b/crates/rpc/rpc/src/eth/error.rs @@ -113,6 +113,9 @@ pub enum EthApiError { /// Evm generic purpose error. #[error("Revm error: {0}")] EvmCustom(String), + /// Evm precompile error + #[error("Revm precompile error: {0}")] + EvmPrecompile(String), /// Error encountered when converting a transaction type #[error("Transaction conversion error")] TransactionConversionError, @@ -151,6 +154,7 @@ impl From for ErrorObject<'static> { EthApiError::Internal(_) | EthApiError::TransactionNotFound | EthApiError::EvmCustom(_) | + EthApiError::EvmPrecompile(_) | EthApiError::InvalidRewardPercentiles => internal_rpc_err(error.to_string()), EthApiError::UnknownBlockNumber | EthApiError::UnknownBlockOrTxIndex => { rpc_error_with_code(EthRpcErrorCode::ResourceNotFound.code(), error.to_string()) @@ -221,6 +225,7 @@ where EVMError::Header(InvalidHeader::ExcessBlobGasNotSet) => Self::ExcessBlobGasNotSet, EVMError::Database(err) => err.into(), EVMError::Custom(err) => Self::EvmCustom(err), + EVMError::Precompile(err) => Self::EvmPrecompile(err), } } } diff --git a/crates/rpc/rpc/src/eth/revm_utils.rs b/crates/rpc/rpc/src/eth/revm_utils.rs index 02ddf43b9b..ced65c72de 100644 --- a/crates/rpc/rpc/src/eth/revm_utils.rs +++ b/crates/rpc/rpc/src/eth/revm_utils.rs @@ -44,10 +44,32 @@ impl EvmOverrides { Self { state, block: None } } + /// Creates a new instance with the given block overrides. + pub const fn block(block: Option>) -> Self { + Self { state: None, block } + } + /// Returns `true` if the overrides contain state overrides. pub const fn has_state(&self) -> bool { self.state.is_some() } + + /// Returns `true` if the overrides contain block overrides. + pub const fn has_block(&self) -> bool { + self.block.is_some() + } + + /// Adds state overrides to an existing instance. + pub fn with_state(mut self, state: StateOverride) -> Self { + self.state = Some(state); + self + } + + /// Adds block overrides to an existing instance. + pub fn with_block(mut self, block: Box) -> Self { + self.block = Some(block); + self + } } impl From> for EvmOverrides { @@ -58,7 +80,7 @@ impl From> for EvmOverrides { /// Returns the addresses of the precompiles corresponding to the `SpecId`. #[inline] -pub(crate) fn get_precompiles(spec_id: SpecId) -> impl IntoIterator { +pub fn get_precompiles(spec_id: SpecId) -> impl IntoIterator { let spec = PrecompileSpecId::from_spec_id(spec_id); Precompiles::new(spec).addresses().copied().map(Address::from) } @@ -72,7 +94,7 @@ pub(crate) fn get_precompiles(spec_id: SpecId) -> impl IntoIterator( +pub fn prepare_call_env( mut cfg: CfgEnvWithHandlerCfg, mut block: BlockEnv, request: TransactionRequest, @@ -142,7 +164,7 @@ where /// `eth_call`. /// /// Note: this does _not_ access the Database to check the sender. -pub(crate) fn build_call_evm_env( +pub fn build_call_evm_env( cfg: CfgEnvWithHandlerCfg, block: BlockEnv, request: TransactionRequest, @@ -155,10 +177,7 @@ pub(crate) fn build_call_evm_env( /// /// All [`TxEnv`] fields are derived from the given [`TransactionRequest`], if fields are `None`, /// they fall back to the [`BlockEnv`]'s settings. -pub(crate) fn create_txn_env( - block_env: &BlockEnv, - request: TransactionRequest, -) -> EthResult { +pub fn create_txn_env(block_env: &BlockEnv, request: TransactionRequest) -> EthResult { // Ensure that if versioned hashes are set, they're not empty if request.blob_versioned_hashes.as_ref().map_or(false, |hashes| hashes.is_empty()) { return Err(RpcInvalidTransactionError::BlobTransactionMissingBlobHashes.into()) @@ -221,10 +240,7 @@ pub(crate) fn create_txn_env( } /// Caps the configured [`TxEnv`] `gas_limit` with the allowance of the caller. -pub(crate) fn cap_tx_gas_limit_with_caller_allowance( - db: &mut DB, - env: &mut TxEnv, -) -> EthResult<()> +pub fn cap_tx_gas_limit_with_caller_allowance(db: &mut DB, env: &mut TxEnv) -> EthResult<()> where DB: Database, EthApiError: From<::Error>, @@ -242,7 +258,7 @@ where /// /// Returns an error if the caller has insufficient funds. /// Caution: This assumes non-zero `env.gas_price`. Otherwise, zero allowance will be returned. -pub(crate) fn caller_gas_allowance(db: &mut DB, env: &TxEnv) -> EthResult +pub fn caller_gas_allowance(db: &mut DB, env: &TxEnv) -> EthResult where DB: Database, EthApiError: From<::Error>, @@ -264,7 +280,8 @@ where } /// Helper type for representing the fees of a [`TransactionRequest`] -pub(crate) struct CallFees { +#[derive(Debug)] +pub struct CallFees { /// EIP-1559 priority fee max_priority_fee_per_gas: Option, /// Unified gas price setting @@ -427,10 +444,7 @@ fn apply_block_overrides(overrides: BlockOverrides, env: &mut BlockEnv) { } /// Applies the given state overrides (a set of [`AccountOverride`]) to the [`CacheDB`]. -pub(crate) fn apply_state_overrides( - overrides: StateOverride, - db: &mut CacheDB, -) -> EthResult<()> +pub fn apply_state_overrides(overrides: StateOverride, db: &mut CacheDB) -> EthResult<()> where DB: DatabaseRef, EthApiError: From<::Error>, @@ -502,9 +516,8 @@ where #[cfg(test)] mod tests { - use reth_primitives::constants::GWEI_TO_WEI; - use super::*; + use reth_primitives::constants::GWEI_TO_WEI; #[test] fn test_ensure_0_fallback() { diff --git a/crates/rpc/rpc/src/eth/signer.rs b/crates/rpc/rpc/src/eth/signer.rs index 7b76794cae..016b70fe80 100644 --- a/crates/rpc/rpc/src/eth/signer.rs +++ b/crates/rpc/rpc/src/eth/signer.rs @@ -115,7 +115,6 @@ impl EthSigner for DevSigner { fn sign_typed_data(&self, address: Address, payload: &TypedData) -> Result { let encoded = payload.eip712_signing_hash().map_err(|_| SignError::InvalidTypedData)?; - // let b256 = encoded; self.sign_hash(encoded, address) } } @@ -136,8 +135,7 @@ mod tests { #[tokio::test] async fn test_sign_type_data() { - let eip_712_example = serde_json::json!( - r#"{ + let eip_712_example = r#"{ "types": { "EIP712Domain": [ { @@ -200,9 +198,8 @@ mod tests { }, "contents": "Hello, Bob!" } - }"# - ); - let data: TypedData = serde_json::from_value(eip_712_example).unwrap(); + }"#; + let data: TypedData = serde_json::from_str(eip_712_example).unwrap(); let signer = build_signer(); let sig = signer.sign_typed_data(Address::default(), &data).unwrap(); let expected = Signature { diff --git a/crates/stages/api/src/test_utils.rs b/crates/stages/api/src/test_utils.rs index 1495c54b06..8d76cee31b 100644 --- a/crates/stages/api/src/test_utils.rs +++ b/crates/stages/api/src/test_utils.rs @@ -16,7 +16,7 @@ pub struct TestStage { } impl TestStage { - pub fn new(id: StageId) -> Self { + pub const fn new(id: StageId) -> Self { Self { id, exec_outputs: VecDeque::new(), unwind_outputs: VecDeque::new() } } diff --git a/crates/stages/stages/src/stages/execution.rs b/crates/stages/stages/src/stages/execution.rs index 0f2e5db651..b5b66cca77 100644 --- a/crates/stages/stages/src/stages/execution.rs +++ b/crates/stages/stages/src/stages/execution.rs @@ -5,7 +5,10 @@ use reth_db::{static_file::HeaderMask, tables}; use reth_db_api::{cursor::DbCursorRO, database::Database, transaction::DbTx}; use reth_evm::execute::{BatchExecutor, BlockExecutorProvider}; use reth_exex::{ExExManagerHandle, ExExNotification}; -use reth_primitives::{BlockNumber, Header, StaticFileSegment}; +use reth_primitives::{ + constants::gas_units::{GIGAGAS, KILOGAS, MEGAGAS}, + BlockNumber, Header, StaticFileSegment, +}; use reth_provider::{ providers::{StaticFileProvider, StaticFileProviderRWRefMut, StaticFileWriter}, BlockReader, Chain, DatabaseProviderRW, ExecutionOutcome, HeaderProvider, @@ -611,12 +614,12 @@ impl From for ExecutionStageThresholds { /// Depending on the magnitude of the gas throughput. pub fn format_gas_throughput(gas: u64, execution_duration: Duration) -> String { let gas_per_second = gas as f64 / execution_duration.as_secs_f64(); - if gas_per_second < 1_000_000.0 { - format!("{:.} Kgas/second", gas_per_second / 1_000.0) - } else if gas_per_second < 1_000_000_000.0 { - format!("{:.} Mgas/second", gas_per_second / 1_000_000.0) + if gas_per_second < MEGAGAS as f64 { + format!("{:.} Kgas/second", gas_per_second / KILOGAS as f64) + } else if gas_per_second < GIGAGAS as f64 { + format!("{:.} Mgas/second", gas_per_second / MEGAGAS as f64) } else { - format!("{:.} Ggas/second", gas_per_second / 1_000_000_000.0) + format!("{:.} Ggas/second", gas_per_second / GIGAGAS as f64) } } diff --git a/crates/stages/stages/src/test_utils/set.rs b/crates/stages/stages/src/test_utils/set.rs index df167f5c80..d17695168e 100644 --- a/crates/stages/stages/src/test_utils/set.rs +++ b/crates/stages/stages/src/test_utils/set.rs @@ -11,7 +11,7 @@ pub struct TestStages { } impl TestStages { - pub fn new( + pub const fn new( exec_outputs: VecDeque>, unwind_outputs: VecDeque>, ) -> Self { diff --git a/crates/stages/stages/src/test_utils/test_db.rs b/crates/stages/stages/src/test_utils/test_db.rs index 37fdacd28f..f2d653c0bb 100644 --- a/crates/stages/stages/src/test_utils/test_db.rs +++ b/crates/stages/stages/src/test_utils/test_db.rs @@ -349,9 +349,7 @@ impl TestStageDB { let mut writer = provider.latest_writer(StaticFileSegment::Receipts)?; let res = receipts.into_iter().try_for_each(|(block_num, receipts)| { writer.increment_block(StaticFileSegment::Receipts, block_num)?; - for (tx_num, receipt) in receipts { - writer.append_receipt(tx_num, receipt)?; - } + writer.append_receipts(receipts.into_iter().map(Ok))?; Ok(()) }); writer.commit_without_sync_all()?; diff --git a/crates/stages/types/Cargo.toml b/crates/stages/types/Cargo.toml index ab64a89c90..973cd572ce 100644 --- a/crates/stages/types/Cargo.toml +++ b/crates/stages/types/Cargo.toml @@ -13,7 +13,7 @@ workspace = true [dependencies] reth-codecs.workspace = true -reth-trie-types.workspace = true +reth-trie-common.workspace = true alloy-primitives.workspace = true modular-bitfield.workspace = true diff --git a/crates/stages/types/src/checkpoints.rs b/crates/stages/types/src/checkpoints.rs index b78751cc67..d7188de1be 100644 --- a/crates/stages/types/src/checkpoints.rs +++ b/crates/stages/types/src/checkpoints.rs @@ -1,7 +1,7 @@ use alloy_primitives::{Address, BlockNumber, B256}; use bytes::Buf; use reth_codecs::{main_codec, Compact}; -use reth_trie_types::{hash_builder::HashBuilderState, StoredSubNode}; +use reth_trie_common::{hash_builder::HashBuilderState, StoredSubNode}; use std::ops::RangeInclusive; use super::StageId; @@ -21,7 +21,7 @@ pub struct MerkleCheckpoint { impl MerkleCheckpoint { /// Creates a new Merkle checkpoint. - pub fn new( + pub const fn new( target_block: BlockNumber, last_account_key: B256, walker_stack: Vec, diff --git a/crates/static-file/static-file/src/segments/receipts.rs b/crates/static-file/static-file/src/segments/receipts.rs index 06102a7d8a..e0ed580867 100644 --- a/crates/static-file/static-file/src/segments/receipts.rs +++ b/crates/static-file/static-file/src/segments/receipts.rs @@ -42,11 +42,9 @@ impl Segment for Receipts { let mut receipts_cursor = provider.tx_ref().cursor_read::()?; let receipts_walker = receipts_cursor.walk_range(block_body_indices.tx_num_range())?; - for entry in receipts_walker { - let (tx_number, receipt) = entry?; - - static_file_writer.append_receipt(tx_number, receipt)?; - } + static_file_writer.append_receipts( + receipts_walker.map(|result| result.map_err(ProviderError::from)), + )?; } Ok(()) diff --git a/crates/storage/db-api/Cargo.toml b/crates/storage/db-api/Cargo.toml index fbbf0ca5d7..a3ecc56f85 100644 --- a/crates/storage/db-api/Cargo.toml +++ b/crates/storage/db-api/Cargo.toml @@ -18,7 +18,7 @@ reth-primitives.workspace = true reth-prune-types.workspace = true reth-storage-errors.workspace = true reth-stages-types.workspace = true -reth-trie-types.workspace = true +reth-trie-common.workspace = true # codecs modular-bitfield.workspace = true diff --git a/crates/storage/db-api/src/models/mod.rs b/crates/storage/db-api/src/models/mod.rs index e74b8811f7..df64673365 100644 --- a/crates/storage/db-api/src/models/mod.rs +++ b/crates/storage/db-api/src/models/mod.rs @@ -8,7 +8,7 @@ use reth_codecs::{main_codec, Compact}; use reth_primitives::{Address, B256, *}; use reth_prune_types::{PruneCheckpoint, PruneSegment}; use reth_stages_types::StageCheckpoint; -use reth_trie_types::{StoredNibbles, StoredNibblesSubKey, *}; +use reth_trie_common::{StoredNibbles, StoredNibblesSubKey, *}; pub mod accounts; pub mod blocks; diff --git a/crates/storage/db/Cargo.toml b/crates/storage/db/Cargo.toml index e144e81271..2bac4c1078 100644 --- a/crates/storage/db/Cargo.toml +++ b/crates/storage/db/Cargo.toml @@ -25,7 +25,7 @@ reth-nippy-jar.workspace = true reth-prune-types.workspace = true reth-stages-types.workspace = true reth-tracing.workspace = true -reth-trie-types.workspace = true +reth-trie-common.workspace = true # codecs serde = { workspace = true, default-features = false } diff --git a/crates/storage/db/src/implementation/mdbx/cursor.rs b/crates/storage/db/src/implementation/mdbx/cursor.rs index 956374072b..e2afbe0c16 100644 --- a/crates/storage/db/src/implementation/mdbx/cursor.rs +++ b/crates/storage/db/src/implementation/mdbx/cursor.rs @@ -36,7 +36,7 @@ pub struct Cursor { } impl Cursor { - pub(crate) fn new_with_metrics( + pub(crate) const fn new_with_metrics( inner: reth_libmdbx::Cursor, metrics: Option>, ) -> Self { diff --git a/crates/storage/db/src/implementation/mdbx/mod.rs b/crates/storage/db/src/implementation/mdbx/mod.rs index 78b1ad6359..4191d7aae3 100644 --- a/crates/storage/db/src/implementation/mdbx/mod.rs +++ b/crates/storage/db/src/implementation/mdbx/mod.rs @@ -41,7 +41,6 @@ const DEFAULT_MAX_READERS: u64 = 32_000; /// Space that a read-only transaction can occupy until the warning is emitted. /// See [`reth_libmdbx::EnvironmentBuilder::set_handle_slow_readers`] for more information. -#[cfg(not(windows))] const MAX_SAFE_READER_SPACE: usize = 10 * GIGABYTE; /// Environment used when opening a MDBX environment. RO/RW. diff --git a/crates/storage/db/src/tables/mod.rs b/crates/storage/db/src/tables/mod.rs index 5d3c685a52..367a7dd553 100644 --- a/crates/storage/db/src/tables/mod.rs +++ b/crates/storage/db/src/tables/mod.rs @@ -37,7 +37,7 @@ use reth_primitives::{ }; use reth_prune_types::{PruneCheckpoint, PruneSegment}; use reth_stages_types::StageCheckpoint; -use reth_trie_types::{StorageTrieEntry, StoredBranchNode, StoredNibbles, StoredNibblesSubKey}; +use reth_trie_common::{StorageTrieEntry, StoredBranchNode, StoredNibbles, StoredNibblesSubKey}; use serde::{Deserialize, Serialize}; use std::fmt; diff --git a/crates/storage/db/src/tables/raw.rs b/crates/storage/db/src/tables/raw.rs index 1b501b4c56..1e8fa56b36 100644 --- a/crates/storage/db/src/tables/raw.rs +++ b/crates/storage/db/src/tables/raw.rs @@ -53,7 +53,7 @@ impl RawKey { /// Creates a raw key from an existing `Vec`. Useful when we already have the encoded /// key. - pub fn from_vec(vec: Vec) -> Self { + pub const fn from_vec(vec: Vec) -> Self { Self { key: vec, _phantom: std::marker::PhantomData } } @@ -118,7 +118,7 @@ impl RawValue { /// Creates a raw value from an existing `Vec`. Useful when we already have the encoded /// value. - pub fn from_vec(vec: Vec) -> Self { + pub const fn from_vec(vec: Vec) -> Self { Self { value: vec, _phantom: std::marker::PhantomData } } diff --git a/crates/storage/libmdbx-rs/Cargo.lock b/crates/storage/libmdbx-rs/Cargo.lock deleted file mode 100644 index 18c3cf63dc..0000000000 --- a/crates/storage/libmdbx-rs/Cargo.lock +++ /dev/null @@ -1,1012 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi", - "libc", - "winapi", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "bindgen" -version = "0.60.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "062dddbc1ba4aca46de6338e2bf87771414c335f7b2f2036e8f3e9befebf88e6" -dependencies = [ - "bitflags", - "cexpr", - "clang-sys", - "lazy_static", - "lazycell", - "peeking_take_while", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", -] - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "bstr" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223" -dependencies = [ - "lazy_static", - "memchr", - "regex-automata", - "serde", -] - -[[package]] -name = "bumpalo" -version = "3.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "572f695136211188308f16ad2ca5c851a712c464060ae6974944458eb83880ba" - -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - -[[package]] -name = "bytes" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db" - -[[package]] -name = "cast" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" - -[[package]] -name = "cc" -version = "1.0.73" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" - -[[package]] -name = "cexpr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" -dependencies = [ - "nom", -] - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "clang-sys" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa2e27ae6ab525c3d369ded447057bca5438d86dc3a68f6faafb8269ba82ebf3" -dependencies = [ - "glob", - "libc", - "libloading", -] - -[[package]] -name = "clap" -version = "2.34.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" -dependencies = [ - "bitflags", - "textwrap", - "unicode-width", -] - -[[package]] -name = "convert_case" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" - -[[package]] -name = "criterion" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b01d6de93b2b6c65e17c634a26653a29d107b3c98c607c765bf38d041531cd8f" -dependencies = [ - "atty", - "cast", - "clap", - "criterion-plot", - "csv", - "itertools", - "lazy_static", - "num-traits", - "oorandom", - "plotters", - "rayon", - "regex", - "serde", - "serde_cbor", - "serde_derive", - "serde_json", - "tinytemplate", - "walkdir", -] - -[[package]] -name = "criterion-plot" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2673cc8207403546f45f5fd319a974b1e6983ad1a3ee7e6041650013be041876" -dependencies = [ - "cast", - "itertools", -] - -[[package]] -name = "crossbeam-channel" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" -dependencies = [ - "cfg-if", - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f916dfc5d356b0ed9dae65f1db9fc9770aa2851d2662b988ccf4fe3516e86348" -dependencies = [ - "autocfg", - "cfg-if", - "crossbeam-utils", - "memoffset", - "scopeguard", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edbafec5fa1f196ca66527c1b12c2ec4745ca14b50f1ad8f9f6f720b55d11fac" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "csv" -version = "1.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1" -dependencies = [ - "bstr", - "csv-core", - "itoa 0.4.8", - "ryu", - "serde", -] - -[[package]] -name = "csv-core" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" -dependencies = [ - "memchr", -] - -[[package]] -name = "derive_more" -version = "0.99.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" -dependencies = [ - "convert_case", - "proc-macro2", - "quote", - "rustc_version", - "syn", -] - -[[package]] -name = "either" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" - -[[package]] -name = "fastrand" -version = "1.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499" -dependencies = [ - "instant", -] - -[[package]] -name = "getrandom" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - -[[package]] -name = "glob" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" - -[[package]] -name = "half" -version = "1.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" - -[[package]] -name = "hashbrown" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" - -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "indexmap" -version = "1.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" -dependencies = [ - "autocfg", - "hashbrown", -] - -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "itertools" -version = "0.10.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" -dependencies = [ - "either", -] - -[[package]] -name = "itoa" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" - -[[package]] -name = "itoa" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4217ad341ebadf8d8e724e264f13e593e0648f5b3e94b3896a5df283be015ecc" - -[[package]] -name = "js-sys" -version = "0.3.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49409df3e3bf0856b916e2ceaca09ee28e6871cf7d9ce97a692cacfdb2a25a47" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - -[[package]] -name = "libc" -version = "0.2.136" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55edcf6c0bb319052dea84732cf99db461780fd5e8d3eb46ab6ff312ab31f197" - -[[package]] -name = "libloading" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd" -dependencies = [ - "cfg-if", - "winapi", -] - -[[package]] -name = "lifetimed-bytes" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c970c8ea4c7b023a41cfa4af4c785a16694604c2f2a3b0d1f20a9bcb73fa550" -dependencies = [ - "bytes", -] - -[[package]] -name = "lock_api" -version = "0.4.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" -dependencies = [ - "autocfg", - "scopeguard", -] - -[[package]] -name = "log" -version = "0.4.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "mdbx-sys" -version = "0.11.8-0" -dependencies = [ - "bindgen", - "cc", - "libc", -] - -[[package]] -name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "memoffset" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" -dependencies = [ - "autocfg", -] - -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - -[[package]] -name = "nom" -version = "7.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8903e5a29a317527874d0402f867152a3d21c908bb0b933e416c65e301d4c36" -dependencies = [ - "memchr", - "minimal-lexical", -] - -[[package]] -name = "num-traits" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" -dependencies = [ - "autocfg", -] - -[[package]] -name = "num_cpus" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" -dependencies = [ - "hermit-abi", - "libc", -] - -[[package]] -name = "once_cell" -version = "1.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e82dad04139b71a90c080c8463fe0dc7902db5192d939bd0950f074d014339e1" - -[[package]] -name = "oorandom" -version = "11.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" - -[[package]] -name = "parking_lot" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" -dependencies = [ - "lock_api", - "parking_lot_core", -] - -[[package]] -name = "parking_lot_core" -version = "0.9.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0" -dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-sys", -] - -[[package]] -name = "peeking_take_while" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" - -[[package]] -name = "plotters" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2538b639e642295546c50fcd545198c9d64ee2a38620a628724a3b266d5fbf97" -dependencies = [ - "num-traits", - "plotters-backend", - "plotters-svg", - "wasm-bindgen", - "web-sys", -] - -[[package]] -name = "plotters-backend" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "193228616381fecdc1224c62e96946dfbc73ff4384fba576e052ff8c1bea8142" - -[[package]] -name = "plotters-svg" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a81d2759aae1dae668f783c308bc5c8ebd191ff4184aaa1b37f65a6ae5a56f" -dependencies = [ - "plotters-backend", -] - -[[package]] -name = "ppv-lite86" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" - -[[package]] -name = "proc-macro2" -version = "1.0.47" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ea3d908b0e36316caf9e9e2c4625cdde190a7e6f440d794667ed17a1855e725" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbe448f377a7d6961e30f5955f9b8d106c3f5e449d493ee1b125c1d43c2b5179" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] - -[[package]] -name = "rand_xorshift" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" -dependencies = [ - "rand_core", -] - -[[package]] -name = "rayon" -version = "1.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd99e5772ead8baa5215278c9b15bf92087709e9c1b2d1f97cdb5a183c933a7d" -dependencies = [ - "autocfg", - "crossbeam-deque", - "either", - "rayon-core", -] - -[[package]] -name = "rayon-core" -version = "1.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "258bcdb5ac6dad48491bb2992db6b7cf74878b0384908af124823d118c99683f" -dependencies = [ - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-utils", - "num_cpus", -] - -[[package]] -name = "redox_syscall" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" -dependencies = [ - "bitflags", -] - -[[package]] -name = "regex" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c4eb3267174b8c6c2f654116623910a0fef09c4753f8dd83db29c48a0df988b" -dependencies = [ - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" - -[[package]] -name = "regex-syntax" -version = "0.6.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" - -[[package]] -name = "remove_dir_all" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" -dependencies = [ - "winapi", -] - -[[package]] -name = "reth-libmdbx" -version = "0.1.6" -dependencies = [ - "bitflags", - "byteorder", - "criterion", - "derive_more", - "indexmap", - "libc", - "lifetimed-bytes", - "mdbx-sys", - "parking_lot", - "rand", - "rand_xorshift", - "tempfile", - "thiserror", -] - -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - -[[package]] -name = "rustc_version" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" -dependencies = [ - "semver", -] - -[[package]] -name = "ryu" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4501abdff3ae82a1c1b477a17252eb69cee9e66eb915c1abaa4f44d873df9f09" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "semver" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4" - -[[package]] -name = "serde" -version = "1.0.147" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965" - -[[package]] -name = "serde_cbor" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" -dependencies = [ - "half", - "serde", -] - -[[package]] -name = "serde_derive" -version = "1.0.147" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.87" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce777b7b150d76b9cf60d28b55f5847135a003f7d7350c6be7a773508ce7d45" -dependencies = [ - "itoa 1.0.4", - "ryu", - "serde", -] - -[[package]] -name = "shlex" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43b2853a4d09f215c24cc5489c992ce46052d359b5109343cbafbf26bc62f8a3" - -[[package]] -name = "smallvec" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" - -[[package]] -name = "syn" -version = "1.0.103" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "tempfile" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" -dependencies = [ - "cfg-if", - "fastrand", - "libc", - "redox_syscall", - "remove_dir_all", - "winapi", -] - -[[package]] -name = "textwrap" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" -dependencies = [ - "unicode-width", -] - -[[package]] -name = "thiserror" -version = "1.0.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10deb33631e3c9018b9baf9dcbbc4f737320d2b576bac10f6aefa048fa407e3e" -dependencies = [ - "thiserror-impl", -] - -[[package]] -name = "thiserror-impl" -version = "1.0.37" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "982d17546b47146b28f7c22e3d08465f6b8903d0ea13c1660d9d84a6e7adcdbb" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "tinytemplate" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" -dependencies = [ - "serde", - "serde_json", -] - -[[package]] -name = "unicode-ident" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" - -[[package]] -name = "unicode-width" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" - -[[package]] -name = "walkdir" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" -dependencies = [ - "same-file", - "winapi", - "winapi-util", -] - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "wasm-bindgen" -version = "0.2.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf9f5aceeec8be17c128b2e93e031fb8a4d469bb9c4ae2d7dc1888b26887268" -dependencies = [ - "cfg-if", - "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8ffb332579b0557b52d268b91feab8df3615f265d5270fec2a8c95b17c1142" -dependencies = [ - "bumpalo", - "log", - "once_cell", - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-macro" -version = "0.2.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "052be0f94026e6cbc75cdefc9bae13fd6052cdcaf532fa6c45e7ae33a1e6c810" -dependencies = [ - "quote", - "wasm-bindgen-macro-support", -] - -[[package]] -name = "wasm-bindgen-macro-support" -version = "0.2.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bc0c051dc5f23e307b13285f9d75df86bfdf816c5721e573dec1f9b8aa193c" -dependencies = [ - "proc-macro2", - "quote", - "syn", - "wasm-bindgen-backend", - "wasm-bindgen-shared", -] - -[[package]] -name = "wasm-bindgen-shared" -version = "0.2.83" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c38c045535d93ec4f0b4defec448e4291638ee608530863b1e2ba115d4fff7f" - -[[package]] -name = "web-sys" -version = "0.3.60" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcda906d8be16e728fd5adc5b729afad4e444e106ab28cd1c7256e54fa61510f" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "windows-sys" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" -dependencies = [ - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -] - -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5" diff --git a/crates/storage/libmdbx-rs/Cargo.toml b/crates/storage/libmdbx-rs/Cargo.toml index 68576e0d06..8056b68557 100644 --- a/crates/storage/libmdbx-rs/Cargo.toml +++ b/crates/storage/libmdbx-rs/Cargo.toml @@ -1,32 +1,28 @@ [package] name = "reth-libmdbx" +description = "Idiomatic and safe MDBX wrapper" version.workspace = true edition.workspace = true rust-version.workspace = true license = "Apache-2.0" -description = "Idiomatic and safe MDBX wrapper with good licence" homepage.workspace = true repository.workspace = true [lints] workspace = true -[lib] -name = "reth_libmdbx" - [dependencies] +reth-mdbx-sys.workspace = true + bitflags.workspace = true byteorder = "1" derive_more.workspace = true indexmap = "2" -libc = "0.2" parking_lot.workspace = true thiserror.workspace = true dashmap = { workspace = true, features = ["inline"], optional = true } tracing.workspace = true -reth-mdbx-sys.workspace = true - [features] default = [] return-borrowed = [] diff --git a/crates/storage/libmdbx-rs/LICENSE b/crates/storage/libmdbx-rs/LICENSE deleted file mode 100644 index fec6b43876..0000000000 --- a/crates/storage/libmdbx-rs/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright 2014 Dan Burkert - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. diff --git a/crates/storage/libmdbx-rs/benches/transaction.rs b/crates/storage/libmdbx-rs/benches/transaction.rs index 8cc84b01f3..33d25cdaa6 100644 --- a/crates/storage/libmdbx-rs/benches/transaction.rs +++ b/crates/storage/libmdbx-rs/benches/transaction.rs @@ -2,7 +2,6 @@ mod utils; use criterion::{black_box, criterion_group, criterion_main, Criterion}; -use libc::size_t; use rand::{prelude::SliceRandom, SeedableRng}; use rand_xorshift::XorShiftRng; use reth_libmdbx::{ffi::*, ObjectLength, WriteFlags}; @@ -46,10 +45,10 @@ fn bench_get_rand_raw(c: &mut Criterion) { c.bench_function("bench_get_rand_raw", |b| { b.iter(|| unsafe { txn.txn_execute(|txn| { - let mut i: size_t = 0; + let mut i = 0; for key in &keys { - key_val.iov_len = key.len() as size_t; - key_val.iov_base = key.as_bytes().as_ptr() as *mut _; + key_val.iov_len = key.len(); + key_val.iov_base = key.as_bytes().as_ptr().cast_mut().cast(); mdbx_get(txn, dbi, &key_val, &mut data_val); @@ -102,12 +101,12 @@ fn bench_put_rand_raw(c: &mut Criterion) { env.with_raw_env_ptr(|env| { mdbx_txn_begin_ex(env, ptr::null_mut(), 0, &mut txn, ptr::null_mut()); - let mut i: ::libc::c_int = 0; + let mut i = 0; for (key, data) in &items { - key_val.iov_len = key.len() as size_t; - key_val.iov_base = key.as_bytes().as_ptr() as *mut _; - data_val.iov_len = data.len() as size_t; - data_val.iov_base = data.as_bytes().as_ptr() as *mut _; + key_val.iov_len = key.len(); + key_val.iov_base = key.as_bytes().as_ptr().cast_mut().cast(); + data_val.iov_len = data.len(); + data_val.iov_base = data.as_bytes().as_ptr().cast_mut().cast(); i += mdbx_put(txn, dbi, &key_val, &mut data_val, 0); } diff --git a/crates/storage/libmdbx-rs/mdbx-sys/Cargo.toml b/crates/storage/libmdbx-rs/mdbx-sys/Cargo.toml index fbdad4c510..8cd56d1f27 100644 --- a/crates/storage/libmdbx-rs/mdbx-sys/Cargo.toml +++ b/crates/storage/libmdbx-rs/mdbx-sys/Cargo.toml @@ -1,19 +1,13 @@ [package] name = "reth-mdbx-sys" +description = "Raw bindings for libmdbx" version.workspace = true edition.workspace = true rust-version.workspace = true license = "Apache-2.0" -description = "Rust bindings for libmdbx with good licence." homepage.workspace = true repository.workspace = true -[lib] -name = "reth_mdbx_sys" - -[dependencies] -libc = "0.2" - [build-dependencies] cc = "1.0" bindgen = { version = "0.69", default-features = false, features = ["runtime"] } diff --git a/crates/storage/libmdbx-rs/mdbx-sys/build.rs b/crates/storage/libmdbx-rs/mdbx-sys/build.rs index 5f82d02b4c..c265d02e23 100644 --- a/crates/storage/libmdbx-rs/mdbx-sys/build.rs +++ b/crates/storage/libmdbx-rs/mdbx-sys/build.rs @@ -1,63 +1,98 @@ -use bindgen::{ - callbacks::{IntKind, ParseCallbacks}, - Formatter, +use std::{ + env, + path::{Path, PathBuf}, }; -use std::{env, path::PathBuf}; - -#[derive(Debug)] -struct Callbacks; - -impl ParseCallbacks for Callbacks { - fn int_macro(&self, name: &str, _value: i64) -> Option { - match name { - "MDBX_SUCCESS" | - "MDBX_KEYEXIST" | - "MDBX_NOTFOUND" | - "MDBX_PAGE_NOTFOUND" | - "MDBX_CORRUPTED" | - "MDBX_PANIC" | - "MDBX_VERSION_MISMATCH" | - "MDBX_INVALID" | - "MDBX_MAP_FULL" | - "MDBX_DBS_FULL" | - "MDBX_READERS_FULL" | - "MDBX_TLS_FULL" | - "MDBX_TXN_FULL" | - "MDBX_CURSOR_FULL" | - "MDBX_PAGE_FULL" | - "MDBX_MAP_RESIZED" | - "MDBX_INCOMPATIBLE" | - "MDBX_BAD_RSLOT" | - "MDBX_BAD_TXN" | - "MDBX_BAD_VALSIZE" | - "MDBX_BAD_DBI" | - "MDBX_LOG_DONTCHANGE" | - "MDBX_DBG_DONTCHANGE" | - "MDBX_RESULT_TRUE" | - "MDBX_UNABLE_EXTEND_MAPSIZE" | - "MDBX_PROBLEM" | - "MDBX_LAST_LMDB_ERRCODE" | - "MDBX_BUSY" | - "MDBX_EMULTIVAL" | - "MDBX_EBADSIGN" | - "MDBX_WANNA_RECOVERY" | - "MDBX_EKEYMISMATCH" | - "MDBX_TOO_LARGE" | - "MDBX_THREAD_MISMATCH" | - "MDBX_TXN_OVERLAPPING" | - "MDBX_LAST_ERRCODE" => Some(IntKind::Int), - _ => Some(IntKind::UInt), - } - } -} fn main() { - let mut mdbx = PathBuf::from(&env::var("CARGO_MANIFEST_DIR").unwrap()); - mdbx.push("libmdbx"); + let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); + let mdbx = manifest_dir.join("libmdbx"); println!("cargo:rerun-if-changed={}", mdbx.display()); - let out_path = PathBuf::from(env::var("OUT_DIR").unwrap()); + let bindings = PathBuf::from(std::env::var("OUT_DIR").unwrap()).join("bindings.rs"); + generate_bindings(&mdbx, &bindings); + + let mut cc = cc::Build::new(); + cc.flag_if_supported("-Wno-unused-parameter").flag_if_supported("-Wuninitialized"); + + if env::var("CARGO_CFG_TARGET_OS").unwrap() != "linux" { + cc.flag_if_supported("-Wbad-function-cast"); + } + + let flags = format!("{:?}", cc.get_compiler().cflags_env()); + cc.define("MDBX_BUILD_FLAGS", flags.as_str()).define("MDBX_TXN_CHECKOWNER", "0"); + + // Enable debugging on debug builds + #[cfg(debug_assertions)] + cc.define("MDBX_DEBUG", "1").define("MDBX_ENABLE_PROFGC", "1"); + + // Disables debug logging on optimized builds + #[cfg(not(debug_assertions))] + cc.define("MDBX_DEBUG", "0").define("NDEBUG", None); + + // Propagate `-C target-cpu=native` + let rustflags = env::var("CARGO_ENCODED_RUSTFLAGS").unwrap(); + if rustflags.contains("target-cpu=native") && + env::var("CARGO_CFG_TARGET_ENV").unwrap() != "msvc" + { + cc.flag("-march=native"); + } + + cc.file(mdbx.join("mdbx.c")).compile("libmdbx.a"); +} + +fn generate_bindings(mdbx: &Path, out_file: &Path) { + use bindgen::{ + callbacks::{IntKind, ParseCallbacks}, + Formatter, + }; + + #[derive(Debug)] + struct Callbacks; + + impl ParseCallbacks for Callbacks { + fn int_macro(&self, name: &str, _value: i64) -> Option { + match name { + "MDBX_SUCCESS" | + "MDBX_KEYEXIST" | + "MDBX_NOTFOUND" | + "MDBX_PAGE_NOTFOUND" | + "MDBX_CORRUPTED" | + "MDBX_PANIC" | + "MDBX_VERSION_MISMATCH" | + "MDBX_INVALID" | + "MDBX_MAP_FULL" | + "MDBX_DBS_FULL" | + "MDBX_READERS_FULL" | + "MDBX_TLS_FULL" | + "MDBX_TXN_FULL" | + "MDBX_CURSOR_FULL" | + "MDBX_PAGE_FULL" | + "MDBX_MAP_RESIZED" | + "MDBX_INCOMPATIBLE" | + "MDBX_BAD_RSLOT" | + "MDBX_BAD_TXN" | + "MDBX_BAD_VALSIZE" | + "MDBX_BAD_DBI" | + "MDBX_LOG_DONTCHANGE" | + "MDBX_DBG_DONTCHANGE" | + "MDBX_RESULT_TRUE" | + "MDBX_UNABLE_EXTEND_MAPSIZE" | + "MDBX_PROBLEM" | + "MDBX_LAST_LMDB_ERRCODE" | + "MDBX_BUSY" | + "MDBX_EMULTIVAL" | + "MDBX_EBADSIGN" | + "MDBX_WANNA_RECOVERY" | + "MDBX_EKEYMISMATCH" | + "MDBX_TOO_LARGE" | + "MDBX_THREAD_MISMATCH" | + "MDBX_TXN_OVERLAPPING" | + "MDBX_LAST_ERRCODE" => Some(IntKind::Int), + _ => Some(IntKind::UInt), + } + } + } let bindings = bindgen::Builder::default() .header(mdbx.join("mdbx.h").to_string_lossy()) @@ -65,46 +100,13 @@ fn main() { .allowlist_type("^(MDBX|mdbx)_.*") .allowlist_function("^(MDBX|mdbx)_.*") .size_t_is_usize(true) - .ctypes_prefix("::libc") + .merge_extern_blocks(true) .parse_callbacks(Box::new(Callbacks)) .layout_tests(false) .prepend_enum_name(false) .generate_comments(false) - .disable_header_comment() .formatter(Formatter::Rustfmt) .generate() .expect("Unable to generate bindings"); - - bindings.write_to_file(out_path.join("bindings.rs")).expect("Couldn't write bindings!"); - - let mut mdbx = PathBuf::from(&env::var("CARGO_MANIFEST_DIR").unwrap()); - mdbx.push("libmdbx"); - - let mut cc_builder = cc::Build::new(); - cc_builder.flag_if_supported("-Wno-unused-parameter").flag_if_supported("-Wuninitialized"); - - if env::var("CARGO_CFG_TARGET_OS").unwrap() != "linux" { - cc_builder.flag_if_supported("-Wbad-function-cast"); - } - - let flags = format!("{:?}", cc_builder.get_compiler().cflags_env()); - cc_builder.define("MDBX_BUILD_FLAGS", flags.as_str()).define("MDBX_TXN_CHECKOWNER", "0"); - - // Enable debugging on debug builds - #[cfg(debug_assertions)] - cc_builder.define("MDBX_DEBUG", "1").define("MDBX_ENABLE_PROFGC", "1"); - - // Disables debug logging on optimized builds - #[cfg(not(debug_assertions))] - cc_builder.define("MDBX_DEBUG", "0").define("NDEBUG", None); - - // Propagate `-C target-cpu=native` - let rustflags = env::var("CARGO_ENCODED_RUSTFLAGS").unwrap(); - if rustflags.contains("target-cpu=native") && - env::var("CARGO_CFG_TARGET_ENV").unwrap() != "msvc" - { - cc_builder.flag("-march=native"); - } - - cc_builder.file(mdbx.join("mdbx.c")).compile("libmdbx.a"); + bindings.write_to_file(out_file).expect("Couldn't write bindings!"); } diff --git a/crates/storage/libmdbx-rs/src/cursor.rs b/crates/storage/libmdbx-rs/src/cursor.rs index 6cc9b05f2f..36da31caa6 100644 --- a/crates/storage/libmdbx-rs/src/cursor.rs +++ b/crates/storage/libmdbx-rs/src/cursor.rs @@ -11,8 +11,7 @@ use ffi::{ MDBX_NEXT_MULTIPLE, MDBX_NEXT_NODUP, MDBX_PREV, MDBX_PREV_DUP, MDBX_PREV_MULTIPLE, MDBX_PREV_NODUP, MDBX_SET, MDBX_SET_KEY, MDBX_SET_LOWERBOUND, MDBX_SET_RANGE, }; -use libc::c_void; -use std::{borrow::Cow, fmt, marker::PhantomData, mem, ptr}; +use std::{borrow::Cow, ffi::c_void, fmt, marker::PhantomData, mem, ptr}; /// A cursor for navigating the items within a database. pub struct Cursor diff --git a/crates/storage/libmdbx-rs/src/environment.rs b/crates/storage/libmdbx-rs/src/environment.rs index f1a2cbe14a..1549d42e18 100644 --- a/crates/storage/libmdbx-rs/src/environment.rs +++ b/crates/storage/libmdbx-rs/src/environment.rs @@ -201,8 +201,8 @@ impl Environment { /// Note: /// /// * MDBX stores all the freelists in the designated database 0 in each environment, and the - /// freelist count is stored at the beginning of the value as `libc::uint32_t` in the native - /// byte order. + /// freelist count is stored at the beginning of the value as `uint32_t` in the native byte + /// order. /// /// * It will create a read transaction to traverse the freelist database. pub fn freelist(&self) -> Result { diff --git a/crates/storage/libmdbx-rs/src/error.rs b/crates/storage/libmdbx-rs/src/error.rs index 20a1011538..1df5a397b2 100644 --- a/crates/storage/libmdbx-rs/src/error.rs +++ b/crates/storage/libmdbx-rs/src/error.rs @@ -1,5 +1,4 @@ -use libc::c_int; -use std::result; +use std::{ffi::c_int, result}; /// An MDBX result. pub type Result = result::Result; diff --git a/crates/storage/libmdbx-rs/src/transaction.rs b/crates/storage/libmdbx-rs/src/transaction.rs index 5e8049bb22..37af501c18 100644 --- a/crates/storage/libmdbx-rs/src/transaction.rs +++ b/crates/storage/libmdbx-rs/src/transaction.rs @@ -8,9 +8,9 @@ use crate::{ }; use ffi::{mdbx_txn_renew, MDBX_txn_flags_t, MDBX_TXN_RDONLY, MDBX_TXN_READWRITE}; use indexmap::IndexSet; -use libc::{c_uint, c_void}; use parking_lot::{Mutex, MutexGuard}; use std::{ + ffi::{c_uint, c_void}, fmt::{self, Debug}, mem::size_of, ptr, slice, diff --git a/crates/storage/nippy-jar/src/error.rs b/crates/storage/nippy-jar/src/error.rs index 58e27a76b4..a440a9cb3e 100644 --- a/crates/storage/nippy-jar/src/error.rs +++ b/crates/storage/nippy-jar/src/error.rs @@ -42,6 +42,11 @@ pub enum NippyJarError { /// The read offset size in number of bytes. offset_size: u8, }, + #[error("the size of an offset must be at least 1 byte, got {offset_size}")] + OffsetSizeTooSmall { + /// The read offset size in number of bytes. + offset_size: u8, + }, #[error("attempted to read an out of bounds offset: {index}")] OffsetOutOfBounds { /// The index of the offset that was being read. diff --git a/crates/storage/nippy-jar/src/lib.rs b/crates/storage/nippy-jar/src/lib.rs index c36dbb5c7f..8247599d7a 100644 --- a/crates/storage/nippy-jar/src/lib.rs +++ b/crates/storage/nippy-jar/src/lib.rs @@ -514,6 +514,8 @@ impl DataReader { // Ensure that the size of an offset is at most 8 bytes. if offset_size > 8 { return Err(NippyJarError::OffsetSizeTooBig { offset_size }) + } else if offset_size == 0 { + return Err(NippyJarError::OffsetSizeTooSmall { offset_size }) } Ok(Self { data_file, data_mmap, offset_file, offset_size, offset_mmap }) @@ -551,7 +553,7 @@ impl DataReader { fn offset_at(&self, index: usize) -> Result { let mut buffer: [u8; 8] = [0; 8]; - let offset_end = index + self.offset_size as usize; + let offset_end = index.saturating_add(self.offset_size as usize); if offset_end > self.offset_mmap.len() { return Err(NippyJarError::OffsetOutOfBounds { index }) } diff --git a/crates/storage/provider/src/bundle_state/bundle_state_with_receipts.rs b/crates/storage/provider/src/bundle_state/bundle_state_with_receipts.rs index 81198481e2..a790d92fcf 100644 --- a/crates/storage/provider/src/bundle_state/bundle_state_with_receipts.rs +++ b/crates/storage/provider/src/bundle_state/bundle_state_with_receipts.rs @@ -42,12 +42,14 @@ impl StateWriter for ExecutionOutcome { if let Some(static_file_producer) = &mut static_file_producer { // Increment block on static file header. static_file_producer.increment_block(StaticFileSegment::Receipts, block_number)?; - - for (tx_idx, receipt) in receipts.into_iter().enumerate() { - let receipt = receipt - .expect("receipt should not be filtered when saving to static files."); - static_file_producer.append_receipt(first_tx_index + tx_idx as u64, receipt)?; - } + let receipts = receipts.into_iter().enumerate().map(|(tx_idx, receipt)| { + Ok(( + first_tx_index + tx_idx as u64, + receipt + .expect("receipt should not be filtered when saving to static files."), + )) + }); + static_file_producer.append_receipts(receipts)?; } else if !receipts.is_empty() { for (tx_idx, receipt) in receipts.into_iter().enumerate() { if let Some(receipt) = receipt { @@ -280,6 +282,7 @@ mod tests { EvmStorageSlot { present_value: U256::from(2), original_value: U256::from(1), + ..Default::default() }, )]), }, @@ -470,7 +473,11 @@ mod tests { // 0x00 => 1 => 2 storage: HashMap::from([( U256::ZERO, - EvmStorageSlot { original_value: U256::from(1), present_value: U256::from(2) }, + EvmStorageSlot { + original_value: U256::from(1), + present_value: U256::from(2), + ..Default::default() + }, )]), }, )])); diff --git a/crates/storage/provider/src/providers/bundle_state_provider.rs b/crates/storage/provider/src/providers/bundle_state_provider.rs index aec1ce1828..49fb196ffb 100644 --- a/crates/storage/provider/src/providers/bundle_state_provider.rs +++ b/crates/storage/provider/src/providers/bundle_state_provider.rs @@ -1,9 +1,9 @@ use crate::{ AccountReader, BlockHashReader, ExecutionDataProvider, StateProvider, StateRootProvider, }; -use reth_primitives::{proofs::AccountProof, Account, Address, BlockNumber, Bytecode, B256}; +use reth_primitives::{Account, Address, BlockNumber, Bytecode, B256}; use reth_storage_errors::provider::{ProviderError, ProviderResult}; -use reth_trie::updates::TrieUpdates; +use reth_trie::{updates::TrieUpdates, AccountProof}; use revm::db::BundleState; /// A state provider that resolves to data from either a wrapped [`crate::ExecutionOutcome`] diff --git a/crates/storage/provider/src/providers/database/provider.rs b/crates/storage/provider/src/providers/database/provider.rs index 01c4816599..a305d8ddc9 100644 --- a/crates/storage/provider/src/providers/database/provider.rs +++ b/crates/storage/provider/src/providers/database/provider.rs @@ -115,7 +115,7 @@ impl DatabaseProvider { impl DatabaseProvider { /// Creates a provider with an inner read-write transaction. - pub fn new_rw( + pub const fn new_rw( tx: TX, chain_spec: Arc, static_file_provider: StaticFileProvider, @@ -252,7 +252,7 @@ where impl DatabaseProvider { /// Creates a provider with an inner read-only transaction. - pub fn new( + pub const fn new( tx: TX, chain_spec: Arc, static_file_provider: StaticFileProvider, diff --git a/crates/storage/provider/src/providers/state/historical.rs b/crates/storage/provider/src/providers/state/historical.rs index d0304c1c4a..12545fe783 100644 --- a/crates/storage/provider/src/providers/state/historical.rs +++ b/crates/storage/provider/src/providers/state/historical.rs @@ -10,11 +10,11 @@ use reth_db_api::{ transaction::DbTx, }; use reth_primitives::{ - constants::EPOCH_SLOTS, proofs::AccountProof, Account, Address, BlockNumber, Bytecode, - StaticFileSegment, StorageKey, StorageValue, B256, + constants::EPOCH_SLOTS, Account, Address, BlockNumber, Bytecode, StaticFileSegment, StorageKey, + StorageValue, B256, }; use reth_storage_errors::provider::ProviderResult; -use reth_trie::{updates::TrieUpdates, HashedPostState}; +use reth_trie::{updates::TrieUpdates, AccountProof, HashedPostState}; use revm::db::BundleState; use std::fmt::Debug; diff --git a/crates/storage/provider/src/providers/state/latest.rs b/crates/storage/provider/src/providers/state/latest.rs index a8e554461d..56b4ecc38b 100644 --- a/crates/storage/provider/src/providers/state/latest.rs +++ b/crates/storage/provider/src/providers/state/latest.rs @@ -8,11 +8,10 @@ use reth_db_api::{ transaction::DbTx, }; use reth_primitives::{ - proofs::AccountProof, Account, Address, BlockNumber, Bytecode, StaticFileSegment, StorageKey, - StorageValue, B256, + Account, Address, BlockNumber, Bytecode, StaticFileSegment, StorageKey, StorageValue, B256, }; use reth_storage_errors::provider::{ProviderError, ProviderResult}; -use reth_trie::{proof::Proof, updates::TrieUpdates, HashedPostState}; +use reth_trie::{proof::Proof, updates::TrieUpdates, AccountProof, HashedPostState}; use revm::db::BundleState; /// State provider over latest state that takes tx reference. diff --git a/crates/storage/provider/src/providers/state/macros.rs b/crates/storage/provider/src/providers/state/macros.rs index 1d5a959783..a39cddfe39 100644 --- a/crates/storage/provider/src/providers/state/macros.rs +++ b/crates/storage/provider/src/providers/state/macros.rs @@ -43,7 +43,7 @@ macro_rules! delegate_provider_impls { } StateProvider $(where [$($generics)*])?{ fn storage(&self, account: reth_primitives::Address, storage_key: reth_primitives::StorageKey) -> reth_storage_errors::provider::ProviderResult>; - fn proof(&self, address: reth_primitives::Address, keys: &[reth_primitives::B256]) -> reth_storage_errors::provider::ProviderResult; + fn proof(&self, address: reth_primitives::Address, keys: &[reth_primitives::B256]) -> reth_storage_errors::provider::ProviderResult; fn bytecode_by_hash(&self, code_hash: reth_primitives::B256) -> reth_storage_errors::provider::ProviderResult>; } ); diff --git a/crates/storage/provider/src/providers/static_file/metrics.rs b/crates/storage/provider/src/providers/static_file/metrics.rs index f1a4204a7b..72589ca698 100644 --- a/crates/storage/provider/src/providers/static_file/metrics.rs +++ b/crates/storage/provider/src/providers/static_file/metrics.rs @@ -80,6 +80,28 @@ impl StaticFileProviderMetrics { .record(duration.as_secs_f64()); } } + + pub(crate) fn record_segment_operations( + &self, + segment: StaticFileSegment, + operation: StaticFileProviderOperation, + count: u64, + duration: Option, + ) { + self.segment_operations + .get(&(segment, operation)) + .expect("segment operation metrics should exist") + .calls_total + .increment(count); + + if let Some(duration) = duration { + self.segment_operations + .get(&(segment, operation)) + .expect("segment operation metrics should exist") + .write_duration_seconds + .record(duration.as_secs_f64() / count as f64); + } + } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, EnumIter)] diff --git a/crates/storage/provider/src/providers/static_file/writer.rs b/crates/storage/provider/src/providers/static_file/writer.rs index 147d812ce3..304429a015 100644 --- a/crates/storage/provider/src/providers/static_file/writer.rs +++ b/crates/storage/provider/src/providers/static_file/writer.rs @@ -547,6 +547,44 @@ impl StaticFileProviderRW { Ok(result) } + /// Appends multiple receipts to the static file. + /// + /// Returns the current [`TxNumber`] as seen in the static file, if any. + pub fn append_receipts(&mut self, receipts: I) -> ProviderResult> + where + I: IntoIterator>, + { + let mut receipts_iter = receipts.into_iter().peekable(); + // If receipts are empty, we can simply return None + if receipts_iter.peek().is_none() { + return Ok(None); + } + + let start = Instant::now(); + self.ensure_no_queued_prune()?; + + // At this point receipts contains at least one receipt, so this would be overwritten. + let mut tx_number = 0; + let mut count: u64 = 0; + + for receipt_result in receipts_iter { + let (tx_num, receipt) = receipt_result?; + tx_number = self.append_with_tx_number(StaticFileSegment::Receipts, tx_num, receipt)?; + count += 1; + } + + if let Some(metrics) = &self.metrics { + metrics.record_segment_operations( + StaticFileSegment::Receipts, + StaticFileProviderOperation::Append, + count, + Some(start.elapsed()), + ); + } + + Ok(Some(tx_number)) + } + /// Adds an instruction to prune `to_delete`transactions during commit. /// /// Note: `last_block` refers to the block the unwinds ends at. diff --git a/crates/storage/provider/src/test_utils/blocks.rs b/crates/storage/provider/src/test_utils/blocks.rs index be4420fc51..5fb8beeb24 100644 --- a/crates/storage/provider/src/test_utils/blocks.rs +++ b/crates/storage/provider/src/test_utils/blocks.rs @@ -5,13 +5,11 @@ use alloy_rlp::Decodable; use reth_db::tables; use reth_db_api::{database::Database, models::StoredBlockBodyIndices}; use reth_primitives::{ - alloy_primitives, b256, - hex_literal::hex, - proofs::{state_root_unhashed, storage_root_unhashed}, - revm::compat::into_reth_acc, - Address, BlockNumber, Bytes, Header, Receipt, Requests, SealedBlock, SealedBlockWithSenders, - TxType, Withdrawal, Withdrawals, B256, U256, + alloy_primitives, b256, hex_literal::hex, revm::compat::into_reth_acc, Address, BlockNumber, + Bytes, Header, Receipt, Requests, SealedBlock, SealedBlockWithSenders, TxType, Withdrawal, + Withdrawals, B256, U256, }; +use reth_trie::root::{state_root_unhashed, storage_root_unhashed}; use revm::{ db::BundleState, primitives::{AccountInfo, HashMap}, diff --git a/crates/storage/provider/src/test_utils/mock.rs b/crates/storage/provider/src/test_utils/mock.rs index a255eb28e1..0788ddf1e8 100644 --- a/crates/storage/provider/src/test_utils/mock.rs +++ b/crates/storage/provider/src/test_utils/mock.rs @@ -9,14 +9,14 @@ use parking_lot::Mutex; use reth_db_api::models::{AccountBeforeTx, StoredBlockBodyIndices}; use reth_evm::ConfigureEvmEnv; use reth_primitives::{ - keccak256, proofs::AccountProof, Account, Address, Block, BlockHash, BlockHashOrNumber, - BlockId, BlockNumber, BlockWithSenders, Bytecode, Bytes, ChainInfo, ChainSpec, Header, Receipt, - SealedBlock, SealedBlockWithSenders, SealedHeader, StorageKey, StorageValue, TransactionMeta, + keccak256, Account, Address, Block, BlockHash, BlockHashOrNumber, BlockId, BlockNumber, + BlockWithSenders, Bytecode, Bytes, ChainInfo, ChainSpec, Header, Receipt, SealedBlock, + SealedBlockWithSenders, SealedHeader, StorageKey, StorageValue, TransactionMeta, TransactionSigned, TransactionSignedNoHash, TxHash, TxNumber, Withdrawal, Withdrawals, B256, U256, }; use reth_storage_errors::provider::{ProviderError, ProviderResult}; -use reth_trie::updates::TrieUpdates; +use reth_trie::{updates::TrieUpdates, AccountProof}; use revm::{ db::BundleState, primitives::{BlockEnv, CfgEnvWithHandlerCfg}, diff --git a/crates/storage/provider/src/test_utils/noop.rs b/crates/storage/provider/src/test_utils/noop.rs index 8894a68f7e..b681586a14 100644 --- a/crates/storage/provider/src/test_utils/noop.rs +++ b/crates/storage/provider/src/test_utils/noop.rs @@ -9,16 +9,15 @@ use crate::{ use reth_db_api::models::{AccountBeforeTx, StoredBlockBodyIndices}; use reth_evm::ConfigureEvmEnv; use reth_primitives::{ - proofs::AccountProof, Account, Address, Block, BlockHash, BlockHashOrNumber, BlockId, - BlockNumber, BlockWithSenders, Bytecode, ChainInfo, ChainSpec, Header, Receipt, SealedBlock, - SealedBlockWithSenders, SealedHeader, StorageKey, StorageValue, TransactionMeta, - TransactionSigned, TransactionSignedNoHash, TxHash, TxNumber, Withdrawal, Withdrawals, B256, - MAINNET, U256, + Account, Address, Block, BlockHash, BlockHashOrNumber, BlockId, BlockNumber, BlockWithSenders, + Bytecode, ChainInfo, ChainSpec, Header, Receipt, SealedBlock, SealedBlockWithSenders, + SealedHeader, StorageKey, StorageValue, TransactionMeta, TransactionSigned, + TransactionSignedNoHash, TxHash, TxNumber, Withdrawal, Withdrawals, B256, MAINNET, U256, }; use reth_prune_types::{PruneCheckpoint, PruneSegment}; use reth_stages_types::{StageCheckpoint, StageId}; use reth_storage_errors::provider::ProviderResult; -use reth_trie::updates::TrieUpdates; +use reth_trie::{updates::TrieUpdates, AccountProof}; use revm::{ db::BundleState, primitives::{BlockEnv, CfgEnvWithHandlerCfg}, diff --git a/crates/storage/storage-api/src/state.rs b/crates/storage/storage-api/src/state.rs index 9e258bfd16..059909a463 100644 --- a/crates/storage/storage-api/src/state.rs +++ b/crates/storage/storage-api/src/state.rs @@ -2,10 +2,11 @@ use super::{AccountReader, BlockHashReader, BlockIdReader, StateRootProvider}; use auto_impl::auto_impl; use reth_execution_types::ExecutionOutcome; use reth_primitives::{ - proofs::AccountProof, Address, BlockHash, BlockId, BlockNumHash, BlockNumber, BlockNumberOrTag, - Bytecode, StorageKey, StorageValue, B256, KECCAK_EMPTY, U256, + Address, BlockHash, BlockId, BlockNumHash, BlockNumber, BlockNumberOrTag, Bytecode, StorageKey, + StorageValue, B256, KECCAK_EMPTY, U256, }; use reth_storage_errors::provider::{ProviderError, ProviderResult}; +use reth_trie::AccountProof; /// Type alias of boxed [`StateProvider`]. pub type StateProviderBox = Box; diff --git a/crates/tasks/src/shutdown.rs b/crates/tasks/src/shutdown.rs index 918a0cf36a..bd9a50dc9a 100644 --- a/crates/tasks/src/shutdown.rs +++ b/crates/tasks/src/shutdown.rs @@ -20,7 +20,7 @@ pub struct GracefulShutdown { } impl GracefulShutdown { - pub(crate) fn new(shutdown: Shutdown, guard: GracefulShutdownGuard) -> Self { + pub(crate) const fn new(shutdown: Shutdown, guard: GracefulShutdownGuard) -> Self { Self { shutdown, guard: Some(guard) } } diff --git a/crates/transaction-pool/src/test_utils/gen.rs b/crates/transaction-pool/src/test_utils/gen.rs index 0b981ea155..87c2ba580d 100644 --- a/crates/transaction-pool/src/test_utils/gen.rs +++ b/crates/transaction-pool/src/test_utils/gen.rs @@ -225,13 +225,13 @@ impl TransactionBuilder { } /// Increments the nonce value of the transaction builder by 1. - pub fn inc_nonce(mut self) -> Self { + pub const fn inc_nonce(mut self) -> Self { self.nonce += 1; self } /// Decrements the nonce value of the transaction builder by 1, avoiding underflow. - pub fn decr_nonce(mut self) -> Self { + pub const fn decr_nonce(mut self) -> Self { self.nonce = self.nonce.saturating_sub(1); self } diff --git a/crates/transaction-pool/src/test_utils/mock.rs b/crates/transaction-pool/src/test_utils/mock.rs index 07afac215e..9eb8d832ef 100644 --- a/crates/transaction-pool/src/test_utils/mock.rs +++ b/crates/transaction-pool/src/test_utils/mock.rs @@ -1447,7 +1447,7 @@ pub struct MockTransactionSet { impl MockTransactionSet { /// Create a new [`MockTransactionSet`] from a list of transactions - fn new(transactions: Vec) -> Self { + const fn new(transactions: Vec) -> Self { Self { transactions } } diff --git a/crates/trie/types/Cargo.toml b/crates/trie/common/Cargo.toml similarity index 52% rename from crates/trie/types/Cargo.toml rename to crates/trie/common/Cargo.toml index 4dc2f15dc9..241a3518f7 100644 --- a/crates/trie/types/Cargo.toml +++ b/crates/trie/common/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "reth-trie-types" +name = "reth-trie-common" version.workspace = true edition.workspace = true homepage.workspace = true @@ -12,17 +12,29 @@ description = "Commonly used types for trie usage in reth." workspace = true [dependencies] +reth-primitives-traits.workspace = true reth-codecs.workspace = true alloy-primitives.workspace = true alloy-rlp = { workspace = true, features = ["arrayvec"] } alloy-trie = { workspace = true, features = ["serde"] } +alloy-consensus.workspace = true +alloy-genesis.workspace = true +revm-primitives.workspace = true + bytes.workspace = true derive_more.workspace = true serde.workspace = true - +itertools.workspace = true nybbles = { workspace = true, features = ["serde", "rlp"] } +# `test-utils` feature +hash-db = { version = "~0.15", optional = true } +plain_hasher = { version = "0.2", optional = true } +arbitrary = { workspace = true, features = ["derive"], optional = true } +proptest = { workspace = true, optional = true } +proptest-derive = { workspace = true, optional = true } + [dev-dependencies] arbitrary = { workspace = true, features = ["derive"] } assert_matches.workspace = true @@ -30,4 +42,15 @@ proptest.workspace = true proptest-derive.workspace = true serde_json.workspace = true test-fuzz.workspace = true -toml.workspace = true \ No newline at end of file +toml.workspace = true +hash-db = "~0.15" +plain_hasher = "0.2" + +[features] +test-utils = ["dep:plain_hasher", "dep:hash-db", "arbitrary"] +arbitrary = [ + "alloy-trie/arbitrary", + "dep:arbitrary", + "dep:proptest", + "dep:proptest-derive", +] \ No newline at end of file diff --git a/crates/trie/common/src/account.rs b/crates/trie/common/src/account.rs new file mode 100644 index 0000000000..64860ab78b --- /dev/null +++ b/crates/trie/common/src/account.rs @@ -0,0 +1,73 @@ +use crate::root::storage_root_unhashed; +use alloy_consensus::constants::KECCAK_EMPTY; +use alloy_genesis::GenesisAccount; +use alloy_primitives::{keccak256, B256, U256}; +use alloy_rlp::{RlpDecodable, RlpEncodable}; +use alloy_trie::EMPTY_ROOT_HASH; +use reth_primitives_traits::Account; +use revm_primitives::AccountInfo; + +/// An Ethereum account as represented in the trie. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Default, RlpEncodable, RlpDecodable)] +pub struct TrieAccount { + /// Account nonce. + pub nonce: u64, + /// Account balance. + pub balance: U256, + /// Account's storage root. + pub storage_root: B256, + /// Hash of the account's bytecode. + pub code_hash: B256, +} + +impl TrieAccount { + /// Get account's storage root. + pub const fn storage_root(&self) -> B256 { + self.storage_root + } +} + +impl From for TrieAccount { + fn from(account: GenesisAccount) -> Self { + let storage_root = account + .storage + .map(|storage| { + storage_root_unhashed( + storage + .into_iter() + .filter(|(_, value)| *value != B256::ZERO) + .map(|(slot, value)| (slot, U256::from_be_bytes(*value))), + ) + }) + .unwrap_or(EMPTY_ROOT_HASH); + + Self { + nonce: account.nonce.unwrap_or_default(), + balance: account.balance, + storage_root, + code_hash: account.code.map_or(KECCAK_EMPTY, keccak256), + } + } +} + +impl From<(Account, B256)> for TrieAccount { + fn from((account, storage_root): (Account, B256)) -> Self { + Self { + nonce: account.nonce, + balance: account.balance, + storage_root, + code_hash: account.bytecode_hash.unwrap_or(KECCAK_EMPTY), + } + } +} + +impl From<(AccountInfo, B256)> for TrieAccount { + fn from((account, storage_root): (AccountInfo, B256)) -> Self { + Self { + nonce: account.nonce, + balance: account.balance, + storage_root, + code_hash: account.code_hash, + } + } +} diff --git a/crates/trie/types/src/hash_builder/mod.rs b/crates/trie/common/src/hash_builder/mod.rs similarity index 100% rename from crates/trie/types/src/hash_builder/mod.rs rename to crates/trie/common/src/hash_builder/mod.rs diff --git a/crates/trie/types/src/hash_builder/state.rs b/crates/trie/common/src/hash_builder/state.rs similarity index 100% rename from crates/trie/types/src/hash_builder/state.rs rename to crates/trie/common/src/hash_builder/state.rs diff --git a/crates/trie/types/src/hash_builder/value.rs b/crates/trie/common/src/hash_builder/value.rs similarity index 100% rename from crates/trie/types/src/hash_builder/value.rs rename to crates/trie/common/src/hash_builder/value.rs diff --git a/crates/trie/types/src/lib.rs b/crates/trie/common/src/lib.rs similarity index 87% rename from crates/trie/types/src/lib.rs rename to crates/trie/common/src/lib.rs index 0b4927b9c8..bc3749e6f9 100644 --- a/crates/trie/types/src/lib.rs +++ b/crates/trie/common/src/lib.rs @@ -31,4 +31,11 @@ pub use storage::StorageTrieEntry; mod subnode; pub use subnode::StoredSubNode; +mod proofs; +#[cfg(any(test, feature = "test-utils"))] +pub use proofs::triehash; +pub use proofs::{AccountProof, StorageProof}; + +pub mod root; + pub use alloy_trie::{proof, BranchNodeCompact, HashBuilder, TrieMask, EMPTY_ROOT_HASH}; diff --git a/crates/trie/types/src/mask.rs b/crates/trie/common/src/mask.rs similarity index 100% rename from crates/trie/types/src/mask.rs rename to crates/trie/common/src/mask.rs diff --git a/crates/trie/types/src/nibbles.rs b/crates/trie/common/src/nibbles.rs similarity index 100% rename from crates/trie/types/src/nibbles.rs rename to crates/trie/common/src/nibbles.rs diff --git a/crates/trie/types/src/nodes/branch.rs b/crates/trie/common/src/nodes/branch.rs similarity index 100% rename from crates/trie/types/src/nodes/branch.rs rename to crates/trie/common/src/nodes/branch.rs diff --git a/crates/trie/types/src/nodes/mod.rs b/crates/trie/common/src/nodes/mod.rs similarity index 100% rename from crates/trie/types/src/nodes/mod.rs rename to crates/trie/common/src/nodes/mod.rs diff --git a/crates/primitives/src/proofs/types.rs b/crates/trie/common/src/proofs.rs similarity index 79% rename from crates/primitives/src/proofs/types.rs rename to crates/trie/common/src/proofs.rs index f2225df794..11953a48de 100644 --- a/crates/primitives/src/proofs/types.rs +++ b/crates/trie/common/src/proofs.rs @@ -1,12 +1,13 @@ //! Merkle trie proofs. -use super::{traits::IntoTrieAccount, Nibbles}; -use crate::{keccak256, Account, Address, Bytes, B256, U256}; +use crate::{Nibbles, TrieAccount}; +use alloy_primitives::{keccak256, Address, Bytes, B256, U256}; use alloy_rlp::encode_fixed_size; use alloy_trie::{ proof::{verify_proof, ProofVerificationError}, EMPTY_ROOT_HASH, }; +use reth_primitives_traits::Account; /// The merkle proof with the relevant account info. #[derive(PartialEq, Eq, Debug)] @@ -26,7 +27,7 @@ pub struct AccountProof { impl AccountProof { /// Create new account proof entity. - pub fn new(address: Address) -> Self { + pub const fn new(address: Address) -> Self { Self { address, info: None, @@ -64,7 +65,7 @@ impl AccountProof { let expected = if self.info.is_none() && self.storage_root == EMPTY_ROOT_HASH { None } else { - Some(alloy_rlp::encode(IntoTrieAccount::to_trie_account(( + Some(alloy_rlp::encode(TrieAccount::from(( self.info.unwrap_or_default(), self.storage_root, )))) @@ -122,3 +123,29 @@ impl StorageProof { verify_proof(root, self.nibbles.clone(), expected, &self.proof) } } + +/// Implementation of hasher using our keccak256 hashing function +/// for compatibility with `triehash` crate. +#[cfg(any(test, feature = "test-utils"))] +pub mod triehash { + use alloy_primitives::{keccak256, B256}; + use hash_db::Hasher; + use plain_hasher::PlainHasher; + + /// A [Hasher] that calculates a keccak256 hash of the given data. + #[derive(Default, Debug, Clone, PartialEq, Eq)] + #[non_exhaustive] + pub struct KeccakHasher; + + #[cfg(any(test, feature = "test-utils"))] + impl Hasher for KeccakHasher { + type Out = B256; + type StdHasher = PlainHasher; + + const LENGTH: usize = 32; + + fn hash(x: &[u8]) -> Self::Out { + keccak256(x) + } + } +} diff --git a/crates/trie/common/src/root.rs b/crates/trie/common/src/root.rs new file mode 100644 index 0000000000..434eea20b5 --- /dev/null +++ b/crates/trie/common/src/root.rs @@ -0,0 +1,117 @@ +//! Common root computation functions. + +use crate::TrieAccount; +use alloy_primitives::{keccak256, Address, B256, U256}; +use alloy_rlp::Encodable; +use alloy_trie::HashBuilder; +use itertools::Itertools; +use nybbles::Nibbles; + +/// Adjust the index of an item for rlp encoding. +pub const fn adjust_index_for_rlp(i: usize, len: usize) -> usize { + if i > 0x7f { + i + } else if i == 0x7f || i + 1 == len { + 0 + } else { + i + 1 + } +} + +/// Compute a trie root of the collection of rlp encodable items. +pub fn ordered_trie_root(items: &[T]) -> B256 { + ordered_trie_root_with_encoder(items, |item, buf| item.encode(buf)) +} + +/// Compute a trie root of the collection of items with a custom encoder. +pub fn ordered_trie_root_with_encoder(items: &[T], mut encode: F) -> B256 +where + F: FnMut(&T, &mut Vec), +{ + let mut value_buffer = Vec::new(); + + let mut hb = HashBuilder::default(); + let items_len = items.len(); + for i in 0..items_len { + let index = adjust_index_for_rlp(i, items_len); + + let index_buffer = alloy_rlp::encode_fixed_size(&index); + + value_buffer.clear(); + encode(&items[index], &mut value_buffer); + + hb.add_leaf(Nibbles::unpack(&index_buffer), &value_buffer); + } + + hb.root() +} + +/// Hashes and sorts account keys, then proceeds to calculating the root hash of the state +/// represented as MPT. +/// See [`state_root_unsorted`] for more info. +pub fn state_root_ref_unhashed<'a, A: Into + Clone + 'a>( + state: impl IntoIterator, +) -> B256 { + state_root_unsorted( + state.into_iter().map(|(address, account)| (keccak256(address), account.clone())), + ) +} + +/// Hashes and sorts account keys, then proceeds to calculating the root hash of the state +/// represented as MPT. +/// See [`state_root_unsorted`] for more info. +pub fn state_root_unhashed>( + state: impl IntoIterator, +) -> B256 { + state_root_unsorted(state.into_iter().map(|(address, account)| (keccak256(address), account))) +} + +/// Sorts the hashed account keys and calculates the root hash of the state represented as MPT. +/// See [`state_root`] for more info. +pub fn state_root_unsorted>( + state: impl IntoIterator, +) -> B256 { + state_root(state.into_iter().sorted_by_key(|(key, _)| *key)) +} + +/// Calculates the root hash of the state represented as MPT. +/// Corresponds to [geth's `deriveHash`](https://github.com/ethereum/go-ethereum/blob/6c149fd4ad063f7c24d726a73bc0546badd1bc73/core/genesis.go#L119). +/// +/// # Panics +/// +/// If the items are not in sorted order. +pub fn state_root>(state: impl IntoIterator) -> B256 { + let mut hb = HashBuilder::default(); + let mut account_rlp_buf = Vec::new(); + for (hashed_key, account) in state { + account_rlp_buf.clear(); + account.into().encode(&mut account_rlp_buf); + hb.add_leaf(Nibbles::unpack(hashed_key), &account_rlp_buf); + } + hb.root() +} + +/// Hashes storage keys, sorts them and them calculates the root hash of the storage trie. +/// See [`storage_root_unsorted`] for more info. +pub fn storage_root_unhashed(storage: impl IntoIterator) -> B256 { + storage_root_unsorted(storage.into_iter().map(|(slot, value)| (keccak256(slot), value))) +} + +/// Sorts and calculates the root hash of account storage trie. +/// See [`storage_root`] for more info. +pub fn storage_root_unsorted(storage: impl IntoIterator) -> B256 { + storage_root(storage.into_iter().sorted_by_key(|(key, _)| *key)) +} + +/// Calculates the root hash of account storage trie. +/// +/// # Panics +/// +/// If the items are not in sorted order. +pub fn storage_root(storage: impl IntoIterator) -> B256 { + let mut hb = HashBuilder::default(); + for (hashed_slot, value) in storage { + hb.add_leaf(Nibbles::unpack(hashed_slot), alloy_rlp::encode_fixed_size(&value).as_ref()); + } + hb.root() +} diff --git a/crates/trie/types/src/storage.rs b/crates/trie/common/src/storage.rs similarity index 100% rename from crates/trie/types/src/storage.rs rename to crates/trie/common/src/storage.rs diff --git a/crates/trie/types/src/subnode.rs b/crates/trie/common/src/subnode.rs similarity index 100% rename from crates/trie/types/src/subnode.rs rename to crates/trie/common/src/subnode.rs diff --git a/crates/trie/parallel/src/async_root.rs b/crates/trie/parallel/src/async_root.rs index 7441bd0a02..a36a01be5e 100644 --- a/crates/trie/parallel/src/async_root.rs +++ b/crates/trie/parallel/src/async_root.rs @@ -3,7 +3,7 @@ use alloy_rlp::{BufMut, Encodable}; use itertools::Itertools; use reth_db_api::database::Database; use reth_execution_errors::StorageRootError; -use reth_primitives::{proofs::IntoTrieAccount, B256}; +use reth_primitives::B256; use reth_provider::{providers::ConsistentDbView, DatabaseProviderFactory, ProviderError}; use reth_tasks::pool::BlockingTaskPool; use reth_trie::{ @@ -12,7 +12,7 @@ use reth_trie::{ trie_cursor::TrieCursorFactory, updates::TrieUpdates, walker::TrieWalker, - HashBuilder, HashedPostState, Nibbles, StorageRoot, + HashBuilder, HashedPostState, Nibbles, StorageRoot, TrieAccount, }; use std::{collections::HashMap, sync::Arc}; use thiserror::Error; @@ -170,7 +170,7 @@ where } account_rlp.clear(); - let account = IntoTrieAccount::to_trie_account((account, storage_root)); + let account = TrieAccount::from((account, storage_root)); account.encode(&mut account_rlp as &mut dyn BufMut); hash_builder.add_leaf(Nibbles::unpack(hashed_address), &account_rlp); } diff --git a/crates/trie/parallel/src/parallel_root.rs b/crates/trie/parallel/src/parallel_root.rs index f814e2ff88..edf552096f 100644 --- a/crates/trie/parallel/src/parallel_root.rs +++ b/crates/trie/parallel/src/parallel_root.rs @@ -3,7 +3,7 @@ use alloy_rlp::{BufMut, Encodable}; use rayon::prelude::*; use reth_db_api::database::Database; use reth_execution_errors::StorageRootError; -use reth_primitives::{proofs::IntoTrieAccount, B256}; +use reth_primitives::B256; use reth_provider::{providers::ConsistentDbView, DatabaseProviderFactory, ProviderError}; use reth_trie::{ hashed_cursor::{HashedCursorFactory, HashedPostStateCursorFactory}, @@ -11,7 +11,7 @@ use reth_trie::{ trie_cursor::TrieCursorFactory, updates::TrieUpdates, walker::TrieWalker, - HashBuilder, HashedPostState, Nibbles, StorageRoot, + HashBuilder, HashedPostState, Nibbles, StorageRoot, TrieAccount, }; use std::collections::HashMap; use thiserror::Error; @@ -152,7 +152,7 @@ where } account_rlp.clear(); - let account = IntoTrieAccount::to_trie_account((account, storage_root)); + let account = TrieAccount::from((account, storage_root)); account.encode(&mut account_rlp as &mut dyn BufMut); hash_builder.add_leaf(Nibbles::unpack(hashed_address), &account_rlp); } diff --git a/crates/trie/trie/Cargo.toml b/crates/trie/trie/Cargo.toml index 99beeff070..d01914759a 100644 --- a/crates/trie/trie/Cargo.toml +++ b/crates/trie/trie/Cargo.toml @@ -18,7 +18,7 @@ reth-execution-errors.workspace = true reth-db.workspace = true reth-db-api.workspace = true reth-stages-types.workspace = true -reth-trie-types.workspace = true +reth-trie-common.workspace = true revm.workspace = true @@ -46,6 +46,7 @@ reth-primitives = { workspace = true, features = ["test-utils", "arbitrary"] } reth-db = { workspace = true, features = ["test-utils"] } reth-provider = { workspace = true, features = ["test-utils"] } reth-storage-errors.workspace = true +reth-trie-common = { workspace = true, features = ["test-utils", "arbitrary"] } # trie triehash = "0.8" @@ -65,7 +66,7 @@ criterion.workspace = true [features] metrics = ["reth-metrics", "dep:metrics"] -test-utils = ["triehash"] +test-utils = ["triehash", "reth-trie-common/test-utils"] [[bench]] name = "prefix_set" @@ -74,3 +75,8 @@ harness = false [[bench]] name = "hash_post_state" harness = false + +[[bench]] +name = "trie_root" +required-features = ["test-utils"] +harness = false diff --git a/crates/primitives/benches/trie_root.rs b/crates/trie/trie/benches/trie_root.rs similarity index 92% rename from crates/primitives/benches/trie_root.rs rename to crates/trie/trie/benches/trie_root.rs index b61e3aa854..8a149404ab 100644 --- a/crates/primitives/benches/trie_root.rs +++ b/crates/trie/trie/benches/trie_root.rs @@ -1,7 +1,8 @@ #![allow(missing_docs, unreachable_pub)] use criterion::{black_box, criterion_group, criterion_main, Criterion}; use proptest::{prelude::*, strategy::ValueTree, test_runner::TestRunner}; -use reth_primitives::{proofs::triehash::KeccakHasher, ReceiptWithBloom, B256}; +use reth_primitives::{ReceiptWithBloom, B256}; +use reth_trie::triehash::KeccakHasher; /// Benchmarks different implementations of the root calculation. pub fn trie_root_benchmark(c: &mut Criterion) { @@ -41,8 +42,7 @@ criterion_main!(benches); mod implementations { use super::*; use alloy_rlp::Encodable; - use reth_primitives::proofs::adjust_index_for_rlp; - use reth_trie_types::{HashBuilder, Nibbles}; + use reth_trie_common::{root::adjust_index_for_rlp, HashBuilder, Nibbles}; pub fn trie_hash_ordered_trie_root(receipts: &[ReceiptWithBloom]) -> B256 { triehash::ordered_trie_root::(receipts.iter().map(|receipt| { diff --git a/crates/trie/trie/src/lib.rs b/crates/trie/trie/src/lib.rs index 16251dc119..eea65a7b34 100644 --- a/crates/trie/trie/src/lib.rs +++ b/crates/trie/trie/src/lib.rs @@ -51,7 +51,7 @@ pub use progress::{IntermediateStateRootState, StateRootProgress}; pub mod stats; // re-export for convenience -pub use reth_trie_types::*; +pub use reth_trie_common::*; /// Trie calculation metrics. #[cfg(feature = "metrics")] diff --git a/crates/trie/trie/src/proof.rs b/crates/trie/trie/src/proof.rs index d3438dfaa5..19c8b7fabb 100644 --- a/crates/trie/trie/src/proof.rs +++ b/crates/trie/trie/src/proof.rs @@ -10,13 +10,8 @@ use alloy_rlp::{BufMut, Encodable}; use reth_db::tables; use reth_db_api::transaction::DbTx; use reth_execution_errors::{StateRootError, StorageRootError}; -use reth_primitives::{ - constants::EMPTY_ROOT_HASH, - keccak256, - proofs::{AccountProof, IntoTrieAccount, StorageProof}, - Address, B256, -}; -use reth_trie_types::proof::ProofRetainer; +use reth_primitives::{constants::EMPTY_ROOT_HASH, keccak256, Address, B256}; +use reth_trie_common::{proof::ProofRetainer, AccountProof, StorageProof, TrieAccount}; /// A struct for generating merkle proofs. /// /// Proof generator adds the target address and slots to the prefix set, enables the proof retainer @@ -83,7 +78,7 @@ where }; account_rlp.clear(); - let account = IntoTrieAccount::to_trie_account((account, storage_root)); + let account = TrieAccount::from((account, storage_root)); account.encode(&mut account_rlp as &mut dyn BufMut); hash_builder.add_leaf(Nibbles::unpack(hashed_address), &account_rlp); diff --git a/crates/trie/trie/src/test_utils.rs b/crates/trie/trie/src/test_utils.rs index bd0c1936fb..e2fc1f192c 100644 --- a/crates/trie/trie/src/test_utils.rs +++ b/crates/trie/trie/src/test_utils.rs @@ -1,8 +1,6 @@ use alloy_rlp::encode_fixed_size; -use reth_primitives::{ - proofs::{triehash::KeccakHasher, IntoTrieAccount}, - Account, Address, B256, U256, -}; +use reth_primitives::{Account, Address, B256, U256}; +use reth_trie_common::{triehash::KeccakHasher, TrieAccount}; /// Re-export of [triehash]. pub use triehash; @@ -15,7 +13,7 @@ where { let encoded_accounts = accounts.into_iter().map(|(address, (account, storage))| { let storage_root = storage_root(storage); - let account = IntoTrieAccount::to_trie_account((account, storage_root)); + let account = TrieAccount::from((account, storage_root)); (address, alloy_rlp::encode(account)) }); triehash::sec_trie_root::(encoded_accounts) @@ -36,7 +34,7 @@ where { let encoded_accounts = accounts.into_iter().map(|(address, (account, storage))| { let storage_root = storage_root_prehashed(storage); - let account = IntoTrieAccount::to_trie_account((account, storage_root)); + let account = TrieAccount::from((account, storage_root)); (address, alloy_rlp::encode(account)) }); diff --git a/crates/trie/trie/src/trie.rs b/crates/trie/trie/src/trie.rs index 91ba2e0463..3fe97a6f78 100644 --- a/crates/trie/trie/src/trie.rs +++ b/crates/trie/trie/src/trie.rs @@ -7,14 +7,12 @@ use crate::{ trie_cursor::TrieCursorFactory, updates::{TrieKey, TrieOp, TrieUpdates}, walker::TrieWalker, - HashBuilder, Nibbles, + HashBuilder, Nibbles, TrieAccount, }; use alloy_rlp::{BufMut, Encodable}; use reth_db_api::transaction::DbTx; use reth_execution_errors::{StateRootError, StorageRootError}; -use reth_primitives::{ - constants::EMPTY_ROOT_HASH, keccak256, proofs::IntoTrieAccount, Address, BlockNumber, B256, -}; +use reth_primitives::{constants::EMPTY_ROOT_HASH, keccak256, Address, BlockNumber, B256}; use std::ops::RangeInclusive; use tracing::{debug, trace}; @@ -282,7 +280,7 @@ where }; account_rlp.clear(); - let account = IntoTrieAccount::to_trie_account((account, storage_root)); + let account = TrieAccount::from((account, storage_root)); account.encode(&mut account_rlp as &mut dyn BufMut); hash_builder.add_leaf(Nibbles::unpack(hashed_address), &account_rlp); @@ -558,10 +556,9 @@ mod tests { cursor::{DbCursorRO, DbCursorRW, DbDupCursorRO}, transaction::DbTxMut, }; - use reth_primitives::{ - hex_literal::hex, proofs::triehash::KeccakHasher, Account, StorageEntry, U256, - }; + use reth_primitives::{hex_literal::hex, Account, StorageEntry, U256}; use reth_provider::{test_utils::create_test_provider_factory, DatabaseProviderRW}; + use reth_trie_common::triehash::KeccakHasher; use std::{ collections::{BTreeMap, HashMap}, ops::Mul, @@ -828,8 +825,7 @@ mod tests { } fn encode_account(account: Account, storage_root: Option) -> Vec { - let account = - IntoTrieAccount::to_trie_account((account, storage_root.unwrap_or(EMPTY_ROOT_HASH))); + let account = TrieAccount::from((account, storage_root.unwrap_or(EMPTY_ROOT_HASH))); let mut account_rlp = Vec::with_capacity(account.length()); account.encode(&mut account_rlp); account_rlp diff --git a/crates/trie/types/src/account.rs b/crates/trie/types/src/account.rs deleted file mode 100644 index 480a8c6a69..0000000000 --- a/crates/trie/types/src/account.rs +++ /dev/null @@ -1,22 +0,0 @@ -use alloy_primitives::{B256, U256}; -use alloy_rlp::{RlpDecodable, RlpEncodable}; - -/// An Ethereum account as represented in the trie. -#[derive(Clone, Copy, Debug, PartialEq, Eq, Default, RlpEncodable, RlpDecodable)] -pub struct TrieAccount { - /// Account nonce. - pub nonce: u64, - /// Account balance. - pub balance: U256, - /// Account's storage root. - pub storage_root: B256, - /// Hash of the account's bytecode. - pub code_hash: B256, -} - -impl TrieAccount { - /// Get account's storage root. - pub const fn storage_root(&self) -> B256 { - self.storage_root - } -} diff --git a/docs/repo/layout.md b/docs/repo/layout.md index c3c53321fa..552da3196b 100644 --- a/docs/repo/layout.md +++ b/docs/repo/layout.md @@ -137,11 +137,9 @@ Crates related to building and validating payloads (blocks). ### Primitives -These crates define primitive types or algorithms such as RLP. +These crates define primitive types or algorithms. - [`primitives`](../../crates/primitives): Commonly used types in Reth. -- [`rlp`](../../crates/rlp): An implementation of RLP, forked from an earlier Apache-licensed version of [`fastrlp`][fastrlp] -- [`rlp/rlp-derive`](../../crates/rlp/rlp-derive): Forked from an earlier Apache licenced version of the [`fastrlp-derive`][fastrlp-derive] crate, before it changed licence to GPL. - [`trie`](../../crates/trie): An implementation of a Merkle Patricia Trie used for various roots (e.g. the state root) in Ethereum. ### Misc @@ -154,8 +152,6 @@ Small utility crates. - [`metrics/metrics-derive`](../../crates/metrics/metrics-derive): A derive-style API for creating metrics - [`tracing`](../../crates/tracing): A small utility crate to install a uniform [`tracing`][tracing] subscriber -[fastrlp]: https://crates.io/crates/fastrlp -[fastrlp-derive]: https://crates.io/crates/fastrlp-derive [libmdbx-rs]: https://crates.io/crates/libmdbx [discv4]: https://github.com/ethereum/devp2p/blob/master/discv4.md [jsonrpsee]: https://github.com/paritytech/jsonrpsee/ diff --git a/etc/docker-compose.yml b/etc/docker-compose.yml index 8e69dc34ec..618aa6f5ae 100644 --- a/etc/docker-compose.yml +++ b/etc/docker-compose.yml @@ -46,7 +46,7 @@ services: grafana: restart: unless-stopped - image: grafana/grafana:10.3.3 + image: grafana/grafana:latest depends_on: - reth - prometheus diff --git a/etc/grafana/dashboards/reth-mempool.json b/etc/grafana/dashboards/reth-mempool.json index f93276e509..092faaccb8 100644 --- a/etc/grafana/dashboards/reth-mempool.json +++ b/etc/grafana/dashboards/reth-mempool.json @@ -1458,7 +1458,7 @@ "uid": "${DS_PROMETHEUS}" }, "editorMode": "builder", - "expr": "rate(reth_network_pool_transactions_messages_sent_total{instance=~\"$instance\"}[$__rate_interval])", + "expr": "rate(reth_network_pool_transactions_messages_sent{instance=~\"$instance\"}[$__rate_interval])", "hide": false, "instant": false, "legendFormat": "Tx", @@ -1471,7 +1471,7 @@ "uid": "${DS_PROMETHEUS}" }, "editorMode": "builder", - "expr": "rate(reth_network_pool_transactions_messages_received_total{instance=~\"$instance\"}[$__rate_interval])", + "expr": "rate(reth_network_pool_transactions_messages_received{instance=~\"$instance\"}[$__rate_interval])", "hide": false, "legendFormat": "Rx", "range": true, @@ -1483,7 +1483,7 @@ "uid": "${DS_PROMETHEUS}" }, "editorMode": "code", - "expr": "reth_network_pool_transactions_messages_sent_total{instance=~\"$instance\"} - reth_network_pool_transactions_messages_received_total{instance=~\"$instance\"}", + "expr": "reth_network_pool_transactions_messages_sent{instance=~\"$instance\"} - reth_network_pool_transactions_messages_received{instance=~\"$instance\"}", "hide": false, "legendFormat": "Messages in Channel", "range": true, diff --git a/examples/custom-evm/src/main.rs b/examples/custom-evm/src/main.rs index bda16fbdd8..b6743d62dd 100644 --- a/examples/custom-evm/src/main.rs +++ b/examples/custom-evm/src/main.rs @@ -12,7 +12,7 @@ use reth::{ revm::{ handler::register::EvmHandler, inspector_handle_register, - precompile::{Precompile, PrecompileSpecId, Precompiles}, + precompile::{Precompile, PrecompileOutput, PrecompileSpecId, Precompiles}, Database, Evm, EvmBuilder, GetInspector, }, tasks::TaskManager, @@ -56,7 +56,7 @@ impl MyEvmConfig { /// A custom precompile that does nothing fn my_precompile(_data: &Bytes, _gas: u64, _env: &Env) -> PrecompileResult { - Ok((0, Bytes::new())) + Ok(PrecompileOutput::new(0, Bytes::new())) } }