§ 11

§ 11 · Blockchain

The most-work chain

Which branch wins when the chain splits, and by how much it must win

Mining is a lottery, and sometimes two people win almost at once. Two miners each find a valid block on top of the same parent, a few seconds apart, and send them out. Half the network hears about one first, half about the other. For a moment, the chain has two tips.

Nodes need a rule to settle this without talking it over. The rule is the same idea as Bitcoin’s: follow the branch with the most work. Pearl adds one twist, a safety margin before switching.

Try it

Build a short chain, then edit a block and watch every block after it break. The heavier unbroken chain is the one nodes keep.

A chain of blocks

Each block carries the hash of the one before it

Or edit any block’s text.
  1. #0valid

    prev00000000…

    hash364153cd…

  2. #1valid

    prev364153cd…

    hashf64fa108…

  3. #2valid

    prevf64fa108…

    hashcc973143…

  4. #3valid

    prevcc973143…

    hash051665a3…

  5. #4valid

    prev051665a3…

    hash1213537f…

Every block points at the real hash of the one before it: the chain is intact.

Real Pearl Re-linking was free here. In Pearl the block hash covers the 108-byte header, whose last field commits to a winning ticket, and that ticket came from a mining job keyed by the template, previous block’s hash included. Change a parent and the old ticket is worthless: every re-linked block has to be mined again, with new matrix work and a new certificate. That’s why old blocks get harder to rewrite with every block on top.

Toy header height ‖ previous hash ‖ SHA256d(text), hashed with SHA256d. Real headers are 108 bytes: version, previous block, Merkle root, time, bits, proof commitment.

Runs in your browser · nothing is sent src/lib/hash.ts · sha256d

Which branch do nodes follow?

The valid one with the most total work. Each block’s work is 2²⁵⁶ ÷ (target + 1), the expected effort to win it, and a branch’s work is the sum over all its blocks, back to genesis.

Note “most work”, not “most blocks”. Because work grows with difficulty, a long chain of easy blocks can lose to a short chain of hard ones. In practice, with WTEMA keeping neighboring blocks at almost the same difficulty, the longer branch nearly always wins.

The newest block of the branch a node follows is its tip. Everything below is “the chain” as far as that node is concerned.

Block 100101a101b102bstale: same work as 101b, but outgrowntip: +1 block of work≫ the ¼-block margin
A split. Blocks 101a and 101b share a parent, so they carry identical bits and identical work. A node that saw 101a first stays on it. When 102b arrives, branch b leads by a whole block and every node moves to it; 101a becomes stale.

What is Pearl’s quarter-block margin?

A node switches from its current tip to a competing one only if both of these hold:

  1. the competing branch has strictly more total work, and
  2. its lead is at least a quarter of the work of the smaller of the two tip blocks.
switch⟺Wnew>Wnow and Wnew−Wnow≥14min⁡(wtip,wnew tip)\text{switch} \iff W_{\text{new}} > W_{\text{now}} \;\text{ and }\; W_{\text{new}} - W_{\text{now}} \ge \tfrac{1}{4}\min(w_{\text{tip}}, w_{\text{new tip}})
W = total chain work; w = one block's work.

At block 130,827’s difficulty, one block’s work is 11,303,469,090,474,696,447,598, so the margin is 2,825,867,272,618,674,111,899.

Pearl’s code was run on this rule with competing branches whose lead was a fraction of one block’s work:

Lead of the competing branch Switch?
0 (a tie) no
1/16 of a block no
3/16 of a block no
4/16 = 1/4 of a block yes
5/16 of a block yes
one whole block yes

What happens in a tie?

Nothing: equal work fails the first condition, so a node keeps the tip it already has. This is the first-seen rule, as in Bitcoin.

On Pearl, a fresh split is always an exact tie. A block’s required bits depend only on its parent’s bits and its parent’s solve time (that’s WTEMA’s one-block lag). Two blocks on the same parent therefore need identical bits and carry identical work. Whichever one a node hears first, it keeps.

The tie breaks when the next block arrives. Whichever branch it extends now leads by a whole block of work, far beyond the quarter-block margin, and every node moves there.

Why add a margin at all?

The code’s own comment gives the reason: to prevent “trivial-margin reorgs”. Without it, a branch could win by a crumb of work.

Where would a crumb come from? From timestamps. Two branches of the same length, split two or more blocks back, can carry slightly different bits, because each branch’s timestamps steer its own WTEMA steps.

What is a reorg?

When a node does switch, it performs a reorganization: it disconnects blocks from its old tip back to the point where the branches split, then connects the new branch’s blocks in order, checking each one.

  • Transactions in the disconnected blocks that aren’t in the new branch go back to the mempool, to be mined again.
  • The disconnected blocks become stale. Their coinbase rewards never existed as far as the chain is concerned, which is why coinbase outputs wait 100 blocks before they can be spent.
  • A reorg can never reach below the latest checkpoint: nodes refuse blocks that fork the chain before it.

Pearl’s light client uses the same rule, with the same quarter-block margin, when its headers disagree.

How many confirmations are enough?

There’s no protocol answer; it depends on how much is at stake. Each confirmation is another block of work an attacker would have to redo, and then outrun the honest network by a quarter of a block. Waiting longer makes undoing a payment rapidly harder.

Make a guess

A node follows branch A, 5 blocks above the split. Branch B appears with 5 blocks too, and slightly more total work. Does the node switch?

Think of your answer first, then check it.

Answer Only if B's lead is at least a quarter of a block's work.

Five blocks each, built from the same starting difficulty a few minutes apart, typically differ in total work by well under one percent of a block. That’s far below the quarter-block margin, so the node stays on A. When either branch gains a sixth block, it leads by about a whole block and wins.

Code: ShouldChangeTip

From chain.go (node/blockchain/chain.go:1166-1188 at v1.5.2, on GitHub):

node/blockchain/chain.go Go
func ShouldChangeTip(currentWork, proposedWork, currentTipBlockWork, proposedTipBlockWork *big.Int) bool {
	if currentWork.Cmp(proposedWork) >= 0 {
		return false // not strictly more work: keep the current tip
	}
	diff := new(big.Int).Sub(proposedWork, currentWork)
	minBlockWork := currentTipBlockWork
	if proposedTipBlockWork.Cmp(currentTipBlockWork) < 0 {
		minBlockWork = proposedTipBlockWork
	}
	threshold := new(big.Int).Rsh(minBlockWork, 2) // ÷ 4, despite the comment's "half"
	return diff.Cmp(threshold) >= 0
}

The light client calls the same function in spv/blockmanager.go (spv/blockmanager.go:2669-2672 at v1.5.2, on GitHub).

The codex

Suggested

Up and down arrows move through the results, Enter opens one, Escape closes. Anywhere on the site, slash or Command K opens this search, and the square brackets [ and ] go to the previous and next page.