From 136d446157ed58f56a460deaa48e3ec2cd6f1b0d Mon Sep 17 00:00:00 2001 From: Sami Ahmed Date: Mon, 16 Mar 2026 18:32:11 -0700 Subject: [PATCH] Disable sync checkpoint system that blocks IBD The sync checkpoint (hashSyncCheckpoint) was persisted in LevelDB pointing to block 2,186,940. On startup it was loaded from DB, overriding any code change to the initial value. CheckSync then rejected every block below that height during IBD since they weren't in mapBlockIndex yet. Three-pronged fix: - CheckSync now always returns true (master key disabled, no new sync checkpoints will ever be broadcast) - AcceptBlock no longer calls sync checkpoint enforcement - LoadBlockIndex resets sync checkpoint to genesis if stored hash is not in the block index (prevents assert crash) Co-Authored-By: Claude Opus 4.6 --- src/checkpoints.cpp | 28 ++++------------------------ src/main.cpp | 16 ++++------------ src/txdb-leveldb.cpp | 13 ++++++++++--- 3 files changed, 18 insertions(+), 39 deletions(-) diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp index 2d111d5..673c130 100644 --- a/src/checkpoints.cpp +++ b/src/checkpoints.cpp @@ -218,30 +218,10 @@ namespace Checkpoints } // Check against synchronized checkpoint + // Disabled: master key removed in V5, no new sync checkpoints possible. + // Always returns true to prevent stale DB-persisted checkpoints from blocking IBD. bool CheckSync(const uint256& hashBlock, const CBlockIndex* pindexPrev) { - if (fTestNet) return true; // Testnet has no checkpoints - int nHeight = pindexPrev->nHeight + 1; - - LOCK(cs_hashSyncCheckpoint); - // sync-checkpoint should always be accepted block - assert(mapBlockIndex.count(hashSyncCheckpoint)); - const CBlockIndex* pindexSync = mapBlockIndex[hashSyncCheckpoint]; - - if (nHeight > pindexSync->nHeight) - { - // trace back to same height as sync-checkpoint - const CBlockIndex* pindex = pindexPrev; - while (pindex->nHeight > pindexSync->nHeight) - if (!(pindex = pindex->pprev)) - return error("CheckSync: pprev null - block index structure failure"); - if (pindex->nHeight < pindexSync->nHeight || pindex->GetBlockHash() != hashSyncCheckpoint) - return false; // only descendant of sync-checkpoint can pass check - } - if (nHeight == pindexSync->nHeight && hashBlock != hashSyncCheckpoint) - return false; // same height with sync-checkpoint - if (nHeight < pindexSync->nHeight && !mapBlockIndex.count(hashBlock)) - return false; // lower height than sync-checkpoint return true; } @@ -361,8 +341,8 @@ namespace Checkpoints bool IsMatureSyncCheckpoint() { LOCK(cs_hashSyncCheckpoint); - // sync-checkpoint should always be accepted block - assert(mapBlockIndex.count(hashSyncCheckpoint)); + if (!mapBlockIndex.count(hashSyncCheckpoint)) + return true; // no valid sync checkpoint, treat as mature const CBlockIndex* pindexSync = mapBlockIndex[hashSyncCheckpoint]; return (nBestHeight >= pindexSync->nHeight + nCoinbaseMaturity || pindexSync->GetBlockTime() + nStakeMinAge < GetAdjustedTime()); diff --git a/src/main.cpp b/src/main.cpp index de354f1..af06116 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -2471,18 +2471,10 @@ bool CBlock::AcceptBlock() } } - // Before fork: enforce sync checkpoints for historical chain integrity - // After fork: no sync checkpoint enforcement (decentralized) - if (nHeight < FORK_HEIGHT_V5) - { - bool cpSatisfies = Checkpoints::CheckSync(hash, pindexPrev); - - if (CheckpointsMode == Checkpoints::STRICT && !cpSatisfies) - return error("AcceptBlock() : rejected by synchronized checkpoint"); - - if (CheckpointsMode == Checkpoints::ADVISORY && !cpSatisfies) - strMiscWarning = _("WARNING: syncronized checkpoint violation detected, but skipped!"); - } + // Sync checkpoint enforcement is disabled: + // - Master key was removed in V5 fork, no new sync checkpoints will be broadcast + // - Hardcoded checkpoints already guarantee chain integrity + // - The persisted hashSyncCheckpoint in LevelDB blocks IBD from progressing // Enforce rule that the coinbase starts with serialized block height CScript expect = CScript() << nHeight; diff --git a/src/txdb-leveldb.cpp b/src/txdb-leveldb.cpp index 7e95019..cc27b16 100644 --- a/src/txdb-leveldb.cpp +++ b/src/txdb-leveldb.cpp @@ -484,10 +484,17 @@ bool CTxDB::LoadBlockIndex() hashBestChain.ToString().substr(0,20).c_str(), nBestHeight, CBigNum(nBestChainTrust).ToString().c_str(), DateTimeStrFormat("%x %H:%M:%S", pindexBest->GetBlockTime()).c_str()); - // triangles: load hashSyncCheckpoint + // triangles: load hashSyncCheckpoint (best-effort, non-fatal) if (!ReadSyncCheckpoint(Checkpoints::hashSyncCheckpoint)) - return error("CTxDB::LoadBlockIndex() : hashSyncCheckpoint not loaded"); - printf("LoadBlockIndex(): synchronized checkpoint %s\n", Checkpoints::hashSyncCheckpoint.ToString().c_str()); + printf("LoadBlockIndex(): no sync checkpoint in DB, using default\n"); + else + printf("LoadBlockIndex(): synchronized checkpoint %s\n", Checkpoints::hashSyncCheckpoint.ToString().c_str()); + // If the stored checkpoint isn't in our index, reset to genesis so we don't assert-crash + if (!mapBlockIndex.count(Checkpoints::hashSyncCheckpoint)) + { + printf("LoadBlockIndex(): sync checkpoint not in index, resetting to genesis\n"); + Checkpoints::hashSyncCheckpoint = (!fTestNet ? hashGenesisBlockOfficial : hashGenesisBlockTestNet); + } // Load bnBestInvalidTrust, OK if it doesn't exist CBigNum bnBestInvalidTrust;