Compare commits

...

21 Commits

Author SHA1 Message Date
Brian Picciano
d6324d63e2 chore: release 1.11.3 2026-03-12 12:34:39 +01:00
Brian Picciano
5f3ade1bfe fix(trie): Reset proof v2 calculator on error (#22781)
Co-authored-by: Amp <amp@ampcode.com>
2026-03-12 10:09:18 +00:00
Derek Cofausper
b053f6fafe cherry-pick: fix don't produce both updates and removals for trie nodes (#22507)
Co-Authored-By: Arsenii Kulikov <62447812+klkvr@users.noreply.github.com>
2026-03-12 02:30:25 +00:00
Derek Cofausper
2a58e7a077 cherry-pick: install rayon panic handler (37f5b3a)
Co-Authored-By: Arsenii Kulikov <62447812+klkvr@users.noreply.github.com>
2026-03-12 02:30:17 +00:00
Emma Jamieson-Hoare
793a3d5fb3 fix missing import 2026-03-10 11:44:07 +00:00
Emma Jamieson-Hoare
89ae1af694 chore: upgrade to 1.11.2 2026-03-10 10:48:03 +00:00
Alexey Shekhirin
9c33fb5d45 fix(engine): reset execution cache hash on clear (#22895)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-10 10:46:09 +00:00
Alexey Shekhirin
bef3d7b4d1 fix lockfile 2026-02-23 18:36:44 +00:00
Emma Jamieson-Hoare
e918c17af9 chore: release 1.11.1
Amp-Thread-ID: https://ampcode.com/threads/T-019c8ba4-fd85-736b-9d2d-e878d350a91b
Co-authored-by: Amp <amp@ampcode.com>
2026-02-23 18:02:14 +00:00
Arsenii Kulikov
fcc170d53c fix: properly reveal trie nodes (#22415) 2026-02-23 17:58:13 +00:00
Arsenii Kulikov
c685842ba2 fix: overlay preparation on tokio (#22492) 2026-02-23 17:57:51 +00:00
Georgios Konstantopoulos
564ffa5868 fix(ci): pass docker tags as separate set entries in bake action (#22151)
Co-authored-by: Amp <amp@ampcode.com>
2026-02-12 22:10:35 +00:00
Dan Cline
12891dd171 chore: allow invalid storage metadata (#22150) 2026-02-12 22:02:26 +00:00
Emma Jamieson-Hoare
c1015022f5 chore: release reth v1.11.0 (#22148) 2026-02-12 21:39:30 +00:00
Dan Cline
e3fe6326bc chore(storage): rm storage settings, use only one (#22042)
Co-authored-by: joshieDo <93316087+joshieDo@users.noreply.github.com>
2026-02-12 21:17:05 +00:00
Dan Cline
e3d520b24f feat(network): add inbound / outbound scopes for disconnect reasons (#22070) 2026-02-12 20:54:03 +00:00
Dan Cline
9f29939ea1 feat: bundle mdbx_copy as reth db copy subcommand (#22061)
Co-authored-by: Emma Jamieson-Hoare <emmajam@users.noreply.github.com>
2026-02-12 20:39:56 +00:00
Matthias Seitz
10881d1c73 chore: fix book (#22142) 2026-02-12 21:44:53 +01:00
John Letey
408593467b feat(download): optional chain-aware snapshot url (#22119) 2026-02-12 21:42:19 +01:00
Emma Jamieson-Hoare
8caf8cdf11 docs: improve reth.rs/overview page (#22131)
Co-authored-by: Amp <amp@ampcode.com>
2026-02-12 20:10:34 +00:00
Georgios Konstantopoulos
1e8030ef28 fix(engine): return error on updates channel disconnect in sparse trie task (#22139)
Co-authored-by: Amp <amp@ampcode.com>
2026-02-12 20:00:36 +00:00
79 changed files with 1330 additions and 2530 deletions

View File

@@ -0,0 +1,4 @@
---
---
Improved documentation overview page with better structure and clarity.

View File

@@ -0,0 +1,5 @@
---
reth-trie-sparse: patch
---
Fixed a bug where trie nodes could appear in both `updated_nodes` and `removed_nodes` simultaneously by removing entries from `removed_nodes` when a node is inserted as updated.

View File

@@ -0,0 +1,5 @@
---
reth-trie: patch
---
Fixed a potential panic in `ProofCalculator` by clearing internal computation state (`branch_stack`, `child_stack`, `branch_path`, etc.) after errors, preventing stale state from causing `usize` underflow panics when the calculator is reused. Added a test verifying correct behavior after simulated mid-computation errors.

View File

@@ -70,18 +70,27 @@ jobs:
# Add 'latest' tag for non-RC releases
if [[ ! "$VERSION" =~ -rc ]]; then
echo "ethereum_tags=${REGISTRY}/reth:${VERSION},${REGISTRY}/reth:latest" >> "$GITHUB_OUTPUT"
{
echo "ethereum_set<<EOF"
echo "ethereum.tags=${REGISTRY}/reth:${VERSION}"
echo "ethereum.tags=${REGISTRY}/reth:latest"
echo "EOF"
} >> "$GITHUB_OUTPUT"
else
echo "ethereum_tags=${REGISTRY}/reth:${VERSION}" >> "$GITHUB_OUTPUT"
echo "ethereum_set=ethereum.tags=${REGISTRY}/reth:${VERSION}" >> "$GITHUB_OUTPUT"
fi
elif [[ "${{ github.event_name }}" == "schedule" ]] || [[ "${{ inputs.build_type }}" == "nightly" ]]; then
echo "targets=nightly" >> "$GITHUB_OUTPUT"
echo "ethereum_tags=${REGISTRY}/reth:nightly" >> "$GITHUB_OUTPUT"
echo "ethereum_set=ethereum.tags=${REGISTRY}/reth:nightly" >> "$GITHUB_OUTPUT"
else
# git-sha build
echo "targets=ethereum" >> "$GITHUB_OUTPUT"
echo "ethereum_tags=${REGISTRY}/reth:${{ github.sha }}" >> "$GITHUB_OUTPUT"
echo "ethereum_set=ethereum.tags=${REGISTRY}/reth:${{ github.sha }}" >> "$GITHUB_OUTPUT"
fi
- name: Build and push images
@@ -97,7 +106,7 @@ jobs:
targets: ${{ steps.params.outputs.targets }}
push: ${{ !(github.event_name == 'workflow_dispatch' && inputs.dry_run) }}
set: |
ethereum.tags=${{ steps.params.outputs.ethereum_tags }}
${{ steps.params.outputs.ethereum_set }}
- name: Verify image architectures
env:

242
Cargo.lock generated
View File

@@ -3300,7 +3300,7 @@ dependencies = [
[[package]]
name = "ef-test-runner"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"clap",
"ef-tests",
@@ -3308,7 +3308,7 @@ dependencies = [
[[package]]
name = "ef-tests"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-eips",
@@ -3748,7 +3748,7 @@ dependencies = [
[[package]]
name = "example-full-contract-state"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-primitives",
"eyre",
@@ -3880,7 +3880,7 @@ dependencies = [
[[package]]
name = "exex-subscription"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-primitives",
"clap",
@@ -7532,7 +7532,7 @@ checksum = "1e061d1b48cb8d38042de4ae0a7a6401009d6143dc80d2e2d6f31f0bdd6470c7"
[[package]]
name = "reth"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-node-bindings",
"alloy-primitives",
@@ -7579,7 +7579,7 @@ dependencies = [
[[package]]
name = "reth-basic-payload-builder"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-eips",
@@ -7602,7 +7602,7 @@ dependencies = [
[[package]]
name = "reth-bench"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-eips",
@@ -7649,7 +7649,7 @@ dependencies = [
[[package]]
name = "reth-bench-compare"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-primitives",
"alloy-provider",
@@ -7677,7 +7677,7 @@ dependencies = [
[[package]]
name = "reth-chain-state"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-eips",
@@ -7710,7 +7710,7 @@ dependencies = [
[[package]]
name = "reth-chainspec"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-chains",
"alloy-consensus",
@@ -7730,7 +7730,7 @@ dependencies = [
[[package]]
name = "reth-cli"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-genesis",
"clap",
@@ -7743,7 +7743,7 @@ dependencies = [
[[package]]
name = "reth-cli-commands"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-chains",
"alloy-consensus",
@@ -7830,7 +7830,7 @@ dependencies = [
[[package]]
name = "reth-cli-runner"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"reth-tasks",
"tokio",
@@ -7839,7 +7839,7 @@ dependencies = [
[[package]]
name = "reth-cli-util"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-eips",
"alloy-primitives",
@@ -7860,7 +7860,7 @@ dependencies = [
[[package]]
name = "reth-codecs"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-eips",
@@ -7884,7 +7884,7 @@ dependencies = [
[[package]]
name = "reth-codecs-derive"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"proc-macro2",
"quote",
@@ -7894,7 +7894,7 @@ dependencies = [
[[package]]
name = "reth-config"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-primitives",
"eyre",
@@ -7912,7 +7912,7 @@ dependencies = [
[[package]]
name = "reth-consensus"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-primitives",
@@ -7924,7 +7924,7 @@ dependencies = [
[[package]]
name = "reth-consensus-common"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-eips",
@@ -7938,7 +7938,7 @@ dependencies = [
[[package]]
name = "reth-consensus-debug-client"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-eips",
@@ -7963,7 +7963,7 @@ dependencies = [
[[package]]
name = "reth-db"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-primitives",
@@ -7998,7 +7998,7 @@ dependencies = [
[[package]]
name = "reth-db-api"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-genesis",
@@ -8029,7 +8029,7 @@ dependencies = [
[[package]]
name = "reth-db-common"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-genesis",
@@ -8060,7 +8060,7 @@ dependencies = [
[[package]]
name = "reth-db-models"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-eips",
"alloy-primitives",
@@ -8076,7 +8076,7 @@ dependencies = [
[[package]]
name = "reth-discv4"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-primitives",
"alloy-rlp",
@@ -8102,7 +8102,7 @@ dependencies = [
[[package]]
name = "reth-discv5"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-primitives",
"alloy-rlp",
@@ -8127,7 +8127,7 @@ dependencies = [
[[package]]
name = "reth-dns-discovery"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-chains",
"alloy-primitives",
@@ -8155,7 +8155,7 @@ dependencies = [
[[package]]
name = "reth-downloaders"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-eips",
@@ -8193,7 +8193,7 @@ dependencies = [
[[package]]
name = "reth-e2e-test-utils"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-eips",
@@ -8250,7 +8250,7 @@ dependencies = [
[[package]]
name = "reth-ecies"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"aes",
"alloy-primitives",
@@ -8277,7 +8277,7 @@ dependencies = [
[[package]]
name = "reth-engine-local"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-primitives",
@@ -8300,7 +8300,7 @@ dependencies = [
[[package]]
name = "reth-engine-primitives"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-eips",
@@ -8324,7 +8324,7 @@ dependencies = [
[[package]]
name = "reth-engine-service"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-eips",
"futures",
@@ -8354,7 +8354,7 @@ dependencies = [
[[package]]
name = "reth-engine-tree"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-eip7928",
@@ -8427,7 +8427,7 @@ dependencies = [
[[package]]
name = "reth-engine-util"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-rpc-types-engine",
@@ -8454,7 +8454,7 @@ dependencies = [
[[package]]
name = "reth-era"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-eips",
@@ -8476,7 +8476,7 @@ dependencies = [
[[package]]
name = "reth-era-downloader"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-primitives",
"bytes",
@@ -8494,7 +8494,7 @@ dependencies = [
[[package]]
name = "reth-era-utils"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-primitives",
@@ -8520,7 +8520,7 @@ dependencies = [
[[package]]
name = "reth-errors"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"reth-consensus",
"reth-execution-errors",
@@ -8530,7 +8530,7 @@ dependencies = [
[[package]]
name = "reth-eth-wire"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-chains",
"alloy-consensus",
@@ -8568,7 +8568,7 @@ dependencies = [
[[package]]
name = "reth-eth-wire-types"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-chains",
"alloy-consensus",
@@ -8593,7 +8593,7 @@ dependencies = [
[[package]]
name = "reth-ethereum"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-rpc-types-engine",
"alloy-rpc-types-eth",
@@ -8633,7 +8633,7 @@ dependencies = [
[[package]]
name = "reth-ethereum-cli"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"clap",
"eyre",
@@ -8656,7 +8656,7 @@ dependencies = [
[[package]]
name = "reth-ethereum-consensus"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-eips",
@@ -8672,7 +8672,7 @@ dependencies = [
[[package]]
name = "reth-ethereum-engine-primitives"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-eips",
"alloy-primitives",
@@ -8690,7 +8690,7 @@ dependencies = [
[[package]]
name = "reth-ethereum-forks"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-eip2124",
"alloy-hardforks 0.4.7",
@@ -8703,7 +8703,7 @@ dependencies = [
[[package]]
name = "reth-ethereum-payload-builder"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-eips",
@@ -8731,7 +8731,7 @@ dependencies = [
[[package]]
name = "reth-ethereum-primitives"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-eips",
@@ -8758,7 +8758,7 @@ dependencies = [
[[package]]
name = "reth-etl"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-primitives",
"rayon",
@@ -8768,7 +8768,7 @@ dependencies = [
[[package]]
name = "reth-evm"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-eips",
@@ -8792,7 +8792,7 @@ dependencies = [
[[package]]
name = "reth-evm-ethereum"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-eips",
@@ -8816,7 +8816,7 @@ dependencies = [
[[package]]
name = "reth-execution-errors"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-evm",
"alloy-primitives",
@@ -8828,7 +8828,7 @@ dependencies = [
[[package]]
name = "reth-execution-types"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-eips",
@@ -8848,7 +8848,7 @@ dependencies = [
[[package]]
name = "reth-exex"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-eips",
@@ -8893,7 +8893,7 @@ dependencies = [
[[package]]
name = "reth-exex-test-utils"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-eips",
"eyre",
@@ -8924,7 +8924,7 @@ dependencies = [
[[package]]
name = "reth-exex-types"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-eips",
"alloy-primitives",
@@ -8941,7 +8941,7 @@ dependencies = [
[[package]]
name = "reth-fs-util"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"serde",
"serde_json",
@@ -8950,7 +8950,7 @@ dependencies = [
[[package]]
name = "reth-invalid-block-hooks"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-eips",
@@ -8983,7 +8983,7 @@ dependencies = [
[[package]]
name = "reth-ipc"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"bytes",
"futures",
@@ -9005,7 +9005,7 @@ dependencies = [
[[package]]
name = "reth-libmdbx"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"bitflags 2.10.0",
"byteorder",
@@ -9023,7 +9023,7 @@ dependencies = [
[[package]]
name = "reth-mdbx-sys"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"bindgen",
"cc",
@@ -9031,7 +9031,7 @@ dependencies = [
[[package]]
name = "reth-metrics"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"futures",
"metrics",
@@ -9042,7 +9042,7 @@ dependencies = [
[[package]]
name = "reth-net-banlist"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-primitives",
"ipnet",
@@ -9050,7 +9050,7 @@ dependencies = [
[[package]]
name = "reth-net-nat"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"futures-util",
"if-addrs",
@@ -9064,7 +9064,7 @@ dependencies = [
[[package]]
name = "reth-network"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-eips",
@@ -9126,7 +9126,7 @@ dependencies = [
[[package]]
name = "reth-network-api"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-primitives",
@@ -9150,7 +9150,7 @@ dependencies = [
[[package]]
name = "reth-network-p2p"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-eips",
@@ -9172,7 +9172,7 @@ dependencies = [
[[package]]
name = "reth-network-peers"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-primitives",
"alloy-rlp",
@@ -9189,7 +9189,7 @@ dependencies = [
[[package]]
name = "reth-network-types"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-eip2124",
"humantime-serde",
@@ -9202,7 +9202,7 @@ dependencies = [
[[package]]
name = "reth-nippy-jar"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"anyhow",
"bincode 1.3.3",
@@ -9220,7 +9220,7 @@ dependencies = [
[[package]]
name = "reth-node-api"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-rpc-types-engine",
"eyre",
@@ -9243,7 +9243,7 @@ dependencies = [
[[package]]
name = "reth-node-builder"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-eips",
@@ -9315,7 +9315,7 @@ dependencies = [
[[package]]
name = "reth-node-core"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-eips",
@@ -9371,7 +9371,7 @@ dependencies = [
[[package]]
name = "reth-node-ethereum"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-contract",
@@ -9431,7 +9431,7 @@ dependencies = [
[[package]]
name = "reth-node-ethstats"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-primitives",
@@ -9454,7 +9454,7 @@ dependencies = [
[[package]]
name = "reth-node-events"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-eips",
@@ -9477,7 +9477,7 @@ dependencies = [
[[package]]
name = "reth-node-metrics"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"bytes",
"eyre",
@@ -9506,7 +9506,7 @@ dependencies = [
[[package]]
name = "reth-node-types"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"reth-chainspec",
"reth-db-api",
@@ -9517,7 +9517,7 @@ dependencies = [
[[package]]
name = "reth-payload-builder"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-primitives",
@@ -9537,7 +9537,7 @@ dependencies = [
[[package]]
name = "reth-payload-builder-primitives"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"pin-project",
"reth-payload-primitives",
@@ -9548,7 +9548,7 @@ dependencies = [
[[package]]
name = "reth-payload-primitives"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-eips",
@@ -9571,7 +9571,7 @@ dependencies = [
[[package]]
name = "reth-payload-util"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-primitives",
@@ -9580,7 +9580,7 @@ dependencies = [
[[package]]
name = "reth-payload-validator"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-rpc-types-engine",
@@ -9589,7 +9589,7 @@ dependencies = [
[[package]]
name = "reth-primitives"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-eips",
@@ -9611,7 +9611,7 @@ dependencies = [
[[package]]
name = "reth-primitives-traits"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-eips",
@@ -9649,7 +9649,7 @@ dependencies = [
[[package]]
name = "reth-provider"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-eips",
@@ -9699,7 +9699,7 @@ dependencies = [
[[package]]
name = "reth-prune"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-eips",
@@ -9732,11 +9732,11 @@ dependencies = [
[[package]]
name = "reth-prune-db"
version = "1.10.2"
version = "1.11.3"
[[package]]
name = "reth-prune-types"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-primitives",
"arbitrary",
@@ -9756,7 +9756,7 @@ dependencies = [
[[package]]
name = "reth-revm"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-primitives",
@@ -9770,7 +9770,7 @@ dependencies = [
[[package]]
name = "reth-rpc"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-dyn-abi",
@@ -9850,7 +9850,7 @@ dependencies = [
[[package]]
name = "reth-rpc-api"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-eip7928",
"alloy-eips",
@@ -9880,7 +9880,7 @@ dependencies = [
[[package]]
name = "reth-rpc-api-testing-util"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-eips",
"alloy-primitives",
@@ -9899,7 +9899,7 @@ dependencies = [
[[package]]
name = "reth-rpc-builder"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-eips",
"alloy-network",
@@ -9955,7 +9955,7 @@ dependencies = [
[[package]]
name = "reth-rpc-convert"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-evm",
@@ -9979,7 +9979,7 @@ dependencies = [
[[package]]
name = "reth-rpc-e2e-tests"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-genesis",
"alloy-rpc-types-engine",
@@ -9999,7 +9999,7 @@ dependencies = [
[[package]]
name = "reth-rpc-engine-api"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-eips",
"alloy-primitives",
@@ -10035,7 +10035,7 @@ dependencies = [
[[package]]
name = "reth-rpc-eth-api"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-dyn-abi",
@@ -10078,7 +10078,7 @@ dependencies = [
[[package]]
name = "reth-rpc-eth-types"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-eips",
@@ -10126,7 +10126,7 @@ dependencies = [
[[package]]
name = "reth-rpc-layer"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-rpc-types-engine",
"http",
@@ -10143,7 +10143,7 @@ dependencies = [
[[package]]
name = "reth-rpc-server-types"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-eips",
"alloy-primitives",
@@ -10158,7 +10158,7 @@ dependencies = [
[[package]]
name = "reth-stages"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-eips",
@@ -10220,7 +10220,7 @@ dependencies = [
[[package]]
name = "reth-stages-api"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-eips",
"alloy-primitives",
@@ -10253,7 +10253,7 @@ dependencies = [
[[package]]
name = "reth-stages-types"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-primitives",
"arbitrary",
@@ -10269,7 +10269,7 @@ dependencies = [
[[package]]
name = "reth-static-file"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-primitives",
"assert_matches",
@@ -10292,7 +10292,7 @@ dependencies = [
[[package]]
name = "reth-static-file-types"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-primitives",
"clap",
@@ -10310,7 +10310,7 @@ dependencies = [
[[package]]
name = "reth-storage-api"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-eips",
@@ -10333,7 +10333,7 @@ dependencies = [
[[package]]
name = "reth-storage-errors"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-eips",
"alloy-primitives",
@@ -10349,7 +10349,7 @@ dependencies = [
[[package]]
name = "reth-storage-rpc-provider"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-eips",
@@ -10378,7 +10378,7 @@ dependencies = [
[[package]]
name = "reth-tasks"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"auto_impl",
"dyn-clone",
@@ -10395,7 +10395,7 @@ dependencies = [
[[package]]
name = "reth-testing-utils"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-eips",
@@ -10411,7 +10411,7 @@ dependencies = [
[[package]]
name = "reth-tokio-util"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"tokio",
"tokio-stream",
@@ -10420,7 +10420,7 @@ dependencies = [
[[package]]
name = "reth-tracing"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"clap",
"eyre",
@@ -10438,7 +10438,7 @@ dependencies = [
[[package]]
name = "reth-tracing-otlp"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"clap",
"eyre",
@@ -10455,7 +10455,7 @@ dependencies = [
[[package]]
name = "reth-transaction-pool"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-eips",
@@ -10506,7 +10506,7 @@ dependencies = [
[[package]]
name = "reth-trie"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-eips",
@@ -10540,7 +10540,7 @@ dependencies = [
[[package]]
name = "reth-trie-common"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-genesis",
@@ -10573,7 +10573,7 @@ dependencies = [
[[package]]
name = "reth-trie-db"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-consensus",
"alloy-primitives",
@@ -10604,7 +10604,7 @@ dependencies = [
[[package]]
name = "reth-trie-parallel"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-primitives",
"alloy-rlp",
@@ -10634,7 +10634,7 @@ dependencies = [
[[package]]
name = "reth-trie-sparse"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"alloy-primitives",
"alloy-rlp",
@@ -10665,7 +10665,7 @@ dependencies = [
[[package]]
name = "reth-zstd-compressors"
version = "1.10.2"
version = "1.11.3"
dependencies = [
"zstd",
]

View File

@@ -1,5 +1,5 @@
[workspace.package]
version = "1.10.2"
version = "1.11.3"
edition = "2024"
rust-version = "1.88"
license = "MIT OR Apache-2.0"
@@ -449,14 +449,18 @@ revm-inspectors = "0.34.2"
# eth
alloy-dyn-abi = "1.5.6"
alloy-primitives = { version = "1.5.6", default-features = false, features = ["map-foldhash"] }
alloy-primitives = { version = "1.5.6", default-features = false, features = [
"map-foldhash",
] }
alloy-sol-types = { version = "1.5.6", default-features = false }
alloy-chains = { version = "0.2.5", default-features = false }
alloy-eip2124 = { version = "0.2.0", default-features = false }
alloy-eip7928 = { version = "0.3.0", default-features = false }
alloy-evm = { version = "0.27.2", default-features = false }
alloy-rlp = { version = "0.3.13", default-features = false, features = ["core-net"] }
alloy-rlp = { version = "0.3.13", default-features = false, features = [
"core-net",
] }
alloy-trie = { version = "0.9.4", default-features = false }
alloy-hardforks = "0.4.5"
@@ -468,10 +472,15 @@ alloy-genesis = { version = "1.6.3", default-features = false }
alloy-json-rpc = { version = "1.6.3", default-features = false }
alloy-network = { version = "1.6.3", default-features = false }
alloy-network-primitives = { version = "1.6.3", default-features = false }
alloy-provider = { version = "1.6.3", features = ["reqwest", "debug-api"], default-features = false }
alloy-provider = { version = "1.6.3", features = [
"reqwest",
"debug-api",
], default-features = false }
alloy-pubsub = { version = "1.6.3", default-features = false }
alloy-rpc-client = { version = "1.6.3", default-features = false }
alloy-rpc-types = { version = "1.6.3", features = ["eth"], default-features = false }
alloy-rpc-types = { version = "1.6.3", features = [
"eth",
], default-features = false }
alloy-rpc-types-admin = { version = "1.6.3", default-features = false }
alloy-rpc-types-anvil = { version = "1.6.3", default-features = false }
alloy-rpc-types-beacon = { version = "1.6.3", default-features = false }
@@ -485,7 +494,9 @@ alloy-serde = { version = "1.6.3", default-features = false }
alloy-signer = { version = "1.6.3", default-features = false }
alloy-signer-local = { version = "1.6.3", default-features = false }
alloy-transport = { version = "1.6.3" }
alloy-transport-http = { version = "1.6.3", features = ["reqwest-rustls-tls"], default-features = false }
alloy-transport-http = { version = "1.6.3", features = [
"reqwest-rustls-tls",
], default-features = false }
alloy-transport-ipc = { version = "1.6.3", default-features = false }
alloy-transport-ws = { version = "1.6.3", default-features = false }
@@ -504,7 +515,10 @@ either = { version = "1.15.0", default-features = false }
arrayvec = { version = "0.7.6", default-features = false }
aquamarine = "0.6"
auto_impl = "1"
backon = { version = "1.2", default-features = false, features = ["std-blocking-sleep", "tokio-sleep"] }
backon = { version = "1.2", default-features = false, features = [
"std-blocking-sleep",
"tokio-sleep",
] }
bincode = "1.3"
bitflags = "2.4"
boyer-moore-magiclen = "0.2.16"
@@ -526,9 +540,13 @@ itertools = { version = "0.14", default-features = false }
linked_hash_set = "0.1"
lz4 = "1.28.1"
modular-bitfield = "0.13.1"
notify = { version = "8.0.0", default-features = false, features = ["macos_fsevent"] }
notify = { version = "8.0.0", default-features = false, features = [
"macos_fsevent",
] }
nybbles = { version = "0.4.8", default-features = false }
once_cell = { version = "1.19", default-features = false, features = ["critical-section"] }
once_cell = { version = "1.19", default-features = false, features = [
"critical-section",
] }
parking_lot = "0.12"
paste = "1.0"
rand = "0.9"
@@ -547,7 +565,9 @@ strum_macros = "0.27"
syn = "2.0"
thiserror = { version = "2.0.0", default-features = false }
tar = "0.4.44"
tracing = { version = "0.1.0", default-features = false, features = ["attributes"] }
tracing = { version = "0.1.0", default-features = false, features = [
"attributes",
] }
tracing-appender = "0.2"
url = { version = "2.3", default-features = false }
zstd = "0.13"
@@ -585,7 +605,11 @@ futures-util = { version = "0.3", default-features = false }
hyper = "1.3"
hyper-util = "0.1.5"
pin-project = "1.0.12"
reqwest = { version = "0.12", default-features = false, features = ["rustls-tls", "rustls-tls-native-roots", "stream"] }
reqwest = { version = "0.12", default-features = false, features = [
"rustls-tls",
"rustls-tls-native-roots",
"stream",
] }
tracing-futures = "0.2"
tower = "0.5"
tower-http = "0.6"
@@ -610,7 +634,10 @@ proptest-arbitrary-interop = "0.1.0"
# crypto
enr = { version = "0.13", default-features = false }
k256 = { version = "0.13", default-features = false, features = ["ecdsa"] }
secp256k1 = { version = "0.30", default-features = false, features = ["global-context", "recovery"] }
secp256k1 = { version = "0.30", default-features = false, features = [
"global-context",
"recovery",
] }
# rand 8 for secp256k1
rand_08 = { package = "rand", version = "0.8" }

View File

@@ -312,6 +312,11 @@ impl DeferredTrieData {
/// Given that invariant, circular wait dependencies are impossible.
#[instrument(level = "debug", target = "engine::tree::deferred_trie", skip_all)]
pub fn wait_cloned(&self) -> ComputedTrieData {
#[cfg(feature = "rayon")]
debug_assert!(
rayon::current_thread_index().is_none(),
"wait_cloned must not be called from a rayon worker thread"
);
let mut state = self.state.lock();
match &mut *state {
// If the deferred trie data is ready, return the cached result.

View File

@@ -19,7 +19,7 @@ use reth_node_builder::{
Node, NodeComponents, NodeComponentsBuilder, NodeTypes, NodeTypesWithDBAdapter,
};
use reth_node_core::{
args::{DatabaseArgs, DatadirArgs, RocksDbArgs, StaticFilesArgs, StorageArgs},
args::{DatabaseArgs, DatadirArgs, StaticFilesArgs, StorageArgs},
dirs::{ChainPath, DataDirPath},
};
use reth_provider::{
@@ -67,62 +67,23 @@ pub struct EnvironmentArgs<C: ChainSpecParser> {
#[command(flatten)]
pub static_files: StaticFilesArgs,
/// All `RocksDB` related arguments
#[command(flatten)]
pub rocksdb: RocksDbArgs,
/// Storage mode configuration (v2 vs v1/legacy)
#[command(flatten)]
pub storage: StorageArgs,
}
impl<C: ChainSpecParser> EnvironmentArgs<C> {
/// Returns the effective storage settings derived from `--storage.v2`, static-file, and
/// `RocksDB` CLI args.
/// Returns the effective storage settings derived from `--storage.v2`.
///
/// The base storage mode is determined by `--storage.v2`:
/// - When `--storage.v2` is set: uses [`StorageSettings::v2()`] defaults
/// - Otherwise: uses [`StorageSettings::v1()`] defaults
///
/// Individual `--static-files.*` and `--rocksdb.*` flags override the base when explicitly set.
/// - Otherwise: uses [`StorageSettings::base()`] defaults
pub fn storage_settings(&self) -> StorageSettings {
let mut s = if self.storage.v2 { StorageSettings::v2() } else { StorageSettings::base() };
// Apply static files overrides (only when explicitly set)
if let Some(v) = self.static_files.receipts {
s = s.with_receipts_in_static_files(v);
if self.storage.v2 {
StorageSettings::v2()
} else {
StorageSettings::base()
}
if let Some(v) = self.static_files.transaction_senders {
s = s.with_transaction_senders_in_static_files(v);
}
if let Some(v) = self.static_files.account_changesets {
s = s.with_account_changesets_in_static_files(v);
}
if let Some(v) = self.static_files.storage_changesets {
s = s.with_storage_changesets_in_static_files(v);
}
// Apply rocksdb overrides
// --rocksdb.all sets all rocksdb flags to true
if self.rocksdb.all {
s = s
.with_transaction_hash_numbers_in_rocksdb(true)
.with_storages_history_in_rocksdb(true)
.with_account_history_in_rocksdb(true);
}
// Individual rocksdb flags override --rocksdb.all when explicitly set
if let Some(v) = self.rocksdb.tx_hash {
s = s.with_transaction_hash_numbers_in_rocksdb(v);
}
if let Some(v) = self.rocksdb.storages_history {
s = s.with_storages_history_in_rocksdb(v);
}
if let Some(v) = self.rocksdb.account_history {
s = s.with_account_history_in_rocksdb(v);
}
s
}
/// Initializes environment according to [`AccessRights`] and returns an instance of

View File

@@ -23,7 +23,7 @@ impl Command {
/// Execute `db account-storage` command
pub fn execute<N: NodeTypesWithDB>(self, tool: &DbTool<N>) -> eyre::Result<()> {
let address = self.address;
let use_hashed_state = tool.provider_factory.cached_storage_settings().use_hashed_state;
let use_hashed_state = tool.provider_factory.cached_storage_settings().use_hashed_state();
let (slot_count, storage_size) = if use_hashed_state {
let hashed_address = keccak256(address);

View File

@@ -0,0 +1,61 @@
use clap::Parser;
use reth_db::mdbx::{self, ffi};
use std::path::PathBuf;
/// Copies the MDBX database to a new location.
///
/// Equivalent to the standalone `mdbx_copy` tool but bundled into reth.
#[derive(Parser, Debug)]
pub struct Command {
/// Destination path for the database copy.
dest: PathBuf,
/// Compact the database while copying (reclaims free space).
#[arg(short, long)]
compact: bool,
/// Force dynamic size for the destination database.
#[arg(short = 'd', long)]
force_dynamic_size: bool,
/// Throttle to avoid MVCC pressure on writers.
#[arg(short = 'p', long)]
throttle_mvcc: bool,
}
impl Command {
/// Execute `db copy` command
pub fn execute(self, db: &mdbx::DatabaseEnv) -> eyre::Result<()> {
let mut flags: ffi::MDBX_copy_flags_t = ffi::MDBX_CP_DEFAULTS;
if self.compact {
flags |= ffi::MDBX_CP_COMPACT;
}
if self.force_dynamic_size {
flags |= ffi::MDBX_CP_FORCE_DYNAMIC_SIZE;
}
if self.throttle_mvcc {
flags |= ffi::MDBX_CP_THROTTLE_MVCC;
}
let dest = self
.dest
.to_str()
.ok_or_else(|| eyre::eyre!("destination path must be valid UTF-8"))?;
let dest_cstr = std::ffi::CString::new(dest)?;
println!("Copying database to {} ...", self.dest.display());
let rc = db.with_raw_env_ptr(|env_ptr| unsafe {
ffi::mdbx_env_copy(env_ptr, dest_cstr.as_ptr(), flags)
});
if rc != 0 {
eyre::bail!("mdbx_env_copy failed with error code {rc}: {}", unsafe {
std::ffi::CStr::from_ptr(ffi::mdbx_strerror(rc)).to_string_lossy()
});
}
println!("Done.");
Ok(())
}
}

View File

@@ -12,6 +12,7 @@ use std::{
mod account_storage;
mod checksum;
mod clear;
mod copy;
mod diff;
mod get;
mod list;
@@ -42,6 +43,8 @@ pub enum Subcommands {
List(list::Command),
/// Calculates the content checksum of a table or static file segment
Checksum(checksum::Command),
/// Copies the MDBX database to a new location (bundled mdbx_copy)
Copy(copy::Command),
/// Create a diff between two database tables or two entire databases.
Diff(diff::Command),
/// Gets the content of a table for the given key
@@ -124,6 +127,11 @@ impl<C: ChainSpecParser<ChainSpec: EthChainSpec + EthereumHardforks>> Command<C>
command.execute(&tool)?;
});
}
Subcommands::Copy(command) => {
db_exec!(self.env, tool, N, AccessRights::RO, {
command.execute(tool.provider_factory.db_ref())?;
});
}
Subcommands::Diff(command) => {
db_exec!(self.env, tool, N, AccessRights::RO, {
command.execute(&tool)?;

View File

@@ -39,50 +39,12 @@ enum Subcommands {
#[derive(Debug, Clone, Copy, Subcommand)]
#[clap(rename_all = "snake_case")]
pub enum SetCommand {
/// Store receipts in static files instead of the database
Receipts {
#[clap(action(ArgAction::Set))]
value: bool,
},
/// Store transaction senders in static files instead of the database
TransactionSenders {
#[clap(action(ArgAction::Set))]
value: bool,
},
/// Store account changesets in static files instead of the database
AccountChangesets {
#[clap(action(ArgAction::Set))]
value: bool,
},
/// Store storage history in rocksdb instead of MDBX
StoragesHistory {
#[clap(action(ArgAction::Set))]
value: bool,
},
/// Store transaction hash to number mapping in rocksdb instead of MDBX
TransactionHashNumbers {
#[clap(action(ArgAction::Set))]
value: bool,
},
/// Store account history in rocksdb instead of MDBX
AccountHistory {
#[clap(action(ArgAction::Set))]
value: bool,
},
/// Store storage changesets in static files instead of the database
StorageChangesets {
#[clap(action(ArgAction::Set))]
value: bool,
},
/// Use hashed state tables (HashedAccounts/HashedStorages) as canonical state
/// Enable or disable v2 storage layout
///
/// When enabled, execution writes directly to hashed tables, eliminating need for
/// separate hashing stages. State reads come from hashed tables.
///
/// WARNING: Changing this setting in either direction requires re-syncing the database.
/// Enabling on an existing plain-state database leaves hashed tables empty.
/// Disabling on an existing hashed-state database leaves plain tables empty.
UseHashedState {
/// When enabled, uses static files for receipts/senders/changesets and RocksDB for
/// history indices and transaction hashes. When disabled, uses v1/legacy layout (everything in
/// MDBX).
V2 {
#[clap(action(ArgAction::Set))]
value: bool,
},
@@ -125,87 +87,18 @@ impl Command {
println!("No storage settings found, creating new settings.");
}
let mut settings @ StorageSettings {
receipts_in_static_files: _,
transaction_senders_in_static_files: _,
storages_history_in_rocksdb: _,
transaction_hash_numbers_in_rocksdb: _,
account_history_in_rocksdb: _,
account_changesets_in_static_files: _,
storage_changesets_in_static_files: _,
use_hashed_state: _,
} = settings.unwrap_or_else(StorageSettings::v1);
let mut settings @ StorageSettings { storage_v2: _ } =
settings.unwrap_or_else(StorageSettings::v1);
// Update the setting based on the key
match cmd {
SetCommand::Receipts { value } => {
if settings.receipts_in_static_files == value {
println!("receipts_in_static_files is already set to {}", value);
SetCommand::V2 { value } => {
if settings.storage_v2 == value {
println!("storage_v2 is already set to {}", value);
return Ok(());
}
settings.receipts_in_static_files = value;
println!("Set receipts_in_static_files = {}", value);
}
SetCommand::TransactionSenders { value } => {
if settings.transaction_senders_in_static_files == value {
println!("transaction_senders_in_static_files is already set to {}", value);
return Ok(());
}
settings.transaction_senders_in_static_files = value;
println!("Set transaction_senders_in_static_files = {}", value);
}
SetCommand::AccountChangesets { value } => {
if settings.account_changesets_in_static_files == value {
println!("account_changesets_in_static_files is already set to {}", value);
return Ok(());
}
settings.account_changesets_in_static_files = value;
println!("Set account_changesets_in_static_files = {}", value);
}
SetCommand::StoragesHistory { value } => {
if settings.storages_history_in_rocksdb == value {
println!("storages_history_in_rocksdb is already set to {}", value);
return Ok(());
}
settings.storages_history_in_rocksdb = value;
println!("Set storages_history_in_rocksdb = {}", value);
}
SetCommand::TransactionHashNumbers { value } => {
if settings.transaction_hash_numbers_in_rocksdb == value {
println!("transaction_hash_numbers_in_rocksdb is already set to {}", value);
return Ok(());
}
settings.transaction_hash_numbers_in_rocksdb = value;
println!("Set transaction_hash_numbers_in_rocksdb = {}", value);
}
SetCommand::AccountHistory { value } => {
if settings.account_history_in_rocksdb == value {
println!("account_history_in_rocksdb is already set to {}", value);
return Ok(());
}
settings.account_history_in_rocksdb = value;
println!("Set account_history_in_rocksdb = {}", value);
}
SetCommand::StorageChangesets { value } => {
if settings.storage_changesets_in_static_files == value {
println!("storage_changesets_in_static_files is already set to {}", value);
return Ok(());
}
settings.storage_changesets_in_static_files = value;
println!("Set storage_changesets_in_static_files = {}", value);
}
SetCommand::UseHashedState { value } => {
if settings.use_hashed_state == value {
println!("use_hashed_state is already set to {}", value);
return Ok(());
}
if settings.use_hashed_state && !value {
println!("WARNING: Disabling use_hashed_state on an existing hashed-state database requires a full resync.");
} else {
println!("WARNING: Enabling use_hashed_state on an existing plain-state database requires a full resync.");
}
settings.use_hashed_state = value;
println!("Set use_hashed_state = {}", value);
settings.storage_v2 = value;
println!("Set storage_v2 = {}", value);
}
}

View File

@@ -63,7 +63,7 @@ impl Command {
address: Address,
limit: usize,
) -> eyre::Result<()> {
let use_hashed_state = tool.provider_factory.cached_storage_settings().use_hashed_state;
let use_hashed_state = tool.provider_factory.cached_storage_settings().use_hashed_state();
let entries = tool.provider_factory.db_ref().view(|tx| {
let (account, walker_entries) = if use_hashed_state {
@@ -145,7 +145,7 @@ impl Command {
// Check storage settings to determine where history is stored
let storage_settings = tool.provider_factory.cached_storage_settings();
let history_in_rocksdb = storage_settings.storages_history_in_rocksdb;
let history_in_rocksdb = storage_settings.storage_v2;
// For historical queries, enumerate keys from history indices only
// (not PlainStorageState, which reflects current state)

View File

@@ -37,6 +37,14 @@ pub struct DownloadDefaults {
pub available_snapshots: Vec<Cow<'static, str>>,
/// Default base URL for snapshots
pub default_base_url: Cow<'static, str>,
/// Default base URL for chain-aware snapshots.
///
/// When set, the chain ID is appended to form the full URL: `{base_url}/{chain_id}`.
/// For example, given a base URL of `https://snapshots.example.com` and chain ID `1`,
/// the resulting URL would be `https://snapshots.example.com/1`.
///
/// Falls back to [`default_base_url`](Self::default_base_url) when `None`.
pub default_chain_aware_base_url: Option<Cow<'static, str>>,
/// Optional custom long help text that overrides the generated help
pub long_help: Option<String>,
}
@@ -60,6 +68,7 @@ impl DownloadDefaults {
Cow::Borrowed("https://publicnode.com/snapshots (full nodes & testnets)"),
],
default_base_url: Cow::Borrowed(MERKLE_BASE_URL),
default_chain_aware_base_url: None,
long_help: None,
}
}
@@ -84,9 +93,11 @@ impl DownloadDefaults {
}
help.push_str(
"\nIf no URL is provided, the latest mainnet archive snapshot\nwill be proposed for download from ",
"\nIf no URL is provided, the latest archive snapshot for the selected chain\nwill be proposed for download from ",
);
help.push_str(
self.default_chain_aware_base_url.as_deref().unwrap_or(&self.default_base_url),
);
help.push_str(self.default_base_url.as_ref());
help.push_str(
".\n\nLocal file:// URLs are also supported for extracting snapshots from disk.",
);
@@ -111,6 +122,12 @@ impl DownloadDefaults {
self
}
/// Set the default chain-aware base URL.
pub fn with_chain_aware_base_url(mut self, url: impl Into<Cow<'static, str>>) -> Self {
self.default_chain_aware_base_url = Some(url.into());
self
}
/// Builder: Set custom long help text, overriding the generated help
pub fn with_long_help(mut self, help: impl Into<String>) -> Self {
self.long_help = Some(help.into());
@@ -142,7 +159,7 @@ impl<C: ChainSpecParser<ChainSpec: EthChainSpec + EthereumHardforks>> DownloadCo
let url = match self.url {
Some(url) => url,
None => {
let url = get_latest_snapshot_url().await?;
let url = get_latest_snapshot_url(self.env.chain.chain().id()).await?;
info!(target: "reth::cli", "Using default snapshot URL: {}", url);
url
}
@@ -509,8 +526,12 @@ async fn stream_and_extract(url: &str, target_dir: &Path) -> Result<()> {
}
// Builds default URL for latest mainnet archive snapshot using configured defaults
async fn get_latest_snapshot_url() -> Result<String> {
let base_url = &DownloadDefaults::get_global().default_base_url;
async fn get_latest_snapshot_url(chain_id: u64) -> Result<String> {
let defaults = DownloadDefaults::get_global();
let base_url = match &defaults.default_chain_aware_base_url {
Some(url) => format!("{url}/{chain_id}"),
None => defaults.default_base_url.to_string(),
};
let latest_url = format!("{base_url}/latest.txt");
let filename = Client::new()
.get(latest_url)

View File

@@ -10,8 +10,8 @@ use reth_node_builder::NodeBuilder;
use reth_node_core::{
args::{
DatabaseArgs, DatadirArgs, DebugArgs, DevArgs, EngineArgs, EraArgs, MetricArgs,
NetworkArgs, PayloadBuilderArgs, PruningArgs, RocksDbArgs, RpcServerArgs, StaticFilesArgs,
StorageArgs, TxPoolArgs,
NetworkArgs, PayloadBuilderArgs, PruningArgs, RpcServerArgs, StaticFilesArgs, StorageArgs,
TxPoolArgs,
},
node_config::NodeConfig,
version,
@@ -103,10 +103,6 @@ pub struct NodeCommand<C: ChainSpecParser, Ext: clap::Args + fmt::Debug = NoArgs
#[command(flatten)]
pub pruning: PruningArgs,
/// All `RocksDB` table routing arguments
#[command(flatten)]
pub rocksdb: RocksDbArgs,
/// Engine cli arguments
#[command(flatten, next_help_heading = "Engine")]
pub engine: EngineArgs,
@@ -175,7 +171,6 @@ where
db,
dev,
pruning,
rocksdb,
engine,
era,
static_files,
@@ -183,9 +178,6 @@ where
ext,
} = self;
// Validate RocksDB arguments
rocksdb.validate()?;
// set up node config
let mut node_config = NodeConfig {
datadir,
@@ -201,7 +193,6 @@ where
db,
dev,
pruning,
rocksdb,
engine,
era,
static_files,

View File

@@ -133,7 +133,7 @@ impl<C: ChainSpecParser> Command<C> {
reset_stage_checkpoint(tx, StageId::SenderRecovery)?;
}
StageEnum::Execution => {
if provider_rw.cached_storage_settings().use_hashed_state {
if provider_rw.cached_storage_settings().use_hashed_state() {
tx.clear::<tables::HashedAccounts>()?;
tx.clear::<tables::HashedStorages>()?;
reset_stage_checkpoint(tx, StageId::AccountHashing)?;
@@ -187,7 +187,7 @@ impl<C: ChainSpecParser> Command<C> {
let settings = provider_rw.cached_storage_settings();
let rocksdb = tool.provider_factory.rocksdb_provider();
if settings.account_history_in_rocksdb {
if settings.storage_v2 {
rocksdb.clear::<tables::AccountsHistory>()?;
} else {
tx.clear::<tables::AccountsHistory>()?;
@@ -204,7 +204,7 @@ impl<C: ChainSpecParser> Command<C> {
let settings = provider_rw.cached_storage_settings();
let rocksdb = tool.provider_factory.rocksdb_provider();
if settings.storages_history_in_rocksdb {
if settings.storage_v2 {
rocksdb.clear::<tables::StoragesHistory>()?;
} else {
tx.clear::<tables::StoragesHistory>()?;
@@ -218,7 +218,7 @@ impl<C: ChainSpecParser> Command<C> {
)?;
}
StageEnum::TxLookup => {
if provider_rw.cached_storage_settings().transaction_hash_numbers_in_rocksdb {
if provider_rw.cached_storage_settings().storage_v2 {
tool.provider_factory
.rocksdb_provider()
.clear::<tables::TransactionHashNumbers>()?;

View File

@@ -10,7 +10,6 @@ use jsonrpsee::core::client::ClientT;
use reth_chainspec::{ChainSpec, ChainSpecBuilder, MAINNET};
use reth_db::tables;
use reth_e2e_test_utils::{transaction::TransactionTestContext, wallet, E2ETestSetupBuilder};
use reth_node_core::args::RocksDbArgs;
use reth_node_ethereum::EthereumNode;
use reth_payload_builder::EthPayloadBuilderAttributes;
use reth_provider::RocksDBProviderFactory;
@@ -96,22 +95,6 @@ fn test_attributes_generator(timestamp: u64) -> EthPayloadBuilderAttributes {
EthPayloadBuilderAttributes::new(B256::ZERO, attributes)
}
/// Verifies that `RocksDB` CLI defaults are `None` (deferred to storage mode).
#[test]
fn test_rocksdb_defaults_are_none() {
let args = RocksDbArgs::default();
assert!(args.tx_hash.is_none(), "tx_hash default should be None (deferred to --storage.v2)");
assert!(
args.storages_history.is_none(),
"storages_history default should be None (deferred to --storage.v2)"
);
assert!(
args.account_history.is_none(),
"account_history default should be None (deferred to --storage.v2)"
);
}
/// Smoke test: node boots with `RocksDB` routing enabled.
#[tokio::test]
async fn test_rocksdb_node_startup() -> Result<()> {
@@ -477,7 +460,7 @@ async fn test_rocksdb_pending_tx_not_in_storage() -> Result<()> {
///
/// This test exercises `unwind_trie_state_from` which previously failed with
/// `UnsortedInput` errors because it read changesets directly from MDBX tables
/// instead of using storage-aware methods that check `storage_changesets_in_static_files`.
/// instead of using storage-aware methods that check `is_v2()`.
#[tokio::test]
async fn test_rocksdb_reorg_unwind() -> Result<()> {
reth_tracing::init_test_tracing();

View File

@@ -94,7 +94,7 @@ where
if chain_spec.is_optimism() { EngineApiKind::OpStack } else { EngineApiKind::Ethereum };
let downloader = BasicBlockDownloader::new(client, consensus.clone());
let use_hashed_state = provider.cached_storage_settings().use_hashed_state;
let use_hashed_state = provider.cached_storage_settings().use_hashed_state();
let persistence_handle =
PersistenceHandle::<N::Primitives>::spawn_service(provider, pruner, sync_metrics_tx);

View File

@@ -845,8 +845,10 @@ impl SavedCache {
self.caches.update_metrics(&self.metrics);
}
/// Clears all caches, resetting them to empty state.
pub(crate) fn clear(&self) {
/// Clears all caches, resetting them to empty state,
/// and updates the hash of the block this cache belongs to.
pub(crate) fn clear_with_hash(&mut self, hash: B256) {
self.hash = hash;
self.caches.clear();
}
}

View File

@@ -1411,7 +1411,7 @@ where
// Spawn a background task to trigger computation so it's ready when the next payload
// arrives.
if let Some(overlay) = self.state.tree_state.prepare_canonical_overlay() {
rayon::spawn(move || {
tokio::task::spawn_blocking(move || {
let _ = overlay.get();
});
}

View File

@@ -50,7 +50,7 @@ use std::{
mpsc::{self, channel},
Arc,
},
time::Instant,
time::{Duration, Instant},
};
use tracing::{debug, debug_span, instrument, warn, Span};
@@ -444,8 +444,8 @@ where
let _ = execute_tx.send(tx);
next_for_execution += 1;
while let Some(entry) = queue.first_entry() &&
*entry.key() == next_for_execution
while let Some(entry) = queue.first_entry()
&& *entry.key() == next_for_execution
{
let _ = execute_tx.send(entry.remove());
next_for_execution += 1;
@@ -926,7 +926,7 @@ impl PayloadExecutionCache {
#[instrument(level = "debug", target = "engine::tree::payload_processor", skip(self))]
pub(crate) fn get_cache_for(&self, parent_hash: B256) -> Option<SavedCache> {
let start = Instant::now();
let cache = self.inner.read();
let mut cache = self.inner.write();
let elapsed = start.elapsed();
self.metrics.execution_cache_wait_duration.record(elapsed.as_secs_f64());
@@ -934,7 +934,7 @@ impl PayloadExecutionCache {
warn!(blocked_for=?elapsed, "Blocked waiting for execution cache mutex");
}
if let Some(c) = cache.as_ref() {
if let Some(c) = cache.as_mut() {
let cached_hash = c.executed_block_hash();
// Check that the cache hash matches the parent hash of the current block. It won't
// match in case it's a fork block.
@@ -955,13 +955,13 @@ impl PayloadExecutionCache {
);
if available {
// If the has is available (no other threads are using it), but has a mismatching
// parent hash, we can just clear it and keep using without re-creating from
// scratch.
if !hash_matches {
c.clear();
// Fork block: clear and update the hash on the ORIGINAL before cloning.
// This prevents the canonical chain from matching on the stale hash
// and picking up polluted data if the fork block fails.
c.clear_with_hash(parent_hash);
}
return Some(c.clone())
return Some(c.clone());
} else if hash_matches {
self.metrics.execution_cache_in_use.increment(1);
}
@@ -972,10 +972,25 @@ impl PayloadExecutionCache {
None
}
/// Clears the tracked cache
#[expect(unused)]
pub(crate) fn clear(&self) {
self.inner.write().take();
/// Waits until the execution cache becomes available for use.
///
/// This acquires a write lock to ensure exclusive access, then immediately releases it.
/// This is useful for synchronization before starting payload processing.
///
/// Returns the time spent waiting for the lock.
pub fn wait_for_availability(&self) -> Duration {
let start = Instant::now();
// Acquire write lock to wait for any current holders to finish
let _guard = self.inner.write();
let elapsed = start.elapsed();
if elapsed.as_millis() > 5 {
debug!(
target: "engine::tree::payload_processor",
blocked_for=?elapsed,
"Waited for execution cache to become available"
);
}
elapsed
}
/// Updates the cache with a closure that has exclusive access to the guard.
@@ -1128,10 +1143,18 @@ mod tests {
execution_cache.update_with_guard(|slot| *slot = Some(make_saved_cache(hash)));
// When the parent hash doesn't match, the cache is cleared and returned for reuse
// When the parent hash doesn't match (fork block), the cache is cleared,
// hash updated on the original, and clone returned for reuse
let different_hash = B256::from([4u8; 32]);
let cache = execution_cache.get_cache_for(different_hash);
assert!(cache.is_some(), "cache should be returned for reuse after clearing")
assert!(cache.is_some(), "cache should be returned for reuse after clearing");
drop(cache);
// The stored cache now has the fork block's parent hash.
// Canonical chain looking for original hash sees a mismatch → clears and reuses.
let original = execution_cache.get_cache_for(hash);
assert!(original.is_some(), "canonical chain gets cache back via mismatch+clear");
}
#[test]
@@ -1355,4 +1378,61 @@ mod tests {
"State root mismatch: task={root_from_task}, base={root_from_regular}"
);
}
/// Tests the full prewarm lifecycle for a fork block:
///
/// 1. Cache is at canonical block 4.
/// 2. Fork block (parent = block 2) checks out the cache via `get_cache_for`, simulating what
/// `PrewarmCacheTask` does when it receives a `SavedCache`.
/// 3. Prewarm populates the shared cache with fork-specific state.
/// 4. While the prewarm clone is alive, the cache is unavailable (`usage_guard` > 1).
/// 5. Prewarm drops without calling `save_cache` (fork block was invalid).
/// 6. Canonical block 5 (parent = block 4) must get a cache with correct hash and no stale fork
/// data.
#[test]
fn fork_prewarm_dropped_without_save_does_not_corrupt_cache() {
let execution_cache = PayloadExecutionCache::default();
// Canonical chain at block 4.
let block4_hash = B256::from([4u8; 32]);
execution_cache.update_with_guard(|slot| *slot = Some(make_saved_cache(block4_hash)));
// Fork block arrives with parent = block 2. Prewarm task checks out the cache.
// This simulates PrewarmCacheTask receiving a SavedCache clone from get_cache_for.
let fork_parent = B256::from([2u8; 32]);
let prewarm_cache = execution_cache.get_cache_for(fork_parent);
assert!(prewarm_cache.is_some(), "prewarm should obtain cache for fork block");
let prewarm_cache = prewarm_cache.unwrap();
assert_eq!(prewarm_cache.executed_block_hash(), fork_parent);
// Prewarm populates cache with fork-specific state (ancestor data for block 2).
// Since ExecutionCache uses Arc<Inner>, this data is shared with the stored original.
let fork_addr = Address::from([0xBB; 20]);
let fork_key = B256::from([0xCC; 32]);
prewarm_cache.cache().insert_storage(fork_addr, fork_key, Some(U256::from(999)));
// While prewarm holds the clone, the usage_guard count > 1 → cache is in use.
let during_prewarm = execution_cache.get_cache_for(block4_hash);
assert!(
during_prewarm.is_none(),
"cache must be unavailable while prewarm holds a reference"
);
// Fork block fails — prewarm task drops without calling save_cache/update_with_guard.
drop(prewarm_cache);
// Canonical block 5 arrives (parent = block 4).
// Stored hash = fork_parent (our fix), so get_cache_for sees a mismatch,
// clears the stale fork data, and returns a cache with hash = block4_hash.
let block5_cache = execution_cache.get_cache_for(block4_hash);
assert!(
block5_cache.is_some(),
"canonical chain must get cache after fork prewarm is dropped"
);
assert_eq!(
block5_cache.as_ref().unwrap().executed_block_hash(),
block4_hash,
"cache must carry the canonical parent hash, not the fork parent"
);
}
}

View File

@@ -416,7 +416,9 @@ where
let update = match message {
Ok(m) => m,
Err(_) => {
break
return Err(ParallelStateRootError::Other(
"updates channel disconnected before state root calculation".to_string(),
))
}
};

View File

@@ -221,7 +221,7 @@ impl TestHarness {
EngineApiKind::Ethereum,
evm_config,
changeset_cache,
provider.cached_storage_settings().use_hashed_state,
provider.cached_storage_settings().use_hashed_state(),
);
let block_builder = TestBlockBuilder::default().with_chain_spec((*chain_spec).clone());

View File

@@ -25,7 +25,7 @@ use crate::{
listener::ConnectionListener,
message::{NewBlockMessage, PeerMessage},
metrics::{
BackedOffPeersMetrics, ClosedSessionsMetrics, DisconnectMetrics, NetworkMetrics,
BackedOffPeersMetrics, ClosedSessionsMetrics, DirectionalDisconnectMetrics, NetworkMetrics,
PendingSessionFailureMetrics, NETWORK_POOL_TRANSACTIONS_SCOPE,
},
network::{NetworkHandle, NetworkHandleMessage},
@@ -140,8 +140,8 @@ pub struct NetworkManager<N: NetworkPrimitives = EthNetworkPrimitives> {
num_active_peers: Arc<AtomicUsize>,
/// Metrics for the Network
metrics: NetworkMetrics,
/// Disconnect metrics for the Network
disconnect_metrics: DisconnectMetrics,
/// Disconnect metrics for the Network, split by connection direction.
disconnect_metrics: DirectionalDisconnectMetrics,
/// Closed sessions metrics, split by direction.
closed_sessions_metrics: ClosedSessionsMetrics,
/// Pending session failure metrics, split by direction.
@@ -864,6 +864,9 @@ impl<N: NetworkPrimitives> NetworkManager<N> {
"Session disconnected"
);
// Capture direction before state is reset to Idle
let is_inbound = self.swarm.state().peers().is_inbound_peer(&peer_id);
let reason = if let Some(ref err) = error {
// If the connection was closed due to an error, we report
// the peer
@@ -887,7 +890,11 @@ impl<N: NetworkPrimitives> NetworkManager<N> {
self.update_active_connection_metrics();
if let Some(reason) = reason {
self.disconnect_metrics.increment(reason);
if is_inbound {
self.disconnect_metrics.increment_inbound(reason);
} else {
self.disconnect_metrics.increment_outbound(reason);
}
}
self.metrics
.backed_off_peers
@@ -910,7 +917,7 @@ impl<N: NetworkPrimitives> NetworkManager<N> {
.on_incoming_pending_session_dropped(remote_addr, err);
self.pending_session_failure_metrics.inbound.increment(1);
if let Some(reason) = err.as_disconnected() {
self.disconnect_metrics.increment(reason);
self.disconnect_metrics.increment_inbound(reason);
}
} else {
self.swarm
@@ -943,7 +950,7 @@ impl<N: NetworkPrimitives> NetworkManager<N> {
BackoffReason::from_disconnect(err.as_disconnected()),
);
if let Some(reason) = err.as_disconnected() {
self.disconnect_metrics.increment(reason);
self.disconnect_metrics.increment_outbound(reason);
}
} else {
self.swarm

View File

@@ -301,6 +301,34 @@ macro_rules! duration_metered_exec {
}};
}
/// Direction-aware wrapper for disconnect metrics.
///
/// Tracks disconnect reasons for inbound and outbound connections separately, in addition to
/// the combined (legacy) counters.
#[derive(Debug, Default)]
pub(crate) struct DirectionalDisconnectMetrics {
/// Combined disconnect metrics (all directions).
pub(crate) total: DisconnectMetrics,
/// Disconnect metrics for inbound connections only.
pub(crate) inbound: InboundDisconnectMetrics,
/// Disconnect metrics for outbound connections only.
pub(crate) outbound: OutboundDisconnectMetrics,
}
impl DirectionalDisconnectMetrics {
/// Increments disconnect counters for an inbound connection.
pub(crate) fn increment_inbound(&self, reason: DisconnectReason) {
self.total.increment(reason);
self.inbound.increment(reason);
}
/// Increments disconnect counters for an outbound connection.
pub(crate) fn increment_outbound(&self, reason: DisconnectReason) {
self.total.increment(reason);
self.outbound.increment(reason);
}
}
/// Metrics for Disconnection types
///
/// These are just counters, and ideally we would implement these metrics on a peer-by-peer basis,
@@ -370,6 +398,144 @@ impl DisconnectMetrics {
}
}
/// Disconnect metrics scoped to inbound connections only.
///
/// These counters track disconnect reasons exclusively for sessions that were initiated by
/// remote peers connecting to this node. This helps operators distinguish between being rejected
/// by remote peers (outbound) vs rejecting incoming peers (inbound).
#[derive(Metrics)]
#[metrics(scope = "network.inbound")]
pub struct InboundDisconnectMetrics {
/// Number of inbound peer disconnects due to `DisconnectRequested` (0x00)
pub(crate) disconnect_requested: Counter,
/// Number of inbound peer disconnects due to `TcpSubsystemError` (0x01)
pub(crate) tcp_subsystem_error: Counter,
/// Number of inbound peer disconnects due to `ProtocolBreach` (0x02)
pub(crate) protocol_breach: Counter,
/// Number of inbound peer disconnects due to `UselessPeer` (0x03)
pub(crate) useless_peer: Counter,
/// Number of inbound peer disconnects due to `TooManyPeers` (0x04)
pub(crate) too_many_peers: Counter,
/// Number of inbound peer disconnects due to `AlreadyConnected` (0x05)
pub(crate) already_connected: Counter,
/// Number of inbound peer disconnects due to `IncompatibleP2PProtocolVersion` (0x06)
pub(crate) incompatible: Counter,
/// Number of inbound peer disconnects due to `NullNodeIdentity` (0x07)
pub(crate) null_node_identity: Counter,
/// Number of inbound peer disconnects due to `ClientQuitting` (0x08)
pub(crate) client_quitting: Counter,
/// Number of inbound peer disconnects due to `UnexpectedHandshakeIdentity` (0x09)
pub(crate) unexpected_identity: Counter,
/// Number of inbound peer disconnects due to `ConnectedToSelf` (0x0a)
pub(crate) connected_to_self: Counter,
/// Number of inbound peer disconnects due to `PingTimeout` (0x0b)
pub(crate) ping_timeout: Counter,
/// Number of inbound peer disconnects due to `SubprotocolSpecific` (0x10)
pub(crate) subprotocol_specific: Counter,
}
impl InboundDisconnectMetrics {
/// Increments the proper counter for the given disconnect reason
pub(crate) fn increment(&self, reason: DisconnectReason) {
match reason {
DisconnectReason::DisconnectRequested => self.disconnect_requested.increment(1),
DisconnectReason::TcpSubsystemError => self.tcp_subsystem_error.increment(1),
DisconnectReason::ProtocolBreach => self.protocol_breach.increment(1),
DisconnectReason::UselessPeer => self.useless_peer.increment(1),
DisconnectReason::TooManyPeers => self.too_many_peers.increment(1),
DisconnectReason::AlreadyConnected => self.already_connected.increment(1),
DisconnectReason::IncompatibleP2PProtocolVersion => self.incompatible.increment(1),
DisconnectReason::NullNodeIdentity => self.null_node_identity.increment(1),
DisconnectReason::ClientQuitting => self.client_quitting.increment(1),
DisconnectReason::UnexpectedHandshakeIdentity => self.unexpected_identity.increment(1),
DisconnectReason::ConnectedToSelf => self.connected_to_self.increment(1),
DisconnectReason::PingTimeout => self.ping_timeout.increment(1),
DisconnectReason::SubprotocolSpecific => self.subprotocol_specific.increment(1),
}
}
}
/// Disconnect metrics scoped to outbound connections only.
///
/// These counters track disconnect reasons exclusively for sessions that this node initiated
/// by dialing out to remote peers. A high `too_many_peers` count here indicates remote peers
/// are rejecting our connection attempts because they are full.
#[derive(Metrics)]
#[metrics(scope = "network.outbound")]
pub struct OutboundDisconnectMetrics {
/// Number of outbound peer disconnects due to `DisconnectRequested` (0x00)
pub(crate) disconnect_requested: Counter,
/// Number of outbound peer disconnects due to `TcpSubsystemError` (0x01)
pub(crate) tcp_subsystem_error: Counter,
/// Number of outbound peer disconnects due to `ProtocolBreach` (0x02)
pub(crate) protocol_breach: Counter,
/// Number of outbound peer disconnects due to `UselessPeer` (0x03)
pub(crate) useless_peer: Counter,
/// Number of outbound peer disconnects due to `TooManyPeers` (0x04)
pub(crate) too_many_peers: Counter,
/// Number of outbound peer disconnects due to `AlreadyConnected` (0x05)
pub(crate) already_connected: Counter,
/// Number of outbound peer disconnects due to `IncompatibleP2PProtocolVersion` (0x06)
pub(crate) incompatible: Counter,
/// Number of outbound peer disconnects due to `NullNodeIdentity` (0x07)
pub(crate) null_node_identity: Counter,
/// Number of outbound peer disconnects due to `ClientQuitting` (0x08)
pub(crate) client_quitting: Counter,
/// Number of outbound peer disconnects due to `UnexpectedHandshakeIdentity` (0x09)
pub(crate) unexpected_identity: Counter,
/// Number of outbound peer disconnects due to `ConnectedToSelf` (0x0a)
pub(crate) connected_to_self: Counter,
/// Number of outbound peer disconnects due to `PingTimeout` (0x0b)
pub(crate) ping_timeout: Counter,
/// Number of outbound peer disconnects due to `SubprotocolSpecific` (0x10)
pub(crate) subprotocol_specific: Counter,
}
impl OutboundDisconnectMetrics {
/// Increments the proper counter for the given disconnect reason
pub(crate) fn increment(&self, reason: DisconnectReason) {
match reason {
DisconnectReason::DisconnectRequested => self.disconnect_requested.increment(1),
DisconnectReason::TcpSubsystemError => self.tcp_subsystem_error.increment(1),
DisconnectReason::ProtocolBreach => self.protocol_breach.increment(1),
DisconnectReason::UselessPeer => self.useless_peer.increment(1),
DisconnectReason::TooManyPeers => self.too_many_peers.increment(1),
DisconnectReason::AlreadyConnected => self.already_connected.increment(1),
DisconnectReason::IncompatibleP2PProtocolVersion => self.incompatible.increment(1),
DisconnectReason::NullNodeIdentity => self.null_node_identity.increment(1),
DisconnectReason::ClientQuitting => self.client_quitting.increment(1),
DisconnectReason::UnexpectedHandshakeIdentity => self.unexpected_identity.increment(1),
DisconnectReason::ConnectedToSelf => self.connected_to_self.increment(1),
DisconnectReason::PingTimeout => self.ping_timeout.increment(1),
DisconnectReason::SubprotocolSpecific => self.subprotocol_specific.increment(1),
}
}
}
/// Metrics for the `EthRequestHandler`
#[derive(Metrics)]
#[metrics(scope = "network")]

View File

@@ -218,6 +218,13 @@ impl PeersManager {
})
}
/// Returns `true` if the given peer is connected via an inbound session.
pub(crate) fn is_inbound_peer(&self, peer_id: &PeerId) -> bool {
self.peers.get(peer_id).is_some_and(|p| {
matches!(p.state, PeerConnectionState::In | PeerConnectionState::DisconnectingIn)
})
}
/// Returns an iterator over all peer ids for peers with the given kind
pub(crate) fn peers_by_kind(&self, kind: PeerKind) -> impl Iterator<Item = PeerId> + '_ {
self.peers.iter().filter_map(move |(peer_id, peer)| (peer.kind == kind).then_some(*peer_id))

View File

@@ -76,10 +76,6 @@ pub use era::{DefaultEraHost, EraArgs, EraSourceArgs};
mod static_files;
pub use static_files::{StaticFilesArgs, MINIMAL_BLOCKS_PER_FILE};
/// `RocksDbArgs` for configuring RocksDB table routing.
mod rocksdb;
pub use rocksdb::{RocksDbArgs, RocksDbArgsError};
/// `StorageArgs` for configuring storage settings.
mod storage;
pub use storage::StorageArgs;

View File

@@ -1,160 +0,0 @@
//! clap [Args](clap::Args) for `RocksDB` table routing configuration
use clap::{ArgAction, Args};
/// Parameters for `RocksDB` table routing configuration.
///
/// These flags control which database tables are stored in `RocksDB` instead of MDBX.
/// All flags are genesis-initialization-only: changing them after genesis requires a re-sync.
///
/// When `--storage.v2` is used, the defaults for these flags change to enable `RocksDB` routing.
/// Individual flags can still override those defaults when explicitly set.
#[derive(Debug, Args, PartialEq, Eq, Clone, Copy, Default)]
#[command(next_help_heading = "RocksDB")]
pub struct RocksDbArgs {
/// Route all supported tables to `RocksDB` instead of MDBX.
///
/// This enables `RocksDB` for `tx-hash`, `storages-history`, and `account-history` tables.
/// Cannot be combined with individual flags set to false.
#[arg(long = "rocksdb.all", action = ArgAction::SetTrue)]
pub all: bool,
/// Route tx hash -> number table to `RocksDB` instead of MDBX.
///
/// This is a genesis-initialization-only flag: changing it after genesis requires a re-sync.
/// Defaults to the base storage mode (v1: false, v2: true).
#[arg(long = "rocksdb.tx-hash", action = ArgAction::Set)]
pub tx_hash: Option<bool>,
/// Route storages history tables to `RocksDB` instead of MDBX.
///
/// This is a genesis-initialization-only flag: changing it after genesis requires a re-sync.
/// Defaults to the base storage mode (v1: false, v2: true).
#[arg(long = "rocksdb.storages-history", action = ArgAction::Set)]
pub storages_history: Option<bool>,
/// Route account history tables to `RocksDB` instead of MDBX.
///
/// This is a genesis-initialization-only flag: changing it after genesis requires a re-sync.
/// Defaults to the base storage mode (v1: false, v2: true).
#[arg(long = "rocksdb.account-history", action = ArgAction::Set)]
pub account_history: Option<bool>,
}
impl RocksDbArgs {
/// Validates the `RocksDB` arguments.
///
/// Returns an error if `--rocksdb.all` is used with any individual flag explicitly set to
/// `false`.
pub const fn validate(&self) -> Result<(), RocksDbArgsError> {
if self.all {
if matches!(self.tx_hash, Some(false)) {
return Err(RocksDbArgsError::ConflictingFlags("tx-hash"));
}
if matches!(self.storages_history, Some(false)) {
return Err(RocksDbArgsError::ConflictingFlags("storages-history"));
}
if matches!(self.account_history, Some(false)) {
return Err(RocksDbArgsError::ConflictingFlags("account-history"));
}
}
Ok(())
}
}
/// Error type for `RocksDB` argument validation.
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
pub enum RocksDbArgsError {
/// `--rocksdb.all` cannot be combined with an individual flag set to false.
#[error("--rocksdb.all cannot be combined with --rocksdb.{0}=false")]
ConflictingFlags(&'static str),
}
#[cfg(test)]
mod tests {
use super::*;
use clap::Parser;
#[derive(Parser)]
struct CommandParser<T: Args> {
#[command(flatten)]
args: T,
}
#[test]
fn test_default_rocksdb_args() {
let args = CommandParser::<RocksDbArgs>::parse_from(["reth"]).args;
assert_eq!(args, RocksDbArgs::default());
assert!(!args.all);
assert!(args.tx_hash.is_none());
assert!(args.storages_history.is_none());
assert!(args.account_history.is_none());
}
#[test]
fn test_parse_all_flag() {
let args = CommandParser::<RocksDbArgs>::parse_from(["reth", "--rocksdb.all"]).args;
assert!(args.all);
assert!(args.tx_hash.is_none());
}
#[test]
fn test_parse_individual_flags() {
let args = CommandParser::<RocksDbArgs>::parse_from([
"reth",
"--rocksdb.tx-hash=true",
"--rocksdb.storages-history=false",
"--rocksdb.account-history=true",
])
.args;
assert!(!args.all);
assert_eq!(args.tx_hash, Some(true));
assert_eq!(args.storages_history, Some(false));
assert_eq!(args.account_history, Some(true));
}
#[test]
fn test_validate_all_with_none_ok() {
let args =
RocksDbArgs { all: true, tx_hash: None, storages_history: None, account_history: None };
assert!(args.validate().is_ok());
}
#[test]
fn test_validate_all_with_true_ok() {
let args = RocksDbArgs {
all: true,
tx_hash: Some(true),
storages_history: Some(true),
account_history: Some(true),
};
assert!(args.validate().is_ok());
}
#[test]
fn test_validate_all_with_false_errors() {
let args = RocksDbArgs {
all: true,
tx_hash: Some(false),
storages_history: None,
account_history: None,
};
assert_eq!(args.validate(), Err(RocksDbArgsError::ConflictingFlags("tx-hash")));
let args = RocksDbArgs {
all: true,
tx_hash: None,
storages_history: Some(false),
account_history: None,
};
assert_eq!(args.validate(), Err(RocksDbArgsError::ConflictingFlags("storages-history")));
let args = RocksDbArgs {
all: true,
tx_hash: None,
storages_history: None,
account_history: Some(false),
};
assert_eq!(args.validate(), Err(RocksDbArgsError::ConflictingFlags("account-history")));
}
}

View File

@@ -9,9 +9,6 @@ use reth_config::config::{BlocksPerFileConfig, StaticFilesConfig};
pub const MINIMAL_BLOCKS_PER_FILE: u64 = 10000;
/// Parameters for static files configuration
///
/// When `--storage.v2` is used, the defaults for the storage flags change to enable static file
/// storage. Individual flags can still override those defaults when explicitly set.
#[derive(Debug, Args, PartialEq, Eq, Clone, Copy, Default)]
#[command(next_help_heading = "Static Files")]
pub struct StaticFilesArgs {
@@ -38,53 +35,6 @@ pub struct StaticFilesArgs {
/// Number of blocks per file for the storage changesets segment.
#[arg(long = "static-files.blocks-per-file.storage-change-sets")]
pub blocks_per_file_storage_change_sets: Option<u64>,
/// Store receipts in static files instead of the database.
///
/// When enabled, receipts will be written to static files on disk instead of the database.
///
/// Note: This setting can only be configured at genesis initialization. Once
/// the node has been initialized, changing this flag requires re-syncing from scratch.
///
/// Defaults to the base storage mode (v1: false, v2: true).
#[arg(long = "static-files.receipts", action = clap::ArgAction::Set)]
pub receipts: Option<bool>,
/// Store transaction senders in static files instead of the database.
///
/// When enabled, transaction senders will be written to static files on disk instead of the
/// database.
///
/// Note: This setting can only be configured at genesis initialization. Once
/// the node has been initialized, changing this flag requires re-syncing from scratch.
///
/// Defaults to the base storage mode (v1: false, v2: true).
#[arg(long = "static-files.transaction-senders", action = clap::ArgAction::Set)]
pub transaction_senders: Option<bool>,
/// Store account changesets in static files.
///
/// When enabled, account changesets will be written to static files on disk instead of the
/// database.
///
/// Note: This setting can only be configured at genesis initialization. Once
/// the node has been initialized, changing this flag requires re-syncing from scratch.
///
/// Defaults to the base storage mode (v1: false, v2: true).
#[arg(long = "static-files.account-change-sets", action = clap::ArgAction::Set)]
pub account_changesets: Option<bool>,
/// Store storage changesets in static files.
///
/// When enabled, storage changesets will be written to static files on disk instead of the
/// database.
///
/// Note: This setting can only be configured at genesis initialization. Once
/// the node has been initialized, changing this flag requires re-syncing from scratch.
///
/// Defaults to the base storage mode (v1: false, v2: true).
#[arg(long = "static-files.storage-change-sets", action = clap::ArgAction::Set)]
pub storage_changesets: Option<bool>,
}
impl StaticFilesArgs {

View File

@@ -25,16 +25,6 @@ pub struct StorageArgs {
/// flags.
#[arg(long = "storage.v2", action = ArgAction::SetTrue)]
pub v2: bool,
/// Use hashed state tables (`HashedAccounts`/`HashedStorages`) as canonical state
/// representation instead of plain state tables.
///
/// When enabled, execution writes directly to hashed tables, eliminating the need for
/// separate hashing stages. This should only be enabled for new databases.
///
/// WARNING: Changing this setting on an existing database requires a full resync.
#[arg(long = "storage.use-hashed-state", default_value_t = false)]
pub use_hashed_state: bool,
}
#[cfg(test)]

View File

@@ -3,7 +3,7 @@
use crate::{
args::{
DatabaseArgs, DatadirArgs, DebugArgs, DevArgs, EngineArgs, NetworkArgs, PayloadBuilderArgs,
PruningArgs, RocksDbArgs, RpcServerArgs, StaticFilesArgs, StorageArgs, TxPoolArgs,
PruningArgs, RpcServerArgs, StaticFilesArgs, StorageArgs, TxPoolArgs,
},
dirs::{ChainPath, DataDirPath},
utils::get_single_header,
@@ -152,9 +152,6 @@ pub struct NodeConfig<ChainSpec> {
/// All static files related arguments
pub static_files: StaticFilesArgs,
/// All `RocksDB` table routing arguments
pub rocksdb: RocksDbArgs,
/// All storage related arguments with --storage prefix
pub storage: StorageArgs,
}
@@ -188,7 +185,6 @@ impl<ChainSpec> NodeConfig<ChainSpec> {
engine: EngineArgs::default(),
era: EraArgs::default(),
static_files: StaticFilesArgs::default(),
rocksdb: RocksDbArgs::default(),
storage: StorageArgs::default(),
}
}
@@ -264,7 +260,6 @@ impl<ChainSpec> NodeConfig<ChainSpec> {
engine,
era,
static_files,
rocksdb,
storage,
..
} = self;
@@ -285,7 +280,6 @@ impl<ChainSpec> NodeConfig<ChainSpec> {
engine,
era,
static_files,
rocksdb,
storage,
}
}
@@ -369,49 +363,17 @@ impl<ChainSpec> NodeConfig<ChainSpec> {
self.pruning.prune_config(&self.chain)
}
/// Returns the effective storage settings derived from `--storage.v2`, static-file, and
/// `RocksDB` CLI args.
/// Returns the effective storage settings derived from `--storage.v2`.
///
/// The base storage mode is determined by `--storage.v2`:
/// - When `--storage.v2` is set: uses [`StorageSettings::v2()`] defaults
/// - Otherwise: uses [`StorageSettings::v1()`] defaults
///
/// Individual `--static-files.*` and `--rocksdb.*` flags override the base when explicitly set.
/// - Otherwise: uses [`StorageSettings::base()`] defaults
pub const fn storage_settings(&self) -> StorageSettings {
let mut s = if self.storage.v2 { StorageSettings::v2() } else { StorageSettings::base() };
// Apply static files overrides (only when explicitly set)
s = s
.with_receipts_in_static_files_opt(self.static_files.receipts)
.with_transaction_senders_in_static_files_opt(self.static_files.transaction_senders)
.with_account_changesets_in_static_files_opt(self.static_files.account_changesets)
.with_storage_changesets_in_static_files_opt(self.static_files.storage_changesets);
// Apply rocksdb overrides
// --rocksdb.all sets all rocksdb flags to true
if self.rocksdb.all {
s = s
.with_transaction_hash_numbers_in_rocksdb(true)
.with_storages_history_in_rocksdb(true)
.with_account_history_in_rocksdb(true);
if self.storage.v2 {
StorageSettings::v2()
} else {
StorageSettings::base()
}
// Individual rocksdb flags override --rocksdb.all when explicitly set
s = s
.with_transaction_hash_numbers_in_rocksdb_opt(self.rocksdb.tx_hash)
.with_storages_history_in_rocksdb_opt(self.rocksdb.storages_history)
.with_account_history_in_rocksdb_opt(self.rocksdb.account_history);
s = s.with_use_hashed_state(self.storage.use_hashed_state);
if s.use_hashed_state {
s = s.with_storage_changesets_in_static_files(true);
}
if s.storage_changesets_in_static_files {
s = s.with_use_hashed_state(true);
}
s
}
/// Returns the max block that the node should run to, looking it up from the network if
@@ -608,7 +570,6 @@ impl<ChainSpec> NodeConfig<ChainSpec> {
engine: self.engine,
era: self.era,
static_files: self.static_files,
rocksdb: self.rocksdb,
storage: self.storage,
}
}
@@ -651,7 +612,6 @@ impl<ChainSpec> Clone for NodeConfig<ChainSpec> {
engine: self.engine.clone(),
era: self.era.clone(),
static_files: self.static_files,
rocksdb: self.rocksdb,
storage: self.storage,
}
}

View File

@@ -75,7 +75,7 @@ where
// Check where account history indices are stored
#[cfg(all(unix, feature = "rocksdb"))]
if provider.cached_storage_settings().account_history_in_rocksdb {
if provider.cached_storage_settings().storage_v2 {
return self.prune_rocksdb(provider, input, range, range_end);
}
@@ -405,9 +405,7 @@ mod tests {
let segment = AccountHistory::new(prune_mode);
let provider = db.factory.database_provider_rw().unwrap();
provider.set_storage_settings_cache(
StorageSettings::default().with_account_changesets_in_static_files(false),
);
provider.set_storage_settings_cache(StorageSettings::v1());
let result = segment.prune(&provider, input).unwrap();
limiter.increment_deleted_entries_count_by(result.pruned);
@@ -508,7 +506,11 @@ mod tests {
test_prune(1400, 3, (PruneProgress::Finished, 804));
}
/// Tests the `prune_static_files` code path. On unix with rocksdb feature, v2 storage
/// routes to `prune_rocksdb` instead, so this test only runs without rocksdb (the
/// `prune_rocksdb_path` test covers that configuration).
#[test]
#[cfg(not(all(unix, feature = "rocksdb")))]
fn prune_static_file() {
let db = TestStageDB::default();
let mut rng = generators::rng();
@@ -564,9 +566,7 @@ mod tests {
let segment = AccountHistory::new(prune_mode);
let provider = db.factory.database_provider_rw().unwrap();
provider.set_storage_settings_cache(
StorageSettings::default().with_account_changesets_in_static_files(true),
);
provider.set_storage_settings_cache(StorageSettings::v2());
let result = segment.prune(&provider, input).unwrap();
limiter.increment_deleted_entries_count_by(result.pruned);
@@ -714,11 +714,7 @@ mod tests {
PruneInput { previous_checkpoint: None, to_block, limiter: PruneLimiter::default() };
let segment = AccountHistory::new(prune_mode);
db.factory.set_storage_settings_cache(
StorageSettings::default()
.with_account_changesets_in_static_files(true)
.with_account_history_in_rocksdb(true),
);
db.factory.set_storage_settings_cache(StorageSettings::v2());
let provider = db.factory.database_provider_rw().unwrap();
let result = segment.prune(&provider, input).unwrap();
@@ -832,9 +828,7 @@ mod tests {
let segment = AccountHistory::new(prune_mode);
let provider = db.factory.database_provider_rw().unwrap();
provider.set_storage_settings_cache(
StorageSettings::default().with_account_changesets_in_static_files(false),
);
provider.set_storage_settings_cache(StorageSettings::v1());
let result = segment.prune(&provider, input).unwrap();
// Should report that there's more data
@@ -892,9 +886,7 @@ mod tests {
};
let provider2 = db.factory.database_provider_rw().unwrap();
provider2.set_storage_settings_cache(
StorageSettings::default().with_account_changesets_in_static_files(false),
);
provider2.set_storage_settings_cache(StorageSettings::v1());
let result2 = segment.prune(&provider2, input2).unwrap();
assert!(result2.progress.is_finished(), "Second run should complete");

View File

@@ -76,7 +76,7 @@ where
// Check where storage history indices are stored
#[cfg(all(unix, feature = "rocksdb"))]
if provider.cached_storage_settings().storages_history_in_rocksdb {
if provider.cached_storage_settings().storage_v2 {
return self.prune_rocksdb(provider, input, range, range_end);
}
@@ -413,9 +413,7 @@ mod tests {
let segment = StorageHistory::new(prune_mode);
let provider = db.factory.database_provider_rw().unwrap();
provider.set_storage_settings_cache(
StorageSettings::default().with_storage_changesets_in_static_files(false),
);
provider.set_storage_settings_cache(StorageSettings::v1());
let result = segment.prune(&provider, input).unwrap();
limiter.increment_deleted_entries_count_by(result.pruned);
@@ -520,7 +518,11 @@ mod tests {
test_prune(1200, 3, (PruneProgress::Finished, 202));
}
/// Tests the `prune_static_files` code path. On unix with rocksdb feature, v2 storage
/// routes to `prune_rocksdb` instead, so this test only runs without rocksdb (the
/// `prune_rocksdb_path` test covers that configuration).
#[test]
#[cfg(not(all(unix, feature = "rocksdb")))]
fn prune_static_file() {
let db = TestStageDB::default();
let mut rng = generators::rng();
@@ -577,9 +579,7 @@ mod tests {
let segment = StorageHistory::new(prune_mode);
let provider = db.factory.database_provider_rw().unwrap();
provider.set_storage_settings_cache(
StorageSettings::default().with_storage_changesets_in_static_files(true),
);
provider.set_storage_settings_cache(StorageSettings::v2());
let result = segment.prune(&provider, input).unwrap();
limiter.increment_deleted_entries_count_by(result.pruned);
@@ -739,9 +739,7 @@ mod tests {
let segment = StorageHistory::new(prune_mode);
let provider = db.factory.database_provider_rw().unwrap();
provider.set_storage_settings_cache(
StorageSettings::default().with_storage_changesets_in_static_files(false),
);
provider.set_storage_settings_cache(StorageSettings::v1());
let result = segment.prune(&provider, input).unwrap();
// Should report that there's more data
@@ -793,9 +791,7 @@ mod tests {
};
let provider2 = db.factory.database_provider_rw().unwrap();
provider2.set_storage_settings_cache(
StorageSettings::default().with_storage_changesets_in_static_files(false),
);
provider2.set_storage_settings_cache(StorageSettings::v1());
let result2 = segment.prune(&provider2, input2).unwrap();
assert!(result2.progress.is_finished(), "Second run should complete");
@@ -895,11 +891,7 @@ mod tests {
let segment = StorageHistory::new(prune_mode);
let provider = db.factory.database_provider_rw().unwrap();
provider.set_storage_settings_cache(
StorageSettings::default()
.with_storage_changesets_in_static_files(true)
.with_storages_history_in_rocksdb(true),
);
provider.set_storage_settings_cache(StorageSettings::v2());
let result = segment.prune(&provider, input).unwrap();
provider.commit().expect("commit");

View File

@@ -96,7 +96,7 @@ where
// Check where transaction hash numbers are stored
#[cfg(all(unix, feature = "rocksdb"))]
if provider.cached_storage_settings().transaction_hash_numbers_in_rocksdb {
if provider.cached_storage_settings().storage_v2 {
return self.prune_rocksdb(provider, input, start, end);
}
@@ -491,9 +491,7 @@ mod tests {
let segment = TransactionLookup::new(prune_mode);
// Enable RocksDB storage for transaction hash numbers
db.factory.set_storage_settings_cache(
StorageSettings::v1().with_transaction_hash_numbers_in_rocksdb(true),
);
db.factory.set_storage_settings_cache(StorageSettings::v2());
let provider = db.factory.database_provider_rw().unwrap();
let result = segment.prune(&provider, input).unwrap();
@@ -578,9 +576,7 @@ mod tests {
}
// Enable RocksDB storage for transaction hash numbers
db.factory.set_storage_settings_cache(
StorageSettings::v1().with_transaction_hash_numbers_in_rocksdb(true),
);
db.factory.set_storage_settings_cache(StorageSettings::v2());
let to_block: BlockNumber = 6;
let prune_mode = PruneMode::Before(to_block);

View File

@@ -467,7 +467,7 @@ where
// state is then written separately below.
provider.write_state(&state, OriginalValuesKnown::Yes, StateWriteConfig::default())?;
if provider.cached_storage_settings().use_hashed_state {
if provider.cached_storage_settings().use_hashed_state() {
let hashed_state = state.hash_state_slow::<KeccakKeyHasher>();
provider.write_hashed_state(&hashed_state.into_sorted())?;
}
@@ -1269,8 +1269,7 @@ mod tests {
// but no receipt data is written.
let factory = create_test_provider_factory();
factory
.set_storage_settings_cache(StorageSettings::v1().with_receipts_in_static_files(true));
factory.set_storage_settings_cache(StorageSettings::v2());
// Setup with block 1
let provider_rw = factory.database_provider_rw().unwrap();

View File

@@ -159,7 +159,7 @@ where
// If using hashed state as canonical, execution already writes to `HashedAccounts`,
// so this stage becomes a no-op.
if provider.cached_storage_settings().use_hashed_state {
if provider.cached_storage_settings().use_hashed_state() {
return Ok(ExecOutput::done(input.checkpoint().with_block_number(input.target())));
}

View File

@@ -89,7 +89,7 @@ where
// If use_hashed_state is enabled, execution writes directly to `HashedStorages`,
// so this stage becomes a no-op.
if provider.cached_storage_settings().use_hashed_state {
if provider.cached_storage_settings().use_hashed_state() {
return Ok(ExecOutput::done(input.checkpoint().with_block_number(input.target())));
}

View File

@@ -103,7 +103,7 @@ where
let mut range = input.next_block_range();
let first_sync = input.checkpoint().block_number == 0;
let use_rocksdb = provider.cached_storage_settings().account_history_in_rocksdb;
let use_rocksdb = provider.cached_storage_settings().storage_v2;
// On first sync we might have history coming from genesis. We clear the table since it's
// faster to rebuild from scratch.
@@ -122,7 +122,7 @@ where
info!(target: "sync::stages::index_account_history::exec", ?first_sync, ?use_rocksdb, "Collecting indices");
let collector = if provider.cached_storage_settings().account_changesets_in_static_files {
let collector = if provider.cached_storage_settings().storage_v2 {
// Use the provider-based collection that can read from static files.
collect_account_history_indices(provider, range.clone(), &self.etl_config)?
} else {
@@ -666,32 +666,43 @@ mod tests {
#[cfg(all(unix, feature = "rocksdb"))]
mod rocksdb_tests {
use super::*;
use reth_provider::RocksDBProviderFactory;
use reth_provider::{
providers::StaticFileWriter, RocksDBProviderFactory, StaticFileProviderFactory,
};
use reth_static_file_types::StaticFileSegment;
use reth_storage_api::StorageSettings;
/// Sets up v2 account test data: writes block body indices to MDBX and
/// account changesets to static files (matching realistic v2 layout).
fn setup_v2_account_data(db: &TestStageDB, block_range: std::ops::RangeInclusive<u64>) {
db.factory.set_storage_settings_cache(StorageSettings::v2());
db.commit(|tx| {
for block in block_range.clone() {
tx.put::<tables::BlockBodyIndices>(
block,
StoredBlockBodyIndices { tx_count: 3, ..Default::default() },
)?;
}
Ok(())
})
.unwrap();
let static_file_provider = db.factory.static_file_provider();
let mut writer =
static_file_provider.latest_writer(StaticFileSegment::AccountChangeSets).unwrap();
for block in block_range {
writer.append_account_changeset(vec![acc()], block).unwrap();
}
writer.commit().unwrap();
}
/// Test that when `account_history_in_rocksdb` is enabled, the stage
/// writes account history indices to `RocksDB` instead of MDBX.
#[tokio::test]
async fn execute_writes_to_rocksdb_when_enabled() {
// init
let db = TestStageDB::default();
// Enable RocksDB for account history
db.factory.set_storage_settings_cache(
StorageSettings::v1().with_account_history_in_rocksdb(true),
);
db.commit(|tx| {
for block in 0..=10 {
tx.put::<tables::BlockBodyIndices>(
block,
StoredBlockBodyIndices { tx_count: 3, ..Default::default() },
)?;
tx.put::<tables::AccountChangeSets>(block, acc())?;
}
Ok(())
})
.unwrap();
setup_v2_account_data(&db, 0..=10);
let input = ExecInput { target: Some(10), ..Default::default() };
let mut stage = IndexAccountHistoryStage::default();
@@ -721,22 +732,7 @@ mod tests {
#[tokio::test]
async fn unwind_works_when_rocksdb_enabled() {
let db = TestStageDB::default();
db.factory.set_storage_settings_cache(
StorageSettings::v1().with_account_history_in_rocksdb(true),
);
db.commit(|tx| {
for block in 0..=10 {
tx.put::<tables::BlockBodyIndices>(
block,
StoredBlockBodyIndices { tx_count: 3, ..Default::default() },
)?;
tx.put::<tables::AccountChangeSets>(block, acc())?;
}
Ok(())
})
.unwrap();
setup_v2_account_data(&db, 0..=10);
let input = ExecInput { target: Some(10), ..Default::default() };
let mut stage = IndexAccountHistoryStage::default();
@@ -772,22 +768,7 @@ mod tests {
#[tokio::test]
async fn execute_incremental_sync() {
let db = TestStageDB::default();
db.factory.set_storage_settings_cache(
StorageSettings::v1().with_account_history_in_rocksdb(true),
);
db.commit(|tx| {
for block in 0..=5 {
tx.put::<tables::BlockBodyIndices>(
block,
StoredBlockBodyIndices { tx_count: 3, ..Default::default() },
)?;
tx.put::<tables::AccountChangeSets>(block, acc())?;
}
Ok(())
})
.unwrap();
setup_v2_account_data(&db, 0..=10);
let input = ExecInput { target: Some(5), ..Default::default() };
let mut stage = IndexAccountHistoryStage::default();
@@ -802,18 +783,6 @@ mod tests {
let blocks: Vec<u64> = result.unwrap().iter().collect();
assert_eq!(blocks, (0..=5).collect::<Vec<_>>());
db.commit(|tx| {
for block in 6..=10 {
tx.put::<tables::BlockBodyIndices>(
block,
StoredBlockBodyIndices { tx_count: 3, ..Default::default() },
)?;
tx.put::<tables::AccountChangeSets>(block, acc())?;
}
Ok(())
})
.unwrap();
let input = ExecInput { target: Some(10), checkpoint: Some(StageCheckpoint::new(5)) };
let provider = db.factory.database_provider_rw().unwrap();
let out = stage.execute(&provider, input).unwrap();

View File

@@ -107,7 +107,7 @@ where
let mut range = input.next_block_range();
let first_sync = input.checkpoint().block_number == 0;
let use_rocksdb = provider.cached_storage_settings().storages_history_in_rocksdb;
let use_rocksdb = provider.cached_storage_settings().storage_v2;
// On first sync we might have history coming from genesis. We clear the table since it's
// faster to rebuild from scratch.
@@ -125,7 +125,7 @@ where
}
info!(target: "sync::stages::index_storage_history::exec", ?first_sync, ?use_rocksdb, "Collecting indices");
let collector = if provider.cached_storage_settings().storage_changesets_in_static_files {
let collector = if provider.cached_storage_settings().storage_v2 {
collect_storage_history_indices(provider, range.clone(), &self.etl_config)?
} else {
collect_history_indices::<_, tables::StorageChangeSets, tables::StoragesHistory, _>(
@@ -694,33 +694,51 @@ mod tests {
#[cfg(all(unix, feature = "rocksdb"))]
mod rocksdb_tests {
use super::*;
use reth_provider::RocksDBProviderFactory;
use reth_db_api::models::StorageBeforeTx;
use reth_provider::{providers::StaticFileWriter, RocksDBProviderFactory};
use reth_static_file_types::StaticFileSegment;
use reth_storage_api::StorageSettings;
/// Sets up v2 storage test data: writes block body indices to MDBX and
/// storage changesets to static files (matching realistic v2 layout).
fn setup_v2_storage_data(db: &TestStageDB, block_range: std::ops::RangeInclusive<u64>) {
db.factory.set_storage_settings_cache(StorageSettings::v2());
db.commit(|tx| {
for block in block_range.clone() {
tx.put::<tables::BlockBodyIndices>(
block,
StoredBlockBodyIndices { tx_count: 3, ..Default::default() },
)?;
}
Ok(())
})
.unwrap();
let static_file_provider = db.factory.static_file_provider();
let mut writer =
static_file_provider.latest_writer(StaticFileSegment::StorageChangeSets).unwrap();
for block in block_range {
writer
.append_storage_changeset(
vec![StorageBeforeTx {
address: ADDRESS,
key: STORAGE_KEY,
value: U256::ZERO,
}],
block,
)
.unwrap();
}
writer.commit().unwrap();
}
/// Test that when `storages_history_in_rocksdb` is enabled, the stage
/// writes storage history indices to `RocksDB` instead of MDBX.
#[tokio::test]
async fn execute_writes_to_rocksdb_when_enabled() {
let db = TestStageDB::default();
db.factory.set_storage_settings_cache(
StorageSettings::v1().with_storages_history_in_rocksdb(true),
);
db.commit(|tx| {
for block in 0..=10 {
tx.put::<tables::BlockBodyIndices>(
block,
StoredBlockBodyIndices { tx_count: 3, ..Default::default() },
)?;
tx.put::<tables::StorageChangeSets>(
block_number_address(block),
storage(STORAGE_KEY),
)?;
}
Ok(())
})
.unwrap();
setup_v2_storage_data(&db, 0..=10);
let input = ExecInput { target: Some(10), ..Default::default() };
let mut stage = IndexStorageHistoryStage::default();
@@ -748,25 +766,7 @@ mod tests {
#[tokio::test]
async fn unwind_works_when_rocksdb_enabled() {
let db = TestStageDB::default();
db.factory.set_storage_settings_cache(
StorageSettings::v1().with_storages_history_in_rocksdb(true),
);
db.commit(|tx| {
for block in 0..=10 {
tx.put::<tables::BlockBodyIndices>(
block,
StoredBlockBodyIndices { tx_count: 3, ..Default::default() },
)?;
tx.put::<tables::StorageChangeSets>(
block_number_address(block),
storage(STORAGE_KEY),
)?;
}
Ok(())
})
.unwrap();
setup_v2_storage_data(&db, 0..=10);
let input = ExecInput { target: Some(10), ..Default::default() };
let mut stage = IndexStorageHistoryStage::default();
@@ -803,25 +803,7 @@ mod tests {
#[tokio::test]
async fn unwind_to_zero_keeps_block_zero() {
let db = TestStageDB::default();
db.factory.set_storage_settings_cache(
StorageSettings::v1().with_storages_history_in_rocksdb(true),
);
db.commit(|tx| {
for block in 0..=5 {
tx.put::<tables::BlockBodyIndices>(
block,
StoredBlockBodyIndices { tx_count: 3, ..Default::default() },
)?;
tx.put::<tables::StorageChangeSets>(
block_number_address(block),
storage(STORAGE_KEY),
)?;
}
Ok(())
})
.unwrap();
setup_v2_storage_data(&db, 0..=5);
let input = ExecInput { target: Some(5), ..Default::default() };
let mut stage = IndexStorageHistoryStage::default();
@@ -852,25 +834,7 @@ mod tests {
#[tokio::test]
async fn execute_incremental_sync() {
let db = TestStageDB::default();
db.factory.set_storage_settings_cache(
StorageSettings::v1().with_storages_history_in_rocksdb(true),
);
db.commit(|tx| {
for block in 0..=5 {
tx.put::<tables::BlockBodyIndices>(
block,
StoredBlockBodyIndices { tx_count: 3, ..Default::default() },
)?;
tx.put::<tables::StorageChangeSets>(
block_number_address(block),
storage(STORAGE_KEY),
)?;
}
Ok(())
})
.unwrap();
setup_v2_storage_data(&db, 0..=10);
let input = ExecInput { target: Some(5), ..Default::default() };
let mut stage = IndexStorageHistoryStage::default();
@@ -885,21 +849,6 @@ mod tests {
let blocks: Vec<u64> = result.unwrap().iter().collect();
assert_eq!(blocks, (0..=5).collect::<Vec<_>>());
db.commit(|tx| {
for block in 6..=10 {
tx.put::<tables::BlockBodyIndices>(
block,
StoredBlockBodyIndices { tx_count: 3, ..Default::default() },
)?;
tx.put::<tables::StorageChangeSets>(
block_number_address(block),
storage(STORAGE_KEY),
)?;
}
Ok(())
})
.unwrap();
let input = ExecInput { target: Some(10), checkpoint: Some(StageCheckpoint::new(5)) };
let provider = db.factory.database_provider_rw().unwrap();
let out = stage.execute(&provider, input).unwrap();
@@ -919,27 +868,8 @@ mod tests {
use reth_db_api::models::sharded_key::NUM_OF_INDICES_IN_SHARD;
let db = TestStageDB::default();
db.factory.set_storage_settings_cache(
StorageSettings::v1().with_storages_history_in_rocksdb(true),
);
let num_blocks = (NUM_OF_INDICES_IN_SHARD * 2 + 100) as u64;
db.commit(|tx| {
for block in 0..num_blocks {
tx.put::<tables::BlockBodyIndices>(
block,
StoredBlockBodyIndices { tx_count: 3, ..Default::default() },
)?;
tx.put::<tables::StorageChangeSets>(
block_number_address(block),
storage(STORAGE_KEY),
)?;
}
Ok(())
})
.unwrap();
setup_v2_storage_data(&db, 0..=num_blocks - 1);
let input = ExecInput { target: Some(num_blocks - 1), ..Default::default() };
let mut stage = IndexStorageHistoryStage::default();

View File

@@ -540,9 +540,7 @@ mod tests {
let mut rng = generators::rng();
let runner = SenderRecoveryTestRunner::default();
runner.db.factory.set_storage_settings_cache(
StorageSettings::v1().with_transaction_senders_in_static_files(true),
);
runner.db.factory.set_storage_settings_cache(StorageSettings::v2());
let input = ExecInput {
target: Some(target),
checkpoint: Some(StageCheckpoint::new(stage_progress)),

View File

@@ -200,7 +200,7 @@ where
}
#[cfg(all(unix, feature = "rocksdb"))]
if provider.cached_storage_settings().transaction_hash_numbers_in_rocksdb {
if provider.cached_storage_settings().storage_v2 {
provider.commit_pending_rocksdb_batches()?;
provider.rocksdb_provider().flush(&[Tables::TransactionHashNumbers.name()])?;
}
@@ -618,9 +618,7 @@ mod tests {
let runner = TransactionLookupTestRunner::default();
// Enable RocksDB for transaction hash numbers
runner.db.factory.set_storage_settings_cache(
StorageSettings::v1().with_transaction_hash_numbers_in_rocksdb(true),
);
runner.db.factory.set_storage_settings_cache(StorageSettings::v2());
let input = ExecInput {
target: Some(previous_stage),
@@ -686,9 +684,7 @@ mod tests {
let runner = TransactionLookupTestRunner::default();
// Enable RocksDB for transaction hash numbers
runner.db.factory.set_storage_settings_cache(
StorageSettings::v1().with_transaction_hash_numbers_in_rocksdb(true),
);
runner.db.factory.set_storage_settings_cache(StorageSettings::v2());
// Insert blocks with transactions
let blocks = random_block_range(

View File

@@ -79,7 +79,7 @@ fn assert_changesets_queryable(
let settings = provider.cached_storage_settings();
// Verify storage changesets
if settings.storage_changesets_in_static_files {
if settings.storage_v2 {
let static_file_provider = provider_factory.static_file_provider();
static_file_provider.initialize_index()?;
let storage_changesets =
@@ -118,7 +118,7 @@ fn assert_changesets_queryable(
}
// Verify account changesets
if settings.account_changesets_in_static_files {
if settings.storage_v2 {
let static_file_provider = provider_factory.static_file_provider();
static_file_provider.initialize_index()?;
let account_changesets =
@@ -604,7 +604,7 @@ async fn test_pipeline() -> eyre::Result<()> {
}
/// Same as [`test_pipeline`] but runs with v2 storage settings (`use_hashed_state=true`,
/// `storage_changesets_in_static_files=true`, etc.).
/// `is_v2()=true`, etc.).
///
/// In v2 mode:
/// - The execution stage writes directly to `HashedAccounts`/`HashedStorages`

View File

@@ -5,39 +5,25 @@ use serde::{Deserialize, Serialize};
/// Storage configuration settings for this node.
///
/// Controls whether this node uses v2 storage layout (static files + `RocksDB` routing)
/// or v1/legacy layout (everything in MDBX).
///
/// These should be set during `init_genesis` or `init_db` depending on whether we want dictate
/// behaviour of new or old nodes respectively.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize, Compact)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Compact, Serialize, Deserialize)]
#[cfg_attr(any(test, feature = "arbitrary"), derive(arbitrary::Arbitrary))]
#[add_arbitrary_tests(compact)]
pub struct StorageSettings {
/// Whether this node always writes receipts to static files.
/// Whether this node uses v2 storage layout.
///
/// If this is set to FALSE AND receipt pruning IS ENABLED, all receipts should be written to DB. Otherwise, they should be written to static files. This ensures that older nodes do not need to migrate their current DB tables to static files. For more, read: <https://github.com/paradigmxyz/reth/issues/18890#issuecomment-3457760097>
#[serde(default)]
pub receipts_in_static_files: bool,
/// Whether this node always writes transaction senders to static files.
#[serde(default)]
pub transaction_senders_in_static_files: bool,
/// Whether `StoragesHistory` is stored in `RocksDB`.
#[serde(default)]
pub storages_history_in_rocksdb: bool,
/// Whether `TransactionHashNumbers` is stored in `RocksDB`.
#[serde(default)]
pub transaction_hash_numbers_in_rocksdb: bool,
/// Whether `AccountsHistory` is stored in `RocksDB`.
#[serde(default)]
pub account_history_in_rocksdb: bool,
/// Whether this node should read and write account changesets from static files.
#[serde(default)]
pub account_changesets_in_static_files: bool,
/// Whether this node should read and write storage changesets from static files.
#[serde(default)]
pub storage_changesets_in_static_files: bool,
/// Whether to use hashed state tables (`HashedAccounts`/`HashedStorages`) as the canonical
/// state representation instead of plain state tables.
#[serde(default)]
pub use_hashed_state: bool,
/// When `true`, enables all v2 storage features:
/// - Receipts and transaction senders in static files
/// - History indices in `RocksDB` (accounts, storages, transaction hashes)
/// - Account and storage changesets in static files
/// - Hashed state tables as canonical state representation
///
/// When `false`, uses v1/legacy layout (everything in MDBX).
pub storage_v2: bool,
}
impl StorageSettings {
@@ -62,159 +48,58 @@ impl StorageSettings {
/// - Receipts and transaction senders in static files
/// - History indices in `RocksDB` (storages, accounts, transaction hashes)
/// - Account and storage changesets in static files
/// - Hashed state as canonical state representation
///
/// Use this when the `--storage.v2` CLI flag is set.
pub const fn v2() -> Self {
Self {
receipts_in_static_files: true,
transaction_senders_in_static_files: true,
account_changesets_in_static_files: true,
storage_changesets_in_static_files: true,
storages_history_in_rocksdb: true,
transaction_hash_numbers_in_rocksdb: true,
account_history_in_rocksdb: true,
use_hashed_state: true,
}
Self { storage_v2: true }
}
/// Creates `StorageSettings` for v1/legacy nodes.
///
/// This explicitly sets `receipts_in_static_files` and `transaction_senders_in_static_files` to
/// `false`, ensuring older nodes continue writing receipts and transaction senders to the
/// database when receipt pruning is enabled.
/// This keeps all data in MDBX, matching the original storage layout.
pub const fn v1() -> Self {
Self {
receipts_in_static_files: false,
transaction_senders_in_static_files: false,
storages_history_in_rocksdb: false,
transaction_hash_numbers_in_rocksdb: false,
account_history_in_rocksdb: false,
account_changesets_in_static_files: false,
storage_changesets_in_static_files: false,
use_hashed_state: false,
}
Self { storage_v2: false }
}
/// Sets the `receipts_in_static_files` flag to the provided value.
pub const fn with_receipts_in_static_files(mut self, value: bool) -> Self {
self.receipts_in_static_files = value;
self
/// Returns `true` if this node uses v2 storage layout.
pub const fn is_v2(&self) -> bool {
self.storage_v2
}
/// Sets the `transaction_senders_in_static_files` flag to the provided value.
pub const fn with_transaction_senders_in_static_files(mut self, value: bool) -> Self {
self.transaction_senders_in_static_files = value;
self
/// Whether receipts are stored in static files.
pub const fn receipts_in_static_files(&self) -> bool {
self.storage_v2
}
/// Sets the `storages_history_in_rocksdb` flag to the provided value.
pub const fn with_storages_history_in_rocksdb(mut self, value: bool) -> Self {
self.storages_history_in_rocksdb = value;
self
/// Whether transaction senders are stored in static files.
pub const fn transaction_senders_in_static_files(&self) -> bool {
self.storage_v2
}
/// Sets the `transaction_hash_numbers_in_rocksdb` flag to the provided value.
pub const fn with_transaction_hash_numbers_in_rocksdb(mut self, value: bool) -> Self {
self.transaction_hash_numbers_in_rocksdb = value;
self
/// Whether storages history is stored in `RocksDB`.
pub const fn storages_history_in_rocksdb(&self) -> bool {
self.storage_v2
}
/// Sets the `account_history_in_rocksdb` flag to the provided value.
pub const fn with_account_history_in_rocksdb(mut self, value: bool) -> Self {
self.account_history_in_rocksdb = value;
self
/// Whether transaction hash numbers are stored in `RocksDB`.
pub const fn transaction_hash_numbers_in_rocksdb(&self) -> bool {
self.storage_v2
}
/// Sets the `account_changesets_in_static_files` flag to the provided value.
pub const fn with_account_changesets_in_static_files(mut self, value: bool) -> Self {
self.account_changesets_in_static_files = value;
self
/// Whether account history is stored in `RocksDB`.
pub const fn account_history_in_rocksdb(&self) -> bool {
self.storage_v2
}
/// Sets the `storage_changesets_in_static_files` flag to the provided value.
pub const fn with_storage_changesets_in_static_files(mut self, value: bool) -> Self {
self.storage_changesets_in_static_files = value;
self
}
/// Sets the `use_hashed_state` flag to the provided value.
pub const fn with_use_hashed_state(mut self, value: bool) -> Self {
self.use_hashed_state = value;
self
}
/// Sets `receipts_in_static_files` if `value` is `Some`.
pub const fn with_receipts_in_static_files_opt(mut self, value: Option<bool>) -> Self {
if let Some(v) = value {
self.receipts_in_static_files = v;
}
self
}
/// Sets `transaction_senders_in_static_files` if `value` is `Some`.
pub const fn with_transaction_senders_in_static_files_opt(
mut self,
value: Option<bool>,
) -> Self {
if let Some(v) = value {
self.transaction_senders_in_static_files = v;
}
self
}
/// Sets `account_changesets_in_static_files` if `value` is `Some`.
pub const fn with_account_changesets_in_static_files_opt(
mut self,
value: Option<bool>,
) -> Self {
if let Some(v) = value {
self.account_changesets_in_static_files = v;
}
self
}
/// Sets `storage_changesets_in_static_files` if `value` is `Some`.
pub const fn with_storage_changesets_in_static_files_opt(
mut self,
value: Option<bool>,
) -> Self {
if let Some(v) = value {
self.storage_changesets_in_static_files = v;
}
self
}
/// Sets `transaction_hash_numbers_in_rocksdb` if `value` is `Some`.
pub const fn with_transaction_hash_numbers_in_rocksdb_opt(
mut self,
value: Option<bool>,
) -> Self {
if let Some(v) = value {
self.transaction_hash_numbers_in_rocksdb = v;
}
self
}
/// Sets `storages_history_in_rocksdb` if `value` is `Some`.
pub const fn with_storages_history_in_rocksdb_opt(mut self, value: Option<bool>) -> Self {
if let Some(v) = value {
self.storages_history_in_rocksdb = v;
}
self
}
/// Sets `account_history_in_rocksdb` if `value` is `Some`.
pub const fn with_account_history_in_rocksdb_opt(mut self, value: Option<bool>) -> Self {
if let Some(v) = value {
self.account_history_in_rocksdb = v;
}
self
/// Whether to use hashed state tables (`HashedAccounts`/`HashedStorages`) as the canonical
/// state representation instead of plain state tables. Implied by v2 storage layout.
pub const fn use_hashed_state(&self) -> bool {
self.storage_v2
}
/// Returns `true` if any tables are configured to be stored in `RocksDB`.
pub const fn any_in_rocksdb(&self) -> bool {
self.transaction_hash_numbers_in_rocksdb ||
self.account_history_in_rocksdb ||
self.storages_history_in_rocksdb
self.storage_v2
}
}

View File

@@ -214,13 +214,13 @@ where
// not the genesis block number. This would cause increment_block(N) to fail.
let static_file_provider = provider_rw.static_file_provider();
if genesis_block_number > 0 {
if genesis_storage_settings.account_changesets_in_static_files {
if genesis_storage_settings.storage_v2 {
static_file_provider
.get_writer(genesis_block_number, StaticFileSegment::AccountChangeSets)?
.user_header_mut()
.set_expected_block_start(genesis_block_number);
}
if genesis_storage_settings.storage_changesets_in_static_files {
if genesis_storage_settings.storage_v2 {
static_file_provider
.get_writer(genesis_block_number, StaticFileSegment::StorageChangeSets)?
.user_header_mut()
@@ -259,7 +259,7 @@ where
.user_header_mut()
.set_block_range(genesis_block_number, genesis_block_number);
if genesis_storage_settings.transaction_senders_in_static_files {
if genesis_storage_settings.storage_v2 {
static_file_provider
.get_writer(genesis_block_number, StaticFileSegment::TransactionSenders)?
.user_header_mut()
@@ -1052,7 +1052,7 @@ mod tests {
)
};
let (accounts, storages) = if settings.account_history_in_rocksdb {
let (accounts, storages) = if settings.storage_v2 {
collect_rocksdb(&rocksdb)
} else {
collect_from_mdbx(&factory)
@@ -1075,10 +1075,7 @@ mod tests {
init_genesis_with_settings(&factory, StorageSettings::v1()).unwrap();
// Request different settings - should warn but succeed
let result = init_genesis_with_settings(
&factory,
StorageSettings::v1().with_receipts_in_static_files(true),
);
let result = init_genesis_with_settings(&factory, StorageSettings::v2());
// Should succeed (warning is logged, not an error)
assert!(result.is_ok());
@@ -1087,7 +1084,7 @@ mod tests {
#[test]
fn allow_same_storage_settings() {
let factory = create_test_provider_factory_with_chain_spec(MAINNET.clone());
let settings = StorageSettings::v1().with_receipts_in_static_files(true);
let settings = StorageSettings::v2();
init_genesis_with_settings(&factory, settings).unwrap();
let result = init_genesis_with_settings(&factory, settings);

View File

@@ -162,7 +162,7 @@ impl<'a> EitherWriter<'a, (), ()> {
P: DBProvider + NodePrimitivesProvider + StorageSettingsCache + StaticFileProviderFactory,
P::Tx: DbTxMut,
{
if provider.cached_storage_settings().account_changesets_in_static_files {
if provider.cached_storage_settings().storage_v2 {
Ok(EitherWriter::StaticFile(
provider
.get_static_file_writer(block_number, StaticFileSegment::AccountChangeSets)?,
@@ -183,7 +183,7 @@ impl<'a> EitherWriter<'a, (), ()> {
P: DBProvider + NodePrimitivesProvider + StorageSettingsCache + StaticFileProviderFactory,
P::Tx: DbTxMut,
{
if provider.cached_storage_settings().storage_changesets_in_static_files {
if provider.cached_storage_settings().storage_v2 {
Ok(EitherWriter::StaticFile(
provider
.get_static_file_writer(block_number, StaticFileSegment::StorageChangeSets)?,
@@ -206,7 +206,7 @@ impl<'a> EitherWriter<'a, (), ()> {
pub fn receipts_destination<P: DBProvider + StorageSettingsCache>(
provider: &P,
) -> EitherWriterDestination {
let receipts_in_static_files = provider.cached_storage_settings().receipts_in_static_files;
let receipts_in_static_files = provider.cached_storage_settings().storage_v2;
let prune_modes = provider.prune_modes_ref();
if !receipts_in_static_files && prune_modes.has_receipts_pruning() ||
@@ -225,7 +225,7 @@ impl<'a> EitherWriter<'a, (), ()> {
pub fn account_changesets_destination<P: DBProvider + StorageSettingsCache>(
provider: &P,
) -> EitherWriterDestination {
if provider.cached_storage_settings().account_changesets_in_static_files {
if provider.cached_storage_settings().storage_v2 {
EitherWriterDestination::StaticFile
} else {
EitherWriterDestination::Database
@@ -238,7 +238,7 @@ impl<'a> EitherWriter<'a, (), ()> {
pub fn storage_changesets_destination<P: DBProvider + StorageSettingsCache>(
provider: &P,
) -> EitherWriterDestination {
if provider.cached_storage_settings().storage_changesets_in_static_files {
if provider.cached_storage_settings().storage_v2 {
EitherWriterDestination::StaticFile
} else {
EitherWriterDestination::Database
@@ -255,7 +255,7 @@ impl<'a> EitherWriter<'a, (), ()> {
P::Tx: DbTxMut,
{
#[cfg(all(unix, feature = "rocksdb"))]
if provider.cached_storage_settings().storages_history_in_rocksdb {
if provider.cached_storage_settings().storage_v2 {
return Ok(EitherWriter::RocksDB(_rocksdb_batch));
}
@@ -272,7 +272,7 @@ impl<'a> EitherWriter<'a, (), ()> {
P::Tx: DbTxMut,
{
#[cfg(all(unix, feature = "rocksdb"))]
if provider.cached_storage_settings().transaction_hash_numbers_in_rocksdb {
if provider.cached_storage_settings().storage_v2 {
return Ok(EitherWriter::RocksDB(_rocksdb_batch));
}
@@ -291,7 +291,7 @@ impl<'a> EitherWriter<'a, (), ()> {
P::Tx: DbTxMut,
{
#[cfg(all(unix, feature = "rocksdb"))]
if provider.cached_storage_settings().account_history_in_rocksdb {
if provider.cached_storage_settings().storage_v2 {
return Ok(EitherWriter::RocksDB(_rocksdb_batch));
}
@@ -764,7 +764,7 @@ impl<'a> EitherReader<'a, (), ()> {
P::Tx: DbTx,
{
#[cfg(all(unix, feature = "rocksdb"))]
if provider.cached_storage_settings().storages_history_in_rocksdb {
if provider.cached_storage_settings().storage_v2 {
return Ok(EitherReader::RocksDB(
_rocksdb_tx.expect("storages_history_in_rocksdb requires rocksdb tx"),
));
@@ -786,7 +786,7 @@ impl<'a> EitherReader<'a, (), ()> {
P::Tx: DbTx,
{
#[cfg(all(unix, feature = "rocksdb"))]
if provider.cached_storage_settings().transaction_hash_numbers_in_rocksdb {
if provider.cached_storage_settings().storage_v2 {
return Ok(EitherReader::RocksDB(
_rocksdb_tx.expect("transaction_hash_numbers_in_rocksdb requires rocksdb tx"),
));
@@ -808,7 +808,7 @@ impl<'a> EitherReader<'a, (), ()> {
P::Tx: DbTx,
{
#[cfg(all(unix, feature = "rocksdb"))]
if provider.cached_storage_settings().account_history_in_rocksdb {
if provider.cached_storage_settings().storage_v2 {
return Ok(EitherReader::RocksDB(
_rocksdb_tx.expect("account_history_in_rocksdb requires rocksdb tx"),
));
@@ -1046,7 +1046,7 @@ impl EitherWriterDestination {
P: StorageSettingsCache,
{
// Write senders to static files only if they're explicitly enabled
if provider.cached_storage_settings().transaction_senders_in_static_files {
if provider.cached_storage_settings().storage_v2 {
Self::StaticFile
} else {
Self::Database
@@ -1059,7 +1059,7 @@ impl EitherWriterDestination {
P: StorageSettingsCache,
{
// Write account changesets to static files only if they're explicitly enabled
if provider.cached_storage_settings().account_changesets_in_static_files {
if provider.cached_storage_settings().storage_v2 {
Self::StaticFile
} else {
Self::Database
@@ -1072,7 +1072,7 @@ impl EitherWriterDestination {
P: StorageSettingsCache,
{
// Write storage changesets to static files only if they're explicitly enabled
if provider.cached_storage_settings().storage_changesets_in_static_files {
if provider.cached_storage_settings().storage_v2 {
Self::StaticFile
} else {
Self::Database
@@ -1127,9 +1127,7 @@ mod tests {
writer.commit().unwrap();
}
factory.set_storage_settings_cache(
StorageSettings::default().with_account_changesets_in_static_files(true),
);
factory.set_storage_settings_cache(StorageSettings::v2());
let provider = factory.database_provider_ro().unwrap();
@@ -1161,10 +1159,11 @@ mod tests {
];
for transaction_senders_in_static_files in [false, true] {
factory.set_storage_settings_cache(
factory.set_storage_settings_cache(if transaction_senders_in_static_files {
StorageSettings::v2()
} else {
StorageSettings::v1()
.with_transaction_senders_in_static_files(transaction_senders_in_static_files),
);
});
let provider = factory.database_provider_rw().unwrap();
let mut writer = EitherWriter::new_senders(&provider, 0).unwrap();
@@ -1234,9 +1233,7 @@ mod rocksdb_tests {
let factory = create_test_provider_factory();
// Enable RocksDB for transaction hash numbers
factory.set_storage_settings_cache(
StorageSettings::v1().with_transaction_hash_numbers_in_rocksdb(true),
);
factory.set_storage_settings_cache(StorageSettings::v2());
let hash1 = B256::from([1u8; 32]);
let hash2 = B256::from([2u8; 32]);
@@ -1278,9 +1275,7 @@ mod rocksdb_tests {
let factory = create_test_provider_factory();
// Enable RocksDB for transaction hash numbers
factory.set_storage_settings_cache(
StorageSettings::v1().with_transaction_hash_numbers_in_rocksdb(true),
);
factory.set_storage_settings_cache(StorageSettings::v2());
let hash = B256::from([1u8; 32]);
let tx_num = 100u64;
@@ -1832,9 +1827,7 @@ mod rocksdb_tests {
let factory = create_test_provider_factory();
// Enable RocksDB for transaction hash numbers
factory.set_storage_settings_cache(
StorageSettings::v1().with_transaction_hash_numbers_in_rocksdb(true),
);
factory.set_storage_settings_cache(StorageSettings::v2());
let hash1 = B256::from([1u8; 32]);
let hash2 = B256::from([2u8; 32]);
@@ -1892,9 +1885,7 @@ mod rocksdb_tests {
fn test_settings_mismatch_panics() {
let factory = create_test_provider_factory();
factory.set_storage_settings_cache(
StorageSettings::v1().with_account_history_in_rocksdb(true),
);
factory.set_storage_settings_cache(StorageSettings::v2());
let provider = factory.database_provider_ro().unwrap();
let _ = EitherReader::<(), ()>::new_accounts_history(&provider, None);

View File

@@ -1313,7 +1313,7 @@ impl<N: ProviderNodeTypes> StorageChangeSetReader for ConsistentProvider<N> {
&self,
block_number: BlockNumber,
) -> ProviderResult<Vec<(BlockNumberAddress, ChangesetEntry)>> {
let use_hashed = self.storage_provider.cached_storage_settings().use_hashed_state;
let use_hashed = self.storage_provider.cached_storage_settings().use_hashed_state();
if let Some(state) =
self.head_block.as_ref().and_then(|b| b.block_on_chain(block_number.into()))
{
@@ -1368,7 +1368,7 @@ impl<N: ProviderNodeTypes> StorageChangeSetReader for ConsistentProvider<N> {
address: Address,
storage_key: B256,
) -> ProviderResult<Option<ChangesetEntry>> {
let use_hashed = self.storage_provider.cached_storage_settings().use_hashed_state;
let use_hashed = self.storage_provider.cached_storage_settings().use_hashed_state();
if let Some(state) =
self.head_block.as_ref().and_then(|b| b.block_on_chain(block_number.into()))
{
@@ -1421,7 +1421,7 @@ impl<N: ProviderNodeTypes> StorageChangeSetReader for ConsistentProvider<N> {
let database_start = range.start;
let mut database_end = range.end;
let use_hashed = self.storage_provider.cached_storage_settings().use_hashed_state;
let use_hashed = self.storage_provider.cached_storage_settings().use_hashed_state();
if let Some(head_block) = &self.head_block {
database_end = head_block.anchor().number;

View File

@@ -559,7 +559,7 @@ impl<TX: DbTx + DbTxMut + 'static, N: NodeTypesForProvider> DatabaseProvider<TX,
#[cfg(all(unix, feature = "rocksdb"))]
let rocksdb_ctx = self.rocksdb_write_ctx(first_number);
#[cfg(all(unix, feature = "rocksdb"))]
let rocksdb_enabled = rocksdb_ctx.storage_settings.any_in_rocksdb();
let rocksdb_enabled = rocksdb_ctx.storage_settings.storage_v2;
let mut sf_result = None;
#[cfg(all(unix, feature = "rocksdb"))]
@@ -595,7 +595,7 @@ impl<TX: DbTx + DbTxMut + 'static, N: NodeTypesForProvider> DatabaseProvider<TX,
let mdbx_start = Instant::now();
// Collect all transaction hashes across all blocks, sort them, and write in batch
if !self.cached_storage_settings().transaction_hash_numbers_in_rocksdb &&
if !self.cached_storage_settings().storage_v2 &&
self.prune_modes.transaction_lookup.is_none_or(|m| !m.is_full())
{
let start = Instant::now();
@@ -1396,7 +1396,7 @@ impl<TX: DbTxMut + DbTx + 'static, N: NodeTypes> DatabaseProvider<TX, N> {
impl<TX: DbTx, N: NodeTypes> AccountReader for DatabaseProvider<TX, N> {
fn basic_account(&self, address: &Address) -> ProviderResult<Option<Account>> {
if self.cached_storage_settings().use_hashed_state {
if self.cached_storage_settings().use_hashed_state() {
let hashed_address = keccak256(address);
Ok(self.tx.get_by_encoded_key::<tables::HashedAccounts>(&hashed_address)?)
} else {
@@ -1419,7 +1419,7 @@ impl<TX: DbTx + 'static, N: NodeTypes> AccountExtReader for DatabaseProvider<TX,
&self,
iter: impl IntoIterator<Item = Address>,
) -> ProviderResult<Vec<(Address, Option<Account>)>> {
if self.cached_storage_settings().use_hashed_state {
if self.cached_storage_settings().use_hashed_state() {
let mut hashed_accounts = self.tx.cursor_read::<tables::HashedAccounts>()?;
Ok(iter
.into_iter()
@@ -1448,7 +1448,7 @@ impl<TX: DbTx + 'static, N: NodeTypes> AccountExtReader for DatabaseProvider<TX,
.get_highest_static_file_block(StaticFileSegment::AccountChangeSets);
if let Some(highest) = highest_static_block &&
self.cached_storage_settings().account_changesets_in_static_files
self.cached_storage_settings().storage_v2
{
let start = *range.start();
let static_end = (*range.end()).min(highest);
@@ -1489,7 +1489,7 @@ impl<TX: DbTx, N: NodeTypes> StorageChangeSetReader for DatabaseProvider<TX, N>
&self,
block_number: BlockNumber,
) -> ProviderResult<Vec<(BlockNumberAddress, ChangesetEntry)>> {
if self.cached_storage_settings().storage_changesets_in_static_files {
if self.cached_storage_settings().storage_v2 {
self.static_file_provider.storage_changeset(block_number)
} else {
let range = block_number..=block_number;
@@ -1517,7 +1517,7 @@ impl<TX: DbTx, N: NodeTypes> StorageChangeSetReader for DatabaseProvider<TX, N>
address: Address,
storage_key: B256,
) -> ProviderResult<Option<ChangesetEntry>> {
if self.cached_storage_settings().storage_changesets_in_static_files {
if self.cached_storage_settings().storage_v2 {
self.static_file_provider.get_storage_before_block(block_number, address, storage_key)
} else {
Ok(self
@@ -1536,7 +1536,7 @@ impl<TX: DbTx, N: NodeTypes> StorageChangeSetReader for DatabaseProvider<TX, N>
&self,
range: impl RangeBounds<BlockNumber>,
) -> ProviderResult<Vec<(BlockNumberAddress, ChangesetEntry)>> {
if self.cached_storage_settings().storage_changesets_in_static_files {
if self.cached_storage_settings().storage_v2 {
self.static_file_provider.storage_changesets_range(range)
} else {
self.tx
@@ -1557,7 +1557,7 @@ impl<TX: DbTx, N: NodeTypes> StorageChangeSetReader for DatabaseProvider<TX, N>
}
fn storage_changeset_count(&self) -> ProviderResult<usize> {
if self.cached_storage_settings().storage_changesets_in_static_files {
if self.cached_storage_settings().storage_v2 {
self.static_file_provider.storage_changeset_count()
} else {
Ok(self.tx.entries::<tables::StorageChangeSets>()?)
@@ -1570,7 +1570,7 @@ impl<TX: DbTx, N: NodeTypes> ChangeSetReader for DatabaseProvider<TX, N> {
&self,
block_number: BlockNumber,
) -> ProviderResult<Vec<AccountBeforeTx>> {
if self.cached_storage_settings().account_changesets_in_static_files {
if self.cached_storage_settings().storage_v2 {
let static_changesets =
self.static_file_provider.account_block_changeset(block_number)?;
Ok(static_changesets)
@@ -1592,7 +1592,7 @@ impl<TX: DbTx, N: NodeTypes> ChangeSetReader for DatabaseProvider<TX, N> {
block_number: BlockNumber,
address: Address,
) -> ProviderResult<Option<AccountBeforeTx>> {
if self.cached_storage_settings().account_changesets_in_static_files {
if self.cached_storage_settings().storage_v2 {
Ok(self.static_file_provider.get_account_before_block(block_number, address)?)
} else {
self.tx
@@ -1608,7 +1608,7 @@ impl<TX: DbTx, N: NodeTypes> ChangeSetReader for DatabaseProvider<TX, N> {
&self,
range: impl core::ops::RangeBounds<BlockNumber>,
) -> ProviderResult<Vec<(BlockNumber, AccountBeforeTx)>> {
if self.cached_storage_settings().account_changesets_in_static_files {
if self.cached_storage_settings().storage_v2 {
self.static_file_provider.account_changesets_range(range)
} else {
self.tx
@@ -1622,7 +1622,7 @@ impl<TX: DbTx, N: NodeTypes> ChangeSetReader for DatabaseProvider<TX, N> {
fn account_changeset_count(&self) -> ProviderResult<usize> {
// check if account changesets are in static files, otherwise just count the changeset
// entries in the DB
if self.cached_storage_settings().account_changesets_in_static_files {
if self.cached_storage_settings().storage_v2 {
self.static_file_provider.account_changeset_count()
} else {
Ok(self.tx.entries::<tables::AccountChangeSets>()?)
@@ -2243,7 +2243,7 @@ impl<TX: DbTx + 'static, N: NodeTypes> StorageReader for DatabaseProvider<TX, N>
&self,
addresses_with_keys: impl IntoIterator<Item = (Address, impl IntoIterator<Item = B256>)>,
) -> ProviderResult<Vec<(Address, Vec<StorageEntry>)>> {
if self.cached_storage_settings().use_hashed_state {
if self.cached_storage_settings().use_hashed_state() {
let mut hashed_storage = self.tx.cursor_dup_read::<tables::HashedStorages>()?;
addresses_with_keys
@@ -2290,7 +2290,7 @@ impl<TX: DbTx + 'static, N: NodeTypes> StorageReader for DatabaseProvider<TX, N>
&self,
range: RangeInclusive<BlockNumber>,
) -> ProviderResult<BTreeMap<Address, BTreeSet<B256>>> {
if self.cached_storage_settings().storage_changesets_in_static_files {
if self.cached_storage_settings().storage_v2 {
self.storage_changesets_range(range)?.into_iter().try_fold(
BTreeMap::new(),
|mut accounts: BTreeMap<Address, BTreeSet<B256>>, entry| {
@@ -2320,7 +2320,7 @@ impl<TX: DbTx + 'static, N: NodeTypes> StorageReader for DatabaseProvider<TX, N>
&self,
range: RangeInclusive<BlockNumber>,
) -> ProviderResult<BTreeMap<(Address, B256), Vec<u64>>> {
if self.cached_storage_settings().storage_changesets_in_static_files {
if self.cached_storage_settings().storage_v2 {
self.storage_changesets_range(range)?.into_iter().try_fold(
BTreeMap::new(),
|mut storages: BTreeMap<(Address, B256), Vec<u64>>, (index, storage)| {
@@ -2470,7 +2470,7 @@ impl<TX: DbTxMut + DbTx + 'static, N: NodeTypesForProvider> StateWriter
first_block: BlockNumber,
config: StateWriteConfig,
) -> ProviderResult<()> {
let use_hashed_state = self.cached_storage_settings().use_hashed_state;
let use_hashed_state = self.cached_storage_settings().use_hashed_state();
// Write storage changes
if config.write_storage_changesets {
@@ -2575,7 +2575,7 @@ impl<TX: DbTxMut + DbTx + 'static, N: NodeTypesForProvider> StateWriter
// When use_hashed_state is enabled, skip plain state writes for accounts and storage.
// The hashed state is already written by the separate `write_hashed_state()` call.
// Bytecode writes remain unconditional since Bytecodes is not a plain/hashed table.
if !self.cached_storage_settings().use_hashed_state {
if !self.cached_storage_settings().use_hashed_state() {
// Write new account state
tracing::trace!(len = changes.accounts.len(), "Writing new account state");
let mut accounts_cursor = self.tx_ref().cursor_write::<tables::PlainAccountState>()?;
@@ -2709,8 +2709,7 @@ impl<TX: DbTxMut + DbTx + 'static, N: NodeTypesForProvider> StateWriter
block_bodies.first().expect("already checked if there are blocks").first_tx_num();
let storage_range = BlockNumberAddress::range(range.clone());
let storage_changeset = if self.cached_storage_settings().storage_changesets_in_static_files
{
let storage_changeset = if self.cached_storage_settings().storage_v2 {
let changesets = self.storage_changesets_range(range.clone())?;
let mut changeset_writer =
self.static_file_provider.latest_writer(StaticFileSegment::StorageChangeSets)?;
@@ -2724,8 +2723,7 @@ impl<TX: DbTxMut + DbTx + 'static, N: NodeTypesForProvider> StateWriter
})
.collect()
};
let account_changeset = if self.cached_storage_settings().account_changesets_in_static_files
{
let account_changeset = if self.cached_storage_settings().storage_v2 {
let changesets = self.account_changesets_range(range)?;
let mut changeset_writer =
self.static_file_provider.latest_writer(StaticFileSegment::AccountChangeSets)?;
@@ -2735,7 +2733,7 @@ impl<TX: DbTxMut + DbTx + 'static, N: NodeTypesForProvider> StateWriter
self.take::<tables::AccountChangeSets>(range)?
};
if self.cached_storage_settings().use_hashed_state {
if self.cached_storage_settings().use_hashed_state() {
let mut hashed_accounts_cursor = self.tx.cursor_write::<tables::HashedAccounts>()?;
let mut hashed_storage_cursor = self.tx.cursor_dup_write::<tables::HashedStorages>()?;
@@ -2868,7 +2866,7 @@ impl<TX: DbTxMut + DbTx + 'static, N: NodeTypesForProvider> StateWriter
let storage_changeset = if let Some(highest_block) = self
.static_file_provider
.get_highest_static_file_block(StaticFileSegment::StorageChangeSets) &&
self.cached_storage_settings().storage_changesets_in_static_files
self.cached_storage_settings().storage_v2
{
let changesets = self.storage_changesets_range(block + 1..=highest_block)?;
let mut changeset_writer =
@@ -2889,7 +2887,7 @@ impl<TX: DbTxMut + DbTx + 'static, N: NodeTypesForProvider> StateWriter
.static_file_provider
.get_highest_static_file_block(StaticFileSegment::AccountChangeSets);
let account_changeset = if let Some(highest_block) = highest_changeset_block &&
self.cached_storage_settings().account_changesets_in_static_files
self.cached_storage_settings().storage_v2
{
// TODO: add a `take` method that removes and returns the items instead of doing this
let changesets = self.account_changesets_range(block + 1..highest_block + 1)?;
@@ -2904,7 +2902,7 @@ impl<TX: DbTxMut + DbTx + 'static, N: NodeTypesForProvider> StateWriter
self.take::<tables::AccountChangeSets>(range)?
};
let (state, reverts) = if self.cached_storage_settings().use_hashed_state {
let (state, reverts) = if self.cached_storage_settings().use_hashed_state() {
let mut hashed_accounts_cursor = self.tx.cursor_write::<tables::HashedAccounts>()?;
let mut hashed_storage_cursor = self.tx.cursor_dup_write::<tables::HashedStorages>()?;
@@ -3260,7 +3258,7 @@ impl<TX: DbTxMut + DbTx + 'static, N: NodeTypes> HistoryWriter for DatabaseProvi
.collect::<Vec<_>>();
last_indices.sort_unstable_by_key(|(a, _)| *a);
if self.cached_storage_settings().account_history_in_rocksdb {
if self.cached_storage_settings().storage_v2 {
#[cfg(all(unix, feature = "rocksdb"))]
{
let batch = self.rocksdb_provider.unwind_account_history_indices(&last_indices)?;
@@ -3322,7 +3320,7 @@ impl<TX: DbTxMut + DbTx + 'static, N: NodeTypes> HistoryWriter for DatabaseProvi
.collect::<Vec<_>>();
storage_changesets.sort_by_key(|(address, key, _)| (*address, *key));
if self.cached_storage_settings().storages_history_in_rocksdb {
if self.cached_storage_settings().storage_v2 {
#[cfg(all(unix, feature = "rocksdb"))]
{
let batch =
@@ -3381,12 +3379,12 @@ impl<TX: DbTxMut + DbTx + 'static, N: NodeTypes> HistoryWriter for DatabaseProvi
#[instrument(level = "debug", target = "providers::db", skip_all)]
fn update_history_indices(&self, range: RangeInclusive<BlockNumber>) -> ProviderResult<()> {
let storage_settings = self.cached_storage_settings();
if !storage_settings.account_history_in_rocksdb {
if !storage_settings.storage_v2 {
let indices = self.changed_accounts_and_blocks_with_range(range.clone())?;
self.insert_account_history_index(indices)?;
}
if !storage_settings.storages_history_in_rocksdb {
if !storage_settings.storage_v2 {
let indices = self.changed_storages_and_blocks_with_range(range)?;
self.insert_storage_history_index(indices)?;
}
@@ -3645,7 +3643,7 @@ impl<TX: DbTxMut + DbTx + 'static, N: NodeTypesForProvider> BlockWriter
// This is necessary because with edge storage, changesets are written to static files
// whose index isn't updated until commit, making them invisible to subsequent reads
// within the same transaction.
let use_hashed = self.cached_storage_settings().use_hashed_state;
let use_hashed = self.cached_storage_settings().use_hashed_state();
let (account_transitions, storage_transitions) = {
let mut account_transitions: BTreeMap<Address, Vec<u64>> = BTreeMap::new();
let mut storage_transitions: BTreeMap<(Address, B256), Vec<u64>> = BTreeMap::new();
@@ -3681,7 +3679,7 @@ impl<TX: DbTxMut + DbTx + 'static, N: NodeTypesForProvider> BlockWriter
// Note: For MDBX we use insert_*_history_index. For RocksDB we use
// append_*_history_shard which handles read-merge-write internally.
let storage_settings = self.cached_storage_settings();
if storage_settings.account_history_in_rocksdb {
if storage_settings.storage_v2 {
#[cfg(all(unix, feature = "rocksdb"))]
self.with_rocksdb_batch(|mut batch| {
for (address, blocks) in account_transitions {
@@ -3692,7 +3690,7 @@ impl<TX: DbTxMut + DbTx + 'static, N: NodeTypesForProvider> BlockWriter
} else {
self.insert_account_history_index(account_transitions)?;
}
if storage_settings.storages_history_in_rocksdb {
if storage_settings.storage_v2 {
#[cfg(all(unix, feature = "rocksdb"))]
self.with_rocksdb_batch(|mut batch| {
for ((address, key), blocks) in storage_transitions {
@@ -4445,7 +4443,7 @@ mod tests {
// Static files mode
{
let factory = create_test_provider_factory();
let storage_settings = StorageSettings::v1().with_receipts_in_static_files(true);
let storage_settings = StorageSettings::v2();
factory.set_storage_settings_cache(storage_settings);
let factory = factory.with_prune_modes(PruneModes {
receipts: Some(PruneMode::Before(2)),
@@ -4603,7 +4601,7 @@ mod tests {
fn test_write_and_remove_state_roundtrip_legacy() {
let factory = create_test_provider_factory();
let storage_settings = StorageSettings::v1();
assert!(!storage_settings.use_hashed_state);
assert!(!storage_settings.use_hashed_state());
factory.set_storage_settings_cache(storage_settings);
let address = Address::with_last_byte(1);
@@ -4771,7 +4769,7 @@ mod tests {
fn test_unwind_storage_hashing_legacy() {
let factory = create_test_provider_factory();
let storage_settings = StorageSettings::v1();
assert!(!storage_settings.use_hashed_state);
assert!(!storage_settings.use_hashed_state());
factory.set_storage_settings_cache(storage_settings);
let address = Address::random();
@@ -5205,7 +5203,7 @@ mod tests {
fn test_write_and_remove_state_roundtrip_v2() {
let factory = create_test_provider_factory();
let storage_settings = StorageSettings::v2();
assert!(storage_settings.use_hashed_state);
assert!(storage_settings.use_hashed_state());
factory.set_storage_settings_cache(storage_settings);
let address = Address::with_last_byte(1);

View File

@@ -62,21 +62,21 @@ impl RocksDBProvider {
let mut unwind_target: Option<BlockNumber> = None;
// Heal TransactionHashNumbers if stored in RocksDB
if provider.cached_storage_settings().transaction_hash_numbers_in_rocksdb &&
if provider.cached_storage_settings().storage_v2 &&
let Some(target) = self.heal_transaction_hash_numbers(provider)?
{
unwind_target = Some(unwind_target.map_or(target, |t| t.min(target)));
}
// Heal StoragesHistory if stored in RocksDB
if provider.cached_storage_settings().storages_history_in_rocksdb &&
if provider.cached_storage_settings().storage_v2 &&
let Some(target) = self.heal_storages_history(provider)?
{
unwind_target = Some(unwind_target.map_or(target, |t| t.min(target)));
}
// Heal AccountsHistory if stored in RocksDB
if provider.cached_storage_settings().account_history_in_rocksdb &&
if provider.cached_storage_settings().storage_v2 &&
let Some(target) = self.heal_accounts_history(provider)?
{
unwind_target = Some(unwind_target.map_or(target, |t| t.min(target)));
@@ -496,19 +496,11 @@ mod tests {
#[test]
fn test_check_consistency_empty_rocksdb_no_checkpoint_is_ok() {
let temp_dir = TempDir::new().unwrap();
let rocksdb = RocksDBBuilder::new(temp_dir.path())
.with_table::<tables::TransactionHashNumbers>()
.with_table::<tables::StoragesHistory>()
.build()
.unwrap();
let rocksdb = RocksDBBuilder::new(temp_dir.path()).with_default_tables().build().unwrap();
// Create a test provider factory for MDBX
let factory = create_test_provider_factory();
factory.set_storage_settings_cache(
StorageSettings::v1()
.with_transaction_hash_numbers_in_rocksdb(true)
.with_storages_history_in_rocksdb(true),
);
factory.set_storage_settings_cache(StorageSettings::v2());
let provider = factory.database_provider_ro().unwrap();
@@ -520,16 +512,11 @@ mod tests {
#[test]
fn test_check_consistency_empty_rocksdb_with_checkpoint_is_first_run() {
let temp_dir = TempDir::new().unwrap();
let rocksdb = RocksDBBuilder::new(temp_dir.path())
.with_table::<tables::TransactionHashNumbers>()
.build()
.unwrap();
let rocksdb = RocksDBBuilder::new(temp_dir.path()).with_default_tables().build().unwrap();
// Create a test provider factory for MDBX
let factory = create_test_provider_factory();
factory.set_storage_settings_cache(
StorageSettings::v1().with_transaction_hash_numbers_in_rocksdb(true),
);
factory.set_storage_settings_cache(StorageSettings::v2());
// Set a checkpoint indicating we should have processed up to block 100
{
@@ -553,15 +540,10 @@ mod tests {
#[test]
fn test_check_consistency_checkpoint_zero_with_rocksdb_data_prunes_all() {
let temp_dir = TempDir::new().unwrap();
let rocksdb = RocksDBBuilder::new(temp_dir.path())
.with_table::<tables::TransactionHashNumbers>()
.build()
.unwrap();
let rocksdb = RocksDBBuilder::new(temp_dir.path()).with_default_tables().build().unwrap();
let factory = create_test_provider_factory();
factory.set_storage_settings_cache(
StorageSettings::v1().with_transaction_hash_numbers_in_rocksdb(true),
);
factory.set_storage_settings_cache(StorageSettings::v2());
// Generate blocks with real transactions and insert them
let mut rng = generators::rng();
@@ -589,12 +571,18 @@ mod tests {
provider.commit().unwrap();
}
// Explicitly clear the TransactionLookup checkpoint to simulate crash recovery
// Explicitly clear the checkpoints to simulate crash recovery
{
let provider = factory.database_provider_rw().unwrap();
provider
.save_stage_checkpoint(StageId::TransactionLookup, StageCheckpoint::new(0))
.unwrap();
provider
.save_stage_checkpoint(StageId::IndexStorageHistory, StageCheckpoint::new(0))
.unwrap();
provider
.save_stage_checkpoint(StageId::IndexAccountHistory, StageCheckpoint::new(0))
.unwrap();
provider.commit().unwrap();
}
@@ -620,16 +608,11 @@ mod tests {
#[test]
fn test_check_consistency_storages_history_empty_with_checkpoint_is_first_run() {
let temp_dir = TempDir::new().unwrap();
let rocksdb = RocksDBBuilder::new(temp_dir.path())
.with_table::<tables::StoragesHistory>()
.build()
.unwrap();
let rocksdb = RocksDBBuilder::new(temp_dir.path()).with_default_tables().build().unwrap();
// Create a test provider factory for MDBX
let factory = create_test_provider_factory();
factory.set_storage_settings_cache(
StorageSettings::v1().with_storages_history_in_rocksdb(true),
);
factory.set_storage_settings_cache(StorageSettings::v2());
// Set a checkpoint indicating we should have processed up to block 100
{
@@ -652,10 +635,7 @@ mod tests {
#[test]
fn test_check_consistency_storages_history_has_data_no_checkpoint_prunes_data() {
let temp_dir = TempDir::new().unwrap();
let rocksdb = RocksDBBuilder::new(temp_dir.path())
.with_table::<tables::StoragesHistory>()
.build()
.unwrap();
let rocksdb = RocksDBBuilder::new(temp_dir.path()).with_default_tables().build().unwrap();
// Insert data into RocksDB
let key = StorageShardedKey::new(Address::ZERO, B256::ZERO, 50);
@@ -667,9 +647,7 @@ mod tests {
// Create a test provider factory for MDBX with NO checkpoint
let factory = create_test_provider_factory();
factory.set_storage_settings_cache(
StorageSettings::v1().with_storages_history_in_rocksdb(true),
);
factory.set_storage_settings_cache(StorageSettings::v2());
let provider = factory.database_provider_ro().unwrap();
@@ -687,15 +665,10 @@ mod tests {
#[test]
fn test_check_consistency_mdbx_behind_checkpoint_needs_unwind() {
let temp_dir = TempDir::new().unwrap();
let rocksdb = RocksDBBuilder::new(temp_dir.path())
.with_table::<tables::TransactionHashNumbers>()
.build()
.unwrap();
let rocksdb = RocksDBBuilder::new(temp_dir.path()).with_default_tables().build().unwrap();
let factory = create_test_provider_factory();
factory.set_storage_settings_cache(
StorageSettings::v1().with_transaction_hash_numbers_in_rocksdb(true),
);
factory.set_storage_settings_cache(StorageSettings::v2());
// Generate blocks with real transactions (blocks 0-2, 6 transactions total)
let mut rng = generators::rng();
@@ -729,6 +702,13 @@ mod tests {
provider
.save_stage_checkpoint(StageId::TransactionLookup, StageCheckpoint::new(10))
.unwrap();
// Reset history checkpoints so they don't interfere
provider
.save_stage_checkpoint(StageId::IndexStorageHistory, StageCheckpoint::new(0))
.unwrap();
provider
.save_stage_checkpoint(StageId::IndexAccountHistory, StageCheckpoint::new(0))
.unwrap();
provider.commit().unwrap();
}
@@ -742,16 +722,11 @@ mod tests {
#[test]
fn test_check_consistency_rocksdb_ahead_of_checkpoint_prunes_excess() {
let temp_dir = TempDir::new().unwrap();
let rocksdb = RocksDBBuilder::new(temp_dir.path())
.with_table::<tables::TransactionHashNumbers>()
.build()
.unwrap();
let rocksdb = RocksDBBuilder::new(temp_dir.path()).with_default_tables().build().unwrap();
// Create a test provider factory for MDBX
let factory = create_test_provider_factory();
factory.set_storage_settings_cache(
StorageSettings::v1().with_transaction_hash_numbers_in_rocksdb(true),
);
factory.set_storage_settings_cache(StorageSettings::v2());
// Generate blocks with real transactions:
// Blocks 0-5, each with 2 transactions = 12 total transactions (0-11)
@@ -809,6 +784,13 @@ mod tests {
provider
.save_stage_checkpoint(StageId::TransactionLookup, StageCheckpoint::new(2))
.unwrap();
// Reset history checkpoints so they don't interfere
provider
.save_stage_checkpoint(StageId::IndexStorageHistory, StageCheckpoint::new(0))
.unwrap();
provider
.save_stage_checkpoint(StageId::IndexAccountHistory, StageCheckpoint::new(0))
.unwrap();
provider.commit().unwrap();
}
@@ -843,10 +825,7 @@ mod tests {
#[test]
fn test_check_consistency_storages_history_sentinel_only_with_checkpoint_is_first_run() {
let temp_dir = TempDir::new().unwrap();
let rocksdb = RocksDBBuilder::new(temp_dir.path())
.with_table::<tables::StoragesHistory>()
.build()
.unwrap();
let rocksdb = RocksDBBuilder::new(temp_dir.path()).with_default_tables().build().unwrap();
// Insert ONLY sentinel entries (highest_block_number = u64::MAX)
// This simulates a scenario where history tracking started but no shards were completed
@@ -861,9 +840,7 @@ mod tests {
// Create a test provider factory for MDBX
let factory = create_test_provider_factory();
factory.set_storage_settings_cache(
StorageSettings::v1().with_storages_history_in_rocksdb(true),
);
factory.set_storage_settings_cache(StorageSettings::v2());
// Set a checkpoint indicating we should have processed up to block 100
{
@@ -888,10 +865,7 @@ mod tests {
use reth_db_api::models::ShardedKey;
let temp_dir = TempDir::new().unwrap();
let rocksdb = RocksDBBuilder::new(temp_dir.path())
.with_table::<tables::AccountsHistory>()
.build()
.unwrap();
let rocksdb = RocksDBBuilder::new(temp_dir.path()).with_default_tables().build().unwrap();
// Insert ONLY sentinel entries (highest_block_number = u64::MAX)
let key_sentinel_1 = ShardedKey::new(Address::ZERO, u64::MAX);
@@ -905,9 +879,7 @@ mod tests {
// Create a test provider factory for MDBX
let factory = create_test_provider_factory();
factory.set_storage_settings_cache(
StorageSettings::v1().with_account_history_in_rocksdb(true),
);
factory.set_storage_settings_cache(StorageSettings::v2());
// Set a checkpoint indicating we should have processed up to block 100
{
@@ -940,9 +912,7 @@ mod tests {
// Create a test provider factory for MDBX
let factory = create_test_provider_factory();
factory.set_storage_settings_cache(
StorageSettings::v1().with_transaction_hash_numbers_in_rocksdb(true),
);
factory.set_storage_settings_cache(StorageSettings::v2());
// Generate random blocks with unique transactions
// Block 0 (genesis) has no transactions
@@ -1046,16 +1016,11 @@ mod tests {
#[test]
fn test_check_consistency_accounts_history_empty_with_checkpoint_is_first_run() {
let temp_dir = TempDir::new().unwrap();
let rocksdb = RocksDBBuilder::new(temp_dir.path())
.with_table::<tables::AccountsHistory>()
.build()
.unwrap();
let rocksdb = RocksDBBuilder::new(temp_dir.path()).with_default_tables().build().unwrap();
// Create a test provider factory for MDBX
let factory = create_test_provider_factory();
factory.set_storage_settings_cache(
StorageSettings::v1().with_account_history_in_rocksdb(true),
);
factory.set_storage_settings_cache(StorageSettings::v2());
// Set a checkpoint indicating we should have processed up to block 100
{
@@ -1080,10 +1045,7 @@ mod tests {
use reth_db_api::models::ShardedKey;
let temp_dir = TempDir::new().unwrap();
let rocksdb = RocksDBBuilder::new(temp_dir.path())
.with_table::<tables::AccountsHistory>()
.build()
.unwrap();
let rocksdb = RocksDBBuilder::new(temp_dir.path()).with_default_tables().build().unwrap();
// Insert data into RocksDB
let key = ShardedKey::new(Address::ZERO, 50);
@@ -1095,9 +1057,7 @@ mod tests {
// Create a test provider factory for MDBX with NO checkpoint
let factory = create_test_provider_factory();
factory.set_storage_settings_cache(
StorageSettings::v1().with_account_history_in_rocksdb(true),
);
factory.set_storage_settings_cache(StorageSettings::v2());
let provider = factory.database_provider_ro().unwrap();
@@ -1120,10 +1080,7 @@ mod tests {
use reth_static_file_types::StaticFileSegment;
let temp_dir = TempDir::new().unwrap();
let rocksdb = RocksDBBuilder::new(temp_dir.path())
.with_table::<tables::AccountsHistory>()
.build()
.unwrap();
let rocksdb = RocksDBBuilder::new(temp_dir.path()).with_default_tables().build().unwrap();
// Insert some AccountsHistory entries with various highest_block_numbers
let key1 = ShardedKey::new(Address::ZERO, 50);
@@ -1143,9 +1100,7 @@ mod tests {
// Create a test provider factory for MDBX
let factory = create_test_provider_factory();
factory.set_storage_settings_cache(
StorageSettings::v1().with_account_history_in_rocksdb(true),
);
factory.set_storage_settings_cache(StorageSettings::v2());
// Write account changesets to static files for blocks 0-100
{
@@ -1224,17 +1179,10 @@ mod tests {
const CHECKPOINT_BLOCK: u64 = 5_000;
let temp_dir = TempDir::new().unwrap();
let rocksdb = RocksDBBuilder::new(temp_dir.path())
.with_table::<tables::StoragesHistory>()
.build()
.unwrap();
let rocksdb = RocksDBBuilder::new(temp_dir.path()).with_default_tables().build().unwrap();
let factory = create_test_provider_factory();
factory.set_storage_settings_cache(
StorageSettings::v1()
.with_storages_history_in_rocksdb(true)
.with_storage_changesets_in_static_files(true),
);
factory.set_storage_settings_cache(StorageSettings::v2());
// Helper to generate address from block number (reuses stack arrays)
#[inline]
@@ -1348,17 +1296,10 @@ mod tests {
const SF_TIP: u64 = 200;
let temp_dir = TempDir::new().unwrap();
let rocksdb = RocksDBBuilder::new(temp_dir.path())
.with_table::<tables::StoragesHistory>()
.build()
.unwrap();
let rocksdb = RocksDBBuilder::new(temp_dir.path()).with_default_tables().build().unwrap();
let factory = create_test_provider_factory();
factory.set_storage_settings_cache(
StorageSettings::v1()
.with_storages_history_in_rocksdb(true)
.with_storage_changesets_in_static_files(true),
);
factory.set_storage_settings_cache(StorageSettings::v2());
let checkpoint_addr = Address::repeat_byte(0xAA);
let checkpoint_slot = B256::repeat_byte(0xBB);
@@ -1453,18 +1394,11 @@ mod tests {
use reth_static_file_types::StaticFileSegment;
let temp_dir = TempDir::new().unwrap();
let rocksdb = RocksDBBuilder::new(temp_dir.path())
.with_table::<tables::AccountsHistory>()
.build()
.unwrap();
let rocksdb = RocksDBBuilder::new(temp_dir.path()).with_default_tables().build().unwrap();
// Create test provider factory
let factory = create_test_provider_factory();
factory.set_storage_settings_cache(
StorageSettings::v1()
.with_account_history_in_rocksdb(true)
.with_account_changesets_in_static_files(true),
);
factory.set_storage_settings_cache(StorageSettings::v2());
const TOTAL_BLOCKS: u64 = 15_000;
const CHECKPOINT_BLOCK: u64 = 5_000;
@@ -1575,17 +1509,10 @@ mod tests {
const SF_TIP: u64 = 200;
let temp_dir = TempDir::new().unwrap();
let rocksdb = RocksDBBuilder::new(temp_dir.path())
.with_table::<tables::AccountsHistory>()
.build()
.unwrap();
let rocksdb = RocksDBBuilder::new(temp_dir.path()).with_default_tables().build().unwrap();
let factory = create_test_provider_factory();
factory.set_storage_settings_cache(
StorageSettings::v1()
.with_account_history_in_rocksdb(true)
.with_account_changesets_in_static_files(true),
);
factory.set_storage_settings_cache(StorageSettings::v2());
let checkpoint_addr = Address::repeat_byte(0xAA);
let stale_addr = Address::repeat_byte(0xCC);
@@ -1652,10 +1579,7 @@ mod tests {
use reth_static_file_types::StaticFileSegment;
let temp_dir = TempDir::new().unwrap();
let rocksdb = RocksDBBuilder::new(temp_dir.path())
.with_table::<tables::StoragesHistory>()
.build()
.unwrap();
let rocksdb = RocksDBBuilder::new(temp_dir.path()).with_default_tables().build().unwrap();
// Insert StoragesHistory entries into RocksDB
let key1 = StorageShardedKey::new(Address::ZERO, B256::ZERO, 50);
@@ -1671,9 +1595,7 @@ mod tests {
// Create a test provider factory
let factory = create_test_provider_factory();
factory.set_storage_settings_cache(
StorageSettings::v1().with_storages_history_in_rocksdb(true),
);
factory.set_storage_settings_cache(StorageSettings::v2());
// Write storage changesets to static files for blocks 0-100
{

View File

@@ -1204,7 +1204,7 @@ impl RocksDBProvider {
ctx: RocksDBWriteCtx,
runtime: &reth_tasks::Runtime,
) -> ProviderResult<()> {
if !ctx.storage_settings.any_in_rocksdb() {
if !ctx.storage_settings.storage_v2 {
return Ok(());
}
@@ -1212,10 +1212,10 @@ impl RocksDBProvider {
let mut r_account_history = None;
let mut r_storage_history = None;
let write_tx_hash = ctx.storage_settings.transaction_hash_numbers_in_rocksdb &&
ctx.prune_tx_lookup.is_none_or(|m| !m.is_full());
let write_account_history = ctx.storage_settings.account_history_in_rocksdb;
let write_storage_history = ctx.storage_settings.storages_history_in_rocksdb;
let write_tx_hash =
ctx.storage_settings.storage_v2 && ctx.prune_tx_lookup.is_none_or(|m| !m.is_full());
let write_account_history = ctx.storage_settings.storage_v2;
let write_storage_history = ctx.storage_settings.storage_v2;
runtime.storage_pool().in_place_scope(|s| {
if write_tx_hash {

View File

@@ -159,7 +159,7 @@ impl<'b, Provider: DBProvider + ChangeSetReader + StorageChangeSetReader + Block
return Err(ProviderError::StateAtBlockPruned(self.block_number))
}
let lookup_key = if self.provider.cached_storage_settings().use_hashed_state {
let lookup_key = if self.provider.cached_storage_settings().use_hashed_state() {
storage_key.to_hashed()
} else {
debug_assert!(
@@ -193,7 +193,7 @@ impl<'b, Provider: DBProvider + ChangeSetReader + StorageChangeSetReader + Block
where
Provider: StorageSettingsCache + RocksDBProviderFactory + NodePrimitivesProvider,
{
let lookup_key = if self.provider.cached_storage_settings().use_hashed_state {
let lookup_key = if self.provider.cached_storage_settings().use_hashed_state() {
storage_key.to_hashed()
} else {
debug_assert!(
@@ -216,7 +216,7 @@ impl<'b, Provider: DBProvider + ChangeSetReader + StorageChangeSetReader + Block
.map(|entry| entry.value)
.map(Some),
HistoryInfo::InPlainState | HistoryInfo::MaybeInPlainState => {
if self.provider.cached_storage_settings().use_hashed_state {
if self.provider.cached_storage_settings().use_hashed_state() {
let hashed_address = alloy_primitives::keccak256(address);
Ok(self
.tx()
@@ -337,7 +337,7 @@ impl<
.map(|account_before| account_before.info)
}
HistoryInfo::InPlainState | HistoryInfo::MaybeInPlainState => {
if self.provider.cached_storage_settings().use_hashed_state {
if self.provider.cached_storage_settings().use_hashed_state() {
let hashed_address = alloy_primitives::keccak256(address);
Ok(self.tx().get_by_encoded_key::<tables::HashedAccounts>(&hashed_address)?)
} else {
@@ -520,7 +520,7 @@ impl<
address: Address,
hashed_storage_key: StorageKey,
) -> ProviderResult<Option<StorageValue>> {
if !self.provider.cached_storage_settings().use_hashed_state {
if !self.provider.cached_storage_settings().use_hashed_state() {
return Err(ProviderError::UnsupportedProvider)
}
self.storage_by_lookup_key(address, StorageSlotKey::hashed(hashed_storage_key))
@@ -1033,7 +1033,7 @@ mod tests {
fn history_provider_get_storage_legacy() {
let factory = create_test_provider_factory();
assert!(!factory.provider().unwrap().cached_storage_settings().use_hashed_state);
assert!(!factory.provider().unwrap().cached_storage_settings().use_hashed_state());
let tx = factory.provider_rw().unwrap().into_tx();
@@ -1277,7 +1277,7 @@ mod tests {
#[test]
fn test_historical_storage_by_hashed_key_unsupported_in_v1() {
let factory = create_test_provider_factory();
assert!(!factory.provider().unwrap().cached_storage_settings().use_hashed_state);
assert!(!factory.provider().unwrap().cached_storage_settings().use_hashed_state());
let db = factory.provider().unwrap();
let provider = HistoricalStateProviderRef::new(&db, 1);

View File

@@ -54,7 +54,7 @@ impl<Provider: DBProvider + StorageSettingsCache> AccountReader
{
/// Get basic account information.
fn basic_account(&self, address: &Address) -> ProviderResult<Option<Account>> {
if self.0.cached_storage_settings().use_hashed_state {
if self.0.cached_storage_settings().use_hashed_state() {
let hashed_address = alloy_primitives::keccak256(address);
self.tx()
.get_by_encoded_key::<tables::HashedAccounts>(&hashed_address)
@@ -180,7 +180,7 @@ impl<Provider: DBProvider + BlockHashReader + StorageSettingsCache> StateProvide
account: Address,
storage_key: StorageKey,
) -> ProviderResult<Option<StorageValue>> {
if self.0.cached_storage_settings().use_hashed_state {
if self.0.cached_storage_settings().use_hashed_state() {
self.hashed_storage_lookup(
alloy_primitives::keccak256(account),
alloy_primitives::keccak256(storage_key),
@@ -201,7 +201,7 @@ impl<Provider: DBProvider + BlockHashReader + StorageSettingsCache> StateProvide
address: Address,
hashed_storage_key: StorageKey,
) -> ProviderResult<Option<StorageValue>> {
if self.0.cached_storage_settings().use_hashed_state {
if self.0.cached_storage_settings().use_hashed_state() {
self.hashed_storage_lookup(alloy_primitives::keccak256(address), hashed_storage_key)
} else {
Err(ProviderError::UnsupportedProvider)
@@ -321,7 +321,7 @@ mod tests {
#[test]
fn test_latest_storage_legacy() {
let factory = create_test_provider_factory();
assert!(!factory.provider().unwrap().cached_storage_settings().use_hashed_state);
assert!(!factory.provider().unwrap().cached_storage_settings().use_hashed_state());
let address = address!("0x0000000000000000000000000000000000000001");
let slot = b256!("0x0000000000000000000000000000000000000000000000000000000000000005");
@@ -347,7 +347,7 @@ mod tests {
#[test]
fn test_latest_storage_legacy_does_not_read_hashed() {
let factory = create_test_provider_factory();
assert!(!factory.provider().unwrap().cached_storage_settings().use_hashed_state);
assert!(!factory.provider().unwrap().cached_storage_settings().use_hashed_state());
let address = address!("0x0000000000000000000000000000000000000001");
let slot = b256!("0x0000000000000000000000000000000000000000000000000000000000000005");
@@ -400,7 +400,7 @@ mod tests {
#[test]
fn test_latest_storage_by_hashed_key_unsupported_in_v1() {
let factory = create_test_provider_factory();
assert!(!factory.provider().unwrap().cached_storage_settings().use_hashed_state);
assert!(!factory.provider().unwrap().cached_storage_settings().use_hashed_state());
let address = address!("0x0000000000000000000000000000000000000001");
let slot = b256!("0x0000000000000000000000000000000000000000000000000000000000000001");

View File

@@ -39,7 +39,7 @@ pub trait RocksDBProviderFactory {
{
#[cfg(all(unix, feature = "rocksdb"))]
{
if self.cached_storage_settings().any_in_rocksdb() {
if self.cached_storage_settings().storage_v2 {
let rocksdb = self.rocksdb_provider();
let tx = rocksdb.tx();
return f(Some(&tx));
@@ -183,8 +183,7 @@ mod tests {
#[test]
fn test_rocksdb_settings_create_tx() {
let settings =
StorageSettings { account_history_in_rocksdb: true, ..StorageSettings::v1() };
let settings = StorageSettings::v2();
let provider = TestProvider::new(settings);
let result = provider.with_rocksdb_tx(|tx| {

View File

@@ -16,11 +16,15 @@ pub trait MetadataProvider: Send {
/// Get a metadata value by key
fn get_metadata(&self, key: &str) -> ProviderResult<Option<Vec<u8>>>;
/// Get storage settings for this node
/// Get storage settings for this node.
///
/// If the stored metadata can't be deserialized (e.g. the format changed),
/// this returns `None` instead of an error so commands like `db clear` can
/// still operate without requiring a compatible metadata schema.
fn storage_settings(&self) -> ProviderResult<Option<StorageSettings>> {
self.get_metadata(keys::STORAGE_SETTINGS)?
.map(|bytes| serde_json::from_slice(&bytes).map_err(ProviderError::other))
.transpose()
Ok(self
.get_metadata(keys::STORAGE_SETTINGS)?
.and_then(|bytes| serde_json::from_slice(&bytes).ok()))
}
}

View File

@@ -816,6 +816,17 @@ impl RuntimeBuilder {
let (task_manager, on_shutdown, task_events_tx, graceful_tasks) =
TaskManager::new_parts(handle.clone());
#[cfg(feature = "rayon")]
#[allow(clippy::needless_pass_by_value)]
fn rayon_panic_handler(payload: Box<dyn std::any::Any + Send>) {
let msg = payload
.downcast_ref::<&str>()
.copied()
.or_else(|| payload.downcast_ref::<String>().map(|s| s.as_str()))
.unwrap_or("(no message)");
error!(target: "reth::tasks", %msg, "panic in worker pool thread");
}
#[cfg(feature = "rayon")]
let (
cpu_pool,
@@ -853,6 +864,7 @@ impl RuntimeBuilder {
let proof_storage_worker_pool = rayon::ThreadPoolBuilder::new()
.num_threads(proof_storage_worker_threads)
.thread_name(|i| format!("proof-strg-{i:02}"))
.panic_handler(rayon_panic_handler)
.build()?;
let proof_account_worker_threads =
@@ -860,6 +872,7 @@ impl RuntimeBuilder {
let proof_account_worker_pool = rayon::ThreadPoolBuilder::new()
.num_threads(proof_account_worker_threads)
.thread_name(|i| format!("proof-acct-{i:02}"))
.panic_handler(rayon_panic_handler)
.build()?;
debug!(

View File

@@ -528,15 +528,12 @@ mod tests {
#[test]
fn from_reverts_with_hashed_state() {
use reth_db_api::models::StorageBeforeTx;
use reth_db_api::models::{StorageBeforeTx, StorageSettings};
use reth_provider::{StaticFileProviderFactory, StaticFileSegment, StaticFileWriter};
let factory = create_test_provider_factory();
let mut settings = factory.cached_storage_settings();
settings.use_hashed_state = true;
settings.storage_changesets_in_static_files = true;
factory.set_storage_settings_cache(settings);
factory.set_storage_settings_cache(StorageSettings::v2());
let provider = factory.provider_rw().unwrap();
@@ -548,33 +545,32 @@ mod tests {
let hashed_slot1 = keccak256(plain_slot1);
let hashed_slot2 = keccak256(plain_slot2);
provider
.tx_ref()
.put::<tables::AccountChangeSets>(
1,
AccountBeforeTx {
address: address1,
info: Some(Account { nonce: 1, ..Default::default() }),
},
)
.unwrap();
provider
.tx_ref()
.put::<tables::AccountChangeSets>(
2,
AccountBeforeTx {
address: address1,
info: Some(Account { nonce: 2, ..Default::default() }),
},
)
.unwrap();
provider
.tx_ref()
.put::<tables::AccountChangeSets>(3, AccountBeforeTx { address: address2, info: None })
.unwrap();
{
let sf = factory.static_file_provider();
// Write account changesets to static files (v2 reads from here)
let mut aw = sf.latest_writer(StaticFileSegment::AccountChangeSets).unwrap();
aw.append_account_changeset(vec![], 0).unwrap();
aw.append_account_changeset(
vec![AccountBeforeTx {
address: address1,
info: Some(Account { nonce: 1, ..Default::default() }),
}],
1,
)
.unwrap();
aw.append_account_changeset(
vec![AccountBeforeTx {
address: address1,
info: Some(Account { nonce: 2, ..Default::default() }),
}],
2,
)
.unwrap();
aw.append_account_changeset(vec![AccountBeforeTx { address: address2, info: None }], 3)
.unwrap();
aw.commit().unwrap();
let mut writer = sf.latest_writer(StaticFileSegment::StorageChangeSets).unwrap();
writer.append_storage_changeset(vec![], 0).unwrap();
writer

View File

@@ -149,7 +149,7 @@ mod tests {
let factory = create_test_provider_factory();
let provider = factory.provider_rw().unwrap();
assert!(!provider.cached_storage_settings().use_hashed_state);
assert!(!provider.cached_storage_settings().use_hashed_state());
let address = Address::with_last_byte(42);
let slot1 = B256::from(U256::from(100));
@@ -191,18 +191,15 @@ mod tests {
#[test]
fn test_hashed_storage_from_reverts_hashed_state() {
use reth_db_api::models::StorageBeforeTx;
use reth_db_api::models::{StorageBeforeTx, StorageSettings};
let factory = create_test_provider_factory();
let mut settings = factory.cached_storage_settings();
settings.use_hashed_state = true;
settings.storage_changesets_in_static_files = true;
factory.set_storage_settings_cache(settings);
factory.set_storage_settings_cache(StorageSettings::v2());
let provider = factory.provider_rw().unwrap();
assert!(provider.cached_storage_settings().use_hashed_state);
assert!(provider.cached_storage_settings().storage_changesets_in_static_files);
assert!(provider.cached_storage_settings().use_hashed_state());
assert!(provider.cached_storage_settings().is_v2());
let address = Address::with_last_byte(42);
let plain_slot1 = B256::from(U256::from(100));

View File

@@ -258,7 +258,7 @@ impl SparseTrie for ParallelSparseTrie {
#[cfg(feature = "std")]
// Reveal lower subtrie nodes in parallel
{
use rayon::iter::{IndexedParallelIterator, IntoParallelIterator, ParallelIterator};
use rayon::iter::{IntoParallelIterator, ParallelIterator};
use tracing::Span;
// Capture the current span so it can be propagated to rayon worker threads
@@ -267,23 +267,39 @@ impl SparseTrie for ParallelSparseTrie {
// Capture reference to upper subtrie nodes for boundary leaf reachability checks
let upper_nodes = &self.upper_subtrie.nodes;
// Group the nodes by lower subtrie. This must be collected into a Vec in order for
// rayon's `zip` to be happy.
let node_groups: Vec<_> = lower_nodes
// Group the nodes by lower subtrie.
let results = lower_nodes
.chunk_by(|node_a, node_b| {
SparseSubtrieType::from_path(&node_a.path) ==
SparseSubtrieType::from_path(&node_b.path)
})
.collect();
// Take the lower subtries in the same order that the nodes were grouped into, so that
// the two can be zipped together. This also must be collected into a Vec for rayon's
// `zip` to be happy.
let lower_subtries: Vec<_> = node_groups
.iter()
// Filter out chunks for unreachable subtries.
.filter_map(|nodes| {
// NOTE: chunk_by won't produce empty groups
let node = &nodes[0];
let mut nodes = nodes
.iter()
.filter(|node| {
// For boundary leaves, check reachability from upper subtrie's parent
// branch.
if node.path.len() == UPPER_TRIE_MAX_DEPTH &&
!Self::is_boundary_leaf_reachable(
upper_nodes,
&node.path,
&node.node,
)
{
trace!(
target: "trie::parallel_sparse",
path = ?node.path,
"Boundary leaf not reachable from upper subtrie, skipping",
);
false
} else {
true
}
})
.peekable();
let node = nodes.peek()?;
let idx =
SparseSubtrieType::from_path(&node.path).lower_index().unwrap_or_else(
|| panic!("upper subtrie node {node:?} found amongst lower nodes"),
@@ -303,41 +319,24 @@ impl SparseTrie for ParallelSparseTrie {
// shortest path being revealed for each subtrie. Therefore we can reveal the
// subtrie itself using this path and retain correct behavior.
self.lower_subtries[idx].reveal(&node.path);
Some((idx, self.lower_subtries[idx].take_revealed().expect("just revealed")))
Some((
idx,
self.lower_subtries[idx].take_revealed().expect("just revealed"),
nodes,
))
})
.collect();
// Zip the lower subtries and their corresponding node groups, and reveal lower subtrie
// nodes in parallel
let results: Vec<_> = lower_subtries
.collect::<Vec<_>>()
.into_par_iter()
.zip(node_groups.into_par_iter())
.map(|((subtrie_idx, mut subtrie), nodes)| {
.map(|(subtrie_idx, mut subtrie, nodes)| {
// Enter the parent span to propagate context (e.g., hashed_address for storage
// tries) to the worker thread
let _guard = parent_span.enter();
// reserve space in the HashMap ahead of time; doing it on a node-by-node basis
// can cause multiple re-allocations as the hashmap grows.
subtrie.nodes.reserve(nodes.len());
subtrie.nodes.reserve(nodes.size_hint().1.unwrap_or(0));
for node in nodes {
// For boundary leaves, check reachability from upper subtrie's parent
// branch
if node.path.len() == UPPER_TRIE_MAX_DEPTH &&
!Self::is_boundary_leaf_reachable(
upper_nodes,
&node.path,
&node.node,
)
{
trace!(
target: "trie::parallel_sparse",
path = ?node.path,
"Boundary leaf not reachable from upper subtrie, skipping",
);
continue;
}
// Reveal each node in the subtrie, returning early on any errors
let res = subtrie.reveal_node(node.path, &node.node, node.masks);
if res.is_err() {
@@ -346,7 +345,7 @@ impl SparseTrie for ParallelSparseTrie {
}
(subtrie_idx, subtrie, Ok(()))
})
.collect();
.collect::<Vec<_>>();
// Put subtries back which were processed in the rayon pool, collecting the last
// seen error in the process and returning that.
@@ -1958,6 +1957,7 @@ impl ParallelSparseTrie {
}
SparseTrieUpdatesAction::InsertUpdated(path, branch_node) => {
updates.updated_nodes.insert(path, branch_node);
updates.removed_nodes.remove(&path);
}
}
}

View File

@@ -1282,6 +1282,16 @@ where
Ok(())
}
/// Clears internal computation state. Called after errors to ensure the calculator is not
/// left in a partially-computed state when reused.
fn clear_computation_state(&mut self) {
self.branch_stack.clear();
self.branch_path = Nibbles::new();
self.child_stack.clear();
self.cached_branch_stack.clear();
self.retained_proofs.clear();
}
/// Internal implementation of proof calculation. Assumes both cursors have already been reset.
/// See docs on [`Self::proof`] for expected behavior.
fn proof_inner(
@@ -1303,12 +1313,15 @@ where
// Divide targets into chunks, each chunk corresponding to a different sub-trie within the
// overall trie, and handle all proofs within that sub-trie.
for sub_trie_targets in iter_sub_trie_targets(targets) {
self.proof_subtrie(
if let Err(err) = self.proof_subtrie(
value_encoder,
&mut trie_cursor_state,
&mut hashed_cursor_current,
sub_trie_targets,
)?;
) {
self.clear_computation_state();
return Err(err);
}
}
trace!(
@@ -1378,12 +1391,15 @@ where
let sub_trie_targets =
SubTrieTargets { prefix: Nibbles::new(), targets: &EMPTY_TARGETS, retain_root: true };
self.proof_subtrie(
if let Err(err) = self.proof_subtrie(
value_encoder,
&mut trie_cursor_state,
&mut hashed_cursor_current,
sub_trie_targets,
)?;
) {
self.clear_computation_state();
return Err(err);
}
// proof_subtrie will retain the root node if retain_proof is true, regardless of if there
// are any targets.
@@ -1815,6 +1831,79 @@ mod tests {
}
}
/// Tests that `clear_computation_state` properly resets internal stacks, allowing a
/// `ProofCalculator` to be reused after a mid-computation error left stale state.
/// Before the fix, stale data in `branch_stack`, `child_stack`, and `branch_path`
/// could cause a `usize` underflow panic in `pop_branch`.
#[test]
fn test_proof_calculator_reuse_after_error() {
use alloy_primitives::U256;
reth_tracing::init_test_tracing();
let mut post_state = HashedPostState::default();
let addresses = [
B256::right_padding_from(&[0x10]),
B256::right_padding_from(&[0x20]),
B256::right_padding_from(&[0x30]),
B256::right_padding_from(&[0x40]),
];
for addr in &addresses {
let account =
Account { nonce: 1, balance: U256::from(100u64), bytecode_hash: Some(B256::ZERO) };
post_state.accounts.insert(*addr, Some(account));
}
let harness = ProofTestHarness::new(post_state);
let trie_cursor = harness.trie_cursor_factory.account_trie_cursor().unwrap();
let hashed_cursor = harness.hashed_cursor_factory.hashed_account_cursor().unwrap();
let mut proof_calculator = ProofCalculator::new(trie_cursor, hashed_cursor);
// Simulate stale state left by a mid-computation error: push fake entries onto internal
// stacks and set a non-empty branch_path.
proof_calculator.branch_stack.push(ProofTrieBranch {
ext_len: 2,
state_mask: TrieMask::new(0b1111),
masks: None,
});
proof_calculator.branch_stack.push(ProofTrieBranch {
ext_len: 0,
state_mask: TrieMask::new(0b11),
masks: None,
});
proof_calculator
.child_stack
.push(ProofTrieBranchChild::RlpNode(RlpNode::word_rlp(&B256::ZERO)));
proof_calculator.branch_path = Nibbles::from_nibbles([0x1, 0x2, 0x3]);
// clear_computation_state should reset everything so a subsequent proof() call works.
proof_calculator.clear_computation_state();
let mut value_encoder = SyncAccountValueEncoder::new(
harness.trie_cursor_factory.clone(),
harness.hashed_cursor_factory.clone(),
);
let mut sorted_addresses = addresses.to_vec();
sorted_addresses.sort();
let mut targets: Vec<ProofV2Target> =
sorted_addresses.iter().copied().map(ProofV2Target::new).collect();
let result = proof_calculator.proof(&mut value_encoder, &mut targets).unwrap();
// Compare against a fresh calculator to verify correctness.
let trie_cursor = harness.trie_cursor_factory.account_trie_cursor().unwrap();
let hashed_cursor = harness.hashed_cursor_factory.hashed_account_cursor().unwrap();
let mut fresh_calculator = ProofCalculator::new(trie_cursor, hashed_cursor);
let mut value_encoder = SyncAccountValueEncoder::new(
harness.trie_cursor_factory.clone(),
harness.hashed_cursor_factory,
);
let fresh_result = fresh_calculator.proof(&mut value_encoder, &mut targets).unwrap();
pretty_assertions::assert_eq!(fresh_result, result);
}
mod proptest_tests {
use super::*;
use alloy_primitives::{map::B256Map, U256};

View File

@@ -13,6 +13,7 @@
- [`reth db checksum mdbx`](./reth/db/checksum/mdbx.mdx)
- [`reth db checksum static-file`](./reth/db/checksum/static-file.mdx)
- [`reth db checksum rocksdb`](./reth/db/checksum/rocksdb.mdx)
- [`reth db copy`](./reth/db/copy.mdx)
- [`reth db diff`](./reth/db/diff.mdx)
- [`reth db get`](./reth/db/get.mdx)
- [`reth db get mdbx`](./reth/db/get/mdbx.mdx)
@@ -30,14 +31,7 @@
- [`reth db settings`](./reth/db/settings.mdx)
- [`reth db settings get`](./reth/db/settings/get.mdx)
- [`reth db settings set`](./reth/db/settings/set.mdx)
- [`reth db settings set receipts`](./reth/db/settings/set/receipts.mdx)
- [`reth db settings set transaction_senders`](./reth/db/settings/set/transaction_senders.mdx)
- [`reth db settings set account_changesets`](./reth/db/settings/set/account_changesets.mdx)
- [`reth db settings set storages_history`](./reth/db/settings/set/storages_history.mdx)
- [`reth db settings set transaction_hash_numbers`](./reth/db/settings/set/transaction_hash_numbers.mdx)
- [`reth db settings set account_history`](./reth/db/settings/set/account_history.mdx)
- [`reth db settings set storage_changesets`](./reth/db/settings/set/storage_changesets.mdx)
- [`reth db settings set use_hashed_state`](./reth/db/settings/set/use_hashed_state.mdx)
- [`reth db settings set v2`](./reth/db/settings/set/v2.mdx)
- [`reth db account-storage`](./reth/db/account-storage.mdx)
- [`reth db state`](./reth/db/state.mdx)
- [`reth download`](./reth/download.mdx)

View File

@@ -12,6 +12,7 @@ Commands:
stats Lists all the tables, their entry count and their size
list Lists the contents of a table
checksum Calculates the content checksum of a table or static file segment
copy Copies the MDBX database to a new location (bundled mdbx_copy)
diff Create a diff between two database tables or two entire databases
get Gets the content of a table for the given key
drop Deletes all database entries
@@ -128,77 +129,6 @@ Static Files:
--static-files.blocks-per-file.storage-change-sets <BLOCKS_PER_FILE_STORAGE_CHANGE_SETS>
Number of blocks per file for the storage changesets segment
--static-files.receipts <RECEIPTS>
Store receipts in static files instead of the database.
When enabled, receipts will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--static-files.transaction-senders <TRANSACTION_SENDERS>
Store transaction senders in static files instead of the database.
When enabled, transaction senders will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--static-files.account-change-sets <ACCOUNT_CHANGESETS>
Store account changesets in static files.
When enabled, account changesets will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--static-files.storage-change-sets <STORAGE_CHANGESETS>
Store storage changesets in static files.
When enabled, storage changesets will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
RocksDB:
--rocksdb.all
Route all supported tables to `RocksDB` instead of MDBX.
This enables `RocksDB` for `tx-hash`, `storages-history`, and `account-history` tables. Cannot be combined with individual flags set to false.
--rocksdb.tx-hash <TX_HASH>
Route tx hash -> number table to `RocksDB` instead of MDBX.
This is a genesis-initialization-only flag: changing it after genesis requires a re-sync. Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--rocksdb.storages-history <STORAGES_HISTORY>
Route storages history tables to `RocksDB` instead of MDBX.
This is a genesis-initialization-only flag: changing it after genesis requires a re-sync. Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--rocksdb.account-history <ACCOUNT_HISTORY>
Route account history tables to `RocksDB` instead of MDBX.
This is a genesis-initialization-only flag: changing it after genesis requires a re-sync. Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
Storage:
--storage.v2
Enable v2 storage defaults (static files + `RocksDB` routing).
@@ -209,13 +139,6 @@ Storage:
Individual settings can still be overridden with `--static-files.*` and `--rocksdb.*` flags.
--storage.use-hashed-state
Use hashed state tables (`HashedAccounts`/`HashedStorages`) as canonical state representation instead of plain state tables.
When enabled, execution writes directly to hashed tables, eliminating the need for separate hashing stages. This should only be enabled for new databases.
WARNING: Changing this setting on an existing database requires a full resync.
Logging:
--log.stdout.format <FORMAT>
The format to use for logs written to stdout

View File

@@ -0,0 +1,179 @@
# reth db copy
Copies the MDBX database to a new location (bundled mdbx_copy)
```bash
$ reth db copy --help
```
```txt
Usage: reth db copy [OPTIONS] <DEST>
Arguments:
<DEST>
Destination path for the database copy
Options:
-c, --compact
Compact the database while copying (reclaims free space)
-d, --force-dynamic-size
Force dynamic size for the destination database
-p, --throttle-mvcc
Throttle to avoid MVCC pressure on writers
-h, --help
Print help (see a summary with '-h')
Datadir:
--chain <CHAIN_OR_PATH>
The chain this node is running.
Possible values are either a built-in chain or the path to a chain specification file.
Built-in chains:
mainnet, sepolia, holesky, hoodi, dev
[default: mainnet]
Logging:
--log.stdout.format <FORMAT>
The format to use for logs written to stdout
Possible values:
- json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging
- log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications
- terminal: Represents terminal-friendly formatting for logs
[default: terminal]
--log.stdout.filter <FILTER>
The filter to use for logs written to stdout
[default: ]
--log.file.format <FORMAT>
The format to use for logs written to the log file
Possible values:
- json: Represents JSON formatting for logs. This format outputs log records as JSON objects, making it suitable for structured logging
- log-fmt: Represents logfmt (key=value) formatting for logs. This format is concise and human-readable, typically used in command-line applications
- terminal: Represents terminal-friendly formatting for logs
[default: terminal]
--log.file.filter <FILTER>
The filter to use for logs written to the log file
[default: debug]
--log.file.directory <PATH>
The path to put log files in
[default: <CACHE_DIR>/logs]
--log.file.name <NAME>
The prefix name of the log files
[default: reth.log]
--log.file.max-size <SIZE>
The maximum size (in MB) of one log file
[default: 200]
--log.file.max-files <COUNT>
The maximum amount of log files that will be stored. If set to 0, background file logging is disabled
[default: 5]
--log.journald
Write logs to journald
--log.journald.filter <FILTER>
The filter to use for logs written to journald
[default: error]
--color <COLOR>
Sets whether or not the formatter emits ANSI terminal escape codes for colors and other text formatting
Possible values:
- always: Colors on
- auto: Auto-detect
- never: Colors off
[default: always]
--logs-otlp[=<URL>]
Enable `Opentelemetry` logs export to an OTLP endpoint.
If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317`
Example: --logs-otlp=http://collector:4318/v1/logs
[env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=]
--logs-otlp.filter <FILTER>
Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable.
Example: --logs-otlp.filter=info,reth=debug
Defaults to INFO if not specified.
[default: info]
Display:
-v, --verbosity...
Set the minimum log level.
-v Errors
-vv Warnings
-vvv Info
-vvvv Debug
-vvvvv Traces (warning: very verbose!)
-q, --quiet
Silence all log output
Tracing:
--tracing-otlp[=<URL>]
Enable `Opentelemetry` tracing export to an OTLP endpoint.
If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/traces` - gRPC: `http://localhost:4317`
Example: --tracing-otlp=http://collector:4318/v1/traces
[env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=]
--tracing-otlp-protocol <PROTOCOL>
OTLP transport protocol to use for exporting traces and logs.
- `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path
Defaults to HTTP if not specified.
Possible values:
- http: HTTP/Protobuf transport, port 4318, requires `/v1/traces` path
- grpc: gRPC transport, port 4317
[env: OTEL_EXPORTER_OTLP_PROTOCOL=]
[default: http]
--tracing-otlp.filter <FILTER>
Set a filter directive for the OTLP tracer. This controls the verbosity of spans and events sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable.
Example: --tracing-otlp.filter=info,reth=debug,hyper_util=off
Defaults to TRACE if not specified.
[default: debug]
--tracing-otlp.sample-ratio <RATIO>
Trace sampling ratio to control the percentage of traces to export.
Valid range: 0.0 to 1.0 - 1.0, default: Sample all traces - 0.01: Sample 1% of traces - 0.0: Disable sampling
Example: --tracing-otlp.sample-ratio=0.0.
[env: OTEL_TRACES_SAMPLER_ARG=]
```

View File

@@ -9,15 +9,8 @@ $ reth db settings set --help
Usage: reth db settings set [OPTIONS] <COMMAND>
Commands:
receipts Store receipts in static files instead of the database
transaction_senders Store transaction senders in static files instead of the database
account_changesets Store account changesets in static files instead of the database
storages_history Store storage history in rocksdb instead of MDBX
transaction_hash_numbers Store transaction hash to number mapping in rocksdb instead of MDBX
account_history Store account history in rocksdb instead of MDBX
storage_changesets Store storage changesets in static files instead of the database
use_hashed_state Use hashed state tables (HashedAccounts/HashedStorages) as canonical state
help Print this message or the help of the given subcommand(s)
v2 Enable or disable v2 storage layout
help Print this message or the help of the given subcommand(s)
Options:
-h, --help

View File

@@ -1,12 +1,12 @@
# reth db settings set account_changesets_in_static_files
# reth db settings set v2
Store account changesets in static files instead of the database
Enable or disable v2 storage layout
```bash
$ reth db settings set account_changesets_in_static_files --help
$ reth db settings set v2 --help
```
```txt
Usage: reth db settings set account_changesets_in_static_files [OPTIONS] <VALUE>
Usage: reth db settings set v2 [OPTIONS] <VALUE>
Arguments:
<VALUE>
@@ -95,6 +95,24 @@ Logging:
[default: always]
--logs-otlp[=<URL>]
Enable `Opentelemetry` logs export to an OTLP endpoint.
If no value provided, defaults based on protocol: - HTTP: `http://localhost:4318/v1/logs` - gRPC: `http://localhost:4317`
Example: --logs-otlp=http://collector:4318/v1/logs
[env: OTEL_EXPORTER_OTLP_LOGS_ENDPOINT=]
--logs-otlp.filter <FILTER>
Set a filter directive for the OTLP logs exporter. This controls the verbosity of logs sent to the OTLP endpoint. It follows the same syntax as the `RUST_LOG` environment variable.
Example: --logs-otlp.filter=info,reth=debug
Defaults to INFO if not specified.
[default: info]
Display:
-v, --verbosity...
Set the minimum log level.
@@ -119,9 +137,9 @@ Tracing:
[env: OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=]
--tracing-otlp-protocol <PROTOCOL>
OTLP transport protocol to use for exporting traces.
OTLP transport protocol to use for exporting traces and logs.
- `http`: expects endpoint path to end with `/v1/traces` - `grpc`: expects endpoint without a path
- `http`: expects endpoint path to end with `/v1/traces` or `/v1/logs` - `grpc`: expects endpoint without a path
Defaults to HTTP if not specified.

View File

@@ -111,77 +111,6 @@ Static Files:
--static-files.blocks-per-file.storage-change-sets <BLOCKS_PER_FILE_STORAGE_CHANGE_SETS>
Number of blocks per file for the storage changesets segment
--static-files.receipts <RECEIPTS>
Store receipts in static files instead of the database.
When enabled, receipts will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--static-files.transaction-senders <TRANSACTION_SENDERS>
Store transaction senders in static files instead of the database.
When enabled, transaction senders will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--static-files.account-change-sets <ACCOUNT_CHANGESETS>
Store account changesets in static files.
When enabled, account changesets will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--static-files.storage-change-sets <STORAGE_CHANGESETS>
Store storage changesets in static files.
When enabled, storage changesets will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
RocksDB:
--rocksdb.all
Route all supported tables to `RocksDB` instead of MDBX.
This enables `RocksDB` for `tx-hash`, `storages-history`, and `account-history` tables. Cannot be combined with individual flags set to false.
--rocksdb.tx-hash <TX_HASH>
Route tx hash -> number table to `RocksDB` instead of MDBX.
This is a genesis-initialization-only flag: changing it after genesis requires a re-sync. Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--rocksdb.storages-history <STORAGES_HISTORY>
Route storages history tables to `RocksDB` instead of MDBX.
This is a genesis-initialization-only flag: changing it after genesis requires a re-sync. Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--rocksdb.account-history <ACCOUNT_HISTORY>
Route account history tables to `RocksDB` instead of MDBX.
This is a genesis-initialization-only flag: changing it after genesis requires a re-sync. Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
Storage:
--storage.v2
Enable v2 storage defaults (static files + `RocksDB` routing).
@@ -192,13 +121,6 @@ Storage:
Individual settings can still be overridden with `--static-files.*` and `--rocksdb.*` flags.
--storage.use-hashed-state
Use hashed state tables (`HashedAccounts`/`HashedStorages`) as canonical state representation instead of plain state tables.
When enabled, execution writes directly to hashed tables, eliminating the need for separate hashing stages. This should only be enabled for new databases.
WARNING: Changing this setting on an existing database requires a full resync.
-u, --url <URL>
Specify a snapshot URL or let the command propose a default one.
@@ -206,7 +128,7 @@ Storage:
- https://www.merkle.io/snapshots (default, mainnet archive)
- https://publicnode.com/snapshots (full nodes & testnets)
If no URL is provided, the latest mainnet archive snapshot
If no URL is provided, the latest archive snapshot for the selected chain
will be proposed for download from https://downloads.merkle.io.
Local file:// URLs are also supported for extracting snapshots from disk.

View File

@@ -111,77 +111,6 @@ Static Files:
--static-files.blocks-per-file.storage-change-sets <BLOCKS_PER_FILE_STORAGE_CHANGE_SETS>
Number of blocks per file for the storage changesets segment
--static-files.receipts <RECEIPTS>
Store receipts in static files instead of the database.
When enabled, receipts will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--static-files.transaction-senders <TRANSACTION_SENDERS>
Store transaction senders in static files instead of the database.
When enabled, transaction senders will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--static-files.account-change-sets <ACCOUNT_CHANGESETS>
Store account changesets in static files.
When enabled, account changesets will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--static-files.storage-change-sets <STORAGE_CHANGESETS>
Store storage changesets in static files.
When enabled, storage changesets will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
RocksDB:
--rocksdb.all
Route all supported tables to `RocksDB` instead of MDBX.
This enables `RocksDB` for `tx-hash`, `storages-history`, and `account-history` tables. Cannot be combined with individual flags set to false.
--rocksdb.tx-hash <TX_HASH>
Route tx hash -> number table to `RocksDB` instead of MDBX.
This is a genesis-initialization-only flag: changing it after genesis requires a re-sync. Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--rocksdb.storages-history <STORAGES_HISTORY>
Route storages history tables to `RocksDB` instead of MDBX.
This is a genesis-initialization-only flag: changing it after genesis requires a re-sync. Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--rocksdb.account-history <ACCOUNT_HISTORY>
Route account history tables to `RocksDB` instead of MDBX.
This is a genesis-initialization-only flag: changing it after genesis requires a re-sync. Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
Storage:
--storage.v2
Enable v2 storage defaults (static files + `RocksDB` routing).
@@ -192,13 +121,6 @@ Storage:
Individual settings can still be overridden with `--static-files.*` and `--rocksdb.*` flags.
--storage.use-hashed-state
Use hashed state tables (`HashedAccounts`/`HashedStorages`) as canonical state representation instead of plain state tables.
When enabled, execution writes directly to hashed tables, eliminating the need for separate hashing stages. This should only be enabled for new databases.
WARNING: Changing this setting on an existing database requires a full resync.
--first-block-number <first-block-number>
Optional first block number to export from the db.
It is by default 0.

View File

@@ -111,77 +111,6 @@ Static Files:
--static-files.blocks-per-file.storage-change-sets <BLOCKS_PER_FILE_STORAGE_CHANGE_SETS>
Number of blocks per file for the storage changesets segment
--static-files.receipts <RECEIPTS>
Store receipts in static files instead of the database.
When enabled, receipts will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--static-files.transaction-senders <TRANSACTION_SENDERS>
Store transaction senders in static files instead of the database.
When enabled, transaction senders will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--static-files.account-change-sets <ACCOUNT_CHANGESETS>
Store account changesets in static files.
When enabled, account changesets will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--static-files.storage-change-sets <STORAGE_CHANGESETS>
Store storage changesets in static files.
When enabled, storage changesets will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
RocksDB:
--rocksdb.all
Route all supported tables to `RocksDB` instead of MDBX.
This enables `RocksDB` for `tx-hash`, `storages-history`, and `account-history` tables. Cannot be combined with individual flags set to false.
--rocksdb.tx-hash <TX_HASH>
Route tx hash -> number table to `RocksDB` instead of MDBX.
This is a genesis-initialization-only flag: changing it after genesis requires a re-sync. Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--rocksdb.storages-history <STORAGES_HISTORY>
Route storages history tables to `RocksDB` instead of MDBX.
This is a genesis-initialization-only flag: changing it after genesis requires a re-sync. Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--rocksdb.account-history <ACCOUNT_HISTORY>
Route account history tables to `RocksDB` instead of MDBX.
This is a genesis-initialization-only flag: changing it after genesis requires a re-sync. Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
Storage:
--storage.v2
Enable v2 storage defaults (static files + `RocksDB` routing).
@@ -192,13 +121,6 @@ Storage:
Individual settings can still be overridden with `--static-files.*` and `--rocksdb.*` flags.
--storage.use-hashed-state
Use hashed state tables (`HashedAccounts`/`HashedStorages`) as canonical state representation instead of plain state tables.
When enabled, execution writes directly to hashed tables, eliminating the need for separate hashing stages. This should only be enabled for new databases.
WARNING: Changing this setting on an existing database requires a full resync.
--path <IMPORT_ERA_PATH>
The path to a directory for import.

View File

@@ -111,77 +111,6 @@ Static Files:
--static-files.blocks-per-file.storage-change-sets <BLOCKS_PER_FILE_STORAGE_CHANGE_SETS>
Number of blocks per file for the storage changesets segment
--static-files.receipts <RECEIPTS>
Store receipts in static files instead of the database.
When enabled, receipts will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--static-files.transaction-senders <TRANSACTION_SENDERS>
Store transaction senders in static files instead of the database.
When enabled, transaction senders will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--static-files.account-change-sets <ACCOUNT_CHANGESETS>
Store account changesets in static files.
When enabled, account changesets will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--static-files.storage-change-sets <STORAGE_CHANGESETS>
Store storage changesets in static files.
When enabled, storage changesets will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
RocksDB:
--rocksdb.all
Route all supported tables to `RocksDB` instead of MDBX.
This enables `RocksDB` for `tx-hash`, `storages-history`, and `account-history` tables. Cannot be combined with individual flags set to false.
--rocksdb.tx-hash <TX_HASH>
Route tx hash -> number table to `RocksDB` instead of MDBX.
This is a genesis-initialization-only flag: changing it after genesis requires a re-sync. Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--rocksdb.storages-history <STORAGES_HISTORY>
Route storages history tables to `RocksDB` instead of MDBX.
This is a genesis-initialization-only flag: changing it after genesis requires a re-sync. Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--rocksdb.account-history <ACCOUNT_HISTORY>
Route account history tables to `RocksDB` instead of MDBX.
This is a genesis-initialization-only flag: changing it after genesis requires a re-sync. Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
Storage:
--storage.v2
Enable v2 storage defaults (static files + `RocksDB` routing).
@@ -192,13 +121,6 @@ Storage:
Individual settings can still be overridden with `--static-files.*` and `--rocksdb.*` flags.
--storage.use-hashed-state
Use hashed state tables (`HashedAccounts`/`HashedStorages`) as canonical state representation instead of plain state tables.
When enabled, execution writes directly to hashed tables, eliminating the need for separate hashing stages. This should only be enabled for new databases.
WARNING: Changing this setting on an existing database requires a full resync.
--no-state
Disables stages that require state.

View File

@@ -111,77 +111,6 @@ Static Files:
--static-files.blocks-per-file.storage-change-sets <BLOCKS_PER_FILE_STORAGE_CHANGE_SETS>
Number of blocks per file for the storage changesets segment
--static-files.receipts <RECEIPTS>
Store receipts in static files instead of the database.
When enabled, receipts will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--static-files.transaction-senders <TRANSACTION_SENDERS>
Store transaction senders in static files instead of the database.
When enabled, transaction senders will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--static-files.account-change-sets <ACCOUNT_CHANGESETS>
Store account changesets in static files.
When enabled, account changesets will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--static-files.storage-change-sets <STORAGE_CHANGESETS>
Store storage changesets in static files.
When enabled, storage changesets will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
RocksDB:
--rocksdb.all
Route all supported tables to `RocksDB` instead of MDBX.
This enables `RocksDB` for `tx-hash`, `storages-history`, and `account-history` tables. Cannot be combined with individual flags set to false.
--rocksdb.tx-hash <TX_HASH>
Route tx hash -> number table to `RocksDB` instead of MDBX.
This is a genesis-initialization-only flag: changing it after genesis requires a re-sync. Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--rocksdb.storages-history <STORAGES_HISTORY>
Route storages history tables to `RocksDB` instead of MDBX.
This is a genesis-initialization-only flag: changing it after genesis requires a re-sync. Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--rocksdb.account-history <ACCOUNT_HISTORY>
Route account history tables to `RocksDB` instead of MDBX.
This is a genesis-initialization-only flag: changing it after genesis requires a re-sync. Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
Storage:
--storage.v2
Enable v2 storage defaults (static files + `RocksDB` routing).
@@ -192,13 +121,6 @@ Storage:
Individual settings can still be overridden with `--static-files.*` and `--rocksdb.*` flags.
--storage.use-hashed-state
Use hashed state tables (`HashedAccounts`/`HashedStorages`) as canonical state representation instead of plain state tables.
When enabled, execution writes directly to hashed tables, eliminating the need for separate hashing stages. This should only be enabled for new databases.
WARNING: Changing this setting on an existing database requires a full resync.
--without-evm
Specifies whether to initialize the state without relying on EVM historical data.

View File

@@ -111,77 +111,6 @@ Static Files:
--static-files.blocks-per-file.storage-change-sets <BLOCKS_PER_FILE_STORAGE_CHANGE_SETS>
Number of blocks per file for the storage changesets segment
--static-files.receipts <RECEIPTS>
Store receipts in static files instead of the database.
When enabled, receipts will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--static-files.transaction-senders <TRANSACTION_SENDERS>
Store transaction senders in static files instead of the database.
When enabled, transaction senders will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--static-files.account-change-sets <ACCOUNT_CHANGESETS>
Store account changesets in static files.
When enabled, account changesets will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--static-files.storage-change-sets <STORAGE_CHANGESETS>
Store storage changesets in static files.
When enabled, storage changesets will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
RocksDB:
--rocksdb.all
Route all supported tables to `RocksDB` instead of MDBX.
This enables `RocksDB` for `tx-hash`, `storages-history`, and `account-history` tables. Cannot be combined with individual flags set to false.
--rocksdb.tx-hash <TX_HASH>
Route tx hash -> number table to `RocksDB` instead of MDBX.
This is a genesis-initialization-only flag: changing it after genesis requires a re-sync. Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--rocksdb.storages-history <STORAGES_HISTORY>
Route storages history tables to `RocksDB` instead of MDBX.
This is a genesis-initialization-only flag: changing it after genesis requires a re-sync. Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--rocksdb.account-history <ACCOUNT_HISTORY>
Route account history tables to `RocksDB` instead of MDBX.
This is a genesis-initialization-only flag: changing it after genesis requires a re-sync. Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
Storage:
--storage.v2
Enable v2 storage defaults (static files + `RocksDB` routing).
@@ -192,13 +121,6 @@ Storage:
Individual settings can still be overridden with `--static-files.*` and `--rocksdb.*` flags.
--storage.use-hashed-state
Use hashed state tables (`HashedAccounts`/`HashedStorages`) as canonical state representation instead of plain state tables.
When enabled, execution writes directly to hashed tables, eliminating the need for separate hashing stages. This should only be enabled for new databases.
WARNING: Changing this setting on an existing database requires a full resync.
Logging:
--log.stdout.format <FORMAT>
The format to use for logs written to stdout

View File

@@ -912,33 +912,6 @@ Pruning:
--prune.bodies.before <BLOCK_NUMBER>
Prune storage history before the specified block number. The specified block number is not pruned
RocksDB:
--rocksdb.all
Route all supported tables to `RocksDB` instead of MDBX.
This enables `RocksDB` for `tx-hash`, `storages-history`, and `account-history` tables. Cannot be combined with individual flags set to false.
--rocksdb.tx-hash <TX_HASH>
Route tx hash -> number table to `RocksDB` instead of MDBX.
This is a genesis-initialization-only flag: changing it after genesis requires a re-sync. Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--rocksdb.storages-history <STORAGES_HISTORY>
Route storages history tables to `RocksDB` instead of MDBX.
This is a genesis-initialization-only flag: changing it after genesis requires a re-sync. Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--rocksdb.account-history <ACCOUNT_HISTORY>
Route account history tables to `RocksDB` instead of MDBX.
This is a genesis-initialization-only flag: changing it after genesis requires a re-sync. Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
Engine:
--engine.persistence-threshold <PERSISTENCE_THRESHOLD>
Configure persistence threshold for the engine. This determines how many canonical blocks must be in-memory, ahead of the last persisted block, before flushing canonical blocks to disk again.
@@ -1073,50 +1046,6 @@ Static Files:
--static-files.blocks-per-file.storage-change-sets <BLOCKS_PER_FILE_STORAGE_CHANGE_SETS>
Number of blocks per file for the storage changesets segment
--static-files.receipts <RECEIPTS>
Store receipts in static files instead of the database.
When enabled, receipts will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--static-files.transaction-senders <TRANSACTION_SENDERS>
Store transaction senders in static files instead of the database.
When enabled, transaction senders will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--static-files.account-change-sets <ACCOUNT_CHANGESETS>
Store account changesets in static files.
When enabled, account changesets will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--static-files.storage-change-sets <STORAGE_CHANGESETS>
Store storage changesets in static files.
When enabled, storage changesets will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
Storage:
--storage.v2
Enable v2 storage defaults (static files + `RocksDB` routing).
@@ -1127,13 +1056,6 @@ Storage:
Individual settings can still be overridden with `--static-files.*` and `--rocksdb.*` flags.
--storage.use-hashed-state
Use hashed state tables (`HashedAccounts`/`HashedStorages`) as canonical state representation instead of plain state tables.
When enabled, execution writes directly to hashed tables, eliminating the need for separate hashing stages. This should only be enabled for new databases.
WARNING: Changing this setting on an existing database requires a full resync.
Logging:
--log.stdout.format <FORMAT>
The format to use for logs written to stdout

View File

@@ -111,77 +111,6 @@ Static Files:
--static-files.blocks-per-file.storage-change-sets <BLOCKS_PER_FILE_STORAGE_CHANGE_SETS>
Number of blocks per file for the storage changesets segment
--static-files.receipts <RECEIPTS>
Store receipts in static files instead of the database.
When enabled, receipts will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--static-files.transaction-senders <TRANSACTION_SENDERS>
Store transaction senders in static files instead of the database.
When enabled, transaction senders will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--static-files.account-change-sets <ACCOUNT_CHANGESETS>
Store account changesets in static files.
When enabled, account changesets will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--static-files.storage-change-sets <STORAGE_CHANGESETS>
Store storage changesets in static files.
When enabled, storage changesets will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
RocksDB:
--rocksdb.all
Route all supported tables to `RocksDB` instead of MDBX.
This enables `RocksDB` for `tx-hash`, `storages-history`, and `account-history` tables. Cannot be combined with individual flags set to false.
--rocksdb.tx-hash <TX_HASH>
Route tx hash -> number table to `RocksDB` instead of MDBX.
This is a genesis-initialization-only flag: changing it after genesis requires a re-sync. Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--rocksdb.storages-history <STORAGES_HISTORY>
Route storages history tables to `RocksDB` instead of MDBX.
This is a genesis-initialization-only flag: changing it after genesis requires a re-sync. Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--rocksdb.account-history <ACCOUNT_HISTORY>
Route account history tables to `RocksDB` instead of MDBX.
This is a genesis-initialization-only flag: changing it after genesis requires a re-sync. Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
Storage:
--storage.v2
Enable v2 storage defaults (static files + `RocksDB` routing).
@@ -192,13 +121,6 @@ Storage:
Individual settings can still be overridden with `--static-files.*` and `--rocksdb.*` flags.
--storage.use-hashed-state
Use hashed state tables (`HashedAccounts`/`HashedStorages`) as canonical state representation instead of plain state tables.
When enabled, execution writes directly to hashed tables, eliminating the need for separate hashing stages. This should only be enabled for new databases.
WARNING: Changing this setting on an existing database requires a full resync.
Metrics:
--metrics <PROMETHEUS>
Enable Prometheus metrics.

View File

@@ -111,77 +111,6 @@ Static Files:
--static-files.blocks-per-file.storage-change-sets <BLOCKS_PER_FILE_STORAGE_CHANGE_SETS>
Number of blocks per file for the storage changesets segment
--static-files.receipts <RECEIPTS>
Store receipts in static files instead of the database.
When enabled, receipts will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--static-files.transaction-senders <TRANSACTION_SENDERS>
Store transaction senders in static files instead of the database.
When enabled, transaction senders will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--static-files.account-change-sets <ACCOUNT_CHANGESETS>
Store account changesets in static files.
When enabled, account changesets will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--static-files.storage-change-sets <STORAGE_CHANGESETS>
Store storage changesets in static files.
When enabled, storage changesets will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
RocksDB:
--rocksdb.all
Route all supported tables to `RocksDB` instead of MDBX.
This enables `RocksDB` for `tx-hash`, `storages-history`, and `account-history` tables. Cannot be combined with individual flags set to false.
--rocksdb.tx-hash <TX_HASH>
Route tx hash -> number table to `RocksDB` instead of MDBX.
This is a genesis-initialization-only flag: changing it after genesis requires a re-sync. Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--rocksdb.storages-history <STORAGES_HISTORY>
Route storages history tables to `RocksDB` instead of MDBX.
This is a genesis-initialization-only flag: changing it after genesis requires a re-sync. Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--rocksdb.account-history <ACCOUNT_HISTORY>
Route account history tables to `RocksDB` instead of MDBX.
This is a genesis-initialization-only flag: changing it after genesis requires a re-sync. Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
Storage:
--storage.v2
Enable v2 storage defaults (static files + `RocksDB` routing).
@@ -192,13 +121,6 @@ Storage:
Individual settings can still be overridden with `--static-files.*` and `--rocksdb.*` flags.
--storage.use-hashed-state
Use hashed state tables (`HashedAccounts`/`HashedStorages`) as canonical state representation instead of plain state tables.
When enabled, execution writes directly to hashed tables, eliminating the need for separate hashing stages. This should only be enabled for new databases.
WARNING: Changing this setting on an existing database requires a full resync.
--from <FROM>
The height to start at

View File

@@ -111,77 +111,6 @@ Static Files:
--static-files.blocks-per-file.storage-change-sets <BLOCKS_PER_FILE_STORAGE_CHANGE_SETS>
Number of blocks per file for the storage changesets segment
--static-files.receipts <RECEIPTS>
Store receipts in static files instead of the database.
When enabled, receipts will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--static-files.transaction-senders <TRANSACTION_SENDERS>
Store transaction senders in static files instead of the database.
When enabled, transaction senders will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--static-files.account-change-sets <ACCOUNT_CHANGESETS>
Store account changesets in static files.
When enabled, account changesets will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--static-files.storage-change-sets <STORAGE_CHANGESETS>
Store storage changesets in static files.
When enabled, storage changesets will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
RocksDB:
--rocksdb.all
Route all supported tables to `RocksDB` instead of MDBX.
This enables `RocksDB` for `tx-hash`, `storages-history`, and `account-history` tables. Cannot be combined with individual flags set to false.
--rocksdb.tx-hash <TX_HASH>
Route tx hash -> number table to `RocksDB` instead of MDBX.
This is a genesis-initialization-only flag: changing it after genesis requires a re-sync. Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--rocksdb.storages-history <STORAGES_HISTORY>
Route storages history tables to `RocksDB` instead of MDBX.
This is a genesis-initialization-only flag: changing it after genesis requires a re-sync. Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--rocksdb.account-history <ACCOUNT_HISTORY>
Route account history tables to `RocksDB` instead of MDBX.
This is a genesis-initialization-only flag: changing it after genesis requires a re-sync. Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
Storage:
--storage.v2
Enable v2 storage defaults (static files + `RocksDB` routing).
@@ -192,13 +121,6 @@ Storage:
Individual settings can still be overridden with `--static-files.*` and `--rocksdb.*` flags.
--storage.use-hashed-state
Use hashed state tables (`HashedAccounts`/`HashedStorages`) as canonical state representation instead of plain state tables.
When enabled, execution writes directly to hashed tables, eliminating the need for separate hashing stages. This should only be enabled for new databases.
WARNING: Changing this setting on an existing database requires a full resync.
<STAGE>
Possible values:
- headers: The headers stage within the pipeline

View File

@@ -118,77 +118,6 @@ Static Files:
--static-files.blocks-per-file.storage-change-sets <BLOCKS_PER_FILE_STORAGE_CHANGE_SETS>
Number of blocks per file for the storage changesets segment
--static-files.receipts <RECEIPTS>
Store receipts in static files instead of the database.
When enabled, receipts will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--static-files.transaction-senders <TRANSACTION_SENDERS>
Store transaction senders in static files instead of the database.
When enabled, transaction senders will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--static-files.account-change-sets <ACCOUNT_CHANGESETS>
Store account changesets in static files.
When enabled, account changesets will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--static-files.storage-change-sets <STORAGE_CHANGESETS>
Store storage changesets in static files.
When enabled, storage changesets will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
RocksDB:
--rocksdb.all
Route all supported tables to `RocksDB` instead of MDBX.
This enables `RocksDB` for `tx-hash`, `storages-history`, and `account-history` tables. Cannot be combined with individual flags set to false.
--rocksdb.tx-hash <TX_HASH>
Route tx hash -> number table to `RocksDB` instead of MDBX.
This is a genesis-initialization-only flag: changing it after genesis requires a re-sync. Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--rocksdb.storages-history <STORAGES_HISTORY>
Route storages history tables to `RocksDB` instead of MDBX.
This is a genesis-initialization-only flag: changing it after genesis requires a re-sync. Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--rocksdb.account-history <ACCOUNT_HISTORY>
Route account history tables to `RocksDB` instead of MDBX.
This is a genesis-initialization-only flag: changing it after genesis requires a re-sync. Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
Storage:
--storage.v2
Enable v2 storage defaults (static files + `RocksDB` routing).
@@ -199,13 +128,6 @@ Storage:
Individual settings can still be overridden with `--static-files.*` and `--rocksdb.*` flags.
--storage.use-hashed-state
Use hashed state tables (`HashedAccounts`/`HashedStorages`) as canonical state representation instead of plain state tables.
When enabled, execution writes directly to hashed tables, eliminating the need for separate hashing stages. This should only be enabled for new databases.
WARNING: Changing this setting on an existing database requires a full resync.
Logging:
--log.stdout.format <FORMAT>
The format to use for logs written to stdout

View File

@@ -111,77 +111,6 @@ Static Files:
--static-files.blocks-per-file.storage-change-sets <BLOCKS_PER_FILE_STORAGE_CHANGE_SETS>
Number of blocks per file for the storage changesets segment
--static-files.receipts <RECEIPTS>
Store receipts in static files instead of the database.
When enabled, receipts will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--static-files.transaction-senders <TRANSACTION_SENDERS>
Store transaction senders in static files instead of the database.
When enabled, transaction senders will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--static-files.account-change-sets <ACCOUNT_CHANGESETS>
Store account changesets in static files.
When enabled, account changesets will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--static-files.storage-change-sets <STORAGE_CHANGESETS>
Store storage changesets in static files.
When enabled, storage changesets will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
RocksDB:
--rocksdb.all
Route all supported tables to `RocksDB` instead of MDBX.
This enables `RocksDB` for `tx-hash`, `storages-history`, and `account-history` tables. Cannot be combined with individual flags set to false.
--rocksdb.tx-hash <TX_HASH>
Route tx hash -> number table to `RocksDB` instead of MDBX.
This is a genesis-initialization-only flag: changing it after genesis requires a re-sync. Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--rocksdb.storages-history <STORAGES_HISTORY>
Route storages history tables to `RocksDB` instead of MDBX.
This is a genesis-initialization-only flag: changing it after genesis requires a re-sync. Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--rocksdb.account-history <ACCOUNT_HISTORY>
Route account history tables to `RocksDB` instead of MDBX.
This is a genesis-initialization-only flag: changing it after genesis requires a re-sync. Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
Storage:
--storage.v2
Enable v2 storage defaults (static files + `RocksDB` routing).
@@ -192,13 +121,6 @@ Storage:
Individual settings can still be overridden with `--static-files.*` and `--rocksdb.*` flags.
--storage.use-hashed-state
Use hashed state tables (`HashedAccounts`/`HashedStorages`) as canonical state representation instead of plain state tables.
When enabled, execution writes directly to hashed tables, eliminating the need for separate hashing stages. This should only be enabled for new databases.
WARNING: Changing this setting on an existing database requires a full resync.
--metrics <SOCKET>
Enable Prometheus metrics.

View File

@@ -116,77 +116,6 @@ Static Files:
--static-files.blocks-per-file.storage-change-sets <BLOCKS_PER_FILE_STORAGE_CHANGE_SETS>
Number of blocks per file for the storage changesets segment
--static-files.receipts <RECEIPTS>
Store receipts in static files instead of the database.
When enabled, receipts will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--static-files.transaction-senders <TRANSACTION_SENDERS>
Store transaction senders in static files instead of the database.
When enabled, transaction senders will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--static-files.account-change-sets <ACCOUNT_CHANGESETS>
Store account changesets in static files.
When enabled, account changesets will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--static-files.storage-change-sets <STORAGE_CHANGESETS>
Store storage changesets in static files.
When enabled, storage changesets will be written to static files on disk instead of the database.
Note: This setting can only be configured at genesis initialization. Once the node has been initialized, changing this flag requires re-syncing from scratch.
Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
RocksDB:
--rocksdb.all
Route all supported tables to `RocksDB` instead of MDBX.
This enables `RocksDB` for `tx-hash`, `storages-history`, and `account-history` tables. Cannot be combined with individual flags set to false.
--rocksdb.tx-hash <TX_HASH>
Route tx hash -> number table to `RocksDB` instead of MDBX.
This is a genesis-initialization-only flag: changing it after genesis requires a re-sync. Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--rocksdb.storages-history <STORAGES_HISTORY>
Route storages history tables to `RocksDB` instead of MDBX.
This is a genesis-initialization-only flag: changing it after genesis requires a re-sync. Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
--rocksdb.account-history <ACCOUNT_HISTORY>
Route account history tables to `RocksDB` instead of MDBX.
This is a genesis-initialization-only flag: changing it after genesis requires a re-sync. Defaults to the base storage mode (v1: false, v2: true).
[possible values: true, false]
Storage:
--storage.v2
Enable v2 storage defaults (static files + `RocksDB` routing).
@@ -197,13 +126,6 @@ Storage:
Individual settings can still be overridden with `--static-files.*` and `--rocksdb.*` flags.
--storage.use-hashed-state
Use hashed state tables (`HashedAccounts`/`HashedStorages`) as canonical state representation instead of plain state tables.
When enabled, execution writes directly to hashed tables, eliminating the need for separate hashing stages. This should only be enabled for new databases.
WARNING: Changing this setting on an existing database requires a full resync.
--offline
If this is enabled, then all stages except headers, bodies, and sender recovery will be unwound

View File

@@ -10,21 +10,19 @@ Reth is production ready, and suitable for usage in mission-critical environment
![Reth](https://raw.githubusercontent.com/paradigmxyz/reth/main/assets/reth-prod.png)
## What is this about?
## What is Reth?
[Reth](https://github.com/paradigmxyz/reth/) is an execution layer (EL) implementation that is compatible with all Ethereum consensus layer (CL) implementations that support the [Engine API](https://github.com/ethereum/execution-apis/tree/59e3a719021f48c1ef5653840e3ea5750e6af693/src/engine).
[Reth](https://github.com/paradigmxyz/reth/) is an execution layer (EL) implementation that is compatible with all Ethereum consensus layer (CL) implementations that support the [Engine API](https://github.com/ethereum/execution-apis/tree/main/src/engine).
It is originally built and driven forward by [Paradigm](https://paradigm.xyz/), and is licensed under the Apache and MIT licenses.
As a full Ethereum node, Reth allows users to connect to the Ethereum network and interact with the Ethereum blockchain.
As a full Ethereum node, Reth allows users to connect to the Ethereum network and interact with the Ethereum blockchain. This includes sending and receiving transactions, querying logs and traces, as well as accessing and interacting with smart contracts.
This includes sending and receiving transactions, querying logs and traces, as well as accessing and interacting with smart contracts.
## Goals
Building a successful Ethereum node requires creating a high-quality implementation that is both secure and efficient, as well as being easy to use on consumer hardware. It also requires building a strong community of contributors who can help support and improve the software.
## What are the goals of Reth?
**1. Modularity**
### Modularity
Every component of Reth is built to be used as a library: well-tested, heavily documented and benchmarked. We envision that developers will import the node's crates, mix and match, and innovate on top of them.
@@ -32,23 +30,23 @@ Examples of such usage include, but are not limited to, spinning up standalone P
To achieve that, we are licensing Reth under the Apache/MIT permissive license.
**2. Performance**
### Performance
Reth aims to be fast, so we used Rust and the [Erigon staged-sync](https://erigon.substack.com/p/erigon-stage-sync-and-control-flows) node architecture.
We also use our Ethereum libraries (including [Alloy](https://github.com/alloy-rs/alloy/) and [revm](https://github.com/bluealloy/revm/)) which weve battle-tested and optimized via [Foundry](https://github.com/foundry-rs/foundry/).
We also use our Ethereum libraries (including [Alloy](https://github.com/alloy-rs/alloy/) and [revm](https://github.com/bluealloy/revm/)) which we've battle-tested and optimized via [Foundry](https://github.com/foundry-rs/foundry/).
**3. Free for anyone to use any way they want**
### Free for anyone to use any way they want
Reth is free open-source software, built for the community, by the community.
By licensing the software under the Apache/MIT license, we want developers to use it without being bound by business licenses, or having to think about the implications of GPL-like licenses.
**4. Client Diversity**
### Client Diversity
The Ethereum protocol becomes more antifragile when no node implementation dominates. This ensures that if there's a software bug, the network does not finalize a bad block. By building a new client, we hope to contribute to Ethereum's antifragility.
**5. Used by a wide demographic**
### Used by a wide demographic
We want to solve for node operators that care about fast historical queries, but also for hobbyists who cannot operate on large hardware.
@@ -60,8 +58,8 @@ We envision that Reth will be configurable enough for the tradeoffs that each te
Reth is a new Ethereum full node that allows users to sync and interact with the entire blockchain, including its historical state if in archive mode.
- Full node: It can be used as a full node, which stores and processes the entire blockchain, validates blocks and transactions, and participates in the consensus process.
- Archive node: It can also be used as an archive node, which stores the entire history of the blockchain and is useful for applications that need access to historical data.
- **Full node**: Stores and processes the entire blockchain, validates blocks and transactions, and participates in the consensus process.
- **Archive node**: Stores the entire history of the blockchain and is useful for applications that need access to historical data.
As a data engineer/analyst, or as a data indexer, you'll want to use Archive mode. For all other use cases where historical access is not needed, you can use Full mode.
@@ -77,7 +75,7 @@ Reth implements the specification of Ethereum as defined in the [ethereum/execut
We have completed an audit of the [Reth v1.0.0-rc.2](https://github.com/paradigmxyz/reth/releases/tag/v1.0.0-rc.2) with [Sigma Prime](https://sigmaprime.io/), the developers of [Lighthouse](https://github.com/sigp/lighthouse), the Rust Consensus Layer implementation. Find it [here](https://github.com/paradigmxyz/reth/blob/main/audit/sigma_prime_audit_v2.pdf).
[Revm](https://github.com/bluealloy/revm) (the EVM used in Reth) underwent an audit with [Guido Vranken](https://twitter.com/guidovranken) (#1 [Ethereum Bug Bounty](https://ethereum.org/en/bug-bounty)). We will publish the results soon.
[Revm](https://github.com/bluealloy/revm) (the EVM used in Reth) underwent an audit with [Guido Vranken](https://twitter.com/guidovranken) (#1 [Ethereum Bug Bounty](https://ethereum.org/en/bug-bounty)).
## Reth Metrics
@@ -94,21 +92,18 @@ We operate several public Reth nodes across different networks. You can monitor
Want to set up metrics for your own Reth node? Check out our [monitoring guide](/run/monitoring) to learn how to configure Prometheus metrics and build your own dashboards.
:::
## Sections
## Get started
Here are some useful sections to jump to:
- Install Reth by following the [guide](/installation/overview).
- Sync your node on any [official network](/run/overview).
- View [statistics and metrics](/run/monitoring) about your node.
- Query the [JSON-RPC](/jsonrpc/intro) using Foundry's `cast` or `curl`.
- Set up your [development environment and contribute](/introduction/contributing)!
- [Install Reth](/installation/overview) and get up and running.
- [Run a node](/run/overview) on any official network.
- [Monitor your node](/run/monitoring) with statistics and metrics.
- [Query the JSON-RPC](/jsonrpc/intro) using Foundry's `cast` or `curl`.
- [Explore the SDK](/sdk) to build custom blockchain infrastructure.
- [Set up your development environment and contribute](/introduction/contributing)!
:::note
The documentation is continuously rendered [here](https://reth.rs)!
You can contribute to the docs on [GitHub][gh-docs].
:::
[tg-badge]: https://img.shields.io/endpoint?color=neon&logo=telegram&label=chat&url=https%3A%2F%2Ftg.sumanjay.workers.dev%2Fparadigm%5Freth
[tg-url]: https://t.me/paradigm_reth
[gh-docs]: https://github.com/paradigmxyz/reth/tree/main/docs

View File

@@ -65,6 +65,10 @@ export const rethCliSidebar: SidebarItem = {
}
]
},
{
text: "reth db copy",
link: "/cli/reth/db/copy"
},
{
text: "reth db diff",
link: "/cli/reth/db/diff"
@@ -145,36 +149,8 @@ export const rethCliSidebar: SidebarItem = {
collapsed: true,
items: [
{
text: "reth db settings set receipts",
link: "/cli/reth/db/settings/set/receipts"
},
{
text: "reth db settings set transaction_senders",
link: "/cli/reth/db/settings/set/transaction_senders"
},
{
text: "reth db settings set account_changesets",
link: "/cli/reth/db/settings/set/account_changesets"
},
{
text: "reth db settings set storages_history",
link: "/cli/reth/db/settings/set/storages_history"
},
{
text: "reth db settings set transaction_hash_numbers",
link: "/cli/reth/db/settings/set/transaction_hash_numbers"
},
{
text: "reth db settings set account_history",
link: "/cli/reth/db/settings/set/account_history"
},
{
text: "reth db settings set storage_changesets",
link: "/cli/reth/db/settings/set/storage_changesets"
},
{
text: "reth db settings set use_hashed_state",
link: "/cli/reth/db/settings/set/use_hashed_state"
text: "reth db settings set v2",
link: "/cli/reth/db/settings/set/v2"
}
]
}

View File

@@ -22,7 +22,7 @@ export default defineConfig({
},
{ text: 'GitHub', link: 'https://github.com/paradigmxyz/reth' },
{
text: 'v1.10.2',
text: 'v1.11.3',
items: [
{
text: 'Releases',