Skip to content

Commit 8a58e00

Browse files
NateIsernclaude
andcommitted
feat(consensus): make block-1 premine mainnet-only so testnet can bootstrap
GetBlockValue(1) returned the 5,000,000 FAIR premine unconditionally, but ConnectBlock validates a block's mint against GetBlockValue(prev_height) — so for a brand-new chain, block 1 mints 5M while consensus expects the normal reward at height 0, and the block is rejected ("reward pays too much"). Mainnet is unaffected (its block 1 is long since mined and checkpointed), but it makes a fresh testnet impossible to launch. Gate the premine to non-testnet so testnet block 1 mints the normal subsidy and is mineable. Mainnet consensus is byte-identical. release.yml marks *-testnet* tags as prereleases so they never become releases/latest (tracked by mainnet). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 7c44a3f commit 8a58e00

2 files changed

Lines changed: 11 additions & 3 deletions

File tree

.github/workflows/release.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,9 @@ jobs:
201201
with:
202202
name: FairCoin ${{ github.ref_name }}
203203
draft: false
204-
prerelease: false
204+
# Mark *-testnet* tags as prereleases so they never become releases/latest
205+
# (the mainnet node tracks releases/latest). Normal v* tags stay full releases.
206+
prerelease: ${{ contains(github.ref_name, '-testnet') }}
205207
generate_release_notes: true
206208
fail_on_unmatched_files: false
207209
files: |

src/main.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1617,8 +1617,14 @@ double ConvertBitsToDouble(unsigned int nBits)
16171617

16181618
int64_t GetBlockValue(int nHeight)
16191619
{
1620-
if (nHeight == 1)
1621-
return 5000000 * COIN; // premine on block 1 (block 0 coinbase is unspendable by protocol)
1620+
// Premine is a one-time mainnet launch event (block 0 coinbase is unspendable
1621+
// by protocol). It is mainnet-only: a fresh testnet must be bootstrappable, but
1622+
// the miner pays GetBlockValue(1) while ConnectBlock validates against
1623+
// GetBlockValue(prev=0)=normal subsidy, so a premined block 1 is rejected on a
1624+
// brand-new chain. Excluding testnet lets testnet block 1 mint the normal reward
1625+
// and be mined; mainnet consensus is unchanged.
1626+
if (nHeight == 1 && Params().NetworkID() != CBaseChainParams::TESTNET)
1627+
return 5000000 * COIN;
16221628

16231629
int halvings = nHeight / 525600; // halving every ~2 years (2-min blocks)
16241630
int64_t nSubsidy = 10 * COIN;

0 commit comments

Comments
 (0)