// Copyright (c) 2009-2012 The Bitcoin developers // Distributed under the MIT/X11 software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "checkpoints.h" #include "txdb.h" #include "main.h" #include "uint256.h" namespace Checkpoints { typedef std::map MapCheckpoints; // // What makes a good checkpoint block? // + Is surrounded by blocks with reasonable timestamps // (no blocks before with a timestamp after, none after with // timestamp before) // + Contains no strange transactions // static MapCheckpoints mapCheckpoints = { { 0, hashGenesisBlockOfficial }, { 2000, uint256("0x0000000000b5f20078bf46ebdf1500813bb6b2cb482065aa93b89e073b2c6467")}, { 2101, uint256("0xd4ea1ac45b63c8162a7fc8033cec441db8d532ba988202849d7831e32fe2d059")}, { 2847, uint256("0xb5015e2835f13fd3bb6135cff9b31ac33310c9b77d694bdb592b8680d98d018e")}, { 3589, uint256("0xb12a2ca3db4e288cada98aa2139768532bd4474c49dd7b8158031032dac08d51")}, { 3935, uint256("0xe16290c9757d1368b8d7c35de07d4f8f70c2c9f9c785b667df0c3bff85086ca6")}, { 5703, uint256("0x587db07bb2172ad7db72c5fabc2518262a1b27f503f99417510b2c6fafa6557b")}, { 9000, uint256("0x00000000019ef6b2f5e7c324c7d083ee94502305aabc7e9cd73a7fb2a57bb8db")}, { 9001, uint256("0x6d5c6c5f201cc9e59659ee0da30d1430dc6bf3b12a8ff4c3864ab8d6286b0007")}, { 9002, uint256("0xa1e20fb1d44688b763690cf74d6aefe859e4cc32981f9e3f2b2ae9702bbcf249")}, { 10881, uint256("0x4b6554c45e1e6764a6f3c309c47baf53c9edd81f624e52b072518cd15da237e6")}, { 17650, uint256("0x224940e1f986a202209b8e762728d1452ab45870c308abf84905674acf326a47")}, // Recent finality pin (PoS era). Closes the long unchecked span from // 17650 to the live tip so stale-bootstrap / low-trust forks below // this height are rejected outright. Hash from the canonical chain. { 2205000, uint256("0x6bdd3c5e5a32e1dd9a70e705f1a28d1dd84929f89579bd2696d41bc87f39446f")}, { 2206004, uint256("0xb34e8e6a7bb7f52167d81aaad4d26f87a876898fdd0fce860916fc1aaf9a2a46")}, // Continuous finality pins: every 1000 blocks from 2206500 onward so the // gap between the last hardcoded checkpoint and the live tip stays bounded. // Without these, a fresh node syncing from zero (no snapshot) has 8,400+ // unverified blocks at tip — a peer feeding fork blocks at those heights // could trick an IBD node into accepting a divergent chain. With these // pins, any divergence >1000 blocks is rejected at AcceptBlock time. // All hashes verified against the canonical chain on 2026-07-01. { 2206500, uint256("0x707ea288242227e9b36ceeeecd5a16a6c918f8b6f7e6375128cba908ebfcbf27")}, { 2207000, uint256("0x7af1cc23fdffb3a9ed2eb9aa5a8697e8af2f98c67c4f6baa9f4d7899cbfaf4ca")}, { 2210000, uint256("0xe2dc2e55c6e1b3d2ea9d8a1f2b274bf64053ddd6a61335dc6896aa9c056956be")}, { 2211000, uint256("0x61c8a179c928a1f0bbffa029b4f1aea67b04a98227a6d02e6137280404ed29dc")}, { 2212000, uint256("0xf4df2b5d0d1de326b97ed5a3eeefef307a51791e03af401373e142f00453a9a8")}, { 2213000, uint256("0x7bc9652d423676c52ba8b0a287e0b46e1eca6e8eecc51d3f30e0d665d3b236f5")}, { 2214000, uint256("0x17e61ceb45db36358aaabe91b094a77ecba32370a467185fa9af75eef6c8e414")}, { 2214400, uint256("0x8ebb818f7280850c5a3916b7c8a2bca603f7c4f9926d3cdc2262f726035d96ed")}, // Post-rebuild finality pin (v6.2.5.0). Closes the gap between // the last hardcoded checkpoint and the live tip after -rebuildutxo. // Hash from the canonical chain on DNS2 after fresh UTXO rebuild. { 2219922, uint256("0x9ed3e1d38317950927f37f2867e3fc29e239fc1f4c57b182f55c6e04b73b52ec")}, // Live-tip finality pins (v6.2.6.0). Verified against DNS3 chain state // on 2026-08-04. Closes the 4,841-block unchecked span between the // last hardcoded pin (2,219,922) and the live tip (2,224,763). // All hashes verified against the canonical chain on DNS3 (running // v6.2.3.0-geb02f34) at block 2,224,763. Verification transcript // (DNS3 getblockhash output) is archived in the v6.2.6.0 release // notes on bootstrap.cryptographic-triangles.org. // // Note: the gap from 2,219,922 to 2,222,900 is 2,978 blocks (larger than the // 1,000-block standard spacing), because block 2,220,000 etc. were // not indexed in DNS3's local block index when this release was // prepared. The 2,222,900+ pins restore the 1,000-block spacing // guarantee from that point to the live tip. { 2222900, uint256("0xe104c29d6a6ff983d9a02a9854a86c221a1f400f0116cb255cee2b8d5c7ced9f")}, { 2223000, uint256("0x41926ba6dc9147e361ffd1ffc1a0357d7d7b66550ed05864d1ae103c6332371a")}, { 2223500, uint256("0x998e65941f200359ca0c1f53ea128c27f83111e8bbb1db38b7ed2ed7a48b8e32")}, { 2223700, uint256("0x97d3a70d258c34429c15b430e654fa1270e4de635ecec3c72ace92a0d04679c3")}, { 2224000, uint256("0x4dddc0b555266a1207fef70af17db9a7b14ab5e1d7cf27882ea35cc77923841f")}, { 2224500, uint256("0xe0fea543829dd0e8c02b7c657468cff775c7993658c16c1feaf1418b4080ba27")}, { 2224700, uint256("0x2a8ea5ef954adb707286bc468fdf43d8d99d23a1d15cf4f17a35d58dd51b0944")}, { 2224750, uint256("0x0f117fe05befb6d8a93c6e45bc3b3d48889208e2785ba6a3d723c8ad7c9d649f")}, { 2224763, uint256("0x9d3575ac5428e64911e698ba0a8f773954b17b214a044d4b244fa2ec83c06674")}, // live tip }; // Published UTXO snapshot file SHA256, keyed by snapshot height. // Each entry binds height -> SHA256 of the canonical snapshot file produced by // UtxoSnapshot::DumpSnapshot at that height. Used by SnapshotNet to verify // P2P-delivered snapshots without trusting any peer. // // Maintainers: after producing a snapshot, sha256 the file and add an entry // here. The corresponding (height, blockhash) must already exist in // mapCheckpoints / mapCheckpointsTestnet. static std::map mapSnapshotHashes = { { 2206004, uint256("0x1419282dae817315ee1b955543f6248233fe5800f5e8488734a0ece5bd6781ea")}, { 2219922, uint256("0x6dd8d782a04bb8dc4ccd5e88a4bc7726fe26bdebaed96b79242de1e2949b6ee6")}, // Live-tip snapshot (v6.2.6.0). Generated from DNS3 (Samihost) at the // canonical tip 2,224,763, blockhash 9d3575ac...06674. Verified against // the canonical chain on 2026-08-04. { 2224763, uint256("0xa7ea62ad4e158faf07973e5cd1539c1895154c4e28685a3eb7af458a001037b7")}, }; static std::map mapSnapshotHashesTestnet = { }; static MapCheckpoints mapCheckpointsTestnet = { { 0, hashGenesisBlockTestNet }, { 2000, uint256("0x0000000000b5f20078bf46ebdf1500813bb6b2cb482065aa93b89e073b2c6467")}, { 2101, uint256("0xd4ea1ac45b63c8162a7fc8033cec441db8d532ba988202849d7831e32fe2d059")}, { 2847, uint256("0xb5015e2835f13fd3bb6135cff9b31ac33310c9b77d694bdb592b8680d98d018e")}, { 3589, uint256("0xb12a2ca3db4e288cada98aa2139768532bd4474c49dd7b8158031032dac08d51")}, { 3935, uint256("0xe16290c9757d1368b8d7c35de07d4f8f70c2c9f9c785b667df0c3bff85086ca6")}, { 5703, uint256("0x587db07bb2172ad7db72c5fabc2518262a1b27f503f99417510b2c6fafa6557b")}, { 9000, uint256("0x00000000019ef6b2f5e7c324c7d083ee94502305aabc7e9cd73a7fb2a57bb8db")}, { 9001, uint256("0x6d5c6c5f201cc9e59659ee0da30d1430dc6bf3b12a8ff4c3864ab8d6286b0007")}, { 9002, uint256("0xa1e20fb1d44688b763690cf74d6aefe859e4cc32981f9e3f2b2ae9702bbcf249")}, { 10881, uint256("0x4b6554c45e1e6764a6f3c309c47baf53c9edd81f624e52b072518cd15da237e6")}, { 17650, uint256("0x224940e1f986a202209b8e762728d1452ab45870c308abf84905674acf326a47")}, }; bool CheckHardened(int nHeight, const uint256& hash) { MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints); MapCheckpoints::const_iterator i = checkpoints.find(nHeight); if (i == checkpoints.end()) return true; return hash == i->second; } bool IsKnownCheckpoint(int nHeight, const uint256& hash) { MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints); MapCheckpoints::const_iterator i = checkpoints.find(nHeight); if (i == checkpoints.end()) return false; return hash == i->second; } int GetTotalBlocksEstimate() { MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints); return checkpoints.rbegin()->first; } int GetBestSnapshotHeight() { std::map& snaps = (fTestNet ? mapSnapshotHashesTestnet : mapSnapshotHashes); if (snaps.empty()) return 0; return snaps.rbegin()->first; } bool GetSnapshotHash(int nHeight, uint256& fileHashOut) { std::map& snaps = (fTestNet ? mapSnapshotHashesTestnet : mapSnapshotHashes); auto it = snaps.find(nHeight); if (it == snaps.end()) return false; fileHashOut = it->second; return true; } CBlockIndex* GetLastCheckpoint(const std::map& mapBlockIndex) { MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints); for (auto it = checkpoints.rbegin(); it != checkpoints.rend(); ++it) { const uint256& hash = it->second; std::map::const_iterator t = mapBlockIndex.find(hash); if (t != mapBlockIndex.end()) return t->second; } return nullptr; } // Independent of mapBlockIndex: returns the highest compiled checkpoint // height for the current network. Returns -1 if the compiled map is // empty (an unusual, but not impossible, configuration). Used as the // fail-closed reorg floor before pindexLastHardenedCheckpoint has been // resolved against the local block index (early IBD / reindex / // bootstrap before the checkpoint block has been downloaded). int GetLastCheckpointHeight() { MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints); if (checkpoints.empty()) return -1; return checkpoints.rbegin()->first; } // triangles: synchronized checkpoint (centrally broadcasted) uint256 hashSyncCheckpoint = uint256("0x7e7a6e4dd5fe895106fca912dfbacaeaf2a89e76c6a588df8ff96e0e18b96021"); uint256 hashPendingCheckpoint = uint256("0x7e7a6e4dd5fe895106fca912dfbacaeaf2a89e76c6a588df8ff96e0e18b96021"); CSyncCheckpoint checkpointMessage; CSyncCheckpoint checkpointMessagePending; uint256 hashInvalidCheckpoint = 0; CCriticalSection cs_hashSyncCheckpoint; // triangles: get last synchronized checkpoint CBlockIndex* GetLastSyncCheckpoint() { LOCK(cs_hashSyncCheckpoint); if (!mapBlockIndex.count(hashSyncCheckpoint)) error("GetSyncCheckpoint: block index missing for current sync-checkpoint %s", hashSyncCheckpoint.ToString().c_str()); else return mapBlockIndex[hashSyncCheckpoint]; return nullptr; } // triangles: only descendant of current sync-checkpoint is allowed bool ValidateSyncCheckpoint(uint256 hashCheckpoint) { if (!mapBlockIndex.count(hashSyncCheckpoint)) return error("ValidateSyncCheckpoint: block index missing for current sync-checkpoint %s", hashSyncCheckpoint.ToString().c_str()); if (!mapBlockIndex.count(hashCheckpoint)) return error("ValidateSyncCheckpoint: block index missing for received sync-checkpoint %s", hashCheckpoint.ToString().c_str()); CBlockIndex* pindexSyncCheckpoint = mapBlockIndex[hashSyncCheckpoint]; CBlockIndex* pindexCheckpointRecv = mapBlockIndex[hashCheckpoint]; if (pindexCheckpointRecv->nHeight <= pindexSyncCheckpoint->nHeight) { // Received an older checkpoint, trace back from current checkpoint // to the same height of the received checkpoint to verify // that current checkpoint should be a descendant block CBlockIndex* pindex = pindexSyncCheckpoint; while (pindex->nHeight > pindexCheckpointRecv->nHeight) if (!(pindex = pindex->pprev)) return error("ValidateSyncCheckpoint: pprev null - block index structure failure"); if (pindex->GetBlockHash() != hashCheckpoint) { hashInvalidCheckpoint = hashCheckpoint; return error("ValidateSyncCheckpoint: new sync-checkpoint %s is conflicting with current sync-checkpoint %s", hashCheckpoint.ToString().c_str(), hashSyncCheckpoint.ToString().c_str()); } return false; // ignore older checkpoint } // Received checkpoint should be a descendant block of the current // checkpoint. Trace back to the same height of current checkpoint // to verify. CBlockIndex* pindex = pindexCheckpointRecv; while (pindex->nHeight > pindexSyncCheckpoint->nHeight) if (!(pindex = pindex->pprev)) return error("ValidateSyncCheckpoint: pprev2 null - block index structure failure"); if (pindex->GetBlockHash() != hashSyncCheckpoint) { hashInvalidCheckpoint = hashCheckpoint; return error("ValidateSyncCheckpoint: new sync-checkpoint %s is not a descendant of current sync-checkpoint %s", hashCheckpoint.ToString().c_str(), hashSyncCheckpoint.ToString().c_str()); } return true; } bool WriteSyncCheckpoint(const uint256& hashCheckpoint) { auto txdb_holder = MakeChainDB(); CTxDBBase& txdb = *txdb_holder; txdb.TxnBegin(); if (!txdb.WriteSyncCheckpoint(hashCheckpoint)) { txdb.TxnAbort(); return error("WriteSyncCheckpoint(): failed to write to db sync checkpoint %s", hashCheckpoint.ToString().c_str()); } if (!txdb.TxnCommit()) return error("WriteSyncCheckpoint(): failed to commit to db sync checkpoint %s", hashCheckpoint.ToString().c_str()); Checkpoints::hashSyncCheckpoint = hashCheckpoint; return true; } bool AcceptPendingSyncCheckpoint() { LOCK(cs_hashSyncCheckpoint); if (hashPendingCheckpoint != 0 && mapBlockIndex.count(hashPendingCheckpoint)) { if (!ValidateSyncCheckpoint(hashPendingCheckpoint)) { hashPendingCheckpoint = 0; checkpointMessagePending.SetNull(); return false; } auto txdb_holder = MakeChainDB(); CTxDBBase& txdb = *txdb_holder; CBlockIndex* pindexCheckpoint = mapBlockIndex[hashPendingCheckpoint]; if (!pindexCheckpoint->IsInMainChain()) { CBlock block; if (!block.ReadFromDisk(pindexCheckpoint)) return error("AcceptPendingSyncCheckpoint: ReadFromDisk failed for sync checkpoint %s", hashPendingCheckpoint.ToString().c_str()); if (!block.SetBestChain(txdb, pindexCheckpoint)) { hashInvalidCheckpoint = hashPendingCheckpoint; return error("AcceptPendingSyncCheckpoint: SetBestChain failed for sync checkpoint %s", hashPendingCheckpoint.ToString().c_str()); } } if (!WriteSyncCheckpoint(hashPendingCheckpoint)) return error("AcceptPendingSyncCheckpoint(): failed to write sync checkpoint %s", hashPendingCheckpoint.ToString().c_str()); hashPendingCheckpoint = 0; checkpointMessage = checkpointMessagePending; checkpointMessagePending.SetNull(); printf("AcceptPendingSyncCheckpoint : sync-checkpoint at %s\n", hashSyncCheckpoint.ToString().c_str()); // relay the checkpoint if (!checkpointMessage.IsNull()) { for (CNode* pnode : vNodes) checkpointMessage.RelayTo(pnode); } return true; } return false; } // Automatically select a suitable sync-checkpoint uint256 AutoSelectSyncCheckpoint() { const CBlockIndex *pindex = pindexBest; // Search backward for a block within max span and maturity window while (pindex->pprev && (pindex->GetBlockTime() + CHECKPOINT_MAX_SPAN > pindexBest->GetBlockTime() || pindex->nHeight + 8 > pindexBest->nHeight)) pindex = pindex->pprev; return pindex->GetBlockHash(); } // 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) { return true; } bool WantedByPendingSyncCheckpoint(uint256 hashBlock) { LOCK(cs_hashSyncCheckpoint); if (hashPendingCheckpoint == 0) return false; if (hashBlock == hashPendingCheckpoint) return true; if (mapOrphanBlocks.count(hashPendingCheckpoint) && hashBlock == WantedByOrphan(mapOrphanBlocks[hashPendingCheckpoint].get())) return true; return false; } // triangles: reset synchronized checkpoint to last hardened checkpoint bool ResetSyncCheckpoint() { LOCK(cs_hashSyncCheckpoint); const uint256& hash = mapCheckpoints.rbegin()->second; if (mapBlockIndex.count(hash) && !mapBlockIndex[hash]->IsInMainChain()) { // checkpoint block accepted but not yet in main chain printf("ResetSyncCheckpoint: SetBestChain to hardened checkpoint %s\n", hash.ToString().c_str()); auto txdb_holder = MakeChainDB(); CTxDBBase& txdb = *txdb_holder; CBlock block; if (!block.ReadFromDisk(mapBlockIndex[hash])) return error("ResetSyncCheckpoint: ReadFromDisk failed for hardened checkpoint %s", hash.ToString().c_str()); if (!block.SetBestChain(txdb, mapBlockIndex[hash])) { return error("ResetSyncCheckpoint: SetBestChain failed for hardened checkpoint %s", hash.ToString().c_str()); } } else if(!mapBlockIndex.count(hash)) { // checkpoint block not yet accepted hashPendingCheckpoint = hash; checkpointMessagePending.SetNull(); printf("ResetSyncCheckpoint: pending for sync-checkpoint %s\n", hashPendingCheckpoint.ToString().c_str()); } for (auto it = mapCheckpoints.rbegin(); it != mapCheckpoints.rend(); ++it) { const uint256& hash = it->second; if (mapBlockIndex.count(hash) && mapBlockIndex[hash]->IsInMainChain()) { if (!WriteSyncCheckpoint(hash)) return error("ResetSyncCheckpoint: failed to write sync checkpoint %s", hash.ToString().c_str()); printf("ResetSyncCheckpoint: sync-checkpoint reset to %s\n", hashSyncCheckpoint.ToString().c_str()); return true; } } return false; } void AskForPendingSyncCheckpoint(CNode* pfrom) { LOCK(cs_hashSyncCheckpoint); if (pfrom && hashPendingCheckpoint != 0 && (!mapBlockIndex.count(hashPendingCheckpoint)) && (!mapOrphanBlocks.count(hashPendingCheckpoint))) pfrom->AskFor(CInv(MSG_BLOCK, hashPendingCheckpoint)); } bool SetCheckpointPrivKey(std::string strPrivKey) { (void)strPrivKey; return error("SetCheckpointPrivKey: synchronized checkpoints are disabled"); } bool SendSyncCheckpoint(uint256 hashCheckpoint) { (void)hashCheckpoint; return error("SendSyncCheckpoint: synchronized checkpoints are disabled"); } // Is the sync-checkpoint outside maturity window? bool IsMatureSyncCheckpoint() { LOCK(cs_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()); } } // triangles: sync-checkpoint master key (DISABLED for decentralization - v5 hard fork) const std::string CSyncCheckpoint::strMasterPubKey = ""; std::string CSyncCheckpoint::strMasterPrivKey = ""; // triangles: verify signature of sync-checkpoint message // The master-key system is disabled. Reject these legacy messages instead of // treating unsigned data as authenticated if a dispatcher is added later. bool CSyncCheckpoint::CheckSignature() { return error("CSyncCheckpoint::CheckSignature: synchronized checkpoints are disabled"); } // triangles: process synchronized checkpoint bool CSyncCheckpoint::ProcessSyncCheckpoint(CNode* pfrom) { if (!CheckSignature()) return false; LOCK(Checkpoints::cs_hashSyncCheckpoint); if (!mapBlockIndex.count(hashCheckpoint)) { // We haven't received the checkpoint chain, keep the checkpoint as pending Checkpoints::hashPendingCheckpoint = hashCheckpoint; Checkpoints::checkpointMessagePending = *this; printf("ProcessSyncCheckpoint: pending for sync-checkpoint %s\n", hashCheckpoint.ToString().c_str()); // Ask this guy to fill in what we're missing if (pfrom) { pfrom->PushGetBlocks(pindexBest, hashCheckpoint); // ask directly as well in case rejected earlier by duplicate // proof-of-stake because getblocks may not get it this time pfrom->AskFor(CInv(MSG_BLOCK, mapOrphanBlocks.count(hashCheckpoint)? WantedByOrphan(mapOrphanBlocks[hashCheckpoint].get()) : hashCheckpoint)); } return false; } if (!Checkpoints::ValidateSyncCheckpoint(hashCheckpoint)) return false; auto txdb_holder = MakeChainDB(); CTxDBBase& txdb = *txdb_holder; CBlockIndex* pindexCheckpoint = mapBlockIndex[hashCheckpoint]; if (!pindexCheckpoint->IsInMainChain()) { // checkpoint chain received but not yet main chain CBlock block; if (!block.ReadFromDisk(pindexCheckpoint)) return error("ProcessSyncCheckpoint: ReadFromDisk failed for sync checkpoint %s", hashCheckpoint.ToString().c_str()); if (!block.SetBestChain(txdb, pindexCheckpoint)) { Checkpoints::hashInvalidCheckpoint = hashCheckpoint; return error("ProcessSyncCheckpoint: SetBestChain failed for sync checkpoint %s", hashCheckpoint.ToString().c_str()); } } if (!Checkpoints::WriteSyncCheckpoint(hashCheckpoint)) return error("ProcessSyncCheckpoint(): failed to write sync checkpoint %s", hashCheckpoint.ToString().c_str()); Checkpoints::checkpointMessage = *this; Checkpoints::hashPendingCheckpoint = 0; Checkpoints::checkpointMessagePending.SetNull(); printf("ProcessSyncCheckpoint: sync-checkpoint at %s\n", hashCheckpoint.ToString().c_str()); return true; }