diff options
author | Wladimir J. van der Laan <laanwj@gmail.com> | 2011-09-28 21:35:58 +0200 |
---|---|---|
committer | Wladimir J. van der Laan <laanwj@gmail.com> | 2011-09-28 21:35:58 +0200 |
commit | a8b95ce6ed5e84d34748ecdd0ff1db4d03377cf0 (patch) | |
tree | f416d18e89f6e619a84d9e316134afc5380df282 /src | |
parent | 59020408744664fde902406cf41de125859d461f (diff) |
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
Diffstat (limited to 'src')
-rw-r--r-- | src/main.cpp | 16 | ||||
-rw-r--r-- | src/test/util_tests.cpp | 36 | ||||
-rw-r--r-- | src/util.h | 44 |
3 files changed, 85 insertions, 11 deletions
diff --git a/src/main.cpp b/src/main.cpp index e732ddcf5d..5c0dd7d765 100644 --- a/src/main.cpp +++ b/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); } diff --git a/src/test/util_tests.cpp b/src/test/util_tests.cpp new file mode 100644 index 0000000000..337d901277 --- /dev/null +++ b/src/test/util_tests.cpp @@ -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() diff --git a/src/util.h b/src/util.h index fabcaf9303..290195cbfa 100644 --- a/src/util.h +++ b/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; + } + } +}; + |