fix(net): enforce nMinimumChainWork in IBD (eclipse / low-work fake-chain protection)

nMinimumChainWork was defined in chainparams but never checked, and IsInitialBlockDownload
decided "synced" from tip timestamp/height alone -- so an eclipsed or bootstrapping node
could be fed a cheap low-work fake chain with recent timestamps and trust it. Reset the
stale mainnet floor (0x281b32ff3198a1 was ABOVE the live chain, would have bricked mainnet)
to the real chainwork at height ~3,100,000, and hold a node in IBD until its tip reaches the
floor. Gated to the DRAGONX symbol so ephemeral assetchains from the same binary are not
trapped in IBD; the check can only keep a node in IBD, never force it out (no false-sync risk).
Complements the header-flood fix (b9fdc7981): that stops invalid-PoW headers off the real tip;
this stops valid-but-cheap fake chains from a fake genesis.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-13 17:21:12 -05:00
parent 14e3fb6708
commit 7e99311210
2 changed files with 14 additions and 1 deletions

View File

@@ -131,7 +131,9 @@ public:
consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight = Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT; consensus.vUpgrades[Consensus::UPGRADE_SAPLING].nActivationHeight = Consensus::NetworkUpgrade::NO_ACTIVATION_HEIGHT;
// The best chain should have at least this much work. // The best chain should have at least this much work.
consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000000000000000281b32ff3198a1"); // DRAGONX mainnet chainwork @ height ~3,100,000 (2026-07), safely below the live tip.
// (Previous value 0x281b32ff3198a1 was a stale inherited figure ABOVE the live chain.) Bump on release.
consensus.nMinimumChainWork = uint256S("0x0000000000000000000000000000000000000000000000000026dfbdb6fa39e0");
/** /**
* The message start string is designed to be unlikely to occur in normal data. * The message start string is designed to be unlikely to occur in normal data.

View File

@@ -2456,6 +2456,17 @@ bool IsInitialBlockDownload()
//fprintf(stderr,"nullptr in IsInitialDownload\n"); //fprintf(stderr,"nullptr in IsInitialDownload\n");
return true; return true;
} }
// SECURITY: enforce the known-good minimum chain work (defined in chainparams but previously
// never checked). Keeps an eclipsed/bootstrapping node from trusting a cheap low-work fake
// chain -- a recent tip timestamp alone (below) is not sufficient. Gated to the DRAGONX symbol
// so ephemeral assetchains (fresh, low work) run from the same binary are not trapped in IBD.
if (strncmp(SMART_CHAIN_SYMBOL, "DRAGONX", 7) == 0 &&
ptr->chainPower.chainWork < UintToArith256(chainParams.GetConsensus().nMinimumChainWork))
{
return true;
}
state = ((chainActive.Height() < ptr->GetHeight() - 24*60) || state = ((chainActive.Height() < ptr->GetHeight() - 24*60) ||
ptr->GetBlockTime() < (GetTime() - nMaxTipAge)); ptr->GetBlockTime() < (GetTime() - nMaxTipAge));
if ( HUSH_INSYNC != 0 ) if ( HUSH_INSYNC != 0 )