Skip to content

State Proof RPC (Contracts & Slots)

Source: src/rpc/node_rpc_v1.idl, src/storage/state/proofs.rs

state_proof returns a cryptographic proof that a contract exists (or not) under the global state root, and optionally proves a specific storage slot exists (or not) under that contract root.

Proofs are built from:

  • Outer tree: contract address -> contract root (Binary Merkle Tree / QMDB)
  • Inner tree: slot key -> slot value (contract storage tree)

The response includes enough material to verify the proof client-side without access to node state.

{
"address": "0x...",
"slot_key": "0x...", // optional
"height": 1234 // optional (defaults to latest finalized)
}
  • address: contract address (hex)
  • slot_key: optional storage key (hex)
  • height: optional block height; if omitted, uses latest finalized height
{
"address": "0x...",
"canonical_address": "0x...",
"contract_root": "0x...",
"state_root": "0x...",
"last_loc": 42,
"ops": [
{ "canonical_address": "0x...", "contract_root": "0x...", "position": 0 }
],
"bounded_proof": { ... },
"slot_proof": { ... } | null,
"height": 1234
}

Key fields:

  • state_root: global state commitment for the given height
  • contract_root: root of the contract’s storage tree
  • ops + last_loc: QMDB operation log needed to recompute the outer root
  • bounded_proof: membership/non-membership proof for the contract address
  • slot_proof: optional proof for a slot key (exists or non-exists)
  • Sort ops by position and ensure positions are contiguous 0..last_loc.
  • Ensure canonical addresses are strictly increasing.
  • Recompute the QMDB root from ops; must match state_root.
  • Use bounded_proof to prove the contract’s leaf exists (or not) in the outer tree.
  • The bounded proof includes a leaf proof plus left/right neighbor proofs for non-membership ordering checks.

If slot_key was provided:

  • Exists: verify the slot’s leaf digest under contract_root.
  • NonExists: verify neighbor ordering under contract_root.
  • Exists: { canonical_key, value, proof }
  • NonExists: { queried_key, left?, right? }

Both variants are verified against the contract root.

  • INVALID_PARAMS: bad hex in slot_key or malformed request
  • NOT_IMPLEMENTED: backend does not support state proofs
  • INTERNAL: proof generation failed
  • The backend must support ordered QMDB proofs. Some backends may not.
  • Proofs are for finalized state when height is omitted.
  • A missing contract returns a non-membership proof and slot_proof = null.
  • docs/design/state-layout.md
  • docs/design/light-client-mmr-onchain.md
  • docs-site/src/content/docs/upcoming/finalized-mmr-proofs.md