core, eth: disable pathdb snapshot generation for partial state

Geth has two independent snapshot tiers, each with its own disable
mechanism:

1. In-memory snapshot cache: controlled by SnapshotLimit (derived from
   ethconfig.SnapshotCache). Setting SnapshotCache=0 disables it.

2. On-disk snapshot generator: a background goroutine in pathdb that
   iterates the entire state trie to build flat key-value snapshots.
   Controlled by pathdb.Config.SnapshotNoBuild.

The partial state configuration (cmd/utils/flags.go) already set
SnapshotCache=0 to disable the in-memory cache. However, SnapshotNoBuild
was never set, so pathdb.Enable() — called after snap sync completes —
still launched the background generator goroutine.

This generator immediately hits missing storage tries for untracked
contracts (whose storage was intentionally skipped during partial sync),
logs "Trie missing, snapshotting paused", and blocks forever on its
abort channel — a permanent goroutine leak with no recovery path.

Additionally, BlockChainConfig.SnapshotNoBuild was never propagated to
pathdb.Config.SnapshotNoBuild in the triedbConfig() conversion. The
field only reached the hash-scheme snapshot module (core/blockchain.go
setupSnapshot), which is already skipped for path-scheme databases. This
plumbing gap meant pathdb.Config.SnapshotNoBuild was never set in
production code — only in tests.

Fix both issues:
- Set SnapshotNoBuild=true when partial state is enabled
- Propagate BlockChainConfig.SnapshotNoBuild into pathdb.Config
This commit is contained in:
CPerezz 2026-02-08 15:07:26 +01:00
parent c6f49c4708
commit 4cd7b3ba6c
No known key found for this signature in database
GPG key ID: 62045F34B97177DD
2 changed files with 3 additions and 1 deletions

View file

@ -314,7 +314,8 @@ func (cfg *BlockChainConfig) triedbConfig(isVerkle bool) *triedb.Config {
FullValueCheckpoint: cfg.NodeFullValueCheckpoint,
// Testing configurations
NoAsyncFlush: cfg.TrieNoAsyncFlush,
NoAsyncFlush: cfg.TrieNoAsyncFlush,
SnapshotNoBuild: cfg.SnapshotNoBuild,
}
}
return config

View file

@ -290,6 +290,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
options.PartialStateContracts = config.PartialState.Contracts
options.PartialStateBALRetention = config.PartialState.BALRetention
options.PartialStateChainRetention = config.PartialState.ChainRetention
options.SnapshotNoBuild = true
}
eth.blockchain, err = core.NewBlockChain(chainDb, config.Genesis, eth.engine, options)