In a few hours, the Bitcoin network will experience its third “halving”. So what is it and how does it work under the hood?
Let’s deep-dive into the nitty-gritty details. The fun stuff. 🤓
Block subsidy and reward halving
A quick recap: miners all around the world are, at this very moment, running hardware and software to calculate the hash of the next Bitcoin block.
If they manage to solve the mathematical puzzle in time, they can claim the block reward.
That’s a lot of buzzwords right there, isn’t it? Let’s break it down.
What’s a hash?
The whole concept of mining is extremely clever. There isn’t actually a puzzle to solve, it’s more of a brute force attempt at trying to guess a magic number.
The Bitcoin network uses SHA256
hashes pretty much everywhere. In a simplified version, miners all around the world are trying to run this function:
SHA256(
$previousBlockHash,
$newTransactionHeadersToBeIncluded,
$magicNumber
);
The $magicNumber
is also called a nonce, a Number Used Once. By including the previous blocks’ hash in the new hash calculation, an actual chain is formed linking each block to the new one. A blockchain is essentially a linked list on steroids.
Miners are in the process of guessing the value of $magicNumber
. They run the very same calculations over and over again, incrementing (or randomizing) the $magicNumber
value. By doing so, they change the outcome of the function every time.
When do they “win”?
Once they find a hash that is smaller than to a difficulty target.
It’s so simple it’s almost stupid. The difficulty of the calculations are determined by the result of the hash. This loosely translates to the number of zeroes at the front of the block hash. When the very first block was mined, it only had 8 zeroes at the front:
00000000839a8e6886ab5951d76f411475428afc90947ee320161bbf18eb6048
When, at the time of writing, the last hash was calculated, it had 19 zeroes at the front.
0000000000000000000133e7bffe43530e508183ec48a89bad23a370692b16e8
The more zeroes there are at the front, the lower the hash value is, and the more difficult it was to guess that magic number.
Sidenote: the brilliance of this algorithm is actually in the way it automatically re-calculates that difficulty target (aka: how many zeroes are needed) every 2016 blocks, but that’s for another write-up.
The reward
If you guess the number correctly, you get a reward. That reward comes in the form of newly minted Bitcoins.
These are Bitcoins that are essentially created out of thin air. Except it’s neither thin nor air. Effort was put into the network in the form of computational power and energy. As a result, you get Bitcoin. As a miner, your reward is the result for securing the network.
These newly created Bitcoin are created in what is called a Coinbase Transaction. This is a unique transaction, included in every block, that pays a certain amount of Bitcoin to the miner that guessed the correct hash.
(Yes, that’s probably where the popular cryptocurrency Exchange “Coinbase” got its name from, a reference to the miner reward transaction.)
The reward for each correct block is calculated automatically and auto-adjusts as the bitcoin network marches on. The way this works is quite beautiful, and I’d love to take you on a trip through the code.
The GetBlockSubsidy() function
The magic of the reward halving lies in function GetBlockSubsidy()
, located in src/validation.cpp.
CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams)
{
int halvings = nHeight / consensusParams.nSubsidyHalvingInterval;
// Force block reward to zero when right shift is undefined.
if (halvings >= 64)
return 0;
CAmount nSubsidy = 50 * COIN;
// Subsidy is cut in half every 210,000 blocks which will occur approximately every 4 years.
nSubsidy >>= halvings;
return nSubsidy;
}
So, what’s in there? Let’s break it down. It’s been a while since I wrote C, but lucky for us it’s fairly readable.
How many halvings have there already been?
Let’s start at the top:
int halvings = nHeight / consensusParams.nSubsidyHalvingInterval;
The last parameter, consensusParams.nSubsidyHalvingInterval
, is defined in src/chainparams.cpp as part of the consensus rules. These are a set of rules everyone on the bitcoin network needs to honour.
Sidenote: any change on these consensus rules would create a “hard fork”, a new set of rules that no longer follow the original chain.
consensus.nSubsidyHalvingInterval = 210000;
Every 210,000 blocks, a halving occurs.
The nHeight
refers to the current block “height”. Or, put differently, the number of blocks that have already happened.
Soon, we’ll reach block 630,000. At that point, the equation becomes:
int halvings = 630000 / 210000;
Which will give halvings
a value of 3. This will be the third time the network has halved its block reward.
But what happens if there’s a floating point result value, clearly that doesn’t fit in an int
variable?
int halvings = 620000 / 210000;
This would result in 2.952380952. However, since the variable is defined as an integer, it is rounded to the lowest integer value by dropping the fractional. Then, halving
becomes 2.
The end of block rewards
Let’s take a look at this bit:
// Force block reward to zero when right shift is undefined.
if (halvings >= 64)
return 0;
This is safety code for a condition I don’t quite understand: if, for some reason, consensusParams.nSubsidyHalvingInterval
is too low or nHeight
is very high, it would result in the variable halvings
with a high value too.
I don’t think this check matters, because of the code we’ll see lower down?
Would love to know what race condition this is supposed to prevent.
Update: thanks to @niobos, I now know that the shift-by operand is masked. This is important for the code lower in this post, but it means that x >> 65
becomes x >> 1
, so the check for >= 64
needs to stay.
The original Bitcoin Core code didn’t have this bugfix, it was added in 2014 with this pull request.
This part is often misinterpreted as “there will be 64 Bitcoin halvings”. That is incorrect. There will be 33 Bitcoin halvings, as we’ll see lower.
How many Bitcoin do you get as a reward?
The word “halving” refers to the process of limiting the amount of Bitcoin you can get as a miner. At every 210,000 blocks, that amount is cut in half.
CAmount nSubsidy = 50 * COIN;
nSubsidy >>= halvings;
return nSubsidy;
At the very start, more than 10 years ago, 50 Bitcoin were rewarded for every block found on the network.
Then, after 210,000 blocks, that got cut in half to 25. Another 210,000 blocks later, that became 12.5. That’s where we are today.
In a few hours, it’ll be cut in half again, and only 6.25 Bitcoins are rewarded to the miner. Fast-forward another 210,000 blocks and that becomes 3.125. And so on.
There’s a clever bitwise operation going on in that code that I want to highlight:
nSubsidy >>= halvings;
It’s not every day you see a >>=
operator in your code.
Let’s rewrite that code with the filled in values for each variable:
CAmount nSubsidy = 50 * 100000000;
nSubsidy >>= 3;
return nSubsidy;
The block rewards have a fixed start value at 50. Each coin can be divided into 100,000,000 units, defined in src/amount.h. If we want to be correct, a miner doesn’t get “a Bitcoin” as a reward, it gets “100,000,000” pieces of a Bitcoin as a reward.
A hundred million tiny pieces that form a single bitcoin.
This gives us an initial value of nSubsidy
at 5,000,000,000
. If you write that in binary, you get
100101010000001011111001000000000
The nSubsidy >>= 3
means: shift the bits 3 places to the right. This leaves us with:
100101010000001011111001000000
When you convert that binary value to its decimal representation, you get 625,000,000
. In other words: “625,000,000 mBTC” or “6.25 BTC”.
At the next halving, another zero gets cut at the end of the decimal representation, effectively halving the reward value once again.
Because there are only 33 bits in total, we will run out of block rewards to halve after the 33rd halving, roughly in 2140.
(It’s assumed that at that point, the transaction fees being paid should be sufficient to compensate the miner power consumption and hardware.)
In conclusion
Bitcoin’s monetary supply is hard-coded, for everyone to see and review.
The whole idea that a network of thousands, if not millions, of miners can work in harmony is mindblowing. If you’ve ever tried to set up a 5-node cluster of anything, you’ll know reaching consensus or quorum can be hard.
- How do you get all your nodes to agree?
- How do you prevent drift?
- Or split brains?
- Or dataloss?
- What if one node crashes in the middle of a write operation?
This all just works on the Bitcoin network, operating on unknown hardware, on unknown internet speeds with unknown node versions and software - all because of math and the social consensus that everyone follows the same rules on the network.
Fascinating.