Use equivalent PoW for non-main-chain requests

This commit is contained in:
Pieter Wuille 2015-03-17 06:35:59 -07:00
parent b6ea3bcede
commit f7303f9793
4 changed files with 49 additions and 4 deletions

View file

@ -3459,7 +3459,6 @@ bool static AlreadyHave(const CInv& inv)
return true;
}
void static ProcessGetData(CNode* pfrom)
{
std::deque<CInv>::iterator it = pfrom->vRecvGetData.begin();
@ -3487,11 +3486,13 @@ void static ProcessGetData(CNode* pfrom)
if (chainActive.Contains(mi->second)) {
send = true;
} else {
static const int nOneMonth = 30 * 24 * 60 * 60;
// To prevent fingerprinting attacks, only send blocks outside of the active
// chain if they are valid, and no more than a month older than the best header
// chain we know about.
// chain if they are valid, and no more than a month older (both in time, and in
// best equivalent proof of work) than the best header chain we know about.
send = mi->second->IsValid(BLOCK_VALID_SCRIPTS) && (pindexBestHeader != NULL) &&
(mi->second->GetBlockTime() > pindexBestHeader->GetBlockTime() - 30 * 24 * 60 * 60);
(pindexBestHeader->GetBlockTime() - mi->second->GetBlockTime() < nOneMonth) &&
(GetBlockProofEquivalentTime(*pindexBestHeader, *mi->second, *pindexBestHeader, Params().GetConsensus()) < nOneMonth);
if (!send) {
LogPrintf("%s: ignoring request from peer=%i for old block that isn't in the main chain\n", __func__, pfrom->GetId());
}

View file

@ -114,3 +114,20 @@ arith_uint256 GetBlockProof(const CBlockIndex& block)
// or ~bnTarget / (nTarget+1) + 1.
return (~bnTarget / (bnTarget + 1)) + 1;
}
int64_t GetBlockProofEquivalentTime(const CBlockIndex& to, const CBlockIndex& from, const CBlockIndex& tip, const Consensus::Params& params)
{
arith_uint256 r;
int sign = 1;
if (to.nChainWork > from.nChainWork) {
r = to.nChainWork - from.nChainWork;
} else {
r = from.nChainWork - to.nChainWork;
sign = -1;
}
r = r * arith_uint256(params.nPowTargetSpacing) / GetBlockProof(tip);
if (r.bits() > 63) {
return sign * std::numeric_limits<int64_t>::max();
}
return sign * r.GetLow64();
}

View file

@ -22,4 +22,7 @@ unsigned int CalculateNextWorkRequired(const CBlockIndex* pindexLast, int64_t nF
bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params&);
arith_uint256 GetBlockProof(const CBlockIndex& block);
/** Return the time it would take to redo the work difference between from and to, assuming the current hashrate corresponds to the difficulty at tip, in seconds. */
int64_t GetBlockProofEquivalentTime(const CBlockIndex& to, const CBlockIndex& from, const CBlockIndex& tip, const Consensus::Params&);
#endif // BITCOIN_POW_H

View file

@ -69,4 +69,28 @@ BOOST_AUTO_TEST_CASE(get_next_work_upper_limit_actual)
BOOST_CHECK_EQUAL(CalculateNextWorkRequired(&pindexLast, nLastRetargetTime, params), 0x1d00e1fd);
}
BOOST_AUTO_TEST_CASE(GetBlockProofEquivalentTime_test)
{
SelectParams(CBaseChainParams::MAIN);
const Consensus::Params& params = Params().GetConsensus();
std::vector<CBlockIndex> blocks(10000);
for (int i = 0; i < 10000; i++) {
blocks[i].pprev = i ? &blocks[i - 1] : NULL;
blocks[i].nHeight = i;
blocks[i].nTime = 1269211443 + i * params.nPowTargetSpacing;
blocks[i].nBits = 0x207fffff; /* target 0x7fffff000... */
blocks[i].nChainWork = i ? blocks[i - 1].nChainWork + GetBlockProof(blocks[i - 1]) : arith_uint256(0);
}
for (int j = 0; j < 1000; j++) {
CBlockIndex *p1 = &blocks[GetRand(10000)];
CBlockIndex *p2 = &blocks[GetRand(10000)];
CBlockIndex *p3 = &blocks[GetRand(10000)];
int64_t tdiff = GetBlockProofEquivalentTime(*p1, *p2, *p3, params);
BOOST_CHECK_EQUAL(tdiff, p1->GetBlockTime() - p2->GetBlockTime());
}
}
BOOST_AUTO_TEST_SUITE_END()