§ 11

§ 11 · Blockchain

Checkpoints

Twelve block hashes written into the software

Every block hash depends on the block before it. So if you know the hash of block 120,000, you know, in effect, the entire chain up to that point: change any earlier byte and that hash would come out different.

Pearl’s node software ships with such hashes written in. They are checkpoints: one known block hash every 10,000 blocks. A node checks the chain it downloads against them and refuses anything that disagrees.

Try it

Edit an old block in this little chain and watch every later hash change. A checkpoint is simply one of those later hashes, written down in advance.

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

What are Pearl’s checkpoints?

Twelve pairs of height and block hash, in pearld v1.5.2:

HeightBlock hash
10,000a3c196fb1c3f7837bbebd69b98fc451d88d48083af98c318c78486d7f1888490
20,000513270b25c6d538f38b26ecdc014f2a809639ec7ebd3c09e4685675311420273
30,000fd61132c2ad6c22fa48a8df483bc6b885c12ceeb3fe0a9fa55eb5beb849fac7b
40,00035aac0e2a1e7f2d54924d584cf423b56f0d72d6770ee8365dc1667dbb5b5b320
50,000608f32e5390b2ae964c986a53e1be10ba4a640f3ccecf96d6b7838e06cb517ff
60,0005a7f0590c3a89099b2d0f1509d2186c73bc3d8e2e4a60e7ce4ec236856900dad
70,000281a3469d55226bb9e1b3ccee06eeb923177817b4cdead75131074b171b215c1
80,00069d40caca39b3c04ee55589d13cd1c5c546a3eb8712a3367840c5f67ab707cfc
90,0000738b30bb353820a4f97331d805d134de4321a5fc5c8b2955988e7291a0c8562
100,000ca8d5f604a9021e538f31472d9a9641c7bc46a6b8d591748e2869429571edbfb
110,000c119b81da722428e61dcda4ec1d6a2a56e6e40acb29592d11081538ab3d50630
120,000a5f57e441de1da43a27b4bee471c7a7bdd8e36664050385bf0a1b760d2a84b7d

Each hash was checked against Pearl’s public block explorer, and all twelve match. For block 120,000, the research behind this site went further: it fetched the raw block and hashed its header with Pearl’s own code, which gives exactly the checkpoint hash.

When is a checkpoint added?

Once a block is deep enough that nobody expects it to change. The code’s rule of thumb is CheckpointConfirmations = 2016: a candidate must have at least 2,016 blocks on top of it, about four and a half days at the target pace. Then a developer adds the next multiple of 10,000 in a new release.

So the list grows with each release, and older releases simply know fewer checkpoints.

What does a node do with them?

Several things, all in pearld v1.5.2:

  1. Match

    A block at a checkpoint height must have exactly the checkpoint’s hash, or it fails with ErrBadCheckpoint, whatever its work.

  2. No forks below the latest

    A block that would fork the chain below the latest checkpoint (block 120,000) is refused with ErrForkTooOld. The code comment’s reason: such blocks build on old, easier difficulty and could be used to waste memory and disk. It also means no reorganization can reach below that block.

  3. Skip script checks below it

    While catching up, scripts and signatures at or below the latest checkpoint aren’t run: the checkpoint’s hash already pins every transaction through the Merkle roots. Running scripts is the slowest part of checking a block, so this is a big speed-up. Each block’s certificate is still verified.

  4. Sync headers in checkpoint-sized steps

    A new node downloads headers, with their certificates, up to the next checkpoint before it fetches the blocks. See messages.

  5. Sanity-check claimed difficulty

    Before fully checking an unknown block, a node compares its bits with the last checkpoint’s: over a time D, the target can’t have grown by more than (87/32) per started week. See WTEMA.

Pearl’s DNS seeders use checkpoints too. They only hand out addresses of nodes whose chain reaches at least the latest checkpoint, which weeds out nodes stuck on an old, pre-fork chain. See peers and seeds.

Why one every 10,000 blocks?

The comment next to the list gives the reason: “denser checkpoints cap how much headers-first sync progress a peer disconnect can throw away.” A new node syncs headers one checkpoint-sized stretch at a time. If the peer it’s syncing from drops out halfway, the node has at most one stretch to redo.

On Pearl that matters more than on Bitcoin, because each header travels with its roughly 60 KB certificate, and the node verifies every one.

Doesn’t that mean trusting the developers?

A little, and it’s worth being clear how much.

The checkpoints are in the open source code, and anyone can compare them with the chain, as this page’s research did. A checkpoint can’t make an invalid block valid: blocks below it still need valid certificates and must link up correctly. What it does do is freeze history: a node won’t consider any chain that disagrees with a checkpoint or forks below the latest one, however much work it has. And below the latest checkpoint, transaction scripts aren’t re-checked during sync.

So you trust that the block hashes in the release were the real chain when they were written in, something you can check yourself, in exchange for faster syncing and protection against deep rewrites.

Make a guess

An attacker secretly mines a chain from block 115,000 and, by October 2026, it has more total work than the real chain. Can they reorganize Pearl nodes onto it?

Think of your answer first, then check it.

Answer No, not nodes running v1.5.2.

Their chain forks at 115,000, below the latest checkpoint, 120,000. Up-to-date nodes refuse its blocks with ErrForkTooOld, and its block 120,000 wouldn’t match the checkpoint hash anyway. Above the latest checkpoint, though, only the most-work rule protects the chain.

Code: matching checkpoints and refusing old forks

From validate.go (node/blockchain/validate.go:705-726 at v1.5.2, on GitHub):

node/blockchain/validate.go Go
blockHash := header.BlockHash()
if !c.VerifyCheckpoint(blockHeight, &blockHash) {
	return ruleError(ErrBadCheckpoint, str)
}
checkpointNode, err := c.FindPreviousCheckpoint()
if checkpointNode != nil && blockHeight < checkpointNode.Height() {
	return ruleError(ErrForkTooOld, str)
}

The list itself is in params.go (node/chaincfg/params.go:373-390 at v1.5.2, on GitHub), and the script skipping in validate.go (node/blockchain/validate.go:1086-1096 at v1.5.2, on GitHub):

node/blockchain/validate.go Go
checkpoint := b.LatestCheckpoint()
runScripts := true
if checkpoint != nil && node.height <= checkpoint.Height {
	runScripts = false
}

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.