Documentation
A quorum signer's bond — the design
Status: a design, not implemented. No code exists. It was written for an appointed quorum — a fixed list of nine keys in the binary, each with an index. The chain’s quorum is the miners of the last 2,880 blocks (finality, §2) and changes every day, so a bond posted per index does not fit it; a key caught signing twice already loses its say (finality, §4). Whether such a key should also lose money is open (finality, §9). The design below is kept for its reasoning, which is also why it speaks of signer indexes and a key list.
It follows on from security, §3 (“Staking — considered, rejected”), from which exactly this stayed open: skin in the game for the holders of the quorum keys — without touching anything in the emission or in block production.
1. What it solves and what it does not
It solves: in an appointed quorum the worst consequence for a member who signs two different
blocks at the same height is that their key is replaced in the next release. Yet the proof (Equivocation) is
self-contained — 210 B, both signatures, verifiable by anyone with no trust required. It can
therefore be used to make the offence cost that member money.
It does not solve — and it is important to say so out loud — signing according to a node that lies to the signer. The bond punishes a provable offence (two signatures for one height). A signer who signs a single block at a height, and that block was slipped to them by somebody else’s node, broke no rule — there is nothing to burn. There is only one answer to that: a signer runs with its own node. The bond and running your own node are two independent things.
It is not staking. It does not decide who may sign (in this design, the list of keys in the binary), it gives nobody a share of the emission and it does not vote on blocks. It is a deposit that forfeiture takes away.
2. The parameters
| The minimum bond | 10,000 POWM (on the order of a few days of mining on one decent machine) |
| The minimum lock length | 21,600 blocks (≈ 7.5 days at the 30 s block) |
| A forfeited bond | is burned — neither the reporter, nor a miner, nor the dev fee gets it |
| Activation | from the mainnet genesis — no activation logic |
| The script version | ScriptVersionBond = 1 (the first of the reserved 1–15, spec, §2.4) |
Why burn it: a reward for the reporter would turn the proof into money and with it into a race over who writes it into a block first — more surface for speculation in a mechanism that is meant to be boring. The proof spreads by gossip on its own anyway, so we do not need a reward to spread it. The dev fee would mean the operator benefits from a signer’s offence — exactly the impression that does not suit a quorum.
Why from genesis and not by a soft fork: it is cheaper to have the rule valid from the first block than to have activation logic and two different behaviours by height. The soft-fork path (versions 1–15 are anyone-can-spend for old nodes) stays open in case the rule ever has to change.
3. The shape of a bond
An output with ScriptVersion = 1 and a script of a fixed length of 41 B:
[0] the signer's index in the quorum 1 B
[1:9] the lock height (little-endian) 8 B
[9:41] the owner's public key (Schnorr) 32 B
Validity at creation (a new rule in Tx.ValidateStandalone / ValidateBlock):
- the script’s length is exactly 41 B,
index < FinalitySigners(that is, 0–8),the value ≥ MinBond(10,000 POWM),the lock height ≥ the block's height + MinBondLock(21,600).
An output that does not satisfy these conditions is not a valid bond and a block containing it is rejected. The consequence: “I have a bond” is verifiable by anyone from the UTXO set, not a claim.
4. How a bond is spent
Two paths, both in VerifyInput for ScriptVersionBond:
4.1 The owner after the lock
the block's height ≥ the lock height ∧ witness[i] = a Schnorr signature by the key from the script
Renewing a bond is an ordinary spend and the creation of a new one with a higher lock height. While the lock is in the future, the owner cannot get to the coins.
4.2 Burning with a proof
witness[i] = [the 210 B proof of a double signature]
The conditions:
- the proof is valid (an
Equivocationwith two signatures by the same member for the same height and two different blocks — verified against the network’s quorum, that isNetParams.FinalitySigners), proof.SignerIdx == the index in the bond— a proof against member 3 cannot burn member 5’s bond,proof.Height ≥ the height at which the bond was created(taken fromCoin.Height, the storage has it) — an old offence does not burn a new bond,- the transaction must not have any input or output other than:
- the input: that bond,
- the output: one data output (
ScriptVersion = 0xff) with a value equal to the whole bond.
Point 4 is what makes the “burning” real. Data outputs do not enter the UTXO set (spec, §3.2), so the value disappears; and since the sum of the outputs equals the sum of the inputs, the fee is zero and the miner gets nothing. The only change to the existing rules: a data output may have a non-zero value only in such a transaction (otherwise it always has to be 0).
Burning does not need the owner’s signature — the proof authorizes it. Anybody can publish it and nobody gets anything for it.
5. The edge cases
| case | what happens |
|---|---|
| two proofs against the same bond | the first transaction spends the bond, the second has nothing to spend (an ordinary double spend) |
| a proof against an index with no bond | nothing is burned; the proof still takes away that key’s say (finality, §4) |
| a bond for an index that is not in the quorum | it is rejected at creation (index < FinalitySigners) |
| two bonds for the same index | both are valid; the proof burns the one the transaction points at. How many bonds a member should have is a question for whoever curates the list, not for consensus |
| an offence after the lock expired | there is nothing to burn. The hole is closed by the key list — whoever’s bond expires is not in the quorum in the next release |
| a bond without signing | nothing. A bond is not a ticket into the quorum; the quorum is a list in the binary |
6. What the wallet has to support
bond-lock <index> <height> <amount>— creates a bond to your own key,bond-renew— spends it and creates a new one with a higher lock height,bond-withdraw— withdraws it after the lock,bond-burn <the proof in hex>— assembles and sends the burn; it needs no keys, so anyone who has the proof can run it.
A node could additionally assemble the burn itself when it sees a proof and finds a matching bond in the UTXO set — the transaction needs no signature, so it is not work with keys. Considered as optional; it is not necessary, because the proof spreads on its own.
7. What it costs in code
chain/tx.go |
ScriptVersionBond, validating a bond’s shape at creation |
chain/script.go |
the two spending paths in VerifyInput (the owner after the lock, burning with a proof) |
chain/block.go |
the exception: a data output with a value only in a burn transaction |
chain/params.go |
MinBond, MinBondLock |
| the wallet | the four commands from §6 |
| the tests | the bond’s shape, both spending paths, all six edge cases from §5, and a live cycle on a test network: lock → offend → burn |
No new state in consensus: a bond is an ordinary UTXO output, the proof is self-contained, and the
creation height is in Coin.Height. That is the whole point of this shape — security, §3
rejected staking mainly because it would bring “more consensus code than the whole of today’s
internal/chain”.
8. Testing it on a test network
Once the bond is implemented, the whole cycle is run through on a test network:
- signer 0 locks 10,000 tpowm for 21,600 blocks,
- a one-off tool signs a different block at the same height for them,
bond-burnwith that proof → the bond disappears from the UTXO set, the fee is zero and the miner gets nothing,- the check:
getrichlistand the total circulation show 10,000 less.