From 6e9cff06ce6843257536b07da5be6d1ca22c7c8f Mon Sep 17 00:00:00 2001 From: Peter Bushnell Date: Fri, 30 Nov 2018 17:45:59 +0000 Subject: [PATCH] Automatic Checkpointing update --- src/checkpoints.cpp | 32 ------- src/checkpoints.h | 9 -- src/checkpointsync.cpp | 203 ++++++++++++++++++++++------------------- src/checkpointsync.h | 12 +-- src/net_processing.cpp | 5 +- src/validation.cpp | 20 ++-- src/validation.h | 1 + 7 files changed, 124 insertions(+), 158 deletions(-) diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp index 419b06fb5..9189c9a8a 100644 --- a/src/checkpoints.cpp +++ b/src/checkpoints.cpp @@ -28,36 +28,4 @@ namespace Checkpoints { return nullptr; } - int GetTotalBlocksEstimate(const CCheckpointData& data) - { - const MapCheckpoints& checkpoints = data.mapCheckpoints; - - if (checkpoints.empty()) - return 0; - - return checkpoints.rbegin()->first; - } - - uint256 GetLastAvailableCheckpoint(const CCheckpointData& data) - { - const MapCheckpoints& checkpoints = data.mapCheckpoints; - - for (const MapCheckpoints::value_type& i : reverse_iterate(checkpoints)) - { - const uint256& hash = i.second; - if (mapBlockIndex.count(hash) && chainActive.Contains(mapBlockIndex[hash])) - return hash; - } - return(Params().GetConsensus().hashGenesisBlock); - } - - uint256 GetLatestHardenedCheckpoint(const CCheckpointData& data) - { - const MapCheckpoints& checkpoints = data.mapCheckpoints; - - if (checkpoints.empty()) - return Params().GetConsensus().hashGenesisBlock; - - return (checkpoints.rbegin()->second); - } } // namespace Checkpoints diff --git a/src/checkpoints.h b/src/checkpoints.h index 4bf972885..bf935f80a 100644 --- a/src/checkpoints.h +++ b/src/checkpoints.h @@ -22,15 +22,6 @@ namespace Checkpoints //! Returns last CBlockIndex* in mapBlockIndex that is a checkpoint CBlockIndex* GetLastCheckpoint(const CCheckpointData& data); -//! Return conservative estimate of total number of blocks, 0 if unknown -int GetTotalBlocksEstimate(const CCheckpointData& data); - -//! Returns the last available checkpoint in the main chain -uint256 GetLastAvailableCheckpoint(const CCheckpointData& data); - -//! Returns the block hash of latest hardened checkpoint, if empty genesis block returned -uint256 GetLatestHardenedCheckpoint(const CCheckpointData& data); - } //namespace Checkpoints #endif // BITCOIN_CHECKPOINTS_H diff --git a/src/checkpointsync.cpp b/src/checkpointsync.cpp index 8ab387c24..883c4d3ac 100644 --- a/src/checkpointsync.cpp +++ b/src/checkpointsync.cpp @@ -46,6 +46,7 @@ // mode is also the default mode (default value -1 for checkpointdepth). // +#include #include #include @@ -75,9 +76,9 @@ string strCheckpointWarning; bool ValidateSyncCheckpoint(uint256 hashCheckpoint) { if (!mapBlockIndex.count(hashSyncCheckpoint)) - return error("ValidateSyncCheckpoint: block index missing for current sync-checkpoint %s", hashSyncCheckpoint.ToString().c_str()); + return error("%s: block index missing for current sync-checkpoint %s", __func__, hashSyncCheckpoint.ToString()); if (!mapBlockIndex.count(hashCheckpoint)) - return error("ValidateSyncCheckpoint: block index missing for received sync-checkpoint %s", hashCheckpoint.ToString().c_str()); + return error("%s: block index missing for received sync-checkpoint %s", __func__, hashCheckpoint.ToString()); CBlockIndex* pindexSyncCheckpoint = mapBlockIndex[hashSyncCheckpoint]; CBlockIndex* pindexCheckpointRecv = mapBlockIndex[hashCheckpoint]; @@ -87,15 +88,10 @@ bool ValidateSyncCheckpoint(uint256 hashCheckpoint) // 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: pprev1 null - block index structure failure"); - - if (pindex->GetBlockHash() != hashCheckpoint) + if (!chainActive.Contains(pindexCheckpointRecv)) { 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 error("%s: new sync-checkpoint %s is conflicting with current sync-checkpoint %s", __func__, hashCheckpoint.ToString(), hashSyncCheckpoint.ToString()); } return false; // ignore older checkpoint } @@ -104,26 +100,24 @@ bool ValidateSyncCheckpoint(uint256 hashCheckpoint) // 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) + while (pindex->nHeight > pindexSyncCheckpoint->nHeight) + if (!(pindex = pindex->pprev)) + return error("%s: pprev2 null - block index structure failure", __func__); + + 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 error("%s: new sync-checkpoint %s is not a descendant of current sync-checkpoint %s", __func__, hashCheckpoint.ToString(), hashSyncCheckpoint.ToString()); + } return true; } bool WriteSyncCheckpoint(const uint256& hashCheckpoint) { if (!pblocktree->WriteSyncCheckpoint(hashCheckpoint)) - return error("WriteSyncCheckpoint(): failed to write to txdb sync checkpoint %s", hashCheckpoint.ToString().c_str()); - - if (!pblocktree->Sync()) - return error("WriteSyncCheckpoint(): failed to commit to txdb sync checkpoint %s", hashCheckpoint.ToString().c_str()); + return error("%s: failed to write to txdb sync checkpoint %s", __func__, hashCheckpoint.ToString()); + FlushStateToDisk(); hashSyncCheckpoint = hashCheckpoint; return true; } @@ -131,33 +125,36 @@ bool WriteSyncCheckpoint(const uint256& hashCheckpoint) bool AcceptPendingSyncCheckpoint() { LOCK(cs_hashSyncCheckpoint); - if (hashPendingCheckpoint != ArithToUint256(arith_uint256(0)) && mapBlockIndex.count(hashPendingCheckpoint)) + bool havePendingCheckpoint = hashPendingCheckpoint != ArithToUint256(arith_uint256(0)) && mapBlockIndex.count(hashPendingCheckpoint); + if (!havePendingCheckpoint) + return false; + + if (!ValidateSyncCheckpoint(hashPendingCheckpoint)) { - if (!ValidateSyncCheckpoint(hashPendingCheckpoint)) - { - hashPendingCheckpoint = ArithToUint256(arith_uint256(0)); - checkpointMessagePending.SetNull(); - return false; - } - - if (!WriteSyncCheckpoint(hashPendingCheckpoint)) - return error("AcceptPendingSyncCheckpoint(): failed to write sync checkpoint %s", hashPendingCheckpoint.ToString().c_str()); - - hashPendingCheckpoint = ArithToUint256(arith_uint256(0)); - checkpointMessage = checkpointMessagePending; + hashPendingCheckpoint = ArithToUint256(arith_uint256(0)); checkpointMessagePending.SetNull(); + return false; + } - // Relay the checkpoint - if (!checkpointMessage.IsNull()) - { - g_connman->ForEachNode([](CNode* pnode) { - checkpointMessage.RelayTo(pnode); - }); - } + if (!chainActive.Contains(mapBlockIndex[hashPendingCheckpoint])) + return false; - return true; + if (!WriteSyncCheckpoint(hashPendingCheckpoint)) + return error("%s: failed to write sync checkpoint %s", __func__, hashPendingCheckpoint.ToString()); + + hashPendingCheckpoint = ArithToUint256(arith_uint256(0)); + checkpointMessage = checkpointMessagePending; + checkpointMessagePending.SetNull(); + + // Relay the checkpoint + if (g_connman && !checkpointMessage.IsNull()) + { + g_connman->ForEachNode([](CNode* pnode) { + checkpointMessage.RelayTo(pnode); + }); } - return false; + + return true; } // Automatically select a suitable sync-checkpoint @@ -165,85 +162,80 @@ uint256 AutoSelectSyncCheckpoint() { // Search backward for a block with specified depth policy const CBlockIndex *pindex = chainActive.Tip(); - while (pindex->pprev && pindex->nHeight + (int)gArgs.GetArg("-checkpointdepth", -1) > chainActive.Tip()->nHeight) + while (pindex->pprev && pindex->nHeight + (int)gArgs.GetArg("-checkpointdepth", DEFAULT_AUTOCHECKPOINT) > chainActive.Tip()->nHeight) pindex = pindex->pprev; return pindex->GetBlockHash(); } // Check against synchronized checkpoint -bool CheckSyncCheckpoint(const uint256& hashBlock, const CBlockIndex* pindexPrev) +bool CheckSyncCheckpoint(const CBlockIndex* pindexNew) { - int nHeight = pindexPrev->nHeight + 1; - LOCK(cs_hashSyncCheckpoint); + assert(pindexNew != NULL); + if (pindexNew->nHeight == 0) + return true; + const uint256& hashBlock = pindexNew->GetBlockHash(); + int nHeight = pindexNew->nHeight; + // Reset checkpoint to Genesis block if not found or initialised if (hashSyncCheckpoint == ArithToUint256(arith_uint256(0)) || !(mapBlockIndex.count(hashSyncCheckpoint))) { - LogPrintf("%s: hashSyncCheckpoint not initialised, setting to genesis block: %s\n",__func__, Params().GetConsensus().hashGenesisBlock.ToString().c_str()); WriteSyncCheckpoint(Params().GetConsensus().hashGenesisBlock); return true; } const CBlockIndex* pindexSync = mapBlockIndex[hashSyncCheckpoint]; + // Blocks could have been rewound on startup, do not + // return or false here or block could be marked invalid + if (!chainActive.Contains(pindexSync)) + return true; + if (nHeight > pindexSync->nHeight) { // Trace back to same height as sync-checkpoint - const CBlockIndex* pindex = pindexPrev; - while (pindex->nHeight > pindexSync->nHeight) + const CBlockIndex* pindex = pindexNew; + while (pindex->nHeight > pindexSync->nHeight && !chainActive.Contains(pindex)) if (!(pindex = pindex->pprev)) - return error("CheckSyncCheckpoint: pprev null - block index structure failure"); - if (pindex->nHeight < pindexSync->nHeight || pindex->GetBlockHash() != hashSyncCheckpoint) - return false; // Only descendant of sync-checkpoint can pass check + return error("%s: pprev null - block index structure failure", __func__); + + // At this point we could have: + // 1. Found block in our blockchain + // 2. Reached pindexSync->nHeight without finding it + if (!chainActive.Contains(pindex)) + return error("%s: Only descendants of checkpoint accepted", __func__); } if (nHeight == pindexSync->nHeight && hashBlock != hashSyncCheckpoint) - return false; // Same height with sync-checkpoint + return error("%s: Same height with sync-checkpoint", __func__); if (nHeight < pindexSync->nHeight && !mapBlockIndex.count(hashBlock)) - return false; // Lower height than sync-checkpoint + return error("%s: Lower height than sync-checkpoint", __func__); return true; } -// Reset synchronized checkpoint to last hardened checkpoint +// Reset synchronized checkpoint to the assume valid block bool ResetSyncCheckpoint() { LOCK(cs_hashSyncCheckpoint); - // Hash of latest checkpoint - uint256 checkpointHash = Checkpoints::GetLatestHardenedCheckpoint(Params().Checkpoints()); - - // Checkpoint block not yet accepted - if (mapBlockIndex.count(checkpointHash)) { - checkpointMessagePending.SetNull(); - hashPendingCheckpoint = checkpointHash; - } - - if (!WriteSyncCheckpoint((mapBlockIndex.count(checkpointHash) && chainActive.Contains(mapBlockIndex[checkpointHash]))? checkpointHash : Params().GetConsensus().hashGenesisBlock)) - return error("ResetSyncCheckpoint: failed to write sync checkpoint %s", checkpointHash.ToString().c_str()); + if (!WriteSyncCheckpoint(Params().GetConsensus().defaultAssumeValid)) + return error("%s: failed to write sync checkpoint %s", __func__, Params().GetConsensus().defaultAssumeValid.ToString()); return true; } -void AskForPendingSyncCheckpoint(CNode* pfrom) -{ - LOCK(cs_hashSyncCheckpoint); - if (pfrom && hashPendingCheckpoint != ArithToUint256(arith_uint256(0)) && !mapBlockIndex.count(hashPendingCheckpoint)) - pfrom->AskFor(CInv(MSG_BLOCK, hashPendingCheckpoint)); -} - // Verify sync checkpoint master pubkey and reset sync checkpoint if changed bool CheckCheckpointPubKey() { string strPubKey = ""; string strMasterPubKey = Params().GetConsensus().checkpointPubKey; - + if (!pblocktree->ReadCheckpointPubKey(strPubKey) || strPubKey != strMasterPubKey) { // write checkpoint master key to db - if (!pblocktree->WriteCheckpointPubKey(strMasterPubKey)) - return error("CheckCheckpointPubKey() : failed to write new checkpoint master key to db"); - if (!pblocktree->Sync()) - return error("CheckCheckpointPubKey() : failed to commit new checkpoint master key to db"); if (!ResetSyncCheckpoint()) - return error("CheckCheckpointPubKey() : failed to reset sync-checkpoint"); + return error("%s: failed to reset sync-checkpoint", __func__); + if (!pblocktree->WriteCheckpointPubKey(strMasterPubKey)) + return error("%s: failed to write new checkpoint master key to db", __func__); + FlushStateToDisk(); } return true; @@ -253,11 +245,11 @@ bool SetCheckpointPrivKey(string strPrivKey) { CBitcoinSecret vchSecret; if (!vchSecret.SetString(strPrivKey)) - return error("SendSyncCheckpoint: Checkpoint master key invalid"); + return error("%s: Checkpoint master key invalid", __func__); CKey key = vchSecret.GetKey(); if (!key.IsValid()) - return error("SendSyncCheckpoint: Checkpoint master key invalid"); + return error("%s: Checkpoint master key invalid", __func__); CSyncCheckpoint::strMasterPrivKey = strPrivKey; return true; @@ -265,6 +257,18 @@ bool SetCheckpointPrivKey(string strPrivKey) bool SendSyncCheckpoint(uint256 hashCheckpoint) { + // P2P disabled + if (!g_connman) + return true; + + // No connections + if (g_connman->GetNodeCount(CConnman::CONNECTIONS_ALL) == 0) + return true; + + // Do not send dummy checkpoint + if (hashCheckpoint == uint256()) + return true; + CSyncCheckpoint checkpoint; checkpoint.hashCheckpoint = hashCheckpoint; CDataStream sMsg(SER_NETWORK, PROTOCOL_VERSION); @@ -272,7 +276,7 @@ bool SendSyncCheckpoint(uint256 hashCheckpoint) checkpoint.vchMsg = vector(sMsg.begin(), sMsg.end()); if (CSyncCheckpoint::strMasterPrivKey.empty()) - return error("SendSyncCheckpoint: Checkpoint master key unavailable."); + return error("%s: Checkpoint master key unavailable.", __func__); CBitcoinSecret vchSecret; if (!vchSecret.SetString(CSyncCheckpoint::strMasterPrivKey)) @@ -280,10 +284,10 @@ bool SendSyncCheckpoint(uint256 hashCheckpoint) CKey key = vchSecret.GetKey(); if (!key.Sign(Hash(checkpoint.vchMsg.begin(), checkpoint.vchMsg.end()), checkpoint.vchSig)) - return error("SendSyncCheckpoint: Unable to sign checkpoint, check private key?"); + return error("%s: Unable to sign checkpoint, check private key?", __func__); - if(!checkpoint.ProcessSyncCheckpoint(NULL)) - return error("WARNING: SendSyncCheckpoint: Failed to process checkpoint.\n"); + if(!checkpoint.ProcessSyncCheckpoint()) + return error("%s: Failed to process checkpoint.", __func__); // Relay checkpoint g_connman->ForEachNode([checkpoint](CNode* pnode) { @@ -299,7 +303,7 @@ bool CSyncCheckpoint::CheckSignature() string strMasterPubKey = Params().GetConsensus().checkpointPubKey; CPubKey key(ParseHex(strMasterPubKey)); if (!key.Verify(Hash(vchMsg.begin(), vchMsg.end()), vchSig)) - return error("CSyncCheckpoint::CheckSignature() : verify signature failed"); + return error("%s: verify signature failed", __func__); // Now unserialize the data CDataStream sMsg(vchMsg, SER_NETWORK, PROTOCOL_VERSION); @@ -308,32 +312,39 @@ bool CSyncCheckpoint::CheckSignature() } // Process synchronized checkpoint -bool CSyncCheckpoint::ProcessSyncCheckpoint(CNode* pfrom) +bool CSyncCheckpoint::ProcessSyncCheckpoint() { if (!CheckSignature()) return false; - LOCK(cs_hashSyncCheckpoint); + LOCK(cs_hashSyncCheckpoint); if (!mapBlockIndex.count(hashCheckpoint)) { - // We haven't received the checkpoint chain, keep the checkpoint as pending - hashPendingCheckpoint = hashCheckpoint; - checkpointMessagePending = *this; - + LogPrintf("%s: Missing headers for received sync-checkpoint %s\n", __func__, hashCheckpoint.ToString()); return false; } if (!ValidateSyncCheckpoint(hashCheckpoint)) return false; - if (!WriteSyncCheckpoint(hashCheckpoint)) - return error("ProcessSyncCheckpoint(): failed to write sync checkpoint %s", hashCheckpoint.ToString().c_str()); + bool pass = chainActive.Contains(mapBlockIndex[hashCheckpoint]); + + if (!pass) + { + // We haven't received the checkpoint chain, keep the checkpoint as pending + hashPendingCheckpoint = hashCheckpoint; + checkpointMessagePending = *this; + LogPrintf("%s: pending for sync-checkpoint %s\n", __func__, hashCheckpoint.ToString()); + + return false; + } + + if (!WriteSyncCheckpoint(hashCheckpoint)) + return error("%s: failed to write sync checkpoint %s\n", __func__, hashCheckpoint.ToString()); checkpointMessage = *this; hashPendingCheckpoint = ArithToUint256(arith_uint256(0)); checkpointMessagePending.SetNull(); - LogPrintf("ProcessSyncCheckpoint: sync-checkpoint at %s\n", hashCheckpoint.ToString().c_str()); - return true; } diff --git a/src/checkpointsync.h b/src/checkpointsync.h index 86dd742c2..c9374545a 100644 --- a/src/checkpointsync.h +++ b/src/checkpointsync.h @@ -27,9 +27,8 @@ extern std::string strCheckpointWarning; bool WriteSyncCheckpoint(const uint256& hashCheckpoint); bool AcceptPendingSyncCheckpoint(); uint256 AutoSelectSyncCheckpoint(); -bool CheckSyncCheckpoint(const uint256& hashBlock, const CBlockIndex* pindexPrev); +bool CheckSyncCheckpoint(const CBlockIndex* pindexNew); bool ResetSyncCheckpoint(); -void AskForPendingSyncCheckpoint(CNode* pfrom); bool CheckCheckpointPubKey(); bool SetCheckpointPrivKey(std::string strPrivKey); bool SendSyncCheckpoint(uint256 hashCheckpoint); @@ -112,21 +111,18 @@ class CSyncCheckpoint : public CUnsignedSyncCheckpoint bool RelayTo(CNode* pfrom) const { - const CNetMsgMaker msgMaker(pfrom->GetSendVersion()); - // returns true if wasn't already sent - if (pfrom->hashCheckpointKnown != hashCheckpoint) + if (g_connman && pfrom->hashCheckpointKnown != hashCheckpoint) { - CConnman& connman = *g_connman; pfrom->hashCheckpointKnown = hashCheckpoint; - connman.PushMessage(pfrom, msgMaker.Make(NetMsgType::CHECKPOINT, *this)); + g_connman->PushMessage(pfrom, CNetMsgMaker(pfrom->GetSendVersion()).Make(NetMsgType::CHECKPOINT, *this)); return true; } return false; } bool CheckSignature(); - bool ProcessSyncCheckpoint(CNode* pfrom); + bool ProcessSyncCheckpoint(); }; #endif diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 424c69ba1..8e5ff426b 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -1718,9 +1718,6 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr pfrom->nTimeOffset = nTimeOffset; AddTimeData(pfrom->addr, nTimeOffset); - if (!IsInitialBlockDownload()) - AskForPendingSyncCheckpoint(pfrom); - // Feeler connections exist only to verify if address is online. if (pfrom->fFeeler) { assert(pfrom->fInbound == false); @@ -2793,7 +2790,7 @@ bool static ProcessMessage(CNode* pfrom, const std::string& strCommand, CDataStr CSyncCheckpoint checkpoint; vRecv >> checkpoint; - if (checkpoint.ProcessSyncCheckpoint(pfrom)) + if (checkpoint.ProcessSyncCheckpoint()) { LogPrintf("%s: hashCheckpoint=%s\n", __func__, checkpoint.hashCheckpoint.ToString().c_str()); diff --git a/src/validation.cpp b/src/validation.cpp index b5467fcb8..afd76d712 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -2211,8 +2211,6 @@ void static UpdateTip(const CBlockIndex *pindexNew, const CChainParams& chainPar LogPrintf(" warning='%s'", boost::algorithm::join(warningMessages, ", ")); LogPrintf("\n"); - if (pindexBestHeader->pprev) - CheckSyncCheckpoint(pindexBestHeader->GetBlockHash(), pindexBestHeader->pprev); } /** Disconnect chainActive's tip. @@ -3181,11 +3179,6 @@ static bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationSta return state.Invalid(false, REJECT_OBSOLETE, strprintf("bad-version(0x%08x)", block.nVersion), strprintf("rejected nVersion=0x%08x block", block.nVersion)); - // Check that the block satisfies synchronized checkpoint - if (!IsInitialBlockDownload() && !CheckSyncCheckpoint(block.GetHash(), pindexPrev)) - return state.Invalid(error("%s : rejected by synchronized checkpoint", __func__), - REJECT_OBSOLETE, "bad-version"); - return true; } @@ -3452,6 +3445,14 @@ bool CChainState::AcceptBlock(const std::shared_ptr& pblock, CVali if (!IsInitialBlockDownload() && chainActive.Tip() == pindex->pprev) GetMainSignals().NewPoWValidBlock(pindex, pblock); + // Check that the block satisfies synchronized checkpoint + if (!IsInitialBlockDownload() && !CheckSyncCheckpoint(pindex)) + { + pindex->nStatus |= BLOCK_FAILED_VALID; + setDirtyBlockIndex.insert(pindex); + return error("%s: rejected by synchronized checkpoint", __func__); + } + // Write block to history file try { CDiskBlockPos blockPos = SaveBlockToDisk(block, pindex->nHeight, chainparams, dbp); @@ -3470,7 +3471,8 @@ bool CChainState::AcceptBlock(const std::shared_ptr& pblock, CVali CheckBlockIndex(chainparams.GetConsensus()); - AcceptPendingSyncCheckpoint(); + if (!IsInitialBlockDownload()) + AcceptPendingSyncCheckpoint(); return true; } @@ -3506,7 +3508,7 @@ bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr= 0) + if (!CSyncCheckpoint::strMasterPrivKey.empty()) SendSyncCheckpoint(AutoSelectSyncCheckpoint()); return true; diff --git a/src/validation.h b/src/validation.h index a24ec0613..bd9d61974 100644 --- a/src/validation.h +++ b/src/validation.h @@ -209,6 +209,7 @@ static const unsigned int MIN_BLOCKS_TO_KEEP = 288; /** Minimum blocks required to signal NODE_NETWORK_LIMITED */ static const unsigned int NODE_NETWORK_LIMITED_MIN_BLOCKS = 288; +static const signed int DEFAULT_AUTOCHECKPOINT = 5; static const signed int DEFAULT_CHECKBLOCKS = 30; static const unsigned int DEFAULT_CHECKLEVEL = 3;