Compare commits

..

21 Commits

Author SHA1 Message Date
yongkangc
f568349be9 perf(engine-tree): reuse provider builder in validation 2025-12-22 07:48:35 +00:00
YK
62abfdaeb5 feat(cli): add tracing-samply to profiling (#20546) 2025-12-21 11:52:26 +00:00
emmmm
256a9fdb79 docs: add missing trace methods to pruning tables (#20547) 2025-12-21 12:40:58 +01:00
github-actions[bot]
4d9aff99bf chore(deps): weekly cargo update (#20545)
Co-authored-by: github-merge-queue <118344674+github-merge-queue@users.noreply.github.com>
2025-12-21 12:40:14 +01:00
Vitalyr
28bb2891bb refactor(consensus): simplify verify_receipts return (#20517) 2025-12-20 19:05:50 +01:00
kurahin
1d8f265744 chore(net): remove stale ECIES rand TODO (#20531) 2025-12-20 19:05:37 +01:00
Matthias Seitz
c754caf8c7 fix: remove stale blobs (#20528) 2025-12-20 15:35:22 +00:00
cui
e1b0046329 chore: remove todo after jovian fork (#20535)
Co-authored-by: weixie.cui <weixie.cui@okg.com>
2025-12-20 15:31:08 +00:00
cui
ddfe177578 chore: remove todo (#20533)
Co-authored-by: weixie.cui <weixie.cui@okg.com>
2025-12-20 15:19:53 +00:00
Gigi
178558c6d7 fix(tree): correct block buffer eviction policy comment (#20512) 2025-12-20 09:44:51 +00:00
Emilia Hane
f4d3a9701f chore(trie): Rm redundant clone of propagated error (#20466)
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
2025-12-20 08:42:20 +00:00
Gigi
42e41a9370 docs: add reth JSON-RPC namespace documentation (#20522) 2025-12-20 08:03:06 +00:00
pepes
a66dcce834 chore(evm): remove deprecated state_change compatibility alias (#20518) 2025-12-20 07:50:12 +00:00
Arsenii Kulikov
21d835cf2b perf: use LRU eviction policy for precompile cache (#20527) 2025-12-20 02:12:42 +00:00
Alexey Shekhirin
29438631be fix: propagate keccak-cache-global feature to reth-node-core (#20524) 2025-12-19 17:11:41 +00:00
Brian Picciano
0eb4e0ce29 fix(stages): Fix two bugs related to stage checkpoints and pipeline syncs (#20521) 2025-12-19 16:09:57 +00:00
gustavo
9147f9aafe perf(trie): remove more unnecessary channels (#20489) 2025-12-19 15:34:42 +00:00
Snezhkko
13b111e058 refactor: remove dead storage multiproof path (#20485) 2025-12-19 15:11:31 +00:00
leniram159
25c247b14c refactor(engine): simplify fork detection in insert_block (#20441) 2025-12-19 14:49:33 +00:00
Matthias Seitz
72bea44d8c chore: remove redundant num hash (#20501) 2025-12-19 14:48:42 +00:00
alex017
63b9d5fe57 refactor(db-api): remove redundant clone and unused import in unwind (#20499)
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
2025-12-19 14:47:11 +00:00
44 changed files with 486 additions and 700 deletions

274
Cargo.lock generated
View File

@@ -177,9 +177,9 @@ dependencies = [
[[package]]
name = "alloy-dyn-abi"
version = "1.4.1"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdff496dd4e98a81f4861e66f7eaf5f2488971848bb42d9c892f871730245c8"
checksum = "0d48a9101f4a67c22fae57489f1ddf3057b8ab4a368d8eac3be088b6e9d9c9d9"
dependencies = [
"alloy-json-abi",
"alloy-primitives",
@@ -329,9 +329,9 @@ dependencies = [
[[package]]
name = "alloy-json-abi"
version = "1.5.0"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6bfca3dbbcb7498f0f60e67aff2ad6aff57032e22eb2fd03189854be11a22c03"
checksum = "9914c147bb9b25f440eca68a31dc29f5c22298bfa7754aa802965695384122b0"
dependencies = [
"alloy-primitives",
"alloy-sol-type-parser",
@@ -426,9 +426,9 @@ dependencies = [
[[package]]
name = "alloy-primitives"
version = "1.5.0"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c850e6ccbd34b8a463a1e934ffc8fc00e1efc5e5489f2ad82d7797949f3bd4e"
checksum = "7db950a29746be9e2f2c6288c8bd7a6202a81f999ce109a2933d2379970ec0fa"
dependencies = [
"alloy-rlp",
"arbitrary",
@@ -436,6 +436,7 @@ dependencies = [
"cfg-if",
"const-hex",
"derive_more",
"fixed-cache",
"foldhash 0.2.0",
"getrandom 0.3.4",
"hashbrown 0.16.1",
@@ -782,9 +783,9 @@ dependencies = [
[[package]]
name = "alloy-sol-macro"
version = "1.5.0"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2218e3aeb3ee665d117fdf188db0d5acfdc3f7b7502c827421cb78f26a2aec0"
checksum = "a3b96d5f5890605ba9907ce1e2158e2701587631dc005bfa582cf92dd6f21147"
dependencies = [
"alloy-sol-macro-expander",
"alloy-sol-macro-input",
@@ -796,9 +797,9 @@ dependencies = [
[[package]]
name = "alloy-sol-macro-expander"
version = "1.5.0"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b231cb8cc48e66dd1c6e11a1402f3ac86c3667cbc13a6969a0ac030ba7bb8c88"
checksum = "b8247b7cca5cde556e93f8b3882b01dbd272f527836049083d240c57bf7b4c15"
dependencies = [
"alloy-sol-macro-input",
"const-hex",
@@ -814,9 +815,9 @@ dependencies = [
[[package]]
name = "alloy-sol-macro-input"
version = "1.5.0"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49a522d79929c1bf0152b07567a38f7eaed3ab149e53e7528afa78ff11994668"
checksum = "3cd54f38512ac7bae10bbc38480eefb1b9b398ca2ce25db9cc0c048c6411c4f1"
dependencies = [
"const-hex",
"dunce",
@@ -830,9 +831,9 @@ dependencies = [
[[package]]
name = "alloy-sol-type-parser"
version = "1.5.0"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0475c459859c8d9428af6ff3736614655a57efda8cc435a3b8b4796fa5ac1dd0"
checksum = "444b09815b44899564566d4d56613d14fa9a274b1043a021f00468568752f449"
dependencies = [
"serde",
"winnow",
@@ -840,9 +841,9 @@ dependencies = [
[[package]]
name = "alloy-sol-types"
version = "1.5.0"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "35287d9d821d5f26011bcd8d9101340898f761c9933cf50fca689bb7ed62fdeb"
checksum = "dc1038284171df8bfd48befc0c7b78f667a7e2be162f45f07bd1c378078ebe58"
dependencies = [
"alloy-json-abi",
"alloy-primitives",
@@ -1939,9 +1940,9 @@ dependencies = [
[[package]]
name = "bumpalo"
version = "3.19.0"
version = "3.19.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43"
checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510"
[[package]]
name = "byte-slice-cast"
@@ -2018,9 +2019,9 @@ dependencies = [
[[package]]
name = "camino"
version = "1.2.1"
version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "276a59bf2b2c967788139340c9f0c5b12d7fd6630315c15c217e559de85d2609"
checksum = "e629a66d692cb9ff1a1c664e41771b3dcaf961985a9774c0eb0bd1b51cf60a48"
dependencies = [
"serde_core",
]
@@ -2131,7 +2132,7 @@ dependencies = [
"num-traits",
"serde",
"wasm-bindgen",
"windows-link 0.2.1",
"windows-link",
]
[[package]]
@@ -3986,6 +3987,15 @@ dependencies = [
"windows-sys 0.60.2",
]
[[package]]
name = "fixed-cache"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ba59b6c98ba422a13f17ee1305c995cb5742bba7997f5b4d9af61b2ff0ffb213"
dependencies = [
"equivalent",
]
[[package]]
name = "fixed-hash"
version = "0.8.0"
@@ -4229,16 +4239,17 @@ checksum = "42012b0f064e01aa58b545fe3727f90f7dd4020f4a3ea735b50344965f5a57e9"
[[package]]
name = "generator"
version = "0.8.7"
version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "605183a538e3e2a9c1038635cc5c2d194e2ee8fd0d1b66b8349fad7dbacce5a2"
checksum = "52f04ae4152da20c76fe800fa48659201d5cf627c5149ca0b707b69d7eef6cf9"
dependencies = [
"cc",
"cfg-if",
"libc",
"log",
"rustversion",
"windows 0.61.3",
"windows-link",
"windows-result 0.4.1",
]
[[package]]
@@ -5017,13 +5028,14 @@ dependencies = [
[[package]]
name = "insta"
version = "1.44.3"
version = "1.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5c943d4415edd8153251b6f197de5eb1640e56d84e8d9159bea190421c73698"
checksum = "b76866be74d68b1595eb8060cb9191dca9c021db2316558e52ddc5d55d41b66c"
dependencies = [
"console",
"once_cell",
"similar",
"tempfile",
]
[[package]]
@@ -5146,9 +5158,9 @@ dependencies = [
[[package]]
name = "itoa"
version = "1.0.15"
version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c"
checksum = "7ee5b5339afb4c41626dde77b7a611bd4f2c202b897852b4bcf5d03eddc61010"
[[package]]
name = "jni"
@@ -5464,7 +5476,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55"
dependencies = [
"cfg-if",
"windows-link 0.2.1",
"windows-link",
]
[[package]]
@@ -5505,13 +5517,13 @@ dependencies = [
[[package]]
name = "libredox"
version = "0.1.10"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb"
checksum = "df15f6eac291ed1cf25865b1ee60399f57e7c227e7f51bdbd4c5270396a9ed50"
dependencies = [
"bitflags 2.10.0",
"libc",
"redox_syscall",
"redox_syscall 0.6.0",
]
[[package]]
@@ -6020,9 +6032,9 @@ checksum = "5e0826a989adedc2a244799e823aece04662b66609d96af8dff7ac6df9a8925d"
[[package]]
name = "ntapi"
version = "0.4.1"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4"
checksum = "c70f219e21142367c70c0b30c6a9e3a14d55b4d12a204d897fbec83a0363f081"
dependencies = [
"winapi",
]
@@ -6545,9 +6557,9 @@ checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"redox_syscall 0.5.18",
"smallvec",
"windows-link 0.2.1",
"windows-link",
]
[[package]]
@@ -6744,9 +6756,9 @@ dependencies = [
[[package]]
name = "portable-atomic"
version = "1.11.1"
version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483"
checksum = "f59e70c4aef1e55797c2e8fd94a4f2a973fc972cfde0e0b05f683667b0cd39dd"
[[package]]
name = "potential_utf"
@@ -6818,7 +6830,7 @@ version = "3.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983"
dependencies = [
"toml_edit 0.23.9",
"toml_edit 0.23.10+spec-1.0.0",
]
[[package]]
@@ -7212,9 +7224,9 @@ dependencies = [
[[package]]
name = "rapidhash"
version = "4.1.1"
version = "4.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8e65c75143ce5d47c55b510297eeb1182f3c739b6043c537670e9fc18612dae"
checksum = "2988730ee014541157f48ce4dcc603940e00915edc3c7f9a8d78092256bb2493"
dependencies = [
"rand 0.9.2",
"rustversion",
@@ -7285,6 +7297,15 @@ dependencies = [
"bitflags 2.10.0",
]
[[package]]
name = "redox_syscall"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec96166dafa0886eb81fe1c0a388bece180fbef2135f97c1e2cf8302e74b43b5"
dependencies = [
"bitflags 2.10.0",
]
[[package]]
name = "redox_users"
version = "0.4.6"
@@ -7374,9 +7395,9 @@ checksum = "ba39f3699c378cd8970968dcbff9c43159ea4cfbd88d43c00b22f2ef10a435d2"
[[package]]
name = "reqwest"
version = "0.12.25"
version = "0.12.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6eff9328d40131d43bd911d42d79eb6a47312002a4daefc9e37f17e74a7701a"
checksum = "3b4c14b2d9afca6a60277086b0cc6a6ae0b568f6f7916c943a8cdc79f8be240f"
dependencies = [
"base64 0.22.1",
"bytes",
@@ -9613,6 +9634,7 @@ dependencies = [
"alloy-consensus",
"alloy-genesis",
"alloy-network",
"alloy-op-hardforks",
"alloy-primitives",
"alloy-rpc-types-engine",
"alloy-rpc-types-eth",
@@ -10829,6 +10851,7 @@ dependencies = [
"tracing-appender",
"tracing-journald",
"tracing-logfmt",
"tracing-samply",
"tracing-subscriber 0.3.22",
]
@@ -11592,9 +11615,9 @@ dependencies = [
[[package]]
name = "rustls-pki-types"
version = "1.13.1"
version = "1.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "708c0f9d5f54ba0272468c1d306a52c495b31fa155e91bc25371e6df7996908c"
checksum = "21e6f2ab2928ca4291b86736a8bd920a277a399bba1589409d72154ff87c1282"
dependencies = [
"web-time",
"zeroize",
@@ -11658,9 +11681,9 @@ dependencies = [
[[package]]
name = "ryu"
version = "1.0.20"
version = "1.0.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
checksum = "62049b2877bf12821e8f9ad256ee38fdc31db7387ec2d3b3f403024de2034aea"
[[package]]
name = "ryu-js"
@@ -12358,9 +12381,9 @@ dependencies = [
[[package]]
name = "syn-solidity"
version = "1.5.0"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60ceeb7c95a4536de0c0e1649bd98d1a72a4bb9590b1f3e45a8a0bfdb7c188c0"
checksum = "f6b1d2e2059056b66fec4a6bb2b79511d5e8d76196ef49c38996f4b48db7662f"
dependencies = [
"paste",
"proc-macro2",
@@ -12818,9 +12841,9 @@ dependencies = [
[[package]]
name = "toml_datetime"
version = "0.7.3"
version = "0.7.5+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533"
checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347"
dependencies = [
"serde_core",
]
@@ -12841,21 +12864,21 @@ dependencies = [
[[package]]
name = "toml_edit"
version = "0.23.9"
version = "0.23.10+spec-1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d7cbc3b4b49633d57a0509303158ca50de80ae32c265093b24c414705807832"
checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269"
dependencies = [
"indexmap 2.12.1",
"toml_datetime 0.7.3",
"toml_datetime 0.7.5+spec-1.1.0",
"toml_parser",
"winnow",
]
[[package]]
name = "toml_parser"
version = "1.0.4"
version = "1.0.6+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e"
checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44"
dependencies = [
"winnow",
]
@@ -12968,9 +12991,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3"
[[package]]
name = "tracing"
version = "0.1.43"
version = "0.1.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d15d90a0b5c19378952d479dc858407149d7bb45a14de0142f6c534b16fc647"
checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100"
dependencies = [
"log",
"pin-project-lite",
@@ -13003,9 +13026,9 @@ dependencies = [
[[package]]
name = "tracing-core"
version = "0.1.35"
version = "0.1.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a04e24fab5c89c6a36eb8558c9656f30d81de51dfa4d3b45f26b21d61fa0a6c"
checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a"
dependencies = [
"once_cell",
"valuable",
@@ -13074,6 +13097,22 @@ dependencies = [
"web-time",
]
[[package]]
name = "tracing-samply"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c175f7ecc002b6ef04776a39f440503e4e788790ddbdbfac8259b7a069526334"
dependencies = [
"cfg-if",
"itoa",
"libc",
"mach2",
"memmap2",
"smallvec",
"tracing-core",
"tracing-subscriber 0.3.22",
]
[[package]]
name = "tracing-serde"
version = "0.2.0"
@@ -13685,38 +13724,16 @@ dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "windows"
version = "0.61.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9babd3a767a4c1aef6900409f85f5d53ce2544ccdfaa86dad48c91782c6d6893"
dependencies = [
"windows-collections 0.2.0",
"windows-core 0.61.2",
"windows-future 0.2.1",
"windows-link 0.1.3",
"windows-numerics 0.2.0",
]
[[package]]
name = "windows"
version = "0.62.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "527fadee13e0c05939a6a05d5bd6eec6cd2e3dbd648b9f8e447c6518133d8580"
dependencies = [
"windows-collections 0.3.2",
"windows-collections",
"windows-core 0.62.2",
"windows-future 0.3.2",
"windows-numerics 0.3.1",
]
[[package]]
name = "windows-collections"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8"
dependencies = [
"windows-core 0.61.2",
"windows-future",
"windows-numerics",
]
[[package]]
@@ -13740,19 +13757,6 @@ dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "windows-core"
version = "0.61.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3"
dependencies = [
"windows-implement 0.60.2",
"windows-interface 0.59.3",
"windows-link 0.1.3",
"windows-result 0.3.4",
"windows-strings 0.4.2",
]
[[package]]
name = "windows-core"
version = "0.62.2"
@@ -13761,20 +13765,9 @@ checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb"
dependencies = [
"windows-implement 0.60.2",
"windows-interface 0.59.3",
"windows-link 0.2.1",
"windows-link",
"windows-result 0.4.1",
"windows-strings 0.5.1",
]
[[package]]
name = "windows-future"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc6a41e98427b19fe4b73c550f060b59fa592d7d686537eebf9385621bfbad8e"
dependencies = [
"windows-core 0.61.2",
"windows-link 0.1.3",
"windows-threading 0.1.0",
"windows-strings",
]
[[package]]
@@ -13784,8 +13777,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1d6f90251fe18a279739e78025bd6ddc52a7e22f921070ccdc67dde84c605cb"
dependencies = [
"windows-core 0.62.2",
"windows-link 0.2.1",
"windows-threading 0.2.1",
"windows-link",
"windows-threading",
]
[[package]]
@@ -13832,28 +13825,12 @@ dependencies = [
"syn 2.0.111",
]
[[package]]
name = "windows-link"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a"
[[package]]
name = "windows-link"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[package]]
name = "windows-numerics"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1"
dependencies = [
"windows-core 0.61.2",
"windows-link 0.1.3",
]
[[package]]
name = "windows-numerics"
version = "0.3.1"
@@ -13861,7 +13838,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e2e40844ac143cdb44aead537bbf727de9b044e107a0f1220392177d15b0f26"
dependencies = [
"windows-core 0.62.2",
"windows-link 0.2.1",
"windows-link",
]
[[package]]
@@ -13873,31 +13850,13 @@ dependencies = [
"windows-targets 0.52.6",
]
[[package]]
name = "windows-result"
version = "0.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6"
dependencies = [
"windows-link 0.1.3",
]
[[package]]
name = "windows-result"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5"
dependencies = [
"windows-link 0.2.1",
]
[[package]]
name = "windows-strings"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57"
dependencies = [
"windows-link 0.1.3",
"windows-link",
]
[[package]]
@@ -13906,7 +13865,7 @@ version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091"
dependencies = [
"windows-link 0.2.1",
"windows-link",
]
[[package]]
@@ -13960,7 +13919,7 @@ version = "0.61.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
dependencies = [
"windows-link 0.2.1",
"windows-link",
]
[[package]]
@@ -14015,7 +13974,7 @@ version = "0.53.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3"
dependencies = [
"windows-link 0.2.1",
"windows-link",
"windows_aarch64_gnullvm 0.53.1",
"windows_aarch64_msvc 0.53.1",
"windows_i686_gnu 0.53.1",
@@ -14026,22 +13985,13 @@ dependencies = [
"windows_x86_64_msvc 0.53.1",
]
[[package]]
name = "windows-threading"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b66463ad2e0ea3bbf808b7f1d371311c80e115c0b71d60efc142cafbcfb057a6"
dependencies = [
"windows-link 0.1.3",
]
[[package]]
name = "windows-threading"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3949bd5b99cafdf1c7ca86b43ca564028dfe27d66958f2470940f73d86d75b37"
dependencies = [
"windows-link 0.2.1",
"windows-link",
]
[[package]]

View File

@@ -730,6 +730,7 @@ socket2 = { version = "0.5", default-features = false }
sysinfo = { version = "0.33", default-features = false }
tracing-journald = "0.3"
tracing-logfmt = "0.3.3"
tracing-samply = "0.1"
tracing-subscriber = { version = "0.3", default-features = false }
triehash = "0.8"
typenum = "1.15.0"

View File

@@ -329,6 +329,7 @@ pub(crate) async fn run_comparison(args: Args, _ctx: CliContext) -> Result<()> {
output_dir.clone(),
git_manager.clone(),
args.features.clone(),
args.profile,
)?;
// Initialize node manager
let mut node_manager = NodeManager::new(&args);

View File

@@ -14,6 +14,7 @@ pub(crate) struct CompilationManager {
output_dir: PathBuf,
git_manager: GitManager,
features: String,
enable_profiling: bool,
}
impl CompilationManager {
@@ -23,8 +24,9 @@ impl CompilationManager {
output_dir: PathBuf,
git_manager: GitManager,
features: String,
enable_profiling: bool,
) -> Result<Self> {
Ok(Self { repo_root, output_dir, git_manager, features })
Ok(Self { repo_root, output_dir, git_manager, features, enable_profiling })
}
/// Detect if the RPC endpoint is an Optimism chain
@@ -100,9 +102,18 @@ impl CompilationManager {
let mut cmd = Command::new("cargo");
cmd.arg("build").arg("--profile").arg("profiling");
// Add features
cmd.arg("--features").arg(&self.features);
info!("Using features: {}", self.features);
// Append samply feature when profiling to enable tracing span markers.
// NOTE: The `samply` feature must exist in the branch being compiled. If comparing
// against an older branch that predates the samply integration, compilation will fail
// or markers won't appear. In that case, omit --profile or ensure both branches
// include the samply feature support.
let features = if self.enable_profiling && !self.features.contains("samply") {
format!("{},samply", self.features)
} else {
self.features.clone()
};
cmd.arg("--features").arg(&features);
info!("Using features: {}", features);
// Add bin-specific arguments for optimism
if is_optimism {

View File

@@ -87,6 +87,10 @@ otlp = [
"reth-ethereum-cli/otlp",
"reth-node-core/otlp",
]
samply = [
"reth-ethereum-cli/samply",
"reth-node-core/samply",
]
js-tracer = [
"reth-node-builder/js-tracer",
"reth-node-ethereum/js-tracer",
@@ -103,6 +107,7 @@ asm-keccak = [
"reth-node-ethereum/asm-keccak",
]
keccak-cache-global = [
"reth-node-core/keccak-cache-global",
"reth-node-ethereum/keccak-cache-global",
]
jemalloc = [

View File

@@ -115,6 +115,10 @@ harness = false
name = "state_root_task"
harness = false
[[bench]]
name = "state_provider_builder"
harness = false
[features]
test-utils = [
"reth-chain-state/test-utils",

View File

@@ -0,0 +1,49 @@
//! Benchmark for state provider builder reuse.
#![allow(missing_docs)]
use alloy_consensus::Header;
use alloy_primitives::B256;
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
use reth_engine_tree::tree::StateProviderBuilder;
use reth_ethereum_primitives::EthPrimitives;
use reth_provider::{test_utils::MockEthProvider, HeaderProvider};
use std::hint::black_box;
fn build_builder(
provider: &MockEthProvider<EthPrimitives>,
hash: B256,
) -> StateProviderBuilder<EthPrimitives, MockEthProvider<EthPrimitives>> {
let header = provider.header(hash).expect("header lookup failed");
assert!(header.is_some(), "missing header for hash");
StateProviderBuilder::new(provider.clone(), hash, None)
}
fn bench_state_provider_builder(c: &mut Criterion) {
let provider = MockEthProvider::<EthPrimitives>::new();
let hash = B256::from([0x11u8; 32]);
let header = Header { number: 1, ..Header::default() };
provider.add_header(hash, header);
let mut group = c.benchmark_group("state_provider_builder_reuse");
group.bench_with_input(BenchmarkId::new("single_lookup", 1), &hash, |b, hash| {
b.iter(|| {
let builder = build_builder(&provider, *hash);
black_box(builder);
});
});
group.bench_with_input(BenchmarkId::new("double_lookup", 2), &hash, |b, hash| {
b.iter(|| {
let first = build_builder(&provider, *hash);
let second = build_builder(&provider, *hash);
black_box((first, second));
});
});
group.finish();
}
criterion_group!(benches, bench_state_provider_builder);
criterion_main!(benches);

View File

@@ -1,5 +1,4 @@
use crate::metrics::PersistenceMetrics;
use alloy_consensus::BlockHeader;
use alloy_eips::BlockNumHash;
use reth_chain_state::ExecutedBlock;
use reth_errors::ProviderError;
@@ -142,27 +141,23 @@ where
&self,
blocks: Vec<ExecutedBlock<N::Primitives>>,
) -> Result<Option<BlockNumHash>, PersistenceError> {
let first_block_hash = blocks.first().map(|b| b.recovered_block.num_hash());
let last_block_hash = blocks.last().map(|b| b.recovered_block.num_hash());
debug!(target: "engine::persistence", first=?first_block_hash, last=?last_block_hash, "Saving range of blocks");
let first_block = blocks.first().map(|b| b.recovered_block.num_hash());
let last_block = blocks.last().map(|b| b.recovered_block.num_hash());
debug!(target: "engine::persistence", first=?first_block, last=?last_block, "Saving range of blocks");
let start_time = Instant::now();
let last_block_hash_num = blocks.last().map(|block| BlockNumHash {
hash: block.recovered_block().hash(),
number: block.recovered_block().header().number(),
});
if last_block_hash_num.is_some() {
if last_block.is_some() {
let provider_rw = self.provider.database_provider_rw()?;
provider_rw.save_blocks(blocks)?;
provider_rw.commit()?;
}
debug!(target: "engine::persistence", first=?first_block_hash, last=?last_block_hash, "Saved range of blocks");
debug!(target: "engine::persistence", first=?first_block, last=?last_block, "Saved range of blocks");
self.metrics.save_blocks_duration_seconds.record(start_time.elapsed());
Ok(last_block_hash_num)
Ok(last_block)
}
}

View File

@@ -14,7 +14,7 @@ use std::collections::{BTreeMap, HashMap, HashSet, VecDeque};
/// * [`BlockBuffer::remove_old_blocks`] to remove old blocks that precede the finalized number.
///
/// Note: Buffer is limited by number of blocks that it can contain and eviction of the block
/// is done by last recently used block.
/// is done in FIFO order (oldest inserted block is evicted first).
#[derive(Debug)]
pub struct BlockBuffer<B: Block> {
/// All blocks in the buffer stored by their block hash.

View File

@@ -321,7 +321,7 @@ where
BlockReader<Block = N::Block, Header = N::BlockHeader>,
C: ConfigureEvm<Primitives = N> + 'static,
T: PayloadTypes<BuiltPayload: BuiltPayload<Primitives = N>>,
V: EngineValidator<T>,
V: EngineValidator<T, N>,
{
/// Creates a new [`EngineApiTreeHandler`].
#[expect(clippy::too_many_arguments)]
@@ -931,48 +931,6 @@ where
Ok(())
}
/// Determines if the given block is part of a fork by checking that these
/// conditions are true:
/// * walking back from the target hash to verify that the target hash is not part of an
/// extension of the canonical chain.
/// * walking back from the current head to verify that the target hash is not already part of
/// the canonical chain.
///
/// The header is required as an arg, because we might be checking that the header is a fork
/// block before it's in the tree state and before it's in the database.
fn is_fork(&self, target: BlockWithParent) -> ProviderResult<bool> {
let target_hash = target.block.hash;
// verify that the given hash is not part of an extension of the canon chain.
let canonical_head = self.state.tree_state.canonical_head();
let mut current_hash;
let mut current_block = target;
loop {
if current_block.block.hash == canonical_head.hash {
return Ok(false)
}
// We already passed the canonical head
if current_block.block.number <= canonical_head.number {
break
}
current_hash = current_block.parent;
let Some(next_block) = self.sealed_header_by_hash(current_hash)? else { break };
current_block = next_block.block_with_parent();
}
// verify that the given hash is not already part of canonical chain stored in memory
if self.canonical_in_memory_state.header_by_hash(target_hash).is_some() {
return Ok(false)
}
// verify that the given hash is not already part of persisted canonical chain
if self.provider.block_number(target_hash)?.is_some() {
return Ok(false)
}
Ok(true)
}
/// Invoked when we receive a new forkchoice update message. Calls into the blockchain tree
/// to resolve chain forks and ensure that the Execution Layer is working with the latest valid
/// chain.
@@ -2479,7 +2437,9 @@ where
self.insert_block_or_payload(
payload.block_with_parent(),
payload,
|validator, payload, ctx| validator.validate_payload(payload, ctx),
|validator, payload, ctx, provider_builder| {
validator.validate_payload(payload, ctx, provider_builder)
},
|this, payload| Ok(this.payload_validator.convert_payload_to_block(payload)?),
)
}
@@ -2491,7 +2451,9 @@ where
self.insert_block_or_payload(
block.block_with_parent(),
block,
|validator, block, ctx| validator.validate_block(block, ctx),
|validator, block, ctx, provider_builder| {
validator.validate_block(block, ctx, provider_builder)
},
|_, block| Ok(block),
)
}
@@ -2517,7 +2479,12 @@ where
&mut self,
block_id: BlockWithParent,
input: Input,
execute: impl FnOnce(&mut V, Input, TreeCtx<'_, N>) -> Result<ExecutedBlock<N>, Err>,
execute: impl FnOnce(
&mut V,
Input,
TreeCtx<'_, N>,
V::ProviderBuilder,
) -> Result<ExecutedBlock<N>, Err>,
convert_to_block: impl FnOnce(&mut Self, Input) -> Result<SealedBlock<N::Block>, Err>,
) -> Result<InsertPayloadOk, Err>
where
@@ -2542,7 +2509,7 @@ where
};
// Ensure that the parent state is available.
match self.state_provider_builder(block_id.parent) {
let provider_builder = match self.payload_validator.provider_builder(block_id.parent, &self.state) {
Err(err) => {
let block = convert_to_block(self, input)?;
return Err(InsertBlockError::new(block, err.into()).into());
@@ -2566,23 +2533,20 @@ where
missing_ancestor,
}))
}
Ok(Some(_)) => {}
}
// determine whether we are on a fork chain
let is_fork = match self.is_fork(block_id) {
Err(err) => {
let block = convert_to_block(self, input)?;
return Err(InsertBlockError::new(block, err.into()).into());
}
Ok(is_fork) => is_fork,
Ok(Some(provider_builder)) => provider_builder,
};
// determine whether we are on a fork chain by comparing the block number with the
// canonical head. This is a simple check that is sufficient for the event emission below.
// A block is considered a fork if its number is less than or equal to the canonical head,
// as this indicates there's already a canonical block at that height.
let is_fork = block_id.block.number <= self.state.tree_state.current_canonical_head.number;
let ctx = TreeCtx::new(&mut self.state, &self.canonical_in_memory_state);
let start = Instant::now();
let executed = execute(&mut self.payload_validator, input, ctx)?;
let executed = execute(&mut self.payload_validator, input, ctx, provider_builder)?;
// if the parent is the canonical head, we can insert the block as the pending block
if self.state.tree_state.canonical_block_hash() == executed.recovered_block().parent_hash()

View File

@@ -3,11 +3,7 @@
use crate::tree::payload_processor::bal::bal_to_hashed_post_state;
use alloy_eip7928::BlockAccessList;
use alloy_evm::block::StateChangeSource;
use alloy_primitives::{
keccak256,
map::{B256Set, HashSet},
B256,
};
use alloy_primitives::{keccak256, map::HashSet, B256};
use crossbeam_channel::{unbounded, Receiver as CrossbeamReceiver, Sender as CrossbeamSender};
use dashmap::DashMap;
use derive_more::derive::Deref;
@@ -23,7 +19,6 @@ use reth_trie_parallel::{
proof::ParallelProof,
proof_task::{
AccountMultiproofInput, ProofResultContext, ProofResultMessage, ProofWorkerHandle,
StorageProofInput,
},
};
use std::{collections::BTreeMap, mem, ops::DerefMut, sync::Arc, time::Instant};
@@ -236,74 +231,6 @@ pub(crate) fn evm_state_to_hashed_post_state(update: EvmState) -> HashedPostStat
hashed_state
}
/// A pending multiproof task, either [`StorageMultiproofInput`] or [`MultiproofInput`].
#[derive(Debug)]
enum PendingMultiproofTask {
/// A storage multiproof task input.
Storage(StorageMultiproofInput),
/// A regular multiproof task input.
Regular(MultiproofInput),
}
impl PendingMultiproofTask {
/// Returns the proof sequence number of the task.
const fn proof_sequence_number(&self) -> u64 {
match self {
Self::Storage(input) => input.proof_sequence_number,
Self::Regular(input) => input.proof_sequence_number,
}
}
/// Returns whether or not the proof targets are empty.
fn proof_targets_is_empty(&self) -> bool {
match self {
Self::Storage(input) => input.proof_targets.is_empty(),
Self::Regular(input) => input.proof_targets.is_empty(),
}
}
/// Destroys the input and sends a [`MultiProofMessage::EmptyProof`] message to the sender.
fn send_empty_proof(self) {
match self {
Self::Storage(input) => input.send_empty_proof(),
Self::Regular(input) => input.send_empty_proof(),
}
}
}
impl From<StorageMultiproofInput> for PendingMultiproofTask {
fn from(input: StorageMultiproofInput) -> Self {
Self::Storage(input)
}
}
impl From<MultiproofInput> for PendingMultiproofTask {
fn from(input: MultiproofInput) -> Self {
Self::Regular(input)
}
}
/// Input parameters for dispatching a dedicated storage multiproof calculation.
#[derive(Debug)]
struct StorageMultiproofInput {
hashed_state_update: HashedPostState,
hashed_address: B256,
proof_targets: B256Set,
proof_sequence_number: u64,
state_root_message_sender: CrossbeamSender<MultiProofMessage>,
multi_added_removed_keys: Arc<MultiAddedRemovedKeys>,
}
impl StorageMultiproofInput {
/// Destroys the input and sends a [`MultiProofMessage::EmptyProof`] message to the sender.
fn send_empty_proof(self) {
let _ = self.state_root_message_sender.send(MultiProofMessage::EmptyProof {
sequence_number: self.proof_sequence_number,
state: self.hashed_state_update,
});
}
}
/// Input parameters for dispatching a multiproof calculation.
#[derive(Debug)]
struct MultiproofInput {
@@ -378,91 +305,18 @@ impl MultiproofManager {
}
/// Dispatches a new multiproof calculation to worker pools.
fn dispatch(&self, input: PendingMultiproofTask) {
fn dispatch(&self, input: MultiproofInput) {
// If there are no proof targets, we can just send an empty multiproof back immediately
if input.proof_targets_is_empty() {
if input.proof_targets.is_empty() {
trace!(
sequence_number = input.proof_sequence_number(),
sequence_number = input.proof_sequence_number,
"No proof targets, sending empty multiproof back immediately"
);
input.send_empty_proof();
return;
}
match input {
PendingMultiproofTask::Storage(storage_input) => {
self.dispatch_storage_proof(storage_input);
}
PendingMultiproofTask::Regular(multiproof_input) => {
self.dispatch_multiproof(multiproof_input);
}
}
}
/// Dispatches a single storage proof calculation to worker pool.
fn dispatch_storage_proof(&self, storage_multiproof_input: StorageMultiproofInput) {
let StorageMultiproofInput {
hashed_state_update,
hashed_address,
proof_targets,
proof_sequence_number,
multi_added_removed_keys,
state_root_message_sender: _,
} = storage_multiproof_input;
let storage_targets = proof_targets.len();
trace!(
target: "engine::tree::payload_processor::multiproof",
proof_sequence_number,
?proof_targets,
storage_targets,
"Dispatching storage proof to workers"
);
let start = Instant::now();
// Create prefix set from targets
let prefix_set = reth_trie::prefix_set::PrefixSetMut::from(
proof_targets.iter().map(reth_trie::Nibbles::unpack),
);
let prefix_set = prefix_set.freeze();
// Build computation input (data only)
let input = StorageProofInput::new(
hashed_address,
prefix_set,
proof_targets,
true, // with_branch_node_masks
Some(multi_added_removed_keys),
);
// Dispatch to storage worker
if let Err(e) = self.proof_worker_handle.dispatch_storage_proof(
input,
ProofResultContext::new(
self.proof_result_tx.clone(),
proof_sequence_number,
hashed_state_update,
start,
),
) {
error!(target: "engine::tree::payload_processor::multiproof", ?e, "Failed to dispatch storage proof");
return;
}
self.metrics
.active_storage_workers_histogram
.record(self.proof_worker_handle.active_storage_workers() as f64);
self.metrics
.active_account_workers_histogram
.record(self.proof_worker_handle.active_account_workers() as f64);
self.metrics
.pending_storage_multiproofs_histogram
.record(self.proof_worker_handle.pending_storage_tasks() as f64);
self.metrics
.pending_account_multiproofs_histogram
.record(self.proof_worker_handle.pending_account_tasks() as f64);
self.dispatch_multiproof(input);
}
/// Signals that a multiproof calculation has finished.
@@ -809,17 +663,14 @@ impl MultiProofTask {
available_storage_workers,
MultiProofTargets::chunks,
|proof_targets| {
self.multiproof_manager.dispatch(
MultiproofInput {
source: None,
hashed_state_update: Default::default(),
proof_targets,
proof_sequence_number: self.proof_sequencer.next_sequence(),
state_root_message_sender: self.tx.clone(),
multi_added_removed_keys: Some(multi_added_removed_keys.clone()),
}
.into(),
);
self.multiproof_manager.dispatch(MultiproofInput {
source: None,
hashed_state_update: Default::default(),
proof_targets,
proof_sequence_number: self.proof_sequencer.next_sequence(),
state_root_message_sender: self.tx.clone(),
multi_added_removed_keys: Some(multi_added_removed_keys.clone()),
});
},
);
self.metrics.prefetch_proof_chunks_histogram.record(num_chunks as f64);
@@ -967,17 +818,14 @@ impl MultiProofTask {
);
spawned_proof_targets.extend_ref(&proof_targets);
self.multiproof_manager.dispatch(
MultiproofInput {
source: Some(source),
hashed_state_update,
proof_targets,
proof_sequence_number: self.proof_sequencer.next_sequence(),
state_root_message_sender: self.tx.clone(),
multi_added_removed_keys: Some(multi_added_removed_keys.clone()),
}
.into(),
);
self.multiproof_manager.dispatch(MultiproofInput {
source: Some(source),
hashed_state_update,
proof_targets,
proof_sequence_number: self.proof_sequencer.next_sequence(),
state_root_message_sender: self.tx.clone(),
multi_added_removed_keys: Some(multi_added_removed_keys.clone()),
});
},
);
self.metrics

View File

@@ -166,8 +166,7 @@ where
// Update storage slots with new values and calculate storage roots.
let span = tracing::Span::current();
let (tx, rx) = mpsc::channel();
state
let results: Vec<_> = state
.storages
.into_iter()
.map(|(address, storage)| (address, storage, trie.take_storage_trie(&address)))
@@ -217,13 +216,7 @@ where
SparseStateTrieResult::Ok((address, storage_trie))
})
.for_each_init(
|| tx.clone(),
|tx, result| {
let _ = tx.send(result);
},
);
drop(tx);
.collect();
// Defer leaf removals until after updates/additions, so that we don't delete an intermediate
// branch node during a removal and then re-add that branch back during a later leaf addition.
@@ -235,7 +228,7 @@ where
let _enter =
tracing::debug_span!(target: "engine::tree::payload_processor::sparse_trie", "account trie")
.entered();
for result in rx {
for result in results {
let (address, storage_trie) = result?;
trie.insert_storage_trie(address, storage_trie);

View File

@@ -323,6 +323,7 @@ where
&mut self,
input: BlockOrPayload<T>,
mut ctx: TreeCtx<'_, N>,
provider_builder: StateProviderBuilder<N, P>,
) -> ValidationOutcome<N, InsertPayloadError<N::Block>>
where
V: PayloadValidator<T, Block = N::Block>,
@@ -362,16 +363,6 @@ where
trace!(target: "engine::tree::payload_validator", "Fetching block state provider");
let _enter =
debug_span!(target: "engine::tree::payload_validator", "state provider").entered();
let Some(provider_builder) =
ensure_ok!(self.state_provider_builder(parent_hash, ctx.state()))
else {
// this is pre-validated in the tree
return Err(InsertBlockError::new(
self.convert_to_block(input)?,
ProviderError::HeaderNotFound(parent_hash.into()).into(),
)
.into())
};
let mut state_provider = ensure_ok!(provider_builder.build());
drop(_enter);
@@ -876,37 +867,6 @@ where
}
}
/// Creates a `StateProviderBuilder` for the given parent hash.
///
/// This method checks if the parent is in the tree state (in-memory) or persisted to disk,
/// and creates the appropriate provider builder.
fn state_provider_builder(
&self,
hash: B256,
state: &EngineApiTreeState<N>,
) -> ProviderResult<Option<StateProviderBuilder<N, P>>> {
if let Some((historical, blocks)) = state.tree_state.blocks_by_hash(hash) {
debug!(target: "engine::tree::payload_validator", %hash, %historical, "found canonical state for block in memory, creating provider builder");
// the block leads back to the canonical chain
return Ok(Some(StateProviderBuilder::new(
self.provider.clone(),
historical,
Some(blocks),
)))
}
// Check if the block is persisted
if let Some(header) = self.provider.header(hash)? {
debug!(target: "engine::tree::payload_validator", %hash, number = %header.number(), "found canonical state for block in database, creating provider builder");
// For persisted blocks, we create a builder that will fetch state directly from the
// database
return Ok(Some(StateProviderBuilder::new(self.provider.clone(), hash, None)))
}
debug!(target: "engine::tree::payload_validator", %hash, "no canonical state found for block");
Ok(None)
}
/// Determines the state root computation strategy based on configuration.
///
/// Note: Use state root task only if prefix sets are empty, otherwise proof generation is
@@ -1129,6 +1089,19 @@ pub trait EngineValidator<
N: NodePrimitives = <<Types as PayloadTypes>::BuiltPayload as BuiltPayload>::Primitives,
>: Send + Sync + 'static
{
/// State provider builder type used by the validator.
type ProviderBuilder;
/// Creates a `StateProviderBuilder` for the given parent hash.
///
/// This method checks if the parent is in the tree state (in-memory) or persisted to disk,
/// and creates the appropriate provider builder.
fn provider_builder(
&self,
hash: B256,
state: &EngineApiTreeState<N>,
) -> ProviderResult<Option<Self::ProviderBuilder>>;
/// Validates the payload attributes with respect to the header.
///
/// By default, this enforces that the payload attributes timestamp is greater than the
@@ -1162,6 +1135,7 @@ pub trait EngineValidator<
&mut self,
payload: Types::ExecutionData,
ctx: TreeCtx<'_, N>,
provider_builder: Self::ProviderBuilder,
) -> ValidationOutcome<N>;
/// Validates a block downloaded from the network.
@@ -1169,6 +1143,7 @@ pub trait EngineValidator<
&mut self,
block: SealedBlock<N::Block>,
ctx: TreeCtx<'_, N>,
provider_builder: Self::ProviderBuilder,
) -> ValidationOutcome<N>;
/// Hook called after an executed block is inserted directly into the tree.
@@ -1193,6 +1168,35 @@ where
Evm: ConfigureEngineEvm<Types::ExecutionData, Primitives = N> + 'static,
Types: PayloadTypes<BuiltPayload: BuiltPayload<Primitives = N>>,
{
type ProviderBuilder = StateProviderBuilder<N, P>;
fn provider_builder(
&self,
hash: B256,
state: &EngineApiTreeState<N>,
) -> ProviderResult<Option<Self::ProviderBuilder>> {
if let Some((historical, blocks)) = state.tree_state.blocks_by_hash(hash) {
debug!(target: "engine::tree::payload_validator", %hash, %historical, "found canonical state for block in memory, creating provider builder");
// the block leads back to the canonical chain
return Ok(Some(StateProviderBuilder::new(
self.provider.clone(),
historical,
Some(blocks),
)))
}
// Check if the block is persisted
if let Some(header) = self.provider.header(hash)? {
debug!(target: "engine::tree::payload_validator", %hash, number = %header.number(), "found canonical state for block in database, creating provider builder");
// For persisted blocks, we create a builder that will fetch state directly from the
// database
return Ok(Some(StateProviderBuilder::new(self.provider.clone(), hash, None)))
}
debug!(target: "engine::tree::payload_validator", %hash, "no canonical state found for block");
Ok(None)
}
fn validate_payload_attributes_against_header(
&self,
attr: &Types::PayloadAttributes,
@@ -1213,16 +1217,18 @@ where
&mut self,
payload: Types::ExecutionData,
ctx: TreeCtx<'_, N>,
provider_builder: Self::ProviderBuilder,
) -> ValidationOutcome<N> {
self.validate_block_with_state(BlockOrPayload::Payload(payload), ctx)
self.validate_block_with_state(BlockOrPayload::Payload(payload), ctx, provider_builder)
}
fn validate_block(
&mut self,
block: SealedBlock<N::Block>,
ctx: TreeCtx<'_, N>,
provider_builder: Self::ProviderBuilder,
) -> ValidationOutcome<N> {
self.validate_block_with_state(BlockOrPayload::Block(block), ctx)
self.validate_block_with_state(BlockOrPayload::Block(block), ctx, provider_builder)
}
fn on_inserted_executed_block(&self, block: ExecutedBlock<N>) {

View File

@@ -2,6 +2,7 @@
use alloy_primitives::Bytes;
use dashmap::DashMap;
use moka::policy::EvictionPolicy;
use reth_evm::precompiles::{DynPrecompile, Precompile, PrecompileInput};
use revm::precompile::{PrecompileId, PrecompileOutput, PrecompileResult};
use revm_primitives::Address;
@@ -49,6 +50,7 @@ where
Self(
moka::sync::CacheBuilder::new(MAX_CACHE_SIZE as u64)
.initial_capacity(MAX_CACHE_SIZE as usize)
.eviction_policy(EvictionPolicy::lru())
.build_with_hasher(Default::default()),
)
}

View File

@@ -428,7 +428,13 @@ impl ValidatorTestHarness {
&mut self.harness.tree.state,
&self.harness.tree.canonical_in_memory_state,
);
let result = self.validator.validate_block(block, ctx);
let provider_builder = self
.harness
.tree
.state_provider_builder(block.parent_hash())
.expect("state provider builder lookup failed")
.expect("missing parent state provider builder");
let result = self.validator.validate_block(block, ctx, provider_builder);
self.metrics.record_validation(result.is_ok());
result
}

View File

@@ -38,6 +38,7 @@ tempfile.workspace = true
default = []
otlp = ["reth-tracing/otlp", "reth-node-core/otlp"]
samply = ["reth-tracing/samply", "reth-node-core/samply"]
dev = ["reth-cli-commands/arbitrary"]

View File

@@ -87,9 +87,7 @@ fn verify_receipts<R: Receipt>(
logs_bloom,
expected_receipts_root,
expected_logs_bloom,
)?;
Ok(())
)
}
/// Compare the calculated receipts root with the expected receipts root, also compare

View File

@@ -91,6 +91,7 @@ asm-keccak = [
]
keccak-cache-global = [
"alloy-primitives/keccak-cache-global",
"reth-node-core/keccak-cache-global",
]
js-tracer = [
"reth-node-builder/js-tracer",

View File

@@ -81,6 +81,7 @@ arbitrary = [
]
keccak-cache-global = [
"reth-node-ethereum?/keccak-cache-global",
"reth-node-core?/keccak-cache-global",
]
test-utils = [
"reth-chainspec/test-utils",

View File

@@ -61,8 +61,6 @@ pub use alloy_evm::{
*,
};
pub use alloy_evm::block::state_changes as state_change;
/// A complete configuration of EVM for Reth.
///
/// This trait encapsulates complete configuration required for transaction execution and block

View File

@@ -312,7 +312,6 @@ impl ECIES {
/// Create a new ECIES client with the given static secret key and remote peer ID.
pub fn new_client(secret_key: SecretKey, remote_id: PeerId) -> Result<Self, ECIESError> {
// TODO(rand): use rng for nonce
let mut rng = rng();
let nonce = B256::random();
let ephemeral_secret_key = SecretKey::new(&mut rng);

View File

@@ -938,9 +938,13 @@ where
///
/// A target block hash if the pipeline is inconsistent, otherwise `None`.
pub fn check_pipeline_consistency(&self) -> ProviderResult<Option<B256>> {
// We skip the era stage if it's not enabled
let era_enabled = self.era_import_source().is_some();
let mut all_stages =
StageId::ALL.into_iter().filter(|id| era_enabled || id != &StageId::Era);
// Get the expected first stage based on config.
let first_stage =
if self.era_import_source().is_some() { StageId::Era } else { StageId::Headers };
let first_stage = all_stages.next().expect("there must be at least one stage");
// If no target was provided, check if the stages are congruent - check if the
// checkpoint of the last stage matches the checkpoint of the first.
@@ -950,20 +954,28 @@ where
.unwrap_or_default()
.block_number;
// Skip the first stage as we've already retrieved it and comparing all other checkpoints
// against it.
for stage_id in StageId::ALL.iter().skip(1) {
// Compare all other stages against the first
for stage_id in all_stages {
let stage_checkpoint = self
.blockchain_db()
.get_stage_checkpoint(*stage_id)?
.get_stage_checkpoint(stage_id)?
.unwrap_or_default()
.block_number;
// If the checkpoint of any stage is less than the checkpoint of the first stage,
// retrieve and return the block hash of the latest header and use it as the target.
debug!(
target: "consensus::engine",
first_stage_id = %first_stage,
first_stage_checkpoint,
stage_id = %stage_id,
stage_checkpoint = stage_checkpoint,
"Checking stage against first stage",
);
if stage_checkpoint < first_stage_checkpoint {
debug!(
target: "consensus::engine",
first_stage_id = %first_stage,
first_stage_checkpoint,
inconsistent_stage_id = %stage_id,
inconsistent_stage_checkpoint = stage_checkpoint,

View File

@@ -80,8 +80,9 @@ tokio.workspace = true
# Features for vergen to generate correct env vars
jemalloc = ["reth-cli-util/jemalloc"]
asm-keccak = ["alloy-primitives/asm-keccak"]
# Feature to enable opentelemetry export
keccak-cache-global = ["alloy-primitives/keccak-cache-global"]
otlp = ["reth-tracing/otlp"]
samply = ["reth-tracing/samply"]
min-error-logs = ["tracing/release_max_level_error"]
min-warn-logs = ["tracing/release_max_level_warn"]

View File

@@ -30,6 +30,7 @@ workspace = true
default = ["jemalloc", "otlp", "reth-optimism-evm/portable", "js-tracer", "keccak-cache-global", "asm-keccak"]
otlp = ["reth-optimism-cli/otlp"]
samply = ["reth-optimism-cli/samply"]
js-tracer = [
"reth-optimism-node/js-tracer",

View File

@@ -78,6 +78,7 @@ default = []
# Opentelemtry feature to activate metrics export
otlp = ["reth-tracing/otlp", "reth-node-core/otlp"]
samply = ["reth-tracing/samply", "reth-node-core/samply"]
asm-keccak = [
"alloy-primitives/asm-keccak",

View File

@@ -83,6 +83,7 @@ reth-rpc-eth-types.workspace = true
reth-stages-types.workspace = true
alloy-network.workspace = true
alloy-op-hardforks.workspace = true
futures.workspace = true
op-alloy-network.workspace = true
@@ -96,6 +97,7 @@ asm-keccak = [
]
keccak-cache-global = [
"alloy-primitives/keccak-cache-global",
"reth-node-core/keccak-cache-global",
"reth-optimism-node/keccak-cache-global",
]
js-tracer = [

View File

@@ -299,23 +299,16 @@ mod test {
use super::*;
use crate::engine;
use alloy_op_hardforks::BASE_SEPOLIA_JOVIAN_TIMESTAMP;
use alloy_primitives::{b64, Address, B256, B64};
use alloy_rpc_types_engine::PayloadAttributes;
use reth_chainspec::{ChainSpec, ForkCondition, Hardfork};
use reth_chainspec::ChainSpec;
use reth_optimism_chainspec::{OpChainSpec, BASE_SEPOLIA};
use reth_optimism_forks::OpHardfork;
use reth_provider::noop::NoopProvider;
use reth_trie_common::KeccakKeyHasher;
const JOVIAN_TIMESTAMP: u64 = 1744909000;
fn get_chainspec() -> Arc<OpChainSpec> {
let mut base_sepolia_spec = BASE_SEPOLIA.inner.clone();
// TODO: Remove this once we know the Jovian timestamp
base_sepolia_spec
.hardforks
.insert(OpHardfork::Jovian.boxed(), ForkCondition::Timestamp(JOVIAN_TIMESTAMP));
let base_sepolia_spec = BASE_SEPOLIA.inner.clone();
Arc::new(OpChainSpec {
inner: ChainSpec {
@@ -427,7 +420,8 @@ mod test {
fn test_well_formed_attributes_jovian_valid() {
let validator =
OpEngineValidator::new::<KeccakKeyHasher>(get_chainspec(), NoopProvider::default());
let attributes = get_attributes(Some(b64!("0000000000000000")), Some(1), JOVIAN_TIMESTAMP);
let attributes =
get_attributes(Some(b64!("0000000000000000")), Some(1), BASE_SEPOLIA_JOVIAN_TIMESTAMP);
let result = <engine::OpEngineValidator<_, _, _> as EngineApiValidator<
OpEngineTypes,
@@ -442,7 +436,7 @@ mod test {
fn test_malformed_attributes_jovian_with_eip_1559_params_none() {
let validator =
OpEngineValidator::new::<KeccakKeyHasher>(get_chainspec(), NoopProvider::default());
let attributes = get_attributes(None, Some(1), JOVIAN_TIMESTAMP);
let attributes = get_attributes(None, Some(1), BASE_SEPOLIA_JOVIAN_TIMESTAMP);
let result = <engine::OpEngineValidator<_, _, _> as EngineApiValidator<
OpEngineTypes,
@@ -472,7 +466,8 @@ mod test {
fn test_malformed_attributes_post_jovian_with_min_base_fee_none() {
let validator =
OpEngineValidator::new::<KeccakKeyHasher>(get_chainspec(), NoopProvider::default());
let attributes = get_attributes(Some(b64!("0000000000000000")), None, JOVIAN_TIMESTAMP);
let attributes =
get_attributes(Some(b64!("0000000000000000")), None, BASE_SEPOLIA_JOVIAN_TIMESTAMP);
let result = <engine::OpEngineValidator<_, _, _> as EngineApiValidator<
OpEngineTypes,

View File

@@ -76,6 +76,7 @@ arbitrary = [
]
keccak-cache-global = [
"reth-optimism-node?/keccak-cache-global",
"reth-node-core?/keccak-cache-global",
]
test-utils = [
"reth-chainspec/test-utils",

View File

@@ -5,7 +5,7 @@ use reth_consensus::ConsensusError;
use reth_primitives_traits::{GotExpected, SealedHeader};
use reth_provider::{
ChainStateBlockReader, DBProvider, HeaderProvider, ProviderError, PruneCheckpointReader,
PruneCheckpointWriter, StageCheckpointReader, TrieWriter,
PruneCheckpointWriter, StageCheckpointReader, StageCheckpointWriter, TrieWriter,
};
use reth_prune_types::{
PruneCheckpoint, PruneMode, PruneSegment, MERKLE_CHANGESETS_RETENTION_BLOCKS,
@@ -300,6 +300,7 @@ where
+ DBProvider
+ HeaderProvider
+ ChainStateBlockReader
+ StageCheckpointWriter
+ PruneCheckpointReader
+ PruneCheckpointWriter,
{
@@ -404,6 +405,28 @@ where
computed_range.start = computed_range.end;
}
// If we've unwound so far that there are no longer enough trie changesets available then
// simply clear them and the checkpoints, so that on next pipeline startup they will be
// regenerated.
debug!(
target: "sync::stages::merkle_changesets",
?computed_range,
retention_blocks=?self.retention_blocks,
"Checking if computed range is over retention threshold",
);
if computed_range.end - computed_range.start < self.retention_blocks {
debug!(
target: "sync::stages::merkle_changesets",
?computed_range,
retention_blocks=?self.retention_blocks,
"Clearing checkpoints completely",
);
provider.clear_trie_changesets()?;
provider
.save_stage_checkpoint(StageId::MerkleChangeSets, StageCheckpoint::default())?;
return Ok(UnwindOutput { checkpoint: StageCheckpoint::default() })
}
// `computed_range.end` is exclusive
let checkpoint = StageCheckpoint::new(computed_range.end.saturating_sub(1));

View File

@@ -30,7 +30,7 @@ pub trait DbTxUnwindExt: DbTxMut {
let mut deleted = 0;
while let Some(Ok((entry_key, _))) = reverse_walker.next() {
if selector(entry_key.clone()) <= key {
if selector(entry_key) <= key {
break
}
reverse_walker.delete_current()?;

View File

@@ -12936,125 +12936,6 @@ int mdbx_txn_renew(MDBX_txn *txn) {
return LOG_IFERR(rc);
}
int mdbx_txn_clone(const MDBX_txn *src, MDBX_txn **dest) {
if (unlikely(!dest))
return LOG_IFERR(MDBX_EINVAL);
*dest = nullptr;
int rc = check_txn(src, MDBX_TXN_BLOCKED);
if (unlikely(rc != MDBX_SUCCESS))
return LOG_IFERR(rc);
if (unlikely((src->flags & MDBX_TXN_RDONLY) == 0))
return LOG_IFERR(MDBX_EINVAL);
MDBX_env *const env = src->env;
rc = check_env(env, true);
if (unlikely(rc != MDBX_SUCCESS))
return LOG_IFERR(rc);
if (unlikely((env->flags & MDBX_NOSTICKYTHREADS) == 0))
return LOG_IFERR(MDBX_TXN_OVERLAPPING);
MDBX_txn *txn = nullptr;
const intptr_t bitmap_bytes =
#if MDBX_ENABLE_DBI_SPARSE
ceil_powerof2(env->max_dbi, CHAR_BIT * sizeof(txn->dbi_sparse[0])) / CHAR_BIT;
#else
0;
#endif /* MDBX_ENABLE_DBI_SPARSE */
STATIC_ASSERT(sizeof(txn->tw) > sizeof(txn->to));
const size_t base = sizeof(MDBX_txn) - sizeof(txn->tw) + sizeof(txn->to);
const size_t size = base + (size_t)bitmap_bytes + env->max_dbi * sizeof(txn->dbi_seqs[0]) +
env->max_dbi * (sizeof(txn->dbs[0]) + sizeof(txn->cursors[0]) + sizeof(txn->dbi_state[0]));
txn = osal_malloc(size);
if (unlikely(txn == nullptr))
return LOG_IFERR(MDBX_ENOMEM);
#if MDBX_DEBUG
memset(txn, 0xCD, size);
VALGRIND_MAKE_MEM_UNDEFINED(txn, size);
#endif /* MDBX_DEBUG */
MDBX_ANALYSIS_ASSUME(size > base);
memset(txn, 0, (MDBX_GOOFY_MSVC_STATIC_ANALYZER && base > size) ? size : base);
txn->dbs = ptr_disp(txn, base);
txn->cursors = ptr_disp(txn->dbs, env->max_dbi * sizeof(txn->dbs[0]));
#if MDBX_DEBUG
txn->cursors[FREE_DBI] = nullptr; /* avoid SIGSEGV in an assertion later */
#endif
txn->dbi_state = ptr_disp(txn, size - env->max_dbi * sizeof(txn->dbi_state[0]));
txn->dbi_seqs = ptr_disp(txn->cursors, env->max_dbi * sizeof(txn->cursors[0]));
#if MDBX_ENABLE_DBI_SPARSE
txn->dbi_sparse = ptr_disp(txn->dbi_state, -bitmap_bytes);
#endif /* MDBX_ENABLE_DBI_SPARSE */
txn->env = env;
txn->flags = src->flags & ~txn_state_flags;
txn->parent = nullptr;
txn->nested = nullptr;
txn->txnid = src->txnid;
txn->front_txnid = src->front_txnid;
txn->geo = src->geo;
txn->canary = src->canary;
txn->owner = (env->flags & MDBX_NOSTICKYTHREADS) ? 0 : osal_thread_self();
if (unlikely(src->n_dbi > env->max_dbi)) {
rc = MDBX_CORRUPTED;
goto bailout;
}
txn->n_dbi = src->n_dbi;
memset(txn->cursors, 0, env->max_dbi * sizeof(txn->cursors[0]));
memset(txn->dbi_state, 0, env->max_dbi * sizeof(txn->dbi_state[0]));
memset(txn->dbi_seqs, 0, env->max_dbi * sizeof(txn->dbi_seqs[0]));
#if MDBX_ENABLE_DBI_SPARSE
if (bitmap_bytes)
memset(txn->dbi_sparse, 0, bitmap_bytes);
#endif /* MDBX_ENABLE_DBI_SPARSE */
memcpy(txn->dbs, src->dbs, txn->n_dbi * sizeof(txn->dbs[0]));
memcpy(txn->dbi_state, src->dbi_state, txn->n_dbi * sizeof(txn->dbi_state[0]));
memcpy(txn->dbi_seqs, src->dbi_seqs, txn->n_dbi * sizeof(txn->dbi_seqs[0]));
#if MDBX_ENABLE_DBI_SPARSE
if (bitmap_bytes)
memcpy(txn->dbi_sparse, src->dbi_sparse, bitmap_bytes);
#endif /* MDBX_ENABLE_DBI_SPARSE */
txn->to.reader = nullptr;
if (env->lck_mmap.lck) {
bsr_t brs = mvcc_bind_slot(env);
if (unlikely(brs.err != MDBX_SUCCESS)) {
rc = brs.err;
goto bailout;
}
txn->to.reader = brs.rslot;
safe64_reset(&txn->to.reader->txnid, true);
if (src->to.reader) {
atomic_store32(&txn->to.reader->snapshot_pages_used,
atomic_load32(&src->to.reader->snapshot_pages_used, mo_Relaxed), mo_Relaxed);
atomic_store64(&txn->to.reader->snapshot_pages_retired,
atomic_load64(&src->to.reader->snapshot_pages_retired, mo_Relaxed), mo_Relaxed);
} else {
atomic_store32(&txn->to.reader->snapshot_pages_used, src->geo.first_unallocated, mo_Relaxed);
atomic_store64(&txn->to.reader->snapshot_pages_retired, 0, mo_Relaxed);
}
safe64_write(&txn->to.reader->txnid, src->txnid);
atomic_store32(&env->lck->rdt_refresh_flag, true, mo_AcquireRelease);
}
txn->signature = txn_signature;
txn->userctx = nullptr;
*dest = txn;
DEBUG("clone txn %" PRIaTXN "r %p from %p on env %p", txn->txnid, (void *)txn, (void *)src, (void *)env);
return MDBX_SUCCESS;
bailout:
osal_free(txn);
return LOG_IFERR(rc);
}
int mdbx_txn_set_userctx(MDBX_txn *txn, void *ctx) {
int rc = check_txn(txn, MDBX_TXN_FINISHED);
if (unlikely(rc != MDBX_SUCCESS))

View File

@@ -3882,35 +3882,6 @@ MDBX_NOTHROW_PURE_FUNCTION LIBMDBX_API void *mdbx_env_get_userctx(const MDBX_env
LIBMDBX_API int mdbx_txn_begin_ex(MDBX_env *env, MDBX_txn *parent, MDBX_txn_flags_t flags, MDBX_txn **txn,
void *context);
/** \brief Clone a read-only transaction snapshot.
* \ingroup c_transactions
*
* Creates a new read-only transaction that uses the same MVCC snapshot as
* the \p src transaction. This allows parallel read operations across threads
* without re-opening a read transaction and re-fetching state.
*
* \note This function requires \ref MDBX_NOSTICKYTHREADS (aka MDBX_NOTLS)
* to be enabled for the environment. Otherwise it will return
* \ref MDBX_TXN_OVERLAPPING.
*
* \note The \p src transaction must be an active read-only transaction.
*
* \note The \p src transaction and the cloned transaction must not be used
* concurrently from multiple threads. Each transaction and its cursors must
* be confined to a single thread at a time.
*
* \param [in] src A read-only transaction handle returned by
* \ref mdbx_txn_begin_ex() or \ref mdbx_txn_begin().
* \param [out] dest Address where the cloned \ref MDBX_txn handle will be
* stored. Must not be NULL.
*
* \returns A non-zero error value on failure and 0 on success.
* \retval MDBX_EINVAL Invalid arguments or \p src is not read-only.
* \retval MDBX_TXN_OVERLAPPING \ref MDBX_NOSTICKYTHREADS is not enabled.
* \retval MDBX_READERS_FULL Reader lock table is full.
* \retval MDBX_ENOMEM Out of memory. */
LIBMDBX_API int mdbx_txn_clone(const MDBX_txn *src, MDBX_txn **dest);
/** \brief Create a transaction for use with the environment.
* \ingroup c_transactions
*

View File

@@ -483,20 +483,6 @@ impl Transaction<RW> {
}
impl Transaction<RO> {
/// Clones this read-only transaction, preserving the same MVCC snapshot.
///
/// This requires the environment to be opened with `MDBX_NOSTICKYTHREADS` (aka `MDBX_NOTLS`).
/// The cloned transaction must not be used concurrently with this transaction from multiple
/// threads.
pub fn clone_snapshot(&self) -> Result<Self> {
let cloned = self.txn_execute(|txn| {
let mut cloned: *mut ffi::MDBX_txn = ptr::null_mut();
mdbx_result(unsafe { ffi::mdbx_txn_clone(txn, &mut cloned) }).map(|_| cloned)
})??;
Ok(Self::new_from_ptr(self.env().clone(), cloned))
}
/// Closes the database handle.
///
/// # Safety

View File

@@ -373,35 +373,3 @@ fn test_stat_dupsort() {
assert_eq!(stat.entries(), 8);
}
}
#[test]
fn test_txn_clone_snapshot() {
let dir = tempdir().unwrap();
let env = Environment::builder().open(dir.path()).unwrap();
{
let txn = env.begin_rw_txn().unwrap();
let db = txn.open_db(None).unwrap();
txn.put(db.dbi(), b"k", b"v1", WriteFlags::empty()).unwrap();
txn.commit().unwrap();
}
let ro = env.begin_ro_txn().unwrap();
let clone = ro.clone_snapshot().unwrap();
{
let txn = env.begin_rw_txn().unwrap();
let db = txn.open_db(None).unwrap();
txn.put(db.dbi(), b"k", b"v2", WriteFlags::empty()).unwrap();
txn.commit().unwrap();
}
let db = ro.open_db(None).unwrap();
assert_eq!(ro.get::<[u8; 2]>(db.dbi(), b"k").unwrap(), Some(*b"v1"));
let db = clone.open_db(None).unwrap();
assert_eq!(clone.get::<[u8; 2]>(db.dbi(), b"k").unwrap(), Some(*b"v1"));
let ro2 = env.begin_ro_txn().unwrap();
let db = ro2.open_db(None).unwrap();
assert_eq!(ro2.get::<[u8; 2]>(db.dbi(), b"k").unwrap(), Some(*b"v2"));
}

View File

@@ -26,7 +26,9 @@ tracing-logfmt.workspace = true
clap = { workspace = true, features = ["derive"] }
eyre.workspace = true
rolling-file.workspace = true
tracing-samply = { workspace = true, optional = true }
[features]
default = ["otlp"]
otlp = ["reth-tracing-otlp"]
samply = ["tracing-samply"]

View File

@@ -224,6 +224,12 @@ impl Tracer for RethTracer {
None
};
#[cfg(feature = "samply")]
layers.add_layer(
tracing_samply::SamplyLayer::new()
.map_err(|e| eyre::eyre!("Failed to create samply layer: {}", e))?,
);
// The error is returned if the global default subscriber is already set,
// so it's safe to ignore it
let _ = tracing_subscriber::registry().with(layers.into_inner()).try_init();

View File

@@ -151,6 +151,9 @@ impl BlobStore for DiskFileBlobStore {
}
fn delete_all(&self, txs: Vec<B256>) -> Result<(), BlobStoreError> {
if txs.is_empty() {
return Ok(())
}
let txs = self.inner.retain_existing(txs)?;
self.inner.txs_to_delete.write().extend(txs);
Ok(())

View File

@@ -269,17 +269,26 @@ pub async fn maintain_transaction_pool<N, Client, P, St, Tasks>(
}
}
_ = stale_eviction_interval.tick() => {
let stale_txs: Vec<_> = pool
.queued_transactions()
let queued = pool
.queued_transactions();
let mut stale_blobs = Vec::new();
let now = std::time::Instant::now();
let stale_txs: Vec<_> = queued
.into_iter()
.filter(|tx| {
// filter stale transactions based on config
(tx.origin.is_external() || config.no_local_exemptions) && tx.timestamp.elapsed() > config.max_tx_lifetime
(tx.origin.is_external() || config.no_local_exemptions) && now - tx.timestamp > config.max_tx_lifetime
})
.map(|tx| {
if tx.is_eip4844() {
stale_blobs.push(*tx.hash());
}
*tx.hash()
})
.map(|tx| *tx.hash())
.collect();
debug!(target: "txpool", count=%stale_txs.len(), "removing stale transactions");
pool.remove_transactions(stale_txs);
pool.delete_blobs(stale_blobs);
}
}
// handle the result of the account reload

View File

@@ -276,13 +276,12 @@ where
{
use rayon::iter::{ParallelBridge, ParallelIterator};
let (tx, rx) = std::sync::mpsc::channel();
let retain_updates = self.retain_updates;
// Process all storage trie revealings in parallel, having first removed the
// `reveal_nodes` tracking and `SparseTrie`s for each account from their HashMaps.
// These will be returned after processing.
storages
let results: Vec<_> = storages
.into_iter()
.map(|(account, storage_subtree)| {
let revealed_nodes = self.storage.take_or_create_revealed_paths(&account);
@@ -301,14 +300,12 @@ where
(account, revealed_nodes, trie, result)
})
.for_each_init(|| tx.clone(), |tx, result| tx.send(result).unwrap());
drop(tx);
.collect();
// Return `revealed_nodes` and `SparseTrie` for each account, incrementing metrics and
// returning the last error seen if any.
let mut any_err = Ok(());
for (account, revealed_nodes, trie, result) in rx {
for (account, revealed_nodes, trie, result) in results {
self.storage.revealed_paths.insert(account, revealed_nodes);
self.storage.tries.insert(account, trie);
if let Ok(_metric_values) = result {

View File

@@ -160,15 +160,15 @@ where
///
/// If `metrics` feature is enabled, it also updates the metrics.
fn next_hashed_entry(&mut self) -> Result<Option<(B256, H::Value)>, DatabaseError> {
let result = self.hashed_cursor.next();
let next = self.hashed_cursor.next()?;
self.last_next_result = result.clone()?;
self.last_next_result = next;
#[cfg(feature = "metrics")]
{
self.metrics.inc_leaf_nodes_advanced();
}
result
Ok(next)
}
}

View File

@@ -26,7 +26,7 @@ The methods are grouped into namespaces, which are listed below:
| [`trace`](/jsonrpc/trace) | The `trace` API provides several methods to inspect the Ethereum state, including Parity-style traces. | No |
| [`admin`](/jsonrpc/admin) | The `admin` API allows you to configure your node. | **Yes** |
| [`rpc`](/jsonrpc/rpc) | The `rpc` API provides information about the RPC server and its modules. | No |
| `reth` | The `reth` API provides reth-specific methods like balance changes and chain notifications. | No |
| [`reth`](/jsonrpc/reth) | The `reth` API provides reth-specific methods like balance changes and chain notifications. | No |
| `ots` | The `ots` API provides Otterscan-compatible methods for block exploration. | No |
| `flashbots` | The `flashbots` API provides block submission validation methods for builders. | No |
| `miner` | The `miner` API allows you to configure miner/builder settings like extra data and gas limits. | **Yes** |

View File

@@ -0,0 +1,89 @@
---
description: Reth-specific API for balance changes and chain notifications.
---
# `reth` Namespace
The `reth` API provides reth-specific methods that are not part of the standard Ethereum JSON-RPC specification. These methods offer additional functionality for monitoring balance changes and subscribing to chain state notifications.
## `reth_getBalanceChangesInBlock`
Returns all ETH balance changes that occurred in a specific block.
This method is useful for tracking value transfers, mining rewards, and other balance modifications without having to trace every transaction in a block.
The method accepts a block identifier (number, hash, or tag like `latest`) and returns a map of addresses to their new balances.
| Client | Method invocation |
| ------ | -------------------------------------------------------------- |
| RPC | `{"method": "reth_getBalanceChangesInBlock", "params": [block]}` |
### Example
```js
// > {"jsonrpc":"2.0","id":1,"method":"reth_getBalanceChangesInBlock","params":["latest"]}
{"jsonrpc":"2.0","id":1,"result":{"0x95222290dd7278aa3ddd389cc1e1d165cc4bafe5":"0x1bc16d674ec80000","0x388c818ca8b9251b393131c08a736a67ccb19297":"0x0"}}
```
The result is a mapping of addresses to their new balance after the block was executed. Only addresses whose balance changed during block execution are included.
## `reth_subscribeChainNotifications`, `reth_unsubscribeChainNotifications`
Subscribe to canonical chain state notifications. This creates a subscription that emits notifications whenever the canonical chain state changes.
Like other subscription methods, this returns the ID of the subscription, which is then used in all events subsequently.
To unsubscribe from chain notifications, call `reth_unsubscribeChainNotifications` with the subscription ID.
| Client | Method invocation |
| ------ | -------------------------------------------------------------------------- |
| RPC | `{"method": "reth_subscribeChainNotifications", "params": []}` |
| RPC | `{"method": "reth_unsubscribeChainNotifications", "params": [subscription_id]}` |
### Event Types
The subscription emits events with the following structure:
```json
{
"jsonrpc": "2.0",
"method": "reth_subscription",
"params": {
"subscription": "0xcd0c3e8af590364c09d0fa6a1210faf5",
"result": {
"Commit": { // or "Reorg"
"new": {
// Chain segment with blocks, receipts, etc.
},
"old": {
// Only present for "Reorg": chain segment that was reverted
}
}
}
}
}
```
- **Commit**: New blocks are added to the canonical chain. Contains only `new` with the committed chain segment.
- **Reorg**: Chain reorganization occurred. Contains both `old` (reverted blocks) and `new` (replacement blocks).
This is particularly useful for applications that need to react immediately to chain state changes, such as indexers, monitoring tools, or ExEx (Execution Extensions).
### Example
```js
// > {"jsonrpc":"2.0","id":1,"method":"reth_subscribeChainNotifications","params":[]}
// responds with subscription ID
{"jsonrpc":"2.0","id":1,"result":"0xcd0c3e8af590364c09d0fa6a1210faf5"}
// Example notification when new blocks are committed
{"jsonrpc":"2.0","method":"reth_subscription","params":{"subscription":"0xcd0c3e8af590364c09d0fa6a1210faf5","result":{"Commit":{"new":{"blocks":[...],"receipts":[...],"first_block":1000,"last_block":1000}}}}}
// Unsubscribe
// > {"jsonrpc":"2.0","id":2,"method":"reth_unsubscribeChainNotifications","params":["0xcd0c3e8af590364c09d0fa6a1210faf5"]}
{"jsonrpc":"2.0","id":2,"result":true}
```
:::note
This subscription is only available over WebSocket and IPC transports, as HTTP does not support server-initiated messages.
:::

View File

@@ -201,13 +201,16 @@ The following tables describe RPC methods available in the full node.
| RPC / Segment | Note |
| ------------------------------- | ------------------------------ |
| `trace_block` | Only for the last 10064 blocks |
| `trace_blockOpcodeGas` | Only for the last 10064 blocks |
| `trace_call` | Only for the last 10064 blocks |
| `trace_callMany` | Only for the last 10064 blocks |
| `trace_filter` | Only for the last 10064 blocks |
| `trace_get` | Only for the last 10064 blocks |
| `trace_rawTransaction` | Only for the last 10064 blocks |
| `trace_replayBlockTransactions` | Only for the last 10064 blocks |
| `trace_replayTransaction` | Only for the last 10064 blocks |
| `trace_transaction` | Only for the last 10064 blocks |
| `trace_transactionOpcodeGas` | Only for the last 10064 blocks |
#### `txpool` namespace
@@ -301,13 +304,16 @@ The following tables describe the requirements for prune segments, per RPC metho
| RPC / Segment | Sender Recovery | Transaction Lookup | Receipts | Account History | Storage History |
| ------------------------------- | --------------- | ------------------ | -------- | --------------- | --------------- |
| `trace_block` | ✅ | ✅ | ✅ | ❌ | ❌ |
| `trace_blockOpcodeGas` | ✅ | ✅ | ✅ | ❌ | ❌ |
| `trace_call` | ✅ | ✅ | ✅ | ❌ | ❌ |
| `trace_callMany` | ✅ | ✅ | ✅ | ❌ | ❌ |
| `trace_filter` | ✅ | ✅ | ✅ | ❌ | ❌ |
| `trace_get` | ✅ | ❌ | ✅ | ❌ | ❌ |
| `trace_rawTransaction` | ✅ | ✅ | ✅ | ❌ | ❌ |
| `trace_replayBlockTransactions` | ✅ | ✅ | ✅ | ❌ | ❌ |
| `trace_replayTransaction` | ✅ | ❌ | ✅ | ❌ | ❌ |
| `trace_transaction` | ✅ | ❌ | ✅ | ❌ | ❌ |
| `trace_transactionOpcodeGas` | ✅ | ❌ | ✅ | ❌ | ❌ |
#### `txpool` namespace

View File

@@ -441,7 +441,6 @@ pub fn random_contract_account_range<R: Rng>(
let mut accounts = Vec::with_capacity(acc_range.end.saturating_sub(acc_range.start) as usize);
for _ in acc_range {
let (address, eoa_account) = random_eoa_account(rng);
// todo: can a non-eoa account have a nonce > 0?
let account = Account { bytecode_hash: Some(B256::random()), ..eoa_account };
accounts.push((address, account))
}