Receipts and the network topology
You are looking at an old version of this page: revision #853 by zoobc.how, 2026-10-26 22:31 UTC. See the current version
A blockchain lives on its nodes passing blocks and transactions to one another. Proof of Participation measures exactly that service. When a registered node receives data from another registered node, it answers with a receipt, a short statement signed with its node key. The proof of the work therefore comes from the peer that received it, not from the node that claims it. Which peers count is not up to the nodes either: every 40 blocks the protocol shuffles the registry with the block seed and gives each node its priority peers.
Priority peers: the topology
The registry is reshuffled once per period of 40 blocks (topology_period_blocks), about 10 minutes. At the first block of a period, each registered node gets a sort key:
key = SHA3-256(seed of the period's first block (64 bytes)
‖ node id (8 bytes, little-endian)
‖ period height (8 bytes, little-endian)
‖ "zbc-topology-v2")
Sorting the registry by these keys gives the scrambled list. Each node is assigned a window of P consecutive nodes from it as its priority peers, where P is max_assigned_peers: 12 on mainnet and 8 on devnet. The window of the node at position i starts at position (i × P) mod L, L being the length of the list; the window is always a full P nodes, and its starts are spread out when P and L share a factor. The relation runs one way: A being a priority peer of B does not make B a priority peer of A.
Because the order depends on a seed none of them controls, and changes every 10 minutes, a group of colluding nodes cannot arrange to be each other's peers and vouch only for one another. Connection speed plays no part, and nobody publishes a peer list.
What a receipt says
A receipt is 232 bytes:
| Field | Bytes |
|---|---|
| sender's node key (the node that pushed the data) | 32 |
| recipient's node key (the node that signs) | 32 |
| reference block: the recipient's latest block, height | 4 |
| reference block: hash | 32 |
| datum type: 1 for a block, 2 for a transaction | 4 |
| datum hash: which block or transaction was received | 32 |
| the recipient's latest receipt-batch root | 32 |
| the recipient's Ed25519 signature over the 168 bytes above | 64 |
Only registered nodes give and keep receipts, and only for data pushed by another registered node. A node that is not registered can follow and check the chain, but it neither gives nor earns receipts. A receipt names no chain, so unlike transactions (see chain-bound signatures) it carries no chain binding.
Receipts have nothing to do with wallet confirmations or fee refunds, which are ordinary records of transactions and balances.
Batches and publication
The sender keeps the receipts it earns. For each height it groups them into a batch of at most 1,000, sorted by signature, under a Merkle root. When it makes a block of its own, it publishes a sample of its receipts in it, of two kinds: unlinked receipts, shown as they are, and linked receipts, shown with a Merkle proof against an earlier batch root. The reference software samples receipts from about 40 blocks back; that is its behaviour, not a validity rule.
What validators check
For every receipt published in a block, every node checks the following, where n is the number of registered nodes:
- the recipient's signature;
- that the reference block hash is the block of this chain at that height;
- its age: a receipt expires after max(max(100, 2 × n) + 1,
receipt_lifecycle) blocks, which is 518,400 blocks (about 90 days) on mainnet; - from height 40, that the signer of an unlinked receipt was a priority peer of the block's producer in the period the receipt comes from;
- from height 80, the Merkle proof of every linked receipt;
- the count: at most 2 × min(n − 1, P) receipts, and never more than 200.
Some things are not validity rules, and should not be read into them: validators do not check that the receipt's sender is the block's producer, that the receipt is new, that its datum is about 40 blocks old, or that a linked root appeared on the chain before.
From receipts to score
Relaying earns receipts, not score. The score moves only when the node publishes its receipts in a block of its own: showing more than a pivot of about half of what it could show raises its score, showing fewer lowers it. No score moves before height 40. See participation score for the details, and coinbase lottery for how the score turns into income.