§ 07

§ 07 · Blocks

Version

Four bytes inherited from Bitcoin that Pearl never checks

The version is the first field of every Pearl header: 4 bytes holding a number.

In Bitcoin, that number is how miners vote for upgrades. Pearl copied the format along with the rest of Bitcoin’s header, but it never uses it for anything. No rule checks it, and none of Pearl’s upgrades was voted in this way.

So this page is short, and mostly a history lesson. It’s still worth knowing, because explorers show the version on every block, and one stretch of Pearl’s history has an odd value that looks meaningful but isn’t.

Try it

The converter starts at 536,870,912, which is 0x20000000. Look at its 4 bytes in little-endian order: they’re the first 4 bytes of almost every Pearl header.

Hex converter

Decimal, hex and binary, and the bytes in both orders

Big-endian as written
20000000
Little-endian as stored
00000020
Runs in your browser · nothing is sent src/lib/bytes.ts

What does it look like?

Size
4 bytes
Type
Signed integer (int32)
Format
Little-endian
Range
Any value; not checked
Block 130,827 · header 108 bytes
00000020 999c961b04d94b8b21134e862dc31d5fa56cf9d1f027adb2a0cf95c6525c55eb 6389faa36bd9daffdefc800dea88ac3ef5af1198f7d7179ef3b904420c1cc2c6 1a96d76a a6f36a17 4d52a3fd32160cb032e22edf76912f67dfb1b88946a215281f203836c77ae649
Field Bytes Value
Version header.version 4 @0 0x20000000 int32 LE. BIP-9 style 0x20000000 since block 1; no consensus meaning in Pearl.
Previous block header.prevBlock 32 @4 eb555c52c695cfa0b2ad27f0d1f96ca55f1dc32d864e13218b4bd9041b969c99 Hash of the parent block, stored byte-reversed; shown in display order.
Merkle root header.merkleRoot 32 @36 c6c21c0c4204b9f39e17d7f79811aff53eac88ea0d80fcdeffdad96ba3fa8963 Root of the SHA256d Merkle tree of this block’s txids, stored byte-reversed.
Time header.timestamp 4 @68 1792513562 (2026-10-20 16:26:02 UTC) uint32 LE Unix seconds. Must be at least 1 s after the parent and at most 5 min in the future.
Bits header.bits 4 @72 0x176af3a6 Compact target. Difficulty 40157376.49334089. The certificate's jackpot hash (not this header's hash) must meet it.
Proof commitment header.proofCommitment 32 @76 49e67ac73638201f2815a24689b8b1df672f9176df2ee232b00c1632fda3524d SHA256d(LE32(certificate version) ‖ public data). Replaces Bitcoin’s nonce: Pearl headers have no nonce.
Block hash
1df2f2c1bf39b1a444e622c1788c11736da2f91f4e9a875a38dc23063c6d45b9
Height
130,827
Time
2026-10-20 16:26:02 UTC
Difficulty
40,157,376.49

Block 130,827’s header starts with 00 00 00 20. Integers are stored little-endian, smallest byte first, so you read the bytes backwards: 20 00 00 00, the number 0x20000000 (536,870,912 in decimal).

Pearl’s chain has used three values:

Blocks Version Bytes in the header
Genesis (block 0) 1 01000000
1 onward, normally 0x20000000 00000020
About 2,100 to 100,799 0x20400000 00004020

Why 0x20000000?

Because of Bitcoin’s version bits scheme, BIP 9. Written in binary, the version splits into two parts:

00100000010000000000000000000000bits 31–29: formatbit 22bits 28–0: one signal each310
0x20400000 in binary. The top three bits, 001, mark the version-bits format; each of the other 29 bits can signal one proposed upgrade. Bit 22 is set here.
  • The top three bits are 001. That says “this block uses version bits”. It’s what makes every version start with hex digit 2.
  • The other 29 bits are signals. Each proposed upgrade (a deployment) is given one bit. A miner who supports it sets that bit. If enough blocks in a 2,016-block window signal, the upgrade locks in.

With no signals set, you get exactly 0x20000000. Pearl’s node builds every block template’s version this way, starting from those top bits and adding the bit of any deployment currently being voted on.

What was 0x20400000 about?

For most of Pearl’s first 100,000 blocks, the version was 0x20400000: the same number plus bit 22. It looked like a vote for something. It wasn’t, really.

Pearl’s mainnet settings define only three deployments, all test dummies left in from the btcd code Pearl is built on, on bits 28, 22 and 30. Nothing in the code depends on any of them. The bit-22 dummy is a “speedy trial” deployment that can only activate after block 100,000.

The chain data fits this story, though the exact history is an inference, not something the code records. The dummy was switched on soon after launch, so templates set bit 22 from roughly block 2,100. It then locked in and waited for its minimum height. It became active at block 100,800, the first 2,016-block boundary after 100,000. Once active, a deployment stops being signalled, so templates went back to plain 0x20000000.

The bit never had any consensus effect.

Does anything check the version?

No. Pearl’s node has an error code for “block version too old”, inherited from btcd, but the block validation code never raises it. As far as Pearl’s consensus rules go, the version can be any 4 bytes.

That makes the version a rare thing in a Pearl header: data that is hashed into the block’s ID, but means nothing.

How does Pearl upgrade instead?

At fixed heights, written into the node software. Each fork switches on at a set block number, and the two hard forks also changed the certificate version that blocks must carry:

Height Fork Kind What changed
71,935 MoE hard fork hard Blocks must carry a V2 certificate, which adds support for Mixture-of-Experts proofs.
91,630 Dense-only soft fork soft Mixture-of-Experts proofs are rejected again; only dense proofs count.
96,251 Rank-penalty soft fork soft Noise rank must be at least 128, and a higher rank makes the winning bar stricter in proportion.
99,000 Salted noise-seed hard fork hard Blocks must carry a V3 certificate: the noise seeds now also commit to the matrix sizes.
Code: the top bits and the template version

From calcNextBlockVersion (node/blockchain/versionbits.go:278-296 at v1.5.2, on GitHub): start from the top bits, then add the bit of every deployment that is being voted on or is locked in.

node/blockchain/versionbits.go Go
vbTopBits = 0x20000000

expectedVersion := uint32(vbTopBits)
for id := 0; id < len(b.chainParams.Deployments); id++ {
	deployment := &b.chainParams.Deployments[id]
	state, err := b.thresholdState(prevNode, checker, cache)
	if state == ThresholdStarted || state == ThresholdLockedIn {
		expectedVersion |= uint32(1) << deployment.BitNumber
	}
}

The three test deployments, including DeploymentTestDummyMinActivation on bit 22 with MinActivationHeight: 100000, are in params.go (node/chaincfg/params.go:398-429 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.