From dce8360e44d5330cc9f9d09c9b09ac9237237204 Mon Sep 17 00:00:00 2001 From: Pieter Wuille Date: Thu, 19 Mar 2015 05:34:06 -0700 Subject: [PATCH] Reduce checkpoints' effect on consensus. Instead of only checking height to decide whether to disable script checks, actually check whether a block is an ancestor of a checkpoint, up to which headers have been validated. This means that we don't have to prevent accepting a side branch anymore - it will be safe, just less fast to do. We still need to prevent being fed a multitude of low-difficulty headers filling up our memory. The mechanism for that is unchanged for now: once a checkpoint is reached with headers, no headers chain branching off before that point are allowed anymore. --- src/chain.cpp | 7 ++++--- src/checkpoints.cpp | 9 --------- src/checkpoints.h | 3 --- src/init.cpp | 2 +- src/main.cpp | 16 +++++++++------- src/test/Checkpoints_tests.cpp | 16 +--------------- 6 files changed, 15 insertions(+), 38 deletions(-) diff --git a/src/chain.cpp b/src/chain.cpp index 719256106e0..5b8ce076c47 100644 --- a/src/chain.cpp +++ b/src/chain.cpp @@ -82,9 +82,10 @@ CBlockIndex* CBlockIndex::GetAncestor(int height) while (heightWalk > height) { int heightSkip = GetSkipHeight(heightWalk); int heightSkipPrev = GetSkipHeight(heightWalk - 1); - if (heightSkip == height || - (heightSkip > height && !(heightSkipPrev < heightSkip - 2 && - heightSkipPrev >= height))) { + if (pindexWalk->pskip != NULL && + (heightSkip == height || + (heightSkip > height && !(heightSkipPrev < heightSkip - 2 && + heightSkipPrev >= height)))) { // Only follow pskip if pprev->pskip isn't better than pskip->pprev. pindexWalk = pindexWalk->pskip; heightWalk = heightSkip; diff --git a/src/checkpoints.cpp b/src/checkpoints.cpp index 20244861399..87f4ad7f2ec 100644 --- a/src/checkpoints.cpp +++ b/src/checkpoints.cpp @@ -24,15 +24,6 @@ namespace Checkpoints { */ static const double SIGCHECK_VERIFICATION_FACTOR = 5.0; - bool CheckBlock(const CCheckpointData& data, int nHeight, const uint256& hash) - { - const MapCheckpoints& checkpoints = data.mapCheckpoints; - - MapCheckpoints::const_iterator i = checkpoints.find(nHeight); - if (i == checkpoints.end()) return true; - return hash == i->second; - } - //! Guess how far we are in the verification process at the given block index double GuessVerificationProgress(const CCheckpointData& data, CBlockIndex *pindex, bool fSigchecks) { if (pindex==NULL) diff --git a/src/checkpoints.h b/src/checkpoints.h index a720f096c09..001e3cc8015 100644 --- a/src/checkpoints.h +++ b/src/checkpoints.h @@ -26,9 +26,6 @@ struct CCheckpointData { double fTransactionsPerDay; }; -//! Returns true if block passes checkpoint checks -bool CheckBlock(const CCheckpointData& data, int nHeight, const uint256& hash); - //! Return conservative estimate of total number of blocks, 0 if unknown int GetTotalBlocksEstimate(const CCheckpointData& data); diff --git a/src/init.cpp b/src/init.cpp index 47cbda32f5b..1905bbf8b86 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -347,7 +347,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageGroup(_("Debugging/Testing options:")); if (GetBoolArg("-help-debug", false)) { - strUsage += HelpMessageOpt("-checkpoints", strprintf(_("Only accept block chain matching built-in checkpoints (default: %u)"), 1)); + strUsage += HelpMessageOpt("-checkpoints", strprintf(_("Disable expensive verification for known chain history (default: %u)"), 1)); strUsage += HelpMessageOpt("-dblogsize=", strprintf(_("Flush database activity from memory pool to disk log every megabytes (default: %u)"), 100)); strUsage += HelpMessageOpt("-disablesafemode", strprintf(_("Disable safemode, override a real safe mode event (default: %u)"), 0)); strUsage += HelpMessageOpt("-testsafemode", strprintf(_("Force safe mode (default: %u)"), 0)); diff --git a/src/main.cpp b/src/main.cpp index 4f4926eb40c..39da3406a8f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1714,7 +1714,14 @@ bool ConnectBlock(const CBlock& block, CValidationState& state, CBlockIndex* pin return true; } - bool fScriptChecks = (!fCheckpointsEnabled || pindex->nHeight >= Checkpoints::GetTotalBlocksEstimate(chainparams.Checkpoints())); + bool fScriptChecks = true; + if (fCheckpointsEnabled) { + CBlockIndex *pindexLastCheckpoint = Checkpoints::GetLastCheckpoint(chainparams.Checkpoints()); + if (pindexLastCheckpoint && pindexLastCheckpoint->GetAncestor(pindex->nHeight) == pindex) { + // This block is an ancestor of a checkpoint: disable script checks + fScriptChecks = false; + } + } // Do not allow blocks that contain transactions which 'overwrite' older transactions, // unless those are already completely spent. @@ -2630,13 +2637,8 @@ bool ContextualCheckBlockHeader(const CBlockHeader& block, CValidationState& sta return state.Invalid(error("%s: block's timestamp is too early", __func__), REJECT_INVALID, "time-too-old"); - if(fCheckpointsEnabled) + if (fCheckpointsEnabled) { - // Check that the block chain matches the known block chain up to a checkpoint - if (!Checkpoints::CheckBlock(chainParams.Checkpoints(), nHeight, hash)) - return state.DoS(100, error("%s: rejected by checkpoint lock-in at %d", __func__, nHeight), - REJECT_CHECKPOINT, "checkpoint mismatch"); - // Don't accept any forks from the main chain prior to last checkpoint CBlockIndex* pcheckpoint = Checkpoints::GetLastCheckpoint(chainParams.Checkpoints()); if (pcheckpoint && nHeight < pcheckpoint->nHeight) diff --git a/src/test/Checkpoints_tests.cpp b/src/test/Checkpoints_tests.cpp index 642ce13bcdb..703cf307d12 100644 --- a/src/test/Checkpoints_tests.cpp +++ b/src/test/Checkpoints_tests.cpp @@ -21,21 +21,7 @@ BOOST_FIXTURE_TEST_SUITE(Checkpoints_tests, BasicTestingSetup) BOOST_AUTO_TEST_CASE(sanity) { const Checkpoints::CCheckpointData& checkpoints = Params(CBaseChainParams::MAIN).Checkpoints(); - uint256 p11111 = uint256S("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d"); - uint256 p134444 = uint256S("0x00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe"); - BOOST_CHECK(Checkpoints::CheckBlock(checkpoints, 11111, p11111)); - BOOST_CHECK(Checkpoints::CheckBlock(checkpoints, 134444, p134444)); - - - // Wrong hashes at checkpoints should fail: - BOOST_CHECK(!Checkpoints::CheckBlock(checkpoints, 11111, p134444)); - BOOST_CHECK(!Checkpoints::CheckBlock(checkpoints, 134444, p11111)); - - // ... but any hash not at a checkpoint should succeed: - BOOST_CHECK(Checkpoints::CheckBlock(checkpoints, 11111+1, p134444)); - BOOST_CHECK(Checkpoints::CheckBlock(checkpoints, 134444+1, p11111)); - BOOST_CHECK(Checkpoints::GetTotalBlocksEstimate(checkpoints) >= 134444); -} +} BOOST_AUTO_TEST_SUITE_END()