> ## Documentation Index
> Fetch the complete documentation index at: https://docs.intention.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Storage and proofs

> How committed state is persisted across three RocksDB stores, authenticated by a versioned Merkle tree and accumulators, and pruned over time.

Committed state has to satisfy two demands that pull against each other. Execution wants the current value of a key, fast, millions of times. Verification wants a proof that a value was what the network says it was at a particular version. Serving both from one structure means doing both badly.

Storage therefore splits the problem across separate stores, each shaped for its own access pattern.

## Three stores

<div className="dg" data-dg="storage-stores">
  <div className="dg-c" style={{aspectRatio:"720 / 332"}}>
    <svg className="dg-w" viewBox="0 0 720 332" aria-hidden="true">
      <path className="dg-wire dg--green dg-dash" d="M 434.00 48.00 L 459.60 48.00" />

      <path className="dg-head dg--green" d="M 466.00 48.00 L 459.60 52.40 L 459.60 43.60 Z" />

      <path className="dg-wire dg--green dg-dash" d="M 434.00 144.00 L 459.60 144.00" />

      <path className="dg-head dg--green" d="M 466.00 144.00 L 459.60 148.40 L 459.60 139.60 Z" />

      <path className="dg-wire dg--green dg-dash" d="M 434.00 240.00 L 459.60 240.00" />

      <path className="dg-head dg--green" d="M 466.00 240.00 L 459.60 244.40 L 459.60 235.60 Z" />

      <path className="dg-wire dg--blue dg-soft" d="M 135.00 144.00 L 172.54 53.91" />

      <path className="dg-head dg--blue" d="M 175.00 48.00 L 176.60 55.60 L 168.48 52.22 Z" />

      <path className="dg-wire dg--blue dg-soft" d="M 135.00 144.00 L 168.60 144.00" />

      <path className="dg-head dg--blue" d="M 175.00 144.00 L 168.60 148.40 L 168.60 139.60 Z" />

      <path className="dg-wire dg--blue dg-soft" d="M 135.00 144.00 L 172.54 234.09" />

      <path className="dg-head dg--blue" d="M 175.00 240.00 L 168.48 235.78 L 176.60 232.40 Z" />
    </svg>

    <div className="dg-b dg--blue" style={{left:"0.0000%",top:"31.3253%",width:"18.0556%",height:"24.0964%"}}><span className="dg-t">Committed block</span></div>
    <div className="dg-b dg--sky dg-left" style={{left:"25.0000%",top:"2.4096%",width:"34.7222%",height:"24.0964%"}}><span className="dg-t">Ledger store</span><span className="dg-s">transactions · outputs · events · write sets · accumulators · block metadata</span></div>
    <div className="dg-b dg--green" style={{left:"65.2778%",top:"2.4096%",width:"34.7222%",height:"24.0964%"}}><span className="dg-t">Replay and audit</span></div>
    <div className="dg-b dg--sky dg-left" style={{left:"25.0000%",top:"31.3253%",width:"34.7222%",height:"24.0964%"}}><span className="dg-t">State KV store</span><span className="dg-s">current and historical values, sharded sixteen ways, hot state in its own tier</span></div>
    <div className="dg-b dg--green" style={{left:"65.2778%",top:"31.3253%",width:"34.7222%",height:"24.0964%"}}><span className="dg-t">Queries and execution</span></div>
    <div className="dg-b dg--sky dg-left" style={{left:"25.0000%",top:"60.2410%",width:"34.7222%",height:"24.0964%"}}><span className="dg-t">State Merkle store</span><span className="dg-s">a versioned sparse Merkle tree, plus the indexes tracking superseded nodes</span></div>
    <div className="dg-b dg--green" style={{left:"65.2778%",top:"60.2410%",width:"34.7222%",height:"24.0964%"}}><span className="dg-t">Verification — proofs</span></div>
    <div className="dg-free" style={{left:"0.0000%",top:"89.1566%",width:"100.0000%"}}><div className="dg-n">A read that only needs a value does not pay for tree traversal, and a proof is not reconstructed from a store optimized for point lookups.</div></div>
  </div>
</div>

**The ledger store** holds the chain's history: transactions, their outputs and auxiliary data, events, write sets, block metadata, and the accumulators. This is what you replay.

**The state KV store** holds state values, addressed by key and version. This is what execution and queries read. It is **sharded sixteen ways**, so writes from one block spread across sixteen independent RocksDB instances rather than contending on one. Frequently-accessed state is additionally kept in its own tier, so the working set of an active market does not have to be found among everything the chain has ever stored.

**The state Merkle store** holds the authenticated structure — the tree nodes that let a value be proven, and the indexes that track which nodes have been superseded.

Splitting them means a read that only needs a value does not pay for tree traversal, and a proof does not have to be reconstructed from a store optimized for point lookups.

## Authentication

Two Merkle structures do different jobs.

<div className="dg" data-dg="storage-proofs">
  <div className="dg-c" style={{aspectRatio:"720 / 400"}}>
    <svg className="dg-w" viewBox="0 0 720 400" aria-hidden="true">
      <path className="dg-wire" d="M 173.50 98.50 L 173.50 110.10" />

      <path className="dg-head" d="M 173.50 116.50 L 169.10 110.10 L 177.90 110.10 Z" />

      <path className="dg-wire" d="M 173.50 169.00 L 173.50 180.60" />

      <path className="dg-head" d="M 173.50 187.00 L 169.10 180.60 L 177.90 180.60 Z" />

      <path className="dg-wire" d="M 173.50 239.50 L 173.50 251.10" />

      <path className="dg-head" d="M 173.50 257.50 L 169.10 251.10 L 177.90 251.10 Z" />

      <path className="dg-wire" d="M 546.50 122.00 L 546.50 133.60" />

      <path className="dg-head" d="M 546.50 140.00 L 542.10 133.60 L 550.90 133.60 Z" />

      <path className="dg-wire" d="M 546.50 216.00 L 546.50 227.60" />

      <path className="dg-head" d="M 546.50 234.00 L 542.10 227.60 L 550.90 227.60 Z" />
    </svg>

    <div className="dg-band" style={{left:"0.0000%",top:"6.5000%",width:"48.1944%",height:"72.5000%"}}><span className="dg-cap">Versioned sparse Merkle tree</span></div>
    <div className="dg-band" style={{left:"51.8056%",top:"6.5000%",width:"48.1944%",height:"72.5000%"}}><span className="dg-cap">Accumulators</span></div>
    <div className="dg-b dg--blue" style={{left:"2.2222%",top:"12.5000%",width:"43.7500%",height:"11.1250%"}}><span className="dg-t">Your key and its value</span></div>
    <div className="dg-b" style={{left:"2.2222%",top:"30.1250%",width:"43.7500%",height:"11.1250%"}}><span className="dg-t">sibling hash</span></div>
    <div className="dg-b" style={{left:"2.2222%",top:"47.7500%",width:"43.7500%",height:"11.1250%"}}><span className="dg-t">sibling hash</span></div>
    <div className="dg-b dg--green" style={{left:"2.2222%",top:"65.3750%",width:"43.7500%",height:"11.1250%"}}><span className="dg-t">State root, committed by consensus</span></div>
    <div className="dg-b dg--blue" style={{left:"54.0278%",top:"12.5000%",width:"43.7500%",height:"17.0000%"}}><span className="dg-t">Your transaction, or an event</span></div>
    <div className="dg-b" style={{left:"54.0278%",top:"36.0000%",width:"43.7500%",height:"17.0000%"}}><span className="dg-t">Transaction accumulator · event accumulator</span><span className="dg-s">each commits to everything included so far, in order</span></div>
    <div className="dg-b dg--green" style={{left:"54.0278%",top:"59.5000%",width:"43.7500%",height:"17.0000%"}}><span className="dg-t">Ledger root, committed by consensus</span></div>
    <div className="dg-b dg-dashed dg-left" style={{left:"0.0000%",top:"83.0000%",width:"100.0000%",height:"14.5000%"}}><span className="dg-s">The tree proves what a value was; the accumulators prove what happened and in what order. Together they make "this transaction is in the chain at this position" provable without holding the chain.</span></div>
  </div>
</div>

**A versioned sparse Merkle tree** authenticates state. Every key has a position determined by its hash, and every version of the tree shares the nodes that did not change — so writing one key in a block adds a path, not a tree. A proof for a key at a version is the path from that key's leaf to the root the network committed.

**Accumulators** authenticate sequence. One accumulates transactions and one accumulates events, each producing a root that commits to everything included so far in order. This is what makes "this transaction is in the chain at this position" provable without holding the chain.

Between them: the state tree proves *what a value was*, the accumulators prove *what happened and in what order*.

### Speculative state

A block's results exist before they are committed. Rather than writing them into the durable tree and undoing that if the block does not commit, uncommitted state is held in an **in-memory sparse Merkle overlay** on top of the last committed version.

Execution reads through the overlay and sees a consistent view. If the block commits, the overlay is materialized. If it does not, the overlay is dropped and nothing durable was ever touched. This is what keeps speculative execution from leaving debris in storage.

### Caching

Tree nodes are cached at two levels: a version-aware cache that keeps recent versions addressable, and a least-recently-used cache underneath it. The access pattern of a trading chain — a small set of hot keys touched every block, against a long tail touched rarely — is exactly the shape these are for.

## Pruning

Keeping every version forever is a choice, not a requirement. Three independent pruners run against the three stores, each with its own retention policy: one over the ledger, one over state values, one over Merkle nodes.

The Merkle and state-value pruners are driven by **stale indexes** written at the same time as the data. When a version supersedes a node or a value, the superseded entry is recorded as stale at that version. Pruning is then a range scan over an index rather than a search for garbage — the writer already said what would become collectable and when.

<Note>
  Retention is an operator decision with real consequences. A node pruned aggressively serves current state efficiently and cannot answer historical queries or serve state sync to a node starting from further back. An archival node keeps everything and pays for it. See [Run a node](/developers/run-a-node).
</Note>

## Backup and restore

The stores can be backed up and restored independently of the running node, which is what makes it possible to stand up a node from a snapshot rather than replaying from genesis, and to verify a restored node's state against the committed roots rather than trusting the backup.

## Where to go next

<CardGroup cols={2}>
  <Card title="State sync" href="/protocol/architecture/state/sync">
    How a node catches up to the chain without replaying all of it.
  </Card>

  <Card title="State model" href="/protocol/architecture/state/model">
    What is being stored, and which representation is authoritative.
  </Card>

  <Card title="Indexer" href="/protocol/architecture/indexer">
    Reconstructing history from committed records.
  </Card>

  <Card title="Run a node" href="/developers/run-a-node">
    Node roles, and how to ask about operating one.
  </Card>
</CardGroup>
