State and proofs
Application state lives in an authenticated tree. Every final block produces one state root that commits to all of it, identical on every member. A client can check a single record against that root without trusting the node that served it.
You’ll learn: what a state root commits to, what a proof contains, how to read a proof result precisely, and how much a verification actually proves.
Before you start: read Consensus and finality.
The state root
Section titled “The state root”Every write a state machine makes is an entry in one authenticated tree. The tree’s type is chosen when the ledger is created and never changes:
| Profile | Tree | Proofs verify |
|---|---|---|
mpf-blake2b256-v1 | Merkle Patricia Forestry, the same construction as Aiken’s merkle-patricia-forestry | Off-chain, and inside a Cardano validator |
jmt-blake2b256-v1 | Jellyfish Merkle tree | Off-chain only |
The profile, its exact state.format-fingerprint, and a fresh
state.genesis-id are configured together as state.commitment-profile,
state.format-fingerprint, and state.genesis-id. Together they are the
chain’s state identity. The stock cluster configuration uses MPF.
After each block, the root is:
- identical on every honest member: each one re-executes the block and compares the root byte for byte before it votes;
- provable: it supports inclusion and exclusion proofs; and
- anchorable: the same root can be published to Cardano.
Effect records are committed through an effectsRoot entry, so an authorized
but not yet executed external action is as provable as ordinary state. New
chains also record each block’s [height, messagesRoot, messageCount] in state
by default, which ties a message inclusion proof to the state root.
What a proof contains
Section titled “What a proof contains”- State root → Root you trust (must equal).
- State root → Node 3….
- State root → Node a….
- Node 3… → Node 3c….
- Node 3… → No child 3e….
- Node 3… → Node 3f….
- Node 3c… → Leaf 3c1….
- Node 3c… → Leaf 3c9….
Select a node to see what the proof carries for it.
- State root
- The root the verifier recomputes. If it equals the root in the same response, the proof is internally consistent, and that is all it shows. It proves your record only against a root you obtained some other way.
- Root you trust
- A root obtained independently of the node that served the proof: one you pinned, one from a block whose finality certificate you checked against member keys you pinned, or one bound by a Cardano anchor. Where it came from sets the trust level of the result. Trust levels →
- Node 3…
- On the path from your record to the root. The verifier recomputes this node’s hash from the hash below it and the sibling hashes in the proof.
- Node a…
- Not on your path. The proof carries only this node’s hash, not its contents; the verifier needs it to recompute the parent.
- Node 3c…
- On the path from your record to the root. The verifier recomputes this node’s hash from the hash below it and the sibling hashes in the proof.
- No child 3e…
- An exclusion proof for key 3e…: the path ends at node 3…, which has no child for it. This shows the key is absent from this state. It does not show that the business fact never happened, and a height whose proof material was pruned gives no proof at all: unavailable, not absent.
- Node 3f…
- Not on your path. The proof carries only this node’s hash, not its contents; the verifier needs it to recompute the parent.
- Leaf 3c1…
- Your record: a canonical state key and its value. The proof carries the value, and the verifier hashes it itself, so a changed value changes every hash above it and the root no longer matches.
- Leaf 3c9…
- Not on your path. The proof carries only this node’s hash, not its contents; the verifier needs it to recompute the parent.
- on the path
- your record
- sibling: only its hash is in the proof
- absent key
- the root you trust
A state proof carries your record, its canonical key and value, and the hashes of the siblings along its path to the root. The verifier hashes the record itself and recomputes each node up to the root. If the recomputed root matches, the proof is consistent with that root, and nothing more. Whether the record is really in the ledger depends on where that root came from.
An exclusion proof shows that a key is absent from the state under that root. It does not show that the underlying business fact never happened: the data set might simply be incomplete. Do not expose a business-level absence check unless a marker, a paired subject, or an authenticated snapshot descriptor proves that the data set is complete.
Proof subjects: ask in application terms
Section titled “Proof subjects: ask in application terms”Raw key proofs force the caller to know the physical storage layout. A proof subject is a typed descriptor that turns an application-level identity into its canonical state key, decodes only the value the verified proof carries, and evaluates only the claims it declares.
curl -s -X POST \ "http://127.0.0.1:7070/api/v1/app-chain/chains/orders-chain/proof-subjects/finalized-message-v1/proof" \ -H 'Content-Type: application/json' \ -d '{ "coordinates": {"message-id": "<id>"}, "view": "latest", "claim": {"claimId": "recorded", "operands": {}}, "includeEvidence": false }' | jqYou supply coordinates in your own vocabulary: a message id, an account, a
registry key, a document id. The response includes a trust field with the
result’s trust level; see How much does a proof prove?.
finalized-message-v1 is built into ordered-log, which orders-chain uses.
Other state machines provide it only when the chain is created with
machines.finalized-message-index.enabled=true.
Stock v1 subjects cover finalized block messages, finalized message records, balances, registry entries, document heads, basic approval outcomes, authenticated-map entries, actor roles, role approval outcomes, and composite profile markers. Composite subjects are rebound to their component namespace automatically and get component-qualified ids.
Read the result precisely
Section titled “Read the result precisely”Each of these statements means something different, and a proof response keeps them separate:
| Result | What it asserts |
|---|---|
| Message inclusion | The message id is a leaf under one app block’s messagesRoot. |
| Finality certificate | A membership threshold the caller pinned signed the block. |
| Authenticated block record | Final state contains [height, messagesRoot, messageCount]. |
| State recording | The application wrote a typed fact under its canonical state key. |
| Anchor binding | A trusted Cardano output commits the selected application identity or root. |
| Claim satisfied | The value carried by the proof satisfies the selected bounded predicate. |
| Locally retained | This node has the bytes now. Durable availability is separately NOT_PROVEN. |
How much does a proof prove?
Section titled “How much does a proof prove?”A proof always recomputes a root. Its trust level names where the root it was checked against came from. There are five levels:
What you're seeing: the five trust levels name where the root came from. Answer for the root your verifier compared the proof against.
Where did the root you checked the proof against come from?
A proof always recomputes a root. The question is whether anything other than the serving node vouches for that root.
- From the same response as the proof
INTERNAL_CONSISTENCY_ONLYThe proof is consistent with the root it came with, and that root is whatever the node chose. A node’s proof response reports this level by default.
- Establishes
- the proof is well formed
- Does not establish
- that the root is the ledger’s certified root
- From me: a root I pinned, or member keys and a threshold I pinned
CALLER_PINNED_ROOTThe proof matches a root you authenticated yourself: a root you pinned, or the root of a block whose finality certificate verifies under member keys and a threshold you pinned.
- Establishes
- the record is in the state your pinned members certified
- Does not establish
- any public Cardano record
- For example
- Attest
--members keys.json;yano-explorer verify --members
- From a Cardano anchor
Who read the anchor from Cardano?
- The node reported a confirmed anchor
NODE_CONFIRMED_L1_REFERENCEThe node proved the record at the height of its latest confirmed anchor and says Cardano carries that anchor. That is the node’s claim about Cardano, not something you checked.
- Establishes
- what the node reports about its anchor
- Does not establish
- that the anchor is on Cardano
- For example
- a proof request with
"view": "latest-confirmed-anchor"
- I supplied an anchor datum to my verifier
CALLER_PINNED_ANCHORThe proof is bound to an anchor datum you supplied: its height, root, block hash, genesis, and member set, without the verifier reading Cardano itself. Yano defines this level, but no Yano X command reports it today: the tools that take an anchor datum report the independent level below.
- Establishes
- the record matches the anchor data you supplied
- Does not establish
- that the datum came from Cardano
- I or my verifier read the anchor output from Cardano
INDEPENDENTLY_VERIFIED_L1_ANCHORThe root is bound to anchor data read from Cardano, independently of any member or node. This is the strongest level.
- Establishes
- the record is in the state the anchored root commits to
- Does not establish
- that the data is still available: availability is always reported separately
- For example
- Attest, Trust Registry, and
yano-explorer verifywith--anchor-datum-hex, using a datum you read from Cardano
- The node reported a confirmed anchor
Where did the root you checked the proof against come from?
A proof always recomputes a root. The question is whether anything other than the serving node vouches for that root.
Who read the anchor from Cardano?
INTERNAL_CONSISTENCY_ONLYThe proof is consistent with the root it came with, and that root is whatever the node chose. A node’s proof response reports this level by default.
- Establishes
- the proof is well formed
- Does not establish
- that the root is the ledger’s certified root
CALLER_PINNED_ROOTThe proof matches a root you authenticated yourself: a root you pinned, or the root of a block whose finality certificate verifies under member keys and a threshold you pinned.
- Establishes
- the record is in the state your pinned members certified
- Does not establish
- any public Cardano record
- For example
- Attest
--members keys.json;yano-explorer verify --members
NODE_CONFIRMED_L1_REFERENCEThe node proved the record at the height of its latest confirmed anchor and says Cardano carries that anchor. That is the node’s claim about Cardano, not something you checked.
- Establishes
- what the node reports about its anchor
- Does not establish
- that the anchor is on Cardano
- For example
- a proof request with
"view": "latest-confirmed-anchor"
CALLER_PINNED_ANCHORThe proof is bound to an anchor datum you supplied: its height, root, block hash, genesis, and member set, without the verifier reading Cardano itself. Yano defines this level, but no Yano X command reports it today: the tools that take an anchor datum report the independent level below.
- Establishes
- the record matches the anchor data you supplied
- Does not establish
- that the datum came from Cardano
INDEPENDENTLY_VERIFIED_L1_ANCHORThe root is bound to anchor data read from Cardano, independently of any member or node. This is the strongest level.
- Establishes
- the record is in the state the anchored root commits to
- Does not establish
- that the data is still available: availability is always reported separately
- For example
- Attest, Trust Registry, and
yano-explorer verifywith--anchor-datum-hex, using a datum you read from Cardano
Availability is reported separately, with its own two values:
LOCALLY_RETAINED (this node has the bytes now) and NOT_PROVEN (nothing
proves the data will stay available).
Retention and pruning
Section titled “Retention and pruning”A node keeps proof material for past heights so it can answer historical proof
requests. Optional MPF proof pruning is experimental and off by default; when
enabled, it removes material below a retained horizon. Check where retained
history starts with oldestProvableHeight:
./yano.sh appchain state identity --url http://node:8080/api/v1 --chain registry./yano.sh appchain state oldest --url http://node:8080/api/v1 --chain registryA pruned proof is unavailable. It is not evidence that the fact was absent.
Verifying independently
Section titled “Verifying independently”Proofs are portable. The Java client SDK (yano-x-client) verifies them in your
application, and the composite client (yano-x-composite-client) also verifies
governed-profile finality, one-root MPF, epoch chains, and authorization
policy.
Retrieve a proof from a node, then verify the saved proof offline:
# Online: save the proof for a canonical key at a retained height../yano.sh appchain state proof --url http://node:8080/api/v1 \ --chain registry --key <canonical-key-hex> --height <height> > proof.json
# Offline: supply a root and identity authenticated independently of that file../yano.sh appchain state verify --proof-file proof.json \ --trusted-root <root-hex> --profile <profile-id> \ --genesis-id <64-hex-genesis-id> --chain registry --height <height> \ --root-source caller-pinnedNever take the trusted root from the proof itself. Obtain it from an independently authenticated block, a finality policy you pinned, or a Cardano commitment.
Reference
Section titled “Reference”The finalized block-message index
Section titled “The finalized block-message index”New chains enable state-index:finalized-block-messages-v1 by default. Its
enabled flag and configuration digest are part of the chain’s state identity,
so an existing database with a different configuration fails to start instead
of drifting silently. Disable it only in a new genesis profile.
Rough raw growth for that index, before MPF or JMT node and RocksDB amplification, is one 32-byte key plus a canonical CBOR value of about 38–47 bytes per block:
| Block interval | Records per day | Raw logical growth per day |
|---|---|---|
| 1 second | 86,400 | 5.8–6.5 MiB |
| 5 seconds | 17,280 | 1.15–1.30 MiB |
| 20 seconds | 4,320 | 0.29–0.33 MiB |
Capacity planning must measure backend amplification, compaction, snapshots, and retained proof history on the intended workload.
Custom proof subjects
Section titled “Custom proof subjects”For a custom subject, implement ProofSubjectProvider next to the module that
owns the canonical key and value codec. Each descriptor is closed data:
coordinates, fact fields, claims, completeness, verification targets, retention
hints, and fixed bounds. Its descriptorDigest goes into the capability
manifest, and the runtime activates the provider only when the subject id,
version, component id, and digest all match. Resolution must be deterministic
and free of side effects.
Deeper reading
Section titled “Deeper reading”- Proof Lab: message, typed-state, imported, and on-chain proof workflows, plus the independent-verifier and Cardano-validator guides.
- Composable state and portable proofs: the verification trust boundary and MPF proofs in a Cardano validator.
- Tutorial 2: retrieve and read a proof.
- Tutorial 7: bind a root to Cardano.
- Authenticated snapshots: archive and prove large immutable period data sets.
Next: Effects.