Pattern
Polite actions
Each shielded wallet must try to decrypt each action on the chain. Each action that an app adds increases the scan work of all wallets. Thus, an app must keep its number of actions small.
Problem
An app that keeps state on the chain often uses one note for each user. When a user changes, the app spends the old note and makes a new note. That is one action for each changed user. A busy app makes thousands of actions each day.
The app pays only the fee for these actions. All other wallets pay with scan time and bandwidth. The cost increases with each user of the app.
Mechanism
A light wallet downloads compact blocks. A compact block keeps about 148 bytes of each Orchard-protocol action:
nullifier 32 bytes
cmx 32 bytes
ephemeral key 32 bytes
ciphertext prefix 52 bytes
─────────
148 bytes
The wallet tries to decrypt each action with each key that it holds. This is trial decryption. The compact block drops the memo. Thus, in the compact-block scan:
- each action costs one trial decryption for each key, and 148 bytes of download;
- memo bytes are free.
To read a memo, a wallet gets the full transaction. Only the wallets that read the record pay for its memo bytes.
The action count is the lever. An app that uses fewer actions makes the chain faster to scan for all wallets.
Techniques
- Put user state in leaves. Put the state of each user in a leaf of a Merkle tree. Bind the root in one bound note. A change to a user changes a leaf, and the root note changes one time for each epoch. Each user gets a leaf proof from the app and compares the leaf with the bound root.
- Put records in the memo. A memo holds 512 bytes, and the compact-block scan skips it. Put the public record of the epoch in the memo of the root note. When the record is too long, add chunk notes to the same transaction. Bind a hash of the full record in the root note. Thus, the binding covers each chunk.
- Use the free action. An Orchard-protocol bundle has two actions or more. The builder adds a padding action to a bundle with one action. The root note (spend and output) fills one action. A fee from a shielded note and its change fill the second action. With a transparent fee, the second action is padding. Thus, a record that fits in one memo costs two actions, and each chunk adds one action.
- Use epochs. Collect the changes of a period in one transaction. A longer epoch makes fewer transactions each day.
Cost
- Proof delivery. Each user must get leaf proofs from the app. A leaf proof is about 32 × log₂(N) bytes for N users. If the app holds back a proof, the user must wait. The user can see the delay.
- Privacy. The result is better privacy. With one note for each user, the action count shows how many users changed in each epoch. With leaves, the action count stays the same.
- Payouts. A payment to a user wallet is one action for each payment. The user must receive a usual note, so this cost stays.
- Proving. Fewer actions make faster transaction builds.
Spec
This pattern is a design rule. It uses the protocol of today: bound notes for the root, and the ZIP 302 memo format for the record.
Demo: the cost of a scoreboard
A toy app keeps a scoreboard for a game. The scores of some players change in each transaction. The calculator compares two designs:
- One note per player: 2 actions for the root and the fee, plus 1 action for each changed player.
- One note per epoch: 2 actions, plus 1 action for each chunk note.
The calculator pays the fee from a shielded note. With a transparent fee, the per-player design uses one action fewer. The mainnet target block time is 75 seconds. Thus, the chain makes about 1,152 blocks each day.
| Design | Actions each transaction | Actions each day | Download each day, per wallet | Download each year, per wallet |
|---|
Example results
Each row has 20 changed players in each transaction, and no chunk notes.
| Design and cadence | Actions each day | Download each day |
|---|---|---|
| One note per player, each block | 25,344 | 3.75 MB |
| One note per epoch, each block | 2,304 | 341 kB |
| One note per epoch, each 10 minutes | 288 | 42.6 kB |