Cairn protocol specification

What a node must do to be a node on this network, written so that a second implementation could be built from it without reading the first.

Why this exists apart from the implementation

Until this document, the implementation was the specification. That is a problem with two halves. A second implementation cannot exist, because there is nothing to build it from except a reading of the first, and two readings of the same Rust are not two independent implementations. And a reviewer cannot check a rule without being a Rust programmer, which excludes most of the people whose review would be worth having.

This document is normative. Where it and the implementation disagree that is a defect in one of them, and neither is presumed right. Every statement here that names a number, a byte layout or an ordering is held against the code by a test, and the last section says where those tests are. A specification nobody checks goes wrong the way a comment goes wrong: quietly, and without anyone deciding to.

1

Conformance

MUST and MUST NOT mark what a node has to do to reach the same conclusions as every other node. Getting one of them wrong is a chain split, not a matter of taste. SHOULD marks what a node is expected to do, where doing otherwise costs that node or its operator and nobody else. MAY marks a choice.

This document specifies what a node must agree with other nodes about. It does not specify how a node stores anything, how it schedules work, what it keeps on disk, or how it talks to a person. Those are the implementation's own, and the reference implementation makes choices in all of them that another implementation is free to make differently.

Anything not stated here is not a rule. If the reference implementation refuses something this document does not say it must refuse, that is a defect in the implementation or an omission here, and the way to tell them apart is to ask whether two honest nodes could disagree about it.

2

Primitives

2.1Integers

Integers are unsigned, of fixed width, and encoded little-endian with no padding, no length prefix and no tag: u8 in one byte, u16 in two, u32 in four, u64 in eight, u128 in sixteen. There is no variable-length integer anywhere in this protocol. A decoder MUST read exactly the width the field's type says and no more.

There are no signed integers in any encoded structure. Arithmetic on a decoded value MUST NOT wrap: an operation whose result does not fit is a refusal, not a wrapped value, and the refusal is named where the operation is specified.

2.2Byte arrays and hashes

A fixed-size byte array is encoded as its bytes in order, with no length prefix, because its width is known from its type. A hash is a 32-byte array and is encoded the same way.

Every hash this protocol defines is BLAKE3 in keyed mode. The key is a 32-byte domain constant, and a value hashed under one domain MUST NOT be accepted where another domain is required. Each domain is a distinct constant, so a preimage under one says nothing under any other. The one other hash a node computes is the SHA-512 inside Ed25519, which belongs to the signature scheme and is specified with it in How a signature is verified.

2.3Sequences

A sequence is encoded as a u32 count, little-endian, followed by that many items back to back in order. There is no terminator and no per-item framing.

A decoder MUST refuse a declared count above 1 048 576 before reading any item, and MUST NOT reserve memory in proportion to a count it has not yet read. Every sequence in a block or a message has its own tighter limit, stated where that structure is specified. This one is the floor under all of them, and it exists so that a declared length can never drive an allocation.

An encoder MUST NOT produce a sequence longer than that limit. A structure holding one would encode to bytes no conforming decoder can read back, and a node could then commit to an identifier over a structure it cannot re-parse. No structure in this protocol can reach the limit, since every sequence in a block or a message has a tighter one of its own, so the reference encoder relies on that rather than checking, and only a debug build asserts it.

2.4Structures and choices

A structure is encoded as its fields in the order this document lists them, back to back, with nothing between them and nothing around them. There is no field tag, no optional field and no reordering. The order is part of the format, and changing it changes every identifier ever computed.

A choice between shapes is encoded as a u8 tag followed by the bytes of the shape that tag selects. A decoder MUST refuse a tag it does not know rather than skipping it, since it cannot know how many bytes to skip.

2.5Money

An amount is a count of pebbles, encoded as a u64. One CAIRN is 100 000 000 pebbles. No amount may exceed the monetary ceiling, which is 100 000 000 000 000 000 pebbles, one billion CAIRN, and a decoder MUST refuse an amount above it rather than accepting and clamping, so a value past the ceiling cannot exist in a decoded structure anywhere in the system.

3

Identifiers

An identifier is the hash of an encoding under a stated domain. Because the encoding is positional and unpadded, an identifier commits to every field of what it names, in order, and to nothing else.

Each 32-byte domain constant is BLAKE3's derive_key over the context string below with empty key material, and every hash under that domain is BLAKE3 keyed with that constant. All twenty are given here, because a document that named only some of them could not be used to compute an identifier, which is the one thing it exists for.

Called hereContext string
transfer idcairn v1 transfer id
coinbase idcairn v1 coinbase id
block header idcairn v1 block header id
signature messagecairn v1 signature message
merkle leafcairn v1 merkle leaf
merkle nodecairn v1 merkle node
merkle emptycairn v1 merkle empty
state entrycairn v1 state entry
accumulator emptycairn v1 accumulator empty
accumulator leafcairn v1 accumulator leaf
accumulator nodecairn v1 accumulator node
note keycairn v1 note key
hot note valuecairn v1 hot note value
state commitmentcairn v1 state commitment
forest leafcairn v1 forest leaf
forest nodecairn v1 forest node
forest rootscairn v1 forest roots
header history leafcairn v1 header history leaf
sampling seedcairn v1 sampling seed
grace windowcairn v1 grace window

One of them, state entry, is reserved: nothing on the network is hashed under it. It is published so that its string cannot come to mean one thing to one implementation and another to a second.

Two consequences follow and both are load-bearing.

Adding a field to a structure changes every identifier that structure ever had, so it cannot be done to a chain that already exists. Extending a structure at a version boundary is a different operation, and whether this protocol permits it is settled in part 4 rather than here.

A field left out of an identifier's encoding is a field the identifier does not commit to, which is a place two nodes can hold the same identifier over different bytes. Where that is done deliberately it is stated, with the reason, where the structure is specified.

4

Notes

A note is an amount and the public key that may spend it.

FieldTypeBytes
valueamount8
ownerpublic key32

A note has no identity of its own. It is named by where it was created: the identifier of the transaction that made it, and its index among that transaction's outputs.

FieldTypeBytes
sourcehash32
indexu324

A public key is 32 bytes and is an Ed25519 verifying key. A decoder MUST refuse bytes that are not a canonical encoding of a point on the curve, MUST refuse a key of small order, and MUST refuse a key that is not in the prime order subgroup. All three refusals happen at decode, so a structure that decoded holds no unusable key.

The third is the one that carries the sentence after it. Ed25519's group has a cofactor of eight, so a point may be A + T for a prime order point A and a non-identity point T of order dividing eight. Such a point is canonically encoded, decodes cleanly, and is not of small order, so the first two refusals pass it. No signer can produce a signature that verifies under it: Ed25519 clamping clears the low three bits of the scalar, so a public key is always a multiple of eight times the basepoint and therefore always lies in the prime order subgroup. Seven of every eight byte strings that pass the first two refusals are addresses nobody holds a secret for, and a note paid to one is unspendable.

5

Transactions

There are two kinds and they are not interchangeable. A transfer moves notes that exist. A coinbase creates them, and exactly one appears in each block.

5.1Transfer

FieldTypeBytes
versionu162
inputssequence of input4 + n
outputssequence of note4 + 40m

An input names a note, says how its existence is being shown, and carries the signature that authorises spending it.

FieldTypeBytes
note_idnote identifier36
witnesswitness1 or more
signaturesignature64

A witness is a choice. Tag 0 means the note is in the hot set and the node already holds it, and carries nothing further. Tag 1 means the note has fallen to the cold set, and carries the note itself, its position, and a proof that it sits at that position. A decoder MUST refuse any other tag.

FieldTypeBytes
notenote40
positionu648
proofsequence of hash4 + 32d

Those are the bytes after the tag. The proof's hashes are the siblings from the note's leaf up to the root of its tree, bottom first, as Proofs gives them.

A transfer's identifier is not the hash of its wire encoding. It is the hash, under the transfer domain, of the version, the count of inputs, each input's note identifier alone, and the outputs. Signatures and witnesses are left out.

FieldTypeBytes
versionu162
input countu324
note identifiersnote identifier, one per input, in order36n
outputssequence of note4 + 40m

It is the transfer's own encoding with each input cut down to its note identifier: the input count is the count the inputs sequence carries, and the outputs are the same sequence, count included.

That is deliberate and a second implementation must reproduce it exactly. A cold witness carries a proof that goes stale as the accumulator moves, and it has to be refreshable without changing the identifier, for the same reason a signature must not change it: everything already built on top of that transaction would otherwise become invalid. It also means the identifier is known before the transaction is signed.

It is an instance of the case section 3 names: a field left out of an identifier's encoding is a field the identifier does not commit to. Two nodes can hold the same transfer identifier over different bytes, differing in signatures and witnesses, and that is intended rather than tolerated.

5.2What a signature commits to

Each input is signed separately, over the hash under the signature domain of: the network identifier, the transfer's version, the transfer's identifier, the input's index, and the value and owner of the note being spent.

FieldTypeBytes
networku324
versionu162
transferhash32
indexu324
valueamount8
ownerpublic key32

That is 82 bytes. network is the identifier the network's headers carry, version is the transfer's, transfer is its identifier, index is the input's position among the transfer's inputs counting from nought, and value and owner are the spent note's.

The last two matter and are not obvious. Without them a wallet shown a false value for the note it is spending would sign a transaction whose real fee is the difference, and the signature would be perfectly valid.

5.3How a signature is verified

A signature is 64 bytes: the encoding of a point R in the first 32, and a scalar S, little-endian, in the last 32. It is pure Ed25519 as RFC 8032 defines it, with the 32 bytes of the digest above as the message: no prehash and no context, so neither Ed25519ph nor Ed25519ctx.

RFC 8032 leaves a verifier two choices, and the verifiers in use differ exactly there, so this protocol makes both. With A the owner's public key, B the base point, M the message, and L the order of the prime order subgroup, which is 2^252 + 27742317777372353535851937790883648493, a node MUST accept a signature if and only if all four of these hold:

  1. S, read as a 256-bit little-endian integer, is below L;
  2. R is the canonical encoding of a point on the curve;
  3. that point is not of small order;
  4. [S]B = R + [k]A, where k is SHA-512 of the 32 bytes of R, the 32 bytes of A and the message, in that order, read as a little-endian integer and reduced modulo L. The equation is checked as written, without multiplying either side by the cofactor.

Any other signature is refused, and the refusal is InvalidSignature. A is a key that passed the three refusals in Notes, so it is never of small order itself.

The third and the fourth are the choices. RFC 8032 never asks about the order of R, and without the third a signature whose R is the identity and whose S is k times the signer's secret scalar verifies. RFC 8032 permits the cofactored equation, [8][S]B = [8]R + [8][k]A, and states it first, and under it a signature whose R carries a torsion component verifies. The holder of a key can make either kind at will, so a node that took them would accept spends every other node refuses, and follow another chain from the first block that carried one.

These vectors are for checking a verifier against. The key is the one whose 32-byte seed is the first 32 bytes of SHA-512 of the ASCII bytes cairn signature vector, and the message is the first 32 bytes of SHA-512 of cairn signature vector message. The first vector is the signature that key makes. The second is the first with L added to S, a second spelling of the same signature that a verifier reducing S would take. The third has the identity as R and k times the secret scalar as S, which both of RFC 8032's equations accept. The fourth has R = rB + T, for T a point of order eight and r the first 32 bytes of SHA-512 of cairn signature vector nonce reduced modulo L, and S = r + ka, which the cofactored equation accepts and the cofactorless one does not.

seed        first 32 bytes of SHA-512("cairn signature vector")
public key  47da95e3585bde332648ce1bf660eb1d68bb4fd9a6b206f80996056edd78995c
message     719caadb13b19302e7bed147c459989d3dd42ea7bdacbec020e90c7a2ef29c50

1 accepted
  R  ee55676db80fe280c81940fa37575a96b8c21ad71eed1fcbe291476eab5e6b20
  S  0d89268dcbb5832ee6a1f74092cd27ca3d725e9ddb9176ebae0f37663b76820b
2 refused, S is not below L
  R  ee55676db80fe280c81940fa37575a96b8c21ad71eed1fcbe291476eab5e6b20
  S  fa5c1ceae5189686bc3eefe370c706df3d725e9ddb9176ebae0f37663b76821b
3 refused, R is of small order
  R  0100000000000000000000000000000000000000000000000000000000000000
  S  da47d66f55f2a53bbd2b3ffbd771feb593dd18170e8c8a23d429af3baebc7909
4 refused, the cofactorless equation does not hold
  R  8a30403f65da91381b89212ab91f54e609038f8cf15a9a15a497697a245745e0
  S  c06945247d082b057059703beedb5cc928346815e7aa6c7fe1afadb508f08b03

5.4Rules a transfer must satisfy

Applied in this order, each producing the refusal named.

#RefusalWhen
1UnsupportedVersionthe version is not one these rules know, which is 1
2NoInputsit spends nothing
3NoOutputsit pays nobody
4TooManyInputspast the network's limit, which is 256 on every network here
5TooManyOutputspast the network's limit, which is 256 on every network here
6DuplicateInputone note named twice
7ZeroValueOutputa note worth nothing
8ValueOverflowthe outputs do not sum

The shape is checked before any signature is verified, because the shape is cheap and a signature is not. The inputs are resolved against the state next, by the refusals in Which witness a spend must carry, and the signatures come last: in a block, after every transfer's inputs have resolved, as the body table in Blocks orders them.

Outputs MUST NOT exceed inputs. The difference is the fee, and it is claimed by the block's coinbase or destroyed; there is no third destination.

5.5Coinbase

FieldTypeBytes
versionu162
heightu648
outputssequence of note4 + 40m
extrasequence of u84 + k

The height is inside the coinbase and MUST equal the height of the block carrying it, so the same coinbase cannot be replayed at another height. extra is free bytes for a miner, bounded, and committed to like everything else.

A coinbase MUST NOT pay more than the schedule allows at its height plus the fees the block's own transfers gave up. Paying less is permitted, and the difference is destroyed rather than held anywhere.

6

Blocks

FieldTypeBytes
versionu162
networku324
heightu648
previoushash32
transactions_roothash32
state_roothash32
historyhash32
timestampu648
difficultyu648
total_worku12816
nonceu648

A first block names thirty two zero bytes as previous, since there is no block before it to name.

The header is a fixed 182 bytes. Nothing in it is optional and nothing is variable-length, which is what lets a header log store them at a fixed stride and what makes extending the header a different problem from extending anything else in this protocol.

A block is its header, its coinbase, and its sequence of transfers. The identifier of a block is the identifier of its header, and the header commits to the body through transactions_root.

transactions_root is the Merkle root, under the merkle domains, of one leaf per transaction: the coinbase first, then the transfers in the order they appear in the block. Each leaf is the hash under the merkle leaf domain of that transaction's identifier. An interior node is the hash under the merkle node domain of its two children in order, and a level with an odd count carries the last node up unchanged rather than duplicating it, which is what stops two different bodies producing one root. The root of no leaves is the hash under the merkle empty domain, and a block always has at least its coinbase, so that case does not arise here.

6.1The order a node applies the rules

This order is normative. Several of these rules are cheap and decisive and the ones after them are not, so applying them out of order lets a sender spend a node's time for nothing.

What the order binds is the rules a block is judged by. Before it begins, a node MAY refuse a block on a fact about the block's own bytes that the order would refuse it for anyway, such as a header that does not meet even the difficulty it claims, or a first block that names a parent; and on a fact about what the node holds, such as an identifier it already knows to be bad, a height below the deepest block it would switch to, or a parent it does not have. None of those turns a block the order accepts into one it refuses. They change only which refusal is named, and what the node does about the peer that sent it.

#RefusalWhat it means
1WrongNetworka header for another network
2BeforeTheNetworkOpeneddated before this network existed
3HeightOverflowa height with no successor
4SoftwareTooOldthe rules here need a build this is not
5UnsupportedVersiona version these rules do not know
6WrongVersionnot the version the rules demand here
7WrongGenesisa first block that is not this network's
8WrongHeightnot one above its parent
9WrongParentnaming a block that is not the tip it follows
10WrongDifficultynot what the retarget demands
11WorkOverflowcumulative work with no room left
12WrongTotalWorknot the parent's work plus its own
13HistoryMismatchnot committing to the headers before it
14InsufficientWorkthe identifier does not meet the target
15BlockTooLargepast the network's byte limit, which is 131 072 on every network here
16TimestampTooFarAheadfurther ahead than the reader allows
17TimestampNotAfterMediannot later than the median before it
18CoinbaseHeightMismatcha coinbase for another height
19TransactionsRootMismatcha body the header does not name
20StateRootMismatcha state the header does not name

Fourteen is where the work is checked, and its position is deliberate. It comes after the header's own arithmetic, which costs nothing, and before the body is looked at, which costs a great deal. A forged block therefore costs its sender the work or costs the reader one hash, once it has been read. Reading it is paid for separately and first: decoding a block decompresses a key off the curve for every owner in it, a frame may be eight times the largest block the rules allow, and so a frame is charged to its sender's allowance by its size before it is decoded. See the allowance.

Sixteen is the one refusal in this list that two honest nodes on the same build can disagree about. It is measured against the reading node's own clock, so the same block is refused by one node and taken by another, and the same node reverses its verdict by waiting. A node MUST NOT remember this verdict as a property of the block, and MUST NOT hold it against the peer that offered it.

Four and five are judgements about the reader's build, not about the block. Two honest nodes on different builds disagree about them by construction, and Rules that activate at a height says what a node MUST NOT do with them: remember them against the block or hold them against the peer. Every other refusal here is a fact about the block that any node reaches from the same bytes.

The body is evaluated between nineteen and twenty, and in this order. Four of these were made by the implementation and stated nowhere here until this revision; by the conformance section they were an omission in this document rather than a defect in the implementation, and they are written out with their numbers now. An earlier revision also put the body between seventeen and eighteen, which the implementation contradicts: the coinbase's height and the transactions root are checked before any of it.

#RefusalWhen
1UnsupportedCoinbaseVersionthe coinbase version is not one these rules know, which is 1
2CoinbaseExtraTooLargethe coinbase carries more than 64 bytes beyond what consensus reads
3TooManyCoinbaseOutputspast the network's limit, which is 16 on every network here
4ZeroValueCoinbaseOutputa coinbase note worth nothing
5TooManyTransferspast the network's limit, which is 4 096 on every network here
6InvalidTransferevery transfer in block order: its shape by the transfer rules above, then its inputs by the refusals in Which witness a spend must carry
7ValueOverflowthe fees the transfers give up do not sum
8InvalidSignatureonce every transfer has passed six, the first input in block order whose signature does not verify
9ValueOverflowthe schedule's reward plus the fees, or the coinbase's outputs, do not sum
10CoinbaseOverpaythe coinbase claims more than the schedule pays plus the fees given up
11TooManyEvictionspast the network's eviction cap
12SupplyDoesNotAddUpthe running supply is not the parent's plus what this block issued

InvalidSignature is reported as InvalidTransfer naming the transfer and the input, like every refusal of a transfer. Because the signatures are verified together after every transfer has resolved, a block whose first transfer is badly signed and whose second is badly shaped is refused for the second transfer's shape. The verdict is the same either way; only the name differs.

Seven, and the first half of nine, cannot happen on any chain these rules produce: fees are given up by notes that exist, so they sum to at most the supply, and the schedule keeps the supply near a tenth of the monetary ceiling. They are named because part 1 names every overflow. The second half of nine can happen: a coinbase carries up to sixteen outputs, each of them an amount, and sixteen amounts need not sum to one. A node asks seven as each transfer passes six, which reaches the same verdict as asking it once afterwards on any chain that can exist.

A block MUST NOT both spend a note and evict it.

The four limits in that table are the network's rather than the format's, and the format holds a ceiling at or above each so that a decoder refuses what no network allows before any rule has read the frame: 256 inputs, 256 outputs, 16 coinbase outputs and 4 096 transfers. The decoder holds the coinbase's extra to its 64 bytes too, so row two of the body table is reached only by a block built beside the rules that judge it, never by one read off the wire. A build whose rules asked for more than its own decoder accepts would refuse blocks its rules allow, which is a fork with nobody at fault, so the two are checked against each other at compile time.

7

The state

The state is the set of unspent notes, split across two tiers, together with three things a block's validity depends on that no note holds: what fell recently, which coinbases cannot be spent yet, and how much money exists. A block header carries all of it as one hash, state_root.

Nothing in a block declares any part of it. A block declares state_root and nothing else about the state. Which notes fall, where each one lands, what the grace window holds afterwards, which coinbases are still waiting and what the issued total comes to are each derived by every node from the state it already holds and the block's own transactions. A node that derives any of them differently refuses the block with StateRootMismatch, and cannot say which part it disagreed about. So every derivation below is normative in the strongest sense available: getting one of them wrong is not a wrong answer to one question, it is a different chain from the first block that reaches the rule.

7.1The two tiers

The hot set is the notes every node holds in full. A note enters it when the transaction that creates it is applied, and leaves it when it is spent or when it is evicted. Spending a note in the hot set takes nothing from the spender but the note's identifier, because every node already has the rest.

The cold set is every note that has been evicted from the hot set and not spent since. It has no bound and no node is required to hold any of it. What a node holds is an append-only accumulator over it: at most 64 hashes and two counters, whatever the set contains. Spending a note in the cold set means supplying the note and a proof.

The hot set holds at most hot_capacity notes. hot_capacity is a consensus parameter of the network and MUST NOT be a choice an operator makes. Two nodes running different values compute different roots for the first block that fills the smaller of them, and go on computing different roots for every block after it, while each believes it is on the same chain as the other. There is no refusal that catches this and no message that reports it, which is why it is written as a rule here rather than left as a number an implementation picks.

Parametertestnet-6devnetWhat it bounds
hot capacity131 07264notes the hot set holds
evictions per block1 0241 024notes one block may push out
coinbase maturity1 02432blocks a reward waits

Mainnet is not in that table because it does not exist: a network exists once its first block does, and there are no mainnet values to state until there is one.

The grace window's two bounds, 64 blocks and 8 192 notes, are protocol constants rather than network parameters: every network carries the same two.

Devnet is a throwaway network and is listed only because a second implementation that supports it has to get it right. It lowers the hot capacity and inherits the eviction cap, so there the cap is larger than the tier and one block can empty the whole of it. On testnet-6 the cap is a hundred and twenty eighth of the tier, so emptying the tier takes at least 128 blocks whatever shape the blocks take.

7.2What the state root commits to

state_root is the hash, under the state commitment domain, of the following in this order. Nothing else is folded in, and no field is ever left out: an empty window is a count of nought and no entries, not an absent field.

#FieldTypeBytes
1hot roothash32
2hot countu648
3cold commitmenthash32
4cold countu648
5grace roothash32
6maturing countu648
7each maturing entry, oldest firstu64 then hash40 each
8issued totalamount8

The hot count is the number of notes in the hot set, not the number of nodes in the tree that commits to them. The cold count is the number of leaves in the accumulator that have not been emptied, which is not the number of positions it has handed out; the difference is committed to inside the cold commitment rather than here.

Both counts are folded in, so the boundary between the tiers is itself part of the commitment. Without them a node could hold more or fewer notes hot than the rules allow and still agree with everyone on the roots.

The maturity window and the issued total are folded in here rather than each through a commitment of its own, and neither is given a name in the header. Both decide which blocks are valid, so both have to be committed to: a node handed a state rather than building one would otherwise start with an empty window and a supply of nothing, and disagree with the network about which blocks are valid with nobody at fault. The window is written length first, so no two windows produce the same bytes.

The domains this section uses are in the identifiers section, which publishes all twenty.

7.3The hot set

The hot set is committed to by a sparse Merkle tree keyed by note.

A note's key is the hash, under the note key domain, of the note identifier's 36-byte encoding. The 32 bytes are read as a path from the root, one bit per level, starting at the most significant bit of the first byte; a set bit means the right child. The identifier is hashed rather than used as the key directly, because every note one transaction creates shares its source identifier, and using it raw would pile those notes onto one path and deepen every proof through it.

A note's value is the hash, under the hot note value domain, of the note's 40-byte encoding followed by the height of the block that created it, as a u64. The height is committed to because it decides eviction order. Leaving it out would let two nodes hold the same notes, agree on the root, and still evict different ones.

The tree's hashes are defined by what a subtree holds, and by nothing else:

A subtree holdingHashes to
no keythe hash of no bytes under the accumulator empty domain
exactly one keythat key's 32 bytes then its value, under the accumulator leaf domain
two keys or moreits left half then its right half, under the accumulator node domain

The single-key case is what makes the root a function of the set alone. A subtree holding one key hashes the same whatever depth it sits at, so a tree never remembers that a sibling once existed, and two nodes that reached the same set by different sequences of insertions and removals reach the same root. An implementation that keeps an internal node above a lone leaf computes a different root for the same set of notes.

The hot root of an empty hot set is therefore the accumulator empty hash, and the hot count is nought.

7.4Eviction

Eviction happens on every block, after the block's transactions have been resolved, and only where the tier would otherwise be over its capacity.

Let the hot set be the one that stood at the block's parent. Let spent be the note identifiers this block's transfers take out of the hot set. A note spent under the grace window is not one of these: it had already fallen, and it comes out of the cold set. Let created be every note this block creates, in this order: the transfers in the order they appear in the block, each transfer's outputs in index order, then the coinbase's outputs in index order. That order decides nothing a rule reads: the hot tree is a set, and the shortfall below sorts by identifier. It is given so that a block's notes have one order to be described in.

Let surviving be the hot count less the number of notes in spent, and let overflow be surviving plus the number of notes in created, less hot_capacity, or nought when that difference would be negative.

If overflow is nought, nothing falls.

Otherwise the notes that fall are the first overflow of the hot set, ordered by the height they were created at ascending, then by note identifier ascending, skipping any note in spent. Two note identifiers are ordered by their 32-byte source hash first, compared byte by byte from the first, then by their index as a number.

The ordering is normative and not merely a convention, because it decides the order leaves are appended to the cold accumulator, and therefore which position each fallen note takes, what the cold commitment comes to, and what the grace window holds. Two nodes that break ties differently agree on which notes fell and disagree on every root afterwards.

Nothing a block contains can move a note up or down that order. The key is the creation height and the identifier, both settled the moment the note exists. Spending notes only takes candidates off the list; it never promotes one. So the only thing a block decides is how far down the list the cut falls, and it pays for every step in notes it has to create.

If the hot set does not hold overflow such notes, the shortfall is made up from created, ordered by note identifier ascending, taking from the start. That is reachable only when one block creates more notes than the whole tier holds, in which case those notes all sit at the same height and the identifier is all that separates them.

A node MUST refuse a block whose eviction list is longer than max_evictions_per_block, with TooManyEvictions. How fast the hot set turns over is a shared resource: every note pushed out is somebody's money now needing a proof to spend, and the pusher chooses whose by choosing nothing, since it is always the oldest that falls. Fees put a price on that; a miner includes its own transfers for free, so this is the bound that holds whatever anyone pays.

The block's effect on the two tiers MUST be applied in this order, and the order is part of the rule rather than an implementation's convenience:

  1. every note the block spends out of the cold set is emptied from the accumulator, all of them proved against the roots as they stood at the parent before any of them is applied;
  2. the accumulator is checked to have room for the notes about to fall, which on any chain these rules produce it has, since its positions are counted in 64 bits;
  3. every note the block spends out of the hot set is removed from the hot tree;
  4. every note the block creates is inserted into the hot tree, carrying this block's height;
  5. each note in the eviction list, in eviction order, is removed from the hot tree and appended to the accumulator at the next free position.

A node that finds, applying a block it has already judged valid, that step 1 or step 2 cannot be done, has found itself holding a state it disagrees with. That is not a refusal a peer can cause and not one another implementation has to reproduce; the reference names it NoteNotWhereProved and refuses the block rather than carry on with a root that describes nothing.

Step 4 before step 5 is what lets a note created by this very block fall straight through to the cold set, which is the case the shortfall rule above is about. The eviction order skips every note the block spends, which is what makes it true that a block never both spends a note and evicts it.

7.5The grace window

The grace window is what fell recently, held in full by every node, so that a note that fell moments ago can still be spent without the spender proving anything.

It is a list of per-block landings, oldest first. Each landing is the notes that fell in one block, in eviction order, each written as its identifier, the position it took in the accumulator, and the note itself. A landing is kept even when it is empty.

The grace root folded into the state root is the hash, under the grace window domain, of: the number of landings as a u64; then, for each landing in order, the number of notes in it as a u64, then for each note its 36-byte identifier, its position as a u64, and its 40-byte encoding.

After a block, the window is the parent's window changed as follows, in this order:

  1. every note this block spends out of the cold set is removed from whichever landing holds it, the rest of that landing keeping its order. A note that has been spent cannot be spent again, so it has no business in a window that says what may be spent without a proof, and a node that left it there would go on naming a note it can no longer prove;
  2. this block's own landing is appended;
  3. while the window holds more than 64 landings, or more than 8 192 notes in total, the oldest landing is dropped.

Step 3 counts landings and notes, whichever runs out first, and it drops from the oldest end only. If a block lands more notes than 8 192, step 3 runs the window out and then reaches the landing this block just appended, and the window is left empty: what that block landed was never in the window at all. That cannot happen on a network whose eviction cap is below 8 192, and it is specified because a network is free to set one that is not.

A node MUST hold, for every note in its window, the note in full, the position it took, and a proof for that position that verifies against the cold accumulator as it currently stands. A node that cannot produce one cannot validate a proofless spend the rest of the network accepts, and cannot hand its state to a newcomer.

Under the block bound, a note that fell in the block at height f may be spent without a proof by the blocks at heights f + 1 through f + 64 inclusive, and not by the block at f + 65. Said of the window rather than of the note: after the block at height h it holds the landings of the blocks at heights h - 63 through h, and the block at h + 1 is judged against that. The note bound moves that edge earlier whenever more than 128 notes a block are falling.

7.6Which witness a spend must carry

Part 2 gives the two witness shapes. Which of them an input must carry is a question about the state, and this is the answer.

The note isTag 0, no proofTag 1, with a proof
in the hot setrequiredrefused, UnexpectedProof
in the grace windowacceptedaccepted
cold, outside the windowrefused, MissingProofrequired

Inside the window both tags are accepted and they reach the same state: either way the note is taken out of the accumulator at its position, and either way the transfer has the same identifier, because a transfer's identifier leaves its witnesses out. A node MUST NOT treat the two as different transfers.

MissingProof names two situations a node cannot tell apart: a note that fell and whose spender did not prove it, and a note that never existed. A node holds neither the cold set nor a record of what was never in it.

The state-dependent refusals a transfer's inputs produce. Inputs are resolved in the order they appear. Within one input, the first two are asked before anything else, the middle four are the branches of where the note turns out to be, and the last is asked once every input has resolved.

#RefusalWhen
1UnknownNotean earlier input in this block already spent it
2ImmatureCoinbaseits source is a coinbase still in the maturity window
3UnexpectedProofit is in the hot set and the input carries a proof
4MissingProofit is neither in the hot set nor in the window, and the input carries no proof
5UnknownNotethe window names it and the accumulator no longer holds it
6InvalidProofthe proof does not verify against the cold commitment
7OutputsExceedInputsthe outputs total more than the inputs, once every input has resolved

Adding each input's value to the running total is an operation on decoded values, so a total that does not fit is refused ValueOverflow, and on a chain these rules produce it never is, for the reason the body table gives for fees.

Rows three to six assume the node holds what What a node MUST hold and what it MAY discard requires of it, the path of every note in its grace window among them. A node that has lost one answers MissingProof for a spend of a window note that every other node takes, which is a fault in that node and not in the block.

A transfer MUST NOT spend a note created by the same block. Every input is resolved against the state as it stood at the block's parent, and a note this block creates is not in it. There is no chaining inside a block.

7.7The cold set

The cold set is committed to by an append-only forest of perfect binary trees.

A node holds two counters and one root per tree. leaves is the number of positions ever handed out. live is the number of leaves not yet emptied. The forest holds one tree for each set bit of leaves: the tree for bit h is a perfect tree of height h, holding two to the power h leaves. The trees are laid out largest first, so reading the bits of leaves from the highest down, each tree that exists takes the next run of positions after the one before it. So the oldest leaves sit in the biggest tree and a merge only ever extends a tree upward, which is what keeps a position's meaning stable for the life of the chain.

A position is handed out when a note falls and is never reused. Emptying a leaf leaves the position where it is rather than reshaping the forest around the hole, so a proof taken today describes the same place tomorrow. That costs a forest that never shrinks, and buys a holder who can keep their own proof current from what every block already carries.

HashIs
the leaf of a fallen noteits 36-byte identifier then its 40-byte encoding, under the forest leaf domain
the empty leafno bytes, under the forest leaf domain
an internal nodeits left child then its right child, under the forest node domain

The identifier is folded into the leaf because a position carries no meaning of its own: without it, a proof for one note would serve for another note of the same value and owner sitting elsewhere. The creation height is not folded in. A cold note never falls again, so nothing needs it, and putting it back would add eight bytes to every cold leaf, every proof and every spend.

The cold commitment folded into the state root is the hash, under the forest roots domain, of: leaves as a u64; live as a u64; then, for each height from 0 to 63 in ascending order that has a tree, one byte of height followed by that tree's 32-byte root. The ascending order here is the reverse of the order the trees are laid out in, and getting it backwards produces a commitment that agrees with nobody.

Appending a leaf reads and writes the roots and nothing else, which is what lets a node holding none of the set keep the commitment current. The new leaf becomes a tree of height 0; while a tree of the same height already exists, that existing tree becomes the left child, the carry becomes the right, and the two merge into a tree one height taller.

7.8Proofs

A proof for a position is the siblings from its leaf up to the root of the tree it sits in, bottom first, and nothing else. The position is not part of the proof and is carried beside it.

Verifying a proof for a leaf at a position requires the current leaves count and the current roots, and nothing more:

  1. find the tree holding the position, reading leaves from the highest bit down; if the position is at or above leaves, refuse;
  2. the proof's sibling count MUST equal that tree's height, or refuse;
  3. take the position's index within the tree, which is the position less the tree's first position;
  4. starting from the leaf, for each sibling in order: if the index's low bit is nought the running value is the left child and the sibling the right, otherwise the other way round; hash the pair as an internal node; then shift the index right by one;
  5. the result MUST equal the root of that tree.

A proof is checked against the accumulator as it stands and against nothing else. There is no window of past roots. Accepting an old proof would be half a rule: emptying a leaf folds the empty leaf up the path the proof carries, and an old path does not reach the root that is there now, so the removal would do nothing and the note could be spent again. Completing the other half would mean holding, as committed state, everything that changed in between, which grows the one thing this design bounds. Refusing a stale proof costs nobody anything: a transfer whose proof went out of date is the same transfer with a newer proof, offered again, and refreshing a witness does not change a transfer's identifier.

Exactly three things change a proof, and a holder who follows every block can keep one current from what the blocks already carry:

  • an append that merges the tree the position sits in adds one sibling at the top, and the proof grows by one;
  • the emptying of another leaf in the same tree replaces exactly one sibling;
  • undoing either puts back what was there.

Nothing else touches it. A proof's length is always the height of the tree the position currently sits in.

Emptying a leaf takes a proof for what is there. The presented leaf MUST NOT be the empty leaf: after a removal the root above the position is exactly what folding the empty leaf gives, so a second removal of the same place would verify, and would take the count down for a leaf that is not there. The roots do not move to show it and only the count would, and the count is committed to. Emptying replaces the tree's root with the fold of the empty leaf up the proof's path, and decreases live by one. leaves does not change.

Every cold spend in one block is verified against the roots as they stood at the parent, all of them before any is applied, then applied in ascending position order with the proofs still waiting brought up to date. So the order the spends appear in the block does not affect either whether they are accepted or what they leave behind. Verifying them one after another as they are applied would refuse valid blocks, because emptying one leaf moves the siblings of every other leaf in its tree.

7.9The maturity window and the issued total

The maturity window is the coinbases whose notes cannot be spent yet. Each entry is the first height at which that coinbase's notes may be spent, followed by the coinbase's identifier, and the entries are ordered oldest first. One entry covers however many notes that coinbase paid.

The entry names the coinbase rather than the notes because every input already carries it: a note a coinbase created has that coinbase's identifier as the source half of its own. So the rule can be asked of an input without knowing where the note is, and a spender cannot get a different answer by letting the note fall to the cold set and bringing it back with a proof.

After the block at height h the window is the parent's window with:

  1. every entry whose height is at or below h removed. These form a prefix, since heights only increase;
  2. an entry appended, holding h + coinbase_maturity and this block's coinbase identifier, unless the coinbase paid no outputs, or unless h + coinbase_maturity is not above h. A coinbase whose notes are spendable from the very next block, which is as soon as any note is, since nothing is spent in the block that creates it, never enters the window at all.

A transfer in a block at height H MUST NOT spend a note whose source names a coinbase in the window whose height is above H. The refusal is ImmatureCoinbase. A reward becomes spendable exactly on the block whose height is the entry's, which is also the block that takes the entry out.

The issued total is every pebble this branch has created and not destroyed. It is the one number that says how much money exists: the note set is the money, but it is held as two accumulators of which no node holds one, so no node could add it up.

A block creates whatever its coinbase pays and destroys whatever its transfers gave up as fees, since the fees are money that already existed and whatever the coinbase declines to claim is gone. So after a block:

  • if what the coinbase paid is at or above the fees, the total rises by the difference, and a total above the monetary ceiling is a refusal;
  • otherwise the total falls by the difference, and a total that would go below nought is a refusal.

The refusal is SupplyDoesNotAddUp either way. Neither direction saturates. Going over the ceiling means a chain that has issued more than any amount can hold; going under nought means a block destroyed more money than the chain ever issued, which cannot happen to a sound ledger and is exactly the sort of thing that should stop a block rather than be rounded away.

7.10What a node MUST hold and what it MAY discard

This is the claim the design rests on, and it is stated as two lists so that it can be checked rather than believed.

A node MUST hold:

  • every note in the hot set, in full, with the height of the block that created it;
  • the cold accumulator's roots, at most 64 hashes, and its two counters;
  • every note in the grace window, in full, with the position it took, and a proof for each position that verifies against the cold roots as they stand;
  • the maturity window;
  • the issued total.

Every one of those is bounded by a rule rather than by the chain's age. The hot set is bounded by hot_capacity, the accumulator by the width of its leaf count, the grace window by its two constants, and the maturity window by coinbase_maturity, since an entry leaves on the block where its notes become spendable and never comes back.

A node MAY discard, and the reference implementation does:

  • every note in the cold set that is not in the grace window: its value, its owner, its position, and its leaf;
  • every proof for a position outside the grace window that it was not asked to keep.

No rule in this document requires a node to hold any part of the cold set beyond the grace window. That is checkable from the rules above rather than taken on trust: every rule that reads the cold set reads its roots, its two counters, and a proof somebody else supplied, and appending to it needs nothing but the roots.

A node MAY keep every leaf the accumulator has ever held, which is the only way to rebuild a proof for someone who lost theirs. Nothing in these rules requires any node to do so, no rule depends on one existing, and nobody is paid for it. The person who needs it is whoever lost their own proof.

A node MAY keep a current proof for the fallen notes of owners it was asked to follow, which is what lets a wallet spend later without asking anyone. A node that does SHOULD bound how many such notes it follows, and SHOULD choose which to let go of by a rule that makes displacing one cost more than the note is worth. An owner is a public key on a public chain, so the set of notes paid to a followed owner is chosen by strangers: without a bound, a dust note costs its sender one transfer and costs the node an entry and a full path for good. The reference implementation follows at most 8 192 notes and lets go of the least valuable first. Neither the bound nor the policy is consensus, and a node that gets either wrong costs only itself and the wallets it serves.

8

Consensus

This part specifies what decides which chain is the chain: the work a block must carry, the difficulty it must carry it at, the timestamps it may claim, what it is allowed to pay, and how a node chooses between two branches that both hold. Everything here is a rule two nodes must reach the same answer on, with one exception, which is named where it occurs and is the only one.

The values below belong to a network rather than to the protocol. Two nodes that disagree about any of them build different chains while believing they are on the same one, so they are chosen by naming a network and never set one at a time by whoever starts a node.

ParameterValueWhat reads it
target block time60 sthe retarget and the solve-time clamp
genesis difficulty227the first block, before any history exists
drift allowance600 show far ahead of a reader a timestamp may sit: ten target block times
halving interval1 051 200the emission schedule
initial reward5 000 000 000 pebblesthe emission schedule
tail reward1 000 000 pebblesthe emission schedule
burial1 024settlement depth
coinbase maturity1 024when a reward becomes spendable
activationsheight 0, version 1which rules judge which height

A throwaway network may set some of them far lower, and the reference implementation's does: a five second block, a genesis difficulty of 223, and a burial and maturity of 32. The emission schedule is the same everywhere. The drift allowance is ten of the network's own target block times everywhere, so the throwaway network's is 50 seconds: it is measured against the retarget's clamp, which is counted in blocks, and a number of seconds shared by networks whose blocks differ twelvefold is what the timestamp rules below were once wrong about.

8.1Proof of work

A block's difficulty is a plain u64 in its header. There is no compact encoding, no mantissa and no exponent: the number in the header is the difficulty, and a second implementation has nothing to unpack.

The target is a 256-bit value derived from the difficulty. Write MAX for the 256-bit value whose every byte is 0xff, which is 2256 minus 1. Then for a difficulty d:

  • if d is 0 or 1, the target is MAX;
  • otherwise the target is MAX / d, integer division, truncated.

The two branches agree at d = 1, so the first exists only to give an answer at d = 0. A block claiming difficulty 0 is refused elsewhere, since the difficulty a block may claim is fixed by the retarget and the retarget never answers below 1.

Doubling the difficulty halves the space of acceptable identifiers, and the division is over the whole 256-bit range rather than over a power of two, so a second implementation MUST do the long division and MUST NOT approximate it. The reference implementation divides four 64-bit limbs, most significant first, carrying the remainder, and writes each quotient limb out big-endian. These are the answers it produces, and a reimplementation that reproduces them has reproduced the division:

DifficultyTarget, 32 bytes, most significant first
1ff repeated 32 times
27f, then ff 31 times
355 repeated 32 times
43f, then ff 31 times
533 repeated 32 times
4 09600 0f, then ff 30 times
22300 00 01, then ff 29 times
22700 00 00 1f, then ff 28 times

What a node checks is one comparison. It computes the block's identifier, which is the hash of the encoded header under the block header domain, reads it as an unsigned 256-bit integer with its first byte most significant, and accepts the block only if that integer is less than or equal to the target. Equality passes. Both values are exactly 32 bytes, so comparing them as unsigned big-endian integers and comparing the two byte arrays lexicographically from the front are the same comparison, and an implementation MAY do either.

The work a block contributes is its difficulty, unchanged and unscaled. The header's total_work MUST equal the parent's total_work plus this block's difficulty, and the first block's MUST equal its own difficulty. Difficulty is the work directly because the chance a uniformly distributed 32-byte identifier meets the target is one in d to within a part in 2256; a reader who expects a conversion between the two is expecting one this protocol does not have.

8.2The difficulty retarget

Every block retargets. There is no epoch and no boundary at which the difficulty is allowed to move and between which it is not.

ConstantValueWhat it is
difficulty window90gaps the answer is weighed over
solve-time clamp6multiple of the target block time one gap may count for, in either direction
retarget clamp4factor one step may move the difficulty by, in either direction
minimum difficulty1the floor, at which every identifier meets the target
headers kept91summaries a node must hold to apply every rule here

The input is a run of header summaries from the branch the candidate block extends, oldest first. A summary is a height, a timestamp and a difficulty, and nothing else: a node MUST hold the last 91 of them and MUST NOT let the answer depend on holding more. A node given a longer run MUST use only the last 91, or two honest nodes with different amounts of history would demand different difficulties of the same block.

Given that run h[0] … h[m-1] and a target block time T:

  1. If m is 0, the branch has no blocks and the answer is the network's genesis difficulty, or 1 if that is lower.
  2. Let last be h[m-1], and let n be the smaller of m - 1 and 90.
  3. If n is 0, or T is 0, the answer is last.difficulty, or 1 if that is lower. Stop.
  4. Let w[0] … w[n] be the last n + 1 summaries. w[0] is the anchor and contributes no gap and no difficulty; the n after it contribute one each.
  5. Let ceiling be T * 6.
  6. Set counted to w[0].timestamp, weighted to 0, and sum_d to 0.
  7. For i from 1 to n, in order, over signed arithmetic wide enough not to wrap: gap = clamp(w[i].timestamp - counted, -ceiling, +ceiling), then counted = counted + gap, then weighted = weighted + i * gap, then sum_d = sum_d + w[i].difficulty.
  8. Let previous be last.difficulty, or 1 if that is lower.
  9. If weighted is zero or negative, the answer is previous * 4, and nothing below applies. Stop.
  10. Let expected = n * (n + 1) / 2 * T.
  11. Let average = sum_d / n, or 1 if that is lower.
  12. Let next = average * expected / weighted.
  13. Let low = previous / 4, or 1 if that is lower, and high = previous * 4.
  14. The answer is next clamped into low … high, and never below 1.

Every division is integer division truncated toward zero, and every quantity divided at steps 10 to 14 is non-negative.

Each gap is measured from counted and not from the previous header's own timestamp. That is the one step an implementer will write differently by reflex, and writing it differently produces a different chain. counted is a timeline the retarget keeps for itself: it opens at the anchor's timestamp and then moves only by what the retarget actually counted, so a header thrown forward past the clamp advances the timeline by the clamp and no more, and the headers after it have their gaps measured from where the timeline really stands. The excess comes back in full while the header is inside the window. Measuring each gap against its own parent instead leaves the give-back short by whatever the clamp cut off, which is exactly the difference a miner holding two blocks in a row keeps.

The anchor's timestamp is taken raw, and that is the one place the excess is counted a second time. When a header thrown forward becomes w[0], the timeline opens at the time it claimed, so the gaps after it measure short by what it claimed beyond the clamp, once, for the retarget that has it as its anchor. At a drift allowance of ten target block times that is under a hundredth of the steady difficulty on either network, measured; it was 1.36 times the steady difficulty on a sixty second chain and four times on a five second one when the allowance was two hours.

Three edge cases the rule answers explicitly, and each is a case a second implementation reaches by accident before it reaches it on purpose.

A span of zero. A window whose timestamps are all the same measures no time. It is not a division by zero and it is not an unchanged difficulty: the answer is the steepest rise the rule allows, previous * 4.

A span running backwards. A gap may be negative, down to -ceiling, and a window can therefore weigh out to a negative total. That is a chain claiming it produced its blocks in less than no time, and it takes the same answer as a span of zero: previous * 4. A negative gap is worth the time it gives back and not one second more, which is what stops a miner buying difficulty by alternating a forward jump with a backward one.

Saturation. Every addition and multiplication saturates rather than wrapping. If previous * 4 is past what a u64 holds, the answer is u64::MAX. If average * expected is past what a u128 holds it saturates there before the division, and the clamp at step 14 bounds the result in any case. An implementation that wraps instead of saturating at any of these points has left the protocol.

On a chain shorter than the window the same formula runs with n = m - 1, and the weights, the expected span and the average all follow n. There is no warm-up rule and no special case. Two consequences: the block at height 1 sees one summary, so n is 0 and it MUST carry the genesis block's difficulty unchanged; the block at height 2 is the first that can retarget, off a single gap.

Two properties of this rule are easy to state backwards, and both have been stated backwards in this project's own documents.

It answers slowly, in hours rather than minutes. The weights run 1 to 90 and sum to 4 095, so the newest gap carries 90 parts of 4 095, about 2.2 per cent of the measurement. Measured on a chain warmed to a full window exactly on schedule at difficulty 1 000 000, one block arriving at the clamp ceiling, which is six times the target, brings the next difficulty to 900 990, about a tenth of the way down, and a block arriving a hundred times the target late brings it to the same 900 990, because the clamp makes the two the same block. On the same fixture a hash rate that halves has half of the doubling correction after 22 blocks and 2 247 seconds of chain time, which is 37 minutes, and ninety per cent of it after 90 blocks and 7 345 seconds, a little over two hours. A tenfold loss reaches ninety per cent after 64 blocks and 13 080 seconds. The damping is what a miner writing its own timestamps cannot get past, and it is the same damping that makes an honest answer take hours.

At the floor the rule reduces to a division, and the floor is held from about half the target and not from the target. When previous is 1 and every difficulty in the window is 1, average is 1 and steps 10 to 12 collapse: with a window spaced evenly g seconds apart, expected is 4095 * T, weighted is 4095 * g, and the answer is T / g clamped into 1 … 4. At a sixty second target, for an evenly spaced window:

SpacingNext difficulty
1 s4 (the clamp; the ratio is 60)
15 s4
20 s3
30 s2
31 s1
60 s or more1

So a chain at the floor spaced evenly 31 seconds apart holds the floor for as long as anyone cares to keep it, and one spaced evenly 30 apart leaves it at the second block. A chain need not be spaced evenly. The floor holds while weighted stays above 4095 * T / 2, and ninety gaps of 30 seconds with one of 31 among them keep it there for ever, at a mean just over 30 seconds; the first window after a fork holds the honest chain's gaps, which buys a little more at the start. The tightest branch of 1 024 blocks found, taking each timestamp as low as the median rule and a retarget of 1 allow, spans 30 069 seconds, 8 h 21 m, against the 31 744 an even 31 seconds gives.

Any argument that prices a run of blocks at the floor MUST price it by what such a run can span and not at a per-block spacing: a run of 1 024 at 30 069 seconds or less, and never at the target, which is twice what it costs. The figure is measured rather than derived, and an implementation that finds a tighter branch has found a smaller number that arguments are then bound by. Off a real difficulty the same spacing is not free: 31 seconds a block off 220 asks for very nearly twice the difficulty a block.

8.3Timestamps

A timestamp is a u64 count of seconds since the Unix epoch. There is no sub-second part and no signed value, so no block can be dated before 1970.

Three rules read it, and they are not three of a kind.

Not before the network opened. A node MUST refuse a block whose timestamp is below the network's opening moment. That moment is a network parameter, published before the network exists, and it is what makes the opening the same for everyone rather than the property of whoever knew first.

Later than the median time past. A node MUST refuse a block whose timestamp is less than or equal to the median time past of the branch it extends, when that branch has one. The median time past is computed from the last 11 header summaries of the branch, or all of them if it holds fewer: take their timestamps, sort them ascending, and take the element at index len / 2, counting from zero, with len the number of timestamps. For an odd count, which is every branch of 11 blocks or more, that is the median. For an even count it is the upper of the two middle values, not their mean, and an implementation MUST NOT average them. A branch with no blocks has no median and the rule does not apply to its first block.

The median rather than the parent's own timestamp, because a miner writes its own header but holds one vote in a median it cannot move, so backdating a block to claim an easier difficulty stops working.

Not further ahead than the reader allows. A node MUST refuse a block whose timestamp is greater than the node's own clock, read as seconds since the Unix epoch, plus the network's drift allowance, which is ten of its target block times: 600 seconds on the public networks.

The allowance is counted in blocks because what it is measured against is. It was 7 200 seconds on every network, which is twenty of the retarget's clamp ceilings at a sixty second block. A minority dating its blocks that far ahead, or an honest miner whose clock was an hour or two fast, held the median time past in the future; an honest block dated at the median plus one then moved the retarget's timeline a second while real time moved a minute, and the retarget read a chain producing blocks in no time and asked for its steepest rise, block after block. Measured with a thirty per cent share, a sixty second chain ran at 1.53 times its target with single blocks asked for 115 times the steady difficulty, and a five second one at fourteen times its target. At ten target block times the same share leaves both within a tenth of their target. A clock kept by NTP meets ten minutes with room.

The first two are facts about the block. The third is a fact about the reader, and that distinction is load-bearing. Two nodes given the same bytes and the same branch reach the same verdict on the opening moment and on the median, and a block refused for either is refused everywhere and for good. The drift bound is measured against a clock the block knows nothing about: the same block is refused by one node and taken by another, and the same node reverses its verdict by waiting. It is the only refusal in the whole of the block rules that two honest nodes on the same build can disagree about.

Three obligations follow, and a node that gets any of them wrong harms itself rather than the network, which is why they must be written down.

  • A node MUST NOT remember a drift refusal as a property of the block. The block is not invalid; the reader is early. A node that records it will go on refusing the block after its clock has caught up, and nothing will tell it why.
  • A node MUST NOT hold a drift refusal against the peer that offered the block. It MUST NOT close the connection, count it as misbehaviour, or refuse the peer's address on account of it. Every peer relaying that block behaves identically, so a node that penalises them refuses the entire network for being right, and does it silently, and does it fastest when it is most wrong.
  • A node re-applying a block it has already accepted and then undone SHOULD ask the drift question against the block's own timestamp rather than against its clock. A valid header cannot sit more than the drift ahead of its own timestamp, so asking it that way asks a question the block has already answered, and it removes the one rule whose answer can change while the block does not. Without this, a clock that steps backwards, which is an NTP correction or a flat battery, makes a node refuse its own history and stand at a fork point it cannot leave.

Nothing else in these rules reads a clock. The drift bound is the whole of the protocol's dependence on wall time.

8.4Emission

The schedule is counted in blocks, so it is a property of the chain rather than of anyone's clock.

QuantityPebblesCAIRN
opening reward5 000 000 00050
floor reward1 000 0000.01
blocks between halvings1 051 200

The reward at height h is computed as follows. Let e = h / 1 051 200, integer division. Let r be the opening reward in pebbles shifted right by e bits, taken as 0 when e is 64 or more. The reward is the larger of r and the floor reward. The shift is on the pebble count, so it truncates: through e = 9 the halvings divide evenly, and from e = 10 they do not. An implementation that halves a decimal quantity and rounds will pay a different reward at heights above 10 512 000 and fork there.

EraFirst heightReward, pebblesReward, CAIRN
005 000 000 00050
11 051 2002 500 000 00025
22 102 4001 250 000 00012.5
33 153 600625 000 0006.25
44 204 800312 500 0003.125
55 256 000156 250 0001.5625
66 307 20078 125 0000.78125
77 358 40039 062 5000.390625
88 409 60019 531 2500.1953125
99 460 8009 765 6250.09765625
1010 512 0004 882 8120.04882812
1111 563 2002 441 4060.02441406
1212 614 4001 220 7030.01220703
13 and after13 665 6001 000 0000.01

The thirteenth halving would take the reward to 610 351 pebbles, which is below the floor, so it never happens: the floor takes over at height 13 665 600 and the reward never falls again. The schedule never reaches zero.

The total the halvings pay out. Thirteen eras, each paying its own rate for 1 051 200 blocks. The thirteen rates in the table sum to 9 998 779 296 pebbles. That is worth checking twice, because it is a number nothing else produces. Halved exactly and without a floor the rates would sum to 10 000 000 000 pebbles less 1 220 703.125, which is everything the fourteenth era and all those after it would have paid, giving 9 998 779 296.875; and truncating the shift at eras 10, 11 and 12 takes off half a pebble, a quarter and an eighth, which is the remaining 0.875. Multiplying by the interval:

9 998 779 296 * 1 051 200 = 10 510 716 795 955 200 pebbles,

which is 105 107 167.959552 CAIRN. That is the whole of the halvings, paid by height 13 665 599 inclusive.

Above that height the floor adds 1 000 000 pebbles a block for ever. At a sixty second block that is 525 600 blocks and 5 256 CAIRN a year, about one twenty-thousandth of what the halvings paid, and the share only falls as the total grows.

Two things the schedule is and is not. It is a ceiling: a coinbase MUST NOT claim more than the reward at its height plus the fees its block's transfers gave up, and it MAY claim less, in which case the difference is destroyed and goes nowhere. So the money a chain has actually issued at a height is at most the running total above and may be under it, and the running total is the one thing about a handed-over ledger that can be checked against the rules rather than against a commitment its sender wrote.

And it is bounded by the monetary ceiling like every other amount. No amount in this protocol may exceed 100 000 000 000 000 000 pebbles, which is 1 000 000 000 CAIRN, and a running total computed past it is answered as the ceiling rather than allowed to wrap. No chain reaches it: from the last halving the floor would need about 170 000 years to add the difference.

8.5Fork choice

What is compared is one number, the total_work the tip of a branch states in its header. On a valid branch that number is the sum of the difficulties of every block up to and including the tip, and the header rules check it against the parent's, so it is not a field a miner can choose. A node follows the branch whose tip states the greatest total_work.

The comparison is strict. A branch whose tip states work less than or equal to the followed branch's is recorded and not followed, so a tie keeps the branch already followed.

This is not a total order and a second implementation MUST NOT assume it is. Two miners finding a block at the same height is ordinary and produces two branches of exactly equal work. Two honest nodes that heard them in opposite orders follow different tips, and neither is wrong: what settles it is the arrival order, which is a fact about each node and not about the chain. The split stands until a further block makes one branch heavier, which is one block interval in the ordinary case. This document defines no order between branches of equal work, and in particular defines none on the block identifier. Breaking the tie on the lower identifier settles it sooner and costs more than it buys, because a node catching up along a rival branch passes through equal work on the way and reorganises there, doing extra rewinding to arrive one block later at the same place.

Before a branch can be compared its blocks have to be held, and a node SHOULD refuse to hold a block whose identifier does not meet the target for the difficulty it claims. That check needs nothing but the block, and without it a peer fills a node's memory for the price of nothing. The difficulty a block off the followed branch claims is otherwise taken at its word: whether it is the difficulty the retarget demands is decided when the branch is applied, and a block claiming more than it is entitled to had to do that much work to be stored at all, so the most it buys is one wasted attempt.

8.6Burial

Burial is the depth below the tip at which this network calls a block settled. It is 1 024 blocks on the network specified here, and 32 on a throwaway one. Three rules read it, and they are not the same kind of rule.

What reads itKind
a handed-over ledger is taken from a block this deep, never from the tipconsensus
a coinbase's notes cannot be spent until the block that paid them is this deepconsensus
a node refuses to switch to a branch that would undo more than this many blockslocal

The coinbase maturity is consensus in the strongest sense: the window of coinbases still waiting is inside the state root, so two nodes with different maturities do not merely disagree about one spend, they compute a different root for every block. It MUST be at or above the network's burial. There is no ceiling on it, only that floor, and the direction matters because it has been written down backwards: a maturity below the burial means a reward becomes spendable while the block that paid it can still be undone, which is the one thing the rule exists to prevent. Every network specified here sets the two equal.

What burial costs is chain time. At a sixty second block, 1 024 blocks on schedule is 61 440 seconds, 17 h 04 m. At the difficulty floor a branch can be held at a little over 30 seconds a block, as the retarget section shows, and the tightest such branch of 1 024 blocks found spans 30 069 seconds, 8 h 21 m. The second figure is the one any argument about how long an attacker must sit is entitled to, and it is under half the first. The drift bound is what keeps that time real: a node refuses a block more than ten blocks ahead of its own clock, ten minutes on the public networks, so a branch spanning more than eight hours cannot be handed over all at once, and its author waits out the difference, all of it but ten minutes, while everybody else keeps working.

The third rule in the table is not a consensus rule. It is a local retention policy, and the difference has a consequence a second implementation must know. Undoing a block needs the record of what applying it did. Keeping those records for every block ever applied is a cost that grows with the chain, on a node whose whole claim is that its cost does not, so they are kept for a bounded window and a switch that would reach deeper is refused. The reference implementation keeps 1 024 and the depth it will actually undo is the smaller of that and the network's burial.

The consequence, plainly: two nodes with different windows build the same chain and differ only when a fork deeper than one of them appears. When one does, the node with the shorter window refuses the heavier branch and stays where it is. It is then following a branch it can see is not the heaviest, no rule in this document says it is wrong, and nothing will move it: the fork choice above describes what a node prefers among branches it will consider, not among branches that exist. On a live network a fork that deep is an attack or a partition lasting the better part of a day. An implementation MAY choose a different window. A window shorter than the burial is safe for the maturity rule, since it undoes less rather than more, but it makes a handover taken at the burial depth unreachable, so an implementation that serves or restores one MUST keep a window at least as deep as the network's burial.

8.7Rules that activate at a height

A network carries a schedule of activations, oldest first. Each is two fields.

FieldTypeBytes
heightu648
versionu162

The schedule is consensus like every other network parameter, and its order is consensus too, which is easy to miss because it reads as tidiness. The first entry MUST sit at height 0 and names the version the network opened under. Every later entry MUST name both a strictly greater height and a strictly greater version than the entry before it. Two builds carrying the same changes in different orders put the same height under different rules and neither says a word, so an implementation SHOULD refuse to build with a schedule that does not have this shape. The network specified here carries one entry: height 0, version 1.

How a node finds the rules in force at a height. Walk the schedule from the end and take the first entry whose height is at or below the height asked about. Because the first entry sits at height 0 there is always one, and an implementation MUST NOT fall back to its own newest known version when the walk finds nothing: the release that raised that version would make every block below the first entry require the new version, and the chain would stop replaying from its own first block.

The height asked about is the height the block will occupy on the branch it extends, which is the parent's height plus one. A node MUST decide which rules judge a block from that height and not from the height the block claims for itself, or a block that lied about its height would choose the rules it is judged by. The block's own claim is checked separately, further down the order.

The block header's version MUST equal the version the schedule names at that height. Exactly equal, not at least: a block carrying the version from the abandoned side of a change is refused. That refusal is a fact about the block and a node MAY remember it, but a node MUST NOT hold it against the peer, because on the day a change takes effect every node that has not updated sends these in good faith.

What a node one version behind does at the boundary. Two situations meet there and they take opposite answers. Telling them apart is the whole of the mechanism's value.

What happenedWhat the node does
the schedule names, at this height, a version above the highest this build knowsrefuses the block, remembers nothing against it, blames nobody, and stops
the block carries a version above the highest this build knows, where the schedule does notrefuses the block, remembers nothing against it, blames nobody, and carries on

In the first the network has moved on without this node. It MUST NOT record the block as invalid, because an update makes the same block valid and the record would outlive the update. It MUST NOT hold it against the peer, because every peer that has updated is sending the same block: a node that treated this as misbehaviour would drop everyone who had updated and follow whoever had not, which is a minority chain believed to be the chain, and it is the one outcome a scheduled change exists to avoid. The reference implementation reports which version it needs and stops rather than going on answering from a chain it has been left behind by. A miner MUST NOT produce a block for a height whose rules its build does not have.

In the second the node cannot judge the block and says so. It MUST NOT stop on this: the version is a number a stranger can write in a field, and on a chain at the difficulty floor writing one costs a single hash, so a node that stopped would be handing any stranger the power to stop it. Deciding that a run of these means the network has moved rather than that somebody is talking nonsense needs evidence from more than one block and more than one peer, and that evidence is not a rule about any single block.

Nobody votes. The height is in the code, published long before it arrives, and a node that disagrees with it is running different software rather than casting a ballot. There is no miner signalling in this protocol: the version field is checked against the schedule and carries no vote.

What this mechanism can and cannot change, which is less than a reader will assume. The schedule gates exactly one field: the version of the block header. Nothing else in these rules is indexed by height. Every limit, every window, every clamp and the whole emission schedule come from the network's parameters, which are fixed for the life of the network.

Two further version numbers exist, one on a transfer and one on a coinbase, and neither is on the schedule. Each is compared for equality against a constant compiled into the build: a transfer MUST carry version 1, and a coinbase MUST carry version 1, at every height. Raising either constant would not take effect at a height. It would make every transfer and every coinbase ever mined refuse on replay, because a node validating its own history from the first block applies today's constant to blocks from every height. So the two transaction versions cannot be changed by the mechanism described here, and changing them at all needs a rule that reads them from the height, which this protocol does not have.

One more limit sits outside this mechanism and is worth naming here because a reader will look for it here. Adding a field to the block header from an activation height onward would leave every header below that height encoding exactly as before, so the identifiers would survive; what would not survive is the header's fixed width, which a header log relies on to find a record by multiplying an index. A header whose width depended on its version would need a different log, not a different encoder.

9

Joining a chain

A node with no chain has to answer two questions before it can check anything, and they are answered by two separate exchanges. Which of the chains being offered to it carries the most work, and what the ledger at that chain's tip is. The first is settled by opening a few thousand of the chain's headers at positions its prover cannot choose. The second is settled by taking a whole ledger from far enough below the tip that whoever wrote it had to go on mining over it, and checking it against the header that commits to it.

Neither exchange is a shortcut past validation of the blocks above the ledger's own header. Those are read and checked one at a time, like any other block. What the two exchanges replace is reading the chain below that point, and what that costs a node is stated exactly under What a newcomer ends up trusting.

9.1What a newcomer is shown

A weighing is one structure. Its fields are encoded in this order, which is not the order they are most easily read in.

FieldTypeWhat it is
tipblock headerthe header everything else is measured against
historyforestthe header forest as it stood before the tip, roots only
parentoptional samplethe header the tip was built on, opened in the tip's own history
genesisproofthe path to the first block, at position zero of the tip's own history; empty at a chain one block long
samplessequence of sampleone opened header per drawn position, in the order drawn
tailsequence of block headera run of consecutive headers ending at the tip, oldest first

A sample is a header followed by a proof.

FieldTypeBytes
headerblock header182
proofsequence of hash4 + 32d

The proof is the siblings from the leaf up to the root of the tree it sits in, nearest first, so d is the height of that tree and nothing else. A decoder MUST refuse a proof of more than 64 siblings. That is the most trees a forest can hold rather than the longest path in one: a leaf count is a u64, so the tallest tree has height 63, and a proof of 64 siblings decodes and is refused when it is verified, where its length has to equal the height of a tree that exists. The verdict is the same whichever check refuses it.

A forest on the wire is its leaf count, the number of leaves still standing, and one root per tree.

FieldTypeBytes
leavesu648
liveu648
rootssequence of (u8, hash)4 + 33r

The u8 beside each root is the height of the tree it is the root of. A decoder MUST refuse more than 64 roots, MUST refuse a height that is not strictly greater than the one before it, MUST refuse live above leaves, and MUST refuse a set of roots whose heights are not exactly the set bits of leaves. The last of those is what makes a decoded forest one something could have produced rather than merely a well-formed message.

The ordering rule subsumes refusing two roots at one height, which is what stood in its place and which left a forest with three roots six encodings. A forest travels inside a handover three times over and inside a weighing once, so that was a factorial number of byte strings meaning one thing, against a format whose first rule is that a value has one spelling. Nothing hashes an encoded forest, so no header ever committed to those bytes and no two nodes could be made to disagree by them.

The optional parent is a u8 tag: 0 for absent, 1 followed by a sample. A decoder MUST refuse any other tag.

Both counted sequences carry their own ceiling, checked before anything is reserved for them, because both are chosen by whoever sent the structure. A decoder MUST refuse more than 4 096 samples and more than 8 282 headers in the tail. The second is the deepest run this weighing will ever walk, and it is 16 * 512 + 90: sixteen times the band the draw leaves unresolved, plus one retarget window. A chain whose difficulty has fallen far enough below its own lifetime average has more blocks inside that band than the ceiling allows, and such a chain cannot be weighed at all. It has to be read. That is a real limit and it is stated rather than hidden.

9.2The draw

Both sides derive the same list of work values from the tip alone, so no round trip is needed to agree on the questions and nobody has to be trusted to ask them honestly. A second implementation MUST reproduce the list exactly.

The seed is the hash, under the sampling domain, of the tip's identifier:

seed = H(sampling, id(tip))

Two further quantities come from the tip. The work the draw ranges over is the work standing behind the tip, not counting the tip's own:

total = tip.total_work - tip.difficulty

The tip is not in its own history, so a draw that landed in the tip's own work would have nothing to open, and nothing needs opening: the tip arrives whole and its work is checked directly.

The other is the number of halvings the draw is spread over, and it comes from how old the tip says its chain is:

age       = (tip.timestamp - opens_at) / target_block_time
separable = min(age, tip.height) / 512
levels    = max(bit_length(max(separable, 1)), 1)

where bit_length(x) is 64 less the number of leading zero bits of x as a u64, and every division is integer division. On a chain of thirty years at a block a minute this is 15.

The age is a ceiling the reading node holds itself. A node refuses a tip dated more than its drift allowance past its own clock, and the opening moment is a constant of the network rather than something a peer sends, so no chain can state an age past the one the network has had. The retarget is what makes an honest chain's age and height agree, since it holds the chain to target_block_time a block.

The clock bounds the count and MUST NOT enter it. Nothing in the expression above reads the time of day. The count is a function of the tip and of this network's constants, so every node derives the same one for the same tip and a prover answers the list its reader asked for. An implementation that clamped the age against the reading node's own clock here would draw a different list from its neighbour the first time the two disagreed about the hour. Where the clock does its work is the refusal above, which a node MUST apply before it derives anything from the tip.

The height is read as the smaller of the two and can therefore only take halvings away. That is deliberate in both directions. A chain that has stalled, ten blocks mined over a year, must not have nine halvings spread across its last block, which is nine levels' worth of draws asking a question already answered. And a prover that understates either number buys nothing: fewer halvings makes each draw worth more, and it widens the band nearest the tip, which is the run of headers the prover then has to hand over in full and which is refused past 8 282 of them.

The height alone would not do, and this is the one place these rules changed for a break rather than for a feature. Through testnet-6 the count was bit_length(height / 1024) and nothing else. A height is not work: the only rule holding the two together is the one that prices an unopened stretch, which asks a run of n blocks to be worth at least n units, one unit being the difficulty floor. So a chain whose blocks averaged difficulty d could state a height d times the one it had, buy log2(d) halvings with it, and take that many slices off what every draw was worth, in work it was already inventing. A forest of any size costs what is opened in it and nothing for the rest, so there was no second price either. Measured on a thirty year chain, a forger holding 40 per cent of the world's work went from missing all 4 096 draws with 2^-207 to missing them with 2^-58, against a figure published as 2^-128.

count is 4 096, and it is not the reader's to choose. It is the one parameter every figure published for this draw is computed at, so a node MUST ask exactly 4 096 questions of every weighing it takes; a weighing checked at any other count has cleared a bar nothing here describes. The reference implementation's measuring instruments ask fewer, to make a forgery likely enough to see, through a function named for it.

The draw is empty when total is zero or when no samples are asked for. Otherwise, for each index i from 0 to count - 1, in order:

#Step
1form 40 bytes: the 32 bytes of the seed, then i as a little-endian u64
2b = H(sampling, those 40 bytes)
3level = (u64 from b[0..8], little-endian) * levels >> 64, in 128-bit arithmetic
4within = u128 from b[8..24], little-endian
5far = total >> level and near = total >> (level + 1), both shift counts clamped at 127
6width = max(far - near, 1)
7value = min(total - far + (within mod width), total - 1)

Every arithmetic operation here saturates rather than wrapping, and the clamp at 127 never binds while levels is at most 64. Level zero is the oldest half of the work and the highest level the band nearest the tip; the work above total - (total >> levels) is never drawn from at all.

The halving stops before it reaches a single block, and that is deliberate. The 512 in the level count is the narrowest band the draw will separate. Halving further would separate chains nothing else here separates either, and it would be paid for by every draw at every level: resolving to one block over thirty years takes twenty-four levels where this takes fifteen, and a draw is worth 1 / levels per question.

512 rather than the 1 024 a node refuses to reorganise past, and the difference is the point. Setting the two equal looked like the two rules agreeing and was not: the depth a newcomer can be moved by is not the band, it is the band plus what the staircase costs at its edges. At 1 024 that was 1 240 blocks measured, against a reorganisation limit of 1 024, so a newcomer put at the far end of the guarantee was on a branch the ordinary rule could not carry it back from. At 512 the same measurement gives 633, which is inside 1 024 with room. What it costs is one more level, so a draw is worth 1/15 of a uniform one rather than 1/14, which takes the share the count holds to from 43.37 per cent to 42.96. Both are floors rather than point estimates, for the reason the reference implementation's own note gives: the measurement is a maximum over noisy estimates and so reads low. The figure published below is 40 either way.

The level is scaled rather than reduced, and that is what makes it even. Through testnet-6 it was b[0] mod levels, and 256 does not divide by 14: the four deepest levels came up nineteen times in 256 and the other ten eighteen, an under-draw of 1.5625 per cent on the ten levels nearest the tip, so 4 096 draws did the work of 4 032. Taking eight bytes as a u64, multiplying by levels in 128-bit arithmetic and keeping the high half spreads the same choice with a bias under one part in 2^64. The multiplication cannot overflow: the product of a u64 and a level count of at most 64 is well inside a u128.

A drawn value names a height by covering rather than by arithmetic. The header a draw lands in is the one whose own work spans the value: everything before it falls short, and its own total reaches it. Formally, the header at height h answers draw i when

h.total_work - h.difficulty <= value[i]   and   h.total_work > value[i]

Because work rises with height, the answering height is found by halving over the heights rather than by scanning them.

9.3Where the chain starts

On a network that pins its first block, a node MUST refuse a weighing whose genesis path does not verify, at position zero of the tip's history forest, against the leaf of the pinned identifier. At a chain one block long the history is empty and so is the path, and the tip itself MUST be the pinned block. A network that pins nothing skips this.

It is the one check on the joining path that reads the pin. The block rules compare a block against it at height zero, and a newcomer that is weighed onto a chain and takes its ledger never reads height zero. Without it, a chain started from another first block, under the same network number and dated after the opening, is weighed on its work alone. The block is not sent, since the reader already holds its identifier; only the path is.

9.4What each sample must prove

For each drawn value, in draw order, the header opened against it MUST satisfy all of the following, and a node MUST stop at the first one it fails.

It belongs to this network and is not dated before this network opened. It carries real proof of work: its identifier meets the target its own difficulty sets. It does not state more cumulative work than the tip. It covers the value drawn, by the two comparisons above. And it sits in the tip's history forest at the height it states, by the proof beside it.

The two comparisons that decide whether a header answers the right question are applied before the proof is folded, because they are two comparisons on numbers already in hand and a proof is up to 64 hashes.

Opening headers settles what the chain is worth at the places the draw looked. It does not settle what the stretches between them are worth, and a draw over work almost never lands in a stretch claiming no work. So the stretches are bounded rather than opened. Every header whose place is established is a point the chain is pinned at: the opened samples, the parent, and the tip. Between two such points there are as many blocks as their heights differ by, and the retarget bounds what those blocks can be worth. The difficulty may fall by at most a factor of 4 per block and never below 1, so a run of n blocks starting from a header of difficulty d is worth at least the sum of that descent, and at most the matching climb. Below the lowest pinned point nothing is established, so all that can be said is that every block down there is a block: the whole opening is worth at least one unit per block.

9.5The run up to the tip

The draw leaves a band of work near the tip unresolved, about 512 blocks wide on a chain whose difficulty is near its own lifetime average, and for a while nothing else looked up there. That was enough on its own to hand a newcomer a forged anchor: a forger leaves the honest chain untouched, appends its own headers at the difficulty floor at one hash each, and puts the work it is inventing inside the band the draw never reaches. Every draw is answered by a genuine honest header, and the run really is worth what it says, which is almost nothing, honestly stated.

The tail closes that. It MUST be exactly the consecutive run of headers from one full retarget window below the deepest header the draw landed on, up to and including the tip, oldest first. The pinned header is the deepest by height among the opened samples; the parent does not count, because it is required rather than drawn and so a forger chooses it. The window below the pinned header comes along because those headers have to chain into it, and a forger cannot swap them without having mined the pinned header on top of its own.

Below the pinned header, only the chaining and the version are checked, since the window that would judge those difficulties is not present and the version needs none. At and above it, each header is held to the same rules a node applies to any block it is handed: the difficulty the retarget demands of it, a timestamp later than the median of its window, and its own work added to its parent's total.

The tip is then held to the run. A node MUST refuse a weighing whose tip's difficulty, multiplied by 32, is less than the difficulty of the hardest header of the run from the pinned header up, the pinned header included. Like the drift, this is a rule about the reader and not about blocks: no block is invalid for it, and a chain it refuses is refused as a weighing and can still be read. A node MUST NOT hold this refusal against the peer that offered the weighing. It is the last check a weighing makes, so a showing refused for it held in every other respect, and every honest peer serving a chain whose miners left offers the same one. It is there because the draw is seeded by the tip, so a fresh set of questions costs what the tip costs, and a run whose every header carries the difficulty the retarget demands can still walk that demand down to the floor with long stated gaps and end on a tip that costs one hash. The run holds at most 8 191 headers above the pinned one, and together with the pinned header they carry the band the draw leaves unresolved, so the hardest of them carries at least the band over 8 192, and a tip within the tie carries at least the band over 218. It is the hardest header and not the pinned one because a forger chooses where its difficulty is low: held to the pinned header alone, it lays a cheap stretch where the deepest question lands and walks the tip down to within the tie of that. What the tie costs an honest chain is stated with what the bound is worth.

The version is asked of every header in the run: each MUST carry exactly the version the rules require at its height. It is asked only when the build can judge the tip at all, meaning the rules at the tip's height and the tip's own version are both within what the build knows. A chain past that is one the build cannot judge, and the handover that follows says so and stops the node; a weighing refused for it would be an honest peer held to rules the reader lacks. The drift allowance is not asked of the run's headers. A block dated past the reader's clock is refused when it arrives and taken once the clock catches up, and a refusal here would be held against the peer who showed the weighing.

The tip's own timestamp is measured against the reading node's clock, against the same drift the block rules allow, which is ten target block times on every network here. It is checked before the draw rather than left to the validation that follows, for two reasons. It is where the decision is made: without it a forger hands over a chain whose cheap blocks are spaced across days it never waited, since blocks at the difficulty floor have to average about half the target or the retarget demands more of them, so a run of them states far more time than a reader will take in advance and the forger has to sit through the difference in real time. And the same timestamp is what the number of halvings is counted from, so the bound on it has to be in force before any question is asked rather than after the answers are in.

It is also the one refusal in this whole exchange that two honest nodes can disagree about, for the reason already given where the block rules are specified, and a node MUST NOT hold it against the peer that offered the weighing.

9.6The order a node applies the checks

This order is normative. The stages run as listed: the tip, then each sample in draw order, then the parent, then the stretches nobody opened, then the run up to the tip.

#RefusalWhat it means
1WrongNetworkthe tip is another network's
2BeforeTheNetworkOpenedthe tip is dated before this network existed
3TipFromTheFuturethe tip is dated further ahead than the reader allows
4TipWithoutWorkthe tip's identifier does not meet its own target
5TipClaimsNothingthe tip states no cumulative work at all
6HistoryMismatchthe forest is not the one the tip commits to
7HistoryWrongLengththe forest holds a number of leaves other than the tip's height
8NotThisNetworksGenesison a network that pins its first block, the chain does not start from it
9WrongCountnot as many samples as the draw asks for
10WrongNetwork, BeforeTheNetworkOpenedan opened header belongs elsewhere
11SampleWithoutWorkan opened header carries no proof of work
12PastTheTipan opened header states more work than the tip
13WrongPlacean opened header does not cover the work drawn
14NotInHistoryan opened header is not in the tip's history at its stated height
15ParentNotOpenedno parent was opened, on a chain more than one block long
16WrongNetwork, BeforeTheNetworkOpenedthe parent belongs elsewhere
17ParentNotTheTipsOwnthe parent is not at the height below, or is not the header the tip names, or carries no work
18NotInHistorythe parent is not in the tip's history at the height below
19ParentNotTheTipsOwnthe parent's work plus the tip's own is not the tip's total
20OpeningWorthLessThanItCostthe chain below the lowest pinned point states less than one unit a block
21WorkRunsBackwardswork falls between two pinned points
22BlocksWorthLessThanTheyCosta stretch states less than that many blocks can be worth
23BlocksWorthMoreThanTheyCoulda stretch states more than that many blocks can be worth
24NothingOpenedthe draw opened nothing, so there is nothing to measure the tip against
25TailWrongLengththe run is not the length the pinned header and the tip demand, or that length is past the ceiling
26WrongNetwork, BeforeTheNetworkOpeneda header in the run belongs elsewhere
27TailWithoutWorka header in the run carries no proof of work
28TailWrongVersiona header in the run carries a version other than the one its height requires, where the build can judge the tip
29TailNotConsecutivea header in the run does not follow the one below it
30TailAtTheWrongDifficultyabove the pinned header, not the difficulty the retarget demands
31TailOutOfTimeabove the pinned header, not later than the median of its window
32TailWorkDoesNotAddUpabove the pinned header, not the work below it plus its own
33TailMissesWhatWasOpenedthe run does not carry the pinned header, or carries a different one at its height
34TailNotConsecutivethe run does not end at the tip
35TipFellTooFarthe tip's difficulty is more than 32 times below the hardest header of the run from the pinned header up

Twenty-four follows from the draw being empty, which happens exactly when no work stands behind the tip. A chain one block long can therefore never be weighed, and is read instead.

What comes out of a weighing that passes is three numbers: the tip's identifier, its height, and its total work. Nothing else about the chain is settled by it, and in particular a weighing that passes says that this chain's work was really done and not that no heavier chain exists.

9.7What the bound is worth

The bound this draw rests on is measured, not proved. It is this project's own derivation, and the project's own SECURITY.md says so. What follows is the shape of the argument and the figure the reference implementation is set from, and neither is a theorem.

A forger holding share s of the world's work cannot mine what it did not mine. To present a chain heavier than the honest one it must invent the difference, so at least 1 - s / (1 - s) of what it presents is work no block of its chain spans. The draw's density is one over the distance from the tip, which is what makes the guarantee indifferent to how deep a forger forks, and the price of that density is a factor of levels on every draw: a draw lands in the invented stretch with probability ln(1 / (1 - lie)) / levels rather than with probability lie. Setting the count from that gives 4 096 draws over a thirty year chain, which holds against every forger up to 40 percent of the world's work and stops holding a few points above that.

Four things about that figure are load-bearing and MUST NOT be read out of it.

It rests on levels being the honest chain's own count. Every other quantity in the inequality is fixed by the forger's share, so levels is the one input a prover could hope to move, and while it was read off the stated height a prover could move it a long way. That is why the count now comes from the tip's age against a clock the reading node holds itself, and why a second implementation that takes it from anywhere else is not implementing this protocol: it will agree with nobody about which positions to open, and it will publish a figure its own draw does not reach.

It is a guarantee about a depth and not about a duration. The draw does not separate chains that differ by less than the band it stops halving at, which is 512 blocks, and the depth a newcomer can actually be moved by is 633: the band plus what the staircase costs at its edges, measured rather than derived. Inside that a forger can move a newcomer, and so can a slow honest peer: it is where any node sits for its first blocks after connecting. Both numbers are inside the 1 024 a node refuses to reorganise past, which is what makes the position a node can be carried back out of by the ordinary rule. Any argument that wants a duration instead has to say which chain it is timing, because a branch sitting at the difficulty floor states the same depth in a fraction of the time.

It is per tip, and a tip is what a forger buys. The seed is the tip's own identifier, so a forger that dislikes the questions it drew can find another tip and ask again, and a forger with g tips faces g times the chance. A tip costs its difficulty, which is not the chain's. A run whose stated gaps sit at the clamp ceiling walks the retarget's demand down to the floor: from 240 the walk is 826 blocks, 82 hours of stated time and about twenty-one blocks' work, paid once, and a forger that forked deep has the time. Before the tie described with the run, every nonce after that walk was a tip, and a fresh set of questions cost what it takes to see one of them land in the invented work: at 40 per cent about forty hashes, since a forger stops at the first. The tie puts a floor under a tip at the band the draw leaves unresolved over 218, which on a chain that ran to schedule is at least a thousandth of an average block. Measured on a thirty year chain at the two networks' opening difficulties, the cheapest tip a forger can present costs 218 hashes on testnet-6 and 214 on the devnet; held to the pinned header alone it would cost 210.3 and 27.3. It does not cost the chain's difficulty, and no tie of this kind can make it: a run whose tip fell by the tie is what an honest chain looks like after a loss.

So the figure MUST be quoted against a grinding budget. At 40 per cent the inequality above gives 2^-161.9 a tip, which stays under 2^-128 against 233 tips and not against 234, and 233 tips cost 251 hashes on testnet-6 and 247 on the devnet at those difficulties. The staircase the draw really is is worth more per question than the inequality, so that budget is a floor under the real one and not the real one; at the measured 42.96 per cent there is no budget at all, since that is the share at which one tip alone reaches 2^-128.

The tie is what an honest chain pays for this. The retarget follows a loss of hash rate with noise of its own, and on chains with random block times the hardest header of a run stood up to twice as far above the tip as the loss alone puts it, so a tie of 32 refused no chain that lost sixteen times its hash rate, sixty-four of them on each network. A chain that lost twenty or more cannot be weighed on testnet-6 from about eight hours after the loss, for up to a day at twenty, about as long as the ceiling on the run's length refuses it anyway, and for under six days at any loss beyond what the ceiling refuses; a newcomer reads such a chain instead, where a peer keeps it.

Past half the world's work nothing here helps, and nothing anywhere else does either: a forger at half has nothing left to invent and can mine the chain.

10

The handover

Weighing settles which chain is heaviest. It says nothing about who owns what, so a newcomer that has settled it still cannot check a single transaction. A handover is the ledger at one header of that chain, with everything needed to check it against what the header already committed to.

No ledger is taken at the tip. A newcomer has watched no transaction go past, so what it is handed is only as good as the header that commits to it, and a header's state root is a field its miner chose. Proof of work says that somebody spent electricity on those bytes, not that the state in them is what honest transactions would have produced. One block would buy an arbitrary ledger. So the ledger is taken from an anchor at least the burial depth below the tip. The burial depth is a rule of the network like any other, and on the public networks it is 1 024 blocks, the same as the deepest reorganisation a node accepts, so a newcomer lands exactly where a node that was away and came back lands. A lie must therefore be that deep, and to be that deep while still being the heaviest chain offered, its author had to out-mine everybody else for as long as it took to build the burial.

10.1What it carries

Encoded in this order.

FieldTypeWhat it is
atblock headerthe header this ledger belongs to, the anchor
tipblock headerthe tip of the chain this ledger belongs to
tip_historyforestthe header forest as it stood before that tip
anchorproofthat the anchor sits where it says in that forest
coldforestthe cold set, roots only
headersforestthe header forest as it stood before the anchor
hotsequence of (note id, note, u64)every note in the hot set, with the height that decides when it falls
gracesequence of sequence of (note id, u64, note)what fell in each of the last few blocks, oldest first
grace_proofssequence of (u64, proof)a path for every note in that window
maturingsequence of (u64, hash)coinbases not spendable yet, oldest first
supplyamountevery pebble the chain had issued at the anchor
recentsequence of block headerthe last few headers in full, oldest first, ending at the anchor
buriedsequence of block headerevery header between the anchor and the tip, oldest first, the last being the tip

Every count is bounded before anything is reserved for it, because a sender chooses all of them. A decoder MUST refuse a hot set of more than 1 048 576 notes, a grace window of more than 64 blocks or more than 8 192 notes across them, more than 8 192 grace proofs, more than 65 536 maturing coinbases, more than 91 recent headers, and a buried run of more than 4 096 headers.

Two of those are wire ceilings rather than rules, and the difference matters. A node MUST check the hot set against the capacity this network's rules set, which is 131 072 notes on the public networks, and the maturity window against this network's maturity depth, which every network here sets equal to its burial depth. The decoder's larger numbers exist only so that a sender cannot make a reader reserve for a set no network allows. The buried ceiling of 4 096 is there because the sender chooses the length of a run the receiver has to walk, and without one a peer could hand over an afternoon's work to check.

The grace proofs are not a courtesy. Spending a note that fell moments ago takes no proof from the spender, because every node holds one; a node handed a ledger holds none and cannot work them out, since they are paths through a set nobody keeps. A handover that omits one is refused rather than believed and found wanting later by whoever tries to spend.

The recent headers come in full rather than as summaries, because the difficulty rule and the timestamp rule read them and an identifier is what the header forest holds. A summary cannot be checked against anything.

10.2The order a node applies the checks

This order is normative.

#RefusalWhat it means
1WrongNetworkthe anchor or the tip belongs to another network
2BeforeTheNetworkOpenedeither is dated before this network existed
3HeaderWithoutWorkeither identifier does not meet its own target
4SoftwareTooOldthe rules at the tip's height, or the tip's own version, are past what this build knows
5WrongVersionthe anchor or the tip carries a version other than the one the rules require where it sits
6NotBuriedthe anchor is not the burial depth or more below the tip
7HistoryMismatchthe forest offered is not the one the tip commits to
8NotOnTheWeighedChainthe anchor does not sit in that forest at the height it states
9HotSetTooLargemore notes than this network's rules allow
10DuplicateHotNoteone note named twice
11NoteInBothTiersone note named in the hot set and in the grace window at once
12TiersAboveTheSchedulethe two tiers together hold more money than the schedule has paid
13GraceWindowTooLargethe grace window holds more blocks than the rules keep
14GraceWindowHoldsTooMuchor more notes than they keep
15GracePositionTwicethe window names one cold position twice, which is one leaf offered as two notes
16MaturityWindowTooLargemore waiting coinbases than the maturity depth
17MaturityOutsideTheWindowa coinbase maturing at a height the window does not cover
18MaturityWindowOutOfOrderthe heights the window's coinbases mature at do not strictly rise
19CoinbaseMaturingTwicethe window names one coinbase twice
20SupplyAboveTheSchedulemore money than the schedule has paid by the anchor's height
21HistoryMismatchthe second forest is not the one the anchor commits to
22RecentNotEndingAtTipthe recent run is empty, or does not end at the anchor
23TooFewRecentfewer recent headers than the anchor's height allows for
24WrongNetwork, BeforeTheNetworkOpeneda recent header belongs elsewhere
25WrongVersiona recent header carries a version other than the one its height requires
26RecentWithoutWorka recent header carries no proof of work
27RecentWorkDoesNotAddUpa recent header's total is not the one below it plus its own
28RecentOutOfTimewhere the run holds the eleven headers below it, a recent header is not later than their median
29RecentNotConsecutivethe recent run is not one chain
30BuriedRunWrongLengththe buried run is not the height difference, or is past the ceiling
31WrongNetwork, BeforeTheNetworkOpeneda buried header belongs elsewhere
32BuriedRunNotConsecutivea buried header does not follow the one below it
33BuriedWithoutWorka buried header carries no proof of work
34SoftwareTooOldthe rules at a buried header's height are past what this build knows
35WrongVersiona buried header carries a version other than the one its height requires
36BuriedAtTheWrongDifficultynot what the retarget demands of it
37BuriedOutOfTimenot later than the median of the window before it
38BuriedWorkDoesNotAddUpnot the work below it plus its own
39BuriedHistoryMismatcha buried header below the tip does not commit to the forest the run has rebuilt below it
40BuriedRunNotEndingAtTheTipthe run does not end at the tip
41NotOnTheWeighedChainthe forest rebuilt from the run is not the one the tip commits to
42StateRootMismatchthe ledger rebuilt from this does not produce the anchor's state root
43BadGraceProofa path for a note in the grace window does not fold to the cold commitment
44MissingGraceProofa note in the grace window has no path

Nine to twenty come before the ledger is rebuilt because each of them needs nothing but what arrived on the wire, and the size of what follows is otherwise decided by whoever sent it.

Seventeen, eighteen and nineteen ask the maturity window what a window a node built would be. A block's coinbase matures a fixed depth above it and blocks come one height apart, so the heights rise strictly and every coinbase appears once. A node empties the window from the front and stops at the first entry still waiting, and keeps one height a coinbase beside it; a window out of order keeps a coinbase unspendable past its height, and one naming a coinbase twice leaves that record saying one thing and the window another. The state root does not settle either, because a sender who mined the burial computes it over the window it chose.

Ten is not covered by the state root and cannot be. The hot set is committed to as a tree keyed by note identifier, so a list naming a note twice folds to exactly the root of the list naming it once. The second entry rides in free, past every check that ends at the header, and what it buys is not a note but a place in the eviction order, which is the one structure a receiver builds from the list rather than from the commitment.

Forty-one is what a forest proof alone cannot say. A proof says a header sits at a position in a forest; it does not say the forest is a chain, and the forest belongs to whoever made the tip. The header forest is append only, so the receiver does not have to take the proof's word for it: it holds the forest as it stood before the anchor, because the anchor commits to it, and it adds the anchor and then every header of the run and sees whether it arrives at the forest the tip commits to. Under a swap anywhere below the tip it does not, and it does not matter whether any draw would have looked there. The tip is not in its own history, so the tip's own leaf is the one leaf that MUST NOT be added.

Thirty-six, thirty-seven and thirty-eight are what make the burial cost something. Before them the sender chose those difficulties and could set them all to the floor, so a thousand blocks of burial were a thousand hashes. The window they are judged against starts as the recent headers that came with the ledger and moves forward with the run, so every step is judged by the rule a node applies to any block it is handed. Thirty-nine is the same rule's last field: a block's history is the forest below it, which is the forest the walk holds when it reaches that header, so each header below the tip MUST be compared with it before its own leaf is added. Without it a sender who mined the burial could write anything there, and the newcomer would take the ledger and then refuse the first block above it for the field the handover let through.

Twenty-eight is asked only where the recent run holds the rule's whole window. The median reads the eleven headers below a block, so from the twelfth recent header on it is exactly the rule each of them was accepted under, and a run that starts at the first block holds every header the rule read from its first. Below the twelfth entry of any other run a median over fewer headers is not the rule, and over timestamps that do not rise it can stand above the real one and refuse an honest handover, so a node MUST NOT ask it there. The retarget is not asked of the recent run at all: it reads ninety gaps, so no header of a run of ninety-one can be judged by it.

10.3What is pinned by a commitment, and what is not

Everything in a handover except one field is checked against something the header already committed to, and the header is checked against the work behind it. That is a strong argument and it has a shape: it says a lie had to be mined, not that a lie is impossible. Whoever did out-mine the network for the burial chose the state root and everything under it.

One check does not go by that road. A coinbase claims at most what the schedule pays at its height plus the fees its own block's transfers gave up, and a fee the coinbase declines is destroyed, so a chain at a height holds at most what the schedule has paid by then and never more. Refusal twelve is that subtraction. It is the only place in this exchange where a newcomer is not taking somebody's word, and no amount of work gets past it. The supply is also inside the state root like everything else; the point is that it is weighed against the rules as well.

The tip is pinned by the caller and the anchor is pinned by nothing until refusal eight. The tip is the header the weighing settled on, and a node MUST check that the handover names that header before anything is drawn from it. The anchor is a header the sender chose; until the forest proof runs, every field of it is a number the sender wrote.

That distinction decides where refusal four may read its version from. Four is the one verdict in this exchange that stops a node rather than refusing a message, so it MUST be drawn from the tip's height and the tip's own version and from nothing else. Reading it off the anchor was worth a node: this network, a timestamp past its opening, the difficulty floor where any identifier meets the target, and one hash shut any node that asked for a ledger. Nothing honest is lost by refusing to read it there, because versions rise with height and the anchor sits below the tip, so an anchor above this build's ceiling while the tip is not is a combination no chain produces. An anchor claiming one falls to refusal five, which refuses the handover and does not stop anything.

Five is the other half and is a judgement rather than a confession, so it may rest on unpinned fields. A block carries exactly the version the rules require where it sits, so a header carrying anything else is a header no chain accepted. Checking only that a version was not too high let a handover arrive under a version below the schedule and be taken, while the very same header offered as a block would have been refused, which is the whole of what a schedule is for.

10.4What a newcomer ends up trusting

This is the trade the design makes, and a specification that leaves it implicit is worse than useless.

A node that read the chain from its first block has validated every block in it. It refuses an invalid history however much work stands behind it, because it checked every rule against every block, and no quantity of proof of work persuades it otherwise.

A node that started at an anchor does not have that property below the anchor. Above the anchor it is in exactly the same position as any other node: it asks for the blocks between the anchor and the tip and beyond, and it validates every one of them against every rule, so from the anchor upward its own work stands behind everything it will ever answer about. Below the anchor it holds the work, the header commitments, and nothing else. It has:

  • proof of work on the tip, on every header the draw opened, on the parent, on every header of the run up to the tip, on every header of the buried run, and on the recent headers;
  • a bound on what every stretch it did not open can be worth, which follows from the retarget rather than from anyone's word;
  • the anchor's own place in the tip's header forest, rebuilt leaf by leaf from the run rather than taken from a proof;
  • on a network that pins its first block, that block's place at position zero of the same forest, so the chain it holds is one that starts there;
  • the ledger reproducing the anchor's state root, and the anchor's supply at or below what the schedule has paid.

It does not have, and cannot obtain without reading the chain, any check that the transactions below the anchor were valid. A ledger that a majority of the world's hash rate mined a burial deep over is a ledger this node takes, so long as the money in it is at or below what the schedule has paid, which is the one thing the schedule check still catches. What that costs an attacker is out-mining the network for the burial while remaining the heaviest chain the whole time, which is the assumption the chain already rests on; what it does not cost is anything the newcomer can detect.

Two consequences follow and both are stated rather than softened. A newcomer lands where a node that was away and came back lands, with the same ability to be moved off by a heavier chain and no more. And the two kinds of node are not interchangeable as sources: a node handed a ledger holds nothing below its anchor and never will, so a branch forking under there cannot be assembled by it however much of it arrives.

11

The message set

Every message is a u8 tag followed by the fields listed, in order. A decoder MUST refuse a tag it does not know rather than skipping it, since it cannot know how many bytes to skip.

TagMessageCarriesAnswered with
0HellohandshakeWelcome, then GetChain when the peer claims more work, then GetPeers
1WelcomehandshakeGetChain when the peer claims more work, then GetPeers
2Pingu64Pong, carrying the same number
3Pongu64nothing
4GetChainsequence of (u64, hash)Chain
5Chainu64, u64GetBlocks, or GetChain, or nothing
6GetBlockssequence of u64one Block per height held, in the order asked
7BlockblockGetBlocks or GetChain, or nothing
8Announcesequence of (u64, hash)GetBlocks, or GetChain, or nothing
9GetPeersnothingPeers
10Peerssequence of addressnothing
11Transactiontransfernothing
12GetJoinu8, u32JoinPart, or nothing
13JoinPartu8, hash, u32, u32, sequence of u8GetJoin for the next piece, or GetChain once the ledger lands
14GetHeadersu64, u64Headers, or nothing
15Headersu64, sequence of block headernothing
16GetProofssequence of u64Proofs
17Proofssequence of placednothing

Every counted sequence here carries a ceiling, and a decoder MUST refuse a count above it before it reads a single element. A count is four bytes a peer chooses and the elements behind it are between seven and forty bytes each, so a decoder that reads the list first and measures it after has let a one megabyte frame build a list up to two thousand times the cap that governs it. The rule is the same either way; read late it is a rule about what to throw away.

MessageCeiling
GetChain64 entries
Chain2 000 (a count, not a sequence)
GetBlocks128 heights
Announce512 identifiers
Peers64 addresses
JoinPart64 parts, 524 288 bytes a part
Headers512 headers
GetProofs64 heights
Proofs64 placed proofs

A frame is at most 1 048 576 bytes whatever it carries, so these ceilings bound what is built and the frame bounds what is read.

A handshake is 108 bytes and carries the protocol version as a u32, the network as a u32, the first block of the branch this node follows, its tip, its height, the work behind that tip as a u128, the port it listens on as a u16, a u64 nonce drawn once when the node started, and two u8 claims about what it kept. A node that does not offer itself to be dialled, as a wallet's does not, names port 0, and a peer MUST NOT write an address down for it. A decoder MUST refuse either claim byte if it is neither 0 nor 1, because reading anything else as true is guessing on the peer's behalf.

The two claims are separate on purpose. Keeping the headers is what lets a node show a newcomer what work stands behind its chain, and almost every node does it. Keeping the whole cold set is what lets a node rebuild the path to a note that fell long ago, and almost none does. They are claims and not facts, and neither is taken on trust: everything either kind of node hands over is checked against something the asker worked out for itself. What the claims save is asking the wrong node and waiting.

An address is a u8 tag: 4 followed by four octets and a u16 port, or 6 followed by sixteen octets and a port. A decoder MUST refuse any other tag.

A placed is a u64 position and then a u8 tag: 0 for no path, 1 followed by a path. A decoder MUST refuse any other tag. A node that cannot produce the path for a position it was asked about MUST answer with 0 at that position rather than leaving it out or saying nothing, because silence from a peer is indistinguishable from a peer that has hung up, and a wallet waiting on the one thing that would let it spend its money has to be able to tell those apart and go and ask somebody else. An answer names every position asked about, in the order asked. A node that does not keep every leaf SHOULD answer 0 at every position, including one whose path it keeps for an owner it follows: past the grace window those are the only paths it keeps, so which of them it hands over says whose node it is, and nothing in a message tells that owner from a stranger.

GetJoin and JoinPart carry a u8 saying which answer is meant: 0 for the weighing, 1 for the ledger. A decoder MUST refuse any other value. Both answers are larger than one message carries, so they arrive in pieces. The at field of a JoinPart is the tip the answer describes, so an asker can tell that every piece came from the same moment: a node that mined a block partway through is answering about a different ledger, and its pieces do not belong with the ones already held. Whether pieces belong together is settled by checking the whole against the header it names, never by the labels on them.

A node with no chain, meeting a peer whose chain is longer than the deepest reorganisation it would accept, MUST NOT ask that peer for a chain on the handshake. Past that length the fork choice is final, so the first long chain a node commits to is the one it keeps. Left to the wire, that choice belongs to whoever answers first, and the first answer is the one an attacker races to give. The choice is therefore made once, against every claim the node has heard, by the node itself. A node with a chain of its own, and a node facing a chain short enough to be undone, simply asks: following the wrong short branch is undone by the fork choice like any other.

11.1What a node MUST refuse

Below the message set, a frame is a four byte network marker, a four byte length, and the message. A reader MUST check the marker against its own network and MUST refuse a declared length above 1 048 576 before reserving a byte for it, because the length is the one number an anonymous peer chooses about this node's memory. A reader MUST refuse a frame with bytes left over after the message decodes.

Every counted list has a ceiling checked while decoding, before anything is reserved. An encoder MUST NOT produce one past its ceiling.

ListMost
GetChain locator64
Chain count2 000
GetBlocks heights128
Announce identifiers512
Peers addresses64
JoinPart pieces64
JoinPart bytes524 288
Headers headers512
GetProofs positions64
Proofs entries64

A decoder MUST also refuse a JoinPart whose piece number is not below its stated count of pieces. Those two ceilings together bound what a collector can be made to hold at 64 pieces of 524 288 bytes, which is 33 554 432 bytes and is the real limit on what one join exchange costs a node in memory.

GetHeaders is the one ask whose count is not bounded at decode. It is clamped to 512 when it is answered, and priced at what it asked for up to that clamp, so asking for more than 512 buys 512 and costs what 512 costs.

Two refusals are about the conversation rather than about a message. A node MUST refuse any message other than Hello or Welcome from a peer that has not introduced itself, and MUST refuse a second introduction on one connection. Both are broken or probing behaviour and a node SHOULD hold them against the address for a while, reading an IPv6 address as its /64 for the reason given under the allowance below.

An introduction is examined in this order, and the order is what keeps a node from spending a connection on itself. First, whether the peer has already introduced itself. Then whether the handshake carries this node's own nonce, which means the connection is this node's own. Then the protocol version, the network, and the first block.

A node that reaches itself MUST close the connection, MUST NOT count it as misbehaviour, and SHOULD take that address out of its book, or it will dial itself again on the next sweep. Comparing addresses cannot detect this, since a node behind a router does not know the address the world reaches it at. Comparing a number the node drew for itself when it started can.

Three refusals are about the peer belonging elsewhere: another protocol version, another network, or a first block that is not this node's. A node MUST close the connection on any of them and MUST NOT hold any of them against the address, because a node on another network or an older build has done nothing wrong and may be on this one tomorrow.

The first block a node compares against is the one its own rules pin, and only where the rules pin none is it the first block of the branch it happens to follow. On a network that pins one, every node applies the check from its first moment. Where nothing is pinned, a node with no branch has nothing to compare against and MUST let the peer past, and so MUST a node meeting a peer that advertises a first block of all zeroes, which is what a node with no chain says about itself. Choosing whom to ask first is then what a seed address is, and it is the one piece of trust in the whole protocol: it belongs to whoever runs the node and not to the network.

A node that cannot build an answer MUST say nothing rather than answer badly. That covers a node with no headers asked for a weighing, a node whose chain has left the band a weighing can reach, and a node asked for a piece of an answer it has no piece of.

12

Versions

There are two version numbers in this protocol and they are compared differently.

The protocol version is compared for equality. It is a u32 in the handshake, it is 9 today, and a node MUST close the connection with a peer carrying anything else. What that costs is that a node on one version and a node on the next turn each other away rather than talking; what it buys is that a message whose meaning changed is never read under the old meaning. The alternative, adding a question without saying so, is worse than it looks: a node on the older version meeting the new question cannot decode it, takes that for a peer that is broken or probing, and refuses the address. A wallet looking for the node that answers the new question would work its way through the network banning itself from it.

The block version is compared both ways, and which comparison is used decides who is at fault. Every network carries a schedule of activations, oldest first, each naming a height and the version in force from it. The version the rules require at a height is the version of the last activation at or below it. A build knows versions up to a ceiling, which is 1 today.

RefusalComparisonWhat it says
SoftwareTooOldthe version the rules require at this height is above this build's ceilingthis build cannot judge here
UnsupportedVersionthe version the header carries is above this build's ceilingthis build cannot judge this block
WrongVersionthe version the header carries is not the one the rules require where it sitsthis block is wrong

The first is an ordering and is drawn from the height rather than from anything the block says about itself, so a block that lied about its height cannot pick the rules it is judged by. It is a verdict about the reader, so a node MUST NOT hold it against the block or the peer, and MUST NOT go on following the chain it can still judge: carrying on would mean refusing every peer that had updated and following whoever had not, which is worse than not running, because a wallet reading a balance off an abandoned chain is answered confidently and wrongly. The reference implementation names the height and the version required and stops.

The second is also an ordering and also a verdict about the reader, and an update reverses it, so a node MUST NOT remember it against the block and MUST NOT hold it against the peer. One of these means nothing on its own: it is a number a stranger wrote in a field. Deciding that a run of them means the chain has moved rather than that somebody is talking nonsense needs evidence from more than one block and more than one peer.

The third is an equality and is a verdict about the block, so a node MUST remember it against the block, since no update reverses it. It MUST NOT be held against the peer either: on the day a rule changes, every node that has not updated sends these in good faith, and refusing the host would turn the first minutes of a rule change into an updated node banning most of the network.

When two builds meet across an activation, which of the two orderings fires depends on whether the older build carries the schedule.

A build that carries the activation but not the rules, which is what a build shipped before an announced change looks like once the chain reaches the height, reaches the first refusal, says it is too old, and stops. A build that carries neither, which is what a build that predates the announcement looks like, never reaches the first refusal at all: it judges by its own schedule, which does not know the change, and so meets the second refusal on every block instead. It follows nothing further, holds nothing against anybody, and its height stops moving. Both are honest answers to different questions, and neither of them is a verdict about the peer.

The updated build, meeting a block from either of them, reaches the third refusal, closes the connection, and MUST NOT refuse the address, because on the day a rule changes that is most of the network.

Collapsing any two of the three has cost this project a defect in both directions: a stranger able to stop any node by writing a number in a field, and an un-updated node banning everyone who had updated.

The handover path carries only two of the three, and folds the second into the first. A tip whose own version is above this build's ceiling is reported as SoftwareTooOld rather than as UnsupportedVersion, so a build that carries neither the schedule nor the rules stops on a handover where it would only have gone quiet on a block. That is sound only because the tip is the header the weighing settled on and is therefore pinned by the caller. Drawing the same verdict from the anchor would not be. See What is pinned by a commitment, and what is not.

13

The allowance

The allowance bounds how much work a peer may ask of a node, and nothing else. How much one answer weighs is bounded separately, by the per-message ceilings above and by the frame limit; how many messages a peer may send is bounded separately again. The three are worth keeping apart, because a price that counts only the asking sells a gigabyte of blocks per window for about six and a half kilobytes a second of asking: 128 heights fit in about a kilobyte of request and draw up to 16 777 216 bytes of reply. Reading what a peer sends is work it asks for too, and is priced with the rest.

It is not consensus. A node that prices differently, or not at all, reaches the same conclusions about every chain; what it decides is how much of itself that node hands to strangers. So everything here is SHOULD, and the numbers are what the reference implementation charges.

A peer's allowance is 8 192 units per window. A window is ten seconds, counted off the clock rather than from whenever a peer first spoke, so a connection and the address it arrived from are always talking about the same ten seconds. A peer that has spent its window SHOULD be answered with silence rather than closed: asking is not misbehaviour, there has only been a lot of it, and it asks again a moment later against a fresh window.

The window belongs to the address and not to the socket. A connection's first ask SHOULD begin where its address left off in the current window, or a peer refills by hanging up and dialling back, which costs it a handshake and earns it no refusal. An IPv6 address SHOULD be read as its /64 here, since that is what a provider hands one customer: read whole, one machine refills by dialling back from the next of its 2^64 addresses. An IPv4 address that arrives spelt as IPv6 (::ffff:a.b.c.d) is that IPv4 address. Two connections open at once SHOULD each spend their own and the address SHOULD keep the larger rather than the sum, because that is what an honest pair of nodes behind one address is, and pooling makes two people behind one carrier gateway invisible to each other.

A frame is charged by its size before it is decoded. Decoding is not free: every note in a frame is an owner's key decompressed off the curve and checked for its subgroup, which costs about what verifying a signature does, so eight hundred kilobytes of note owners are most of a second of processor before anything in them has been priced. A node SHOULD charge every frame from a peer that has introduced itself one unit per 512 bytes, rounded up, before it decodes it, and SHOULD NOT decode a frame the peer's window cannot pay for. That charge counts toward the price of the message the frame carried, so a message pays the larger of the two and never both. Two frames are not charged: a peer's frames before it has introduced itself, which may only be a handshake, and a JoinPart from the peer this node is collecting a join from, which is taken outside the allowance as the answer to a question this node asked that one peer. A JoinPart from any other peer is charged like any other frame: what marks a frame as a piece is its first byte, which anybody can write.

MessageCost
GetChain8, plus 1 per locator entry, counted up to 64
GetBlocks1 per height, counted up to 128, and each block as it is served
GetHeaders1 per header, counted up to 512
GetProofs8 per position, counted up to 64
GetPeers64
GetJoin1 024
Peers1 per address carried, counted up to 64
Announce1 per identifier carried, counted up to 512
Headers1 per header carried, counted up to 512
Proofs8 per path carried, counted up to 64
Transaction4 per input and 4 per output
Block this node asked for1 per 512 bytes of the message, rounded up, and 1 once it is on the branch this node follows
Block nobody asked for, or announced and then asked for8, plus 1 per 512 bytes of the message, rounded up
Ping, Pong, Chain1
Hello, Welcome, and a JoinPart from the peer asked for itnothing

Five of those prices are worth the sentence that explains them.

An ask is priced by what it makes the answerer do, not by what it weighs. A locator is priced by its entries because every entry the answerer does not hold in memory is a seek, a read and a decode, and the walk stops only when one matches, so a locator of entries matching nothing costs one read each. A GetPeers is priced at the largest answer it can draw rather than at what this node's book happens to hold, because a price that moves with the book is a price whoever fills the book gets to set.

A Peers costs what it makes this node take in. Nothing on the wire says a peer was asked, so a message this node requested is charged the same as one a stranger sent unbidden, because taking one in costs the same either way.

The two largest answers a stranger can draw cost the same per byte. What is put on the wire is charged separately from the ask, at one unit per 512 bytes rounded up, for blocks. A join part is 524 288 bytes for 1 024 units, which is the same rate. So a window buys about four megabytes of either. Blocks are the one answer whose size the ask cannot state, since a block is anything up to what the consensus rules allow and only whoever read it off the disk knows which; headers and paths are bounded by the ask and are charged there instead.

A transfer costs what taking it in costs. An input is a note resolved and a signature verified. An output is a key decompressed off the curve and checked for its subgroup while the frame is decoded, which costs about the same, so it is priced the same. Priced by its inputs alone, a transfer of one input and 256 outputs cost what an ordinary payment does and bought over a hundred times the processor for each unit.

A block this node asked for is discounted once it has earned it. It pays for its bytes like any other block, and has all of that but one unit handed back once it is on the branch this node follows, which it cannot be without the work its header claims at the difficulty the chain demands. A block under a parent this node does not hold, or one filed beside the branch without being checked, costs its sender nothing to make, and keeps its price.

A batch SHOULD be charged block by block as it is served, and each block before it is read, from what its record says it weighs, so a peer that has spent its window is handed what it could afford and the rest is not read, not encoded and not queued. Reading a block back off a disk decodes it, so a batch read first and priced after costs its reader a decode of every owner in a hundred and twenty eight blocks whatever the peer can pay. A short batch is what a peer already gets for heights this node no longer holds, so it asks again for the rest.

A join answer SHOULD be built once for each tip, however many peers ask for it at once. An asker arriving while one is being built waits for it, or is answered with silence and asks again; building it once for each of them is a build of the whole weighing, or a copy of the whole ledger unwound to its burial, for every connection that asks after a block.

What the allowance does not bound. It does not bound the number of messages a peer sends: that is a separate ceiling, 2 000 messages in ten seconds, and passing it closes the connection, because a peer asking the same question hundreds of times a second is not syncing. It does not bound one answer's size: the per-message ceilings and the one megabyte frame limit do. And it does not decide how fast a catch-up runs. A batch of 128 empty blocks costs 128 units for the asking and one more for each block put on the wire, so a window pays for 4 096 of them, which is four hundred a second and far above what a catch-up has ever been measured at. Whatever paces a sync, and the exchange asks a fresh locator and waits a round trip for every 128 blocks, it is not this. The allowance is a ceiling an honest sync does not come near, which is all it was ever for, and a document that turns it into a promise about a duration is promising something no rule here delivers.

14

Where this document is held to the code

Statements above that name a layout or a number are checked against the reference implementation by tests in four places, so a change to either side that the other did not make fails the build. crates/cairn-primitives/tests/audit_vectors.rs pins the primitives: integers, byte arrays, sequences, amounts, the hash domains and the Merkle tree. crates/cairn-ledger/tests/audit_the_specification.rs pins the encoded bytes of each structure, the identifier computed over it, and the draw. crates/cairn-net/tests/audit_the_specification.rs pins the tag of every message, the size of a handshake, the protocol version, and every row of the allowance table, priced through the reference implementation. crates/cairn-explorer/tests/published_figures.rs pins the figures this document quotes, among them the list ceilings and the frame limit. What none of them pins is the order of the fields inside each message, which the message table states and a round trip cannot check.

The draw is pinned now, which it was not when this document was first written. crates/cairn-ledger/tests/audit_the_specification.rs implements it from the procedure above and compares it against the shipped one over 82 476 combinations of seed, work and height, chosen to include every power of two and either side of it, because a reimplementation that reached for a base-two logarithm where this one counts leading zeros would be wrong at exactly those heights and nowhere else.

Those vectors were written from this document by somebody forbidden to read the encoders while writing them, which is the only way to find out whether a specification says what its author meant or what the code does. Fifty three agreed and none disagreed, so where this document speaks it is accurate. Where it was silent it was not: ten of the twenty domain constants were named in prose without being published, transactions_root was a header field and a refusal with no definition anywhere, and four refusals the implementation makes were not stated at all. The first two are fixed above. The four are CoinbaseExtraTooLarge, TooManyCoinbaseOutputs, ZeroValueCoinbaseOutput and TooManyTransfers, and by this document's own conformance section they are either an omission here or a defect in the implementation; they are an omission here, and they are stated with their numbers where the body is evaluated. Fixing them turned up a fifth: the body was said to be evaluated between seventeen and eighteen, where the implementation evaluates it between nineteen and twenty.

The allowance is written as SHOULD throughout, because it is not consensus and two implementations may price differently without either being wrong. Its table is held all the same, because it says what the reference implementation charges: for a fortnight six of its rows said otherwise, each of them a price the project had changed because the old one was a defect.

This is not a courtesy. Sixteen figures published by this project have turned out to contradict the code, and in every case the defect was in the instrument rather than in the thing measured. A specification is a published figure with more surface than most.

Until round 19 the vectors pinned the twenty hash domains and the Merkle tree and no encoding at all. A domain says how bytes are hashed; an encoding says which bytes. Swapping two fields of the block header in both directions left every round trip passing, left the record width the header log asserts, left every domain vector green, and changed every block identifier ever computed.