Add recent finality checkpoint at 2205000 (anti-fork); bump v5.9.12

Closes the unchecked span from block 17650 to the live tip. Nodes now
reject stale-bootstrap / low-trust forks below 2205000. Hash taken from
the canonical chain (PC wallet, verified via getblockhash).
This commit is contained in:
Sami Ahmed
2026-06-13 22:04:34 +00:00
parent 43eaa96bc9
commit 6defb54300
2 changed files with 464 additions and 466 deletions
+445 -447
View File
@@ -1,447 +1,445 @@
// Copyright (c) 2009-2012 The Bitcoin developers // Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying // Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php. // file COPYING or http://www.opensource.org/licenses/mit-license.php.
#include "checkpoints.h" #include "checkpoints.h"
#include "txdb.h" #include "txdb.h"
#include "main.h" #include "main.h"
#include "uint256.h" #include "uint256.h"
namespace Checkpoints namespace Checkpoints
{ {
typedef std::map<int, uint256> MapCheckpoints; typedef std::map<int, uint256> MapCheckpoints;
// //
// What makes a good checkpoint block? // What makes a good checkpoint block?
// + Is surrounded by blocks with reasonable timestamps // + Is surrounded by blocks with reasonable timestamps
// (no blocks before with a timestamp after, none after with // (no blocks before with a timestamp after, none after with
// timestamp before) // timestamp before)
// + Contains no strange transactions // + Contains no strange transactions
// //
static MapCheckpoints mapCheckpoints = { static MapCheckpoints mapCheckpoints = {
{ 0, hashGenesisBlockOfficial }, { 0, hashGenesisBlockOfficial },
{ 2000, uint256("0x0000000000b5f20078bf46ebdf1500813bb6b2cb482065aa93b89e073b2c6467")}, { 2000, uint256("0x0000000000b5f20078bf46ebdf1500813bb6b2cb482065aa93b89e073b2c6467")},
{ 2101, uint256("0xd4ea1ac45b63c8162a7fc8033cec441db8d532ba988202849d7831e32fe2d059")}, { 2101, uint256("0xd4ea1ac45b63c8162a7fc8033cec441db8d532ba988202849d7831e32fe2d059")},
{ 2847, uint256("0xb5015e2835f13fd3bb6135cff9b31ac33310c9b77d694bdb592b8680d98d018e")}, { 2847, uint256("0xb5015e2835f13fd3bb6135cff9b31ac33310c9b77d694bdb592b8680d98d018e")},
{ 3589, uint256("0xb12a2ca3db4e288cada98aa2139768532bd4474c49dd7b8158031032dac08d51")}, { 3589, uint256("0xb12a2ca3db4e288cada98aa2139768532bd4474c49dd7b8158031032dac08d51")},
{ 3935, uint256("0xe16290c9757d1368b8d7c35de07d4f8f70c2c9f9c785b667df0c3bff85086ca6")}, { 3935, uint256("0xe16290c9757d1368b8d7c35de07d4f8f70c2c9f9c785b667df0c3bff85086ca6")},
{ 5703, uint256("0x587db07bb2172ad7db72c5fabc2518262a1b27f503f99417510b2c6fafa6557b")}, { 5703, uint256("0x587db07bb2172ad7db72c5fabc2518262a1b27f503f99417510b2c6fafa6557b")},
{ 9000, uint256("0x00000000019ef6b2f5e7c324c7d083ee94502305aabc7e9cd73a7fb2a57bb8db")}, { 9000, uint256("0x00000000019ef6b2f5e7c324c7d083ee94502305aabc7e9cd73a7fb2a57bb8db")},
{ 9001, uint256("0x6d5c6c5f201cc9e59659ee0da30d1430dc6bf3b12a8ff4c3864ab8d6286b0007")}, { 9001, uint256("0x6d5c6c5f201cc9e59659ee0da30d1430dc6bf3b12a8ff4c3864ab8d6286b0007")},
{ 9002, uint256("0xa1e20fb1d44688b763690cf74d6aefe859e4cc32981f9e3f2b2ae9702bbcf249")}, { 9002, uint256("0xa1e20fb1d44688b763690cf74d6aefe859e4cc32981f9e3f2b2ae9702bbcf249")},
{ 10881, uint256("0x4b6554c45e1e6764a6f3c309c47baf53c9edd81f624e52b072518cd15da237e6")}, { 10881, uint256("0x4b6554c45e1e6764a6f3c309c47baf53c9edd81f624e52b072518cd15da237e6")},
{ 17650, uint256("0x224940e1f986a202209b8e762728d1452ab45870c308abf84905674acf326a47")}, { 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
// Published UTXO snapshot file SHA256, keyed by snapshot height. // height are rejected outright. Hash taken from the canonical chain.
// Each entry binds height -> SHA256 of the canonical snapshot file produced by { 2205000, uint256("0x6bdd3c5e5a32e1dd9a70e705f1a28d1dd84929f89579bd2696d41bc87f39446f")},
// UtxoSnapshot::DumpSnapshot at that height. Used by SnapshotNet to verify };
// P2P-delivered snapshots without trusting any peer.
// // Published UTXO snapshot file SHA256, keyed by snapshot height.
// Maintainers: after producing a snapshot, sha256 the file and add an entry // Each entry binds height -> SHA256 of the canonical snapshot file produced by
// here. The corresponding (height, blockhash) must already exist in // UtxoSnapshot::DumpSnapshot at that height. Used by SnapshotNet to verify
// mapCheckpoints / mapCheckpointsTestnet. // P2P-delivered snapshots without trusting any peer.
static std::map<int, uint256> mapSnapshotHashes = { //
}; // Maintainers: after producing a snapshot, sha256 the file and add an entry
// here. The corresponding (height, blockhash) must already exist in
static std::map<int, uint256> mapSnapshotHashesTestnet = { // mapCheckpoints / mapCheckpointsTestnet.
}; static std::map<int, uint256> mapSnapshotHashes = {
};
static MapCheckpoints mapCheckpointsTestnet = {
{ 0, hashGenesisBlockTestNet }, static std::map<int, uint256> mapSnapshotHashesTestnet = {
{ 2000, uint256("0x0000000000b5f20078bf46ebdf1500813bb6b2cb482065aa93b89e073b2c6467")}, };
{ 2101, uint256("0xd4ea1ac45b63c8162a7fc8033cec441db8d532ba988202849d7831e32fe2d059")},
{ 2847, uint256("0xb5015e2835f13fd3bb6135cff9b31ac33310c9b77d694bdb592b8680d98d018e")}, static MapCheckpoints mapCheckpointsTestnet = {
{ 3589, uint256("0xb12a2ca3db4e288cada98aa2139768532bd4474c49dd7b8158031032dac08d51")}, { 0, hashGenesisBlockTestNet },
{ 3935, uint256("0xe16290c9757d1368b8d7c35de07d4f8f70c2c9f9c785b667df0c3bff85086ca6")}, { 2000, uint256("0x0000000000b5f20078bf46ebdf1500813bb6b2cb482065aa93b89e073b2c6467")},
{ 5703, uint256("0x587db07bb2172ad7db72c5fabc2518262a1b27f503f99417510b2c6fafa6557b")}, { 2101, uint256("0xd4ea1ac45b63c8162a7fc8033cec441db8d532ba988202849d7831e32fe2d059")},
{ 9000, uint256("0x00000000019ef6b2f5e7c324c7d083ee94502305aabc7e9cd73a7fb2a57bb8db")}, { 2847, uint256("0xb5015e2835f13fd3bb6135cff9b31ac33310c9b77d694bdb592b8680d98d018e")},
{ 9001, uint256("0x6d5c6c5f201cc9e59659ee0da30d1430dc6bf3b12a8ff4c3864ab8d6286b0007")}, { 3589, uint256("0xb12a2ca3db4e288cada98aa2139768532bd4474c49dd7b8158031032dac08d51")},
{ 9002, uint256("0xa1e20fb1d44688b763690cf74d6aefe859e4cc32981f9e3f2b2ae9702bbcf249")}, { 3935, uint256("0xe16290c9757d1368b8d7c35de07d4f8f70c2c9f9c785b667df0c3bff85086ca6")},
{ 10881, uint256("0x4b6554c45e1e6764a6f3c309c47baf53c9edd81f624e52b072518cd15da237e6")}, { 5703, uint256("0x587db07bb2172ad7db72c5fabc2518262a1b27f503f99417510b2c6fafa6557b")},
{ 17650, uint256("0x224940e1f986a202209b8e762728d1452ab45870c308abf84905674acf326a47")}, { 9000, uint256("0x00000000019ef6b2f5e7c324c7d083ee94502305aabc7e9cd73a7fb2a57bb8db")},
}; { 9001, uint256("0x6d5c6c5f201cc9e59659ee0da30d1430dc6bf3b12a8ff4c3864ab8d6286b0007")},
{ 9002, uint256("0xa1e20fb1d44688b763690cf74d6aefe859e4cc32981f9e3f2b2ae9702bbcf249")},
bool CheckHardened(int nHeight, const uint256& hash) { 10881, uint256("0x4b6554c45e1e6764a6f3c309c47baf53c9edd81f624e52b072518cd15da237e6")},
{ { 17650, uint256("0x224940e1f986a202209b8e762728d1452ab45870c308abf84905674acf326a47")},
MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints); };
MapCheckpoints::const_iterator i = checkpoints.find(nHeight); bool CheckHardened(int nHeight, const uint256& hash)
if (i == checkpoints.end()) return true; {
return hash == i->second; MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);
}
MapCheckpoints::const_iterator i = checkpoints.find(nHeight);
bool IsKnownCheckpoint(int nHeight, const uint256& hash) if (i == checkpoints.end()) return true;
{ return hash == i->second;
MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints); }
MapCheckpoints::const_iterator i = checkpoints.find(nHeight);
if (i == checkpoints.end()) return false; bool IsKnownCheckpoint(int nHeight, const uint256& hash)
return hash == i->second; {
} MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);
MapCheckpoints::const_iterator i = checkpoints.find(nHeight);
int GetTotalBlocksEstimate() if (i == checkpoints.end()) return false;
{ return hash == i->second;
MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints); }
return checkpoints.rbegin()->first; int GetTotalBlocksEstimate()
} {
MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);
int GetBestSnapshotHeight()
{ return checkpoints.rbegin()->first;
std::map<int, uint256>& snaps = (fTestNet ? mapSnapshotHashesTestnet : mapSnapshotHashes); }
if (snaps.empty()) return 0;
return snaps.rbegin()->first; int GetBestSnapshotHeight()
} {
std::map<int, uint256>& snaps = (fTestNet ? mapSnapshotHashesTestnet : mapSnapshotHashes);
bool GetSnapshotHash(int nHeight, uint256& fileHashOut) if (snaps.empty()) return 0;
{ return snaps.rbegin()->first;
std::map<int, uint256>& snaps = (fTestNet ? mapSnapshotHashesTestnet : mapSnapshotHashes); }
auto it = snaps.find(nHeight);
if (it == snaps.end()) return false; bool GetSnapshotHash(int nHeight, uint256& fileHashOut)
fileHashOut = it->second; {
return true; std::map<int, uint256>& snaps = (fTestNet ? mapSnapshotHashesTestnet : mapSnapshotHashes);
} auto it = snaps.find(nHeight);
if (it == snaps.end()) return false;
CBlockIndex* GetLastCheckpoint(const std::map<uint256, CBlockIndex*>& mapBlockIndex) fileHashOut = it->second;
{ return true;
MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints); }
for (auto it = checkpoints.rbegin(); it != checkpoints.rend(); ++it) CBlockIndex* GetLastCheckpoint(const std::map<uint256, CBlockIndex*>& mapBlockIndex)
{ {
const uint256& hash = it->second; MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);
std::map<uint256, CBlockIndex*>::const_iterator t = mapBlockIndex.find(hash);
if (t != mapBlockIndex.end()) for (auto it = checkpoints.rbegin(); it != checkpoints.rend(); ++it)
return t->second; {
} const uint256& hash = it->second;
return nullptr; std::map<uint256, CBlockIndex*>::const_iterator t = mapBlockIndex.find(hash);
} if (t != mapBlockIndex.end())
return t->second;
// triangles: synchronized checkpoint (centrally broadcasted) }
uint256 hashSyncCheckpoint = uint256("0x7e7a6e4dd5fe895106fca912dfbacaeaf2a89e76c6a588df8ff96e0e18b96021"); return nullptr;
uint256 hashPendingCheckpoint = uint256("0x7e7a6e4dd5fe895106fca912dfbacaeaf2a89e76c6a588df8ff96e0e18b96021"); }
CSyncCheckpoint checkpointMessage;
CSyncCheckpoint checkpointMessagePending; // triangles: synchronized checkpoint (centrally broadcasted)
uint256 hashInvalidCheckpoint = 0; uint256 hashSyncCheckpoint = uint256("0x7e7a6e4dd5fe895106fca912dfbacaeaf2a89e76c6a588df8ff96e0e18b96021");
CCriticalSection cs_hashSyncCheckpoint; uint256 hashPendingCheckpoint = uint256("0x7e7a6e4dd5fe895106fca912dfbacaeaf2a89e76c6a588df8ff96e0e18b96021");
CSyncCheckpoint checkpointMessage;
// triangles: get last synchronized checkpoint CSyncCheckpoint checkpointMessagePending;
CBlockIndex* GetLastSyncCheckpoint() uint256 hashInvalidCheckpoint = 0;
{ CCriticalSection cs_hashSyncCheckpoint;
LOCK(cs_hashSyncCheckpoint);
if (!mapBlockIndex.count(hashSyncCheckpoint)) // triangles: get last synchronized checkpoint
error("GetSyncCheckpoint: block index missing for current sync-checkpoint %s", hashSyncCheckpoint.ToString().c_str()); CBlockIndex* GetLastSyncCheckpoint()
else {
return mapBlockIndex[hashSyncCheckpoint]; LOCK(cs_hashSyncCheckpoint);
return nullptr; if (!mapBlockIndex.count(hashSyncCheckpoint))
} error("GetSyncCheckpoint: block index missing for current sync-checkpoint %s", hashSyncCheckpoint.ToString().c_str());
else
// triangles: only descendant of current sync-checkpoint is allowed return mapBlockIndex[hashSyncCheckpoint];
bool ValidateSyncCheckpoint(uint256 hashCheckpoint) return nullptr;
{ }
if (!mapBlockIndex.count(hashSyncCheckpoint))
return error("ValidateSyncCheckpoint: block index missing for current sync-checkpoint %s", hashSyncCheckpoint.ToString().c_str()); // triangles: only descendant of current sync-checkpoint is allowed
if (!mapBlockIndex.count(hashCheckpoint)) bool ValidateSyncCheckpoint(uint256 hashCheckpoint)
return error("ValidateSyncCheckpoint: block index missing for received sync-checkpoint %s", hashCheckpoint.ToString().c_str()); {
if (!mapBlockIndex.count(hashSyncCheckpoint))
CBlockIndex* pindexSyncCheckpoint = mapBlockIndex[hashSyncCheckpoint]; return error("ValidateSyncCheckpoint: block index missing for current sync-checkpoint %s", hashSyncCheckpoint.ToString().c_str());
CBlockIndex* pindexCheckpointRecv = mapBlockIndex[hashCheckpoint]; if (!mapBlockIndex.count(hashCheckpoint))
return error("ValidateSyncCheckpoint: block index missing for received sync-checkpoint %s", hashCheckpoint.ToString().c_str());
if (pindexCheckpointRecv->nHeight <= pindexSyncCheckpoint->nHeight)
{ CBlockIndex* pindexSyncCheckpoint = mapBlockIndex[hashSyncCheckpoint];
// Received an older checkpoint, trace back from current checkpoint CBlockIndex* pindexCheckpointRecv = mapBlockIndex[hashCheckpoint];
// to the same height of the received checkpoint to verify
// that current checkpoint should be a descendant block if (pindexCheckpointRecv->nHeight <= pindexSyncCheckpoint->nHeight)
CBlockIndex* pindex = pindexSyncCheckpoint; {
while (pindex->nHeight > pindexCheckpointRecv->nHeight) // Received an older checkpoint, trace back from current checkpoint
if (!(pindex = pindex->pprev)) // to the same height of the received checkpoint to verify
return error("ValidateSyncCheckpoint: pprev null - block index structure failure"); // that current checkpoint should be a descendant block
if (pindex->GetBlockHash() != hashCheckpoint) CBlockIndex* pindex = pindexSyncCheckpoint;
{ while (pindex->nHeight > pindexCheckpointRecv->nHeight)
hashInvalidCheckpoint = hashCheckpoint; if (!(pindex = pindex->pprev))
return error("ValidateSyncCheckpoint: new sync-checkpoint %s is conflicting with current sync-checkpoint %s", hashCheckpoint.ToString().c_str(), hashSyncCheckpoint.ToString().c_str()); return error("ValidateSyncCheckpoint: pprev null - block index structure failure");
} if (pindex->GetBlockHash() != hashCheckpoint)
return false; // ignore older checkpoint {
} hashInvalidCheckpoint = hashCheckpoint;
return error("ValidateSyncCheckpoint: new sync-checkpoint %s is conflicting with current sync-checkpoint %s", hashCheckpoint.ToString().c_str(), hashSyncCheckpoint.ToString().c_str());
// Received checkpoint should be a descendant block of the current }
// checkpoint. Trace back to the same height of current checkpoint return false; // ignore older checkpoint
// to verify. }
CBlockIndex* pindex = pindexCheckpointRecv;
while (pindex->nHeight > pindexSyncCheckpoint->nHeight) // Received checkpoint should be a descendant block of the current
if (!(pindex = pindex->pprev)) // checkpoint. Trace back to the same height of current checkpoint
return error("ValidateSyncCheckpoint: pprev2 null - block index structure failure"); // to verify.
if (pindex->GetBlockHash() != hashSyncCheckpoint) CBlockIndex* pindex = pindexCheckpointRecv;
{ while (pindex->nHeight > pindexSyncCheckpoint->nHeight)
hashInvalidCheckpoint = hashCheckpoint; if (!(pindex = pindex->pprev))
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 error("ValidateSyncCheckpoint: pprev2 null - block index structure failure");
} if (pindex->GetBlockHash() != hashSyncCheckpoint)
return true; {
} 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());
bool WriteSyncCheckpoint(const uint256& hashCheckpoint) }
{ return true;
auto txdb_holder = MakeChainDB(); CTxDBBase& txdb = *txdb_holder; }
txdb.TxnBegin();
if (!txdb.WriteSyncCheckpoint(hashCheckpoint)) bool WriteSyncCheckpoint(const uint256& hashCheckpoint)
{ {
txdb.TxnAbort(); auto txdb_holder = MakeChainDB(); CTxDBBase& txdb = *txdb_holder;
return error("WriteSyncCheckpoint(): failed to write to db sync checkpoint %s", hashCheckpoint.ToString().c_str()); txdb.TxnBegin();
} if (!txdb.WriteSyncCheckpoint(hashCheckpoint))
if (!txdb.TxnCommit()) {
return error("WriteSyncCheckpoint(): failed to commit to db sync checkpoint %s", hashCheckpoint.ToString().c_str()); txdb.TxnAbort();
return error("WriteSyncCheckpoint(): failed to write to db sync checkpoint %s", hashCheckpoint.ToString().c_str());
Checkpoints::hashSyncCheckpoint = hashCheckpoint; }
return true; if (!txdb.TxnCommit())
} return error("WriteSyncCheckpoint(): failed to commit to db sync checkpoint %s", hashCheckpoint.ToString().c_str());
bool AcceptPendingSyncCheckpoint() Checkpoints::hashSyncCheckpoint = hashCheckpoint;
{ return true;
LOCK(cs_hashSyncCheckpoint); }
if (hashPendingCheckpoint != 0 && mapBlockIndex.count(hashPendingCheckpoint))
{ bool AcceptPendingSyncCheckpoint()
if (!ValidateSyncCheckpoint(hashPendingCheckpoint)) {
{ LOCK(cs_hashSyncCheckpoint);
hashPendingCheckpoint = 0; if (hashPendingCheckpoint != 0 && mapBlockIndex.count(hashPendingCheckpoint))
checkpointMessagePending.SetNull(); {
return false; if (!ValidateSyncCheckpoint(hashPendingCheckpoint))
} {
hashPendingCheckpoint = 0;
auto txdb_holder = MakeChainDB(); CTxDBBase& txdb = *txdb_holder; checkpointMessagePending.SetNull();
CBlockIndex* pindexCheckpoint = mapBlockIndex[hashPendingCheckpoint]; return false;
if (!pindexCheckpoint->IsInMainChain()) }
{
CBlock block; auto txdb_holder = MakeChainDB(); CTxDBBase& txdb = *txdb_holder;
if (!block.ReadFromDisk(pindexCheckpoint)) CBlockIndex* pindexCheckpoint = mapBlockIndex[hashPendingCheckpoint];
return error("AcceptPendingSyncCheckpoint: ReadFromDisk failed for sync checkpoint %s", hashPendingCheckpoint.ToString().c_str()); if (!pindexCheckpoint->IsInMainChain())
if (!block.SetBestChain(txdb, pindexCheckpoint)) {
{ CBlock block;
hashInvalidCheckpoint = hashPendingCheckpoint; if (!block.ReadFromDisk(pindexCheckpoint))
return error("AcceptPendingSyncCheckpoint: SetBestChain failed for sync checkpoint %s", hashPendingCheckpoint.ToString().c_str()); return error("AcceptPendingSyncCheckpoint: ReadFromDisk failed for sync checkpoint %s", hashPendingCheckpoint.ToString().c_str());
} if (!block.SetBestChain(txdb, pindexCheckpoint))
} {
hashInvalidCheckpoint = hashPendingCheckpoint;
if (!WriteSyncCheckpoint(hashPendingCheckpoint)) return error("AcceptPendingSyncCheckpoint: SetBestChain failed for sync checkpoint %s", hashPendingCheckpoint.ToString().c_str());
return error("AcceptPendingSyncCheckpoint(): failed to write sync checkpoint %s", hashPendingCheckpoint.ToString().c_str()); }
hashPendingCheckpoint = 0; }
checkpointMessage = checkpointMessagePending;
checkpointMessagePending.SetNull(); if (!WriteSyncCheckpoint(hashPendingCheckpoint))
printf("AcceptPendingSyncCheckpoint : sync-checkpoint at %s\n", hashSyncCheckpoint.ToString().c_str()); return error("AcceptPendingSyncCheckpoint(): failed to write sync checkpoint %s", hashPendingCheckpoint.ToString().c_str());
// relay the checkpoint hashPendingCheckpoint = 0;
if (!checkpointMessage.IsNull()) checkpointMessage = checkpointMessagePending;
{ checkpointMessagePending.SetNull();
for (CNode* pnode : vNodes) printf("AcceptPendingSyncCheckpoint : sync-checkpoint at %s\n", hashSyncCheckpoint.ToString().c_str());
checkpointMessage.RelayTo(pnode); // relay the checkpoint
} if (!checkpointMessage.IsNull())
return true; {
} for (CNode* pnode : vNodes)
return false; checkpointMessage.RelayTo(pnode);
} }
return true;
// Automatically select a suitable sync-checkpoint }
uint256 AutoSelectSyncCheckpoint() return false;
{ }
const CBlockIndex *pindex = pindexBest;
// Search backward for a block within max span and maturity window // Automatically select a suitable sync-checkpoint
while (pindex->pprev && (pindex->GetBlockTime() + CHECKPOINT_MAX_SPAN > pindexBest->GetBlockTime() || pindex->nHeight + 8 > pindexBest->nHeight)) uint256 AutoSelectSyncCheckpoint()
pindex = pindex->pprev; {
return pindex->GetBlockHash(); 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))
// Check against synchronized checkpoint pindex = pindex->pprev;
// Disabled: master key removed in V5, no new sync checkpoints possible. return pindex->GetBlockHash();
// Always returns true to prevent stale DB-persisted checkpoints from blocking IBD. }
bool CheckSync(const uint256& hashBlock, const CBlockIndex* pindexPrev)
{ // Check against synchronized checkpoint
return true; // 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)
bool WantedByPendingSyncCheckpoint(uint256 hashBlock) {
{ return true;
LOCK(cs_hashSyncCheckpoint); }
if (hashPendingCheckpoint == 0)
return false; bool WantedByPendingSyncCheckpoint(uint256 hashBlock)
if (hashBlock == hashPendingCheckpoint) {
return true; LOCK(cs_hashSyncCheckpoint);
if (mapOrphanBlocks.count(hashPendingCheckpoint) if (hashPendingCheckpoint == 0)
&& hashBlock == WantedByOrphan(mapOrphanBlocks[hashPendingCheckpoint].get())) return false;
return true; if (hashBlock == hashPendingCheckpoint)
return false; return true;
} if (mapOrphanBlocks.count(hashPendingCheckpoint)
&& hashBlock == WantedByOrphan(mapOrphanBlocks[hashPendingCheckpoint].get()))
// triangles: reset synchronized checkpoint to last hardened checkpoint return true;
bool ResetSyncCheckpoint() return false;
{ }
LOCK(cs_hashSyncCheckpoint);
const uint256& hash = mapCheckpoints.rbegin()->second; // triangles: reset synchronized checkpoint to last hardened checkpoint
if (mapBlockIndex.count(hash) && !mapBlockIndex[hash]->IsInMainChain()) bool ResetSyncCheckpoint()
{ {
// checkpoint block accepted but not yet in main chain LOCK(cs_hashSyncCheckpoint);
printf("ResetSyncCheckpoint: SetBestChain to hardened checkpoint %s\n", hash.ToString().c_str()); const uint256& hash = mapCheckpoints.rbegin()->second;
auto txdb_holder = MakeChainDB(); CTxDBBase& txdb = *txdb_holder; if (mapBlockIndex.count(hash) && !mapBlockIndex[hash]->IsInMainChain())
CBlock block; {
if (!block.ReadFromDisk(mapBlockIndex[hash])) // checkpoint block accepted but not yet in main chain
return error("ResetSyncCheckpoint: ReadFromDisk failed for hardened checkpoint %s", hash.ToString().c_str()); printf("ResetSyncCheckpoint: SetBestChain to hardened checkpoint %s\n", hash.ToString().c_str());
if (!block.SetBestChain(txdb, mapBlockIndex[hash])) auto txdb_holder = MakeChainDB(); CTxDBBase& txdb = *txdb_holder;
{ CBlock block;
return error("ResetSyncCheckpoint: SetBestChain failed for hardened checkpoint %s", hash.ToString().c_str()); if (!block.ReadFromDisk(mapBlockIndex[hash]))
} return error("ResetSyncCheckpoint: ReadFromDisk failed for hardened checkpoint %s", hash.ToString().c_str());
} if (!block.SetBestChain(txdb, mapBlockIndex[hash]))
else if(!mapBlockIndex.count(hash)) {
{ return error("ResetSyncCheckpoint: SetBestChain failed for hardened checkpoint %s", hash.ToString().c_str());
// checkpoint block not yet accepted }
hashPendingCheckpoint = hash; }
checkpointMessagePending.SetNull(); else if(!mapBlockIndex.count(hash))
printf("ResetSyncCheckpoint: pending for sync-checkpoint %s\n", hashPendingCheckpoint.ToString().c_str()); {
} // checkpoint block not yet accepted
hashPendingCheckpoint = hash;
for (auto it = mapCheckpoints.rbegin(); it != mapCheckpoints.rend(); ++it) checkpointMessagePending.SetNull();
{ printf("ResetSyncCheckpoint: pending for sync-checkpoint %s\n", hashPendingCheckpoint.ToString().c_str());
const uint256& hash = it->second; }
if (mapBlockIndex.count(hash) && mapBlockIndex[hash]->IsInMainChain())
{ for (auto it = mapCheckpoints.rbegin(); it != mapCheckpoints.rend(); ++it)
if (!WriteSyncCheckpoint(hash)) {
return error("ResetSyncCheckpoint: failed to write sync checkpoint %s", hash.ToString().c_str()); const uint256& hash = it->second;
printf("ResetSyncCheckpoint: sync-checkpoint reset to %s\n", hashSyncCheckpoint.ToString().c_str()); if (mapBlockIndex.count(hash) && mapBlockIndex[hash]->IsInMainChain())
return true; {
} 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 false; return true;
} }
}
void AskForPendingSyncCheckpoint(CNode* pfrom)
{ return false;
LOCK(cs_hashSyncCheckpoint); }
if (pfrom && hashPendingCheckpoint != 0 && (!mapBlockIndex.count(hashPendingCheckpoint)) && (!mapOrphanBlocks.count(hashPendingCheckpoint)))
pfrom->AskFor(CInv(MSG_BLOCK, hashPendingCheckpoint)); void AskForPendingSyncCheckpoint(CNode* pfrom)
} {
LOCK(cs_hashSyncCheckpoint);
bool SetCheckpointPrivKey(std::string strPrivKey) if (pfrom && hashPendingCheckpoint != 0 && (!mapBlockIndex.count(hashPendingCheckpoint)) && (!mapOrphanBlocks.count(hashPendingCheckpoint)))
{ pfrom->AskFor(CInv(MSG_BLOCK, hashPendingCheckpoint));
// Test signing a sync-checkpoint with genesis block }
CSyncCheckpoint checkpoint;
checkpoint.hashCheckpoint = !fTestNet ? hashGenesisBlockOfficial : hashGenesisBlockTestNet; bool SetCheckpointPrivKey(std::string strPrivKey)
CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION); {
sMsg << (CUnsignedSyncCheckpoint)checkpoint; // Test signing a sync-checkpoint with genesis block
checkpoint.vchMsg = std::vector<unsigned char>(sMsg.begin(), sMsg.end()); CSyncCheckpoint checkpoint;
checkpoint.hashCheckpoint = !fTestNet ? hashGenesisBlockOfficial : hashGenesisBlockTestNet;
std::vector<unsigned char> vchPrivKey = ParseHex(strPrivKey); CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION);
CKey key; sMsg << (CUnsignedSyncCheckpoint)checkpoint;
key.SetPrivKey(CPrivKey(vchPrivKey.begin(), vchPrivKey.end())); // if key is not correct openssl may crash checkpoint.vchMsg = std::vector<unsigned char>(sMsg.begin(), sMsg.end());
if (!key.Sign(Hash(checkpoint.vchMsg.begin(), checkpoint.vchMsg.end()), checkpoint.vchSig))
return false; std::vector<unsigned char> vchPrivKey = ParseHex(strPrivKey);
CKey key;
// Test signing successful, proceed key.SetPrivKey(CPrivKey(vchPrivKey.begin(), vchPrivKey.end())); // if key is not correct openssl may crash
CSyncCheckpoint::strMasterPrivKey = strPrivKey; if (!key.Sign(Hash(checkpoint.vchMsg.begin(), checkpoint.vchMsg.end()), checkpoint.vchSig))
return true; return false;
}
// Test signing successful, proceed
bool SendSyncCheckpoint(uint256 hashCheckpoint) CSyncCheckpoint::strMasterPrivKey = strPrivKey;
{ return true;
CSyncCheckpoint checkpoint; }
checkpoint.hashCheckpoint = hashCheckpoint;
CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION); bool SendSyncCheckpoint(uint256 hashCheckpoint)
sMsg << (CUnsignedSyncCheckpoint)checkpoint; {
checkpoint.vchMsg = std::vector<unsigned char>(sMsg.begin(), sMsg.end()); CSyncCheckpoint checkpoint;
checkpoint.hashCheckpoint = hashCheckpoint;
if (CSyncCheckpoint::strMasterPrivKey.empty()) CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION);
return error("SendSyncCheckpoint: Checkpoint master key unavailable."); sMsg << (CUnsignedSyncCheckpoint)checkpoint;
std::vector<unsigned char> vchPrivKey = ParseHex(CSyncCheckpoint::strMasterPrivKey); checkpoint.vchMsg = std::vector<unsigned char>(sMsg.begin(), sMsg.end());
CKey key;
key.SetPrivKey(CPrivKey(vchPrivKey.begin(), vchPrivKey.end())); // if key is not correct openssl may crash if (CSyncCheckpoint::strMasterPrivKey.empty())
if (!key.Sign(Hash(checkpoint.vchMsg.begin(), checkpoint.vchMsg.end()), checkpoint.vchSig)) return error("SendSyncCheckpoint: Checkpoint master key unavailable.");
return error("SendSyncCheckpoint: Unable to sign checkpoint, check private key?"); std::vector<unsigned char> vchPrivKey = ParseHex(CSyncCheckpoint::strMasterPrivKey);
CKey key;
if(!checkpoint.ProcessSyncCheckpoint(nullptr)) key.SetPrivKey(CPrivKey(vchPrivKey.begin(), vchPrivKey.end())); // if key is not correct openssl may crash
{ if (!key.Sign(Hash(checkpoint.vchMsg.begin(), checkpoint.vchMsg.end()), checkpoint.vchSig))
printf("WARNING: SendSyncCheckpoint: Failed to process checkpoint.\n"); return error("SendSyncCheckpoint: Unable to sign checkpoint, check private key?");
return false;
} if(!checkpoint.ProcessSyncCheckpoint(nullptr))
{
// Relay checkpoint printf("WARNING: SendSyncCheckpoint: Failed to process checkpoint.\n");
{ return false;
LOCK(cs_vNodes); }
for (CNode* pnode : vNodes)
checkpoint.RelayTo(pnode); // Relay checkpoint
} {
return true; LOCK(cs_vNodes);
} for (CNode* pnode : vNodes)
checkpoint.RelayTo(pnode);
// Is the sync-checkpoint outside maturity window? }
bool IsMatureSyncCheckpoint() return true;
{ }
LOCK(cs_hashSyncCheckpoint);
if (!mapBlockIndex.count(hashSyncCheckpoint)) // Is the sync-checkpoint outside maturity window?
return true; // no valid sync checkpoint, treat as mature bool IsMatureSyncCheckpoint()
const CBlockIndex* pindexSync = mapBlockIndex[hashSyncCheckpoint]; {
return (nBestHeight >= pindexSync->nHeight + nCoinbaseMaturity || LOCK(cs_hashSyncCheckpoint);
pindexSync->GetBlockTime() + nStakeMinAge < GetAdjustedTime()); if (!mapBlockIndex.count(hashSyncCheckpoint))
} return true; // no valid sync checkpoint, treat as mature
} const CBlockIndex* pindexSync = mapBlockIndex[hashSyncCheckpoint];
return (nBestHeight >= pindexSync->nHeight + nCoinbaseMaturity ||
// triangles: sync-checkpoint master key (DISABLED for decentralization - v5 hard fork) pindexSync->GetBlockTime() + nStakeMinAge < GetAdjustedTime());
const std::string CSyncCheckpoint::strMasterPubKey = ""; }
}
std::string CSyncCheckpoint::strMasterPrivKey = "";
// triangles: sync-checkpoint master key (DISABLED for decentralization - v5 hard fork)
// triangles: verify signature of sync-checkpoint message const std::string CSyncCheckpoint::strMasterPubKey = "";
// Master key system disabled - checkpoint signatures are no longer required
bool CSyncCheckpoint::CheckSignature() std::string CSyncCheckpoint::strMasterPrivKey = "";
{
// Deserialize the checkpoint data without signature verification // triangles: verify signature of sync-checkpoint message
CDataStream sMsg(vchMsg, SER_NETWORK, PROTOCOL_VERSION); // Master key system disabled - checkpoint signatures are no longer required
sMsg >> *(CUnsignedSyncCheckpoint*)this; bool CSyncCheckpoint::CheckSignature()
return true; {
} // Deserialize the checkpoint data without signature verification
CDataStream sMsg(vchMsg, SER_NETWORK, PROTOCOL_VERSION);
// triangles: process synchronized checkpoint sMsg >> *(CUnsignedSyncCheckpoint*)this;
bool CSyncCheckpoint::ProcessSyncCheckpoint(CNode* pfrom) return true;
{ }
if (!CheckSignature())
return false; // triangles: process synchronized checkpoint
bool CSyncCheckpoint::ProcessSyncCheckpoint(CNode* pfrom)
LOCK(Checkpoints::cs_hashSyncCheckpoint); {
if (!mapBlockIndex.count(hashCheckpoint)) if (!CheckSignature())
{ return false;
// We haven't received the checkpoint chain, keep the checkpoint as pending
Checkpoints::hashPendingCheckpoint = hashCheckpoint; LOCK(Checkpoints::cs_hashSyncCheckpoint);
Checkpoints::checkpointMessagePending = *this; if (!mapBlockIndex.count(hashCheckpoint))
printf("ProcessSyncCheckpoint: pending for sync-checkpoint %s\n", hashCheckpoint.ToString().c_str()); {
// Ask this guy to fill in what we're missing // We haven't received the checkpoint chain, keep the checkpoint as pending
if (pfrom) Checkpoints::hashPendingCheckpoint = hashCheckpoint;
{ Checkpoints::checkpointMessagePending = *this;
pfrom->PushGetBlocks(pindexBest, hashCheckpoint); printf("ProcessSyncCheckpoint: pending for sync-checkpoint %s\n", hashCheckpoint.ToString().c_str());
// ask directly as well in case rejected earlier by duplicate // Ask this guy to fill in what we're missing
// proof-of-stake because getblocks may not get it this time if (pfrom)
pfrom->AskFor(CInv(MSG_BLOCK, mapOrphanBlocks.count(hashCheckpoint)? WantedByOrphan(mapOrphanBlocks[hashCheckpoint].get()) : hashCheckpoint)); {
} pfrom->PushGetBlocks(pindexBest, hashCheckpoint);
return false; // 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));
if (!Checkpoints::ValidateSyncCheckpoint(hashCheckpoint)) }
return false; return false;
}
auto txdb_holder = MakeChainDB(); CTxDBBase& txdb = *txdb_holder;
CBlockIndex* pindexCheckpoint = mapBlockIndex[hashCheckpoint]; if (!Checkpoints::ValidateSyncCheckpoint(hashCheckpoint))
if (!pindexCheckpoint->IsInMainChain()) return false;
{
// checkpoint chain received but not yet main chain auto txdb_holder = MakeChainDB(); CTxDBBase& txdb = *txdb_holder;
CBlock block; CBlockIndex* pindexCheckpoint = mapBlockIndex[hashCheckpoint];
if (!block.ReadFromDisk(pindexCheckpoint)) if (!pindexCheckpoint->IsInMainChain())
return error("ProcessSyncCheckpoint: ReadFromDisk failed for sync checkpoint %s", hashCheckpoint.ToString().c_str()); {
if (!block.SetBestChain(txdb, pindexCheckpoint)) // checkpoint chain received but not yet main chain
{ CBlock block;
Checkpoints::hashInvalidCheckpoint = hashCheckpoint; if (!block.ReadFromDisk(pindexCheckpoint))
return error("ProcessSyncCheckpoint: SetBestChain failed for sync checkpoint %s", hashCheckpoint.ToString().c_str()); return error("ProcessSyncCheckpoint: ReadFromDisk failed for sync checkpoint %s", hashCheckpoint.ToString().c_str());
} if (!block.SetBestChain(txdb, pindexCheckpoint))
} {
Checkpoints::hashInvalidCheckpoint = hashCheckpoint;
if (!Checkpoints::WriteSyncCheckpoint(hashCheckpoint)) return error("ProcessSyncCheckpoint: SetBestChain failed for sync checkpoint %s", hashCheckpoint.ToString().c_str());
return error("ProcessSyncCheckpoint(): failed to write sync checkpoint %s", hashCheckpoint.ToString().c_str()); }
Checkpoints::checkpointMessage = *this; }
Checkpoints::hashPendingCheckpoint = 0;
Checkpoints::checkpointMessagePending.SetNull(); if (!Checkpoints::WriteSyncCheckpoint(hashCheckpoint))
printf("ProcessSyncCheckpoint: sync-checkpoint at %s\n", hashCheckpoint.ToString().c_str()); return error("ProcessSyncCheckpoint(
return true;
}
+19 -19
View File
@@ -1,19 +1,19 @@
#ifndef CLIENTVERSION_H #ifndef CLIENTVERSION_H
#define CLIENTVERSION_H #define CLIENTVERSION_H
// //
// client versioning // client versioning
// //
// These need to be macros, as version.cpp's and triangles-qt.rc's voodoo requires it // These need to be macros, as version.cpp's and triangles-qt.rc's voodoo requires it
#define CLIENT_VERSION_MAJOR 5 #define CLIENT_VERSION_MAJOR 5
#define CLIENT_VERSION_MINOR 9 #define CLIENT_VERSION_MINOR 9
#define CLIENT_VERSION_REVISION 11 #define CLIENT_VERSION_REVISION 12
#define CLIENT_VERSION_BUILD 0 #define CLIENT_VERSION_BUILD 0
// Converts the parameter X to a string after macro replacement on X has been performed. // Converts the parameter X to a string after macro replacement on X has been performed.
// Don't merge these into one macro! // Don't merge these into one macro!
#define STRINGIZE(X) DO_STRINGIZE(X) #define STRINGIZE(X) DO_STRINGIZE(X)
#define DO_STRINGIZE(X) #X #define DO_STRINGIZE(X) #X
#endif // CLIENTVERSION_H #endif // CLIENTVERSION_H