|
28 | 28 | #include <boost/algorithm/string/replace.hpp> |
29 | 29 | #include <boost/filesystem.hpp> |
30 | 30 | #include <boost/filesystem/fstream.hpp> |
| 31 | +#include <boost/math/distributions/poisson.hpp> |
31 | 32 | #include <boost/thread.hpp> |
32 | 33 |
|
33 | 34 | using namespace std; |
@@ -1685,6 +1686,64 @@ void ThreadScriptCheck() { |
1685 | 1686 | scriptcheckqueue.Thread(); |
1686 | 1687 | } |
1687 | 1688 |
|
| 1689 | +// |
| 1690 | +// Called periodically asynchronously; alerts if it smells like |
| 1691 | +// we're being fed a bad chain (blocks being generated much |
| 1692 | +// too slowly or too quickly). |
| 1693 | +// |
| 1694 | +void PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const CChain& chain, int64_t nPowTargetSpacing) |
| 1695 | +{ |
| 1696 | + if (initialDownloadCheck()) return; |
| 1697 | + |
| 1698 | + static int64_t lastAlertTime = 0; |
| 1699 | + int64_t now = GetAdjustedTime(); |
| 1700 | + if (lastAlertTime > now-60*60*24) return; // Alert at most once per day |
| 1701 | + |
| 1702 | + const int SPAN_HOURS=4; |
| 1703 | + const int SPAN_SECONDS=SPAN_HOURS*60*60; |
| 1704 | + int BLOCKS_EXPECTED = SPAN_SECONDS / nPowTargetSpacing; |
| 1705 | + |
| 1706 | + boost::math::poisson_distribution<double> poisson(BLOCKS_EXPECTED); |
| 1707 | + |
| 1708 | + std::string strWarning; |
| 1709 | + int64_t startTime = GetAdjustedTime()-SPAN_SECONDS; |
| 1710 | + |
| 1711 | + LOCK(cs); |
| 1712 | + int h = chain.Height(); |
| 1713 | + while (h > 0 && chain[h]->GetBlockTime() >= startTime) |
| 1714 | + --h; |
| 1715 | + int nBlocks = chain.Height()-h; |
| 1716 | + |
| 1717 | + // How likely is it to find that many by chance? |
| 1718 | + double p = boost::math::pdf(poisson, nBlocks); |
| 1719 | + |
| 1720 | + LogPrint("partitioncheck", "%s : Found %d blocks in the last %d hours\n", __func__, nBlocks, SPAN_HOURS); |
| 1721 | + LogPrint("partitioncheck", "%s : likelihood: %g\n", __func__, p); |
| 1722 | + |
| 1723 | + // Aim for one false-positive about every fifty years of normal running: |
| 1724 | + const int FIFTY_YEARS = 50*365*24*60*60; |
| 1725 | + double alertThreshold = 1.0 / (FIFTY_YEARS / SPAN_SECONDS); |
| 1726 | + |
| 1727 | + if (p <= alertThreshold && nBlocks < BLOCKS_EXPECTED) |
| 1728 | + { |
| 1729 | + // Many fewer blocks than expected: alert! |
| 1730 | + strWarning = strprintf(_("WARNING: check your network connection, %d blocks received in the last %d hours (%d expected)"), |
| 1731 | + nBlocks, SPAN_HOURS, BLOCKS_EXPECTED); |
| 1732 | + } |
| 1733 | + else if (p <= alertThreshold && nBlocks > BLOCKS_EXPECTED) |
| 1734 | + { |
| 1735 | + // Many more blocks than expected: alert! |
| 1736 | + strWarning = strprintf(_("WARNING: abnormally high number of blocks generated, %d blocks received in the last %d hours (%d expected)"), |
| 1737 | + nBlocks, SPAN_HOURS, BLOCKS_EXPECTED); |
| 1738 | + } |
| 1739 | + if (!strWarning.empty()) |
| 1740 | + { |
| 1741 | + strMiscWarning = strWarning; |
| 1742 | + CAlert::Notify(strWarning, true); |
| 1743 | + lastAlertTime = now; |
| 1744 | + } |
| 1745 | +} |
| 1746 | + |
1688 | 1747 | static int64_t nTimeVerify = 0; |
1689 | 1748 | static int64_t nTimeConnect = 0; |
1690 | 1749 | static int64_t nTimeIndex = 0; |
|
0 commit comments