Analyzing Mining Pool Behavior to Address Bitcoin Core's Double Coinbase Reservation Issue

In theory, Bitcoin Core’s block-building algorithm reserves 4000 WU for block header, transaction count and miners’ coinbase transactions. This means it should generate a block template with a weight of 3,996,000 WU.
However, in practice, this is not the case due to an accidental double-reservation bug (see #21950).
As a result, Bitcoin Core generates block templates with a weight of 3,992,000 WU.

There is an ongoing attempt to fix this issue (see #31384), but there are concerns that fixing the issue could lead to some miners generating invalid block templates.
If the PR were to be merged, mining pools using the updated Bitcoin Core version must ensure the sum of the coinbase transaction weight and the weight of all additional transactions added to the block template must not exceed 4000 WU.
Otherwise, the block will exceed the consensus limit for the maximum block weight (4,000,000 WU) and be invalid.

The proposed PR fixes the double reservation issue, which means the block template size is increased by 4000 WU, resulting in blocks with a weight of 3,996,000 WU as expected and matches theory.

Miners or pools needing more than 4000 WU for their coinbase transactions should configure bitcoind with a lower -blockmaxweight option.
For example, starting Bitcoin Core with -blockmaxweight=3999000 will free up an additional 1000 WU.

The purpose of this analysis is to examine mining pool behavior and determine the feasibility of this change.

  • Blocks Analyzed: 107,313
  • Period: 24th December 2022 to 23rd December 2024

Methodology

  • I’ve used libbitcoinkernel to read blocks from disk.
  • Each block is deserialized, and bitcoin-data/mining-pools tags are used to match the block to a mining pool. The block weight, coinbase transaction, and mining pool information are then saved to disk.
  • After saving the data for the entire block interval, I generated the analysis results using this script.
  • Charts were generated using a set of scripts.
  • More details on the methodology can be found GitHub - ismaelsadeeq/mining-analysis.

Results

Note: Values in paranthesis represent block heights

Pools Generating Blocks with Coinbase Weight > 4000 WU

Pool Name Average Coinbase weight Lowest Coinbase weight Highest coinbase weight
Ocean.xyz 6994 5308 (865820) 9272 (863471)
Unknown pool 7432 7000 (824116) 7864 (785117)

Figure 1: Box Plot of Coinbase Transaction Weights > 4000 WU

This box plot shows the distribution of coinbase transaction weights for pools generating blocks with coinbase weights greater than 4000 WU.

Remaining mining pools coinbase stats

Pool Name Average Coinbase Weight Lowest Coinbase Weight Highest Coinbase Weight
ViaBTC 1,128 864 (778363) 1,284 (868424)
Foundry USA 834 748 (833764) 1,192 (868391)
F2Pool 1,610 1,176 (787112) 1,832 (868388)
AntPool 1,357 732 (814783) 1,612 (875136)
Binance Pool 1,151 684 (789485) 1,480 (810101)
SpiderPool 997 704 (817123) 1,296 (863176)
Braiins Pool 1,056 684 (853433) 1,232 (785389)
MARA Pool 815 720 (800883) 1,016 (833308)
SecPool 1,371 1,088 (808120) 1,460 (871380)
Poolin 1,110 728 (852695) 1,336 (795979)
Luxor 1,237 780 (770527) 1,480 (868404)
BTC.com 1,205 740 (796334) 1,476 (811469)
Pega Pool 688 688 (800892) 688 (800892)
Ultimus Pool 1,209 1,056 (853449) 1,444 (844214)
EMCDPool 1,082 1,080 (804771) 1,304 (795962)
SBI Crypto 716 716 (833247) 716 (833247)
NiceHash 786 780 (804872) 828 (870207)
Titan 696 696 (770484) 696 (770484)
WhitePool 887 676 (820630) 1,304 (865060)
KuCoin Pool 1,095 1,092 (777136) 1,316 (796122)
CleanIncentive 728 728 (819134) 728 (819134)
1THash 1,084 1,084 (837937) 1,088 (864350)
EclipseMC 860 860 (858559) 860 (858559)
Terra Pool 844 844 (780190) 844 (780190)
CKPool 856 856 (863890) 856 (863890)

Figure 2: Line Chart of Coinbase Transaction Weights

This line chart shows the average, minimum, and maximum coinbase transaction weights for various mining pools.

Pools with Blocks (> 3,996,000 WU)

Pool Name Average Block Weight Lowest Block Weight Highest Block Weight
F2Pool 3,997,857 3,994,044 (828959) 3,998,554 (779729)

Pools with Blocks (< 3,996,000 WU)

Pool Name Average Block Weight Lowest Block Weight Highest Block Weight
Foundry USA 3,993,030 3,992,749 (813879) 3,993,523 (874770)
Binance Pool 3,993,348 3,992,753 (784937) 3,993,768 (846996)
MARA Pool 3,993,017 3,992,721 (802653) 3,994,944 (859968)
Luxor 3,993,434 3,992,782 (768718) 3,993,811 (841510)
AntPool 3,993,554 3,992,868 (814783) 3,993,918 (873367)
ViaBTC 3,993,324 3,992,881 (782955) 3,993,612 (872513)
Poolin 3,993,308 3,992,987 (855538) 3,993,613 (795979)
Braiins Pool 3,993,251 3,992,695 (853433) 3,993,416 (853776)
SBI Crypto 3,992,911 3,992,717 (796840) 3,993,047 (834797)
Ultimus Pool 3,993,407 3,993,076 (852748) 3,993,768 (842345)
BTC.com 3,993,399 3,992,745 (796409) 3,993,781 (806063)
SpiderPool 3,993,190 3,992,912 (856599) 3,993,616 (864899)
WhitePool 3,993,072 3,992,677 (825268) 3,993,631 (872281)
Ocean.xyz 3,988,137 3,986,489 (865820) 3,990,301 (863471)
EMCDPool 3,993,273 3,993,081 (781934) 3,993,428 (796046)
Pega Pool 3,992,894 3,992,690 (783729) 3,993,018 (781576)
Titan 3,992,974 3,992,926 (768641) 3,993,020 (769939)
KuCoin Pool 3,993,282 3,993,101 (781030) 3,993,504 (796188)
Terra Pool 3,993,032 3,992,863 (776927) 3,993,172 (780396)
CleanIncentive 3,992,946 3,992,748 (823029) 3,993,038 (822604)
1THash 3,993,276 3,993,085 (837937) 3,993,412 (814830)
NiceHash 3,992,987 3,992,782 (789503) 3,993,148 (785085)
CKPool 3,993,102 3,992,897 (863890) 3,993,181 (822636)

Figure 3: Line Chart of Mining pool block Weights

This line chart shows the average, minimum, and maximum block weights for various mining pools.

Key Observations

  • Most mining pools adhere to Bitcoin Core’s default setup, keeping coinbase transaction weights well below 4000 WU. However, two pools stand out:
    • Ocean.xyz consistently uses larger coinbase transactions, with an average weight of 6,994 WU. Their smallest coinbase weight was 5,308 WU (in block 865820), and their largest reached 9,272 WU (block 863471). This suggests Ocean.xyz configures its node with a reduced -blockmaxweight setting, as their average block size is 3,986,489 WU, well below the default template size.
    • An Unknown Pool/miner also exceeded the default coinbase weight, averaging 7,432 WU, with a maximum of 7,864 WU but a very low block weight average which is unusual behavior.
  • F2Pool blocks have an average weight of 3,997,857 WU. For instance, block 779729 reached 3,998,554 WU with a coinbase weight of just 1,588 WU, showcasing F2 optimal use of the available block weight.
  • The majority of pools—such as Foundry USA, Binance Pool, and AntPool—produce blocks averaging around 3,993,000 WU, consistent with Bitcoin Core’s current behavior. However, this depicts underutilization which is a direct result of the double-reservation bug.
  • The small increase in the weights of the blocks among these pools suggests minor additions of transactions by miners after building a block template.
  • The small increase in the weights of the blocks after selecting the transactions is accounted for the block headers, as noted by @0xB10C here

If the double-reservation issue is fixed, block templates will increase to 3,996,000 WU, aligning theoretical and actual limits. This change benefits pools by allowing full utilization of the block weight while preserving 4000 WU for coinbase transactions and other small additions.

Miners who need more space, such as Ocean.xyz, can still configure their nodes with a reduced -blockmaxweight. For example, setting it to 3,999,000 WU frees up 1000 WU for larger coinbase transactions, ensuring compliance with consensus rules.

I think addressing this bug will enhance fairness across the mining pools and fix the ambiguity for developers working with the bitcoin core codebase.

9 Likes

How much of Ocean’s data, puts into consideration, their DATUM server, which gives hashers opportunity to generate their own Block template, and edit the miner tag. This I believe is a nuance worthy of noting. Thoughts?

  • The small increase in the weights of the blocks among these pools suggests minor additions of transactions by miners after building a block template.

I was surprised by this. I initially looked at SBI Crypto and noticed that their max block weight of 3,993,047 WU minus the max coinbase weight of 716 WU is 3,992,331 WU. That’s 331 WU more than the soft-maximum of 3,992,000 WU I was expecting. Looking at all pools, it seems it’s quite often around that 331 number, never more though.

Pool Name max block weight max coinbase weight weight above 3,992,000 notes
Foundry USA 3993523 1192 331
Binance Pool 3993768 1440 328
MARA Pool 3994944 904 2040 block with big inscription
Luxor 3993811 1480 331
AntPool 3993918 1612 306
ViaBTC 3993612 1284 328
Poolin 3993613 1336 277
Braiins Pool 3993416 1124 292
SBI Crypto 3993047 716 331
Ultimus Pool 3993768 1440 328
BTC-com 3993781 1472 309
SpiderPool 3993616 1288 328
WhitePool 3993631 1304 327
Ocean.xyz 3990301 9272 -10971 Ocean doesn’t use the default
EMCDPool 3993428 1304 124
Pega Pool 3993018 688 330
Titan 3993020 696 324
KuCoin Pool 3993504 1316 188
Terra Pool 3993172 844 328
CleanIncentive 3993038 728 310
1THash 3993412 1084 328
NiceHash 3993148 820 328
CKPool 3993181 856 325

I’d be surprised if this is really due to ALL pools adding extra transactions AFTER they got a template from Bitcoin Core. That seems risky (why not do it with prioritizetransaction?) and I haven’t noticed this in any of the blocks processed by my miningpool-observer project.

Is there possibly more to it?

1 Like

Yes :man_facepalming:, there is more to it. Especially to a serialized block…

  • the header is 80 bytes, accounting for 320 WU
  • usually, a 3 byte var_int for the number of transactions accounting for 12 WU (if a 1 byte var_int is enough, this is 4 WU)

This leaves us with 332 WU. As we check that the package weight is NOT >= 3,992,000 (i.e. we check that < 3,992,000), we actually have a soft-maximum of 3,991,999 WU.

This allows looking at how close the pools came to actually fill the block: Seems like Foundry, SBI Crypto, Braiins, and Luxor had 0 WU left in their blocks. This also indicates that all listed pools are currently using the default -blockmaxweight=3999000.

Pool Name max block weight max coinbase weight min WU left to fill
Foundry USA 3993523 1192 0
Binance Pool 3993768 1440 3
Luxor 3993811 1480 0
AntPool 3993918 1612 25
ViaBTC 3993612 1284 3
Poolin 3993613 1336 54
Braiins Pool 3993416 1124 39
SBI Crypto 3993047 716 0
Ultimus Pool 3993768 1440 3
BTC-com 3993781 1472 22
SpiderPool 3993616 1288 3
WhitePool 3993631 1304 4
EMCDPool 3993428 1304 207
Pega Pool 3993018 688 1
Titan 3993020 696 7
KuCoin Pool 3993504 1316 143
Terra Pool 3993172 844 3
CleanIncentive 3993038 728 21
1THash 3993412 1084 3
NiceHash 3993148 820 3
CKPool 3993181 856 6

This is probably incorrect then.

3 Likes

Thanks so much for looking into this in depth

Same, but unfortunately, I did not account for the block header size. It all makes sense now.

I’ll strike that through and note that the small increase is due to the size of the block headers.

1 Like

With your recent change to mining: bugfix: Fix duplicate coinbase tx weight reservation by ismaelsadeeq · Pull Request #31384 · bitcoin/bitcoin · GitHub to have a minimal reserved block weight of 2000 WU, I came back here to double check with the F2Pool’s stats.

  1. Can you clarify F2Pool’s min and max coinbase weights? In the table above the min is larger than max.
  2. For block 779729 with the max block weight of 3,998,554, a coinbase weight of ‎1588 WU and 332 WU for header+tx_count leaves me with a default of 3,996,634 WU. That seems to be an odd number to use as a custom -blockmaxweight (and only possible with patches to Bitcoin Core).
  3. If you have the data, it might be interesting to calculate block weight - coinbase weight - header weight for the F2Pool blocks to get a better feeling about the weight they reserve.

Can you clarify F2Pool’s min and max coinbase weights? In the table above the min is larger than max.

This inconsistency is due to a mix-up when compiling the data. Also, I meant the minimum block weight coinbase weight, not the minimum coinbase weight. I’ve separated the coinbase weight stats from the block weight stats and update the coinbase chart.

  • For block 779729 with the max block weight of 3,998,554, a coinbase weight of ‎1588 WU and 332 WU for header+tx_count leaves me with a default of 3,996,634 WU. That seems to be an odd number to use as a custom -blockmaxweight (and only possible with patches to Bitcoin Core).

If you have the data, it might be interesting to calculate block weight - coinbase weight - header weight for the F2Pool blocks to get a better feeling about the weight they reserve.

I think we are a certain that F2Pool is using a patch of Bitcoin Core after mining: bugfix: Fix duplicate coinbase tx weight reservation by ismaelsadeeq · Pull Request #31384 · bitcoin/bitcoin · GitHub

However, it would be useful to review the data for confirmation.

1 Like