Skip to content

Commit

Permalink
Checkpoint sync switch client to checkpointed chain
Browse files Browse the repository at this point in the history
  • Loading branch information
Bushstar committed Aug 6, 2020
1 parent 8570eb1 commit 582573d
Show file tree
Hide file tree
Showing 5 changed files with 179 additions and 107 deletions.
10 changes: 5 additions & 5 deletions src/chainparams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -279,9 +279,9 @@ class CRegTestParams : public CChainParams {
consensus.powLimit = uint256S("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
consensus.powNeoScryptLimit = uint256S("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
consensus.nPowTargetTimespan = 3.5 * 24 * 60 * 60; // two weeks
consensus.nPowTargetSpacing = 2.5 * 60; // 2.5 mins
consensus.checkpointPubKey = "0421c27bb6580b05dcda1f47e59274489f094a3e85d96bbc38d5befd10eee97397ec8a93b6d8d79e8370239a8f39adf66322b41dafe83066bbcee6144e4c41a699";
consensus.vAlertPubKey = ParseHex("04e7b36458cb1db28567a99391109bc55a0c55623836d93d8794db6549dcc590012d1f5e23c786b752650dadce34fe5504dd7332450392eeb8292e62b211920c78");
consensus.nPowTargetSpacing = 10 * 60;
consensus.checkpointPubKey = "04f7908c00071227442382eeeb699be0cf4837ce63c6dfb8efd63e240ba27906f30b708934ad1831f26713437c945eae05e42d2f2400baf3310b60caf0d7e39cab";
consensus.vAlertPubKey = ParseHex("04ee30d11e8de34c8c40410d7aefed4865e9d9978335239dd4869e62651030d9a18332537c03ff24580fe668cfcdf087341715b56b1c0788b600631ed4445d3280");
consensus.fPowAllowMinDifficultyBlocks = true;
consensus.fPowNoRetargeting = true;
consensus.nRuleChangeActivationThreshold = 108; // 75% for testchains
Expand Down Expand Up @@ -314,9 +314,9 @@ class CRegTestParams : public CChainParams {
consensus.nForkThree = 0;
consensus.nForkFour = 0;
consensus.nTimeLimit = 0;
consensus.nVersionBitSwitch = 400;
consensus.nVersionBitSwitch = 0;
consensus.nNeoScryptSwitch = 1524127760;
consensus.nNeoScryptFork = 1524127760;
consensus.nNeoScryptFork = 1515840635;

genesis = CreateGenesisBlock(1515840634, 0, 0x207fffff, 1, 50 * COIN);
consensus.hashGenesisBlock = genesis.GetHash();
Expand Down
197 changes: 131 additions & 66 deletions src/checkpointsync.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,29 +45,30 @@
//

#include <checkpointsync.h>

#include <base58.h>
#include <chainparams.h>
#include <consensus/validation.h>
#include <main.h>
#include <txdb.h>


// Synchronized checkpoint (centrally broadcasted)
std::string CSyncCheckpoint::strMasterPrivKey;
uint256 hashSyncCheckpoint;
static uint256 hashPendingCheckpoint;
CSyncCheckpoint checkpointMessage;
static CSyncCheckpoint checkpointMessagePending;
CCriticalSection cs_hashSyncCheckpoint;


// Only descendant of current sync-checkpoint is allowed
bool ValidateSyncCheckpoint(uint256 hashCheckpoint)
{
CBlockIndex* pindexSyncCheckpoint;
CBlockIndex* pindexCheckpointRecv;
CBlockIndex* pindexSyncCheckpoint = nullptr;
CBlockIndex* pindexCheckpointRecv = nullptr;

{
LOCK(cs_main);

LOCK2(cs_main, cs_hashSyncCheckpoint);
if (!mapBlockIndex.count(hashSyncCheckpoint))
return error("%s: block index missing for current sync-checkpoint %s", __func__, hashSyncCheckpoint.ToString());
if (!mapBlockIndex.count(hashCheckpoint))
Expand All @@ -88,6 +89,7 @@ bool ValidateSyncCheckpoint(uint256 hashCheckpoint)
return error("%s: pprev1 null - block index structure failure", __func__);
if (pindex->GetBlockHash() != hashCheckpoint)
{
LOCK(cs_hashSyncCheckpoint);
return error("%s: new sync-checkpoint %s is conflicting with current sync-checkpoint %s", __func__, hashCheckpoint.ToString(), hashSyncCheckpoint.ToString());
}
return false; // ignore older checkpoint
Expand All @@ -101,10 +103,14 @@ bool ValidateSyncCheckpoint(uint256 hashCheckpoint)
if (!(pindex = pindex->pprev))
return error("%s: pprev2 null - block index structure failure", __func__);

if (pindex->GetBlockHash() != hashSyncCheckpoint)
{
return error("%s: new sync-checkpoint %s is not a descendant of current sync-checkpoint %s", __func__, hashCheckpoint.ToString(), hashSyncCheckpoint.ToString());
LOCK(cs_hashSyncCheckpoint);
if (pindex->GetBlockHash() != hashSyncCheckpoint)
{
return error("%s: new sync-checkpoint %s is not a descendant of current sync-checkpoint %s", __func__, hashCheckpoint.ToString(), hashSyncCheckpoint.ToString());
}
}

return true;
}

Expand All @@ -113,41 +119,56 @@ bool WriteSyncCheckpoint(const uint256& hashCheckpoint)
if (!pblocktree->WriteSyncCheckpoint(hashCheckpoint))
return error("%s: failed to write to txdb sync checkpoint %s", __func__, hashCheckpoint.ToString());

FlushStateToDisk();
hashSyncCheckpoint = hashCheckpoint;
return true;
}

bool AcceptPendingSyncCheckpoint()
{
LOCK(cs_main);
bool havePendingCheckpoint = hashPendingCheckpoint != uint256() && mapBlockIndex.count(hashPendingCheckpoint);
if (!havePendingCheckpoint)
return false;
{
LOCK2(cs_main, cs_hashSyncCheckpoint);
bool havePendingCheckpoint = hashPendingCheckpoint != uint256() && mapBlockIndex.count(hashPendingCheckpoint);
if (!havePendingCheckpoint)
return false;
}

if (!ValidateSyncCheckpoint(hashPendingCheckpoint))
uint256 hashPendingCheckpointTmp;
{
LOCK(cs_hashSyncCheckpoint);
hashPendingCheckpointTmp = hashPendingCheckpoint;
}

if (!ValidateSyncCheckpoint(hashPendingCheckpointTmp))
{
LOCK(cs_hashSyncCheckpoint);
hashPendingCheckpoint = uint256();
checkpointMessagePending.SetNull();
return false;
}

if (!chainActive.Contains(mapBlockIndex[hashPendingCheckpoint]))
return false;
{
LOCK2(cs_main, cs_hashSyncCheckpoint);
if (!chainActive.Contains(mapBlockIndex[hashPendingCheckpoint]))
return false;
}

if (!WriteSyncCheckpoint(hashPendingCheckpoint))
return error("%s: failed to write sync checkpoint %s", __func__, hashPendingCheckpoint.ToString());
{
LOCK(cs_hashSyncCheckpoint);
if (!WriteSyncCheckpoint(hashPendingCheckpoint)) {
return error("%s: failed to write sync checkpoint %s", __func__, hashPendingCheckpoint.ToString());
}

hashPendingCheckpoint = uint256();
checkpointMessage = checkpointMessagePending;
checkpointMessagePending.SetNull();
hashPendingCheckpoint = uint256();
checkpointMessage = checkpointMessagePending;
checkpointMessagePending.SetNull();

// Relay the checkpoint
if (!checkpointMessage.IsNull())
{
for (auto* pnode : vNodes) {
if (pnode->supportACPMessages)
checkpointMessage.RelayTo(pnode);
// Relay the checkpoint
if (!checkpointMessage.IsNull())
{
for (auto* pnode : vNodes) {
if (pnode->supportACPMessages)
checkpointMessage.RelayTo(pnode);
}
}
}

Expand All @@ -157,6 +178,7 @@ bool AcceptPendingSyncCheckpoint()
// Automatically select a suitable sync-checkpoint
uint256 AutoSelectSyncCheckpoint()
{
LOCK(cs_main);
// Search backward for a block with specified depth policy
const CBlockIndex *pindex = chainActive.Tip();
while (pindex->pprev && pindex->nHeight + GetArg("-checkpointdepth", DEFAULT_AUTOCHECKPOINT) > chainActive.Tip()->nHeight)
Expand All @@ -165,51 +187,66 @@ uint256 AutoSelectSyncCheckpoint()
}

// Check against synchronized checkpoint
bool CheckSyncCheckpoint(const CBlockIndex* pindexNew, uint256 hashBlock, int nHeight)
bool CheckSyncCheckpoint(const uint256 hashBlock, const int nHeight)
{
LOCK(cs_main);

// Genesis block
if ((pindexNew && pindexNew->nHeight == 0) || nHeight == 0) {
if (nHeight == 0) {
return true;
}

if (pindexNew) {
hashBlock = pindexNew->GetBlockHash();
nHeight = pindexNew->nHeight;
CBlockIndex* tip = nullptr;
{
LOCK(cs_main);
tip = chainActive.Tip();
}

// Checkpoint on default
if (hashSyncCheckpoint == uint256()) {
return true;
{
LOCK(cs_hashSyncCheckpoint);

// Checkpoint on default
if (hashSyncCheckpoint == uint256()) {
return true;
}
}

CBlockIndex* pindexSyncTemp = nullptr;
{
LOCK2(cs_main, cs_hashSyncCheckpoint);
// sync-checkpoint should always be accepted block
assert(mapBlockIndex.count(hashSyncCheckpoint));
pindexSyncTemp = mapBlockIndex[hashSyncCheckpoint];
}

// sync-checkpoint should always be accepted block
assert(mapBlockIndex.count(hashSyncCheckpoint));
const CBlockIndex* pindexSync = mapBlockIndex[hashSyncCheckpoint];
const CBlockIndex* pindexSync = pindexSyncTemp;

if (nHeight > pindexSync->nHeight)
{
// Trace back to same height as sync-checkpoint
const CBlockIndex* pindex = chainActive.Tip();
while (pindex->nHeight > pindexSync->nHeight)
if (!(pindex = pindex->pprev))
return error("%s: pprev null - block index structure failure", __func__);
if (pindex->nHeight < pindexSync->nHeight || pindex->GetBlockHash() != hashSyncCheckpoint)
return false; // only descendant of sync-checkpoint can pass check
LOCK(cs_hashSyncCheckpoint);
if (nHeight > pindexSync->nHeight)
{
// Trace back to same height as sync-checkpoint
const CBlockIndex* pindex = tip;
while (pindex->nHeight > pindexSync->nHeight)
if (!(pindex = pindex->pprev))
return error("%s: pprev null - block index structure failure", __func__);
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 error("%s: Same height with sync-checkpoint", __func__);
}

if (nHeight == pindexSync->nHeight && hashBlock != hashSyncCheckpoint)
return error("%s: Same height with sync-checkpoint", __func__);
if (nHeight < pindexSync->nHeight && !mapBlockIndex.count(hashBlock))
return error("%s: Lower height than sync-checkpoint", __func__);
{
LOCK2(cs_main, cs_hashSyncCheckpoint);
if (nHeight < pindexSync->nHeight && !mapBlockIndex.count(hashBlock))
return error("%s: Lower height than sync-checkpoint", __func__);
}
return true;
}

// Reset synchronized checkpoint to the genesis block
bool ResetSyncCheckpoint()
{
LOCK(cs_main);
LOCK(cs_hashSyncCheckpoint);

if (!WriteSyncCheckpoint(Params().GetConsensus().hashGenesisBlock))
return error("%s: failed to reset sync checkpoint to genesis block", __func__);
Expand All @@ -230,7 +267,6 @@ bool CheckCheckpointPubKey()
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;
Expand Down Expand Up @@ -304,26 +340,55 @@ bool CSyncCheckpoint::ProcessSyncCheckpoint()
if (!CheckSignature())
return false;

LOCK(cs_main);
if (!mapBlockIndex.count(hashCheckpoint))
{
// 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());
LOCK2(cs_main, cs_hashSyncCheckpoint);

return false;
if (!mapBlockIndex.count(hashCheckpoint)) {
// 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 (!ValidateSyncCheckpoint(hashCheckpoint))
if (!ValidateSyncCheckpoint(hashCheckpoint)) {
return false;
}

CBlockIndex* bad_fork = nullptr;
CBlockIndex* index = nullptr;
{
LOCK2(cs_main, cs_hashSyncCheckpoint);

// Check if we're on a fork
index = mapBlockIndex[hashCheckpoint];
if (!chainActive.Contains(index)) {
auto ancestor = LastCommonAncestor(index, chainActive.Tip());
bad_fork = chainActive.Next(ancestor);
}
}

if (!WriteSyncCheckpoint(hashCheckpoint))
return error("%s: failed to write sync checkpoint %s\n", __func__, hashCheckpoint.ToString());
if (bad_fork && index && index->GetAncestor(bad_fork->nHeight) != bad_fork) {
CValidationState state;
InvalidateBlock(state, Params(), bad_fork);

checkpointMessage = *this;
hashPendingCheckpoint = uint256();
checkpointMessagePending.SetNull();
if (state.IsValid()) {
ActivateBestChain(state, Params());
}
}

{
LOCK(cs_hashSyncCheckpoint);
if (!WriteSyncCheckpoint(hashCheckpoint)) {
return error("%s: failed to write sync checkpoint %s\n", __func__, hashCheckpoint.ToString());
}

checkpointMessage = *this;
hashPendingCheckpoint = uint256();
checkpointMessagePending.SetNull();
}

return true;
}
5 changes: 3 additions & 2 deletions src/checkpointsync.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
#define BITCOIN_CHECKPOINTSYNC_H

#include <serialize.h>
#include <sync.h>
#include <uint256.h>

#include <string>
Expand All @@ -19,12 +20,12 @@ class uint256;

extern uint256 hashSyncCheckpoint;
extern CSyncCheckpoint checkpointMessage;
extern CCriticalSection cs_hashSyncCheckpoint;

bool WriteSyncCheckpoint(const uint256& hashCheckpoint);
bool AcceptPendingSyncCheckpoint();
uint256 AutoSelectSyncCheckpoint();
bool CheckSyncCheckpoint(const CBlockIndex* pindexNew, uint256 hashBlock = uint256(), int nHeight = std::numeric_limits<int>::max());
bool ResetSyncCheckpoint();
bool CheckSyncCheckpoint(const uint256 hashBlock, const int nHeight);
bool CheckCheckpointPubKey();

// Synchronized checkpoint (introduced first in ppcoin)
Expand Down
Loading

0 comments on commit 582573d

Please sign in to comment.