Mining Pool Behavior during Forks

Monday, July 15, 2024

I have recently been looking at mining pool behavior during forks. Which block does a pool choose to mine on during a fork? Do they behave rationally and mine on their own block? In this post, I’ll detail the mining pool behavior during forks and give some recent examples of pool behavior.


I’ve also published a short-form video1 on this topic on Twitter and YouTube.

In Bitcoin, a blockchain fork usually happens when two mining pools find a block based on the same previous block at roughly the same time. The fork is usually resolved with the next block building on top of one of the two fork-blocks. One block becomes part of the active chain (wins) while the other one becomes stale (loses).

A fork at height 45342: Pool A and Pool B both mined a block at height 45342. Pool B mined block 45343 on top of its own block and won. Pool A's block 45343 became stale.
A fork at height 45342: Pool A and Pool B both mined a block at height 45342. Pool B mined block 45343 on top of its own block and won. Pool A’s block 45343 became stale.

During a fork, the game theory is as follows: Pools that mined one of the fork blocks always want to mine on their own block and never on the competing fork-block. The chance of finding a block is equal to the share of network hashrate the pool has, and does not depend on who found the previous block. A pool with 5% of the network hashrate has a 5% chance to find a block on the competing pool’s block and a 5% chance of finding a block on his own block. However, mining on its own block, the pool can find the winning block and yield two blocks, the fork-block and the winning-block. Mining on the competing block, it can only yield the winning-block.

Pool B yields only one block when mining on top of Pool A's block. However, it can yield two blocks when mining on its own block.
Pool B yields only one block when mining on top of Pool A’s block. However, it can yield two blocks when mining on its own block.

Pools that mined neither of the fork-blocks can freely choose which block to build on. By default, they usually end up mining on the block they validate first. Their chance to find a block is equal to their network hashrate. It does not matter which fork-block other pools are mining on.

Recent Examples

The block pools are mining on is sent along with the mining jobs the pools public stratum servers publish. To analyze pool behavior, I’ve been recording the stratum jobs during forks. Note that there are possibly multiple public or even private stratum endpoints that could publish different jobs. The data I have might be incomplete and not show the full picture.

ViaBTC and AntPool at height 848860

Originally posted here.

During the fork at height 848860 between ViaBTC and AntPool, AntPool started off by briefly mining an empty-block-job2, a mining job with no transactions in the block, on their own block but then switched to mining on ViaBTC’s block. By switching to ViaBTC’s block they abandoned their block and lost the chance to find the fork- and the winning-block. However, it turned out that Foundry was mining on the AntPool block and found a block on it. Despite abandoning its block, AntPool was able to include one block in the active chain.

ViaBTC and AntPool at height 848860
ViaBTC and AntPool at height 848860

AntPool and Foundry at height 848968

Originally posted here.

108 blocks later, AntPool and Foundry both mined a block at height 848968 resulting in another fork. Again, AntPool started off with an empty-block-job mining on their own block before switching to Foundry’s block 2. Foundry found a block 848969 causing AntPool’s block 848968 to become stale.

AntPool and Foundry at height 848968
AntPool and Foundry at height 848968

AntPool and Foundry at height 851170

Originally posted here.

Similarly, both Foundry and AntPool found a block at height 851170 and AntPool starts off with an empty-block-job2 on its own block before switching to Foundry’s block. AntPool ended up finding a block on top of Foundry’s block and both AntPool and Foundry end up with one block each. If AntPool had stayed on their own block, they could have ended up mining both blocks.

AntPool and Foundry at height 851170
AntPool and Foundry at height 851170

Foundry and AntPool at height 848477

Originally posted here.

The fork at height 848477 between Foundry and AntPool was different. All pools, including Foundry, started mining on top of AntPool’s block 848477. About 30 seconds3 in, Foundry switched to a different block at height 848477 mined by Foundry, and they end up finding block 848478 building on top of it. In this case, Foundry successfully switched to their own block, yielding two blocks in the active-chain while AntPool’s block became stale.

Foundry and AntPool at height 848477
Foundry and AntPool at height 848477

Why isn’t AntPool mining on their own blocks?

The question of why AntPool, who have been around since 2015 and have mined 10% of all Bitcoin blocks in existence, are not switching to their own blocks during forks remains open. Aren’t forks frequent enough to bother? Probably, calling preciousblock along with the submitblock RPC when submitting a newly found block to their nodes would do the trick. Maybe some part of their pool software is incompatible with this?

2024-08-05: A previous version of this blog post was called “Mining Pool Game Theory during Forks”. I’ve since changed the title to “Mining Pool Behavior during Forks” as I think this better reflects the contents.


  1.  ↩︎

  2. AntPool often mines an empty-block-job for 30 seconds after a new block. These empty jobs aren’t based on a block template generated by a Bitcoin Core node and probably originate from a custom mining job creation software. When the job creation software learns about a new AntPool block, it immediately publishes an empty-block-job for it and the block is probably submitted to a Bitcoin Core node. Probably at around the same time, the Foundry block arrives and is validated on the Bitcoin Core node. A Bitcoin Core node, by default, will mine on the block it validated first. This means that if they don’t manually switch, Foundry’s blocks must have reached the nodes first. ↩︎ ↩︎ ↩︎

  3. Foundry implemented a “switch-to-own-block” logic and my guess is that they didn’t bother, or forgot, to implement sending a new mining job for it. The switch happened with the next job update they sent out. Foundry’s job updates happen every 30 seconds. ↩︎

All text and images in this work are licensed under a Creative Commons Attribution-ShareAlike 4.0 International License Creative Commons License

Previous

Image for Update on LinkingLion: Reduced activity and a statement by LionLink Networks

March 28, 2024

Update on LinkingLion: Reduced activity and a statement by LionLink Networks

This is an update on the LinkingLion entity, presumably linking Bitcoin transactions to IP addresses, I published about a year ago. Yesterday, LionLink Networks AS issued a statement on their non-affiliation with the LinkingLion entity and on the same day, LinkingLion activity significantly dropped.