diff --git a/Cargo.lock b/Cargo.lock index 95a570376bef..085ce63a929a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -121,9 +121,9 @@ dependencies = [ [[package]] name = "alloy-consensus" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d802a6d579d924a2926d181bce43231aaab4699a7c206197e88fbc6b9dda846f" +checksum = "f4138dc275554afa6f18c4217262ac9388790b2fc393c2dfe03c51d357abf013" dependencies = [ "alloy-eips", "alloy-primitives", @@ -155,9 +155,9 @@ dependencies = [ [[package]] name = "alloy-contract" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e56bc4dc06ab205dc4106348c44b92e0d979148f8db751994c11caabf5ebbef" +checksum = "5f21886c1fea0626f755a49b2ac653b396fb345233f6170db2da3d0ada31560c" dependencies = [ "alloy-dyn-abi", "alloy-json-abi", @@ -191,6 +191,21 @@ dependencies = [ "winnow", ] +[[package]] +name = "alloy-eip2124" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "675264c957689f0fd75f5993a73123c2cc3b5c235a38f5b9037fe6c826bfb2c0" +dependencies = [ + "alloy-primitives", + "alloy-rlp", + "arbitrary", + "crc", + "rand 0.8.5", + "serde", + "thiserror 2.0.9", +] + [[package]] name = "alloy-eip2930" version = "0.1.0" @@ -222,9 +237,9 @@ dependencies = [ [[package]] name = "alloy-eips" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "938bc1cf2ec42579e187834efc254e76dd3fa19f526b57872713e6b95f411305" +checksum = "52dd5869ed09e399003e0e0ec6903d981b2a92e74c5d37e6b40890bad2517526" dependencies = [ "alloy-eip2930", "alloy-eip7702", @@ -243,9 +258,9 @@ dependencies = [ [[package]] name = "alloy-genesis" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b648eac186485ead3da160985b929e610a45eb39903f750da9b35f58a91eef52" +checksum = "e7d2a7fe5c1a9bd6793829ea21a636f30fc2b3f5d2e7418ba86d96e41dd1f460" dependencies = [ "alloy-eips", "alloy-primitives", @@ -268,9 +283,9 @@ dependencies = [ [[package]] name = "alloy-json-rpc" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1a38b4b49667a84ecad7cdaf431b8bd3f14ca496e5a021df1c26d5c4595dca6" +checksum = "2008bedb8159a255b46b7c8614516eda06679ea82f620913679afbd8031fea72" dependencies = [ "alloy-primitives", "alloy-sol-types", @@ -282,9 +297,9 @@ dependencies = [ [[package]] name = "alloy-network" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb5dc326960e88eec6b5e9add221a071f15cb8fa93b9e88ee9c76cd0e4e1009" +checksum = "4556f01fe41d0677495df10a648ddcf7ce118b0e8aa9642a0e2b6dd1fb7259de" dependencies = [ "alloy-consensus", "alloy-consensus-any", @@ -307,9 +322,9 @@ dependencies = [ [[package]] name = "alloy-network-primitives" -version = "0.9.0" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1535a4577648ec2fd3c446d4644d9b8e9e01e5816be53a5d515dc1624e2227b2" +checksum = "f31c3c6b71340a1d076831823f09cb6e02de01de5c6630a9631bdb36f947ff80" dependencies = [ "alloy-consensus", "alloy-eips", @@ -320,9 +335,9 @@ dependencies = [ [[package]] name = "alloy-node-bindings" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5af000a8d9aa22694c92a5c6ebd9113495d2eb78fb3579d02a715569b973cc26" +checksum = "4520cd4bc5cec20c32c98e4bc38914c7fb96bf4a712105e44da186a54e65e3ba" dependencies = [ "alloy-genesis", "alloy-primitives", @@ -369,9 +384,9 @@ dependencies = [ [[package]] name = "alloy-provider" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a9d6ef38d75e4b0dce6737463099698f9b839d1c3f7c8883bfdfce8954374b" +checksum = "5a22c4441b3ebe2d77fa9cf629ba68c3f713eb91779cff84275393db97eddd82" dependencies = [ "alloy-chains", "alloy-consensus", @@ -410,9 +425,9 @@ dependencies = [ [[package]] name = "alloy-pubsub" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1be3b30bab565198a1bda090915dd165ca9211154eb0b37d046a22829418dcc0" +checksum = "2269fd635f7b505f27c63a3cb293148cd02301efce4c8bdd9ff54fbfc4a20e23" dependencies = [ "alloy-json-rpc", "alloy-primitives", @@ -451,9 +466,9 @@ dependencies = [ [[package]] name = "alloy-rpc-client" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5ed1e9957edfc8d155e2610e2ff3e10b059b89a6103de9f01579f40d8926d47" +checksum = "d06a292b37e182e514903ede6e623b9de96420e8109ce300da288a96d88b7e4b" dependencies = [ "alloy-json-rpc", "alloy-primitives", @@ -476,9 +491,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "206749723862bd27d5468270e30fc987c5b4376240aefee728d7e64282c9d146" +checksum = "9383845dd924939e7ab0298bbfe231505e20928907d7905aa3bf112287305e06" dependencies = [ "alloy-primitives", "alloy-rpc-types-engine", @@ -489,9 +504,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-admin" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d28cffc71031a68519d302efca15ada5657fed9ca5f504c19a3112c7b2168252" +checksum = "b0fcea70b3872c645fa0ee7fb23370d685f98e8c35f47297de619fb2e9f607ff" dependencies = [ "alloy-genesis", "alloy-primitives", @@ -501,9 +516,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-anvil" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ac98a9d17ec4d851ea38e556c27b92e1ff8c97664cf1feb77aec38dcba34579" +checksum = "11495cb8c8d3141fc27556a4c9188b81531ad5ec3076a0394c61a6dcfbce9f34" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", @@ -524,9 +539,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-beacon" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e59d76349c11aa7fac9aadeceb65cf31d3f3430b407159b172b39d36ccb0671a" +checksum = "4009405b1d3f5e8c529b8cf353f74e815fd2102549af4172fc721b4b9ea09133" dependencies = [ "alloy-eips", "alloy-primitives", @@ -540,9 +555,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-debug" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d72085173d210806a27892eb72770a663f5b0c17598e37f18c6bb24f7583c3c" +checksum = "358d6a8d7340b9eb1a7589a6c1fb00df2c9b26e90737fa5ed0108724dd8dac2c" dependencies = [ "alloy-primitives", "serde", @@ -550,9 +565,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-engine" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee96e9793d3ec528ead6e8580f24e9acc71f5c2bc35feefba24465044bb77d76" +checksum = "4a5f821f30344862a0b6eb9a1c2eb91dfb2ff44c7489f37152a526cdcab79264" dependencies = [ "alloy-consensus", "alloy-eips", @@ -571,9 +586,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-eth" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "319a0ca31863bd6fb9aafeaa16425d0a2f1228da44bc24fd2f997ba50afe7e18" +checksum = "0938bc615c02421bd86c1733ca7205cc3d99a122d9f9bff05726bd604b76a5c2" dependencies = [ "alloy-consensus", "alloy-consensus-any", @@ -593,9 +608,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-mev" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06fb874d3c1bd11f34acbf508c38409693a443ec5e18afd6bc34a7ee9a606e88" +checksum = "06bd42cf54b8a05b596322267f396a7dbdf141a56e93502a2ab4464fb718467a" dependencies = [ "alloy-eips", "alloy-primitives", @@ -607,9 +622,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-trace" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af2769894024f65ba252618e06a0ca22fc025377ade6d60d7f47a83ac9559680" +checksum = "cd38207e056cc7d1372367fbb4560ddf9107cbd20731743f641246bf0dede149" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", @@ -621,9 +636,9 @@ dependencies = [ [[package]] name = "alloy-rpc-types-txpool" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69bfa0d7934827098cd386965a796e7765485dc86c6ae03cda262ad9ccb30e01" +checksum = "b7fd456a3fa9ea732d1c0611c9d52b5326ee29f4d02d01b07dac453ed68d9eb5" dependencies = [ "alloy-primitives", "alloy-rpc-types-eth", @@ -633,9 +648,9 @@ dependencies = [ [[package]] name = "alloy-serde" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81537867986734e5867a9131145bdc56301f5b37ef9c9fb4654d7f7691a4015d" +checksum = "ae0465c71d4dced7525f408d84873aeebb71faf807d22d74c4a426430ccd9b55" dependencies = [ "alloy-primitives", "arbitrary", @@ -645,9 +660,9 @@ dependencies = [ [[package]] name = "alloy-signer" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fdcbfe7079c877b3cb6ec43017e94f66432480f1c1779f736c064e6a8d422cc" +checksum = "9bfa395ad5cc952c82358d31e4c68b27bf4a89a5456d9b27e226e77dac50e4ff" dependencies = [ "alloy-primitives", "async-trait", @@ -659,9 +674,9 @@ dependencies = [ [[package]] name = "alloy-signer-local" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f5175bd063463e25f1ffc6daaa223db15baf4b18e3d83d0d31fb95756aab6cc" +checksum = "fbdc63ce9eda1283fcbaca66ba4a414b841c0e3edbeef9c86a71242fc9e84ccc" dependencies = [ "alloy-consensus", "alloy-network", @@ -747,9 +762,9 @@ dependencies = [ [[package]] name = "alloy-transport" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6121c7a8791d7984bd3e1a487aae55c62358b0bd94330126db41d795d942e24e" +checksum = "d17722a198f33bbd25337660787aea8b8f57814febb7c746bc30407bdfc39448" dependencies = [ "alloy-json-rpc", "base64 0.22.1", @@ -767,9 +782,9 @@ dependencies = [ [[package]] name = "alloy-transport-http" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15487cd2d7f2bfd8546e851d80db470603c2a1de82f7c39403078356b20d9a21" +checksum = "6e1509599021330a31c4a6816b655e34bf67acb1cc03c564e09fd8754ff6c5de" dependencies = [ "alloy-json-rpc", "alloy-transport", @@ -782,9 +797,9 @@ dependencies = [ [[package]] name = "alloy-transport-ipc" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a74511d4703f571c2b4da85458b5634855d97e10a94407c05d97b2052ed5450b" +checksum = "fa4da44bc9a5155ab599666d26decafcf12204b72a80eeaba7c5e234ee8ac205" dependencies = [ "alloy-json-rpc", "alloy-pubsub", @@ -801,9 +816,9 @@ dependencies = [ [[package]] name = "alloy-transport-ws" -version = "0.9.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f812a1f1ae7955964727d3040bf240955ca324d80383b9dd0ab21a6de3007386" +checksum = "58011745b2f17b334db40df9077d75b181f78360a5bc5c35519e15d4bfce15e2" dependencies = [ "alloy-pubsub", "alloy-transport", @@ -1933,7 +1948,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" dependencies = [ "lazy_static", - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] @@ -2781,7 +2796,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -4669,7 +4684,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] @@ -6151,7 +6166,7 @@ dependencies = [ "once_cell", "socket2", "tracing", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -7552,19 +7567,14 @@ name = "reth-ethereum-forks" version = "1.1.4" dependencies = [ "alloy-chains", - "alloy-consensus", + "alloy-eip2124", "alloy-primitives", - "alloy-rlp", "arbitrary", "auto_impl", - "crc", "dyn-clone", "once_cell", - "proptest", - "proptest-derive", "rustc-hash 2.1.0", "serde", - "thiserror 2.0.9", ] [[package]] @@ -8702,7 +8712,6 @@ dependencies = [ "reth-chainspec", "reth-primitives", "reth-primitives-traits", - "reth-rpc-types-compat", ] [[package]] @@ -8773,6 +8782,7 @@ dependencies = [ "proptest", "proptest-arbitrary-interop", "rand 0.8.5", + "rayon", "reth-codecs", "revm-primitives", "secp256k1", @@ -9227,7 +9237,6 @@ dependencies = [ "alloy-consensus", "alloy-eips", "alloy-primitives", - "alloy-rlp", "alloy-rpc-types-engine", "alloy-rpc-types-eth", "jsonrpsee-types", @@ -9972,7 +9981,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -10821,7 +10830,7 @@ dependencies = [ "fastrand 2.3.0", "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -11390,7 +11399,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69fff37da548239c3bf9e64a12193d261e8b22b660991c6fd2df057c168f435f" dependencies = [ "cc", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] @@ -11825,7 +11834,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 05cd7ee96cc8..66ddec61ccc3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -434,6 +434,7 @@ revm-inspectors = "0.14.1" # eth alloy-chains = { version = "0.1.32", default-features = false } alloy-dyn-abi = "0.8.15" +alloy-eip2124 = { version = "0.1.0", default-features = false } alloy-primitives = { version = "0.8.15", default-features = false, features = [ "map-foldhash", ] } @@ -441,40 +442,40 @@ alloy-rlp = { version = "0.3.10", default-features = false } alloy-sol-types = "0.8.15" alloy-trie = { version = "0.7", default-features = false } -alloy-consensus = { version = "0.9.1", default-features = false } -alloy-contract = { version = "0.9.1", default-features = false } -alloy-eips = { version = "0.9.1", default-features = false } -alloy-genesis = { version = "0.9.1", default-features = false } -alloy-json-rpc = { version = "0.9.1", default-features = false } -alloy-network = { version = "0.9.1", default-features = false } -alloy-network-primitives = { version = "0.9.1", default-features = false } -alloy-node-bindings = { version = "0.9.1", default-features = false } -alloy-provider = { version = "0.9.1", features = [ +alloy-consensus = { version = "0.9.2", default-features = false } +alloy-contract = { version = "0.9.2", default-features = false } +alloy-eips = { version = "0.9.2", default-features = false } +alloy-genesis = { version = "0.9.2", default-features = false } +alloy-json-rpc = { version = "0.9.2", default-features = false } +alloy-network = { version = "0.9.2", default-features = false } +alloy-network-primitives = { version = "0.9.2", default-features = false } +alloy-node-bindings = { version = "0.9.2", default-features = false } +alloy-provider = { version = "0.9.2", features = [ "reqwest", ], default-features = false } -alloy-pubsub = { version = "0.9.1", default-features = false } -alloy-rpc-client = { version = "0.9.1", default-features = false } -alloy-rpc-types = { version = "0.9.1", features = [ +alloy-pubsub = { version = "0.9.2", default-features = false } +alloy-rpc-client = { version = "0.9.2", default-features = false } +alloy-rpc-types = { version = "0.9.2", features = [ "eth", ], default-features = false } -alloy-rpc-types-admin = { version = "0.9.1", default-features = false } -alloy-rpc-types-anvil = { version = "0.9.1", default-features = false } -alloy-rpc-types-beacon = { version = "0.9.1", default-features = false } -alloy-rpc-types-debug = { version = "0.9.1", default-features = false } -alloy-rpc-types-engine = { version = "0.9.1", default-features = false } -alloy-rpc-types-eth = { version = "0.9.1", default-features = false } -alloy-rpc-types-mev = { version = "0.9.1", default-features = false } -alloy-rpc-types-trace = { version = "0.9.1", default-features = false } -alloy-rpc-types-txpool = { version = "0.9.1", default-features = false } -alloy-serde = { version = "0.9.1", default-features = false } -alloy-signer = { version = "0.9.1", default-features = false } -alloy-signer-local = { version = "0.9.1", default-features = false } -alloy-transport = { version = "0.9.1" } -alloy-transport-http = { version = "0.9.1", features = [ +alloy-rpc-types-admin = { version = "0.9.2", default-features = false } +alloy-rpc-types-anvil = { version = "0.9.2", default-features = false } +alloy-rpc-types-beacon = { version = "0.9.2", default-features = false } +alloy-rpc-types-debug = { version = "0.9.2", default-features = false } +alloy-rpc-types-engine = { version = "0.9.2", default-features = false } +alloy-rpc-types-eth = { version = "0.9.2", default-features = false } +alloy-rpc-types-mev = { version = "0.9.2", default-features = false } +alloy-rpc-types-trace = { version = "0.9.2", default-features = false } +alloy-rpc-types-txpool = { version = "0.9.2", default-features = false } +alloy-serde = { version = "0.9.2", default-features = false } +alloy-signer = { version = "0.9.2", default-features = false } +alloy-signer-local = { version = "0.9.2", default-features = false } +alloy-transport = { version = "0.9.2" } +alloy-transport-http = { version = "0.9.2", features = [ "reqwest-rustls-tls", ], default-features = false } -alloy-transport-ipc = { version = "0.9.1", default-features = false } -alloy-transport-ws = { version = "0.9.1", default-features = false } +alloy-transport-ipc = { version = "0.9.2", default-features = false } +alloy-transport-ws = { version = "0.9.2", default-features = false } # op op-alloy-rpc-types = { version = "0.9.0", default-features = false } diff --git a/LICENSE-MIT b/LICENSE-MIT index 23dead2c53f8..f7448381d492 100644 --- a/LICENSE-MIT +++ b/LICENSE-MIT @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2022-2024 Reth Contributors +Copyright (c) 2022-2025 Reth Contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/bin/reth-bench/src/bench/new_payload_fcu.rs b/bin/reth-bench/src/bench/new_payload_fcu.rs index baa940437e1d..e3d388b37ece 100644 --- a/bin/reth-bench/src/bench/new_payload_fcu.rs +++ b/bin/reth-bench/src/bench/new_payload_fcu.rs @@ -78,7 +78,7 @@ impl Command { let block_number = block.header.number; let versioned_hashes: Vec = - block.body.blob_versioned_hashes_iter().copied().collect(); + block.body().blob_versioned_hashes_iter().copied().collect(); let parent_beacon_block_root = block.parent_beacon_block_root; let payload = block_to_payload(block).0; diff --git a/bin/reth-bench/src/bench/new_payload_only.rs b/bin/reth-bench/src/bench/new_payload_only.rs index 020164109c22..4485e3fa79ec 100644 --- a/bin/reth-bench/src/bench/new_payload_only.rs +++ b/bin/reth-bench/src/bench/new_payload_only.rs @@ -62,7 +62,7 @@ impl Command { let gas_used = block.gas_used; let versioned_hashes: Vec = - block.body.blob_versioned_hashes_iter().copied().collect(); + block.body().blob_versioned_hashes_iter().copied().collect(); let parent_beacon_block_root = block.parent_beacon_block_root; let payload = block_to_payload(block).0; diff --git a/book/sources/exex/tracking-state/src/bin/2.rs b/book/sources/exex/tracking-state/src/bin/2.rs index 7e9aadf8a04f..44b023967a8c 100644 --- a/book/sources/exex/tracking-state/src/bin/2.rs +++ b/book/sources/exex/tracking-state/src/bin/2.rs @@ -36,7 +36,7 @@ impl>> Fut while let Some(notification) = ready!(this.ctx.notifications.try_next().poll_unpin(cx))? { if let Some(reverted_chain) = notification.reverted_chain() { this.transactions = this.transactions.saturating_sub( - reverted_chain.blocks_iter().map(|b| b.body.transactions.len() as u64).sum(), + reverted_chain.blocks_iter().map(|b| b.body().transactions.len() as u64).sum(), ); } @@ -45,7 +45,7 @@ impl>> Fut this.transactions += committed_chain .blocks_iter() - .map(|b| b.body.transactions.len() as u64) + .map(|b| b.body().transactions.len() as u64) .sum::(); this.ctx diff --git a/crates/blockchain-tree-api/src/error.rs b/crates/blockchain-tree-api/src/error.rs index 2fa5eeb20149..ddd7cea7993c 100644 --- a/crates/blockchain-tree-api/src/error.rs +++ b/crates/blockchain-tree-api/src/error.rs @@ -206,7 +206,7 @@ impl std::fmt::Debug for InsertBlockErrorDataTwo { .field("hash", &self.block.hash()) .field("number", &self.block.number()) .field("parent_hash", &self.block.parent_hash()) - .field("num_txs", &self.block.body.transactions().len()) + .field("num_txs", &self.block.body().transactions().len()) .finish_non_exhaustive() } } diff --git a/crates/blockchain-tree/src/block_indices.rs b/crates/blockchain-tree/src/block_indices.rs index 7778fb9262c5..26a676f4d36c 100644 --- a/crates/blockchain-tree/src/block_indices.rs +++ b/crates/blockchain-tree/src/block_indices.rs @@ -572,23 +572,23 @@ mod tests { // Define blocks with their numbers and parent hashes. let block_1 = SealedBlockWithSenders { - block: SealedBlock { - header: SealedHeader::new( + block: SealedBlock::new( + SealedHeader::new( Header { parent_hash, number: 1, ..Default::default() }, block_hash_1, ), - ..Default::default() - }, + Default::default(), + ), ..Default::default() }; let block_2 = SealedBlockWithSenders { - block: SealedBlock { - header: SealedHeader::new( + block: SealedBlock::new( + SealedHeader::new( Header { parent_hash: block_hash_1, number: 2, ..Default::default() }, block_hash_2, ), - ..Default::default() - }, + Default::default(), + ), ..Default::default() }; diff --git a/crates/blockchain-tree/src/blockchain_tree.rs b/crates/blockchain-tree/src/blockchain_tree.rs index e2d96c289831..b436c0dee350 100644 --- a/crates/blockchain-tree/src/blockchain_tree.rs +++ b/crates/blockchain-tree/src/blockchain_tree.rs @@ -1635,14 +1635,14 @@ mod tests { }; SealedBlockWithSenders::new( - SealedBlock { - header: SealedHeader::seal(header), - body: BlockBody { + SealedBlock::new( + SealedHeader::seal(header), + BlockBody { transactions: signed_body, ommers: Vec::new(), withdrawals: Some(Withdrawals::default()), }, - }, + ), body.iter().map(|tx| tx.signer()).collect(), ) .unwrap() diff --git a/crates/chain-state/src/in_memory.rs b/crates/chain-state/src/in_memory.rs index 41d653ba07c3..06d228a8f82e 100644 --- a/crates/chain-state/src/in_memory.rs +++ b/crates/chain-state/src/in_memory.rs @@ -4,7 +4,7 @@ use crate::{ CanonStateNotification, CanonStateNotificationSender, CanonStateNotifications, ChainInfoTracker, MemoryOverlayStateProvider, }; -use alloy_consensus::BlockHeader; +use alloy_consensus::{transaction::TransactionMeta, BlockHeader}; use alloy_eips::{eip2718::Encodable2718, BlockHashOrNumber, BlockNumHash}; use alloy_primitives::{map::HashMap, Address, TxHash, B256}; use parking_lot::RwLock; @@ -13,12 +13,12 @@ use reth_execution_types::{Chain, ExecutionOutcome}; use reth_metrics::{metrics::Gauge, Metrics}; use reth_primitives::{ BlockWithSenders, EthPrimitives, NodePrimitives, Receipts, SealedBlock, SealedBlockFor, - SealedBlockWithSenders, SealedHeader, TransactionMeta, + SealedBlockWithSenders, SealedHeader, }; use reth_primitives_traits::{Block, BlockBody as _, SignedTransaction}; use reth_storage_api::StateProviderBox; use reth_trie::{updates::TrieUpdates, HashedPostState}; -use std::{collections::BTreeMap, sync::Arc, time::Instant}; +use std::{collections::BTreeMap, ops::Deref, sync::Arc, time::Instant}; use tokio::sync::{broadcast, watch}; /// Size of the broadcast channel used to notify canonical state events. @@ -183,7 +183,7 @@ impl CanonicalInMemoryState { let in_memory_state = InMemoryState::new(blocks, numbers, pending); let header = in_memory_state .head_state() - .map_or_else(SealedHeader::default, |state| state.block_ref().block().header.clone()); + .map_or_else(SealedHeader::default, |state| state.block_ref().block().deref().clone()); let chain_info_tracker = ChainInfoTracker::new(header, finalized, safe); let (canon_state_notification_sender, _) = broadcast::channel(CANON_STATE_NOTIFICATION_CHANNEL_SIZE); @@ -462,7 +462,7 @@ impl CanonicalInMemoryState { /// Returns the `SealedHeader` corresponding to the pending state. pub fn pending_sealed_header(&self) -> Option> { - self.pending_state().map(|h| h.block_ref().block().header.clone()) + self.pending_state().map(|h| h.block_ref().block().deref().clone()) } /// Returns the `Header` corresponding to the pending state. @@ -549,7 +549,7 @@ impl CanonicalInMemoryState { if let Some(tx) = block_state .block_ref() .block() - .body + .body() .transactions() .iter() .find(|tx| tx.trie_hash() == hash) @@ -573,7 +573,7 @@ impl CanonicalInMemoryState { if let Some((index, tx)) = block_state .block_ref() .block() - .body + .body() .transactions() .iter() .enumerate() @@ -584,7 +584,7 @@ impl CanonicalInMemoryState { index: index as u64, block_hash: block_state.hash(), block_number: block_state.block_ref().block.number(), - base_fee: block_state.block_ref().block.header.base_fee_per_gas(), + base_fee: block_state.block_ref().block.base_fee_per_gas(), timestamp: block_state.block_ref().block.timestamp(), excess_blob_gas: block_state.block_ref().block.excess_blob_gas(), }; @@ -664,7 +664,7 @@ impl BlockState { /// Returns the state root after applying the executed block that determines /// the state. pub fn state_root(&self) -> B256 { - self.block.block().header.state_root() + self.block.block().state_root() } /// Returns the `Receipts` of executed block that determines the state. @@ -758,7 +758,7 @@ impl BlockState { block_state .block_ref() .block() - .body + .body() .transactions() .iter() .find(|tx| tx.trie_hash() == hash) @@ -778,7 +778,7 @@ impl BlockState { block_state .block_ref() .block() - .body + .body() .transactions() .iter() .enumerate() @@ -789,7 +789,7 @@ impl BlockState { index: index as u64, block_hash: block_state.hash(), block_number: block_state.block_ref().block.number(), - base_fee: block_state.block_ref().block.header.base_fee_per_gas(), + base_fee: block_state.block_ref().block.base_fee_per_gas(), timestamp: block_state.block_ref().block.timestamp(), excess_blob_gas: block_state.block_ref().block.excess_blob_gas(), }; @@ -1318,7 +1318,7 @@ mod tests { ); // Check the pending header - assert_eq!(state.pending_header().unwrap(), block2.block().header.header().clone()); + assert_eq!(state.pending_header().unwrap(), block2.block().header().clone()); // Check the pending sealed header assert_eq!(state.pending_sealed_header().unwrap(), block2.block().header.clone()); diff --git a/crates/chain-state/src/notifications.rs b/crates/chain-state/src/notifications.rs index 498528813d66..ab2b88cba107 100644 --- a/crates/chain-state/src/notifications.rs +++ b/crates/chain-state/src/notifications.rs @@ -214,9 +214,10 @@ impl Stream for ForkChoiceStream { #[cfg(test)] mod tests { use super::*; + use alloy_consensus::BlockBody; use alloy_primitives::{b256, B256}; use reth_execution_types::ExecutionOutcome; - use reth_primitives::{Receipt, Receipts, TransactionSigned, TxType}; + use reth_primitives::{Receipt, Receipts, SealedBlock, TransactionSigned, TxType}; #[test] fn test_commit_notification() { @@ -295,7 +296,7 @@ mod tests { #[test] fn test_block_receipts_commit() { // Create a default block instance for use in block definitions. - let block: SealedBlockWithSenders = Default::default(); + let mut body = BlockBody::::default(); // Define unique hashes for two blocks to differentiate them in the chain. let block1_hash = B256::new([0x01; 32]); @@ -303,13 +304,17 @@ mod tests { // Create a default transaction to include in block1's transactions. let tx = TransactionSigned::default(); + body.transactions.push(tx); + + let block: SealedBlockWithSenders = + SealedBlock::new(SealedHeader::seal(alloy_consensus::Header::default()), body) + .seal_with_senders() + .unwrap(); // Create a clone of the default block and customize it to act as block1. let mut block1 = block.clone(); block1.set_block_number(1); block1.set_hash(block1_hash); - // Add the transaction to block1's transactions. - block1.block.body.transactions.push(tx); // Clone the default block and customize it to act as block2. let mut block2 = block; @@ -365,10 +370,14 @@ mod tests { #[test] fn test_block_receipts_reorg() { // Define block1 for the old chain segment, which will be reverted. - let mut old_block1: SealedBlockWithSenders = Default::default(); + let mut body = BlockBody::::default(); + body.transactions.push(TransactionSigned::default()); + let mut old_block1: SealedBlockWithSenders = + SealedBlock::new(SealedHeader::seal(alloy_consensus::Header::default()), body) + .seal_with_senders() + .unwrap(); old_block1.set_block_number(1); old_block1.set_hash(B256::new([0x01; 32])); - old_block1.block.body.transactions.push(TransactionSigned::default()); // Create a receipt for a transaction in the reverted block. #[allow(clippy::needless_update)] @@ -389,10 +398,14 @@ mod tests { Arc::new(Chain::new(vec![old_block1.clone()], old_execution_outcome, None)); // Define block2 for the new chain segment, which will be committed. - let mut new_block1: SealedBlockWithSenders = Default::default(); + let mut body = BlockBody::::default(); + body.transactions.push(TransactionSigned::default()); + let mut new_block1: SealedBlockWithSenders = + SealedBlock::new(SealedHeader::seal(alloy_consensus::Header::default()), body) + .seal_with_senders() + .unwrap(); new_block1.set_block_number(2); new_block1.set_hash(B256::new([0x02; 32])); - new_block1.block.body.transactions.push(TransactionSigned::default()); // Create a receipt for a transaction in the new committed block. #[allow(clippy::needless_update)] diff --git a/crates/chain-state/src/test_utils.rs b/crates/chain-state/src/test_utils.rs index 977b92bf057c..292c21e54008 100644 --- a/crates/chain-state/src/test_utils.rs +++ b/crates/chain-state/src/test_utils.rs @@ -168,14 +168,14 @@ impl TestBlockBuilder { ..Default::default() }; - let block = SealedBlock { - header: SealedHeader::seal(header), - body: BlockBody { + let block = SealedBlock::new( + SealedHeader::seal(header), + BlockBody { transactions: transactions.into_iter().map(|tx| tx.into_signed()).collect(), ommers: Vec::new(), withdrawals: Some(vec![].into()), }, - }; + ); SealedBlockWithSenders::new(block, vec![self.signer; num_txs as usize]).unwrap() } @@ -259,7 +259,7 @@ impl TestBlockBuilder { /// updated. pub fn get_execution_outcome(&mut self, block: SealedBlockWithSenders) -> ExecutionOutcome { let receipts = block - .body + .body() .transactions .iter() .enumerate() @@ -273,7 +273,7 @@ impl TestBlockBuilder { let mut bundle_state_builder = BundleState::builder(block.number..=block.number); - for tx in &block.body.transactions { + for tx in &block.body().transactions { self.signer_execute_account_info.balance -= Self::single_tx_cost(); bundle_state_builder = bundle_state_builder.state_present_account_info( self.signer, diff --git a/crates/consensus/beacon/src/engine/mod.rs b/crates/consensus/beacon/src/engine/mod.rs index 9ff0b9cd8c81..2dc139acedb4 100644 --- a/crates/consensus/beacon/src/engine/mod.rs +++ b/crates/consensus/beacon/src/engine/mod.rs @@ -2774,8 +2774,7 @@ mod tests { .with_real_consensus() .build(); - let genesis = - SealedBlock { header: chain_spec.sealed_genesis_header(), ..Default::default() }; + let genesis = SealedBlock::new(chain_spec.sealed_genesis_header(), Default::default()); let block1 = random_block( &mut rng, 1, diff --git a/crates/consensus/common/src/validation.rs b/crates/consensus/common/src/validation.rs index a53500412dad..8754fe818520 100644 --- a/crates/consensus/common/src/validation.rs +++ b/crates/consensus/common/src/validation.rs @@ -42,7 +42,7 @@ pub fn validate_header_base_fee( pub fn validate_shanghai_withdrawals( block: &SealedBlock, ) -> Result<(), ConsensusError> { - let withdrawals = block.body.withdrawals().ok_or(ConsensusError::BodyWithdrawalsMissing)?; + let withdrawals = block.body().withdrawals().ok_or(ConsensusError::BodyWithdrawalsMissing)?; let withdrawals_root = alloy_consensus::proofs::calculate_withdrawals_root(withdrawals); let header_withdrawals_root = block.withdrawals_root().ok_or(ConsensusError::WithdrawalsRootMissing)?; @@ -67,7 +67,7 @@ pub fn validate_cancun_gas( // blob tx let header_blob_gas_used = block.header().blob_gas_used().ok_or(ConsensusError::BlobGasUsedMissing)?; - let total_blob_gas = block.body.blob_gas_used(); + let total_blob_gas = block.body().blob_gas_used(); if total_blob_gas != header_blob_gas_used { return Err(ConsensusError::BlobGasUsedDiff(GotExpected { got: header_blob_gas_used, @@ -139,12 +139,12 @@ where ChainSpec: EthereumHardforks, { // Check ommers hash - let ommers_hash = block.body.calculate_ommers_root(); - if Some(block.header.ommers_hash()) != ommers_hash { + let ommers_hash = block.body().calculate_ommers_root(); + if Some(block.ommers_hash()) != ommers_hash { return Err(ConsensusError::BodyOmmersHashDiff( GotExpected { got: ommers_hash.unwrap_or(EMPTY_OMMER_ROOT_HASH), - expected: block.header.ommers_hash(), + expected: block.ommers_hash(), } .into(), )) @@ -514,10 +514,10 @@ mod tests { let transactions = Vec::new(); ( - SealedBlock { - header: SealedHeader::seal(header), - body: BlockBody { transactions, ommers, withdrawals: None }, - }, + SealedBlock::new( + SealedHeader::seal(header), + BlockBody { transactions, ommers, withdrawals: None }, + ), parent, ) } @@ -539,10 +539,10 @@ mod tests { ..Default::default() }; - SealedBlock { - header: SealedHeader::seal(header), - body: BlockBody { withdrawals: Some(withdrawals), ..Default::default() }, - } + SealedBlock::new( + SealedHeader::seal(header), + BlockBody { withdrawals: Some(withdrawals), ..Default::default() }, + ) }; // Single withdrawal diff --git a/crates/e2e-test-utils/src/payload.rs b/crates/e2e-test-utils/src/payload.rs index 1f2df9e072f2..858e311cacb2 100644 --- a/crates/e2e-test-utils/src/payload.rs +++ b/crates/e2e-test-utils/src/payload.rs @@ -58,7 +58,7 @@ impl PayloadTestContext { pub async fn wait_for_built_payload(&self, payload_id: PayloadId) { loop { let payload = self.payload_builder.best_payload(payload_id).await.unwrap().unwrap(); - if payload.block().body.transactions().is_empty() { + if payload.block().body().transactions().is_empty() { tokio::time::sleep(std::time::Duration::from_millis(20)).await; continue } diff --git a/crates/engine/util/src/reorg.rs b/crates/engine/util/src/reorg.rs index 38683e206e37..073f83545ab6 100644 --- a/crates/engine/util/src/reorg.rs +++ b/crates/engine/util/src/reorg.rs @@ -269,7 +269,7 @@ where // Fetch reorg target block depending on its depth and its parent. let mut previous_hash = next_block.parent_hash; - let mut candidate_transactions = next_block.body.transactions; + let mut candidate_transactions = next_block.into_body().transactions; let reorg_target = 'target: { loop { let reorg_target = provider diff --git a/crates/ethereum-forks/Cargo.toml b/crates/ethereum-forks/Cargo.toml index 1a08498633c4..2d65949df452 100644 --- a/crates/ethereum-forks/Cargo.toml +++ b/crates/ethereum-forks/Cargo.toml @@ -14,53 +14,42 @@ workspace = true [dependencies] # ethereum alloy-chains.workspace = true +alloy-eip2124.workspace = true alloy-primitives = { workspace = true, features = ["serde", "rlp"] } -alloy-rlp = { workspace = true, features = ["arrayvec", "derive"] } once_cell.workspace = true -# used for forkid -crc = "3" - # misc serde = { workspace = true, features = ["derive"], optional = true } -thiserror.workspace = true dyn-clone.workspace = true rustc-hash = { workspace = true, optional = true } # arbitrary utils arbitrary = { workspace = true, features = ["derive"], optional = true } -proptest = { workspace = true, optional = true } -proptest-derive = { workspace = true, optional = true } auto_impl.workspace = true [dev-dependencies] arbitrary = { workspace = true, features = ["derive"] } -alloy-consensus.workspace = true [features] default = ["std", "serde", "rustc-hash"] arbitrary = [ "dep:arbitrary", - "dep:proptest", - "dep:proptest-derive", "alloy-chains/arbitrary", - "alloy-consensus/arbitrary", - "alloy-primitives/arbitrary" + "alloy-primitives/arbitrary", + "alloy-eip2124/arbitrary" ] serde = [ "dep:serde", "alloy-chains/serde", - "alloy-consensus/serde", - "alloy-primitives/serde" + "alloy-primitives/serde", + "alloy-eip2124/serde" ] std = [ "alloy-chains/std", "alloy-primitives/std", - "thiserror/std", "rustc-hash/std", - "alloy-consensus/std", "once_cell/std", "serde?/std", - "alloy-rlp/std" + "alloy-eip2124/std" ] rustc-hash = ["dep:rustc-hash"] diff --git a/crates/ethereum-forks/src/forkid.rs b/crates/ethereum-forks/src/forkid.rs deleted file mode 100644 index ebc9fb106371..000000000000 --- a/crates/ethereum-forks/src/forkid.rs +++ /dev/null @@ -1,797 +0,0 @@ -//! EIP-2124 implementation based on . -//! -//! Previously version of Apache licenced [`ethereum-forkid`](https://crates.io/crates/ethereum-forkid). - -use crate::Head; -use alloc::{ - collections::{BTreeMap, BTreeSet}, - vec::Vec, -}; -use alloy_primitives::{hex, BlockNumber, B256}; -use alloy_rlp::{Error as RlpError, *}; -#[cfg(any(test, feature = "arbitrary"))] -use arbitrary::Arbitrary; -use core::{ - cmp::Ordering, - fmt, - ops::{Add, AddAssign}, -}; -use crc::*; -#[cfg(any(test, feature = "arbitrary"))] -use proptest_derive::Arbitrary as PropTestArbitrary; -#[cfg(feature = "serde")] -use serde::{Deserialize, Serialize}; - -const CRC_32_IEEE: Crc = Crc::::new(&CRC_32_ISO_HDLC); -const TIMESTAMP_BEFORE_ETHEREUM_MAINNET: u64 = 1_300_000_000; - -/// `CRC32` hash of all previous forks starting from genesis block. -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[cfg_attr(any(test, feature = "arbitrary"), derive(PropTestArbitrary, Arbitrary))] -#[derive( - Clone, Copy, PartialEq, Eq, Hash, RlpEncodableWrapper, RlpDecodableWrapper, RlpMaxEncodedLen, -)] -pub struct ForkHash(pub [u8; 4]); - -impl fmt::Debug for ForkHash { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("ForkHash").field(&hex::encode(&self.0[..])).finish() - } -} - -impl From for ForkHash { - fn from(genesis: B256) -> Self { - Self(CRC_32_IEEE.checksum(&genesis[..]).to_be_bytes()) - } -} - -impl AddAssign for ForkHash -where - T: Into, -{ - fn add_assign(&mut self, v: T) { - let blob = v.into().to_be_bytes(); - let digest = CRC_32_IEEE.digest_with_initial(u32::from_be_bytes(self.0)); - let value = digest.finalize(); - let mut digest = CRC_32_IEEE.digest_with_initial(value); - digest.update(&blob); - self.0 = digest.finalize().to_be_bytes(); - } -} - -impl Add for ForkHash -where - T: Into, -{ - type Output = Self; - fn add(mut self, block: T) -> Self { - self += block; - self - } -} - -/// How to filter forks. -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[derive(Clone, Copy, Debug, Eq, PartialEq)] -pub enum ForkFilterKey { - /// By block number activation. - Block(BlockNumber), - /// By timestamp activation. - Time(u64), -} - -impl PartialOrd for ForkFilterKey { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for ForkFilterKey { - fn cmp(&self, other: &Self) -> Ordering { - match (self, other) { - (Self::Block(a), Self::Block(b)) | (Self::Time(a), Self::Time(b)) => a.cmp(b), - (Self::Block(_), Self::Time(_)) => Ordering::Less, - _ => Ordering::Greater, - } - } -} - -impl From for u64 { - fn from(value: ForkFilterKey) -> Self { - match value { - ForkFilterKey::Block(block) => block, - ForkFilterKey::Time(time) => time, - } - } -} - -/// A fork identifier as defined by EIP-2124. -/// Serves as the chain compatibility identifier. -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[cfg_attr(any(test, feature = "arbitrary"), derive(PropTestArbitrary, Arbitrary))] -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, RlpEncodable, RlpDecodable, RlpMaxEncodedLen)] -pub struct ForkId { - /// CRC32 checksum of the all fork blocks and timestamps from genesis. - pub hash: ForkHash, - /// Next upcoming fork block number or timestamp, 0 if not yet known. - pub next: u64, -} - -/// Represents a forward-compatible ENR entry for including the forkid in a node record via -/// EIP-868. Forward compatibility is achieved via EIP-8. -/// -/// See: -/// -/// -/// for how geth implements `ForkId` values and forward compatibility. -#[derive(Debug, Clone, PartialEq, Eq, RlpEncodable)] -pub struct EnrForkIdEntry { - /// The inner forkid - pub fork_id: ForkId, -} - -impl Decodable for EnrForkIdEntry { - // NOTE(onbjerg): Manual implementation to satisfy EIP-8. - // - // See https://eips.ethereum.org/EIPS/eip-8 - fn decode(buf: &mut &[u8]) -> alloy_rlp::Result { - let b = &mut &**buf; - let rlp_head = Header::decode(b)?; - if !rlp_head.list { - return Err(RlpError::UnexpectedString) - } - let started_len = b.len(); - - let this = Self { fork_id: Decodable::decode(b)? }; - - // NOTE(onbjerg): Because of EIP-8, we only check that we did not consume *more* than the - // payload length, i.e. it is ok if payload length is greater than what we consumed, as we - // just discard the remaining list items - let consumed = started_len - b.len(); - if consumed > rlp_head.payload_length { - return Err(RlpError::ListLengthMismatch { - expected: rlp_head.payload_length, - got: consumed, - }) - } - - let rem = rlp_head.payload_length - consumed; - b.advance(rem); - *buf = *b; - - Ok(this) - } -} - -impl From for EnrForkIdEntry { - fn from(fork_id: ForkId) -> Self { - Self { fork_id } - } -} - -impl From for ForkId { - fn from(entry: EnrForkIdEntry) -> Self { - entry.fork_id - } -} - -/// Reason for rejecting provided `ForkId`. -#[derive(Clone, Copy, Debug, thiserror::Error, PartialEq, Eq, Hash)] -pub enum ValidationError { - /// Remote node is outdated and needs a software update. - #[error( - "remote node is outdated and needs a software update: local={local:?}, remote={remote:?}" - )] - RemoteStale { - /// locally configured forkId - local: ForkId, - /// `ForkId` received from remote - remote: ForkId, - }, - /// Local node is on an incompatible chain or needs a software update. - #[error("local node is on an incompatible chain or needs a software update: local={local:?}, remote={remote:?}")] - LocalIncompatibleOrStale { - /// locally configured forkId - local: ForkId, - /// `ForkId` received from remote - remote: ForkId, - }, -} - -/// Filter that describes the state of blockchain and can be used to check incoming `ForkId`s for -/// compatibility. -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct ForkFilter { - /// The forks in the filter are keyed by `(timestamp, block)`. This ensures that block-based - /// forks (`time == 0`) are processed before time-based forks as required by - /// [EIP-6122][eip-6122]. - /// - /// Time-based forks have their block number set to 0, allowing easy comparisons with a [Head]; - /// a fork is active if both it's time and block number are less than or equal to [Head]. - /// - /// [eip-6122]: https://eips.ethereum.org/EIPS/eip-6122 - forks: BTreeMap, - - /// The current head, used to select forks that are active locally. - head: Head, - - cache: Cache, -} - -impl ForkFilter { - /// Create the filter from provided head, genesis block hash, past forks and expected future - /// forks. - pub fn new(head: Head, genesis_hash: B256, genesis_timestamp: u64, forks: F) -> Self - where - F: IntoIterator, - { - let genesis_fork_hash = ForkHash::from(genesis_hash); - let mut forks = forks.into_iter().collect::>(); - forks.remove(&ForkFilterKey::Time(0)); - forks.remove(&ForkFilterKey::Block(0)); - - let forks = forks - .into_iter() - // filter out forks that are pre-genesis by timestamp - .filter(|key| match key { - ForkFilterKey::Block(_) => true, - ForkFilterKey::Time(time) => *time > genesis_timestamp, - }) - .collect::>() - .into_iter() - .fold( - (BTreeMap::from([(ForkFilterKey::Block(0), genesis_fork_hash)]), genesis_fork_hash), - |(mut acc, base_hash), key| { - let fork_hash = base_hash + u64::from(key); - acc.insert(key, fork_hash); - (acc, fork_hash) - }, - ) - .0; - - // Compute cache based on filtered forks and the current head. - let cache = Cache::compute_cache(&forks, head); - - // Create and return a new `ForkFilter`. - Self { forks, head, cache } - } - - fn set_head_priv(&mut self, head: Head) -> Option { - let head_in_past = match self.cache.epoch_start { - ForkFilterKey::Block(epoch_start_block) => head.number < epoch_start_block, - ForkFilterKey::Time(epoch_start_time) => head.timestamp < epoch_start_time, - }; - let head_in_future = match self.cache.epoch_end { - Some(ForkFilterKey::Block(epoch_end_block)) => head.number >= epoch_end_block, - Some(ForkFilterKey::Time(epoch_end_time)) => head.timestamp >= epoch_end_time, - None => false, - }; - - self.head = head; - - // Recompute the cache if the head is in the past or future epoch. - (head_in_past || head_in_future).then(|| { - let past = self.current(); - self.cache = Cache::compute_cache(&self.forks, head); - ForkTransition { current: self.current(), past } - }) - } - - /// Set the current head. - /// - /// If the update updates the current [`ForkId`] it returns a [`ForkTransition`] - pub fn set_head(&mut self, head: Head) -> Option { - self.set_head_priv(head) - } - - /// Return current fork id - #[must_use] - pub const fn current(&self) -> ForkId { - self.cache.fork_id - } - - /// Manually set the current fork id. - /// - /// Caution: this disregards all configured fork filters and is reset on the next head update. - /// This is useful for testing or to connect to networks over p2p where only the latest forkid - /// is known. - pub fn set_current_fork_id(&mut self, fork_id: ForkId) { - self.cache.fork_id = fork_id; - } - - /// Check whether the provided `ForkId` is compatible based on the validation rules in - /// `EIP-2124`. - /// - /// Implements the rules following: - /// - /// # Errors - /// - /// Returns a `ValidationError` if the `ForkId` is not compatible. - pub fn validate(&self, fork_id: ForkId) -> Result<(), ValidationError> { - // 1) If local and remote FORK_HASH matches... - if self.current().hash == fork_id.hash { - if fork_id.next == 0 { - // 1b) No remotely announced fork, connect. - return Ok(()) - } - - let is_incompatible = if self.head.number < TIMESTAMP_BEFORE_ETHEREUM_MAINNET { - // When the block number is less than an old timestamp before Ethereum mainnet, - // we check if this fork is time-based or block number-based by estimating that, - // if fork_id.next is bigger than the old timestamp, we are dealing with a - // timestamp, otherwise with a block. - (fork_id.next > TIMESTAMP_BEFORE_ETHEREUM_MAINNET && - self.head.timestamp >= fork_id.next) || - (fork_id.next <= TIMESTAMP_BEFORE_ETHEREUM_MAINNET && - self.head.number >= fork_id.next) - } else { - // Extra safety check to future-proof for when Ethereum has over a billion blocks. - let head_block_or_time = match self.cache.epoch_start { - ForkFilterKey::Block(_) => self.head.number, - ForkFilterKey::Time(_) => self.head.timestamp, - }; - head_block_or_time >= fork_id.next - }; - - return if is_incompatible { - // 1a) A remotely announced but remotely not passed block is already passed locally, - // disconnect, since the chains are incompatible. - Err(ValidationError::LocalIncompatibleOrStale { - local: self.current(), - remote: fork_id, - }) - } else { - // 1b) Remotely announced fork not yet passed locally, connect. - Ok(()) - } - } - - // 2) If the remote FORK_HASH is a subset of the local past forks... - let mut it = self.cache.past.iter(); - while let Some((_, hash)) = it.next() { - if *hash == fork_id.hash { - // ...and the remote FORK_NEXT matches with the locally following fork block number - // or timestamp, connect. - if let Some((actual_key, _)) = it.next() { - return if u64::from(*actual_key) == fork_id.next { - Ok(()) - } else { - Err(ValidationError::RemoteStale { local: self.current(), remote: fork_id }) - } - } - - break - } - } - - // 3) If the remote FORK_HASH is a superset of the local past forks and can be completed - // with locally known future forks, connect. - for future_fork_hash in &self.cache.future { - if *future_fork_hash == fork_id.hash { - return Ok(()) - } - } - - // 4) Reject in all other cases. - Err(ValidationError::LocalIncompatibleOrStale { local: self.current(), remote: fork_id }) - } -} - -/// Represents a transition from one fork to another -/// -/// See also [`ForkFilter::set_head`] -#[derive(Debug, Clone, Eq, PartialEq)] -pub struct ForkTransition { - /// The new, active `ForkId` - pub current: ForkId, - /// The previously active `ForkId` before the transition - pub past: ForkId, -} - -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[derive(Clone, Debug, PartialEq, Eq)] -struct Cache { - // An epoch is a period between forks. - // When we progress from one fork to the next one we move to the next epoch. - epoch_start: ForkFilterKey, - epoch_end: Option, - past: Vec<(ForkFilterKey, ForkHash)>, - future: Vec, - fork_id: ForkId, -} - -impl Cache { - /// Compute cache. - fn compute_cache(forks: &BTreeMap, head: Head) -> Self { - // Prepare vectors to store past and future forks. - let mut past = Vec::with_capacity(forks.len()); - let mut future = Vec::with_capacity(forks.len()); - - // Initialize variables to track the epoch range. - let mut epoch_start = ForkFilterKey::Block(0); - let mut epoch_end = None; - - // Iterate through forks and categorize them into past and future. - for (key, hash) in forks { - // Check if the fork is active based on its type (Block or Time). - let active = match key { - ForkFilterKey::Block(block) => *block <= head.number, - ForkFilterKey::Time(time) => *time <= head.timestamp, - }; - - // Categorize forks into past or future based on activity. - if active { - epoch_start = *key; - past.push((*key, *hash)); - } else { - if epoch_end.is_none() { - epoch_end = Some(*key); - } - future.push(*hash); - } - } - - // Create ForkId using the last past fork's hash and the next epoch start. - let fork_id = ForkId { - hash: past.last().expect("there is always at least one - genesis - fork hash").1, - next: epoch_end.unwrap_or(ForkFilterKey::Block(0)).into(), - }; - - // Return the computed cache. - Self { epoch_start, epoch_end, past, future, fork_id } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use alloy_consensus::constants::MAINNET_GENESIS_HASH; - - // EIP test vectors. - #[test] - fn forkhash() { - let mut fork_hash = ForkHash::from(MAINNET_GENESIS_HASH); - assert_eq!(fork_hash.0, hex!("fc64ec04")); - - fork_hash += 1_150_000u64; - assert_eq!(fork_hash.0, hex!("97c2c34c")); - - fork_hash += 1_920_000u64; - assert_eq!(fork_hash.0, hex!("91d1f948")); - } - - #[test] - fn compatibility_check() { - let mut filter = ForkFilter::new( - Head { number: 0, ..Default::default() }, - MAINNET_GENESIS_HASH, - 0, - vec![ - ForkFilterKey::Block(1_150_000), - ForkFilterKey::Block(1_920_000), - ForkFilterKey::Block(2_463_000), - ForkFilterKey::Block(2_675_000), - ForkFilterKey::Block(4_370_000), - ForkFilterKey::Block(7_280_000), - ], - ); - - // Local is mainnet Petersburg, remote announces the same. No future fork is announced. - filter.set_head(Head { number: 7_987_396, ..Default::default() }); - assert_eq!(filter.validate(ForkId { hash: ForkHash(hex!("668db0af")), next: 0 }), Ok(())); - - // Local is mainnet Petersburg, remote announces the same. Remote also announces a next fork - // at block 0xffffffff, but that is uncertain. - filter.set_head(Head { number: 7_987_396, ..Default::default() }); - assert_eq!( - filter.validate(ForkId { hash: ForkHash(hex!("668db0af")), next: BlockNumber::MAX }), - Ok(()) - ); - - // Local is mainnet currently in Byzantium only (so it's aware of Petersburg),remote - // announces also Byzantium, but it's not yet aware of Petersburg (e.g. non updated - // node before the fork). In this case we don't know if Petersburg passed yet or - // not. - filter.set_head(Head { number: 7_279_999, ..Default::default() }); - assert_eq!(filter.validate(ForkId { hash: ForkHash(hex!("a00bc324")), next: 0 }), Ok(())); - - // Local is mainnet currently in Byzantium only (so it's aware of Petersburg), remote - // announces also Byzantium, and it's also aware of Petersburg (e.g. updated node - // before the fork). We don't know if Petersburg passed yet (will pass) or not. - filter.set_head(Head { number: 7_279_999, ..Default::default() }); - assert_eq!( - filter.validate(ForkId { hash: ForkHash(hex!("a00bc324")), next: 7_280_000 }), - Ok(()) - ); - - // Local is mainnet currently in Byzantium only (so it's aware of Petersburg), remote - // announces also Byzantium, and it's also aware of some random fork (e.g. - // misconfigured Petersburg). As neither forks passed at neither nodes, they may - // mismatch, but we still connect for now. - filter.set_head(Head { number: 7_279_999, ..Default::default() }); - assert_eq!( - filter.validate(ForkId { hash: ForkHash(hex!("a00bc324")), next: BlockNumber::MAX }), - Ok(()) - ); - - // Local is mainnet Petersburg, remote announces Byzantium + knowledge about Petersburg. - // Remote is simply out of sync, accept. - filter.set_head(Head { number: 7_987_396, ..Default::default() }); - assert_eq!( - filter.validate(ForkId { hash: ForkHash(hex!("a00bc324")), next: 7_280_000 }), - Ok(()) - ); - - // Local is mainnet Petersburg, remote announces Spurious + knowledge about Byzantium. - // Remote is definitely out of sync. It may or may not need the Petersburg update, - // we don't know yet. - filter.set_head(Head { number: 7_987_396, ..Default::default() }); - assert_eq!( - filter.validate(ForkId { hash: ForkHash(hex!("3edd5b10")), next: 4_370_000 }), - Ok(()) - ); - - // Local is mainnet Byzantium, remote announces Petersburg. Local is out of sync, accept. - filter.set_head(Head { number: 7_279_999, ..Default::default() }); - assert_eq!(filter.validate(ForkId { hash: ForkHash(hex!("668db0af")), next: 0 }), Ok(())); - - // Local is mainnet Spurious, remote announces Byzantium, but is not aware of Petersburg. - // Local out of sync. Local also knows about a future fork, but that is uncertain - // yet. - filter.set_head(Head { number: 4_369_999, ..Default::default() }); - assert_eq!(filter.validate(ForkId { hash: ForkHash(hex!("a00bc324")), next: 0 }), Ok(())); - - // Local is mainnet Petersburg. remote announces Byzantium but is not aware of further - // forks. Remote needs software update. - filter.set_head(Head { number: 7_987_396, ..Default::default() }); - let remote = ForkId { hash: ForkHash(hex!("a00bc324")), next: 0 }; - assert_eq!( - filter.validate(remote), - Err(ValidationError::RemoteStale { local: filter.current(), remote }) - ); - - // Local is mainnet Petersburg, and isn't aware of more forks. Remote announces Petersburg + - // 0xffffffff. Local needs software update, reject. - filter.set_head(Head { number: 7_987_396, ..Default::default() }); - let remote = ForkId { hash: ForkHash(hex!("5cddc0e1")), next: 0 }; - assert_eq!( - filter.validate(remote), - Err(ValidationError::LocalIncompatibleOrStale { local: filter.current(), remote }) - ); - - // Local is mainnet Byzantium, and is aware of Petersburg. Remote announces Petersburg + - // 0xffffffff. Local needs software update, reject. - filter.set_head(Head { number: 7_279_999, ..Default::default() }); - let remote = ForkId { hash: ForkHash(hex!("5cddc0e1")), next: 0 }; - assert_eq!( - filter.validate(remote), - Err(ValidationError::LocalIncompatibleOrStale { local: filter.current(), remote }) - ); - - // Local is mainnet Petersburg, remote is Rinkeby Petersburg. - filter.set_head(Head { number: 7_987_396, ..Default::default() }); - let remote = ForkId { hash: ForkHash(hex!("afec6b27")), next: 0 }; - assert_eq!( - filter.validate(remote), - Err(ValidationError::LocalIncompatibleOrStale { local: filter.current(), remote }) - ); - - // Local is mainnet Petersburg, far in the future. Remote announces Gopherium (non existing - // fork) at some future block 88888888, for itself, but past block for local. Local - // is incompatible. - // - // This case detects non-upgraded nodes with majority hash power (typical Ropsten mess). - filter.set_head(Head { number: 88_888_888, ..Default::default() }); - let remote = ForkId { hash: ForkHash(hex!("668db0af")), next: 88_888_888 }; - assert_eq!( - filter.validate(remote), - Err(ValidationError::LocalIncompatibleOrStale { local: filter.current(), remote }) - ); - - // Local is mainnet Byzantium. Remote is also in Byzantium, but announces Gopherium (non - // existing fork) at block 7279999, before Petersburg. Local is incompatible. - filter.set_head(Head { number: 7_279_999, ..Default::default() }); - let remote = ForkId { hash: ForkHash(hex!("a00bc324")), next: 7_279_999 }; - assert_eq!( - filter.validate(remote), - Err(ValidationError::LocalIncompatibleOrStale { local: filter.current(), remote }) - ); - - // Block far in the future (block number bigger than TIMESTAMP_BEFORE_ETHEREUM_MAINNET), not - // compatible. - filter - .set_head(Head { number: TIMESTAMP_BEFORE_ETHEREUM_MAINNET + 1, ..Default::default() }); - let remote = ForkId { - hash: ForkHash(hex!("668db0af")), - next: TIMESTAMP_BEFORE_ETHEREUM_MAINNET + 1, - }; - assert_eq!( - filter.validate(remote), - Err(ValidationError::LocalIncompatibleOrStale { local: filter.current(), remote }) - ); - - // Block far in the future (block number bigger than TIMESTAMP_BEFORE_ETHEREUM_MAINNET), - // compatible. - filter - .set_head(Head { number: TIMESTAMP_BEFORE_ETHEREUM_MAINNET + 1, ..Default::default() }); - let remote = ForkId { - hash: ForkHash(hex!("668db0af")), - next: TIMESTAMP_BEFORE_ETHEREUM_MAINNET + 2, - }; - assert_eq!(filter.validate(remote), Ok(())); - - // block number smaller than TIMESTAMP_BEFORE_ETHEREUM_MAINNET and - // fork_id.next > TIMESTAMP_BEFORE_ETHEREUM_MAINNET && self.head.timestamp >= fork_id.next, - // not compatible. - filter.set_head(Head { - number: TIMESTAMP_BEFORE_ETHEREUM_MAINNET - 1, - timestamp: TIMESTAMP_BEFORE_ETHEREUM_MAINNET + 2, - ..Default::default() - }); - let remote = ForkId { - hash: ForkHash(hex!("668db0af")), - next: TIMESTAMP_BEFORE_ETHEREUM_MAINNET + 1, - }; - assert_eq!( - filter.validate(remote), - Err(ValidationError::LocalIncompatibleOrStale { local: filter.current(), remote }) - ); - - // block number smaller than TIMESTAMP_BEFORE_ETHEREUM_MAINNET and - // fork_id.next <= TIMESTAMP_BEFORE_ETHEREUM_MAINNET && self.head.number >= fork_id.next, - // not compatible. - filter - .set_head(Head { number: TIMESTAMP_BEFORE_ETHEREUM_MAINNET - 1, ..Default::default() }); - let remote = ForkId { - hash: ForkHash(hex!("668db0af")), - next: TIMESTAMP_BEFORE_ETHEREUM_MAINNET - 2, - }; - assert_eq!( - filter.validate(remote), - Err(ValidationError::LocalIncompatibleOrStale { local: filter.current(), remote }) - ); - - // block number smaller than TIMESTAMP_BEFORE_ETHEREUM_MAINNET and - // !((fork_id.next > TIMESTAMP_BEFORE_ETHEREUM_MAINNET && self.head.timestamp >= - // fork_id.next) || (fork_id.next <= TIMESTAMP_BEFORE_ETHEREUM_MAINNET && self.head.number - // >= fork_id.next)), compatible. - filter - .set_head(Head { number: TIMESTAMP_BEFORE_ETHEREUM_MAINNET - 2, ..Default::default() }); - let remote = ForkId { - hash: ForkHash(hex!("668db0af")), - next: TIMESTAMP_BEFORE_ETHEREUM_MAINNET - 1, - }; - assert_eq!(filter.validate(remote), Ok(())); - } - - #[test] - fn forkid_serialization() { - assert_eq!( - &*encode_fixed_size(&ForkId { hash: ForkHash(hex!("00000000")), next: 0 }), - hex!("c6840000000080") - ); - assert_eq!( - &*encode_fixed_size(&ForkId { hash: ForkHash(hex!("deadbeef")), next: 0xBADD_CAFE }), - hex!("ca84deadbeef84baddcafe") - ); - assert_eq!( - &*encode_fixed_size(&ForkId { hash: ForkHash(hex!("ffffffff")), next: u64::MAX }), - hex!("ce84ffffffff88ffffffffffffffff") - ); - - assert_eq!( - ForkId::decode(&mut (&hex!("c6840000000080") as &[u8])).unwrap(), - ForkId { hash: ForkHash(hex!("00000000")), next: 0 } - ); - assert_eq!( - ForkId::decode(&mut (&hex!("ca84deadbeef84baddcafe") as &[u8])).unwrap(), - ForkId { hash: ForkHash(hex!("deadbeef")), next: 0xBADD_CAFE } - ); - assert_eq!( - ForkId::decode(&mut (&hex!("ce84ffffffff88ffffffffffffffff") as &[u8])).unwrap(), - ForkId { hash: ForkHash(hex!("ffffffff")), next: u64::MAX } - ); - } - - #[test] - fn fork_id_rlp() { - // - let val = hex!("c6840000000080"); - let id = ForkId::decode(&mut &val[..]).unwrap(); - assert_eq!(id, ForkId { hash: ForkHash(hex!("00000000")), next: 0 }); - assert_eq!(alloy_rlp::encode(id), &val[..]); - - let val = hex!("ca84deadbeef84baddcafe"); - let id = ForkId::decode(&mut &val[..]).unwrap(); - assert_eq!(id, ForkId { hash: ForkHash(hex!("deadbeef")), next: 0xBADDCAFE }); - assert_eq!(alloy_rlp::encode(id), &val[..]); - - let val = hex!("ce84ffffffff88ffffffffffffffff"); - let id = ForkId::decode(&mut &val[..]).unwrap(); - assert_eq!(id, ForkId { hash: ForkHash(u32::MAX.to_be_bytes()), next: u64::MAX }); - assert_eq!(alloy_rlp::encode(id), &val[..]); - } - - #[test] - fn compute_cache() { - let b1 = 1_150_000; - let b2 = 1_920_000; - - let h0 = ForkId { hash: ForkHash(hex!("fc64ec04")), next: b1 }; - let h1 = ForkId { hash: ForkHash(hex!("97c2c34c")), next: b2 }; - let h2 = ForkId { hash: ForkHash(hex!("91d1f948")), next: 0 }; - - let mut fork_filter = ForkFilter::new( - Head { number: 0, ..Default::default() }, - MAINNET_GENESIS_HASH, - 0, - vec![ForkFilterKey::Block(b1), ForkFilterKey::Block(b2)], - ); - - assert!(fork_filter.set_head_priv(Head { number: 0, ..Default::default() }).is_none()); - assert_eq!(fork_filter.current(), h0); - - assert!(fork_filter.set_head_priv(Head { number: 1, ..Default::default() }).is_none()); - assert_eq!(fork_filter.current(), h0); - - assert_eq!( - fork_filter.set_head_priv(Head { number: b1 + 1, ..Default::default() }).unwrap(), - ForkTransition { current: h1, past: h0 } - ); - assert_eq!(fork_filter.current(), h1); - - assert!(fork_filter.set_head_priv(Head { number: b1, ..Default::default() }).is_none()); - assert_eq!(fork_filter.current(), h1); - - assert_eq!( - fork_filter.set_head_priv(Head { number: b1 - 1, ..Default::default() }).unwrap(), - ForkTransition { current: h0, past: h1 } - ); - assert_eq!(fork_filter.current(), h0); - - assert!(fork_filter.set_head_priv(Head { number: b1, ..Default::default() }).is_some()); - assert_eq!(fork_filter.current(), h1); - - assert!(fork_filter.set_head_priv(Head { number: b2 - 1, ..Default::default() }).is_none()); - assert_eq!(fork_filter.current(), h1); - - assert!(fork_filter.set_head_priv(Head { number: b2, ..Default::default() }).is_some()); - assert_eq!(fork_filter.current(), h2); - } - - mod eip8 { - use super::*; - - fn junk_enr_fork_id_entry() -> Vec { - let mut buf = Vec::new(); - // enr request is just an expiration - let fork_id = ForkId { hash: ForkHash(hex!("deadbeef")), next: 0xBADDCAFE }; - - // add some junk - let junk: u64 = 112233; - - // rlp header encoding - let payload_length = fork_id.length() + junk.length(); - alloy_rlp::Header { list: true, payload_length }.encode(&mut buf); - - // fields - fork_id.encode(&mut buf); - junk.encode(&mut buf); - - buf - } - - #[test] - fn eip8_decode_enr_fork_id_entry() { - let enr_fork_id_entry_with_junk = junk_enr_fork_id_entry(); - - let mut buf = enr_fork_id_entry_with_junk.as_slice(); - let decoded = EnrForkIdEntry::decode(&mut buf).unwrap(); - assert_eq!( - decoded.fork_id, - ForkId { hash: ForkHash(hex!("deadbeef")), next: 0xBADDCAFE } - ); - } - } -} diff --git a/crates/ethereum-forks/src/head.rs b/crates/ethereum-forks/src/head.rs deleted file mode 100644 index 1b867bcb852f..000000000000 --- a/crates/ethereum-forks/src/head.rs +++ /dev/null @@ -1,65 +0,0 @@ -use alloy_primitives::{BlockNumber, B256, U256}; -use core::fmt; -#[cfg(feature = "serde")] -use serde::{Deserialize, Serialize}; - -/// Describes the current head block. -/// -/// The head block is the highest fully synced block. -/// -/// Note: This is a slimmed down version of Header, primarily for communicating the highest block -/// with the P2P network and the RPC. -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash, PartialOrd, Ord)] -pub struct Head { - /// The number of the head block. - pub number: BlockNumber, - /// The hash of the head block. - pub hash: B256, - /// The difficulty of the head block. - pub difficulty: U256, - /// The total difficulty at the head block. - pub total_difficulty: U256, - /// The timestamp of the head block. - pub timestamp: u64, -} - -impl Head { - /// Creates a new `Head` instance. - pub const fn new( - number: BlockNumber, - hash: B256, - difficulty: U256, - total_difficulty: U256, - timestamp: u64, - ) -> Self { - Self { number, hash, difficulty, total_difficulty, timestamp } - } - - /// Updates the head block with new information. - pub fn update( - &mut self, - number: BlockNumber, - hash: B256, - difficulty: U256, - total_difficulty: U256, - timestamp: u64, - ) { - *self = Self { number, hash, difficulty, total_difficulty, timestamp }; - } - - /// Checks if the head block is an empty block (i.e., has default values). - pub fn is_empty(&self) -> bool { - *self == Self::default() - } -} - -impl fmt::Display for Head { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "Head Block:\n Number: {}\n Hash: {}\n Difficulty: {:?}\n Total Difficulty: {:?}\n Timestamp: {}", - self.number, self.hash, self.difficulty, self.total_difficulty, self.timestamp - ) - } -} diff --git a/crates/ethereum-forks/src/lib.rs b/crates/ethereum-forks/src/lib.rs index ea7fb6515717..ec74d3634cc8 100644 --- a/crates/ethereum-forks/src/lib.rs +++ b/crates/ethereum-forks/src/lib.rs @@ -4,7 +4,7 @@ //! //! ## Feature Flags //! -//! - `arbitrary`: Adds `proptest` and `arbitrary` support for primitive types. +//! - `arbitrary`: Adds `arbitrary` support for primitive types. #![doc( html_logo_url = "https://raw.githubusercontent.com/paradigmxyz/reth/main/assets/reth-docs.png", @@ -17,18 +17,15 @@ extern crate alloc; +/// Re-exported EIP-2124 forkid types. +pub use alloy_eip2124::*; + mod display; mod forkcondition; -mod forkid; mod hardfork; mod hardforks; -mod head; -pub use forkid::{ - EnrForkIdEntry, ForkFilter, ForkFilterKey, ForkHash, ForkId, ForkTransition, ValidationError, -}; pub use hardfork::{EthereumHardfork, Hardfork, DEV_HARDFORKS}; -pub use head::Head; pub use display::DisplayHardforks; pub use forkcondition::ForkCondition; diff --git a/crates/ethereum/primitives/src/transaction.rs b/crates/ethereum/primitives/src/transaction.rs index 97e71f11edd0..d1221aeffe62 100644 --- a/crates/ethereum/primitives/src/transaction.rs +++ b/crates/ethereum/primitives/src/transaction.rs @@ -572,3 +572,32 @@ impl SignedTransaction for TransactionSigned { recover_signer_unchecked(&self.signature, signature_hash) } } + +#[cfg(test)] +mod tests { + use super::*; + use alloy_eips::eip7702::constants::SECP256K1N_HALF; + use alloy_primitives::hex; + + #[test] + fn eip_2_reject_high_s_value() { + // This pre-homestead transaction has a high `s` value and should be rejected by the + // `recover_signer` method: + // https://etherscan.io/getRawTx?tx=0x9e6e19637bb625a8ff3d052b7c2fe57dc78c55a15d258d77c43d5a9c160b0384 + // + // Block number: 46170 + let raw_tx = hex!("f86d8085746a52880082520894c93f2250589a6563f5359051c1ea25746549f0d889208686e75e903bc000801ba034b6fdc33ea520e8123cf5ac4a9ff476f639cab68980cd9366ccae7aef437ea0a0e517caa5f50e27ca0d1e9a92c503b4ccb039680c6d9d0c71203ed611ea4feb33"); + let tx = TransactionSigned::decode_2718(&mut &raw_tx[..]).unwrap(); + let signature = tx.signature(); + + // make sure we know it's greater than SECP256K1N_HALF + assert!(signature.s() > SECP256K1N_HALF); + + // recover signer, expect failure + let hash = *tx.tx_hash(); + assert!(recover_signer(signature, hash).is_none()); + + // use unchecked, ensure it succeeds (the signature is valid if not for EIP-2) + assert!(recover_signer_unchecked(signature, hash).is_some()); + } +} diff --git a/crates/evm/execution-types/src/chain.rs b/crates/evm/execution-types/src/chain.rs index 929ac1c5c0dd..e207209a997a 100644 --- a/crates/evm/execution-types/src/chain.rs +++ b/crates/evm/execution-types/src/chain.rs @@ -254,7 +254,7 @@ impl Chain { self.blocks().iter().zip(self.execution_outcome.receipts().iter()) { let mut tx_receipts = Vec::with_capacity(receipts.len()); - for (tx, receipt) in block.body.transactions().iter().zip(receipts.iter()) { + for (tx, receipt) in block.body().transactions().iter().zip(receipts.iter()) { tx_receipts.push(( tx.trie_hash(), receipt.as_ref().expect("receipts have not been pruned").clone(), @@ -437,7 +437,7 @@ impl>> ChainBlocks<'_, /// Returns an iterator over all transactions in the chain. #[inline] pub fn transactions(&self) -> impl Iterator::Transaction> + '_ { - self.blocks.values().flat_map(|block| block.body.transactions().iter()) + self.blocks.values().flat_map(|block| block.body().transactions().iter()) } /// Returns an iterator over all transactions and their senders. @@ -710,10 +710,10 @@ mod tests { let mut block3 = block.clone(); let mut block4 = block; - block1.block.header.set_hash(block1_hash); - block2.block.header.set_hash(block2_hash); - block3.block.header.set_hash(block3_hash); - block4.block.header.set_hash(block4_hash); + block1.block.set_hash(block1_hash); + block2.block.set_hash(block2_hash); + block3.block.set_hash(block3_hash); + block4.block.set_hash(block4_hash); block3.set_parent_hash(block2_hash); diff --git a/crates/exex/exex/src/backfill/job.rs b/crates/exex/exex/src/backfill/job.rs index 0bd4ce5f2b7d..cb5f01d06a09 100644 --- a/crates/exex/exex/src/backfill/job.rs +++ b/crates/exex/exex/src/backfill/job.rs @@ -101,15 +101,16 @@ where cumulative_gas += block.gas_used(); // Configure the executor to use the current state. - trace!(target: "exex::backfill", number = block_number, txs = block.body.transactions().len(), "Executing block"); + trace!(target: "exex::backfill", number = block_number, txs = block.body().transactions().len(), "Executing block"); // Execute the block let execute_start = Instant::now(); // Unseal the block for execution let (block, senders) = block.into_components(); - let (unsealed_header, hash) = block.header.split(); - let block = P::Block::new(unsealed_header, block.body).with_senders_unchecked(senders); + let (header, body) = block.split_header_body(); + let (unsealed_header, hash) = header.split(); + let block = P::Block::new(unsealed_header, body).with_senders_unchecked(senders); executor.execute_and_verify_one(&block)?; execution_duration += execute_start.elapsed(); diff --git a/crates/net/downloaders/src/bodies/bodies.rs b/crates/net/downloaders/src/bodies/bodies.rs index 2f6015a09166..47a816f4ce6b 100644 --- a/crates/net/downloaders/src/bodies/bodies.rs +++ b/crates/net/downloaders/src/bodies/bodies.rs @@ -678,8 +678,10 @@ mod tests { ); let headers = blocks.iter().map(|block| block.header.clone()).collect::>(); - let bodies = - blocks.into_iter().map(|block| (block.hash(), block.body)).collect::>(); + let bodies = blocks + .into_iter() + .map(|block| (block.hash(), block.into_body())) + .collect::>(); insert_headers(db.db(), &headers); diff --git a/crates/net/downloaders/src/bodies/test_utils.rs b/crates/net/downloaders/src/bodies/test_utils.rs index ca35c7449a00..6ca012f9c684 100644 --- a/crates/net/downloaders/src/bodies/test_utils.rs +++ b/crates/net/downloaders/src/bodies/test_utils.rs @@ -21,7 +21,7 @@ pub(crate) fn zip_blocks<'a, H: Clone + BlockHeader + 'a, B>( if header.is_empty() { BlockResponse::Empty(header.clone()) } else { - BlockResponse::Full(SealedBlock { header: header.clone(), body }) + BlockResponse::Full(SealedBlock::new(header.clone(), body)) } }) .collect() diff --git a/crates/net/downloaders/src/file_client.rs b/crates/net/downloaders/src/file_client.rs index 431762696e74..9230af541519 100644 --- a/crates/net/downloaders/src/file_client.rs +++ b/crates/net/downloaders/src/file_client.rs @@ -340,7 +340,7 @@ impl BodiesClient for FileClient { impl DownloadClient for FileClient { fn report_bad_message(&self, _peer_id: PeerId) { - warn!("Reported a bad message on a file client, the file may be corrupted or invalid"); + trace!("Reported a bad message on a file client, the file may be corrupted or invalid"); // noop } diff --git a/crates/net/downloaders/src/test_utils/mod.rs b/crates/net/downloaders/src/test_utils/mod.rs index 635383ce3f34..0529b78a2b20 100644 --- a/crates/net/downloaders/src/test_utils/mod.rs +++ b/crates/net/downloaders/src/test_utils/mod.rs @@ -29,7 +29,7 @@ pub(crate) fn generate_bodies( ); let headers = blocks.iter().map(|block| block.header.clone()).collect(); - let bodies = blocks.into_iter().map(|block| (block.hash(), block.body)).collect(); + let bodies = blocks.into_iter().map(|block| (block.hash(), block.into_body())).collect(); (headers, bodies) } diff --git a/crates/net/p2p/src/bodies/response.rs b/crates/net/p2p/src/bodies/response.rs index 1b415246f544..956057d98bff 100644 --- a/crates/net/p2p/src/bodies/response.rs +++ b/crates/net/p2p/src/bodies/response.rs @@ -40,7 +40,7 @@ where /// Return the reference to the response body pub fn into_body(self) -> Option { match self { - Self::Full(block) => Some(block.body), + Self::Full(block) => Some(block.into_body()), Self::Empty(_) => None, } } diff --git a/crates/net/p2p/src/full_block.rs b/crates/net/p2p/src/full_block.rs index a966c01c933d..62981ad5d9ab 100644 --- a/crates/net/p2p/src/full_block.rs +++ b/crates/net/p2p/src/full_block.rs @@ -709,7 +709,7 @@ mod tests { assert_eq!(received.len(), 10); for (i, block) in received.iter().enumerate() { let expected_number = header.number - i as u64; - assert_eq!(block.header.number, expected_number); + assert_eq!(block.number, expected_number); } } @@ -728,7 +728,7 @@ mod tests { assert_eq!(received.len(), 50); for (i, block) in received.iter().enumerate() { let expected_number = header.number - i as u64; - assert_eq!(block.header.number, expected_number); + assert_eq!(block.number, expected_number); } } @@ -748,7 +748,7 @@ mod tests { assert_eq!(received.len(), range_length); for (i, block) in received.iter().enumerate() { let expected_number = header.number - i as u64; - assert_eq!(block.header.number, expected_number); + assert_eq!(block.number, expected_number); } } } diff --git a/crates/node/core/Cargo.toml b/crates/node/core/Cargo.toml index 96919b7de7e0..7d4a417bed80 100644 --- a/crates/node/core/Cargo.toml +++ b/crates/node/core/Cargo.toml @@ -15,7 +15,7 @@ workspace = true reth-chainspec.workspace = true reth-consensus.workspace = true reth-primitives.workspace = true -reth-primitives-traits.workspace = true +reth-primitives-traits = { workspace = true, features = ["rayon"] } reth-cli-util.workspace = true reth-db = { workspace = true, features = ["mdbx"] } reth-storage-errors.workspace = true diff --git a/crates/node/core/src/utils.rs b/crates/node/core/src/utils.rs index 65f90f27eb72..1db9c1f6b9ff 100644 --- a/crates/node/core/src/utils.rs +++ b/crates/node/core/src/utils.rs @@ -84,7 +84,7 @@ where eyre::bail!("Invalid number of bodies received. Expected: 1. Received: 0") }; - let block = SealedBlock { header, body }; + let block = SealedBlock::new(header, body); consensus.validate_block_pre_execution(&block)?; Ok(block) diff --git a/crates/node/events/src/node.rs b/crates/node/events/src/node.rs index 07aa0bb0da95..129fe20ea785 100644 --- a/crates/node/events/src/node.rs +++ b/crates/node/events/src/node.rs @@ -254,7 +254,7 @@ impl NodeState { number=block.number(), hash=?block.hash(), peers=self.num_connected_peers(), - txs=block.body.transactions().len(), + txs=block.body().transactions().len(), gas=%format_gas(block.header.gas_used()), gas_throughput=%format_gas_throughput(block.header.gas_used(), elapsed), full=%format!("{:.1}%", block.header.gas_used() as f64 * 100.0 / block.header.gas_limit() as f64), diff --git a/crates/optimism/consensus/src/lib.rs b/crates/optimism/consensus/src/lib.rs index 6d587f757343..01f8f9a72f50 100644 --- a/crates/optimism/consensus/src/lib.rs +++ b/crates/optimism/consensus/src/lib.rs @@ -74,10 +74,10 @@ impl Consensus for OpBeaconConsensus { block: &SealedBlockFor, ) -> Result<(), ConsensusError> { // Check ommers hash - let ommers_hash = reth_primitives::proofs::calculate_ommers_root(&block.body.ommers); - if block.header.ommers_hash != ommers_hash { + let ommers_hash = block.body().calculate_ommers_root(); + if block.ommers_hash != ommers_hash { return Err(ConsensusError::BodyOmmersHashDiff( - GotExpected { got: ommers_hash, expected: block.header.ommers_hash }.into(), + GotExpected { got: ommers_hash, expected: block.ommers_hash }.into(), )) } diff --git a/crates/optimism/evm/src/lib.rs b/crates/optimism/evm/src/lib.rs index ec2a56389782..9fc7ee528697 100644 --- a/crates/optimism/evm/src/lib.rs +++ b/crates/optimism/evm/src/lib.rs @@ -543,11 +543,11 @@ mod tests { let mut block2 = block; // Set the hashes of block1 and block2 - block1.block.header.set_block_number(10); - block1.block.header.set_hash(block1_hash); + block1.block.set_block_number(10); + block1.block.set_hash(block1_hash); - block2.block.header.set_block_number(11); - block2.block.header.set_hash(block2_hash); + block2.block.set_block_number(11); + block2.block.set_hash(block2_hash); // Create a random receipt object, receipt1 let receipt1 = OpReceipt::Legacy(Receipt { diff --git a/crates/optimism/node/src/txpool.rs b/crates/optimism/node/src/txpool.rs index b598fc3a7efa..9692e8cdb136 100644 --- a/crates/optimism/node/src/txpool.rs +++ b/crates/optimism/node/src/txpool.rs @@ -408,7 +408,7 @@ where self.inner.on_new_head_block(new_tip_block); self.update_l1_block_info( new_tip_block.header(), - new_tip_block.body.transactions().first(), + new_tip_block.body().transactions().first(), ); } } diff --git a/crates/optimism/node/tests/it/priority.rs b/crates/optimism/node/tests/it/priority.rs index 031300aba3e0..510cd5cdb20b 100644 --- a/crates/optimism/node/tests/it/priority.rs +++ b/crates/optimism/node/tests/it/priority.rs @@ -187,10 +187,10 @@ async fn test_custom_block_priority_config() { assert_eq!(block_payloads.len(), 1); let (block_payload, _) = block_payloads.first().unwrap(); let block_payload = block_payload.block().clone(); - assert_eq!(block_payload.body.transactions.len(), 2); // L1 block info tx + end-of-block custom tx + assert_eq!(block_payload.body().transactions.len(), 2); // L1 block info tx + end-of-block custom tx // Check that last transaction in the block looks like a transfer to a random address. - let end_of_block_tx = block_payload.body.transactions.last().unwrap(); + let end_of_block_tx = block_payload.body().transactions.last().unwrap(); let OpTypedTransaction::Eip1559(end_of_block_tx) = &end_of_block_tx.transaction else { panic!("expected EIP-1559 transaction"); }; diff --git a/crates/optimism/rpc/src/eth/block.rs b/crates/optimism/rpc/src/eth/block.rs index a4806f096b1a..dc35db1e42a8 100644 --- a/crates/optimism/rpc/src/eth/block.rs +++ b/crates/optimism/rpc/src/eth/block.rs @@ -1,6 +1,6 @@ //! Loads and formats OP block RPC response. -use alloy_consensus::BlockHeader; +use alloy_consensus::{transaction::TransactionMeta, BlockHeader}; use alloy_rpc_types_eth::BlockId; use op_alloy_network::Network; use op_alloy_rpc_types::OpTransactionReceipt; @@ -8,7 +8,6 @@ use reth_chainspec::ChainSpecProvider; use reth_node_api::BlockBody; use reth_optimism_chainspec::OpChainSpec; use reth_optimism_primitives::{OpReceipt, OpTransactionSigned}; -use reth_primitives::TransactionMeta; use reth_primitives_traits::SignedTransaction; use reth_provider::{BlockReader, HeaderProvider}; use reth_rpc_eth_api::{ @@ -42,10 +41,10 @@ where let timestamp = block.timestamp(); let l1_block_info = - reth_optimism_evm::extract_l1_info(&block.body).map_err(OpEthApiError::from)?; + reth_optimism_evm::extract_l1_info(block.body()).map_err(OpEthApiError::from)?; return block - .body + .body() .transactions() .iter() .zip(receipts.iter()) diff --git a/crates/optimism/rpc/src/eth/receipt.rs b/crates/optimism/rpc/src/eth/receipt.rs index 5cf389bafb86..cc37dbbb5320 100644 --- a/crates/optimism/rpc/src/eth/receipt.rs +++ b/crates/optimism/rpc/src/eth/receipt.rs @@ -1,5 +1,6 @@ //! Loads and formats OP receipt RPC response. +use alloy_consensus::transaction::TransactionMeta; use alloy_eips::eip2718::Encodable2718; use alloy_rpc_types_eth::{Log, TransactionReceipt}; use op_alloy_consensus::{OpDepositReceipt, OpDepositReceiptWithBloom, OpReceiptEnvelope}; @@ -9,7 +10,6 @@ use reth_optimism_chainspec::OpChainSpec; use reth_optimism_evm::RethL1BlockInfo; use reth_optimism_forks::OpHardforks; use reth_optimism_primitives::{OpReceipt, OpTransactionSigned}; -use reth_primitives::TransactionMeta; use reth_provider::{ChainSpecProvider, ReceiptProvider, TransactionsProvider}; use reth_rpc_eth_api::{helpers::LoadReceipt, FromEthApiError, RpcReceipt}; use reth_rpc_eth_types::{receipt::build_receipt, EthApiError}; @@ -41,7 +41,7 @@ where )))?; let l1_block_info = - reth_optimism_evm::extract_l1_info(&block.body).map_err(OpEthApiError::from)?; + reth_optimism_evm::extract_l1_info(block.body()).map_err(OpEthApiError::from)?; Ok(OpReceiptBuilder::new( &self.inner.eth_api.provider().chain_spec(), diff --git a/crates/payload/validator/Cargo.toml b/crates/payload/validator/Cargo.toml index fee8d01d2baa..5c34a9f456f9 100644 --- a/crates/payload/validator/Cargo.toml +++ b/crates/payload/validator/Cargo.toml @@ -16,7 +16,6 @@ workspace = true reth-chainspec.workspace = true reth-primitives.workspace = true reth-primitives-traits.workspace = true -reth-rpc-types-compat.workspace = true # alloy alloy-rpc-types = { workspace = true, features = ["engine"] } diff --git a/crates/payload/validator/src/lib.rs b/crates/payload/validator/src/lib.rs index 30f1ca02b964..e696e557afa0 100644 --- a/crates/payload/validator/src/lib.rs +++ b/crates/payload/validator/src/lib.rs @@ -14,7 +14,6 @@ use alloy_rpc_types::engine::{ use reth_chainspec::EthereumHardforks; use reth_primitives::{BlockBody, BlockExt, Header, SealedBlock}; use reth_primitives_traits::SignedTransaction; -use reth_rpc_types_compat::engine::payload::try_into_block; use std::sync::Arc; /// Execution payload validator. @@ -121,7 +120,7 @@ impl ExecutionPayloadValidator { let expected_hash = payload.block_hash(); // First parse the block - let sealed_block = try_into_block(payload, &sidecar)?.seal_slow(); + let sealed_block = payload.try_into_block_with_sidecar(&sidecar)?.seal_slow(); // Ensure the hash included in the payload matches the block hash if expected_hash != sealed_block.hash() { @@ -132,11 +131,11 @@ impl ExecutionPayloadValidator { } if self.is_cancun_active_at_timestamp(sealed_block.timestamp) { - if sealed_block.header.blob_gas_used.is_none() { + if sealed_block.blob_gas_used.is_none() { // cancun active but blob gas used not present return Err(PayloadError::PostCancunBlockWithoutBlobGasUsed) } - if sealed_block.header.excess_blob_gas.is_none() { + if sealed_block.excess_blob_gas.is_none() { // cancun active but excess blob gas not present return Err(PayloadError::PostCancunBlockWithoutExcessBlobGas) } @@ -145,15 +144,15 @@ impl ExecutionPayloadValidator { return Err(PayloadError::PostCancunWithoutCancunFields) } } else { - if sealed_block.body.has_eip4844_transactions() { + if sealed_block.body().has_eip4844_transactions() { // cancun not active but blob transactions present return Err(PayloadError::PreCancunBlockWithBlobTransactions) } - if sealed_block.header.blob_gas_used.is_some() { + if sealed_block.blob_gas_used.is_some() { // cancun not active but blob gas used present return Err(PayloadError::PreCancunBlockWithBlobGasUsed) } - if sealed_block.header.excess_blob_gas.is_some() { + if sealed_block.excess_blob_gas.is_some() { // cancun not active but excess blob gas present return Err(PayloadError::PreCancunBlockWithExcessBlobGas) } @@ -164,13 +163,13 @@ impl ExecutionPayloadValidator { } let shanghai_active = self.is_shanghai_active_at_timestamp(sealed_block.timestamp); - if !shanghai_active && sealed_block.body.withdrawals.is_some() { + if !shanghai_active && sealed_block.body().withdrawals.is_some() { // shanghai not active but withdrawals present return Err(PayloadError::PreShanghaiBlockWithWithdrawals) } if !self.is_prague_active_at_timestamp(sealed_block.timestamp) && - sealed_block.body.has_eip7702_transactions() + sealed_block.body().has_eip7702_transactions() { return Err(PayloadError::PrePragueBlockWithEip7702Transactions) } diff --git a/crates/primitives-traits/Cargo.toml b/crates/primitives-traits/Cargo.toml index a84394033704..23589be58283 100644 --- a/crates/primitives-traits/Cargo.toml +++ b/crates/primitives-traits/Cargo.toml @@ -49,6 +49,7 @@ serde = { workspace = true, optional = true} arbitrary = { workspace = true, features = ["derive"], optional = true } proptest = { workspace = true, optional = true } proptest-arbitrary-interop = { workspace = true, optional = true } +rayon = { workspace = true, optional = true } [dev-dependencies] reth-codecs.workspace = true @@ -142,3 +143,6 @@ reth-codec = [ op = [ "dep:op-alloy-consensus", ] +rayon = [ + "dep:rayon", +] diff --git a/crates/primitives-traits/src/block/body.rs b/crates/primitives-traits/src/block/body.rs index 37342733b4c9..a68aaa0157b6 100644 --- a/crates/primitives-traits/src/block/body.rs +++ b/crates/primitives-traits/src/block/body.rs @@ -6,13 +6,16 @@ use crate::{ use alloc::{fmt, vec::Vec}; use alloy_consensus::{Header, Transaction}; use alloy_eips::{eip2718::Encodable2718, eip4895::Withdrawals}; -use alloy_primitives::{Bytes, B256}; +use alloy_primitives::{Address, Bytes, B256}; /// Helper trait that unifies all behaviour required by transaction to support full node operations. pub trait FullBlockBody: BlockBody + MaybeSerdeBincodeCompat {} impl FullBlockBody for T where T: BlockBody + MaybeSerdeBincodeCompat {} +#[cfg(feature = "rayon")] +use rayon::prelude::*; + /// Abstraction for block's body. pub trait BlockBody: Send @@ -38,6 +41,11 @@ pub trait BlockBody: /// Returns reference to transactions in block. fn transactions(&self) -> &[Self::Transaction]; + /// Returns an iterator over all transaction hashes in the block body. + fn transaction_hashes_iter(&self) -> impl Iterator + '_ { + self.transactions().iter().map(|tx| tx.tx_hash()) + } + /// Consume the block body and return a [`Vec`] of transactions. fn into_transactions(self) -> Vec; @@ -97,6 +105,39 @@ pub trait BlockBody: fn encoded_2718_transactions(&self) -> Vec { self.encoded_2718_transactions_iter().map(Into::into).collect() } + + /// Recover signer addresses for all transactions in the block body. + fn recover_signers(&self) -> Option> + where + Self::Transaction: SignedTransaction, + { + #[cfg(feature = "rayon")] + { + self.transactions().into_par_iter().map(|tx| tx.recover_signer()).collect() + } + #[cfg(not(feature = "rayon"))] + { + self.transactions().iter().map(|tx| tx.recover_signer()).collect() + } + } + + /// Recover signer addresses for all transactions in the block body _without ensuring that the + /// signature has a low `s` value_. + /// + /// Returns `None`, if some transaction's signature is invalid. + fn recover_signers_unchecked(&self) -> Option> + where + Self::Transaction: SignedTransaction, + { + #[cfg(feature = "rayon")] + { + self.transactions().into_par_iter().map(|tx| tx.recover_signer_unchecked()).collect() + } + #[cfg(not(feature = "rayon"))] + { + self.transactions().iter().map(|tx| tx.recover_signer_unchecked()).collect() + } + } } impl BlockBody for alloy_consensus::BlockBody diff --git a/crates/primitives-traits/src/transaction/mod.rs b/crates/primitives-traits/src/transaction/mod.rs index a75e371e9c50..e474c8993c55 100644 --- a/crates/primitives-traits/src/transaction/mod.rs +++ b/crates/primitives-traits/src/transaction/mod.rs @@ -6,6 +6,8 @@ pub mod signed; pub mod error; +pub use alloy_consensus::transaction::{TransactionInfo, TransactionMeta}; + use crate::{InMemorySize, MaybeCompact, MaybeSerde}; use core::{fmt, hash::Hash}; diff --git a/crates/primitives-traits/src/transaction/signature.rs b/crates/primitives-traits/src/transaction/signature.rs index 1ff56671bf77..06bbb6db14dd 100644 --- a/crates/primitives-traits/src/transaction/signature.rs +++ b/crates/primitives-traits/src/transaction/signature.rs @@ -2,3 +2,31 @@ /// Re-exported signature type pub use alloy_primitives::PrimitiveSignature as Signature; + +#[cfg(test)] +mod tests { + use crate::crypto::secp256k1::recover_signer; + use alloy_primitives::{Address, PrimitiveSignature as Signature, B256, U256}; + use std::str::FromStr; + + #[test] + fn test_recover_signer() { + let signature = Signature::new( + U256::from_str( + "18515461264373351373200002665853028612451056578545711640558177340181847433846", + ) + .unwrap(), + U256::from_str( + "46948507304638947509940763649030358759909902576025900602547168820602576006531", + ) + .unwrap(), + false, + ); + let hash = + B256::from_str("daf5a779ae972f972197303d7b574746c7ef83eadac0f2791ad23db92e4c8e53") + .unwrap(); + let signer = recover_signer(&signature, hash).unwrap(); + let expected = Address::from_str("0x9d8a62f656a8d1615c1294fd71e9cfb3e4855a4f").unwrap(); + assert_eq!(expected, signer); + } +} diff --git a/crates/primitives/src/alloy_compat.rs b/crates/primitives/src/alloy_compat.rs index 2409c535cd3b..fc83e6622e11 100644 --- a/crates/primitives/src/alloy_compat.rs +++ b/crates/primitives/src/alloy_compat.rs @@ -16,14 +16,14 @@ impl TryFrom for SealedBlock { let block_hash = block.header.hash; let block = block.try_map_transactions(|tx| tx.try_into())?; - Ok(Self { - header: SealedHeader::new(block.header.inner.into_header_with_defaults(), block_hash), - body: BlockBody { + Ok(Self::new( + SealedHeader::new(block.header.inner.into_header_with_defaults(), block_hash), + BlockBody { transactions: block.transactions.into_transactions().collect(), ommers: Default::default(), withdrawals: block.withdrawals.map(|w| w.into_inner().into()), }, - }) + )) } } diff --git a/crates/primitives/src/block.rs b/crates/primitives/src/block.rs index 399ebaa24af9..acf76b1e591e 100644 --- a/crates/primitives/src/block.rs +++ b/crates/primitives/src/block.rs @@ -1,6 +1,6 @@ use crate::{ - traits::BlockExt, transaction::SignedTransactionIntoRecoveredExt, BlockBodyTxExt, GotExpected, - RecoveredTx, SealedHeader, TransactionSigned, + traits::BlockExt, transaction::SignedTransactionIntoRecoveredExt, GotExpected, RecoveredTx, + SealedHeader, TransactionSigned, }; use alloc::vec::Vec; use alloy_consensus::Header; @@ -169,7 +169,7 @@ pub struct SealedBlock { #[deref_mut] pub header: SealedHeader, /// Block body. - pub body: B, + body: B, } impl SealedBlock { @@ -190,6 +190,16 @@ impl SealedBlock { &self.body } + /// Consumes the block and returns the header. + pub fn into_header(self) -> H { + self.header.unseal() + } + + /// Consumes the block and returns the body. + pub fn into_body(self) -> B { + self.body + } + /// Splits the [`BlockBody`] and [`SealedHeader`] into separate components #[inline] pub fn split_header_body(self) -> (SealedHeader, B) { diff --git a/crates/primitives/src/lib.rs b/crates/primitives/src/lib.rs index 9b7cf7d13cc0..d44391de7cd9 100644 --- a/crates/primitives/src/lib.rs +++ b/crates/primitives/src/lib.rs @@ -43,11 +43,14 @@ pub use reth_primitives_traits::{ }; pub use static_file::StaticFileSegment; -pub use alloy_consensus::{transaction::PooledTransaction, ReceiptWithBloom}; +pub use alloy_consensus::{ + transaction::{PooledTransaction, TransactionMeta}, + ReceiptWithBloom, +}; pub use transaction::{ util::secp256k1::{public_key_to_address, recover_signer_unchecked, sign_message}, InvalidTransactionError, PooledTransactionsElementEcRecovered, RecoveredTx, Transaction, - TransactionMeta, TransactionSigned, TransactionSignedEcRecovered, TxType, + TransactionSigned, TransactionSignedEcRecovered, TxType, }; // Re-exports diff --git a/crates/primitives/src/traits.rs b/crates/primitives/src/traits.rs index 3f009bba84bb..08a8ab3e665a 100644 --- a/crates/primitives/src/traits.rs +++ b/crates/primitives/src/traits.rs @@ -1,7 +1,4 @@ -use crate::{ - transaction::{recover_signers, recover_signers_unchecked}, - BlockWithSenders, SealedBlock, -}; +use crate::{BlockWithSenders, SealedBlock}; use alloc::vec::Vec; use reth_primitives_traits::{Block, BlockBody, SealedHeader, SignedTransaction}; use revm_primitives::{Address, B256}; @@ -13,7 +10,7 @@ pub trait BlockExt: Block { /// Calculate the header hash and seal the block so that it can't be changed. fn seal_slow(self) -> SealedBlock { let (header, body) = self.split(); - SealedBlock { header: SealedHeader::seal(header), body } + SealedBlock::new(SealedHeader::seal(header), body) } /// Seal the block with a known hash. @@ -21,7 +18,7 @@ pub trait BlockExt: Block { /// WARNING: This method does not perform validation whether the hash is correct. fn seal(self, hash: B256) -> SealedBlock { let (header, body) = self.split(); - SealedBlock { header: SealedHeader::new(header, hash), body } + SealedBlock::new(SealedHeader::new(header, hash), body) } /// Expensive operation that recovers transaction signer. @@ -52,7 +49,6 @@ pub trait BlockExt: Block { /// /// If the number of senders does not match the number of transactions in the block, this falls /// back to manually recovery, but _without ensuring that the signature has a low `s` value_. - /// See also [`recover_signers_unchecked`] /// /// Returns an error if a signature is invalid. #[track_caller] @@ -87,28 +83,3 @@ pub trait BlockExt: Block { } impl BlockExt for T {} - -/// Extension trait for [`BlockBody`] adding helper methods operating with transactions. -pub trait BlockBodyTxExt: BlockBody { - /// Recover signer addresses for all transactions in the block body. - fn recover_signers(&self) -> Option> - where - Self::Transaction: SignedTransaction, - { - recover_signers(self.transactions(), self.transactions().len()) - } - - /// Recover signer addresses for all transactions in the block body _without ensuring that the - /// signature has a low `s` value_. - /// - /// Returns `None`, if some transaction's signature is invalid, see also - /// [`recover_signers_unchecked`]. - fn recover_signers_unchecked(&self) -> Option> - where - Self::Transaction: SignedTransaction, - { - recover_signers_unchecked(self.transactions(), self.transactions().len()) - } -} - -impl BlockBodyTxExt for T {} diff --git a/crates/primitives/src/transaction/meta.rs b/crates/primitives/src/transaction/meta.rs deleted file mode 100644 index c7cb9d8b697d..000000000000 --- a/crates/primitives/src/transaction/meta.rs +++ /dev/null @@ -1,20 +0,0 @@ -use alloy_primitives::B256; - -/// Additional fields in the context of a block that contains this transaction. -#[derive(Debug, Clone, Copy, Default, Eq, PartialEq)] -pub struct TransactionMeta { - /// Hash of the transaction. - pub tx_hash: B256, - /// Index of the transaction in the block - pub index: u64, - /// Hash of the block. - pub block_hash: B256, - /// Number of the block. - pub block_number: u64, - /// Base fee of the block. - pub base_fee: Option, - /// The excess blob gas of the block. - pub excess_blob_gas: Option, - /// The block's timestamp. - pub timestamp: u64, -} diff --git a/crates/primitives/src/transaction/mod.rs b/crates/primitives/src/transaction/mod.rs index ca971550c373..b7ca75f87457 100644 --- a/crates/primitives/src/transaction/mod.rs +++ b/crates/primitives/src/transaction/mod.rs @@ -19,7 +19,6 @@ use alloy_primitives::{ use alloy_rlp::{Decodable, Encodable, Error as RlpError, Header}; use core::hash::{Hash, Hasher}; use derive_more::{AsRef, Deref}; -pub use meta::TransactionMeta; use once_cell as _; #[cfg(not(feature = "std"))] use once_cell::sync::{Lazy as LazyLock, OnceCell as OnceLock}; @@ -49,7 +48,6 @@ pub mod signature; pub mod util; pub(crate) mod access_list; -mod meta; mod pooled; mod tx_type; @@ -911,37 +909,6 @@ impl TransactionSigned { *self.tx_hash() } - /// Recovers a list of signers from a transaction list iterator. - /// - /// Returns `None`, if some transaction's signature is invalid, see also - /// [`Self::recover_signer`]. - pub fn recover_signers<'a, T>(txes: T, num_txes: usize) -> Option> - where - T: IntoParallelIterator + IntoIterator + Send, - { - if num_txes < *PARALLEL_SENDER_RECOVERY_THRESHOLD { - txes.into_iter().map(|tx| tx.recover_signer()).collect() - } else { - txes.into_par_iter().map(|tx| tx.recover_signer()).collect() - } - } - - /// Recovers a list of signers from a transaction list iterator _without ensuring that the - /// signature has a low `s` value_. - /// - /// Returns `None`, if some transaction's signature is invalid, see also - /// [`Self::recover_signer_unchecked`]. - pub fn recover_signers_unchecked<'a, T>(txes: T, num_txes: usize) -> Option> - where - T: IntoParallelIterator + IntoIterator, - { - if num_txes < *PARALLEL_SENDER_RECOVERY_THRESHOLD { - txes.into_iter().map(|tx| tx.recover_signer_unchecked()).collect() - } else { - txes.into_par_iter().map(|tx| tx.recover_signer_unchecked()).collect() - } - } - /// Returns the [`RecoveredTx`] transaction with the given sender. #[inline] pub const fn with_signer(self, signer: Address) -> RecoveredTx { @@ -2208,38 +2175,6 @@ mod tests { assert_eq!(data.as_slice(), b.as_slice()); } - #[cfg(feature = "secp256k1")] - proptest::proptest! { - #![proptest_config(proptest::prelude::ProptestConfig::with_cases(1))] - - #[test] - fn test_parallel_recovery_order(txes in proptest::collection::vec( - proptest_arbitrary_interop::arb::(), - *crate::transaction::PARALLEL_SENDER_RECOVERY_THRESHOLD * 5 - )) { - let mut rng =rand::thread_rng(); - let secp = secp256k1::Secp256k1::new(); - let txes: Vec = txes.into_iter().map(|mut tx| { - if let Some(chain_id) = tx.chain_id() { - // Otherwise we might overflow when calculating `v` on `recalculate_hash` - tx.set_chain_id(chain_id % (u64::MAX / 2 - 36)); - } - - let key_pair = secp256k1::Keypair::new(&secp, &mut rng); - - let signature = - crate::sign_message(B256::from_slice(&key_pair.secret_bytes()[..]), tx.signature_hash()).unwrap(); - - TransactionSigned::new_unhashed(tx, signature) - }).collect(); - - let parallel_senders = TransactionSigned::recover_signers(&txes, txes.len()).unwrap(); - let seq_senders = txes.iter().map(|tx| tx.recover_signer()).collect::>>().unwrap(); - - assert_eq!(parallel_senders, seq_senders); - } - } - // #[test] fn recover_legacy_singer() { diff --git a/crates/primitives/src/transaction/signature.rs b/crates/primitives/src/transaction/signature.rs index 03b6327df2e9..cc5df1d74ca2 100644 --- a/crates/primitives/src/transaction/signature.rs +++ b/crates/primitives/src/transaction/signature.rs @@ -1,53 +1 @@ pub use reth_primitives_traits::crypto::secp256k1::{recover_signer, recover_signer_unchecked}; - -#[cfg(test)] -mod tests { - use crate::transaction::signature::{recover_signer, recover_signer_unchecked}; - use alloy_eips::{eip2718::Decodable2718, eip7702::constants::SECP256K1N_HALF}; - use alloy_primitives::{hex, Address, PrimitiveSignature as Signature, B256, U256}; - use reth_primitives_traits::SignedTransaction; - use std::str::FromStr; - - #[test] - fn test_recover_signer() { - let signature = Signature::new( - U256::from_str( - "18515461264373351373200002665853028612451056578545711640558177340181847433846", - ) - .unwrap(), - U256::from_str( - "46948507304638947509940763649030358759909902576025900602547168820602576006531", - ) - .unwrap(), - false, - ); - let hash = - B256::from_str("daf5a779ae972f972197303d7b574746c7ef83eadac0f2791ad23db92e4c8e53") - .unwrap(); - let signer = recover_signer(&signature, hash).unwrap(); - let expected = Address::from_str("0x9d8a62f656a8d1615c1294fd71e9cfb3e4855a4f").unwrap(); - assert_eq!(expected, signer); - } - - #[test] - fn eip_2_reject_high_s_value() { - // This pre-homestead transaction has a high `s` value and should be rejected by the - // `recover_signer` method: - // https://etherscan.io/getRawTx?tx=0x9e6e19637bb625a8ff3d052b7c2fe57dc78c55a15d258d77c43d5a9c160b0384 - // - // Block number: 46170 - let raw_tx = hex!("f86d8085746a52880082520894c93f2250589a6563f5359051c1ea25746549f0d889208686e75e903bc000801ba034b6fdc33ea520e8123cf5ac4a9ff476f639cab68980cd9366ccae7aef437ea0a0e517caa5f50e27ca0d1e9a92c503b4ccb039680c6d9d0c71203ed611ea4feb33"); - let tx = crate::transaction::TransactionSigned::decode_2718(&mut &raw_tx[..]).unwrap(); - let signature = tx.signature(); - - // make sure we know it's greater than SECP256K1N_HALF - assert!(signature.s() > SECP256K1N_HALF); - - // recover signer, expect failure - let hash = tx.hash(); - assert!(recover_signer(signature, hash).is_none()); - - // use unchecked, ensure it succeeds (the signature is valid if not for EIP-2) - assert!(recover_signer_unchecked(signature, hash).is_some()); - } -} diff --git a/crates/prune/prune/src/segments/mod.rs b/crates/prune/prune/src/segments/mod.rs index 1dc907732894..25f4b39cbb93 100644 --- a/crates/prune/prune/src/segments/mod.rs +++ b/crates/prune/prune/src/segments/mod.rs @@ -242,7 +242,8 @@ mod tests { let range = input.get_next_tx_num_range(&provider).expect("Expected range").unwrap(); // Calculate the total number of transactions - let num_txs = blocks.iter().map(|block| block.body.transactions.len() as u64).sum::(); + let num_txs = + blocks.iter().map(|block| block.body().transactions.len() as u64).sum::(); assert_eq!(range, 0..=num_txs - 1); } @@ -288,7 +289,8 @@ mod tests { let range = input.get_next_tx_num_range(&provider).expect("Expected range").unwrap(); // Calculate the total number of transactions - let num_txs = blocks.iter().map(|block| block.body.transactions.len() as u64).sum::(); + let num_txs = + blocks.iter().map(|block| block.body().transactions.len() as u64).sum::(); assert_eq!(range, 0..=num_txs - 1,); } @@ -322,7 +324,8 @@ mod tests { // Get the last tx number // Calculate the total number of transactions - let num_txs = blocks.iter().map(|block| block.body.transactions.len() as u64).sum::(); + let num_txs = + blocks.iter().map(|block| block.body().transactions.len() as u64).sum::(); let max_range = num_txs - 1; // Create a prune input with a previous checkpoint that is the last tx number diff --git a/crates/prune/prune/src/segments/receipts.rs b/crates/prune/prune/src/segments/receipts.rs index dbea32c47fe5..922d11e83a64 100644 --- a/crates/prune/prune/src/segments/receipts.rs +++ b/crates/prune/prune/src/segments/receipts.rs @@ -113,8 +113,8 @@ mod tests { let mut receipts = Vec::new(); for block in &blocks { - receipts.reserve_exact(block.body.transactions.len()); - for transaction in &block.body.transactions { + receipts.reserve_exact(block.body().transactions.len()); + for transaction in &block.body().transactions { receipts .push((receipts.len() as u64, random_receipt(&mut rng, transaction, Some(0)))); } @@ -124,7 +124,7 @@ mod tests { assert_eq!( db.table::().unwrap().len(), - blocks.iter().map(|block| block.body.transactions.len()).sum::() + blocks.iter().map(|block| block.body().transactions.len()).sum::() ); assert_eq!( db.table::().unwrap().len(), @@ -158,7 +158,7 @@ mod tests { let last_pruned_tx_number = blocks .iter() .take(to_block as usize) - .map(|block| block.body.transactions.len()) + .map(|block| block.body().transactions.len()) .sum::() .min( next_tx_number_to_prune as usize + @@ -186,7 +186,7 @@ mod tests { let last_pruned_block_number = blocks .iter() .fold_while((0, 0), |(_, mut tx_count), block| { - tx_count += block.body.transactions.len(); + tx_count += block.body().transactions.len(); if tx_count > last_pruned_tx_number { Done((block.number, tx_count)) diff --git a/crates/prune/prune/src/segments/static_file/transactions.rs b/crates/prune/prune/src/segments/static_file/transactions.rs index 12ffbf727987..19a6fd06d0e7 100644 --- a/crates/prune/prune/src/segments/static_file/transactions.rs +++ b/crates/prune/prune/src/segments/static_file/transactions.rs @@ -124,7 +124,7 @@ mod tests { db.insert_blocks(blocks.iter(), StorageKind::Database(None)).expect("insert blocks"); let transactions = - blocks.iter().flat_map(|block| &block.body.transactions).collect::>(); + blocks.iter().flat_map(|block| &block.body().transactions).collect::>(); assert_eq!(db.table::().unwrap().len(), transactions.len()); @@ -174,7 +174,7 @@ mod tests { let last_pruned_tx_number = blocks .iter() .take(to_block as usize) - .map(|block| block.body.transactions.len()) + .map(|block| block.body().transactions.len()) .sum::() .min( next_tx_number_to_prune as usize + @@ -185,7 +185,7 @@ mod tests { let last_pruned_block_number = blocks .iter() .fold_while((0, 0), |(_, mut tx_count), block| { - tx_count += block.body.transactions.len(); + tx_count += block.body().transactions.len(); if tx_count > last_pruned_tx_number { Done((block.number, tx_count)) diff --git a/crates/prune/prune/src/segments/user/receipts_by_logs.rs b/crates/prune/prune/src/segments/user/receipts_by_logs.rs index 91bad6f67ed2..b82f38e5f1a8 100644 --- a/crates/prune/prune/src/segments/user/receipts_by_logs.rs +++ b/crates/prune/prune/src/segments/user/receipts_by_logs.rs @@ -273,12 +273,12 @@ mod tests { let (deposit_contract_addr, _) = random_eoa_account(&mut rng); for block in &blocks { - receipts.reserve_exact(block.body.size()); - for (txi, transaction) in block.body.transactions.iter().enumerate() { + receipts.reserve_exact(block.body().size()); + for (txi, transaction) in block.body().transactions.iter().enumerate() { let mut receipt = random_receipt(&mut rng, transaction, Some(1)); receipt.logs.push(random_log( &mut rng, - (txi == (block.body.transactions.len() - 1)).then_some(deposit_contract_addr), + (txi == (block.body().transactions.len() - 1)).then_some(deposit_contract_addr), Some(1), )); receipts.push((receipts.len() as u64, receipt)); @@ -288,7 +288,7 @@ mod tests { assert_eq!( db.table::().unwrap().len(), - blocks.iter().map(|block| block.body.transactions.len()).sum::() + blocks.iter().map(|block| block.body().transactions.len()).sum::() ); assert_eq!( db.table::().unwrap().len(), @@ -337,7 +337,7 @@ mod tests { assert_eq!( db.table::().unwrap().len(), - blocks.iter().map(|block| block.body.transactions.len()).sum::() - + blocks.iter().map(|block| block.body().transactions.len()).sum::() - ((pruned_tx + 1) - unprunable) as usize ); diff --git a/crates/prune/prune/src/segments/user/sender_recovery.rs b/crates/prune/prune/src/segments/user/sender_recovery.rs index bc4ba5ab0674..a119b8ca8fd1 100644 --- a/crates/prune/prune/src/segments/user/sender_recovery.rs +++ b/crates/prune/prune/src/segments/user/sender_recovery.rs @@ -111,8 +111,8 @@ mod tests { let mut transaction_senders = Vec::new(); for block in &blocks { - transaction_senders.reserve_exact(block.body.transactions.len()); - for transaction in &block.body.transactions { + transaction_senders.reserve_exact(block.body().transactions.len()); + for transaction in &block.body().transactions { transaction_senders.push(( transaction_senders.len() as u64, transaction.recover_signer().expect("recover signer"), @@ -124,7 +124,7 @@ mod tests { assert_eq!( db.table::().unwrap().len(), - blocks.iter().map(|block| block.body.transactions.len()).sum::() + blocks.iter().map(|block| block.body().transactions.len()).sum::() ); assert_eq!( db.table::().unwrap().len(), @@ -159,7 +159,7 @@ mod tests { let last_pruned_tx_number = blocks .iter() .take(to_block as usize) - .map(|block| block.body.transactions.len()) + .map(|block| block.body().transactions.len()) .sum::() .min( next_tx_number_to_prune as usize + @@ -170,7 +170,7 @@ mod tests { let last_pruned_block_number = blocks .iter() .fold_while((0, 0), |(_, mut tx_count), block| { - tx_count += block.body.transactions.len(); + tx_count += block.body().transactions.len(); if tx_count > last_pruned_tx_number { Done((block.number, tx_count)) diff --git a/crates/prune/prune/src/segments/user/transaction_lookup.rs b/crates/prune/prune/src/segments/user/transaction_lookup.rs index f2331fee1b01..f1637123ad02 100644 --- a/crates/prune/prune/src/segments/user/transaction_lookup.rs +++ b/crates/prune/prune/src/segments/user/transaction_lookup.rs @@ -139,8 +139,8 @@ mod tests { let mut tx_hash_numbers = Vec::new(); for block in &blocks { - tx_hash_numbers.reserve_exact(block.body.transactions.len()); - for transaction in &block.body.transactions { + tx_hash_numbers.reserve_exact(block.body().transactions.len()); + for transaction in &block.body().transactions { tx_hash_numbers.push((transaction.hash(), tx_hash_numbers.len() as u64)); } } @@ -149,7 +149,7 @@ mod tests { assert_eq!( db.table::().unwrap().len(), - blocks.iter().map(|block| block.body.transactions.len()).sum::() + blocks.iter().map(|block| block.body().transactions.len()).sum::() ); assert_eq!( db.table::().unwrap().len(), @@ -184,7 +184,7 @@ mod tests { let last_pruned_tx_number = blocks .iter() .take(to_block as usize) - .map(|block| block.body.transactions.len()) + .map(|block| block.body().transactions.len()) .sum::() .min( next_tx_number_to_prune as usize + @@ -195,7 +195,7 @@ mod tests { let last_pruned_block_number = blocks .iter() .fold_while((0, 0), |(_, mut tx_count), block| { - tx_count += block.body.transactions.len(); + tx_count += block.body().transactions.len(); if tx_count > last_pruned_tx_number { Done((block.number, tx_count)) diff --git a/crates/rpc/rpc-builder/tests/it/auth.rs b/crates/rpc/rpc-builder/tests/it/auth.rs index 390ea7d6ba40..ca5db0494e66 100644 --- a/crates/rpc/rpc-builder/tests/it/auth.rs +++ b/crates/rpc/rpc-builder/tests/it/auth.rs @@ -2,15 +2,16 @@ use crate::utils::launch_auth; use alloy_primitives::U64; -use alloy_rpc_types_engine::{ForkchoiceState, PayloadId, TransitionConfiguration}; +use alloy_rpc_types_engine::{ + ExecutionPayloadInputV2, ExecutionPayloadV1, ForkchoiceState, PayloadId, + TransitionConfiguration, +}; use jsonrpsee::core::client::{ClientT, SubscriptionClientT}; use reth_ethereum_engine_primitives::EthEngineTypes; -use reth_primitives::{Block, BlockExt}; +use reth_primitives::{Block, BlockExt, TransactionSigned}; use reth_rpc_api::clients::EngineApiClient; use reth_rpc_layer::JwtSecret; -use reth_rpc_types_compat::engine::payload::{ - block_to_payload_v1, convert_block_to_payload_input_v2, -}; +use reth_rpc_types_compat::engine::payload::block_to_payload_v1; #[allow(unused_must_use)] async fn test_basic_engine_calls(client: &C) where @@ -18,7 +19,16 @@ where { let block = Block::default().seal_slow(); EngineApiClient::new_payload_v1(client, block_to_payload_v1(block.clone())).await; - EngineApiClient::new_payload_v2(client, convert_block_to_payload_input_v2(block)).await; + EngineApiClient::new_payload_v2( + client, + ExecutionPayloadInputV2 { + execution_payload: ExecutionPayloadV1::from_block_slow::( + &block.unseal(), + ), + withdrawals: None, + }, + ) + .await; EngineApiClient::fork_choice_updated_v1(client, ForkchoiceState::default(), None).await; EngineApiClient::get_payload_v1(client, PayloadId::new([0, 0, 0, 0, 0, 0, 0, 0])).await; EngineApiClient::get_payload_v2(client, PayloadId::new([0, 0, 0, 0, 0, 0, 0, 0])).await; diff --git a/crates/rpc/rpc-engine-api/src/engine_api.rs b/crates/rpc/rpc-engine-api/src/engine_api.rs index 85b7ed162d2e..db27d8a1e35d 100644 --- a/crates/rpc/rpc-engine-api/src/engine_api.rs +++ b/crates/rpc/rpc-engine-api/src/engine_api.rs @@ -26,9 +26,7 @@ use reth_payload_primitives::{ }; use reth_primitives::EthereumHardfork; use reth_rpc_api::EngineApiServer; -use reth_rpc_types_compat::engine::payload::{ - convert_payload_input_v2_to_payload, convert_to_payload_body_v1, -}; +use reth_rpc_types_compat::engine::payload::convert_to_payload_body_v1; use reth_storage_api::{BlockReader, HeaderProvider, StateProviderFactory}; use reth_tasks::TaskSpawner; use reth_transaction_pool::TransactionPool; @@ -176,7 +174,7 @@ where &self, payload: ExecutionPayloadInputV2, ) -> EngineApiResult { - let payload = convert_payload_input_v2_to_payload(payload); + let payload = payload.into_payload(); let payload_or_attrs = PayloadOrAttributes::<'_, EngineT::PayloadAttributes>::from_execution_payload( &payload, None, @@ -1031,9 +1029,8 @@ mod tests { use reth_engine_primitives::BeaconEngineMessage; use reth_ethereum_engine_primitives::{EthEngineTypes, EthereumEngineValidator}; use reth_payload_builder::test_utils::spawn_test_payload_service; - use reth_primitives::{Block, SealedBlock}; + use reth_primitives::{Block, TransactionSigned}; use reth_provider::test_utils::MockEthProvider; - use reth_rpc_types_compat::engine::payload::execution_payload_from_sealed_block; use reth_tasks::TokioTaskExecutor; use reth_testing_utils::generators::random_block; use reth_transaction_pool::noop::NoopTransactionPool; @@ -1100,9 +1097,11 @@ mod tests { let (mut handle, api) = setup_engine_api(); tokio::spawn(async move { - api.new_payload_v1(execution_payload_from_sealed_block(SealedBlock::default())) - .await - .unwrap(); + api.new_payload_v1(ExecutionPayloadV1::from_block_slow( + &Block::::default(), + )) + .await + .unwrap(); }); assert_matches!(handle.from_api.recv().await, Some(BeaconEngineMessage::NewPayload { .. })); } @@ -1110,6 +1109,7 @@ mod tests { // tests covering `engine_getPayloadBodiesByRange` and `engine_getPayloadBodiesByHash` mod get_payload_bodies { use super::*; + use alloy_rpc_types_engine::ExecutionPayloadBodyV1; use reth_testing_utils::generators::{self, random_block_range, BlockRangeParams}; #[tokio::test] @@ -1155,7 +1155,7 @@ mod tests { let expected = blocks .iter() .cloned() - .map(|b| Some(convert_to_payload_body_v1(b.unseal::()))) + .map(|b| Some(ExecutionPayloadBodyV1::from_block(b.unseal::()))) .collect::>(); let res = api.get_payload_bodies_by_range_v1(start, count).await.unwrap(); @@ -1197,7 +1197,7 @@ mod tests { if first_missing_range.contains(&b.number) { None } else { - Some(convert_to_payload_body_v1(b.unseal::())) + Some(ExecutionPayloadBodyV1::from_block(b.unseal::())) } }) .collect::>(); @@ -1216,7 +1216,7 @@ mod tests { { None } else { - Some(convert_to_payload_body_v1(b.unseal::())) + Some(ExecutionPayloadBodyV1::from_block(b.unseal::())) } }) .collect::>(); diff --git a/crates/rpc/rpc-engine-api/tests/it/payload.rs b/crates/rpc/rpc-engine-api/tests/it/payload.rs index 61199773e0ed..385607e47f9f 100644 --- a/crates/rpc/rpc-engine-api/tests/it/payload.rs +++ b/crates/rpc/rpc-engine-api/tests/it/payload.rs @@ -1,7 +1,7 @@ //! Some payload tests use alloy_eips::eip4895::Withdrawals; -use alloy_primitives::{Bytes, U256}; +use alloy_primitives::Bytes; use alloy_rlp::{Decodable, Error as RlpError}; use alloy_rpc_types_engine::{ ExecutionPayload, ExecutionPayloadBodyV1, ExecutionPayloadSidecar, ExecutionPayloadV1, @@ -9,12 +9,9 @@ use alloy_rpc_types_engine::{ }; use assert_matches::assert_matches; use reth_primitives::{proofs, Block, SealedBlock, SealedHeader, TransactionSigned}; -use reth_rpc_types_compat::engine::payload::{ - block_to_payload, block_to_payload_v1, convert_to_payload_body_v1, try_into_sealed_block, - try_payload_v1_to_block, -}; +use reth_rpc_types_compat::engine::payload::{block_to_payload, block_to_payload_v1}; use reth_testing_utils::generators::{ - self, random_block, random_block_range, random_header, BlockParams, BlockRangeParams, Rng, + self, random_block, random_block_range, BlockParams, BlockRangeParams, Rng, }; fn transform_block Block>(src: SealedBlock, f: F) -> ExecutionPayload { @@ -24,11 +21,7 @@ fn transform_block Block>(src: SealedBlock, f: F) -> Executi transformed.header.transactions_root = proofs::calculate_transaction_root(&transformed.body.transactions); transformed.header.ommers_hash = proofs::calculate_ommers_root(&transformed.body.ommers); - block_to_payload(SealedBlock { - header: SealedHeader::seal(transformed.header), - body: transformed.body, - }) - .0 + block_to_payload(SealedBlock::new(SealedHeader::seal(transformed.header), transformed.body)).0 } #[test] @@ -39,11 +32,11 @@ fn payload_body_roundtrip() { 0..=99, BlockRangeParams { tx_count: 0..2, ..Default::default() }, ) { - let unsealed = block.clone().unseal::(); - let payload_body: ExecutionPayloadBodyV1 = convert_to_payload_body_v1(unsealed); + let payload_body: ExecutionPayloadBodyV1 = + ExecutionPayloadBodyV1::from_block(block.clone().unseal::()); assert_eq!( - Ok(block.body.transactions), + Ok(block.body().transactions.clone()), payload_body .transactions .iter() @@ -51,12 +44,12 @@ fn payload_body_roundtrip() { .collect::, _>>(), ); let withdraw = payload_body.withdrawals.map(Withdrawals::new); - assert_eq!(block.body.withdrawals, withdraw); + assert_eq!(block.body().withdrawals.clone(), withdraw); } } #[test] -fn payload_validation() { +fn payload_validation_conversion() { let mut rng = generators::rng(); let parent = rng.gen(); let block = random_block( @@ -77,7 +70,8 @@ fn payload_validation() { }); assert_matches!( - try_into_sealed_block(block_with_valid_extra_data, &ExecutionPayloadSidecar::none()), + block_with_valid_extra_data + .try_into_block_with_sidecar::(&ExecutionPayloadSidecar::none()), Ok(_) ); @@ -88,7 +82,7 @@ fn payload_validation() { b }); assert_matches!( - try_into_sealed_block(invalid_extra_data_block, &ExecutionPayloadSidecar::none()), + invalid_extra_data_block.try_into_block_with_sidecar::(&ExecutionPayloadSidecar::none()), Err(PayloadError::ExtraData(data)) if data == block_with_invalid_extra_data ); @@ -98,52 +92,16 @@ fn payload_validation() { b }); assert_matches!( - try_into_sealed_block(block_with_zero_base_fee, &ExecutionPayloadSidecar::none()), + block_with_zero_base_fee.try_into_block_with_sidecar::(&ExecutionPayloadSidecar::none()), Err(PayloadError::BaseFee(val)) if val.is_zero() ); // Invalid encoded transactions - let mut payload_with_invalid_txs: ExecutionPayloadV1 = block_to_payload_v1(block.clone()); + let mut payload_with_invalid_txs: ExecutionPayloadV1 = block_to_payload_v1(block); payload_with_invalid_txs.transactions.iter_mut().for_each(|tx| { *tx = Bytes::new(); }); - let payload_with_invalid_txs = - try_payload_v1_to_block::(payload_with_invalid_txs); + let payload_with_invalid_txs = payload_with_invalid_txs.try_into_block::(); assert_matches!(payload_with_invalid_txs, Err(PayloadError::Decode(RlpError::InputTooShort))); - - // Non empty ommers - let block_with_ommers = transform_block(block.clone(), |mut b| { - b.body.ommers.push(random_header(&mut rng, 100, None).unseal()); - b - }); - assert_matches!( - try_into_sealed_block(block_with_ommers.clone(), &ExecutionPayloadSidecar::none()), - Err(PayloadError::BlockHash { consensus, .. }) - if consensus == block_with_ommers.block_hash() - ); - - // None zero difficulty - let block_with_difficulty = transform_block(block.clone(), |mut b| { - b.header.difficulty = U256::from(1); - b - }); - assert_matches!( - try_into_sealed_block(block_with_difficulty.clone(), &ExecutionPayloadSidecar::none()), - Err(PayloadError::BlockHash { consensus, .. }) if consensus == block_with_difficulty.block_hash() - ); - - // None zero nonce - let block_with_nonce = transform_block(block.clone(), |mut b| { - b.header.nonce = 1u64.into(); - b - }); - assert_matches!( - try_into_sealed_block(block_with_nonce.clone(), &ExecutionPayloadSidecar::none()), - Err(PayloadError::BlockHash { consensus, .. }) if consensus == block_with_nonce.block_hash() - ); - - // Valid block - let valid_block = block; - assert_matches!(TryInto::::try_into(valid_block), Ok(_)); } diff --git a/crates/rpc/rpc-eth-api/src/helpers/block.rs b/crates/rpc/rpc-eth-api/src/helpers/block.rs index 1ae084fbe45f..4cb01d16dab3 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/block.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/block.rs @@ -88,7 +88,7 @@ pub trait EthBlocks: LoadBlock { .provider() .pending_block() .map_err(Self::Error::from_eth_err)? - .map(|block| block.body.transactions().len())) + .map(|block| block.body().transactions().len())) } let block_hash = match self @@ -105,7 +105,7 @@ pub trait EthBlocks: LoadBlock { .get_sealed_block_with_senders(block_hash) .await .map_err(Self::Error::from_eth_err)? - .map(|b| b.body.transactions().len())) + .map(|b| b.body().transactions().len())) } } @@ -188,7 +188,7 @@ pub trait EthBlocks: LoadBlock { self.provider() .pending_block() .map_err(Self::Error::from_eth_err)? - .and_then(|block| block.body.ommers().map(|o| o.to_vec())) + .and_then(|block| block.body().ommers().map(|o| o.to_vec())) } else { self.provider().ommers_by_id(block_id).map_err(Self::Error::from_eth_err)? } diff --git a/crates/rpc/rpc-eth-api/src/helpers/call.rs b/crates/rpc/rpc-eth-api/src/helpers/call.rs index d059299923c5..1b20dd9d9fc2 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/call.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/call.rs @@ -314,11 +314,11 @@ pub trait EthCall: EstimateCall + Call + LoadPendingBlock + LoadBlock + FullEthA let mut replay_block_txs = true; let num_txs = - transaction_index.index().unwrap_or_else(|| block.body.transactions().len()); + transaction_index.index().unwrap_or_else(|| block.body().transactions().len()); // but if all transactions are to be replayed, we can use the state at the block itself, // however only if we're not targeting the pending block, because for pending we can't // rely on the block's state being available - if !is_block_target_pending && num_txs == block.body.transactions().len() { + if !is_block_target_pending && num_txs == block.body().transactions().len() { at = block.hash(); replay_block_txs = false; } diff --git a/crates/rpc/rpc-eth-api/src/helpers/fee.rs b/crates/rpc/rpc-eth-api/src/helpers/fee.rs index 194558873eeb..f2ab11acc3c2 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/fee.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/fee.rs @@ -185,7 +185,7 @@ pub trait EthFees: LoadFee { percentiles, header.gas_used(), header.base_fee_per_gas().unwrap_or_default(), - block.body.transactions(), + block.body().transactions(), &receipts, ) .unwrap_or_default(), diff --git a/crates/rpc/rpc-eth-api/src/helpers/receipt.rs b/crates/rpc/rpc-eth-api/src/helpers/receipt.rs index f663c5863b55..b211676f41b0 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/receipt.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/receipt.rs @@ -1,8 +1,8 @@ //! Loads a receipt from database. Helper trait for `eth_` block and transaction RPC methods, that //! loads receipt data w.r.t. network. +use alloy_consensus::transaction::TransactionMeta; use futures::Future; -use reth_primitives::TransactionMeta; use reth_provider::{ProviderReceipt, ProviderTx, ReceiptProvider, TransactionsProvider}; use crate::{EthApiTypes, RpcNodeCoreExt, RpcReceipt}; diff --git a/crates/rpc/rpc-eth-api/src/helpers/trace.rs b/crates/rpc/rpc-eth-api/src/helpers/trace.rs index 9ef8020f7e6a..a5808b04ccbe 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/trace.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/trace.rs @@ -320,7 +320,7 @@ pub trait Trace: let Some(block) = block else { return Ok(None) }; - if block.body.transactions().is_empty() { + if block.body().transactions().is_empty() { // nothing to trace return Ok(Some(Vec::new())) } @@ -350,7 +350,7 @@ pub trait Trace: // prepare transactions, we do everything upfront to reduce time spent with open // state let max_transactions = - highest_index.map_or(block.body.transactions().len(), |highest| { + highest_index.map_or(block.body().transactions().len(), |highest| { // we need + 1 because the index is 0-based highest as usize + 1 }); diff --git a/crates/rpc/rpc-eth-api/src/helpers/transaction.rs b/crates/rpc/rpc-eth-api/src/helpers/transaction.rs index cb35d7f5df58..6096cb3579ff 100644 --- a/crates/rpc/rpc-eth-api/src/helpers/transaction.rs +++ b/crates/rpc/rpc-eth-api/src/helpers/transaction.rs @@ -1,7 +1,12 @@ //! Database access for `eth_` transaction RPC methods. Loads transaction and receipt data w.r.t. //! network. -use alloy_consensus::{BlockHeader, Transaction}; +use super::{EthApiSpec, EthSigner, LoadBlock, LoadReceipt, LoadState, SpawnBlocking}; +use crate::{ + helpers::estimate::EstimateCall, FromEthApiError, FullEthApiTypes, IntoEthApiError, + RpcNodeCore, RpcNodeCoreExt, RpcReceipt, RpcTransaction, +}; +use alloy_consensus::{transaction::TransactionMeta, BlockHeader, Transaction}; use alloy_dyn_abi::TypedData; use alloy_eips::{eip2718::Encodable2718, BlockId}; use alloy_network::TransactionBuilder; @@ -9,9 +14,7 @@ use alloy_primitives::{Address, Bytes, TxHash, B256}; use alloy_rpc_types_eth::{transaction::TransactionRequest, BlockNumberOrTag, TransactionInfo}; use futures::Future; use reth_node_api::BlockBody; -use reth_primitives::{ - transaction::SignedTransactionIntoRecoveredExt, SealedBlockWithSenders, TransactionMeta, -}; +use reth_primitives::{transaction::SignedTransactionIntoRecoveredExt, SealedBlockWithSenders}; use reth_primitives_traits::SignedTransaction; use reth_provider::{ BlockNumReader, BlockReaderIdExt, ProviderBlock, ProviderReceipt, ProviderTx, ReceiptProvider, @@ -22,12 +25,6 @@ use reth_rpc_types_compat::transaction::{from_recovered, from_recovered_with_blo use reth_transaction_pool::{PoolTransaction, TransactionOrigin, TransactionPool}; use std::sync::Arc; -use super::{EthApiSpec, EthSigner, LoadBlock, LoadReceipt, LoadState, SpawnBlocking}; -use crate::{ - helpers::estimate::EstimateCall, FromEthApiError, FullEthApiTypes, IntoEthApiError, - RpcNodeCore, RpcNodeCoreExt, RpcReceipt, RpcTransaction, -}; - /// Transaction related functions for the [`EthApiServer`](crate::EthApiServer) trait in /// the `eth_` namespace. /// @@ -94,7 +91,7 @@ pub trait EthTransactions: LoadTransaction { self.cache() .get_sealed_block_with_senders(block) .await - .map(|b| b.map(|b| b.body.transactions().to_vec())) + .map(|b| b.map(|b| b.body().transactions().to_vec())) .map_err(Self::Error::from_eth_err) } } diff --git a/crates/rpc/rpc-eth-types/src/cache/mod.rs b/crates/rpc/rpc-eth-types/src/cache/mod.rs index b27ca7dadb52..271f9d214162 100644 --- a/crates/rpc/rpc-eth-types/src/cache/mod.rs +++ b/crates/rpc/rpc-eth-types/src/cache/mod.rs @@ -304,7 +304,7 @@ where } Either::Right(transaction_tx) => { let _ = transaction_tx.send(res.clone().map(|maybe_block| { - maybe_block.map(|block| block.block.body.transactions().to_vec()) + maybe_block.map(|block| block.block.body().transactions().to_vec()) })); } } @@ -350,7 +350,7 @@ where } Either::Right(transaction_tx) => { let _ = transaction_tx.send(res.clone().map(|maybe_block| { - maybe_block.map(|block| block.block.body.transactions().to_vec()) + maybe_block.map(|block| block.block.body().transactions().to_vec()) })); } } diff --git a/crates/rpc/rpc-eth-types/src/fee_history.rs b/crates/rpc/rpc-eth-types/src/fee_history.rs index 9b011820390b..2bf3fc7a1dfa 100644 --- a/crates/rpc/rpc-eth-types/src/fee_history.rs +++ b/crates/rpc/rpc-eth-types/src/fee_history.rs @@ -89,7 +89,7 @@ impl FeeHistoryCache { &percentiles, fee_history_entry.gas_used, fee_history_entry.base_fee_per_gas, - block.body.transactions(), + block.body().transactions(), &receipts, ) .unwrap_or_default(); @@ -370,7 +370,7 @@ impl FeeHistoryEntry { base_fee_per_blob_gas: block .excess_blob_gas() .map(alloy_eips::eip4844::calc_blob_gasprice), - blob_gas_used_ratio: block.body.blob_gas_used() as f64 / + blob_gas_used_ratio: block.body().blob_gas_used() as f64 / alloy_eips::eip4844::MAX_DATA_GAS_PER_BLOCK as f64, excess_blob_gas: block.excess_blob_gas(), blob_gas_used: block.blob_gas_used(), diff --git a/crates/rpc/rpc-eth-types/src/gas_oracle.rs b/crates/rpc/rpc-eth-types/src/gas_oracle.rs index e13c9f5a072a..34e430313cf3 100644 --- a/crates/rpc/rpc-eth-types/src/gas_oracle.rs +++ b/crates/rpc/rpc-eth-types/src/gas_oracle.rs @@ -226,7 +226,7 @@ where let parent_hash = block.parent_hash(); // sort the functions by ascending effective tip first - let sorted_transactions = block.body.transactions().iter().sorted_by_cached_key(|tx| { + let sorted_transactions = block.body().transactions().iter().sorted_by_cached_key(|tx| { if let Some(base_fee) = base_fee_per_gas { (*tx).effective_tip_per_gas(base_fee) } else { diff --git a/crates/rpc/rpc-eth-types/src/logs_utils.rs b/crates/rpc/rpc-eth-types/src/logs_utils.rs index 8b2dbaa54412..dd523a19a0a2 100644 --- a/crates/rpc/rpc-eth-types/src/logs_utils.rs +++ b/crates/rpc/rpc-eth-types/src/logs_utils.rs @@ -92,7 +92,7 @@ where if transaction_hash.is_none() { transaction_hash = match &provider_or_block { ProviderOrBlock::Block(block) => { - block.body.transactions().get(receipt_idx).map(|t| t.trie_hash()) + block.body().transactions().get(receipt_idx).map(|t| t.trie_hash()) } ProviderOrBlock::Provider(provider) => { let first_tx_num = match loaded_first_tx_num { diff --git a/crates/rpc/rpc-eth-types/src/receipt.rs b/crates/rpc/rpc-eth-types/src/receipt.rs index 2ddba69566f9..c207eb1bc03e 100644 --- a/crates/rpc/rpc-eth-types/src/receipt.rs +++ b/crates/rpc/rpc-eth-types/src/receipt.rs @@ -1,10 +1,10 @@ //! RPC receipt response builder, extends a layer one receipt with layer two data. use super::{EthApiError, EthResult}; -use alloy_consensus::{ReceiptEnvelope, TxReceipt}; +use alloy_consensus::{transaction::TransactionMeta, ReceiptEnvelope, TxReceipt}; use alloy_primitives::{Address, TxKind}; use alloy_rpc_types_eth::{Log, ReceiptWithBloom, TransactionReceipt}; -use reth_primitives::{Receipt, TransactionMeta, TransactionSigned, TxType}; +use reth_primitives::{Receipt, TransactionSigned, TxType}; use reth_primitives_traits::SignedTransaction; /// Builds an [`TransactionReceipt`] obtaining the inner receipt envelope from the given closure. diff --git a/crates/rpc/rpc-types-compat/Cargo.toml b/crates/rpc/rpc-types-compat/Cargo.toml index 8a6ee44e7cf7..f2d5ce2e2a30 100644 --- a/crates/rpc/rpc-types-compat/Cargo.toml +++ b/crates/rpc/rpc-types-compat/Cargo.toml @@ -19,7 +19,6 @@ reth-primitives-traits.workspace = true # ethereum alloy-eips.workspace = true alloy-primitives.workspace = true -alloy-rlp.workspace = true alloy-rpc-types-eth = { workspace = true, default-features = false, features = ["serde"] } alloy-rpc-types-engine.workspace = true alloy-consensus.workspace = true diff --git a/crates/rpc/rpc-types-compat/src/block.rs b/crates/rpc/rpc-types-compat/src/block.rs index 7d8c1480033a..8d18d110ba15 100644 --- a/crates/rpc/rpc-types-compat/src/block.rs +++ b/crates/rpc/rpc-types-compat/src/block.rs @@ -47,7 +47,7 @@ where B: BlockTrait, { let block_hash = block_hash.unwrap_or_else(|| block.header().hash_slow()); - let transactions = block.body().transactions().iter().map(|tx| *tx.tx_hash()).collect(); + let transactions = block.body().transaction_hashes_iter().copied().collect(); from_block_with_transactions( block.length(), diff --git a/crates/rpc/rpc-types-compat/src/engine/mod.rs b/crates/rpc/rpc-types-compat/src/engine/mod.rs index aa7456250262..a97d880fe8c2 100644 --- a/crates/rpc/rpc-types-compat/src/engine/mod.rs +++ b/crates/rpc/rpc-types-compat/src/engine/mod.rs @@ -1,3 +1,3 @@ //! Standalone functions for engine specific rpc type conversions pub mod payload; -pub use payload::{block_to_payload_v1, try_into_sealed_block, try_payload_v1_to_block}; +pub use payload::block_to_payload_v1; diff --git a/crates/rpc/rpc-types-compat/src/engine/payload.rs b/crates/rpc/rpc-types-compat/src/engine/payload.rs index 0ed30de6a32c..6645188f3177 100644 --- a/crates/rpc/rpc-types-compat/src/engine/payload.rs +++ b/crates/rpc/rpc-types-compat/src/engine/payload.rs @@ -1,135 +1,26 @@ //! Standalone Conversion Functions for Handling Different Versions of Execution Payloads in //! Ethereum's Engine -use alloy_consensus::{constants::MAXIMUM_EXTRA_DATA_SIZE, Header, EMPTY_OMMER_ROOT_HASH}; -use alloy_eips::{ - eip2718::{Decodable2718, Encodable2718}, - eip4895::Withdrawals, - eip7685::RequestsOrHash, -}; -use alloy_primitives::{B256, U256}; -use alloy_rlp::BufMut; +use alloy_consensus::Header; +use alloy_eips::{eip2718::Encodable2718, eip4895::Withdrawals, eip7685::RequestsOrHash}; +use alloy_primitives::U256; use alloy_rpc_types_engine::{ - payload::{ExecutionPayloadBodyV1, ExecutionPayloadFieldV2, ExecutionPayloadInputV2}, + payload::{ExecutionPayloadBodyV1, ExecutionPayloadFieldV2}, CancunPayloadFields, ExecutionPayload, ExecutionPayloadSidecar, ExecutionPayloadV1, - ExecutionPayloadV2, ExecutionPayloadV3, PayloadError, PraguePayloadFields, -}; -use reth_primitives::{ - proofs::{self}, - Block, BlockBody, BlockExt, SealedBlock, + ExecutionPayloadV2, ExecutionPayloadV3, PraguePayloadFields, }; +use reth_primitives::{BlockBody, SealedBlock}; use reth_primitives_traits::{BlockBody as _, SignedTransaction}; -/// Converts [`ExecutionPayloadV1`] to [`Block`] -pub fn try_payload_v1_to_block( - payload: ExecutionPayloadV1, -) -> Result, PayloadError> { - if payload.extra_data.len() > MAXIMUM_EXTRA_DATA_SIZE { - return Err(PayloadError::ExtraData(payload.extra_data)) - } - - if payload.base_fee_per_gas.is_zero() { - return Err(PayloadError::BaseFee(payload.base_fee_per_gas)) - } - - let transactions = payload - .transactions - .iter() - .map(|tx| { - let mut buf = tx.as_ref(); - - let tx = T::decode_2718(&mut buf).map_err(alloy_rlp::Error::from)?; - - if !buf.is_empty() { - return Err(alloy_rlp::Error::UnexpectedLength); - } - - Ok(tx) - }) - .collect::, _>>()?; - - // Reuse the encoded bytes for root calculation - let transactions_root = - proofs::ordered_trie_root_with_encoder(&payload.transactions, |item, buf| { - buf.put_slice(item) - }); - - let header = Header { - parent_hash: payload.parent_hash, - beneficiary: payload.fee_recipient, - state_root: payload.state_root, - transactions_root, - receipts_root: payload.receipts_root, - withdrawals_root: None, - logs_bloom: payload.logs_bloom, - number: payload.block_number, - gas_limit: payload.gas_limit, - gas_used: payload.gas_used, - timestamp: payload.timestamp, - mix_hash: payload.prev_randao, - // WARNING: It’s allowed for a base fee in EIP1559 to increase unbounded. We assume that - // it will fit in an u64. This is not always necessarily true, although it is extremely - // unlikely not to be the case, a u64 maximum would have 2^64 which equates to 18 ETH per - // gas. - base_fee_per_gas: Some( - payload - .base_fee_per_gas - .try_into() - .map_err(|_| PayloadError::BaseFee(payload.base_fee_per_gas))?, - ), - blob_gas_used: None, - excess_blob_gas: None, - parent_beacon_block_root: None, - requests_hash: None, - extra_data: payload.extra_data, - // Defaults - ommers_hash: EMPTY_OMMER_ROOT_HASH, - difficulty: Default::default(), - nonce: Default::default(), - }; - - Ok(Block { header, body: BlockBody { transactions, ..Default::default() } }) -} - -/// Converts [`ExecutionPayloadV2`] to [`Block`] -pub fn try_payload_v2_to_block( - payload: ExecutionPayloadV2, -) -> Result, PayloadError> { - // this performs the same conversion as the underlying V1 payload, but calculates the - // withdrawals root and adds withdrawals - let mut base_sealed_block = try_payload_v1_to_block(payload.payload_inner)?; - let withdrawals_root = proofs::calculate_withdrawals_root(&payload.withdrawals); - base_sealed_block.body.withdrawals = Some(payload.withdrawals.into()); - base_sealed_block.header.withdrawals_root = Some(withdrawals_root); - Ok(base_sealed_block) -} - -/// Converts [`ExecutionPayloadV3`] to [`Block`] -pub fn try_payload_v3_to_block( - payload: ExecutionPayloadV3, -) -> Result, PayloadError> { - // this performs the same conversion as the underlying V2 payload, but inserts the blob gas - // used and excess blob gas - let mut base_block = try_payload_v2_to_block(payload.payload_inner)?; - - base_block.header.blob_gas_used = Some(payload.blob_gas_used); - base_block.header.excess_blob_gas = Some(payload.excess_blob_gas); - - Ok(base_block) -} - /// Converts [`SealedBlock`] to [`ExecutionPayload`] pub fn block_to_payload( value: SealedBlock>, ) -> (ExecutionPayload, ExecutionPayloadSidecar) { - let cancun = if let Some(parent_beacon_block_root) = value.parent_beacon_block_root { - Some(CancunPayloadFields { + let cancun = + value.parent_beacon_block_root.map(|parent_beacon_block_root| CancunPayloadFields { parent_beacon_block_root, - versioned_hashes: value.body.blob_versioned_hashes_iter().copied().collect(), - }) - } else { - None - }; + versioned_hashes: value.body().blob_versioned_hashes_iter().copied().collect(), + }); let prague = value .requests_hash @@ -141,10 +32,10 @@ pub fn block_to_payload( _ => ExecutionPayloadSidecar::none(), }; - let execution_payload = if value.header.parent_beacon_block_root.is_some() { + let execution_payload = if value.parent_beacon_block_root.is_some() { // block with parent beacon block root: V3 ExecutionPayload::V3(block_to_payload_v3(value)) - } else if value.body.withdrawals.is_some() { + } else if value.body().withdrawals.is_some() { // block with withdrawals: V2 ExecutionPayload::V2(block_to_payload_v2(value)) } else { @@ -160,7 +51,7 @@ pub fn block_to_payload_v1( value: SealedBlock>, ) -> ExecutionPayloadV1 { let transactions = - value.body.transactions.iter().map(|tx| tx.encoded_2718().into()).collect::>(); + value.body().transactions.iter().map(|tx| tx.encoded_2718().into()).collect::>(); ExecutionPayloadV1 { parent_hash: value.parent_hash, fee_recipient: value.beneficiary, @@ -181,10 +72,10 @@ pub fn block_to_payload_v1( /// Converts [`SealedBlock`] to [`ExecutionPayloadV2`] pub fn block_to_payload_v2( - mut value: SealedBlock>, + value: SealedBlock>, ) -> ExecutionPayloadV2 { ExecutionPayloadV2 { - withdrawals: value.body.withdrawals.take().unwrap_or_default().into_inner(), + withdrawals: value.body().withdrawals.clone().unwrap_or_default().into_inner(), payload_inner: block_to_payload_v1(value), } } @@ -205,127 +96,14 @@ pub fn convert_block_to_payload_field_v2( value: SealedBlock>, ) -> ExecutionPayloadFieldV2 { // if there are withdrawals, return V2 - if value.body.withdrawals.is_some() { + if value.body().withdrawals.is_some() { ExecutionPayloadFieldV2::V2(block_to_payload_v2(value)) } else { ExecutionPayloadFieldV2::V1(block_to_payload_v1(value)) } } -/// Converts [`ExecutionPayloadFieldV2`] to [`ExecutionPayload`] -pub fn convert_payload_field_v2_to_payload(value: ExecutionPayloadFieldV2) -> ExecutionPayload { - match value { - ExecutionPayloadFieldV2::V1(payload) => ExecutionPayload::V1(payload), - ExecutionPayloadFieldV2::V2(payload) => ExecutionPayload::V2(payload), - } -} - -/// Converts [`ExecutionPayloadV2`] to [`ExecutionPayloadInputV2`]. -/// -/// An [`ExecutionPayloadInputV2`] should have a [`Some`] withdrawals field if shanghai is active, -/// otherwise the withdrawals field should be [`None`], so the `is_shanghai_active` argument is -/// provided which will either: -/// - include the withdrawals field as [`Some`] if true -/// - set the withdrawals field to [`None`] if false -pub fn convert_payload_v2_to_payload_input_v2( - value: ExecutionPayloadV2, - is_shanghai_active: bool, -) -> ExecutionPayloadInputV2 { - ExecutionPayloadInputV2 { - execution_payload: value.payload_inner, - withdrawals: is_shanghai_active.then_some(value.withdrawals), - } -} - -/// Converts [`ExecutionPayloadInputV2`] to [`ExecutionPayload`] -pub fn convert_payload_input_v2_to_payload(value: ExecutionPayloadInputV2) -> ExecutionPayload { - match value.withdrawals { - Some(withdrawals) => ExecutionPayload::V2(ExecutionPayloadV2 { - payload_inner: value.execution_payload, - withdrawals, - }), - None => ExecutionPayload::V1(value.execution_payload), - } -} - -/// Converts [`SealedBlock`] to [`ExecutionPayloadInputV2`] -pub fn convert_block_to_payload_input_v2(value: SealedBlock) -> ExecutionPayloadInputV2 { - ExecutionPayloadInputV2 { - withdrawals: value.body.withdrawals.clone().map(Withdrawals::into_inner), - execution_payload: block_to_payload_v1(value), - } -} - -/// Tries to create a new unsealed block from the given payload and payload sidecar. -/// -/// Performs additional validation of `extra_data` and `base_fee_per_gas` fields. -/// -/// # Note -/// -/// The log bloom is assumed to be validated during serialization. -/// -/// See -pub fn try_into_block( - value: ExecutionPayload, - sidecar: &ExecutionPayloadSidecar, -) -> Result, PayloadError> { - let mut base_payload = match value { - ExecutionPayload::V1(payload) => try_payload_v1_to_block(payload)?, - ExecutionPayload::V2(payload) => try_payload_v2_to_block(payload)?, - ExecutionPayload::V3(payload) => try_payload_v3_to_block(payload)?, - }; - - base_payload.header.parent_beacon_block_root = sidecar.parent_beacon_block_root(); - base_payload.header.requests_hash = sidecar.requests_hash(); - - Ok(base_payload) -} - -/// Tries to create a sealed new block from the given payload and payload sidecar. -/// -/// Uses [`try_into_block`] to convert from the [`ExecutionPayload`] to [`Block`] and seals the -/// block with its hash. -/// -/// Uses [`validate_block_hash`] to validate the payload block hash and ultimately return the -/// [`SealedBlock`]. -/// -/// # Note -/// -/// Empty ommers, nonce, difficulty, and execution request values are validated upon computing block -/// hash and comparing the value with `payload.block_hash`. -pub fn try_into_sealed_block( - payload: ExecutionPayload, - sidecar: &ExecutionPayloadSidecar, -) -> Result { - let block_hash = payload.block_hash(); - let base_payload = try_into_block(payload, sidecar)?; - - // validate block hash and return - validate_block_hash(block_hash, base_payload) -} - -/// Takes the expected block hash and [`Block`], validating the block and converting it into a -/// [`SealedBlock`]. -/// -/// If the provided block hash does not match the block hash computed from the provided block, this -/// returns [`PayloadError::BlockHash`]. -#[inline] -pub fn validate_block_hash( - expected_block_hash: B256, - block: Block, -) -> Result { - let sealed_block = block.seal_slow(); - if expected_block_hash != sealed_block.hash() { - return Err(PayloadError::BlockHash { - execution: sealed_block.hash(), - consensus: expected_block_hash, - }) - } - - Ok(sealed_block) -} - -/// Converts [`Block`] to [`ExecutionPayloadBodyV1`] +/// Converts a [`reth_primitives_traits::Block`] to [`ExecutionPayloadBodyV1`] pub fn convert_to_payload_body_v1( value: impl reth_primitives_traits::Block, ) -> ExecutionPayloadBodyV1 { @@ -336,32 +114,9 @@ pub fn convert_to_payload_body_v1( } } -/// Transforms a [`SealedBlock`] into a [`ExecutionPayloadV1`] -pub fn execution_payload_from_sealed_block(value: SealedBlock) -> ExecutionPayloadV1 { - let transactions = value.encoded_2718_transactions(); - ExecutionPayloadV1 { - parent_hash: value.parent_hash, - fee_recipient: value.beneficiary, - state_root: value.state_root, - receipts_root: value.receipts_root, - logs_bloom: value.logs_bloom, - prev_randao: value.mix_hash, - block_number: value.number, - gas_limit: value.gas_limit, - gas_used: value.gas_used, - timestamp: value.timestamp, - extra_data: value.extra_data.clone(), - base_fee_per_gas: U256::from(value.base_fee_per_gas.unwrap_or_default()), - block_hash: value.hash(), - transactions, - } -} - #[cfg(test)] mod tests { - use super::{ - block_to_payload_v3, try_into_block, try_payload_v3_to_block, validate_block_hash, - }; + use super::block_to_payload_v3; use alloy_primitives::{b256, hex, Bytes, U256}; use alloy_rpc_types_engine::{ CancunPayloadFields, ExecutionPayload, ExecutionPayloadSidecar, ExecutionPayloadV1, @@ -398,7 +153,7 @@ mod tests { excess_blob_gas: 0x580000, }; - let mut block: Block = try_payload_v3_to_block(new_payload.clone()).unwrap(); + let mut block: Block = new_payload.clone().try_into_block().unwrap(); // this newPayload came with a parent beacon block root, we need to manually insert it // before hashing @@ -441,7 +196,8 @@ mod tests { excess_blob_gas: 0x580000, }; - let _block = try_payload_v3_to_block::(new_payload) + let _block = new_payload + .try_into_block::() .expect_err("execution payload conversion requires typed txs without a rlp header"); } @@ -584,9 +340,13 @@ mod tests { let cancun_fields = CancunPayloadFields { parent_beacon_block_root, versioned_hashes }; // convert into block - let block = try_into_block(payload, &ExecutionPayloadSidecar::v3(cancun_fields)).unwrap(); + let block = payload + .try_into_block_with_sidecar::(&ExecutionPayloadSidecar::v3( + cancun_fields, + )) + .unwrap(); // Ensure the actual hash is calculated if we set the fields to what they should be - validate_block_hash(block_hash_with_blob_fee_fields, block).unwrap(); + assert_eq!(block_hash_with_blob_fee_fields, block.header.hash_slow()); } } diff --git a/crates/rpc/rpc/src/debug.rs b/crates/rpc/rpc/src/debug.rs index d4b8c375705f..8421b371df0a 100644 --- a/crates/rpc/rpc/src/debug.rs +++ b/crates/rpc/rpc/src/debug.rs @@ -103,7 +103,7 @@ where let this = self.clone(); self.eth_api() .spawn_with_state_at_block(block.parent_hash().into(), move |state| { - let mut results = Vec::with_capacity(block.body.transactions().len()); + let mut results = Vec::with_capacity(block.body().transactions().len()); let mut db = CacheDB::new(StateProviderDatabase::new(state)); this.eth_api().apply_pre_execution_changes(&block, &mut db, &cfg, &block_env)?; @@ -527,11 +527,12 @@ where let mut replay_block_txs = true; // if a transaction index is provided, we need to replay the transactions until the index - let num_txs = transaction_index.index().unwrap_or_else(|| block.body.transactions().len()); + let num_txs = + transaction_index.index().unwrap_or_else(|| block.body().transactions().len()); // but if all transactions are to be replayed, we can use the state at the block itself // this works with the exception of the PENDING block, because its state might not exist if // built locally - if !target_block.is_pending() && num_txs == block.body.transactions().len() { + if !target_block.is_pending() && num_txs == block.body().transactions().len() { at = block.hash(); replay_block_txs = false; } diff --git a/crates/rpc/rpc/src/eth/helpers/block.rs b/crates/rpc/rpc/src/eth/helpers/block.rs index 51a76f4e98fe..c23f327848b4 100644 --- a/crates/rpc/rpc/src/eth/helpers/block.rs +++ b/crates/rpc/rpc/src/eth/helpers/block.rs @@ -1,8 +1,7 @@ //! Contains RPC handler implementations specific to blocks. -use alloy_consensus::BlockHeader; +use alloy_consensus::{transaction::TransactionMeta, BlockHeader}; use alloy_rpc_types_eth::{BlockId, TransactionReceipt}; -use reth_primitives::TransactionMeta; use reth_primitives_traits::{BlockBody, SignedTransaction}; use reth_provider::BlockReader; use reth_rpc_eth_api::{ @@ -40,7 +39,7 @@ where let timestamp = block.timestamp(); return block - .body + .body() .transactions() .iter() .zip(receipts.iter()) diff --git a/crates/rpc/rpc/src/eth/helpers/receipt.rs b/crates/rpc/rpc/src/eth/helpers/receipt.rs index 12fbf0957345..4b88e2f6f33b 100644 --- a/crates/rpc/rpc/src/eth/helpers/receipt.rs +++ b/crates/rpc/rpc/src/eth/helpers/receipt.rs @@ -1,6 +1,7 @@ //! Builds an RPC receipt response w.r.t. data layout of network. -use reth_primitives::{Receipt, TransactionMeta, TransactionSigned}; +use alloy_consensus::transaction::TransactionMeta; +use reth_primitives::{Receipt, TransactionSigned}; use reth_provider::{BlockReader, ReceiptProvider, TransactionsProvider}; use reth_rpc_eth_api::{helpers::LoadReceipt, FromEthApiError, RpcNodeCoreExt, RpcReceipt}; use reth_rpc_eth_types::{EthApiError, EthReceiptBuilder}; diff --git a/crates/rpc/rpc/src/trace.rs b/crates/rpc/rpc/src/trace.rs index b98cfce62382..aaf8539ab454 100644 --- a/crates/rpc/rpc/src/trace.rs +++ b/crates/rpc/rpc/src/trace.rs @@ -315,7 +315,7 @@ where all_traces.extend( self.extract_reward_traces( block.header.header(), - block.body.ommers(), + block.body().ommers(), base_block_reward, ) .into_iter() @@ -396,7 +396,7 @@ where { traces.extend(self.extract_reward_traces( block.block.header(), - block.body.ommers(), + block.body().ommers(), base_block_reward, )); } diff --git a/crates/stages/stages/benches/setup/mod.rs b/crates/stages/stages/benches/setup/mod.rs index b2e6d4efcea0..2c1174d63292 100644 --- a/crates/stages/stages/benches/setup/mod.rs +++ b/crates/stages/stages/benches/setup/mod.rs @@ -151,9 +151,10 @@ pub(crate) fn txs_testdata(num_blocks: u64) -> TestStageDB { .unwrap(); let second_block = blocks.get_mut(1).unwrap(); let cloned_second = second_block.clone(); - let mut updated_header = cloned_second.header.unseal(); + let mut updated_header = cloned_second.header.clone().unseal(); updated_header.state_root = root; - *second_block = SealedBlock { header: SealedHeader::seal(updated_header), ..cloned_second }; + *second_block = + SealedBlock::new(SealedHeader::seal(updated_header), cloned_second.into_body()); let offset = transitions.len() as u64; @@ -184,9 +185,9 @@ pub(crate) fn txs_testdata(num_blocks: u64) -> TestStageDB { let last_block = blocks.last_mut().unwrap(); let cloned_last = last_block.clone(); - let mut updated_header = cloned_last.header.unseal(); + let mut updated_header = cloned_last.header.clone().unseal(); updated_header.state_root = root; - *last_block = SealedBlock { header: SealedHeader::seal(updated_header), ..cloned_last }; + *last_block = SealedBlock::new(SealedHeader::seal(updated_header), cloned_last.into_body()); db.insert_blocks(blocks.iter(), StorageKind::Static).unwrap(); diff --git a/crates/stages/stages/src/stages/bodies.rs b/crates/stages/stages/src/stages/bodies.rs index 0f311b1bc9e0..9bc1bcc45ca0 100644 --- a/crates/stages/stages/src/stages/bodies.rs +++ b/crates/stages/stages/src/stages/bodies.rs @@ -519,7 +519,7 @@ mod tests { /// A helper to create a collection of block bodies keyed by their hash. pub(crate) fn body_by_hash(block: &SealedBlock) -> (B256, BlockBody) { - (block.hash(), block.body.clone()) + (block.hash(), block.body().clone()) } /// A helper struct for running the [`BodyStage`]. @@ -592,7 +592,7 @@ mod tests { let body = StoredBlockBodyIndices { first_tx_num: 0, - tx_count: progress.body.transactions.len() as u64, + tx_count: progress.body().transactions.len() as u64, }; static_file_producer.set_block_range(0..=progress.number); @@ -614,7 +614,7 @@ mod tests { if !progress.ommers_hash_is_empty() { tx.put::( progress.number, - StoredBlockOmmers { ommers: progress.body.ommers.clone() }, + StoredBlockOmmers { ommers: progress.body().ommers.clone() }, )?; } @@ -801,7 +801,7 @@ mod tests { } else { let body = this.responses.remove(&header.hash()).expect("requested unknown body"); - response.push(BlockResponse::Full(SealedBlock { header, body })); + response.push(BlockResponse::Full(SealedBlock::new(header, body))); } if response.len() as u64 >= this.batch_size { diff --git a/crates/stages/stages/src/stages/hashing_storage.rs b/crates/stages/stages/src/stages/hashing_storage.rs index 0be84665bee1..6110d2101704 100644 --- a/crates/stages/stages/src/stages/hashing_storage.rs +++ b/crates/stages/stages/src/stages/hashing_storage.rs @@ -353,7 +353,7 @@ mod tests { // Insert last progress data let block_number = progress.number; self.db.commit(|tx| { - progress.body.transactions.iter().try_for_each( + progress.body().transactions.iter().try_for_each( |transaction| -> Result<(), reth_db::DatabaseError> { tx.put::( transaction.hash(), @@ -398,7 +398,7 @@ mod tests { let body = StoredBlockBodyIndices { first_tx_num, - tx_count: progress.body.transactions.len() as u64, + tx_count: progress.body().transactions.len() as u64, }; first_tx_num = next_tx_num; diff --git a/crates/stages/stages/src/stages/merkle.rs b/crates/stages/stages/src/stages/merkle.rs index 8cd7abc7316c..f697ced2dc81 100644 --- a/crates/stages/stages/src/stages/merkle.rs +++ b/crates/stages/stages/src/stages/merkle.rs @@ -520,11 +520,12 @@ mod tests { accounts.iter().map(|(addr, acc)| (*addr, (*acc, std::iter::empty()))), )?; - let SealedBlock { header, body } = random_block( + let (header, body) = random_block( &mut rng, stage_progress, BlockParams { parent: preblocks.last().map(|b| b.hash()), ..Default::default() }, - ); + ) + .split_header_body(); let mut header = header.unseal(); header.state_root = state_root( @@ -533,7 +534,7 @@ mod tests { .into_iter() .map(|(address, account)| (address, (account, std::iter::empty()))), ); - let sealed_head = SealedBlock { header: SealedHeader::seal(header), body }; + let sealed_head = SealedBlock::new(SealedHeader::seal(header), body); let head_hash = sealed_head.hash(); let mut blocks = vec![sealed_head]; diff --git a/crates/stages/stages/src/stages/mod.rs b/crates/stages/stages/src/stages/mod.rs index fc782f26f012..22ba6e139ca4 100644 --- a/crates/stages/stages/src/stages/mod.rs +++ b/crates/stages/stages/src/stages/mod.rs @@ -267,8 +267,8 @@ mod tests { let mut receipts = Vec::with_capacity(blocks.len()); let mut tx_num = 0u64; for block in &blocks { - let mut block_receipts = Vec::with_capacity(block.body.transactions.len()); - for transaction in &block.body.transactions { + let mut block_receipts = Vec::with_capacity(block.body().transactions.len()); + for transaction in &block.body().transactions { block_receipts.push((tx_num, random_receipt(&mut rng, transaction, Some(0)))); tx_num += 1; } diff --git a/crates/stages/stages/src/stages/prune.rs b/crates/stages/stages/src/stages/prune.rs index 7e5d7af46eef..4bd29882712b 100644 --- a/crates/stages/stages/src/stages/prune.rs +++ b/crates/stages/stages/src/stages/prune.rs @@ -216,7 +216,7 @@ mod tests { ); self.db.insert_blocks(blocks.iter(), StorageKind::Static)?; self.db.insert_transaction_senders( - blocks.iter().flat_map(|block| block.body.transactions.iter()).enumerate().map( + blocks.iter().flat_map(|block| block.body().transactions.iter()).enumerate().map( |(i, tx)| (i as u64, tx.recover_signer().expect("failed to recover signer")), ), )?; diff --git a/crates/stages/stages/src/stages/sender_recovery.rs b/crates/stages/stages/src/stages/sender_recovery.rs index 833246b1b020..f832df7ffeb7 100644 --- a/crates/stages/stages/src/stages/sender_recovery.rs +++ b/crates/stages/stages/src/stages/sender_recovery.rs @@ -477,7 +477,7 @@ mod tests { let expected_progress = seed .iter() .find(|x| { - tx_count += x.body.transactions.len(); + tx_count += x.body().transactions.len(); tx_count as u64 > threshold }) .map(|x| x.number) @@ -536,7 +536,7 @@ mod tests { let mut tx_senders = Vec::new(); let mut tx_number = 0; for block in &blocks[..=max_processed_block] { - for transaction in &block.body.transactions { + for transaction in &block.body().transactions { if block.number > max_pruned_block { tx_senders .push((tx_number, transaction.recover_signer().expect("recover signer"))); @@ -555,7 +555,7 @@ mod tests { tx_number: Some( blocks[..=max_pruned_block as usize] .iter() - .map(|block| block.body.transactions.len() as u64) + .map(|block| block.body().transactions.len() as u64) .sum(), ), prune_mode: PruneMode::Full, @@ -570,9 +570,9 @@ mod tests { EntitiesCheckpoint { processed: blocks[..=max_processed_block] .iter() - .map(|block| block.body.transactions.len() as u64) + .map(|block| block.body().transactions.len() as u64) .sum(), - total: blocks.iter().map(|block| block.body.transactions.len() as u64).sum() + total: blocks.iter().map(|block| block.body().transactions.len() as u64).sum() } ); } diff --git a/crates/stages/stages/src/stages/tx_lookup.rs b/crates/stages/stages/src/stages/tx_lookup.rs index 90f577360980..04542e1e08bf 100644 --- a/crates/stages/stages/src/stages/tx_lookup.rs +++ b/crates/stages/stages/src/stages/tx_lookup.rs @@ -385,7 +385,7 @@ mod tests { let mut tx_hash_numbers = Vec::new(); let mut tx_hash_number = 0; for block in &blocks[..=max_processed_block] { - for transaction in &block.body.transactions { + for transaction in &block.body().transactions { if block.number > max_pruned_block { tx_hash_numbers.push((transaction.hash(), tx_hash_number)); } @@ -403,7 +403,7 @@ mod tests { tx_number: Some( blocks[..=max_pruned_block as usize] .iter() - .map(|block| block.body.transactions.len() as u64) + .map(|block| block.body().transactions.len() as u64) .sum::() .sub(1), // `TxNumber` is 0-indexed ), @@ -419,9 +419,9 @@ mod tests { EntitiesCheckpoint { processed: blocks[..=max_processed_block] .iter() - .map(|block| block.body.transactions.len() as u64) + .map(|block| block.body().transactions.len() as u64) .sum(), - total: blocks.iter().map(|block| block.body.transactions.len() as u64).sum() + total: blocks.iter().map(|block| block.body().transactions.len() as u64).sum() } ); } diff --git a/crates/stages/stages/src/test_utils/test_db.rs b/crates/stages/stages/src/test_utils/test_db.rs index 5a6c12d8e00f..18680c8ec78a 100644 --- a/crates/stages/stages/src/test_utils/test_db.rs +++ b/crates/stages/stages/src/test_utils/test_db.rs @@ -252,10 +252,10 @@ impl TestStageDB { // Insert into body tables. let block_body_indices = StoredBlockBodyIndices { first_tx_num: next_tx_num, - tx_count: block.body.transactions.len() as u64, + tx_count: block.body().transactions.len() as u64, }; - if !block.body.transactions.is_empty() { + if !block.body().transactions.is_empty() { tx.put::( block_body_indices.last_tx_num(), block.number, @@ -263,7 +263,7 @@ impl TestStageDB { } tx.put::(block.number, block_body_indices)?; - let res = block.body.transactions.iter().try_for_each(|body_tx| { + let res = block.body().transactions.iter().try_for_each(|body_tx| { if let Some(txs_writer) = &mut txs_writer { txs_writer.append_transaction(next_tx_num, body_tx)?; } else { diff --git a/crates/static-file/static-file/src/static_file_producer.rs b/crates/static-file/static-file/src/static_file_producer.rs index 66b01235a5d8..7653d0d5af3d 100644 --- a/crates/static-file/static-file/src/static_file_producer.rs +++ b/crates/static-file/static-file/src/static_file_producer.rs @@ -299,7 +299,7 @@ mod tests { let mut receipts = Vec::new(); for block in &blocks { - for transaction in &block.body.transactions { + for transaction in &block.body().transactions { receipts .push((receipts.len() as u64, random_receipt(&mut rng, transaction, Some(0)))); } diff --git a/crates/storage/provider/src/providers/blockchain_provider.rs b/crates/storage/provider/src/providers/blockchain_provider.rs index 830adb553967..73601316d8f0 100644 --- a/crates/storage/provider/src/providers/blockchain_provider.rs +++ b/crates/storage/provider/src/providers/blockchain_provider.rs @@ -9,7 +9,7 @@ use crate::{ StageCheckpointReader, StateProviderBox, StateProviderFactory, StateReader, StaticFileProviderFactory, TransactionVariant, TransactionsProvider, WithdrawalsProvider, }; -use alloy_consensus::Header; +use alloy_consensus::{transaction::TransactionMeta, Header}; use alloy_eips::{ eip4895::{Withdrawal, Withdrawals}, BlockHashOrNumber, BlockId, BlockNumHash, BlockNumberOrTag, @@ -28,8 +28,7 @@ use reth_execution_types::ExecutionOutcome; use reth_node_types::{BlockTy, HeaderTy, NodeTypesWithDB, ReceiptTy, TxTy}; use reth_primitives::{ Account, Block, BlockWithSenders, EthPrimitives, NodePrimitives, Receipt, SealedBlock, - SealedBlockFor, SealedBlockWithSenders, SealedHeader, StorageEntry, TransactionMeta, - TransactionSigned, + SealedBlockFor, SealedBlockWithSenders, SealedHeader, StorageEntry, TransactionSigned, }; use reth_primitives_traits::BlockBody as _; use reth_prune_types::{PruneCheckpoint, PruneSegment}; @@ -882,7 +881,7 @@ mod tests { let receipts: Vec> = database_blocks .iter() .chain(in_memory_blocks.iter()) - .map(|block| block.body.transactions.iter()) + .map(|block| block.body().transactions.iter()) .map(|tx| tx.map(|tx| random_receipt(rng, tx, Some(2))).collect()) .collect(); @@ -1253,11 +1252,11 @@ mod tests { // First in memory block ommers should be found assert_eq!( provider.ommers(first_in_mem_block.number.into())?, - Some(first_in_mem_block.body.ommers.clone()) + Some(first_in_mem_block.body().ommers.clone()) ); assert_eq!( provider.ommers(first_in_mem_block.hash().into())?, - Some(first_in_mem_block.body.ommers.clone()) + Some(first_in_mem_block.body().ommers.clone()) ); // A random hash should return None as the block number is not found @@ -1468,7 +1467,7 @@ mod tests { shainghai_timestamp )? .unwrap(), - block.body.withdrawals.unwrap(), + block.body().withdrawals.clone().unwrap(), "Expected withdrawals_by_block to return correct withdrawals" ); } @@ -1478,7 +1477,7 @@ mod tests { assert_eq!( Some(provider.latest_withdrawal()?.unwrap()), - canonical_block.body.withdrawals.clone().unwrap().pop(), + canonical_block.body().withdrawals.clone().unwrap().pop(), "Expected latest withdrawal to be equal to last withdrawal entry in canonical block" ); @@ -1675,11 +1674,11 @@ mod tests { assert_eq!( provider.ommers_by_id(block_number.into()).unwrap().unwrap_or_default(), - database_block.body.ommers + database_block.body().ommers ); assert_eq!( provider.ommers_by_id(block_hash.into()).unwrap().unwrap_or_default(), - database_block.body.ommers + database_block.body().ommers ); let block_number = in_memory_block.number; @@ -1687,11 +1686,11 @@ mod tests { assert_eq!( provider.ommers_by_id(block_number.into()).unwrap().unwrap_or_default(), - in_memory_block.body.ommers + in_memory_block.body().ommers ); assert_eq!( provider.ommers_by_id(block_hash.into()).unwrap().unwrap_or_default(), - in_memory_block.body.ommers + in_memory_block.body().ommers ); Ok(()) @@ -2168,9 +2167,9 @@ mod tests { $( // Since data moves for each tried method, need to recalculate everything let db_tx_count = - database_blocks.iter().map(|b| b.body.transactions.len()).sum::() as u64; + database_blocks.iter().map(|b| b.body().transactions.len()).sum::() as u64; let in_mem_tx_count = - in_memory_blocks.iter().map(|b| b.body.transactions.len()).sum::() as u64; + in_memory_blocks.iter().map(|b| b.body().transactions.len()).sum::() as u64; let db_range = 0..=(db_tx_count - 1); let in_mem_range = db_tx_count..=(in_mem_tx_count + db_range.end()); @@ -2249,7 +2248,7 @@ mod tests { .senders() .unwrap()), (transactions_by_tx_range, |block: &SealedBlock, _: &Vec>| block - .body + .body() .transactions .clone()), (receipts_by_tx_range, |block: &SealedBlock, receipts: &Vec>| receipts @@ -2348,7 +2347,7 @@ mod tests { (sealed_block_with_senders_range, |block: &SealedBlock| block .clone() .with_senders_unchecked(vec![])), - (transactions_by_block_range, |block: &SealedBlock| block.body.transactions.clone()), + (transactions_by_block_range, |block: &SealedBlock| block.body().transactions.clone()), ]); Ok(()) @@ -2405,13 +2404,13 @@ mod tests { let mut in_memory_blocks: std::collections::VecDeque<_> = in_memory_blocks.into(); $( - let tx_hash = |block: &SealedBlock| block.body.transactions[0].hash(); + let tx_hash = |block: &SealedBlock| block.body().transactions[0].hash(); let tx_num = |block: &SealedBlock| { database_blocks .iter() .chain(in_memory_blocks.iter()) .take_while(|b| b.number < block.number) - .map(|b| b.body.transactions.len()) + .map(|b| b.body().transactions.len()) .sum::() as u64 }; @@ -2432,7 +2431,7 @@ mod tests { .iter() .chain(in_memory_blocks.iter()) .take_while(|b| b.number < block.number) - .map(|b| b.body.transactions.len()) + .map(|b| b.body().transactions.len()) .sum::() as u64 }; @@ -2528,7 +2527,7 @@ mod tests { block.number, Some(StoredBlockBodyIndices { first_tx_num: tx_num, - tx_count: block.body.transactions.len() as u64 + tx_count: block.body().transactions.len() as u64 }) ), u64::MAX @@ -2597,7 +2596,7 @@ mod tests { transaction_by_id, |block: &SealedBlock, tx_num: TxNumber, _: B256, _: &Vec>| ( tx_num, - Some(block.body.transactions[test_tx_index].clone()) + Some(block.body().transactions[test_tx_index].clone()) ), u64::MAX ), @@ -2606,7 +2605,7 @@ mod tests { transaction_by_id_unhashed, |block: &SealedBlock, tx_num: TxNumber, _: B256, _: &Vec>| ( tx_num, - Some(block.body.transactions[test_tx_index].clone()) + Some(block.body().transactions[test_tx_index].clone()) ), u64::MAX ), @@ -2615,7 +2614,7 @@ mod tests { transaction_by_hash, |block: &SealedBlock, _: TxNumber, tx_hash: B256, _: &Vec>| ( tx_hash, - Some(block.body.transactions[test_tx_index].clone()) + Some(block.body().transactions[test_tx_index].clone()) ), B256::random() ), @@ -2633,7 +2632,7 @@ mod tests { transactions_by_block, |block: &SealedBlock, _: TxNumber, _: B256, _: &Vec>| ( BlockHashOrNumber::Number(block.number), - Some(block.body.transactions.clone()) + Some(block.body().transactions.clone()) ), BlockHashOrNumber::Number(u64::MAX) ), @@ -2642,7 +2641,7 @@ mod tests { transactions_by_block, |block: &SealedBlock, _: TxNumber, _: B256, _: &Vec>| ( BlockHashOrNumber::Hash(block.hash()), - Some(block.body.transactions.clone()) + Some(block.body().transactions.clone()) ), BlockHashOrNumber::Number(u64::MAX) ), @@ -2651,7 +2650,7 @@ mod tests { transaction_sender, |block: &SealedBlock, tx_num: TxNumber, _: B256, _: &Vec>| ( tx_num, - block.body.transactions[test_tx_index].recover_signer() + block.body().transactions[test_tx_index].recover_signer() ), u64::MAX ), @@ -2737,7 +2736,7 @@ mod tests { // This will persist block 1 AFTER a database is created. Moving it from memory to // storage. persist_block_after_db_tx_creation(provider.clone(), in_memory_blocks[0].number); - let to_be_persisted_tx = in_memory_blocks[0].body.transactions[0].clone(); + let to_be_persisted_tx = in_memory_blocks[0].body().transactions[0].clone(); // Even though the block exists, given the order of provider queries done in the method // above, we do not see it. @@ -2756,7 +2755,7 @@ mod tests { // This will persist block 1 AFTER a database is created. Moving it from memory to // storage. persist_block_after_db_tx_creation(provider.clone(), in_memory_blocks[1].number); - let to_be_persisted_tx = in_memory_blocks[1].body.transactions[0].clone(); + let to_be_persisted_tx = in_memory_blocks[1].body().transactions[0].clone(); assert!(matches!( correct_transaction_hash_fn( diff --git a/crates/storage/provider/src/providers/consistent.rs b/crates/storage/provider/src/providers/consistent.rs index f72e0a1d516e..c12324c541c4 100644 --- a/crates/storage/provider/src/providers/consistent.rs +++ b/crates/storage/provider/src/providers/consistent.rs @@ -6,7 +6,7 @@ use crate::{ StageCheckpointReader, StateReader, StaticFileProviderFactory, TransactionVariant, TransactionsProvider, WithdrawalsProvider, }; -use alloy_consensus::BlockHeader; +use alloy_consensus::{transaction::TransactionMeta, BlockHeader}; use alloy_eips::{ eip2718::Encodable2718, eip4895::{Withdrawal, Withdrawals}, @@ -21,7 +21,6 @@ use reth_execution_types::{BundleStateInit, ExecutionOutcome, RevertsInit}; use reth_node_types::{BlockTy, HeaderTy, ReceiptTy, TxTy}; use reth_primitives::{ Account, BlockWithSenders, SealedBlockFor, SealedBlockWithSenders, SealedHeader, StorageEntry, - TransactionMeta, }; use reth_primitives_traits::BlockBody; use reth_prune_types::{PruneCheckpoint, PruneSegment}; @@ -444,7 +443,7 @@ impl ConsistentProvider { let (start, end) = self.convert_range_bounds(range, || { in_mem_chain .iter() - .map(|b| b.block_ref().block().body.transactions().len() as u64) + .map(|b| b.block_ref().block().body().transactions().len() as u64) .sum::() + last_block_body_index.last_tx_num() }); @@ -476,7 +475,7 @@ impl ConsistentProvider { // Iterate from the lowest block to the highest in-memory chain for block_state in in_mem_chain.iter().rev() { - let block_tx_count = block_state.block_ref().block().body.transactions().len(); + let block_tx_count = block_state.block_ref().block().body().transactions().len(); let remaining = (tx_range.end() - tx_range.start() + 1) as usize; // If the transaction range start is equal or higher than the next block first @@ -550,10 +549,10 @@ impl ConsistentProvider { let executed_block = block_state.block_ref(); let block = executed_block.block(); - for tx_index in 0..block.body.transactions().len() { + for tx_index in 0..block.body().transactions().len() { match id { HashOrNumber::Hash(tx_hash) => { - if tx_hash == block.body.transactions()[tx_index].trie_hash() { + if tx_hash == block.body().transactions()[tx_index].trie_hash() { return fetch_from_block_state(tx_index, in_memory_tx_num, block_state) } } @@ -917,7 +916,7 @@ impl TransactionsProvider for ConsistentProvider { id.into(), |provider| provider.transaction_by_id(id), |tx_index, _, block_state| { - Ok(block_state.block_ref().block().body.transactions().get(tx_index).cloned()) + Ok(block_state.block_ref().block().body().transactions().get(tx_index).cloned()) }, ) } @@ -930,7 +929,7 @@ impl TransactionsProvider for ConsistentProvider { id.into(), |provider| provider.transaction_by_id_unhashed(id), |tx_index, _, block_state| { - Ok(block_state.block_ref().block().body.transactions().get(tx_index).cloned()) + Ok(block_state.block_ref().block().body().transactions().get(tx_index).cloned()) }, ) } @@ -971,7 +970,7 @@ impl TransactionsProvider for ConsistentProvider { self.get_in_memory_or_storage_by_block( id, |provider| provider.transactions_by_block(id), - |block_state| Ok(Some(block_state.block_ref().block().body.transactions().to_vec())), + |block_state| Ok(Some(block_state.block_ref().block().body().transactions().to_vec())), ) } @@ -982,7 +981,7 @@ impl TransactionsProvider for ConsistentProvider { self.get_in_memory_or_storage_by_block_range_while( range, |db_provider, range, _| db_provider.transactions_by_block_range(range), - |block_state, _| Some(block_state.block_ref().block().body.transactions().to_vec()), + |block_state, _| Some(block_state.block_ref().block().body().transactions().to_vec()), |_| true, ) } @@ -995,7 +994,7 @@ impl TransactionsProvider for ConsistentProvider { range, |db_provider, db_range| db_provider.transactions_by_tx_range(db_range), |index_range, block_state| { - Ok(block_state.block_ref().block().body.transactions()[index_range].to_vec()) + Ok(block_state.block_ref().block().body().transactions()[index_range].to_vec()) }, ) } @@ -1041,13 +1040,13 @@ impl ReceiptProvider for ConsistentProvider { // assuming 1:1 correspondence between transactions and receipts debug_assert_eq!( - block.body.transactions().len(), + block.body().transactions().len(), receipts.len(), "Mismatch between transaction and receipt count" ); if let Some(tx_index) = - block.body.transactions().iter().position(|tx| tx.trie_hash() == hash) + block.body().transactions().iter().position(|tx| tx.trie_hash() == hash) { // safe to use tx_index for receipts due to 1:1 correspondence return Ok(receipts.get(tx_index).cloned()); @@ -1128,7 +1127,7 @@ impl WithdrawalsProvider for ConsistentProvider { self.get_in_memory_or_storage_by_block( id, |db_provider| db_provider.withdrawals_by_block(id, timestamp), - |block_state| Ok(block_state.block_ref().block().body.withdrawals().cloned()), + |block_state| Ok(block_state.block_ref().block().body().withdrawals().cloned()), ) } @@ -1142,7 +1141,7 @@ impl WithdrawalsProvider for ConsistentProvider { Ok(block_state .block_ref() .block() - .body + .body() .withdrawals() .cloned() .and_then(|mut w| w.pop())) @@ -1161,7 +1160,7 @@ impl OmmersProvider for ConsistentProvider { return Ok(Some(Vec::new())) } - Ok(block_state.block_ref().block().body.ommers().map(|o| o.to_vec())) + Ok(block_state.block_ref().block().body().ommers().map(|o| o.to_vec())) }, ) } @@ -1189,7 +1188,7 @@ impl BlockBodyIndicesProvider for ConsistentProvider { // Iterate from the lowest block in memory until our target block for state in block_state.chain().collect::>().into_iter().rev() { - let block_tx_count = state.block_ref().block.body.transactions().len() as u64; + let block_tx_count = state.block_ref().block.body().transactions().len() as u64; if state.block_ref().block().number() == number { stored_indices.tx_count = block_tx_count; } else { diff --git a/crates/storage/provider/src/providers/database/mod.rs b/crates/storage/provider/src/providers/database/mod.rs index 4d11863c22fa..8ff8ef3b76d4 100644 --- a/crates/storage/provider/src/providers/database/mod.rs +++ b/crates/storage/provider/src/providers/database/mod.rs @@ -7,6 +7,7 @@ use crate::{ PruneCheckpointReader, StageCheckpointReader, StateProviderBox, StaticFileProviderFactory, TransactionVariant, TransactionsProvider, WithdrawalsProvider, }; +use alloy_consensus::transaction::TransactionMeta; use alloy_eips::{ eip4895::{Withdrawal, Withdrawals}, BlockHashOrNumber, @@ -20,7 +21,6 @@ use reth_errors::{RethError, RethResult}; use reth_node_types::{BlockTy, HeaderTy, NodeTypesWithDB, ReceiptTy, TxTy}; use reth_primitives::{ BlockWithSenders, SealedBlockFor, SealedBlockWithSenders, SealedHeader, StaticFileSegment, - TransactionMeta, }; use reth_prune_types::{PruneCheckpoint, PruneModes, PruneSegment}; use reth_stages_types::{StageCheckpoint, StageId}; @@ -718,10 +718,10 @@ mod tests { ); assert_matches!( provider.transaction_sender(0), Ok(Some(sender)) - if sender == block.body.transactions[0].recover_signer().unwrap() + if sender == block.body().transactions[0].recover_signer().unwrap() ); assert_matches!( - provider.transaction_id(block.body.transactions[0].hash()), + provider.transaction_id(block.body().transactions[0].hash()), Ok(Some(0)) ); } @@ -741,7 +741,7 @@ mod tests { Ok(_) ); assert_matches!(provider.transaction_sender(0), Ok(None)); - assert_matches!(provider.transaction_id(block.body.transactions[0].hash()), Ok(None)); + assert_matches!(provider.transaction_id(block.body().transactions[0].hash()), Ok(None)); } } @@ -772,7 +772,7 @@ mod tests { .clone() .map(|tx_number| ( tx_number, - block.body.transactions[tx_number as usize].recover_signer().unwrap() + block.body().transactions[tx_number as usize].recover_signer().unwrap() )) .collect()) ); diff --git a/crates/storage/provider/src/providers/database/provider.rs b/crates/storage/provider/src/providers/database/provider.rs index 006ba369b389..16c62f7c367e 100644 --- a/crates/storage/provider/src/providers/database/provider.rs +++ b/crates/storage/provider/src/providers/database/provider.rs @@ -19,7 +19,7 @@ use crate::{ StorageReader, StorageTrieWriter, TransactionVariant, TransactionsProvider, TransactionsProviderExt, TrieWriter, WithdrawalsProvider, }; -use alloy_consensus::{BlockHeader, Header}; +use alloy_consensus::{transaction::TransactionMeta, BlockHeader, Header}; use alloy_eips::{ eip2718::Encodable2718, eip4895::{Withdrawal, Withdrawals}, @@ -53,7 +53,6 @@ use reth_node_types::{BlockTy, BodyTy, HeaderTy, NodeTypes, ReceiptTy, TxTy}; use reth_primitives::{ Account, BlockExt, BlockWithSenders, Bytecode, GotExpected, NodePrimitives, SealedBlock, SealedBlockFor, SealedBlockWithSenders, SealedHeader, StaticFileSegment, StorageEntry, - TransactionMeta, }; use reth_primitives_traits::{Block as _, BlockBody as _, SignedTransaction}; use reth_prune_types::{PruneCheckpoint, PruneModes, PruneSegment}; @@ -1255,7 +1254,7 @@ impl BlockReader for DatabaseProvid transaction_kind, |block_number| self.sealed_header(block_number), |header, body, senders| { - SealedBlock { header, body } + SealedBlock::new(header, body) // Note: we're using unchecked here because we know the block contains valid txs // wrt to its height and can ignore the s value check so pre // EIP-2 txs are allowed @@ -1297,7 +1296,7 @@ impl BlockReader for DatabaseProvid range, |range| self.sealed_headers_range(range), |header, body, senders| { - SealedBlockWithSenders::new(SealedBlock { header, body }, senders) + SealedBlockWithSenders::new(SealedBlock::new(header, body), senders) .ok_or(ProviderError::SenderRecoveryError) }, ) @@ -2806,11 +2805,11 @@ impl BlockWrite durations_recorder.record_relative(metrics::Action::GetNextTxNum); let first_tx_num = next_tx_num; - let tx_count = block.block.body.transactions().len() as u64; + let tx_count = block.block.body().transactions().len() as u64; // Ensures we have all the senders for the block's transactions. for (transaction, sender) in - block.block.body.transactions().iter().zip(block.senders.iter()) + block.block.body().transactions().iter().zip(block.senders.iter()) { let hash = transaction.tx_hash(); @@ -2824,7 +2823,7 @@ impl BlockWrite next_tx_num += 1; } - self.append_block_bodies(vec![(block_number, Some(block.block.body))], write_to)?; + self.append_block_bodies(vec![(block_number, Some(block.block.into_body()))], write_to)?; debug!( target: "providers::db", diff --git a/crates/storage/provider/src/providers/mod.rs b/crates/storage/provider/src/providers/mod.rs index 25a5df9096d9..0d37f11434a6 100644 --- a/crates/storage/provider/src/providers/mod.rs +++ b/crates/storage/provider/src/providers/mod.rs @@ -9,7 +9,7 @@ use crate::{ StageCheckpointReader, StateProviderBox, StateProviderFactory, StaticFileProviderFactory, TransactionVariant, TransactionsProvider, TreeViewer, WithdrawalsProvider, }; -use alloy_consensus::Header; +use alloy_consensus::{transaction::TransactionMeta, Header}; use alloy_eips::{ eip4895::{Withdrawal, Withdrawals}, BlockHashOrNumber, BlockId, BlockNumHash, BlockNumberOrTag, @@ -31,11 +31,13 @@ use reth_node_types::{ }; use reth_primitives::{ Account, BlockWithSenders, EthPrimitives, Receipt, SealedBlock, SealedBlockFor, - SealedBlockWithSenders, SealedHeader, TransactionMeta, + SealedBlockWithSenders, SealedHeader, }; use reth_prune_types::{PruneCheckpoint, PruneSegment}; use reth_stages_types::{StageCheckpoint, StageId}; -use reth_storage_api::{BlockBodyIndicesProvider, CanonChainTracker, OmmersProvider}; +use reth_storage_api::{ + BlockBodyIndicesProvider, CanonChainTracker, OmmersProvider, StateCommitmentProvider, +}; use reth_storage_errors::provider::ProviderResult; use std::{ collections::BTreeMap, @@ -255,6 +257,10 @@ impl DatabaseProviderFactory for BlockchainProvider { } } +impl StateCommitmentProvider for BlockchainProvider { + type StateCommitment = N::StateCommitment; +} + impl StaticFileProviderFactory for BlockchainProvider { fn static_file_provider(&self) -> StaticFileProvider { self.database.static_file_provider() diff --git a/crates/storage/provider/src/providers/static_file/jar.rs b/crates/storage/provider/src/providers/static_file/jar.rs index 8f2d002ab898..598e726ab08e 100644 --- a/crates/storage/provider/src/providers/static_file/jar.rs +++ b/crates/storage/provider/src/providers/static_file/jar.rs @@ -6,6 +6,7 @@ use crate::{ to_range, BlockHashReader, BlockNumReader, HeaderProvider, ReceiptProvider, TransactionsProvider, }; +use alloy_consensus::transaction::TransactionMeta; use alloy_eips::{eip2718::Encodable2718, BlockHashOrNumber}; use alloy_primitives::{Address, BlockHash, BlockNumber, TxHash, TxNumber, B256, U256}; use reth_chainspec::ChainInfo; @@ -17,7 +18,7 @@ use reth_db::{ table::{Decompress, Value}, }; use reth_node_types::NodePrimitives; -use reth_primitives::{transaction::recover_signers, SealedHeader, TransactionMeta}; +use reth_primitives::{transaction::recover_signers, SealedHeader}; use reth_primitives_traits::SignedTransaction; use reth_storage_errors::provider::{ProviderError, ProviderResult}; use std::{ diff --git a/crates/storage/provider/src/providers/static_file/manager.rs b/crates/storage/provider/src/providers/static_file/manager.rs index ab6b034fd98c..7f8b3e1b97fa 100644 --- a/crates/storage/provider/src/providers/static_file/manager.rs +++ b/crates/storage/provider/src/providers/static_file/manager.rs @@ -7,7 +7,7 @@ use crate::{ ReceiptProvider, StageCheckpointReader, StatsReader, TransactionVariant, TransactionsProvider, TransactionsProviderExt, WithdrawalsProvider, }; -use alloy_consensus::Header; +use alloy_consensus::{transaction::TransactionMeta, Header}; use alloy_eips::{ eip2718::Encodable2718, eip4895::{Withdrawal, Withdrawals}, @@ -39,7 +39,7 @@ use reth_primitives::{ }, transaction::recover_signers, BlockWithSenders, Receipt, SealedBlockFor, SealedBlockWithSenders, SealedHeader, - StaticFileSegment, TransactionMeta, TransactionSigned, + StaticFileSegment, TransactionSigned, }; use reth_primitives_traits::SignedTransaction; use reth_stages_types::{PipelineTarget, StageId}; diff --git a/crates/storage/provider/src/test_utils/blocks.rs b/crates/storage/provider/src/test_utils/blocks.rs index 8d81e98e9619..5ed8b09ee0b8 100644 --- a/crates/storage/provider/src/test_utils/blocks.rs +++ b/crates/storage/provider/src/test_utils/blocks.rs @@ -63,32 +63,39 @@ pub fn assert_genesis_block( // StageCheckpoints is not updated in tests } -pub(crate) static TEST_BLOCK: LazyLock = LazyLock::new(|| SealedBlock { - header: SealedHeader::new( - Header { - parent_hash: hex!("c86e8cc0310ae7c531c758678ddbfd16fc51c8cef8cec650b032de9869e8b94f") +pub(crate) static TEST_BLOCK: LazyLock = LazyLock::new(|| { + SealedBlock::new( + SealedHeader::new( + Header { + parent_hash: hex!( + "c86e8cc0310ae7c531c758678ddbfd16fc51c8cef8cec650b032de9869e8b94f" + ) .into(), - ommers_hash: EMPTY_OMMER_ROOT_HASH, - beneficiary: hex!("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba").into(), - state_root: hex!("50554882fbbda2c2fd93fdc466db9946ea262a67f7a76cc169e714f105ab583d") + ommers_hash: EMPTY_OMMER_ROOT_HASH, + beneficiary: hex!("2adc25665018aa1fe0e6bc666dac8fc2697ff9ba").into(), + state_root: hex!( + "50554882fbbda2c2fd93fdc466db9946ea262a67f7a76cc169e714f105ab583d" + ) .into(), - transactions_root: hex!( - "0967f09ef1dfed20c0eacfaa94d5cd4002eda3242ac47eae68972d07b106d192" - ) - .into(), - receipts_root: hex!("e3c8b47fbfc94667ef4cceb17e5cc21e3b1eebd442cebb27f07562b33836290d") + transactions_root: hex!( + "0967f09ef1dfed20c0eacfaa94d5cd4002eda3242ac47eae68972d07b106d192" + ) .into(), - difficulty: U256::from(131_072), - number: 1, - gas_limit: 1_000_000, - gas_used: 14_352, - timestamp: 1_000, - ..Default::default() - }, - hex!("cf7b274520720b50e6a4c3e5c4d553101f44945396827705518ce17cb7219a42").into(), - ), - body: BlockBody { - transactions: vec![TransactionSigned::new( + receipts_root: hex!( + "e3c8b47fbfc94667ef4cceb17e5cc21e3b1eebd442cebb27f07562b33836290d" + ) + .into(), + difficulty: U256::from(131_072), + number: 1, + gas_limit: 1_000_000, + gas_used: 14_352, + timestamp: 1_000, + ..Default::default() + }, + hex!("cf7b274520720b50e6a4c3e5c4d553101f44945396827705518ce17cb7219a42").into(), + ), + BlockBody { + transactions: vec![TransactionSigned::new( Transaction::Legacy(TxLegacy { gas_price: 10, gas_limit: 400_000, @@ -108,8 +115,9 @@ pub(crate) static TEST_BLOCK: LazyLock = LazyLock::new(|| SealedBlo ), b256!("3541dd1d17e76adeb25dcf2b0a9b60a1669219502e58dcf26a2beafbfb550397"), )], - ..Default::default() - }, + ..Default::default() + }, + ) }); /// Test chain with genesis, blocks, execution results @@ -155,13 +163,13 @@ impl Default for BlockchainTestData { /// Genesis block pub fn genesis() -> SealedBlock { - SealedBlock { - header: SealedHeader::new( + SealedBlock::new( + SealedHeader::new( Header { number: 0, difficulty: U256::from(1), ..Default::default() }, B256::ZERO, ), - body: Default::default(), - } + Default::default(), + ) } fn bundle_state_root(execution_outcome: &ExecutionOutcome) -> B256 { @@ -224,13 +232,13 @@ fn block1(number: BlockNumber) -> (SealedBlockWithSenders, ExecutionOutcome) { b256!("5d035ccb3e75a9057452ff060b773b213ec1fc353426174068edfc3971a0b6bd") ); - let mut block = TEST_BLOCK.clone(); - block.body.withdrawals = Some(Withdrawals::new(vec![Withdrawal::default()])); - let mut header = block.header.clone().unseal(); + let (header, mut body) = TEST_BLOCK.clone().split_header_body(); + body.withdrawals = Some(Withdrawals::new(vec![Withdrawal::default()])); + let mut header = header.unseal(); header.number = number; header.state_root = state_root; header.parent_hash = B256::ZERO; - block.header = SealedHeader::seal(header); + let block = SealedBlock::new(SealedHeader::seal(header), body); (SealedBlockWithSenders { block, senders: vec![Address::new([0x30; 20])] }, execution_outcome) } @@ -286,15 +294,15 @@ fn block2( b256!("90101a13dd059fa5cca99ed93d1dc23657f63626c5b8f993a2ccbdf7446b64f8") ); - let mut block = TEST_BLOCK.clone(); + let (header, mut body) = TEST_BLOCK.clone().split_header_body(); - block.body.withdrawals = Some(Withdrawals::new(vec![Withdrawal::default()])); - let mut header = block.header.clone().unseal(); + body.withdrawals = Some(Withdrawals::new(vec![Withdrawal::default()])); + let mut header = header.unseal(); header.number = number; header.state_root = state_root; // parent_hash points to block1 hash header.parent_hash = parent_hash; - block.header = SealedHeader::seal(header); + let block = SealedBlock::new(SealedHeader::seal(header), body); (SealedBlockWithSenders { block, senders: vec![Address::new([0x31; 20])] }, execution_outcome) } @@ -351,14 +359,14 @@ fn block3( extended.extend(execution_outcome.clone()); let state_root = bundle_state_root(&extended); - let mut block = TEST_BLOCK.clone(); - block.body.withdrawals = Some(Withdrawals::new(vec![Withdrawal::default()])); - let mut header = block.header.clone().unseal(); + let (header, mut body) = TEST_BLOCK.clone().split_header_body(); + body.withdrawals = Some(Withdrawals::new(vec![Withdrawal::default()])); + let mut header = header.unseal(); header.number = number; header.state_root = state_root; // parent_hash points to block1 hash header.parent_hash = parent_hash; - block.header = SealedHeader::seal(header); + let block = SealedBlock::new(SealedHeader::seal(header), body); (SealedBlockWithSenders { block, senders: vec![Address::new([0x31; 20])] }, execution_outcome) } @@ -440,14 +448,14 @@ fn block4( extended.extend(execution_outcome.clone()); let state_root = bundle_state_root(&extended); - let mut block = TEST_BLOCK.clone(); - block.body.withdrawals = Some(Withdrawals::new(vec![Withdrawal::default()])); - let mut header = block.header.clone().unseal(); + let (header, mut body) = TEST_BLOCK.clone().split_header_body(); + body.withdrawals = Some(Withdrawals::new(vec![Withdrawal::default()])); + let mut header = header.unseal(); header.number = number; header.state_root = state_root; // parent_hash points to block1 hash header.parent_hash = parent_hash; - block.header = SealedHeader::seal(header); + let block = SealedBlock::new(SealedHeader::seal(header), body); (SealedBlockWithSenders { block, senders: vec![Address::new([0x31; 20])] }, execution_outcome) } @@ -526,14 +534,14 @@ fn block5( extended.extend(execution_outcome.clone()); let state_root = bundle_state_root(&extended); - let mut block = TEST_BLOCK.clone(); - block.body.withdrawals = Some(Withdrawals::new(vec![Withdrawal::default()])); - let mut header = block.header.clone().unseal(); + let (header, mut body) = TEST_BLOCK.clone().split_header_body(); + body.withdrawals = Some(Withdrawals::new(vec![Withdrawal::default()])); + let mut header = header.unseal(); header.number = number; header.state_root = state_root; // parent_hash points to block1 hash header.parent_hash = parent_hash; - block.header = SealedHeader::seal(header); + let block = SealedBlock::new(SealedHeader::seal(header), body); (SealedBlockWithSenders { block, senders: vec![Address::new([0x31; 20])] }, execution_outcome) } diff --git a/crates/storage/provider/src/test_utils/mock.rs b/crates/storage/provider/src/test_utils/mock.rs index 5bac034b520a..d3196b8195d0 100644 --- a/crates/storage/provider/src/test_utils/mock.rs +++ b/crates/storage/provider/src/test_utils/mock.rs @@ -5,7 +5,7 @@ use crate::{ ReceiptProviderIdExt, StateProvider, StateProviderBox, StateProviderFactory, StateReader, StateRootProvider, TransactionVariant, TransactionsProvider, WithdrawalsProvider, }; -use alloy_consensus::{constants::EMPTY_ROOT_HASH, Header}; +use alloy_consensus::{constants::EMPTY_ROOT_HASH, transaction::TransactionMeta, Header}; use alloy_eips::{ eip4895::{Withdrawal, Withdrawals}, BlockHashOrNumber, BlockId, BlockNumberOrTag, @@ -23,7 +23,7 @@ use reth_execution_types::ExecutionOutcome; use reth_node_types::NodeTypes; use reth_primitives::{ Account, Block, BlockWithSenders, Bytecode, EthPrimitives, GotExpected, Receipt, SealedBlock, - SealedBlockWithSenders, SealedHeader, TransactionMeta, TransactionSigned, + SealedBlockWithSenders, SealedHeader, TransactionSigned, }; use reth_primitives_traits::SignedTransaction; use reth_stages_types::{StageCheckpoint, StageId}; diff --git a/crates/storage/storage-api/src/noop.rs b/crates/storage/storage-api/src/noop.rs index 53ff0d61637a..f58c1e176ef4 100644 --- a/crates/storage/storage-api/src/noop.rs +++ b/crates/storage/storage-api/src/noop.rs @@ -8,6 +8,7 @@ use crate::{ StateProviderBox, StateProviderFactory, StateRootProvider, StorageRootProvider, TransactionVariant, TransactionsProvider, WithdrawalsProvider, }; +use alloy_consensus::transaction::TransactionMeta; use alloy_eips::{ eip4895::{Withdrawal, Withdrawals}, BlockHashOrNumber, BlockId, BlockNumberOrTag, @@ -18,9 +19,7 @@ use alloy_primitives::{ }; use reth_chainspec::{ChainInfo, ChainSpecProvider, EthChainSpec, MAINNET}; use reth_db_models::{AccountBeforeTx, StoredBlockBodyIndices}; -use reth_primitives::{ - BlockWithSenders, EthPrimitives, SealedBlockFor, SealedBlockWithSenders, TransactionMeta, -}; +use reth_primitives::{BlockWithSenders, EthPrimitives, SealedBlockFor, SealedBlockWithSenders}; use reth_primitives_traits::{Account, Bytecode, NodePrimitives, SealedHeader}; use reth_prune_types::{PruneCheckpoint, PruneSegment}; use reth_stages_types::{StageCheckpoint, StageId}; diff --git a/crates/storage/storage-api/src/transactions.rs b/crates/storage/storage-api/src/transactions.rs index ed44b4dd1322..e156119b8b24 100644 --- a/crates/storage/storage-api/src/transactions.rs +++ b/crates/storage/storage-api/src/transactions.rs @@ -1,7 +1,7 @@ use crate::{BlockNumReader, BlockReader}; +use alloy_consensus::transaction::TransactionMeta; use alloy_eips::BlockHashOrNumber; use alloy_primitives::{Address, BlockNumber, TxHash, TxNumber}; -use reth_primitives::TransactionMeta; use reth_primitives_traits::SignedTransaction; use reth_storage_errors::provider::{ProviderError, ProviderResult}; use std::ops::{Range, RangeBounds, RangeInclusive}; diff --git a/crates/transaction-pool/src/blobstore/tracker.rs b/crates/transaction-pool/src/blobstore/tracker.rs index c359dcc7cf00..88c8faa7872a 100644 --- a/crates/transaction-pool/src/blobstore/tracker.rs +++ b/crates/transaction-pool/src/blobstore/tracker.rs @@ -46,7 +46,7 @@ impl BlobStoreCanonTracker { { let blob_txs = blocks.iter().map(|(num, block)| { let iter = block - .body + .body() .transactions() .iter() .filter(|tx| tx.is_eip4844()) @@ -128,12 +128,9 @@ mod tests { // Creating a first block with EIP-4844 transactions let block1 = SealedBlockWithSenders { - block: SealedBlock { - header: SealedHeader::new( - Header { number: 10, ..Default::default() }, - B256::random(), - ), - body: BlockBody { + block: SealedBlock::new( + SealedHeader::new(Header { number: 10, ..Default::default() }, B256::random()), + BlockBody { transactions: vec![ TransactionSigned::new( Transaction::Eip4844(Default::default()), @@ -154,19 +151,16 @@ mod tests { ], ..Default::default() }, - }, + ), ..Default::default() }; // Creating a second block with EIP-1559 and EIP-2930 transactions // Note: This block does not contain any EIP-4844 transactions let block2 = SealedBlockWithSenders { - block: SealedBlock { - header: SealedHeader::new( - Header { number: 11, ..Default::default() }, - B256::random(), - ), - body: BlockBody { + block: SealedBlock::new( + SealedHeader::new(Header { number: 11, ..Default::default() }, B256::random()), + BlockBody { transactions: vec![ TransactionSigned::new( Transaction::Eip1559(Default::default()), @@ -181,7 +175,7 @@ mod tests { ], ..Default::default() }, - }, + ), ..Default::default() }; diff --git a/testing/testing-utils/src/generators.rs b/testing/testing-utils/src/generators.rs index a6610afe9361..e5dc7fc06d4b 100644 --- a/testing/testing-utils/src/generators.rs +++ b/testing/testing-utils/src/generators.rs @@ -232,10 +232,10 @@ pub fn random_block(rng: &mut R, number: u64, block_params: BlockParams) ..Default::default() }; - SealedBlock { - header: SealedHeader::seal(header), - body: BlockBody { transactions, ommers, withdrawals: withdrawals.map(Withdrawals::new) }, - } + SealedBlock::new( + SealedHeader::seal(header), + BlockBody { transactions, ommers, withdrawals: withdrawals.map(Withdrawals::new) }, + ) } /// Generate a range of random blocks. @@ -263,7 +263,7 @@ pub fn random_block_range( idx, BlockParams { parent: Some( - blocks.last().map(|block: &SealedBlock| block.header.hash()).unwrap_or(parent), + blocks.last().map(|block: &SealedBlock| block.hash()).unwrap_or(parent), ), tx_count: Some(tx_count), ommers_count: None,