Purpose and Scope
This document describes the multi-layer caching mechanisms and snapshot system used in StableNet to optimize state access.The caching architecture ranges from in-memory LRU caches for frequently accessed data to a state snapshot system that provides fast access to account and storage data without traversing the trie. For the underlying Merkle Patricia Trie data structure and database interfaces, see Database Layer and Merkle Patricia Trie.
For historical data management and archive strategies, see Ancient Store and Data Lifecycle.
StateDB Caching Architecture
StateDB acts as the top-level caching layer for all blockchain state and maintains multiple in-memory data structures to minimize repeated and expensive trie and database accesses during transaction execution.Account and Storage Cache Maps
StateDB maintains the following cache maps to track state changes during block execution:| Cache Map | Type | Purpose |
|---|---|---|
stateObjects | map[common.Address]*stateObject | Live account objects modified during execution |
accounts | map[common.Hash][]byte | Slim RLP-encoded account data for commit |
storages | map[common.Hash]map[common.Hash][]byte | Storage slot changes to be committed |
accountsOrigin | map[common.Address][]byte | Pre-change account state (for diff computation) |
storagesOrigin | map[common.Address]map[common.Hash][]byte | Pre-change storage state (for diff computation) |
stateObjectsPending | map[common.Address]struct{} | Objects finalised but not yet applied to trie |
stateObjectsDirty | map[common.Address]struct{} | Objects modified in the current execution |
stateObjectsDestruct | map[common.Address]*types.StateAccount | Accounts self-destructed within the block |
stateObjects is the live state object cache maintained during execution of the current block.Each account is loaded only once on first access and reused thereafter. Account loading flow summary:
- Check the
stateObjectscache - If missing, attempt to load from snapshot
- If snapshot is unavailable or misses, load from trie
- Create a
stateObjectwrapper - Cache in
stateObjectsand return
State Object Storage Caching
EachstateObject maintains a three-tier storage cache for storage slot access.
Storage tiers and their roles:
- dirtyStorage
Slots modified in the current transaction. Cleared at transaction end. - pendingStorage
Changes that are finalised but not yet committed to the trie. - originStorage
Baseline state loaded from snapshot or trie.
- Transaction-level rollback capability
- Avoidance of duplicate trie writes for the same slot
- Accurate diff computation of state changes
State Snapshot System
The snapshot system provides a flat state representation that allows account and storage data to be queried without directly traversing the Merkle Patricia Trie.It plays a critical role in both snap synchronization and normal block execution performance.
Snapshot Architecture
The snapshot system consists of three components:- Disk Layer
A persistent snapshot at a specific block height, holding flat mappings of
account hash → account data, and storage hash → storage value. - Diff Layers
In-memory chained layers that store per-block state changes.
Only modified accounts and storage slots are stored. - Snapshot Tree
Manages snapshots per state root and provides theSnapshot(root)interface.
Snapshot-Based State Access
When snapshots are enabled, StateDB queries state in the following order:- Account lookup:
snap.Account(hash) - Storage lookup:
snap.Storage(addrHash, slotHash) - Fallback to trie only on miss
- No trie node decoding
- No hash verification
- Direct access to flat structures
- Typically 10–100× faster account lookups
Trie Prefetcher
The trie prefetcher proactively loads trie nodes that are likely to be accessed during transaction execution, reducing commit latency. Execution flow:StartPrefetcher()is called at block execution start- Modified storage slot information is collected during
finalise() - Worker goroutines asynchronously load trie nodes along those paths
- Cached tries are reused during
IntermediateRoot()or commit StopPrefetcher()is called at block end for cleanup
Journal and Snapshot Rollback
StateDB supports rolling back to previous states at any point during transaction execution via journal-based change tracking. Each state change is recorded as ajournalEntry, including:
- Balance changes
- Nonce changes
- Code changes
- Storage updates
- Selfdestruct operations
- Account creation
Snapshot() is called, the current journal length is recorded.Calling
RevertToSnapshot() replays the journal in reverse to restore state.
This mechanism is essential for:
- EVM
REVERT - Out-of-gas handling
- Exception recovery
- Speculative execution
State Commit and Cache Management
State commit proceeds in three stages.Stage 1: Finalise
- Clean up dirty objects
- Process selfdestructs
- Move
dirtyStorage→pendingStorage - Clear the journal
Stage 2: IntermediateRoot
- Hash storage tries of all pending objects
- Update the account trie
- Compute the intermediate state root
Stage 3: Commit
- Commit all storage tries
- Commit the account trie
- Generate a
NodeSetfor modified nodes - Persist changes in batch via
triedb.Update()
Fast Storage Deletion
Deleting large storage tries via full traversal is inefficient.StateDB provides a fast deletion path using snapshots. How it works:
- Iterate flat storage slots from the snapshot
- Build an in-memory StackTrie
- Generate delete markers for each node
- Fallback to the slow path if size limits are exceeded
- Return a
NodeSetcontaining delete markers
StateDB Copy Semantics
StateDB.Copy() is used for parallel execution and speculative state creation.
Shared (read-only):
- Database interface
- Snapshot tree
- Base tries
- State object maps
- Change-tracking maps
- Journal
- Logs and preimages
- Access lists and transient storage
- Parallel transaction execution
- Minimal memory duplication
- Complete isolation between state instances
Performance Metrics and Instrumentation
StateDB collects detailed metrics across state processing. Example metrics include:- Account and storage read latency
- Trie hashing time
- Commit time
- Snapshot access time
- Number of updates and deletions
- Bottleneck identification
- Cache hit-rate analysis
- Snapshot effectiveness validation
- Performance regression detection
Cleanup and Cache Eviction
Snapshot-Based Cleanup
- Merge old diff layers
- Refresh the disk layer
- Optionally remove obsolete trie nodes
Cache Eviction Strategies
- Trie node LRU caches
- Separation of clean and dirty caches
- Dirty caches evicted after commit
Memory Management
- Journal cleanup at transaction end
- Reset pending objects
- Stop prefetcher
- Structure sharing during StateDB copies

