Use best header chain timestamps to detect partitioning

The partition checking code was using chainActive timestamps
to detect partitioning; with headers-first syncing, it should use
(and with this pull request, does use) pIndexBestHeader timestamps.

Fixes issue #6251
This commit is contained in:
Gavin Andresen 2015-06-08 16:34:58 -04:00
parent 55294a9fb6
commit 65b9454503
No known key found for this signature in database
GPG key ID: 7588242FBE38D3A8
4 changed files with 16 additions and 14 deletions

View file

@ -1396,7 +1396,7 @@ bool AppInit2(boost::thread_group& threadGroup, CScheduler& scheduler)
// Monitor the chain, and alert if we get blocks much quicker or slower than expected // Monitor the chain, and alert if we get blocks much quicker or slower than expected
int64_t nPowTargetSpacing = Params().GetConsensus().nPowTargetSpacing; int64_t nPowTargetSpacing = Params().GetConsensus().nPowTargetSpacing;
CScheduler::Function f = boost::bind(&PartitionCheck, &IsInitialBlockDownload, CScheduler::Function f = boost::bind(&PartitionCheck, &IsInitialBlockDownload,
boost::ref(cs_main), boost::cref(chainActive), nPowTargetSpacing); boost::ref(cs_main), boost::cref(pindexBestHeader), nPowTargetSpacing);
scheduler.scheduleEvery(f, nPowTargetSpacing); scheduler.scheduleEvery(f, nPowTargetSpacing);
#ifdef ENABLE_WALLET #ifdef ENABLE_WALLET

View file

@ -1711,9 +1711,10 @@ void ThreadScriptCheck() {
// we're being fed a bad chain (blocks being generated much // we're being fed a bad chain (blocks being generated much
// too slowly or too quickly). // too slowly or too quickly).
// //
void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const CChain& chain, int64_t nPowTargetSpacing) void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const CBlockIndex *const &bestHeader,
int64_t nPowTargetSpacing)
{ {
if (initialDownloadCheck()) return; if (bestHeader == NULL || initialDownloadCheck()) return;
static int64_t lastAlertTime = 0; static int64_t lastAlertTime = 0;
int64_t now = GetAdjustedTime(); int64_t now = GetAdjustedTime();
@ -1729,10 +1730,13 @@ void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const
int64_t startTime = GetAdjustedTime()-SPAN_SECONDS; int64_t startTime = GetAdjustedTime()-SPAN_SECONDS;
LOCK(cs); LOCK(cs);
int h = chain.Height(); const CBlockIndex* i = bestHeader;
while (h > 0 && chain[h]->GetBlockTime() >= startTime) int nBlocks = 0;
--h; while (i->GetBlockTime() >= startTime) {
int nBlocks = chain.Height()-h; ++nBlocks;
i = i->pprev;
if (i == NULL) return; // Ran out of chain, we must not be fully sync'ed
}
// How likely is it to find that many by chance? // How likely is it to find that many by chance?
double p = boost::math::pdf(poisson, nBlocks); double p = boost::math::pdf(poisson, nBlocks);

View file

@ -186,7 +186,7 @@ bool SendMessages(CNode* pto, bool fSendTrickle);
/** Run an instance of the script checking thread */ /** Run an instance of the script checking thread */
void ThreadScriptCheck(); void ThreadScriptCheck();
/** Try to detect Partition (network isolation) attacks against us */ /** Try to detect Partition (network isolation) attacks against us */
void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const CChain& chain, int64_t nPowTargetSpacing); void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const CBlockIndex *const &bestHeader, int64_t nPowTargetSpacing);
/** Check whether we are doing an initial block download (synchronizing from disk or network) */ /** Check whether we are doing an initial block download (synchronizing from disk or network) */
bool IsInitialBlockDownload(); bool IsInitialBlockDownload();
/** Format a string that describes several potential problems detected by the core */ /** Format a string that describes several potential problems detected by the core */

View file

@ -201,7 +201,6 @@ BOOST_AUTO_TEST_CASE(PartitionAlert)
{ {
// Test PartitionCheck // Test PartitionCheck
CCriticalSection csDummy; CCriticalSection csDummy;
CChain chainDummy;
CBlockIndex indexDummy[100]; CBlockIndex indexDummy[100];
CChainParams& params = Params(CBaseChainParams::MAIN); CChainParams& params = Params(CBaseChainParams::MAIN);
int64_t nPowTargetSpacing = params.GetConsensus().nPowTargetSpacing; int64_t nPowTargetSpacing = params.GetConsensus().nPowTargetSpacing;
@ -220,17 +219,16 @@ BOOST_AUTO_TEST_CASE(PartitionAlert)
// Other members don't matter, the partition check code doesn't // Other members don't matter, the partition check code doesn't
// use them // use them
} }
chainDummy.SetTip(&indexDummy[99]);
// Test 1: chain with blocks every nPowTargetSpacing seconds, // Test 1: chain with blocks every nPowTargetSpacing seconds,
// as normal, no worries: // as normal, no worries:
PartitionCheck(falseFunc, csDummy, chainDummy, nPowTargetSpacing); PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing);
BOOST_CHECK(strMiscWarning.empty()); BOOST_CHECK(strMiscWarning.empty());
// Test 2: go 3.5 hours without a block, expect a warning: // Test 2: go 3.5 hours without a block, expect a warning:
now += 3*60*60+30*60; now += 3*60*60+30*60;
SetMockTime(now); SetMockTime(now);
PartitionCheck(falseFunc, csDummy, chainDummy, nPowTargetSpacing); PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing);
BOOST_CHECK(!strMiscWarning.empty()); BOOST_CHECK(!strMiscWarning.empty());
BOOST_TEST_MESSAGE(std::string("Got alert text: ")+strMiscWarning); BOOST_TEST_MESSAGE(std::string("Got alert text: ")+strMiscWarning);
strMiscWarning = ""; strMiscWarning = "";
@ -239,7 +237,7 @@ BOOST_AUTO_TEST_CASE(PartitionAlert)
// code: // code:
now += 60*10; now += 60*10;
SetMockTime(now); SetMockTime(now);
PartitionCheck(falseFunc, csDummy, chainDummy, nPowTargetSpacing); PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing);
BOOST_CHECK(strMiscWarning.empty()); BOOST_CHECK(strMiscWarning.empty());
// Test 4: get 2.5 times as many blocks as expected: // Test 4: get 2.5 times as many blocks as expected:
@ -248,7 +246,7 @@ BOOST_AUTO_TEST_CASE(PartitionAlert)
int64_t quickSpacing = nPowTargetSpacing*2/5; int64_t quickSpacing = nPowTargetSpacing*2/5;
for (int i = 0; i < 100; i++) // Tweak chain timestamps: for (int i = 0; i < 100; i++) // Tweak chain timestamps:
indexDummy[i].nTime = now - (100-i)*quickSpacing; indexDummy[i].nTime = now - (100-i)*quickSpacing;
PartitionCheck(falseFunc, csDummy, chainDummy, nPowTargetSpacing); PartitionCheck(falseFunc, csDummy, &indexDummy[99], nPowTargetSpacing);
BOOST_CHECK(!strMiscWarning.empty()); BOOST_CHECK(!strMiscWarning.empty());
BOOST_TEST_MESSAGE(std::string("Got alert text: ")+strMiscWarning); BOOST_TEST_MESSAGE(std::string("Got alert text: ")+strMiscWarning);
strMiscWarning = ""; strMiscWarning = "";