From 5b3cb2d1017a40aef58a80c539359d9f275d96ee Mon Sep 17 00:00:00 2001 From: Alexey Shekhirin <5773434+shekhirin@users.noreply.github.com> Date: Tue, 11 Nov 2025 12:22:42 +0000 Subject: [PATCH 1/8] chore: bump version to 1.9.2 (#19647) --- Cargo.lock | 278 +++++++++++++++++++-------------------- Cargo.toml | 2 +- docs/vocs/vocs.config.ts | 2 +- 3 files changed, 141 insertions(+), 141 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 39c71391f5c..17b6476b137 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3193,7 +3193,7 @@ dependencies = [ [[package]] name = "ef-test-runner" -version = "1.9.1" +version = "1.9.2" dependencies = [ "clap", "ef-tests", @@ -3201,7 +3201,7 @@ dependencies = [ [[package]] name = "ef-tests" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-eips", @@ -3681,7 +3681,7 @@ dependencies = [ [[package]] name = "example-full-contract-state" -version = "1.9.1" +version = "1.9.2" dependencies = [ "eyre", "reth-ethereum", @@ -3820,7 +3820,7 @@ dependencies = [ [[package]] name = "exex-subscription" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-primitives", "clap", @@ -6218,7 +6218,7 @@ dependencies = [ [[package]] name = "op-reth" -version = "1.9.1" +version = "1.9.2" dependencies = [ "clap", "reth-cli-util", @@ -7296,7 +7296,7 @@ checksum = "6b3789b30bd25ba102de4beabd95d21ac45b69b1be7d14522bab988c526d6799" [[package]] name = "reth" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-rpc-types", "aquamarine", @@ -7343,7 +7343,7 @@ dependencies = [ [[package]] name = "reth-basic-payload-builder" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7366,7 +7366,7 @@ dependencies = [ [[package]] name = "reth-bench" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-eips", "alloy-json-rpc", @@ -7405,7 +7405,7 @@ dependencies = [ [[package]] name = "reth-bench-compare" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-primitives", "alloy-provider", @@ -7431,7 +7431,7 @@ dependencies = [ [[package]] name = "reth-chain-state" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7463,7 +7463,7 @@ dependencies = [ [[package]] name = "reth-chainspec" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-chains", "alloy-consensus", @@ -7483,7 +7483,7 @@ dependencies = [ [[package]] name = "reth-cli" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-genesis", "clap", @@ -7496,7 +7496,7 @@ dependencies = [ [[package]] name = "reth-cli-commands" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-chains", "alloy-consensus", @@ -7578,7 +7578,7 @@ dependencies = [ [[package]] name = "reth-cli-runner" -version = "1.9.1" +version = "1.9.2" dependencies = [ "reth-tasks", "tokio", @@ -7587,7 +7587,7 @@ dependencies = [ [[package]] name = "reth-cli-util" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-eips", "alloy-primitives", @@ -7607,7 +7607,7 @@ dependencies = [ [[package]] name = "reth-codecs" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7631,7 +7631,7 @@ dependencies = [ [[package]] name = "reth-codecs-derive" -version = "1.9.1" +version = "1.9.2" dependencies = [ "proc-macro2", "quote", @@ -7641,7 +7641,7 @@ dependencies = [ [[package]] name = "reth-config" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-primitives", "eyre", @@ -7658,7 +7658,7 @@ dependencies = [ [[package]] name = "reth-consensus" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -7670,7 +7670,7 @@ dependencies = [ [[package]] name = "reth-consensus-common" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7684,7 +7684,7 @@ dependencies = [ [[package]] name = "reth-consensus-debug-client" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7709,7 +7709,7 @@ dependencies = [ [[package]] name = "reth-db" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -7743,7 +7743,7 @@ dependencies = [ [[package]] name = "reth-db-api" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-genesis", @@ -7773,7 +7773,7 @@ dependencies = [ [[package]] name = "reth-db-common" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-genesis", @@ -7803,7 +7803,7 @@ dependencies = [ [[package]] name = "reth-db-models" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-eips", "alloy-primitives", @@ -7819,7 +7819,7 @@ dependencies = [ [[package]] name = "reth-discv4" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -7845,7 +7845,7 @@ dependencies = [ [[package]] name = "reth-discv5" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -7870,7 +7870,7 @@ dependencies = [ [[package]] name = "reth-dns-discovery" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-chains", "alloy-primitives", @@ -7898,7 +7898,7 @@ dependencies = [ [[package]] name = "reth-downloaders" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7936,7 +7936,7 @@ dependencies = [ [[package]] name = "reth-e2e-test-utils" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-eips", @@ -7993,7 +7993,7 @@ dependencies = [ [[package]] name = "reth-ecies" -version = "1.9.1" +version = "1.9.2" dependencies = [ "aes", "alloy-primitives", @@ -8023,7 +8023,7 @@ dependencies = [ [[package]] name = "reth-engine-local" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -8046,7 +8046,7 @@ dependencies = [ [[package]] name = "reth-engine-primitives" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-eips", @@ -8070,7 +8070,7 @@ dependencies = [ [[package]] name = "reth-engine-service" -version = "1.9.1" +version = "1.9.2" dependencies = [ "futures", "pin-project", @@ -8099,7 +8099,7 @@ dependencies = [ [[package]] name = "reth-engine-tree" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-eips", @@ -8170,7 +8170,7 @@ dependencies = [ [[package]] name = "reth-engine-util" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-rpc-types-engine", @@ -8197,7 +8197,7 @@ dependencies = [ [[package]] name = "reth-era" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-eips", @@ -8219,7 +8219,7 @@ dependencies = [ [[package]] name = "reth-era-downloader" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-primitives", "bytes", @@ -8236,7 +8236,7 @@ dependencies = [ [[package]] name = "reth-era-utils" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -8262,7 +8262,7 @@ dependencies = [ [[package]] name = "reth-errors" -version = "1.9.1" +version = "1.9.2" dependencies = [ "reth-consensus", "reth-execution-errors", @@ -8272,7 +8272,7 @@ dependencies = [ [[package]] name = "reth-eth-wire" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-chains", "alloy-consensus", @@ -8310,7 +8310,7 @@ dependencies = [ [[package]] name = "reth-eth-wire-types" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-chains", "alloy-consensus", @@ -8335,7 +8335,7 @@ dependencies = [ [[package]] name = "reth-ethereum" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-rpc-types-engine", "alloy-rpc-types-eth", @@ -8375,7 +8375,7 @@ dependencies = [ [[package]] name = "reth-ethereum-cli" -version = "1.9.1" +version = "1.9.2" dependencies = [ "clap", "eyre", @@ -8399,7 +8399,7 @@ dependencies = [ [[package]] name = "reth-ethereum-consensus" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-eips", @@ -8415,7 +8415,7 @@ dependencies = [ [[package]] name = "reth-ethereum-engine-primitives" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-eips", "alloy-primitives", @@ -8433,7 +8433,7 @@ dependencies = [ [[package]] name = "reth-ethereum-forks" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-eip2124", "alloy-hardforks", @@ -8446,7 +8446,7 @@ dependencies = [ [[package]] name = "reth-ethereum-payload-builder" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-eips", @@ -8474,7 +8474,7 @@ dependencies = [ [[package]] name = "reth-ethereum-primitives" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-eips", @@ -8501,7 +8501,7 @@ dependencies = [ [[package]] name = "reth-etl" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-primitives", "rayon", @@ -8511,7 +8511,7 @@ dependencies = [ [[package]] name = "reth-evm" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-eips", @@ -8535,7 +8535,7 @@ dependencies = [ [[package]] name = "reth-evm-ethereum" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-eips", @@ -8559,7 +8559,7 @@ dependencies = [ [[package]] name = "reth-execution-errors" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-evm", "alloy-primitives", @@ -8571,7 +8571,7 @@ dependencies = [ [[package]] name = "reth-execution-types" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-eips", @@ -8591,7 +8591,7 @@ dependencies = [ [[package]] name = "reth-exex" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-eips", @@ -8635,7 +8635,7 @@ dependencies = [ [[package]] name = "reth-exex-test-utils" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-eips", "eyre", @@ -8666,7 +8666,7 @@ dependencies = [ [[package]] name = "reth-exex-types" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-eips", "alloy-primitives", @@ -8683,7 +8683,7 @@ dependencies = [ [[package]] name = "reth-fs-util" -version = "1.9.1" +version = "1.9.2" dependencies = [ "serde", "serde_json", @@ -8692,7 +8692,7 @@ dependencies = [ [[package]] name = "reth-invalid-block-hooks" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-eips", @@ -8725,7 +8725,7 @@ dependencies = [ [[package]] name = "reth-ipc" -version = "1.9.1" +version = "1.9.2" dependencies = [ "bytes", "futures", @@ -8747,7 +8747,7 @@ dependencies = [ [[package]] name = "reth-libmdbx" -version = "1.9.1" +version = "1.9.2" dependencies = [ "bitflags 2.10.0", "byteorder", @@ -8765,7 +8765,7 @@ dependencies = [ [[package]] name = "reth-mdbx-sys" -version = "1.9.1" +version = "1.9.2" dependencies = [ "bindgen 0.71.1", "cc", @@ -8773,7 +8773,7 @@ dependencies = [ [[package]] name = "reth-metrics" -version = "1.9.1" +version = "1.9.2" dependencies = [ "futures", "metrics", @@ -8784,14 +8784,14 @@ dependencies = [ [[package]] name = "reth-net-banlist" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-primitives", ] [[package]] name = "reth-net-nat" -version = "1.9.1" +version = "1.9.2" dependencies = [ "futures-util", "if-addrs", @@ -8805,7 +8805,7 @@ dependencies = [ [[package]] name = "reth-network" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-eips", @@ -8865,7 +8865,7 @@ dependencies = [ [[package]] name = "reth-network-api" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -8889,7 +8889,7 @@ dependencies = [ [[package]] name = "reth-network-p2p" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-eips", @@ -8911,7 +8911,7 @@ dependencies = [ [[package]] name = "reth-network-peers" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -8928,7 +8928,7 @@ dependencies = [ [[package]] name = "reth-network-types" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-eip2124", "humantime-serde", @@ -8941,7 +8941,7 @@ dependencies = [ [[package]] name = "reth-nippy-jar" -version = "1.9.1" +version = "1.9.2" dependencies = [ "anyhow", "bincode 1.3.3", @@ -8959,7 +8959,7 @@ dependencies = [ [[package]] name = "reth-node-api" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-rpc-types-engine", "eyre", @@ -8982,7 +8982,7 @@ dependencies = [ [[package]] name = "reth-node-builder" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-eips", @@ -9053,7 +9053,7 @@ dependencies = [ [[package]] name = "reth-node-core" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-eips", @@ -9106,7 +9106,7 @@ dependencies = [ [[package]] name = "reth-node-ethereum" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-contract", @@ -9159,7 +9159,7 @@ dependencies = [ [[package]] name = "reth-node-ethstats" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -9182,7 +9182,7 @@ dependencies = [ [[package]] name = "reth-node-events" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-eips", @@ -9205,7 +9205,7 @@ dependencies = [ [[package]] name = "reth-node-metrics" -version = "1.9.1" +version = "1.9.2" dependencies = [ "eyre", "http", @@ -9227,7 +9227,7 @@ dependencies = [ [[package]] name = "reth-node-types" -version = "1.9.1" +version = "1.9.2" dependencies = [ "reth-chainspec", "reth-db-api", @@ -9238,7 +9238,7 @@ dependencies = [ [[package]] name = "reth-op" -version = "1.9.1" +version = "1.9.2" dependencies = [ "reth-chainspec", "reth-cli-util", @@ -9278,7 +9278,7 @@ dependencies = [ [[package]] name = "reth-optimism-chainspec" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-chains", "alloy-consensus", @@ -9306,7 +9306,7 @@ dependencies = [ [[package]] name = "reth-optimism-cli" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-eips", @@ -9357,7 +9357,7 @@ dependencies = [ [[package]] name = "reth-optimism-consensus" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-chains", "alloy-consensus", @@ -9388,7 +9388,7 @@ dependencies = [ [[package]] name = "reth-optimism-evm" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-eips", @@ -9417,7 +9417,7 @@ dependencies = [ [[package]] name = "reth-optimism-flashblocks" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-eips", @@ -9456,7 +9456,7 @@ dependencies = [ [[package]] name = "reth-optimism-forks" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-op-hardforks", "alloy-primitives", @@ -9466,7 +9466,7 @@ dependencies = [ [[package]] name = "reth-optimism-node" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-genesis", @@ -9524,7 +9524,7 @@ dependencies = [ [[package]] name = "reth-optimism-payload-builder" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-eips", @@ -9563,7 +9563,7 @@ dependencies = [ [[package]] name = "reth-optimism-primitives" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-eips", @@ -9590,7 +9590,7 @@ dependencies = [ [[package]] name = "reth-optimism-rpc" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-eips", @@ -9652,7 +9652,7 @@ dependencies = [ [[package]] name = "reth-optimism-storage" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "reth-codecs", @@ -9664,7 +9664,7 @@ dependencies = [ [[package]] name = "reth-optimism-txpool" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-eips", @@ -9701,7 +9701,7 @@ dependencies = [ [[package]] name = "reth-payload-builder" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -9721,7 +9721,7 @@ dependencies = [ [[package]] name = "reth-payload-builder-primitives" -version = "1.9.1" +version = "1.9.2" dependencies = [ "pin-project", "reth-payload-primitives", @@ -9732,7 +9732,7 @@ dependencies = [ [[package]] name = "reth-payload-primitives" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-eips", "alloy-primitives", @@ -9752,7 +9752,7 @@ dependencies = [ [[package]] name = "reth-payload-util" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -9761,7 +9761,7 @@ dependencies = [ [[package]] name = "reth-payload-validator" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-rpc-types-engine", @@ -9770,7 +9770,7 @@ dependencies = [ [[package]] name = "reth-primitives" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-eips", @@ -9792,7 +9792,7 @@ dependencies = [ [[package]] name = "reth-primitives-traits" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-eips", @@ -9829,7 +9829,7 @@ dependencies = [ [[package]] name = "reth-provider" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-eips", @@ -9877,7 +9877,7 @@ dependencies = [ [[package]] name = "reth-prune" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-eips", "alloy-primitives", @@ -9907,11 +9907,11 @@ dependencies = [ [[package]] name = "reth-prune-db" -version = "1.9.1" +version = "1.9.2" [[package]] name = "reth-prune-types" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-primitives", "arbitrary", @@ -9930,7 +9930,7 @@ dependencies = [ [[package]] name = "reth-ress-protocol" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -9956,7 +9956,7 @@ dependencies = [ [[package]] name = "reth-ress-provider" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -9982,7 +9982,7 @@ dependencies = [ [[package]] name = "reth-revm" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -9996,7 +9996,7 @@ dependencies = [ [[package]] name = "reth-rpc" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -10079,7 +10079,7 @@ dependencies = [ [[package]] name = "reth-rpc-api" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-eips", "alloy-genesis", @@ -10106,7 +10106,7 @@ dependencies = [ [[package]] name = "reth-rpc-api-testing-util" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-eips", "alloy-primitives", @@ -10125,7 +10125,7 @@ dependencies = [ [[package]] name = "reth-rpc-builder" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-eips", "alloy-network", @@ -10180,7 +10180,7 @@ dependencies = [ [[package]] name = "reth-rpc-convert" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-json-rpc", @@ -10207,7 +10207,7 @@ dependencies = [ [[package]] name = "reth-rpc-e2e-tests" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-genesis", "alloy-rpc-types-engine", @@ -10227,7 +10227,7 @@ dependencies = [ [[package]] name = "reth-rpc-engine-api" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-eips", "alloy-primitives", @@ -10263,7 +10263,7 @@ dependencies = [ [[package]] name = "reth-rpc-eth-api" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-dyn-abi", @@ -10306,7 +10306,7 @@ dependencies = [ [[package]] name = "reth-rpc-eth-types" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-eips", @@ -10353,7 +10353,7 @@ dependencies = [ [[package]] name = "reth-rpc-layer" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-rpc-types-engine", "http", @@ -10370,7 +10370,7 @@ dependencies = [ [[package]] name = "reth-rpc-server-types" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-eips", "alloy-primitives", @@ -10385,7 +10385,7 @@ dependencies = [ [[package]] name = "reth-stages" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-eips", @@ -10442,7 +10442,7 @@ dependencies = [ [[package]] name = "reth-stages-api" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-eips", "alloy-primitives", @@ -10471,7 +10471,7 @@ dependencies = [ [[package]] name = "reth-stages-types" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-primitives", "arbitrary", @@ -10487,7 +10487,7 @@ dependencies = [ [[package]] name = "reth-stateless" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -10514,7 +10514,7 @@ dependencies = [ [[package]] name = "reth-static-file" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-primitives", "assert_matches", @@ -10537,7 +10537,7 @@ dependencies = [ [[package]] name = "reth-static-file-types" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-primitives", "clap", @@ -10549,7 +10549,7 @@ dependencies = [ [[package]] name = "reth-storage-api" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-eips", @@ -10571,7 +10571,7 @@ dependencies = [ [[package]] name = "reth-storage-errors" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-eips", "alloy-primitives", @@ -10586,7 +10586,7 @@ dependencies = [ [[package]] name = "reth-storage-rpc-provider" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-eips", @@ -10615,7 +10615,7 @@ dependencies = [ [[package]] name = "reth-tasks" -version = "1.9.1" +version = "1.9.2" dependencies = [ "auto_impl", "dyn-clone", @@ -10632,7 +10632,7 @@ dependencies = [ [[package]] name = "reth-testing-utils" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-eips", @@ -10647,7 +10647,7 @@ dependencies = [ [[package]] name = "reth-tokio-util" -version = "1.9.1" +version = "1.9.2" dependencies = [ "tokio", "tokio-stream", @@ -10656,7 +10656,7 @@ dependencies = [ [[package]] name = "reth-tracing" -version = "1.9.1" +version = "1.9.2" dependencies = [ "clap", "eyre", @@ -10672,7 +10672,7 @@ dependencies = [ [[package]] name = "reth-tracing-otlp" -version = "1.9.1" +version = "1.9.2" dependencies = [ "clap", "eyre", @@ -10688,7 +10688,7 @@ dependencies = [ [[package]] name = "reth-transaction-pool" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-eips", @@ -10736,7 +10736,7 @@ dependencies = [ [[package]] name = "reth-trie" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-eips", @@ -10769,7 +10769,7 @@ dependencies = [ [[package]] name = "reth-trie-common" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-genesis", @@ -10802,7 +10802,7 @@ dependencies = [ [[package]] name = "reth-trie-db" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-consensus", "alloy-primitives", @@ -10827,7 +10827,7 @@ dependencies = [ [[package]] name = "reth-trie-parallel" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -10857,7 +10857,7 @@ dependencies = [ [[package]] name = "reth-trie-sparse" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -10890,7 +10890,7 @@ dependencies = [ [[package]] name = "reth-trie-sparse-parallel" -version = "1.9.1" +version = "1.9.2" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -10919,7 +10919,7 @@ dependencies = [ [[package]] name = "reth-zstd-compressors" -version = "1.9.1" +version = "1.9.2" dependencies = [ "zstd", ] diff --git a/Cargo.toml b/Cargo.toml index 131ec10b7ca..86a09ff5e88 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace.package] -version = "1.9.1" +version = "1.9.2" edition = "2024" rust-version = "1.88" license = "MIT OR Apache-2.0" diff --git a/docs/vocs/vocs.config.ts b/docs/vocs/vocs.config.ts index 4deb6c6df0b..5a4ea636fba 100644 --- a/docs/vocs/vocs.config.ts +++ b/docs/vocs/vocs.config.ts @@ -21,7 +21,7 @@ export default defineConfig({ }, { text: 'GitHub', link: 'https://github.com/paradigmxyz/reth' }, { - text: 'v1.9.0', + text: 'v1.9.2', items: [ { text: 'Releases', From 465d7479a72a443ba768416ef83577d298ee31e6 Mon Sep 17 00:00:00 2001 From: rakita Date: Mon, 10 Nov 2025 15:53:28 +0100 Subject: [PATCH 2/8] chore: bump op-revm v12.0.2 patch (#19629) --- Cargo.lock | 24 ++++++++++++------------ Cargo.toml | 10 +++++----- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 17b6476b137..d4f56c411e2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6236,9 +6236,9 @@ dependencies = [ [[package]] name = "op-revm" -version = "12.0.1" +version = "12.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcd8cb3274e87936b595eb2247ad3bda146695fceb7159afa76010529af53553" +checksum = "e31622d03b29c826e48800f4c8f389c8a9c440eb796a3e35203561a288f12985" dependencies = [ "auto_impl", "revm", @@ -10926,9 +10926,9 @@ dependencies = [ [[package]] name = "revm" -version = "31.0.1" +version = "31.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93df0ff5eb70facbc872f82da4b815d7bd8e36b7ee525c637cabcb2a6af8a708" +checksum = "bb67a5223602113cae59a305acde2d9936bc18f2478dda879a6124b267cebfb6" dependencies = [ "revm-bytecode", "revm-context", @@ -10957,9 +10957,9 @@ dependencies = [ [[package]] name = "revm-context" -version = "11.0.1" +version = "11.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "583c80d674f51b28a0d0a7309bda0867bcb0fd41b4e34976eded145edbb089fc" +checksum = "92850e150f4f99d46c05a20ad0cd09286a7ad4ee21866fffb87101de6e602231" dependencies = [ "bitvec", "cfg-if", @@ -10990,9 +10990,9 @@ dependencies = [ [[package]] name = "revm-database" -version = "9.0.4" +version = "9.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a4505d9688482fe0c3b8c09d9afbc4656e2bf9b48855e1c86c93bd4508e496a" +checksum = "7b6c15bb255481fcf29f5ef7c97f00ed4c28a6ab6c490d77b990d73603031569" dependencies = [ "alloy-eips", "revm-bytecode", @@ -11017,9 +11017,9 @@ dependencies = [ [[package]] name = "revm-handler" -version = "12.0.1" +version = "12.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3da9e26f05ed723cf423b92f012a7775eef9e7d897633d11ec83535e92cda2d" +checksum = "b45418ed95cfdf0cb19effdbb7633cf2144cab7fb0e6ffd6b0eb9117a50adff6" dependencies = [ "auto_impl", "derive-where", @@ -11036,9 +11036,9 @@ dependencies = [ [[package]] name = "revm-inspector" -version = "12.0.1" +version = "12.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57afb06e5985dbd2e8a48a3e6727cb0dd45148e4e6e028ac8222e262e440d3de" +checksum = "c99801eac7da06cc112df2244bd5a64024f4ef21240e923b26e73c4b4a0e5da6" dependencies = [ "auto_impl", "either", diff --git a/Cargo.toml b/Cargo.toml index 86a09ff5e88..42b34cf222d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -466,17 +466,17 @@ reth-ress-protocol = { path = "crates/ress/protocol" } reth-ress-provider = { path = "crates/ress/provider" } # revm -revm = { version = "31.0.1", default-features = false } +revm = { version = "31.0.2", default-features = false } revm-bytecode = { version = "7.1.1", default-features = false } -revm-database = { version = "9.0.4", default-features = false } +revm-database = { version = "9.0.5", default-features = false } revm-state = { version = "8.1.1", default-features = false } revm-primitives = { version = "21.0.2", default-features = false } revm-interpreter = { version = "29.0.1", default-features = false } -revm-inspector = { version = "12.0.1", default-features = false } -revm-context = { version = "11.0.1", default-features = false } +revm-inspector = { version = "12.0.2", default-features = false } +revm-context = { version = "11.0.2", default-features = false } revm-context-interface = { version = "12.0.1", default-features = false } revm-database-interface = { version = "8.0.5", default-features = false } -op-revm = { version = "12.0.1", default-features = false } +op-revm = { version = "12.0.2", default-features = false } revm-inspectors = "0.32.0" # eth From a672700b4fae17fc3622a93e62e7fefe64ccc78d Mon Sep 17 00:00:00 2001 From: Alexey Shekhirin <5773434+shekhirin@users.noreply.github.com> Date: Tue, 11 Nov 2025 12:01:39 +0000 Subject: [PATCH 3/8] revert: "refactor(prune): remove receipts log filter segment (#19184)" (#19646) --- Cargo.lock | 2 + crates/config/src/config.rs | 32 +- crates/exex/exex/src/backfill/factory.rs | 2 +- crates/node/builder/src/launch/common.rs | 6 +- crates/node/core/Cargo.toml | 1 + crates/node/core/src/args/error.rs | 22 ++ crates/node/core/src/args/mod.rs | 1 + crates/node/core/src/args/pruning.rs | 180 +++++++-- crates/prune/prune/Cargo.toml | 1 + crates/prune/prune/src/builder.rs | 2 +- crates/prune/prune/src/segments/mod.rs | 4 +- crates/prune/prune/src/segments/set.rs | 12 +- crates/prune/prune/src/segments/user/mod.rs | 2 + .../src/segments/user/receipts_by_logs.rs | 362 ++++++++++++++++++ crates/prune/types/src/lib.rs | 301 +++++++++++++++ crates/prune/types/src/target.rs | 28 +- crates/stages/stages/src/stages/execution.rs | 26 +- .../static-file/src/static_file_producer.rs | 4 +- .../provider/src/providers/database/mod.rs | 2 +- .../src/providers/database/provider.rs | 26 +- docs/vocs/docs/pages/cli/reth/node.mdx | 3 + 21 files changed, 953 insertions(+), 66 deletions(-) create mode 100644 crates/node/core/src/args/error.rs create mode 100644 crates/prune/prune/src/segments/user/receipts_by_logs.rs diff --git a/Cargo.lock b/Cargo.lock index d4f56c411e2..01d8e726b33 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9096,6 +9096,7 @@ dependencies = [ "serde", "shellexpand", "strum 0.27.2", + "thiserror 2.0.17", "tokio", "toml", "tracing", @@ -9879,6 +9880,7 @@ dependencies = [ name = "reth-prune" version = "1.9.2" dependencies = [ + "alloy-consensus", "alloy-eips", "alloy-primitives", "assert_matches", diff --git a/crates/config/src/config.rs b/crates/config/src/config.rs index dd2e7046b0c..5ff2431bb56 100644 --- a/crates/config/src/config.rs +++ b/crates/config/src/config.rs @@ -33,7 +33,7 @@ pub struct Config { impl Config { /// Sets the pruning configuration. - pub const fn set_prune_config(&mut self, prune_config: PruneConfig) { + pub fn set_prune_config(&mut self, prune_config: PruneConfig) { self.prune = prune_config; } } @@ -451,14 +451,13 @@ impl PruneConfig { } /// Returns whether there is any kind of receipt pruning configuration. - pub const fn has_receipts_pruning(&self) -> bool { - self.segments.receipts.is_some() + pub fn has_receipts_pruning(&self) -> bool { + self.segments.receipts.is_some() || !self.segments.receipts_log_filter.is_empty() } /// Merges another `PruneConfig` into this one, taking values from the other config if and only /// if the corresponding value in this config is not set. pub fn merge(&mut self, other: Self) { - #[expect(deprecated)] let Self { block_interval, segments: @@ -470,7 +469,7 @@ impl PruneConfig { storage_history, bodies_history, merkle_changesets, - receipts_log_filter: (), + receipts_log_filter, }, } = other; @@ -488,6 +487,10 @@ impl PruneConfig { self.segments.bodies_history = self.segments.bodies_history.or(bodies_history); // Merkle changesets is not optional, so we just replace it if provided self.segments.merkle_changesets = merkle_changesets; + + if self.segments.receipts_log_filter.0.is_empty() && !receipts_log_filter.0.is_empty() { + self.segments.receipts_log_filter = receipts_log_filter; + } } } @@ -514,9 +517,10 @@ where mod tests { use super::{Config, EXTENSION}; use crate::PruneConfig; + use alloy_primitives::Address; use reth_network_peers::TrustedPeer; - use reth_prune_types::{PruneMode, PruneModes}; - use std::{path::Path, str::FromStr, time::Duration}; + use reth_prune_types::{PruneMode, PruneModes, ReceiptsLogPruneConfig}; + use std::{collections::BTreeMap, path::Path, str::FromStr, time::Duration}; fn with_tempdir(filename: &str, proc: fn(&std::path::Path)) { let temp_dir = tempfile::tempdir().unwrap(); @@ -1005,8 +1009,10 @@ receipts = 'full' storage_history: Some(PruneMode::Before(5000)), bodies_history: None, merkle_changesets: PruneMode::Before(0), - #[expect(deprecated)] - receipts_log_filter: (), + receipts_log_filter: ReceiptsLogPruneConfig(BTreeMap::from([( + Address::random(), + PruneMode::Full, + )])), }, }; @@ -1020,11 +1026,14 @@ receipts = 'full' storage_history: Some(PruneMode::Distance(3000)), bodies_history: None, merkle_changesets: PruneMode::Distance(10000), - #[expect(deprecated)] - receipts_log_filter: (), + receipts_log_filter: ReceiptsLogPruneConfig(BTreeMap::from([ + (Address::random(), PruneMode::Distance(1000)), + (Address::random(), PruneMode::Before(2000)), + ])), }, }; + let original_filter = config1.segments.receipts_log_filter.clone(); config1.merge(config2); // Check that the configuration has been merged. Any configuration present in config1 @@ -1036,6 +1045,7 @@ receipts = 'full' assert_eq!(config1.segments.account_history, Some(PruneMode::Distance(2000))); assert_eq!(config1.segments.storage_history, Some(PruneMode::Before(5000))); assert_eq!(config1.segments.merkle_changesets, PruneMode::Distance(10000)); + assert_eq!(config1.segments.receipts_log_filter, original_filter); } #[test] diff --git a/crates/exex/exex/src/backfill/factory.rs b/crates/exex/exex/src/backfill/factory.rs index 29734b905e2..d9a51bc47a7 100644 --- a/crates/exex/exex/src/backfill/factory.rs +++ b/crates/exex/exex/src/backfill/factory.rs @@ -39,7 +39,7 @@ impl BackfillJobFactory { } /// Sets the prune modes - pub const fn with_prune_modes(mut self, prune_modes: PruneModes) -> Self { + pub fn with_prune_modes(mut self, prune_modes: PruneModes) -> Self { self.prune_modes = prune_modes; self } diff --git a/crates/node/builder/src/launch/common.rs b/crates/node/builder/src/launch/common.rs index c049ddfbf21..95909e34710 100644 --- a/crates/node/builder/src/launch/common.rs +++ b/crates/node/builder/src/launch/common.rs @@ -405,14 +405,13 @@ impl LaunchContextWith, - /// Receipts Log Filter - #[arg( - long = "prune.receipts-log-filter", - alias = "prune.receiptslogfilter", - value_name = "FILTER_CONFIG", - hide = true - )] - #[deprecated] - pub receipts_log_filter: Option, + // Receipts Log Filter + /// Configure receipts log filter. Format: + /// <`address`>:<`prune_mode`>... where <`prune_mode`> can be 'full', 'distance:<`blocks`>', or + /// 'before:<`block_number`>' + #[arg(long = "prune.receiptslogfilter", value_name = "FILTER_CONFIG", conflicts_with_all = &["receipts_full", "receipts_pre_merge", "receipts_distance", "receipts_before"], value_parser = parse_receipts_log_filter)] + pub receipts_log_filter: Option, // Account History /// Prunes all account history. @@ -136,8 +132,7 @@ impl PruningArgs { .block_number() .map(PruneMode::Before), merkle_changesets: PruneMode::Distance(MINIMUM_PRUNING_DISTANCE), - #[expect(deprecated)] - receipts_log_filter: (), + receipts_log_filter: Default::default(), }, } } @@ -164,14 +159,13 @@ impl PruningArgs { if let Some(mode) = self.storage_history_prune_mode() { config.segments.storage_history = Some(mode); } - - // Log warning if receipts_log_filter is set (deprecated feature) - #[expect(deprecated)] - if self.receipts_log_filter.is_some() { - tracing::warn!( - target: "reth::cli", - "The --prune.receiptslogfilter flag is deprecated and has no effect. It will be removed in a future release." - ); + if let Some(receipt_logs) = + self.receipts_log_filter.as_ref().filter(|c| !c.is_empty()).cloned() + { + config.segments.receipts_log_filter = receipt_logs; + // need to remove the receipts segment filter entirely because that takes precedence + // over the logs filter + config.segments.receipts.take(); } config.is_default().not().then_some(config) @@ -259,3 +253,141 @@ impl PruningArgs { } } } + +/// Parses `,` separated pruning info into [`ReceiptsLogPruneConfig`]. +pub(crate) fn parse_receipts_log_filter( + value: &str, +) -> Result { + let mut config = BTreeMap::new(); + // Split out each of the filters. + let filters = value.split(','); + for filter in filters { + let parts: Vec<&str> = filter.split(':').collect(); + if parts.len() < 2 { + return Err(ReceiptsLogError::InvalidFilterFormat(filter.to_string())); + } + // Parse the address + let address = parts[0] + .parse::
() + .map_err(|_| ReceiptsLogError::InvalidAddress(parts[0].to_string()))?; + + // Parse the prune mode + let prune_mode = match parts[1] { + "full" => PruneMode::Full, + s if s.starts_with("distance") => { + if parts.len() < 3 { + return Err(ReceiptsLogError::InvalidFilterFormat(filter.to_string())); + } + let distance = + parts[2].parse::().map_err(ReceiptsLogError::InvalidDistance)?; + PruneMode::Distance(distance) + } + s if s.starts_with("before") => { + if parts.len() < 3 { + return Err(ReceiptsLogError::InvalidFilterFormat(filter.to_string())); + } + let block_number = + parts[2].parse::().map_err(ReceiptsLogError::InvalidBlockNumber)?; + PruneMode::Before(block_number) + } + _ => return Err(ReceiptsLogError::InvalidPruneMode(parts[1].to_string())), + }; + config.insert(address, prune_mode); + } + Ok(ReceiptsLogPruneConfig(config)) +} + +#[cfg(test)] +mod tests { + use super::*; + use alloy_primitives::address; + use clap::Parser; + + /// A helper type to parse Args more easily + #[derive(Parser)] + struct CommandParser { + #[command(flatten)] + args: T, + } + + #[test] + fn pruning_args_sanity_check() { + let args = CommandParser::::parse_from([ + "reth", + "--prune.receiptslogfilter", + "0x0000000000000000000000000000000000000003:before:5000000", + ]) + .args; + let mut config = ReceiptsLogPruneConfig::default(); + config.0.insert( + address!("0x0000000000000000000000000000000000000003"), + PruneMode::Before(5000000), + ); + assert_eq!(args.receipts_log_filter, Some(config)); + } + + #[test] + fn parse_receiptslogfilter() { + let default_args = PruningArgs::default(); + let args = CommandParser::::parse_from(["reth"]).args; + assert_eq!(args, default_args); + } + + #[test] + fn test_parse_receipts_log_filter() { + let filter1 = "0x0000000000000000000000000000000000000001:full"; + let filter2 = "0x0000000000000000000000000000000000000002:distance:1000"; + let filter3 = "0x0000000000000000000000000000000000000003:before:5000000"; + let filters = [filter1, filter2, filter3].join(","); + + // Args can be parsed. + let result = parse_receipts_log_filter(&filters); + assert!(result.is_ok()); + let config = result.unwrap(); + assert_eq!(config.0.len(), 3); + + // Check that the args were parsed correctly. + let addr1: Address = "0x0000000000000000000000000000000000000001".parse().unwrap(); + let addr2: Address = "0x0000000000000000000000000000000000000002".parse().unwrap(); + let addr3: Address = "0x0000000000000000000000000000000000000003".parse().unwrap(); + + assert_eq!(config.0.get(&addr1), Some(&PruneMode::Full)); + assert_eq!(config.0.get(&addr2), Some(&PruneMode::Distance(1000))); + assert_eq!(config.0.get(&addr3), Some(&PruneMode::Before(5000000))); + } + + #[test] + fn test_parse_receipts_log_filter_invalid_filter_format() { + let result = parse_receipts_log_filter("invalid_format"); + assert!(matches!(result, Err(ReceiptsLogError::InvalidFilterFormat(_)))); + } + + #[test] + fn test_parse_receipts_log_filter_invalid_address() { + let result = parse_receipts_log_filter("invalid_address:full"); + assert!(matches!(result, Err(ReceiptsLogError::InvalidAddress(_)))); + } + + #[test] + fn test_parse_receipts_log_filter_invalid_prune_mode() { + let result = + parse_receipts_log_filter("0x0000000000000000000000000000000000000000:invalid_mode"); + assert!(matches!(result, Err(ReceiptsLogError::InvalidPruneMode(_)))); + } + + #[test] + fn test_parse_receipts_log_filter_invalid_distance() { + let result = parse_receipts_log_filter( + "0x0000000000000000000000000000000000000000:distance:invalid_distance", + ); + assert!(matches!(result, Err(ReceiptsLogError::InvalidDistance(_)))); + } + + #[test] + fn test_parse_receipts_log_filter_invalid_block_number() { + let result = parse_receipts_log_filter( + "0x0000000000000000000000000000000000000000:before:invalid_block", + ); + assert!(matches!(result, Err(ReceiptsLogError::InvalidBlockNumber(_)))); + } +} diff --git a/crates/prune/prune/Cargo.toml b/crates/prune/prune/Cargo.toml index 615a793bb89..a2d82c26923 100644 --- a/crates/prune/prune/Cargo.toml +++ b/crates/prune/prune/Cargo.toml @@ -24,6 +24,7 @@ reth-primitives-traits.workspace = true reth-static-file-types.workspace = true # ethereum +alloy-consensus.workspace = true alloy-eips.workspace = true # metrics diff --git a/crates/prune/prune/src/builder.rs b/crates/prune/prune/src/builder.rs index f61aa6bd46d..78283710e15 100644 --- a/crates/prune/prune/src/builder.rs +++ b/crates/prune/prune/src/builder.rs @@ -43,7 +43,7 @@ impl PrunerBuilder { } /// Sets the configuration for every part of the data that can be pruned. - pub const fn segments(mut self, segments: PruneModes) -> Self { + pub fn segments(mut self, segments: PruneModes) -> Self { self.segments = segments; self } diff --git a/crates/prune/prune/src/segments/mod.rs b/crates/prune/prune/src/segments/mod.rs index f4df3d2a0dd..f917c78ea94 100644 --- a/crates/prune/prune/src/segments/mod.rs +++ b/crates/prune/prune/src/segments/mod.rs @@ -10,8 +10,8 @@ pub use set::SegmentSet; use std::{fmt::Debug, ops::RangeInclusive}; use tracing::error; pub use user::{ - AccountHistory, Bodies, MerkleChangeSets, Receipts as UserReceipts, SenderRecovery, - StorageHistory, TransactionLookup, + AccountHistory, Bodies, MerkleChangeSets, Receipts as UserReceipts, ReceiptsByLogs, + SenderRecovery, StorageHistory, TransactionLookup, }; /// A segment represents a pruning of some portion of the data. diff --git a/crates/prune/prune/src/segments/set.rs b/crates/prune/prune/src/segments/set.rs index acd71f52e1b..7ae9e044e20 100644 --- a/crates/prune/prune/src/segments/set.rs +++ b/crates/prune/prune/src/segments/set.rs @@ -1,6 +1,6 @@ use crate::segments::{ - AccountHistory, Bodies, MerkleChangeSets, Segment, SenderRecovery, StorageHistory, - TransactionLookup, UserReceipts, + user::ReceiptsByLogs, AccountHistory, Bodies, MerkleChangeSets, Segment, SenderRecovery, + StorageHistory, TransactionLookup, UserReceipts, }; use alloy_eips::eip2718::Encodable2718; use reth_db_api::{table::Value, transaction::DbTxMut}; @@ -59,7 +59,6 @@ where _static_file_provider: StaticFileProvider, prune_modes: PruneModes, ) -> Self { - #[expect(deprecated)] let PruneModes { sender_recovery, transaction_lookup, @@ -68,7 +67,7 @@ where storage_history, bodies_history, merkle_changesets, - receipts_log_filter: (), + receipts_log_filter, } = prune_modes; Self::default() @@ -82,6 +81,11 @@ where .segment_opt(storage_history.map(StorageHistory::new)) // User receipts .segment_opt(receipts.map(UserReceipts::new)) + // Receipts by logs + .segment_opt( + (!receipts_log_filter.is_empty()) + .then(|| ReceiptsByLogs::new(receipts_log_filter.clone())), + ) // Transaction lookup .segment_opt(transaction_lookup.map(TransactionLookup::new)) // Sender recovery diff --git a/crates/prune/prune/src/segments/user/mod.rs b/crates/prune/prune/src/segments/user/mod.rs index ef7ae05a9d5..b993d3f2616 100644 --- a/crates/prune/prune/src/segments/user/mod.rs +++ b/crates/prune/prune/src/segments/user/mod.rs @@ -3,6 +3,7 @@ mod bodies; mod history; mod merkle_change_sets; mod receipts; +mod receipts_by_logs; mod sender_recovery; mod storage_history; mod transaction_lookup; @@ -11,6 +12,7 @@ pub use account_history::AccountHistory; pub use bodies::Bodies; pub use merkle_change_sets::MerkleChangeSets; pub use receipts::Receipts; +pub use receipts_by_logs::ReceiptsByLogs; pub use sender_recovery::SenderRecovery; pub use storage_history::StorageHistory; pub use transaction_lookup::TransactionLookup; diff --git a/crates/prune/prune/src/segments/user/receipts_by_logs.rs b/crates/prune/prune/src/segments/user/receipts_by_logs.rs new file mode 100644 index 00000000000..9e57bd2411a --- /dev/null +++ b/crates/prune/prune/src/segments/user/receipts_by_logs.rs @@ -0,0 +1,362 @@ +use crate::{ + db_ext::DbTxPruneExt, + segments::{PruneInput, Segment}, + PrunerError, +}; +use alloy_consensus::TxReceipt; +use reth_db_api::{table::Value, tables, transaction::DbTxMut}; +use reth_primitives_traits::NodePrimitives; +use reth_provider::{ + BlockReader, DBProvider, NodePrimitivesProvider, PruneCheckpointWriter, TransactionsProvider, +}; +use reth_prune_types::{ + PruneCheckpoint, PruneMode, PrunePurpose, PruneSegment, ReceiptsLogPruneConfig, SegmentOutput, + MINIMUM_PRUNING_DISTANCE, +}; +use tracing::{instrument, trace}; +#[derive(Debug)] +pub struct ReceiptsByLogs { + config: ReceiptsLogPruneConfig, +} + +impl ReceiptsByLogs { + pub const fn new(config: ReceiptsLogPruneConfig) -> Self { + Self { config } + } +} + +impl Segment for ReceiptsByLogs +where + Provider: DBProvider + + PruneCheckpointWriter + + TransactionsProvider + + BlockReader + + NodePrimitivesProvider>, +{ + fn segment(&self) -> PruneSegment { + PruneSegment::ContractLogs + } + + fn mode(&self) -> Option { + None + } + + fn purpose(&self) -> PrunePurpose { + PrunePurpose::User + } + + #[instrument(target = "pruner", skip(self, provider), ret(level = "trace"))] + fn prune(&self, provider: &Provider, input: PruneInput) -> Result { + // Contract log filtering removes every receipt possible except the ones in the list. So, + // for the other receipts it's as if they had a `PruneMode::Distance()` of + // `MINIMUM_PRUNING_DISTANCE`. + let to_block = PruneMode::Distance(MINIMUM_PRUNING_DISTANCE) + .prune_target_block(input.to_block, PruneSegment::ContractLogs, PrunePurpose::User)? + .map(|(bn, _)| bn) + .unwrap_or_default(); + + // Get status checkpoint from latest run + let mut last_pruned_block = + input.previous_checkpoint.and_then(|checkpoint| checkpoint.block_number); + + let initial_last_pruned_block = last_pruned_block; + + let mut from_tx_number = match initial_last_pruned_block { + Some(block) => provider + .block_body_indices(block)? + .map(|block| block.last_tx_num() + 1) + .unwrap_or(0), + None => 0, + }; + + // Figure out what receipts have already been pruned, so we can have an accurate + // `address_filter` + let address_filter = self.config.group_by_block(input.to_block, last_pruned_block)?; + + // Splits all transactions in different block ranges. Each block range will have its own + // filter address list and will check it while going through the table + // + // Example: + // For an `address_filter` such as: + // { block9: [a1, a2], block20: [a3, a4, a5] } + // + // The following structures will be created in the exact order as showed: + // `block_ranges`: [ + // (block0, block8, 0 addresses), + // (block9, block19, 2 addresses), + // (block20, to_block, 5 addresses) + // ] + // `filtered_addresses`: [a1, a2, a3, a4, a5] + // + // The first range will delete all receipts between block0 - block8 + // The second range will delete all receipts between block9 - 19, except the ones with + // emitter logs from these addresses: [a1, a2]. + // The third range will delete all receipts between block20 - to_block, except the ones with + // emitter logs from these addresses: [a1, a2, a3, a4, a5] + let mut block_ranges = vec![]; + let mut blocks_iter = address_filter.iter().peekable(); + let mut filtered_addresses = vec![]; + + while let Some((start_block, addresses)) = blocks_iter.next() { + filtered_addresses.extend_from_slice(addresses); + + // This will clear all receipts before the first appearance of a contract log or since + // the block after the last pruned one. + if block_ranges.is_empty() { + let init = last_pruned_block.map(|b| b + 1).unwrap_or_default(); + if init < *start_block { + block_ranges.push((init, *start_block - 1, 0)); + } + } + + let end_block = + blocks_iter.peek().map(|(next_block, _)| *next_block - 1).unwrap_or(to_block); + + // Addresses in lower block ranges, are still included in the inclusion list for future + // ranges. + block_ranges.push((*start_block, end_block, filtered_addresses.len())); + } + + trace!( + target: "pruner", + ?block_ranges, + ?filtered_addresses, + "Calculated block ranges and filtered addresses", + ); + + let mut limiter = input.limiter; + + let mut done = true; + let mut pruned = 0; + let mut last_pruned_transaction = None; + for (start_block, end_block, num_addresses) in block_ranges { + let block_range = start_block..=end_block; + + // Calculate the transaction range from this block range + let tx_range_end = match provider.block_body_indices(end_block)? { + Some(body) => body.last_tx_num(), + None => { + trace!( + target: "pruner", + ?block_range, + "No receipts to prune." + ); + continue + } + }; + let tx_range = from_tx_number..=tx_range_end; + + // Delete receipts, except the ones in the inclusion list + let mut last_skipped_transaction = 0; + let deleted; + (deleted, done) = provider.tx_ref().prune_table_with_range::::Receipt, + >>( + tx_range, + &mut limiter, + |(tx_num, receipt)| { + let skip = num_addresses > 0 && + receipt.logs().iter().any(|log| { + filtered_addresses[..num_addresses].contains(&&log.address) + }); + + if skip { + last_skipped_transaction = *tx_num; + } + skip + }, + |row| last_pruned_transaction = Some(row.0), + )?; + + trace!(target: "pruner", %deleted, %done, ?block_range, "Pruned receipts"); + + pruned += deleted; + + // For accurate checkpoints we need to know that we have checked every transaction. + // Example: we reached the end of the range, and the last receipt is supposed to skip + // its deletion. + let last_pruned_transaction = *last_pruned_transaction + .insert(last_pruned_transaction.unwrap_or_default().max(last_skipped_transaction)); + + last_pruned_block = Some( + provider + .block_by_transaction_id(last_pruned_transaction)? + .ok_or(PrunerError::InconsistentData("Block for transaction is not found"))? + // If there's more receipts to prune, set the checkpoint block number to + // previous, so we could finish pruning its receipts on the + // next run. + .saturating_sub(if done { 0 } else { 1 }), + ); + + if limiter.is_limit_reached() { + done &= end_block == to_block; + break + } + + from_tx_number = last_pruned_transaction + 1; + } + + // If there are contracts using `PruneMode::Distance(_)` there will be receipts before + // `to_block` that become eligible to be pruned in future runs. Therefore, our checkpoint is + // not actually `to_block`, but the `lowest_block_with_distance` from any contract. + // This ensures that in future pruner runs we can prune all these receipts between the + // previous `lowest_block_with_distance` and the new one using + // `get_next_tx_num_range_from_checkpoint`. + // + // Only applies if we were able to prune everything intended for this run, otherwise the + // checkpoint is the `last_pruned_block`. + let prune_mode_block = self + .config + .lowest_block_with_distance(input.to_block, initial_last_pruned_block)? + .unwrap_or(to_block); + + provider.save_prune_checkpoint( + PruneSegment::ContractLogs, + PruneCheckpoint { + block_number: Some(prune_mode_block.min(last_pruned_block.unwrap_or(u64::MAX))), + tx_number: last_pruned_transaction, + prune_mode: PruneMode::Before(prune_mode_block), + }, + )?; + + let progress = limiter.progress(done); + + Ok(SegmentOutput { progress, pruned, checkpoint: None }) + } +} + +#[cfg(test)] +mod tests { + use crate::segments::{user::ReceiptsByLogs, PruneInput, PruneLimiter, Segment}; + use alloy_primitives::B256; + use assert_matches::assert_matches; + use reth_db_api::{cursor::DbCursorRO, tables, transaction::DbTx}; + use reth_primitives_traits::InMemorySize; + use reth_provider::{BlockReader, DBProvider, DatabaseProviderFactory, PruneCheckpointReader}; + use reth_prune_types::{PruneMode, PruneSegment, ReceiptsLogPruneConfig}; + use reth_stages::test_utils::{StorageKind, TestStageDB}; + use reth_testing_utils::generators::{ + self, random_block_range, random_eoa_account, random_log, random_receipt, BlockRangeParams, + }; + use std::collections::BTreeMap; + + #[test] + fn prune_receipts_by_logs() { + reth_tracing::init_test_tracing(); + + let db = TestStageDB::default(); + let mut rng = generators::rng(); + + let tip = 20000; + let blocks = [ + random_block_range( + &mut rng, + 0..=100, + BlockRangeParams { parent: Some(B256::ZERO), tx_count: 1..5, ..Default::default() }, + ), + random_block_range( + &mut rng, + (100 + 1)..=(tip - 100), + BlockRangeParams { parent: Some(B256::ZERO), tx_count: 0..1, ..Default::default() }, + ), + random_block_range( + &mut rng, + (tip - 100 + 1)..=tip, + BlockRangeParams { parent: Some(B256::ZERO), tx_count: 1..5, ..Default::default() }, + ), + ] + .concat(); + db.insert_blocks(blocks.iter(), StorageKind::Database(None)).expect("insert blocks"); + + let mut receipts = Vec::new(); + + 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() { + let mut receipt = random_receipt(&mut rng, transaction, Some(1), None); + receipt.logs.push(random_log( + &mut rng, + (txi == (block.transaction_count() - 1)).then_some(deposit_contract_addr), + Some(1), + )); + receipts.push((receipts.len() as u64, receipt)); + } + } + db.insert_receipts(receipts).expect("insert receipts"); + + assert_eq!( + db.table::().unwrap().len(), + blocks.iter().map(|block| block.transaction_count()).sum::() + ); + assert_eq!( + db.table::().unwrap().len(), + db.table::().unwrap().len() + ); + + let run_prune = || { + let provider = db.factory.database_provider_rw().unwrap(); + + let prune_before_block: usize = 20; + let prune_mode = PruneMode::Before(prune_before_block as u64); + let receipts_log_filter = + ReceiptsLogPruneConfig(BTreeMap::from([(deposit_contract_addr, prune_mode)])); + + let limiter = PruneLimiter::default().set_deleted_entries_limit(10); + + let result = ReceiptsByLogs::new(receipts_log_filter).prune( + &provider, + PruneInput { + previous_checkpoint: db + .factory + .provider() + .unwrap() + .get_prune_checkpoint(PruneSegment::ContractLogs) + .unwrap(), + to_block: tip, + limiter, + }, + ); + provider.commit().expect("commit"); + + assert_matches!(result, Ok(_)); + let output = result.unwrap(); + + let (pruned_block, pruned_tx) = db + .factory + .provider() + .unwrap() + .get_prune_checkpoint(PruneSegment::ContractLogs) + .unwrap() + .map(|checkpoint| (checkpoint.block_number.unwrap(), checkpoint.tx_number.unwrap())) + .unwrap_or_default(); + + // All receipts are in the end of the block + let unprunable = pruned_block.saturating_sub(prune_before_block as u64 - 1); + + assert_eq!( + db.table::().unwrap().len(), + blocks.iter().map(|block| block.transaction_count()).sum::() - + ((pruned_tx + 1) - unprunable) as usize + ); + + output.progress.is_finished() + }; + + while !run_prune() {} + + let provider = db.factory.provider().unwrap(); + let mut cursor = provider.tx_ref().cursor_read::().unwrap(); + let walker = cursor.walk(None).unwrap(); + for receipt in walker { + let (tx_num, receipt) = receipt.unwrap(); + + // Either we only find our contract, or the receipt is part of the unprunable receipts + // set by tip - 128 + assert!( + receipt.logs.iter().any(|l| l.address == deposit_contract_addr) || + provider.block_by_transaction_id(tx_num).unwrap().unwrap() > tip - 128, + ); + } + } +} diff --git a/crates/prune/types/src/lib.rs b/crates/prune/types/src/lib.rs index a588693892a..315063278b2 100644 --- a/crates/prune/types/src/lib.rs +++ b/crates/prune/types/src/lib.rs @@ -18,6 +18,10 @@ mod pruner; mod segment; mod target; +use alloc::{collections::BTreeMap, vec::Vec}; +use alloy_primitives::{Address, BlockNumber}; +use core::ops::Deref; + pub use checkpoint::PruneCheckpoint; pub use event::PrunerEvent; pub use mode::PruneMode; @@ -27,3 +31,300 @@ pub use pruner::{ }; pub use segment::{PrunePurpose, PruneSegment, PruneSegmentError}; pub use target::{PruneModes, UnwindTargetPrunedError, MINIMUM_PRUNING_DISTANCE}; + +/// Configuration for pruning receipts not associated with logs emitted by the specified contracts. +#[derive(Debug, Clone, PartialEq, Eq, Default)] +#[cfg_attr(any(test, feature = "serde"), derive(serde::Serialize, serde::Deserialize))] +pub struct ReceiptsLogPruneConfig(pub BTreeMap); + +impl ReceiptsLogPruneConfig { + /// Checks if the configuration is empty + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } + + /// Given the `tip` block number, consolidates the structure so it can easily be queried for + /// filtering across a range of blocks. + /// + /// Example: + /// + /// `{ addrA: Before(872), addrB: Before(500), addrC: Distance(128) }` + /// + /// for `tip: 1000`, gets transformed to a map such as: + /// + /// `{ 500: [addrB], 872: [addrA, addrC] }` + /// + /// The [`BlockNumber`] key of the new map should be viewed as `PruneMode::Before(block)`, which + /// makes the previous result equivalent to + /// + /// `{ Before(500): [addrB], Before(872): [addrA, addrC] }` + pub fn group_by_block( + &self, + tip: BlockNumber, + pruned_block: Option, + ) -> Result>, PruneSegmentError> { + let mut map = BTreeMap::new(); + let base_block = pruned_block.unwrap_or_default() + 1; + + for (address, mode) in &self.0 { + // Getting `None`, means that there is nothing to prune yet, so we need it to include in + // the BTreeMap (block = 0), otherwise it will be excluded. + // Reminder that this BTreeMap works as an inclusion list that excludes (prunes) all + // other receipts. + // + // Reminder, that we increment because the [`BlockNumber`] key of the new map should be + // viewed as `PruneMode::Before(block)` + let block = base_block.max( + mode.prune_target_block(tip, PruneSegment::ContractLogs, PrunePurpose::User)? + .map(|(block, _)| block) + .unwrap_or_default() + + 1, + ); + + map.entry(block).or_insert_with(Vec::new).push(address) + } + Ok(map) + } + + /// Returns the lowest block where we start filtering logs which use `PruneMode::Distance(_)`. + pub fn lowest_block_with_distance( + &self, + tip: BlockNumber, + pruned_block: Option, + ) -> Result, PruneSegmentError> { + let pruned_block = pruned_block.unwrap_or_default(); + let mut lowest = None; + + for mode in self.values() { + if mode.is_distance() && + let Some((block, _)) = + mode.prune_target_block(tip, PruneSegment::ContractLogs, PrunePurpose::User)? + { + lowest = Some(lowest.unwrap_or(u64::MAX).min(block)); + } + } + + Ok(lowest.map(|lowest| lowest.max(pruned_block))) + } +} + +impl Deref for ReceiptsLogPruneConfig { + type Target = BTreeMap; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_group_by_block_empty_config() { + let config = ReceiptsLogPruneConfig(BTreeMap::new()); + let tip = 1000; + let pruned_block = None; + + let result = config.group_by_block(tip, pruned_block).unwrap(); + assert!(result.is_empty(), "The result should be empty when the config is empty"); + } + + #[test] + fn test_group_by_block_single_entry() { + let mut config_map = BTreeMap::new(); + let address = Address::new([1; 20]); + let prune_mode = PruneMode::Before(500); + config_map.insert(address, prune_mode); + + let config = ReceiptsLogPruneConfig(config_map); + // Big tip to have something to prune for the target block + let tip = 3000000; + let pruned_block = Some(400); + + let result = config.group_by_block(tip, pruned_block).unwrap(); + + // Expect one entry with block 500 and the corresponding address + assert_eq!(result.len(), 1); + assert_eq!(result[&500], vec![&address], "Address should be grouped under block 500"); + + // Tip smaller than the target block, so that we have nothing to prune for the block + let tip = 300; + let pruned_block = Some(400); + + let result = config.group_by_block(tip, pruned_block).unwrap(); + + // Expect one entry with block 400 and the corresponding address + assert_eq!(result.len(), 1); + assert_eq!(result[&401], vec![&address], "Address should be grouped under block 400"); + } + + #[test] + fn test_group_by_block_multiple_entries() { + let mut config_map = BTreeMap::new(); + let address1 = Address::new([1; 20]); + let address2 = Address::new([2; 20]); + let prune_mode1 = PruneMode::Before(600); + let prune_mode2 = PruneMode::Before(800); + config_map.insert(address1, prune_mode1); + config_map.insert(address2, prune_mode2); + + let config = ReceiptsLogPruneConfig(config_map); + let tip = 900000; + let pruned_block = Some(400); + + let result = config.group_by_block(tip, pruned_block).unwrap(); + + // Expect two entries: one for block 600 and another for block 800 + assert_eq!(result.len(), 2); + assert_eq!(result[&600], vec![&address1], "Address1 should be grouped under block 600"); + assert_eq!(result[&800], vec![&address2], "Address2 should be grouped under block 800"); + } + + #[test] + fn test_group_by_block_with_distance_prune_mode() { + let mut config_map = BTreeMap::new(); + let address = Address::new([1; 20]); + let prune_mode = PruneMode::Distance(100000); + config_map.insert(address, prune_mode); + + let config = ReceiptsLogPruneConfig(config_map); + let tip = 100100; + // Pruned block is smaller than the target block + let pruned_block = Some(50); + + let result = config.group_by_block(tip, pruned_block).unwrap(); + + // Expect the entry to be grouped under block 100 (tip - distance) + assert_eq!(result.len(), 1); + assert_eq!(result[&101], vec![&address], "Address should be grouped under block 100"); + + let tip = 100100; + // Pruned block is larger than the target block + let pruned_block = Some(800); + + let result = config.group_by_block(tip, pruned_block).unwrap(); + + // Expect the entry to be grouped under block 800 which is larger than tip - distance + assert_eq!(result.len(), 1); + assert_eq!(result[&801], vec![&address], "Address should be grouped under block 800"); + } + + #[test] + fn test_lowest_block_with_distance_empty_config() { + let config = ReceiptsLogPruneConfig(BTreeMap::new()); + let tip = 1000; + let pruned_block = None; + + let result = config.lowest_block_with_distance(tip, pruned_block).unwrap(); + assert_eq!(result, None, "The result should be None when the config is empty"); + } + + #[test] + fn test_lowest_block_with_distance_no_distance_mode() { + let mut config_map = BTreeMap::new(); + let address = Address::new([1; 20]); + let prune_mode = PruneMode::Before(500); + config_map.insert(address, prune_mode); + + let config = ReceiptsLogPruneConfig(config_map); + let tip = 1000; + let pruned_block = None; + + let result = config.lowest_block_with_distance(tip, pruned_block).unwrap(); + assert_eq!(result, None, "The result should be None when there are no Distance modes"); + } + + #[test] + fn test_lowest_block_with_distance_single_entry() { + let mut config_map = BTreeMap::new(); + let address = Address::new([1; 20]); + let prune_mode = PruneMode::Distance(100000); + config_map.insert(address, prune_mode); + + let config = ReceiptsLogPruneConfig(config_map); + + let tip = 100100; + let pruned_block = Some(400); + + // Expect the lowest block to be 400 as 400 > 100100 - 100000 (tip - distance) + assert_eq!( + config.lowest_block_with_distance(tip, pruned_block).unwrap(), + Some(400), + "The lowest block should be 400" + ); + + let tip = 100100; + let pruned_block = Some(50); + + // Expect the lowest block to be 100 as 100 > 50 (pruned block) + assert_eq!( + config.lowest_block_with_distance(tip, pruned_block).unwrap(), + Some(100), + "The lowest block should be 100" + ); + } + + #[test] + fn test_lowest_block_with_distance_multiple_entries_last() { + let mut config_map = BTreeMap::new(); + let address1 = Address::new([1; 20]); + let address2 = Address::new([2; 20]); + let prune_mode1 = PruneMode::Distance(100100); + let prune_mode2 = PruneMode::Distance(100300); + config_map.insert(address1, prune_mode1); + config_map.insert(address2, prune_mode2); + + let config = ReceiptsLogPruneConfig(config_map); + let tip = 200300; + let pruned_block = Some(100); + + // The lowest block should be 200300 - 100300 = 100000: + // - First iteration will return 100200 => 200300 - 100100 = 100200 + // - Second iteration will return 100000 => 200300 - 100300 = 100000 < 100200 + // - Final result is 100000 + assert_eq!(config.lowest_block_with_distance(tip, pruned_block).unwrap(), Some(100000)); + } + + #[test] + fn test_lowest_block_with_distance_multiple_entries_first() { + let mut config_map = BTreeMap::new(); + let address1 = Address::new([1; 20]); + let address2 = Address::new([2; 20]); + let prune_mode1 = PruneMode::Distance(100400); + let prune_mode2 = PruneMode::Distance(100300); + config_map.insert(address1, prune_mode1); + config_map.insert(address2, prune_mode2); + + let config = ReceiptsLogPruneConfig(config_map); + let tip = 200300; + let pruned_block = Some(100); + + // The lowest block should be 200300 - 100400 = 99900: + // - First iteration, lowest block is 200300 - 100400 = 99900 + // - Second iteration, lowest block is still 99900 < 200300 - 100300 = 100000 + // - Final result is 99900 + assert_eq!(config.lowest_block_with_distance(tip, pruned_block).unwrap(), Some(99900)); + } + + #[test] + fn test_lowest_block_with_distance_multiple_entries_pruned_block() { + let mut config_map = BTreeMap::new(); + let address1 = Address::new([1; 20]); + let address2 = Address::new([2; 20]); + let prune_mode1 = PruneMode::Distance(100400); + let prune_mode2 = PruneMode::Distance(100300); + config_map.insert(address1, prune_mode1); + config_map.insert(address2, prune_mode2); + + let config = ReceiptsLogPruneConfig(config_map); + let tip = 200300; + let pruned_block = Some(100000); + + // The lowest block should be 100000 because: + // - Lowest is 200300 - 100400 = 99900 < 200300 - 100300 = 100000 + // - Lowest is compared to the pruned block 100000: 100000 > 99900 + // - Finally the lowest block is 100000 + assert_eq!(config.lowest_block_with_distance(tip, pruned_block).unwrap(), Some(100000)); + } +} diff --git a/crates/prune/types/src/target.rs b/crates/prune/types/src/target.rs index bb61c006cdc..3ff18554a9b 100644 --- a/crates/prune/types/src/target.rs +++ b/crates/prune/types/src/target.rs @@ -2,7 +2,7 @@ use alloy_primitives::BlockNumber; use derive_more::Display; use thiserror::Error; -use crate::{PruneCheckpoint, PruneMode, PruneSegment}; +use crate::{PruneCheckpoint, PruneMode, PruneSegment, ReceiptsLogPruneConfig}; /// Minimum distance from the tip necessary for the node to work correctly: /// 1. Minimum 2 epochs (32 blocks per epoch) required to handle any reorg according to the @@ -99,10 +99,16 @@ pub struct PruneModes { ) )] pub merkle_changesets: PruneMode, - /// Receipts log filtering has been deprecated and will be removed in a future release. - #[deprecated] - #[cfg_attr(any(test, feature = "serde"), serde(skip))] - pub receipts_log_filter: (), + /// Receipts pruning configuration by retaining only those receipts that contain logs emitted + /// by the specified addresses, discarding others. This setting is overridden by `receipts`. + /// + /// The [`BlockNumber`](`crate::BlockNumber`) represents the starting block from which point + /// onwards the receipts are preserved. + #[cfg_attr( + any(test, feature = "serde"), + serde(skip_serializing_if = "ReceiptsLogPruneConfig::is_empty") + )] + pub receipts_log_filter: ReceiptsLogPruneConfig, } impl Default for PruneModes { @@ -115,15 +121,14 @@ impl Default for PruneModes { storage_history: None, bodies_history: None, merkle_changesets: default_merkle_changesets_mode(), - #[expect(deprecated)] - receipts_log_filter: (), + receipts_log_filter: ReceiptsLogPruneConfig::default(), } } } impl PruneModes { /// Sets pruning to all targets. - pub const fn all() -> Self { + pub fn all() -> Self { Self { sender_recovery: Some(PruneMode::Full), transaction_lookup: Some(PruneMode::Full), @@ -132,14 +137,13 @@ impl PruneModes { storage_history: Some(PruneMode::Full), bodies_history: Some(PruneMode::Full), merkle_changesets: PruneMode::Full, - #[expect(deprecated)] - receipts_log_filter: (), + receipts_log_filter: Default::default(), } } /// Returns whether there is any kind of receipt pruning configuration. - pub const fn has_receipts_pruning(&self) -> bool { - self.receipts.is_some() + pub fn has_receipts_pruning(&self) -> bool { + self.receipts.is_some() || !self.receipts_log_filter.is_empty() } /// Returns an error if we can't unwind to the targeted block because the target block is diff --git a/crates/stages/stages/src/stages/execution.rs b/crates/stages/stages/src/stages/execution.rs index adfc87c5ccc..1666e79baf3 100644 --- a/crates/stages/stages/src/stages/execution.rs +++ b/crates/stages/stages/src/stages/execution.rs @@ -660,7 +660,7 @@ where mod tests { use super::*; use crate::{stages::MERKLE_STAGE_DEFAULT_REBUILD_THRESHOLD, test_utils::TestStageDB}; - use alloy_primitives::{address, hex_literal::hex, keccak256, B256, U256}; + use alloy_primitives::{address, hex_literal::hex, keccak256, Address, B256, U256}; use alloy_rlp::Decodable; use assert_matches::assert_matches; use reth_chainspec::ChainSpecBuilder; @@ -677,7 +677,9 @@ mod tests { DatabaseProviderFactory, ReceiptProvider, StaticFileProviderFactory, }; use reth_prune::PruneModes; + use reth_prune_types::{PruneMode, ReceiptsLogPruneConfig}; use reth_stages_api::StageUnitCheckpoint; + use std::collections::BTreeMap; fn stage() -> ExecutionStage { let evm_config = @@ -894,11 +896,20 @@ mod tests { // If there is a pruning configuration, then it's forced to use the database. // This way we test both cases. let modes = [None, Some(PruneModes::default())]; + let random_filter = ReceiptsLogPruneConfig(BTreeMap::from([( + Address::random(), + PruneMode::Distance(100000), + )])); // Tests node with database and node with static files - for mode in modes { + for mut mode in modes { let mut provider = factory.database_provider_rw().unwrap(); + if let Some(mode) = &mut mode { + // Simulating a full node where we write receipts to database + mode.receipts_log_filter = random_filter.clone(); + } + let mut execution_stage = stage(); provider.set_prune_modes(mode.clone().unwrap_or_default()); @@ -1022,9 +1033,18 @@ mod tests { // If there is a pruning configuration, then it's forced to use the database. // This way we test both cases. let modes = [None, Some(PruneModes::default())]; + let random_filter = ReceiptsLogPruneConfig(BTreeMap::from([( + Address::random(), + PruneMode::Before(100000), + )])); // Tests node with database and node with static files - for mode in modes { + for mut mode in modes { + if let Some(mode) = &mut mode { + // Simulating a full node where we write receipts to database + mode.receipts_log_filter = random_filter.clone(); + } + // Test Execution let mut execution_stage = stage(); provider.set_prune_modes(mode.clone().unwrap_or_default()); 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 2e7aa4b9df4..03337f1fd7d 100644 --- a/crates/static-file/static-file/src/static_file_producer.rs +++ b/crates/static-file/static-file/src/static_file_producer.rs @@ -194,7 +194,9 @@ where let targets = StaticFileTargets { // StaticFile receipts only if they're not pruned according to the user configuration - receipts: if self.prune_modes.receipts.is_none() { + receipts: if self.prune_modes.receipts.is_none() && + self.prune_modes.receipts_log_filter.is_empty() + { finalized_block_numbers.receipts.and_then(|finalized_block_number| { self.get_static_file_target( highest_static_files.receipts, diff --git a/crates/storage/provider/src/providers/database/mod.rs b/crates/storage/provider/src/providers/database/mod.rs index 5d3b5280cda..873b10b0cfc 100644 --- a/crates/storage/provider/src/providers/database/mod.rs +++ b/crates/storage/provider/src/providers/database/mod.rs @@ -96,7 +96,7 @@ impl ProviderFactory { } /// Sets the pruning configuration for an existing [`ProviderFactory`]. - pub const fn with_prune_modes(mut self, prune_modes: PruneModes) -> Self { + pub fn with_prune_modes(mut self, prune_modes: PruneModes) -> Self { self.prune_modes = prune_modes; self } diff --git a/crates/storage/provider/src/providers/database/provider.rs b/crates/storage/provider/src/providers/database/provider.rs index a90b2c2e640..1f0a0aa391a 100644 --- a/crates/storage/provider/src/providers/database/provider.rs +++ b/crates/storage/provider/src/providers/database/provider.rs @@ -22,7 +22,7 @@ use crate::{ }; use alloy_consensus::{ transaction::{SignerRecoverable, TransactionMeta, TxHashRef}, - BlockHeader, + BlockHeader, TxReceipt, }; use alloy_eips::BlockHashOrNumber; use alloy_primitives::{ @@ -214,7 +214,7 @@ impl DatabaseProvider { #[cfg(feature = "test-utils")] /// Sets the prune modes for provider. - pub const fn set_prune_modes(&mut self, prune_modes: PruneModes) { + pub fn set_prune_modes(&mut self, prune_modes: PruneModes) { self.prune_modes = prune_modes; } } @@ -1621,11 +1621,20 @@ impl StateWriter .then(|| self.static_file_provider.get_writer(first_block, StaticFileSegment::Receipts)) .transpose()?; + let has_contract_log_filter = !self.prune_modes.receipts_log_filter.is_empty(); + let contract_log_pruner = self.prune_modes.receipts_log_filter.group_by_block(tip, None)?; + // All receipts from the last 128 blocks are required for blockchain tree, even with // [`PruneSegment::ContractLogs`]. let prunable_receipts = PruneMode::Distance(MINIMUM_PRUNING_DISTANCE).should_prune(first_block, tip); + // Prepare set of addresses which logs should not be pruned. + let mut allowed_addresses: HashSet = HashSet::new(); + for (_, addresses) in contract_log_pruner.range(..first_block) { + allowed_addresses.extend(addresses.iter().copied()); + } + for (idx, (receipts, first_tx_index)) in execution_outcome.receipts.iter().zip(block_indices).enumerate() { @@ -1645,8 +1654,21 @@ impl StateWriter continue } + // If there are new addresses to retain after this block number, track them + if let Some(new_addresses) = contract_log_pruner.get(&block_number) { + allowed_addresses.extend(new_addresses.iter().copied()); + } + for (idx, receipt) in receipts.iter().enumerate() { let receipt_idx = first_tx_index + idx as u64; + // Skip writing receipt if log filter is active and it does not have any logs to + // retain + if prunable_receipts && + has_contract_log_filter && + !receipt.logs().iter().any(|log| allowed_addresses.contains(&log.address)) + { + continue + } if let Some(writer) = &mut receipts_static_writer { writer.append_receipt(receipt_idx, receipt)?; diff --git a/docs/vocs/docs/pages/cli/reth/node.mdx b/docs/vocs/docs/pages/cli/reth/node.mdx index 2326b40d7fc..d92bad0c53d 100644 --- a/docs/vocs/docs/pages/cli/reth/node.mdx +++ b/docs/vocs/docs/pages/cli/reth/node.mdx @@ -801,6 +801,9 @@ Pruning: --prune.receipts.before Prune receipts before the specified block number. The specified block number is not pruned + --prune.receiptslogfilter + Configure receipts log filter. Format: <`address`>:<`prune_mode`>... where <`prune_mode`> can be 'full', 'distance:<`blocks`>', or 'before:<`block_number`>' + --prune.account-history.full Prunes all account history From 74351d98e906b8af5f118694529fb2b71d316946 Mon Sep 17 00:00:00 2001 From: Alexey Shekhirin <5773434+shekhirin@users.noreply.github.com> Date: Tue, 11 Nov 2025 17:37:19 +0000 Subject: [PATCH 4/8] ci: use macos-14 runner (#19658) --- .github/workflows/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 60206b6ace7..b59b967b086 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -78,7 +78,7 @@ jobs: profile: maxperf allow_fail: false - target: x86_64-apple-darwin - os: macos-13 + os: macos-14 profile: maxperf allow_fail: false - target: aarch64-apple-darwin From 2f3628e698e471c7898b508e253379d19c18acfc Mon Sep 17 00:00:00 2001 From: Suthiwat Date: Tue, 26 Aug 2025 17:40:44 +0100 Subject: [PATCH 5/8] import from based-op repo --- crates/evm/src/system_calls/mod.rs | 339 ++++++++++++++++++ crates/node/core/src/args/rpc_server.rs | 4 +- crates/optimism/chainspec/src/lib.rs | 11 + crates/optimism/primitives/Cargo.toml | 2 +- crates/rpc/rpc-engine-api/src/capabilities.rs | 2 + .../provider/src/providers/consistent_view.rs | 6 +- .../src/providers/database/provider.rs | 2 +- justfile | 14 + 8 files changed, 375 insertions(+), 5 deletions(-) create mode 100644 crates/evm/src/system_calls/mod.rs create mode 100644 justfile diff --git a/crates/evm/src/system_calls/mod.rs b/crates/evm/src/system_calls/mod.rs new file mode 100644 index 00000000000..64bdc888825 --- /dev/null +++ b/crates/evm/src/system_calls/mod.rs @@ -0,0 +1,339 @@ +//! System contract call functions. + +use crate::ConfigureEvm; +use alloc::{boxed::Box, sync::Arc}; +use alloy_consensus::BlockHeader; +use alloy_eips::{ + eip7002::WITHDRAWAL_REQUEST_TYPE, eip7251::CONSOLIDATION_REQUEST_TYPE, eip7685::Requests, +}; +use alloy_primitives::Bytes; +use core::fmt::Display; +use reth_chainspec::EthereumHardforks; +use reth_execution_errors::BlockExecutionError; +use revm::{Database, DatabaseCommit, Evm}; +use revm_primitives::{BlockEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg, EvmState, B256}; + +mod eip2935; +mod eip4788; +mod eip7002; +mod eip7251; + +/// A hook that is called after each state change. +pub trait OnStateHook { + /// Invoked with the state after each system call. + fn on_state(&mut self, state: &EvmState); +} + +impl OnStateHook for F +where + F: FnMut(&EvmState), +{ + fn on_state(&mut self, state: &EvmState) { + self(state) + } +} + +/// An [`OnStateHook`] that does nothing. +#[derive(Default, Debug, Clone)] +#[non_exhaustive] +pub struct NoopHook; + +impl OnStateHook for NoopHook { + fn on_state(&mut self, _state: &EvmState) {} +} + +/// An ephemeral helper type for executing system calls. +/// +/// This can be used to chain system transaction calls. +#[allow(missing_debug_implementations)] +pub struct SystemCaller { + evm_config: EvmConfig, + chain_spec: Arc, + /// Optional hook to be called after each state change. + hook: Option>, +} + +impl SystemCaller { + /// Create a new system caller with the given EVM config, database, and chain spec, and creates + /// the EVM with the given initialized config and block environment. + pub const fn new(evm_config: EvmConfig, chain_spec: Arc) -> Self { + Self { evm_config, chain_spec, hook: None } + } + + /// Installs a custom hook to be called after each state change. + pub fn with_state_hook(&mut self, hook: Option>) -> &mut Self { + self.hook = hook; + self + } + + /// Convenience method to consume the type and drop borrowed fields + pub fn finish(self) {} +} + +fn initialize_evm<'a, DB>( + db: &'a mut DB, + initialized_cfg: &'a CfgEnvWithHandlerCfg, + initialized_block_env: &'a BlockEnv, +) -> Evm<'a, (), &'a mut DB> +where + DB: Database, +{ + Evm::builder() + .with_db(db) + .with_env_with_handler_cfg(EnvWithHandlerCfg::new_with_cfg_env( + initialized_cfg.clone(), + initialized_block_env.clone(), + Default::default(), + )) + .build() +} + +impl SystemCaller +where + EvmConfig: ConfigureEvm, + Chainspec: EthereumHardforks, +{ + /// Apply pre execution changes. + pub fn apply_pre_execution_changes( + &mut self, + block: &Block, + evm: &mut Evm<'_, Ext, DB>, + ) -> Result<(), BlockExecutionError> + where + DB: Database + DatabaseCommit, + DB::Error: Display, + Block: reth_primitives_traits::Block
, + { + self.apply_blockhashes_contract_call( + block.header().timestamp(), + block.header().number(), + block.header().parent_hash(), + evm, + )?; + self.apply_beacon_root_contract_call( + block.header().timestamp(), + block.header().number(), + block.header().parent_beacon_block_root(), + evm, + )?; + + Ok(()) + } + + /// Apply post execution changes. + pub fn apply_post_execution_changes( + &mut self, + evm: &mut Evm<'_, Ext, DB>, + ) -> Result + where + DB: Database + DatabaseCommit, + DB::Error: Display, + { + let mut requests = Requests::default(); + + // Collect all EIP-7685 requests + let withdrawal_requests = self.apply_withdrawal_requests_contract_call(evm)?; + if !withdrawal_requests.is_empty() { + requests.push_request_with_type(WITHDRAWAL_REQUEST_TYPE, withdrawal_requests); + } + + // Collect all EIP-7251 requests + let consolidation_requests = self.apply_consolidation_requests_contract_call(evm)?; + if !consolidation_requests.is_empty() { + requests.push_request_with_type(CONSOLIDATION_REQUEST_TYPE, consolidation_requests); + } + + Ok(requests) + } + + /// Applies the pre-block call to the EIP-2935 blockhashes contract. + pub fn pre_block_blockhashes_contract_call( + &mut self, + db: &mut DB, + initialized_cfg: &CfgEnvWithHandlerCfg, + initialized_block_env: &BlockEnv, + parent_block_hash: B256, + ) -> Result<(), BlockExecutionError> + where + DB: Database + DatabaseCommit, + DB::Error: Display, + { + let mut evm = initialize_evm(db, initialized_cfg, initialized_block_env); + self.apply_blockhashes_contract_call( + initialized_block_env.timestamp.to(), + initialized_block_env.number.to(), + parent_block_hash, + &mut evm, + )?; + + Ok(()) + } + + /// Applies the pre-block call to the EIP-2935 blockhashes contract. + pub fn apply_blockhashes_contract_call( + &mut self, + timestamp: u64, + block_number: u64, + parent_block_hash: B256, + evm: &mut Evm<'_, Ext, DB>, + ) -> Result<(), BlockExecutionError> + where + DB: Database + DatabaseCommit, + DB::Error: Display, + { + let result_and_state = eip2935::transact_blockhashes_contract_call( + &self.evm_config, + &self.chain_spec, + timestamp, + block_number, + parent_block_hash, + evm, + )?; + + if let Some(res) = result_and_state { + if let Some(ref mut hook) = self.hook { + hook.on_state(&res.state); + } + evm.context.evm.db.commit(res.state); + } + + Ok(()) + } + + /// Applies the pre-block call to the EIP-4788 beacon root contract. + pub fn pre_block_beacon_root_contract_call( + &mut self, + db: &mut DB, + initialized_cfg: &CfgEnvWithHandlerCfg, + initialized_block_env: &BlockEnv, + parent_beacon_block_root: Option, + ) -> Result<(), BlockExecutionError> + where + DB: Database + DatabaseCommit, + DB::Error: Display, + { + let mut evm = initialize_evm(db, initialized_cfg, initialized_block_env); + + self.apply_beacon_root_contract_call( + initialized_block_env.timestamp.to(), + initialized_block_env.number.to(), + parent_beacon_block_root, + &mut evm, + )?; + + Ok(()) + } + + /// Applies the pre-block call to the EIP-4788 beacon root contract. + pub fn apply_beacon_root_contract_call( + &mut self, + timestamp: u64, + block_number: u64, + parent_block_hash: Option, + evm: &mut Evm<'_, Ext, DB>, + ) -> Result<(), BlockExecutionError> + where + DB: Database + DatabaseCommit, + DB::Error: Display, + { + let result_and_state = eip4788::transact_beacon_root_contract_call( + &self.evm_config, + &self.chain_spec, + timestamp, + block_number, + parent_block_hash, + evm, + )?; + + if let Some(res) = result_and_state { + if let Some(ref mut hook) = self.hook { + hook.on_state(&res.state); + } + evm.context.evm.db.commit(res.state.clone()); + } + Ok(()) + } + + /// Applies the post-block call to the EIP-7002 withdrawal request contract. + pub fn post_block_withdrawal_requests_contract_call( + &mut self, + db: &mut DB, + initialized_cfg: &CfgEnvWithHandlerCfg, + initialized_block_env: &BlockEnv, + ) -> Result + where + DB: Database + DatabaseCommit, + DB::Error: Display, + { + let mut evm = initialize_evm(db, initialized_cfg, initialized_block_env); + + let result = self.apply_withdrawal_requests_contract_call(&mut evm)?; + + Ok(result) + } + + /// Applies the post-block call to the EIP-7002 withdrawal request contract. + pub fn apply_withdrawal_requests_contract_call( + &mut self, + evm: &mut Evm<'_, Ext, DB>, + ) -> Result + where + DB: Database + DatabaseCommit, + DB::Error: Display, + { + let result_and_state = + eip7002::transact_withdrawal_requests_contract_call(&self.evm_config.clone(), evm)?; + + if let Some(ref mut hook) = self.hook { + hook.on_state(&result_and_state.state); + } + evm.context.evm.db.commit(result_and_state.state); + + eip7002::post_commit(result_and_state.result) + } + + /// Applies the post-block call to the EIP-7251 consolidation requests contract. + pub fn post_block_consolidation_requests_contract_call( + &mut self, + db: &mut DB, + initialized_cfg: &CfgEnvWithHandlerCfg, + initialized_block_env: &BlockEnv, + ) -> Result + where + DB: Database + DatabaseCommit, + DB::Error: Display, + { + let mut evm = initialize_evm(db, initialized_cfg, initialized_block_env); + + let res = self.apply_consolidation_requests_contract_call(&mut evm)?; + + Ok(res) + } + + /// Applies the post-block call to the EIP-7251 consolidation requests contract. + pub fn apply_consolidation_requests_contract_call( + &mut self, + evm: &mut Evm<'_, Ext, DB>, + ) -> Result + where + DB: Database + DatabaseCommit, + DB::Error: Display, + { + let result_and_state = + eip7251::transact_consolidation_requests_contract_call(&self.evm_config.clone(), evm)?; + + if let Some(ref mut hook) = self.hook { + hook.on_state(&result_and_state.state); + } + evm.context.evm.db.commit(result_and_state.state); + + eip7251::post_commit(result_and_state.result) + } + + /// Delegate to stored `OnStateHook`, noop if hook is `None`. + pub fn on_state(&mut self, state: &EvmState) { + if let Some(ref mut hook) = &mut self.hook { + hook.on_state(state); + } + } +} diff --git a/crates/node/core/src/args/rpc_server.rs b/crates/node/core/src/args/rpc_server.rs index f4930db9f9b..c6783ef5c3a 100644 --- a/crates/node/core/src/args/rpc_server.rs +++ b/crates/node/core/src/args/rpc_server.rs @@ -29,12 +29,12 @@ use super::types::MaxOr; pub(crate) const RPC_DEFAULT_MAX_SUBS_PER_CONN: u32 = 1024; /// Default max request size in MB. -pub(crate) const RPC_DEFAULT_MAX_REQUEST_SIZE_MB: u32 = 15; +pub(crate) const RPC_DEFAULT_MAX_REQUEST_SIZE_MB: u32 = 4000; /// Default max response size in MB. /// /// This is only relevant for very large trace responses. -pub(crate) const RPC_DEFAULT_MAX_RESPONSE_SIZE_MB: u32 = 160; +pub(crate) const RPC_DEFAULT_MAX_RESPONSE_SIZE_MB: u32 = 4000; /// Default number of incoming connections. pub(crate) const RPC_DEFAULT_MAX_CONNECTIONS: u32 = 500; diff --git a/crates/optimism/chainspec/src/lib.rs b/crates/optimism/chainspec/src/lib.rs index 42bb3e3d2b3..3ad3e6c0bf3 100644 --- a/crates/optimism/chainspec/src/lib.rs +++ b/crates/optimism/chainspec/src/lib.rs @@ -92,6 +92,17 @@ impl OpChainSpecBuilder { Self { inner } } + /// Construct a new builder from the base sepolia chain spec. + pub fn base_sepolia() -> Self { + let mut inner = ChainSpecBuilder::default() + .chain(BASE_SEPOLIA.chain) + .genesis(BASE_SEPOLIA.genesis.clone()); + let forks = BASE_SEPOLIA.hardforks.clone(); + inner = inner.with_forks(forks); + + Self { inner } + } + /// Construct a new builder from the optimism mainnet chain spec. pub fn optimism_mainnet() -> Self { let mut inner = diff --git a/crates/optimism/primitives/Cargo.toml b/crates/optimism/primitives/Cargo.toml index 30257049c20..a332b1dfde5 100644 --- a/crates/optimism/primitives/Cargo.toml +++ b/crates/optimism/primitives/Cargo.toml @@ -106,4 +106,4 @@ arbitrary = [ "alloy-consensus/arbitrary", "alloy-primitives/arbitrary", "alloy-eips/arbitrary", -] +] \ No newline at end of file diff --git a/crates/rpc/rpc-engine-api/src/capabilities.rs b/crates/rpc/rpc-engine-api/src/capabilities.rs index 67a5a1b72d7..4011f575cb7 100644 --- a/crates/rpc/rpc-engine-api/src/capabilities.rs +++ b/crates/rpc/rpc-engine-api/src/capabilities.rs @@ -19,6 +19,8 @@ pub const CAPABILITIES: &[&str] = &[ "engine_getPayloadBodiesByRangeV1", "engine_getBlobsV1", "engine_getBlobsV2", + "engine_newFragV0", + "engine_sealFragV0", ]; // The list of all supported Engine capabilities available over the engine endpoint. diff --git a/crates/storage/provider/src/providers/consistent_view.rs b/crates/storage/provider/src/providers/consistent_view.rs index d8404af5416..e39d678f21b 100644 --- a/crates/storage/provider/src/providers/consistent_view.rs +++ b/crates/storage/provider/src/providers/consistent_view.rs @@ -22,6 +22,7 @@ use reth_storage_errors::provider::ProviderResult; pub struct ConsistentDbView { factory: Factory, tip: Option<(B256, u64)>, + ignore_tip_check: bool, } impl ConsistentDbView @@ -30,7 +31,7 @@ where { /// Creates new consistent database view. pub const fn new(factory: Factory, tip: Option<(B256, u64)>) -> Self { - Self { factory, tip } + Self { factory, tip, ignore_tip_check: false } } /// Creates new consistent database view with latest tip. @@ -46,6 +47,9 @@ where // Create a new provider. let provider_ro = self.factory.database_provider_ro()?; + if self.ignore_tip_check { + return Ok(provider_ro); + } // Check that the currently stored tip is included on-disk. // This means that the database may have moved, but the view was not reorged. // diff --git a/crates/storage/provider/src/providers/database/provider.rs b/crates/storage/provider/src/providers/database/provider.rs index a90b2c2e640..238a876d0f2 100644 --- a/crates/storage/provider/src/providers/database/provider.rs +++ b/crates/storage/provider/src/providers/database/provider.rs @@ -677,7 +677,7 @@ impl DatabaseProvider { /// Populate a [`BundleStateInit`] and [`RevertsInit`] using cursors over the /// [`PlainAccountState`] and [`PlainStorageState`] tables, based on the given storage and /// account changesets. - fn populate_bundle_state( + pub fn populate_bundle_state( &self, account_changeset: Vec<(u64, AccountBeforeTx)>, storage_changeset: Vec<(BlockNumberAddress, StorageEntry)>, diff --git a/justfile b/justfile new file mode 100644 index 00000000000..58dcc97370a --- /dev/null +++ b/justfile @@ -0,0 +1,14 @@ +# Makes sure the nightly-2025-02-26 toolchain is installed +toolchain := "nightly-2025-02-26" + +fmt: + rustup toolchain install {{toolchain}} > /dev/null 2>&1 && \ + cargo +{{toolchain}} fmt + +fmt-check: + rustup toolchain install {{toolchain}} > /dev/null 2>&1 && \ + cargo +{{toolchain}} fmt --check + +clippy: + rustup toolchain install {{toolchain}} > /dev/null 2>&1 && \ + cargo +{{toolchain}} clippy --all-features --no-deps -- -D warnings From 797a00b2998252db830cddf76bafdba3a02ba25e Mon Sep 17 00:00:00 2001 From: Suthiwat Date: Thu, 13 Nov 2025 18:31:18 +0000 Subject: [PATCH 6/8] stateroot --- crates/engine/tree/src/tree/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/engine/tree/src/tree/mod.rs b/crates/engine/tree/src/tree/mod.rs index ca8a93df079..7f78ff2f462 100644 --- a/crates/engine/tree/src/tree/mod.rs +++ b/crates/engine/tree/src/tree/mod.rs @@ -56,7 +56,7 @@ pub mod error; mod instrumented_state; mod invalid_headers; mod metrics; -mod payload_processor; +pub mod payload_processor; pub mod payload_validator; mod persistence_state; pub mod precompile_cache; From a037c8ed94a1c805c1d764596ee72736c735dda0 Mon Sep 17 00:00:00 2001 From: Suthiwat Date: Thu, 13 Nov 2025 18:34:03 +0000 Subject: [PATCH 7/8] MultiProofConfig --- crates/engine/tree/src/tree/payload_processor/multiproof.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/engine/tree/src/tree/payload_processor/multiproof.rs b/crates/engine/tree/src/tree/payload_processor/multiproof.rs index 7da199dd636..8957f87b7e4 100644 --- a/crates/engine/tree/src/tree/payload_processor/multiproof.rs +++ b/crates/engine/tree/src/tree/payload_processor/multiproof.rs @@ -58,7 +58,7 @@ impl SparseTrieUpdate { /// Common configuration for multi proof tasks #[derive(Debug, Clone, Default)] -pub(crate) struct MultiProofConfig { +pub struct MultiProofConfig { /// The sorted collection of cached in-memory intermediate trie nodes that /// can be reused for computation. pub nodes_sorted: Arc, From 25b9ceb8ae88604e87a54cd6590459e200e0e502 Mon Sep 17 00:00:00 2001 From: Suthiwat Date: Thu, 13 Nov 2025 18:35:03 +0000 Subject: [PATCH 8/8] pub from_input --- crates/engine/tree/src/tree/payload_processor/multiproof.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/engine/tree/src/tree/payload_processor/multiproof.rs b/crates/engine/tree/src/tree/payload_processor/multiproof.rs index 8957f87b7e4..b832fdcf50f 100644 --- a/crates/engine/tree/src/tree/payload_processor/multiproof.rs +++ b/crates/engine/tree/src/tree/payload_processor/multiproof.rs @@ -75,7 +75,7 @@ impl MultiProofConfig { /// /// This returns a cleared [`TrieInput`] so that we can reuse any allocated space in the /// [`TrieInput`]. - pub(crate) fn from_input(mut input: TrieInput) -> (TrieInput, Self) { + pub fn from_input(mut input: TrieInput) -> (TrieInput, Self) { let config = Self { nodes_sorted: Arc::new(input.nodes.drain_into_sorted()), state_sorted: Arc::new(input.state.drain_into_sorted()),