Skip to main content

๐Ÿ’ฐ Lazy Digests

This is the core of commitment accounting.

A commitment stores an immutable receipt, but value does not live inside the receipt.

Value lives inside the digest balance, and that balance keeps changing over time.

This is why receipts never update, but commitments still have real-time value

This is called:

lazy resolution

Final value is only realized during resolve_commit()

but it can still be queried at any time.


๐Ÿงพ Receipts Never Changeโ€‹

When a commitment is placed:

place_commit()
-> deposit()
-> receipt created

that receipt becomes immutable.

It stores:

  • ownership claim
  • deposit reference state
  • entitlement identity

It does not store final withdrawable value, because final value depends on how the digest evolves later.

The receipt only proves this user owns a claim, not what that claim is worth right now.

Even raise_commit() does not mutate old receipts.

It creates new immutable commit receipts which are accumulated and resolved later.

This keeps commitment history deterministic.


๐Ÿ†” Digests Hold Live Valueโ€‹

The digest is the active mutable state.

It holds the current balance for all commitments bonded to it.

Example:

Alice deposits 100
BOB deposits 100

The reason provider updates digest state using:

Commitment::set_digest_value(digest, 300) // Digest grows to 300

Alice's receipt does not change.

But:

Commitment::get_commit_value(alice) -> 150

now returns the updated live value by querying LazyBalance::get_receipt_active_value() internally.

As the balance system applies that lazily across all receipts (implicitly).

The value changes as a floating live projection from the current digest balance, while receipts remain unchanged.

This is the entire accounting model.


๐ŸŽฏ Direct Commitment Queriesโ€‹

For direct commitments:

(Proprietor, Reason)
-> one Digest
-> many variants
-> many immutable receipts

the live value of commitments and digests can be queried using:

MethodsPurpose
get_commit_value(who, reason)Current real-time value of a proprietor's commitment (one commitment per reason is enforced)
get_digest_value(reason, digest)Total live value of the default digest variant
get_digest_value_variant(reason, digest, variant)Live value of a specific digest variant
get_total_value(reason)Total committed value across the whole reason

๐Ÿงบ Index Commitment Queriesโ€‹

Indexes work differently.

  • The index itself does not own real balance.
  • Value lives inside entry digests.
  • Each entry digest evolves independently.

The proprietor's index commitment is resolved by aggregating all underlying entry receipts stored inside EntryMap

This is how one top-level commitment safely distributes across many digests.

MethodPurpose
get_index_value(reason, index)Current live aggregate value of the full index
get_entry_value(reason, index, entry)Current value of one entry digest
get_entry_value_for(who, reason, index, entry)Current real-time value of a proprietor's commitment to a specific entry
get_index_value_for(who, reason, index)Current real-time total value of a proprietor's commitment across the full index

So:

Index receipt stays fixed

Entry digest balances keep changing

and final resolution happens only during:

resolve_commit()

through all underlying entry withdrawals.


๐ŸŠ Pool Commitment Queriesโ€‹

Pools are true top-level lazy balances.

  • Unlike indexes Pool itself owns balance
  • A proprietor commits to the pool and receives a pool receipt.
  • The pool then acts as a proprietor itself and commits across slot digests.

This means:

pool receipt = top-level ownership

slot digests = effective deployed value
MethodPurpose
get_pool_value(reason, pool_of)Total live pool value
get_slot_value(reason, pool_of, slot_of)Current value of one slot
get_slot_value_for(who, reason, pool_of, slot_of)Current real-time value of a proprietor's commitment to a specific slot
get_pool_value_for(who, reason, pool_of)Current real-time total value of a proprietor's commitment across the full pool

Pool operations require:

release_pool()
-> mutate balances
-> recover_pool()

because the pool maintains one top-level balance over distributed slot commitments.

This is what makes pool accounting fully lazy and manager-controlled.

โš– Why Pool Slot Value Can Look Skewedโ€‹

Pools have:

one top-level balance

A proprietor commits to the pool, not directly to slots.

So querying a slot value (not encouraged) is often:

pool value
-> Release Full Pool
-> apply slot shares
-> projected slot exposure

not a direct per-slot deposit.

This is why slot values may look skewed.

Indexes are different:

direct commitment to each entry

So index entry value is exact ownership, while pool slot value is proportional exposure.


๐Ÿง  Why Query Methods Existโ€‹

Direct storage values may not tell the truth.

Receipts stay immutable while digest balances keep changing.

So reading storage alone does not show:

current real-time value

Without query methods, users would need to withdraw just to know value.

Instead:

query live state

resolve only when needed

This preserves lazy accounting and deterministic settlement.


๐Ÿ“Œ In One Sentenceโ€‹

Receipt = ownership proof

Digest = live balance state

Resolution = lazy final settlement

๐Ÿš€ Next Stepโ€‹

Now we move into integrating/installing pallet-commitment towards a runtime where the usage pallet exists to be served.

๐Ÿ‘‰ Getting Started -> Installation