use median filter for peer-reported reported number of blocks
- fixes problem that one misconfigured or malicious node can mess up progress bar - implementation in src/util.h - testcase in src/test/util_tests.cpp
This commit is contained in:
parent
5902040874
commit
a8b95ce6ed
3 changed files with 85 additions and 11 deletions
16
src/main.cpp
16
src/main.cpp
|
@ -32,7 +32,6 @@ uint256 hashGenesisBlock("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3
|
|||
static CBigNum bnProofOfWorkLimit(~uint256(0) >> 32);
|
||||
const int nTotalBlocksEstimate = 140700; // Conservative estimate of total nr of blocks on main chain
|
||||
const int nInitialBlockThreshold = 120; // Regard blocks up until N-threshold as "initial download"
|
||||
int nMaxBlocksOfPeers = 0; // Amount of blocks that other nodes claim to have
|
||||
CBlockIndex* pindexGenesisBlock = NULL;
|
||||
int nBestHeight = -1;
|
||||
CBigNum bnBestChainWork = 0;
|
||||
|
@ -41,6 +40,8 @@ uint256 hashBestChain = 0;
|
|||
CBlockIndex* pindexBest = NULL;
|
||||
int64 nTimeBestReceived = 0;
|
||||
|
||||
CMedianFilter<int> cPeerBlockCounts(5, 0); // Amount of blocks that other nodes claim to have
|
||||
|
||||
map<uint256, CBlock*> mapOrphanBlocks;
|
||||
multimap<uint256, CBlock*> mapOrphanBlocksByPrev;
|
||||
|
||||
|
@ -65,11 +66,6 @@ int fUseUPnP = false;
|
|||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// dispatching functions
|
||||
|
@ -730,7 +726,7 @@ int GetTotalBlocksEstimate()
|
|||
// Return maximum amount of blocks that other nodes claim to have
|
||||
int GetNumBlocksOfPeers()
|
||||
{
|
||||
return std::max(nMaxBlocksOfPeers, GetTotalBlocksEstimate());
|
||||
return std::max(cPeerBlockCounts.median(), GetTotalBlocksEstimate());
|
||||
}
|
||||
|
||||
bool IsInitialBlockDownload()
|
||||
|
@ -1847,10 +1843,8 @@ bool static ProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
|
|||
pfrom->fSuccessfullyConnected = true;
|
||||
|
||||
printf("version message: version %d, blocks=%d\n", pfrom->nVersion, pfrom->nStartingHeight);
|
||||
if(pfrom->nStartingHeight > nMaxBlocksOfPeers)
|
||||
{
|
||||
nMaxBlocksOfPeers = pfrom->nStartingHeight;
|
||||
}
|
||||
|
||||
cPeerBlockCounts.input(pfrom->nStartingHeight);
|
||||
}
|
||||
|
||||
|
||||
|
|
36
src/test/util_tests.cpp
Normal file
36
src/test/util_tests.cpp
Normal file
|
@ -0,0 +1,36 @@
|
|||
#include <vector>
|
||||
#include <boost/test/unit_test.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
#include "../util.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
BOOST_AUTO_TEST_SUITE(util_tests)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(util_MedianFilter)
|
||||
{
|
||||
CMedianFilter<int> filter(5, 15);
|
||||
|
||||
BOOST_CHECK(filter.median() == 15);
|
||||
|
||||
filter.input(20); // [15 20]
|
||||
BOOST_CHECK(filter.median() == 17);
|
||||
|
||||
filter.input(30); // [15 20 30]
|
||||
BOOST_CHECK(filter.median() == 20);
|
||||
|
||||
filter.input(3); // [3 15 20 30]
|
||||
BOOST_CHECK(filter.median() == 17);
|
||||
|
||||
filter.input(7); // [3 7 15 20 30]
|
||||
BOOST_CHECK(filter.median() == 15);
|
||||
|
||||
filter.input(18); // [3 7 18 20 30]
|
||||
BOOST_CHECK(filter.median() == 18);
|
||||
|
||||
filter.input(0); // [0 3 7 18 30]
|
||||
BOOST_CHECK(filter.median() == 7);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
44
src/util.h
44
src/util.h
|
@ -565,6 +565,50 @@ inline uint160 Hash160(const std::vector<unsigned char>& vch)
|
|||
}
|
||||
|
||||
|
||||
// Median filter over a stream of values
|
||||
// Returns the median of the last N numbers
|
||||
template <typename T> class CMedianFilter
|
||||
{
|
||||
private:
|
||||
std::vector<T> vValues;
|
||||
std::vector<T> vSorted;
|
||||
int nSize;
|
||||
public:
|
||||
CMedianFilter(int size, T initial_value):
|
||||
nSize(size)
|
||||
{
|
||||
vValues.reserve(size);
|
||||
vValues.push_back(initial_value);
|
||||
vSorted = vValues;
|
||||
}
|
||||
|
||||
void input(T value)
|
||||
{
|
||||
if(vValues.size() == nSize)
|
||||
{
|
||||
vValues.erase(vValues.begin());
|
||||
}
|
||||
vValues.push_back(value);
|
||||
|
||||
vSorted.resize(vValues.size());
|
||||
std::copy(vValues.begin(), vValues.end(), vSorted.begin());
|
||||
std::sort(vSorted.begin(), vSorted.end());
|
||||
}
|
||||
|
||||
T median() const
|
||||
{
|
||||
int size = vSorted.size();
|
||||
if(size & 1) // Odd number of elements
|
||||
{
|
||||
return vSorted[size/2];
|
||||
}
|
||||
else // Even number of elements
|
||||
{
|
||||
return (vSorted[size/2-1] + vSorted[size/2]) / 2;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue