Are you an LLM? Read llms.txt for a summary of the docs, or llms-full.txt for the full context.
Skip to content

Storage (StableDB)

Stable v1.8.0 uses MemIAVL instead of the previous LevelDB-backed state store. MemIAVL keeps one state snapshot in a memory-mapped file and records each new block's changes in a sequential write-ahead log.

Why disk I/O is a bottleneck

Every block changes the application state. A node must complete two related tasks:

  1. State commitment: calculate and commit the root hash for the new state.
  2. State persistence: write the changed data to storage so the node can recover it later.
Coupled State Commitment and Storage

The previous LevelDB-backed store coupled these tasks. It also rewrote data during background compaction, which reorganizes stored records to make later reads efficient.

One logical state update could cause 10–50 times as much physical disk writing. This is called write amplification. Execution then had to wait for a storage path dominated by random writes and compaction.

How MemIAVL changes the store

A memory-mapped file, or mmap, lets the operating system expose file contents through memory addresses. The node can read state by following pointers, while the operating system loads the required pages into its page cache.

MemIAVL combines two structures:

  • Snapshot: one memory-mapped representation of the persisted state tree.
  • Write-ahead log (WAL): an append-only record of raw changes made after that snapshot.
Decoupled State Commitment and Storage

Write path

Each block appends its change set to the WAL in sequence. MemIAVL does not route the update through LevelDB or trigger compaction. Write amplification therefore falls from 10–50 times to approximately one write.

MemIAVL also separates tree nodes into two categories:

  • PersistedNode represents an unchanged subtree already stored in the snapshot.
  • MemNode represents a subtree changed in memory by the current updates.

When MemIAVL calculates the next root hash, it stops at unchanged PersistedNode subtrees. It hashes only the paths containing new MemNode data.

Read path

Current-state reads follow pointers into the memory-mapped snapshot. Frequently accessed pages remain in the operating system's page cache, so the node avoids a separate database lookup for each tree node.

Historical state and VersionDB

MemIAVL serves the current state and the snapshots a node retains. A companion VersionDB stores historical versions in a RocksDB sidecar.

You need VersionDB when the node must answer historical state queries older than its earliest retained MemIAVL snapshot. This is especially important for archive nodes and RPC services that expose long-range queries.

Upgrade considerations

Stable Mainnet activated v1.8.0 at block 36,976,000. The documented upgrade replaced the binary and both configuration files without a state export or snapshot reset.

The v1.8.0 configuration files add settings used by the new storage and proposal paths. Back up config.toml and app.toml, install the v1.8.0 templates, then restore every node-specific setting.

Archive-node operators must also restore their previous pruning settings. The distributed app.toml template uses default pruning, and pruned history cannot be recovered from the local node.

Further reading

For more technical deep-dives and implementation details, refer to:

Where to go next

  • High performance RPC: See how the RPC layer exposes state reads without contending with writes.
  • Execution: Understand how execution writes into the storage layer covered here.
  • Upgrade a node: Prepare backups and verify a node after a coordinated upgrade.
  • Network upgrades: Review the v1.8.0 scope and activation details.