Called periodically asynchronously; alerts if it smells like we're being fed a bad chain (blocks being generated much too slowly or too quickly). Always returns the constant interval at which it should be scheduled.
| 2169 | // Always returns the constant interval at which it should be scheduled. |
| 2170 | // |
| 2171 | int PartitionCheck(bool (*initialDownloadCheck)(), CCriticalSection& cs, const CBlockIndex *const &bestHeader, |
| 2172 | int64_t nPowTargetSpacing) |
| 2173 | { |
| 2174 | // Aim for one false-positive about every fifty years of normal running: |
| 2175 | // The sample interval SPAN_SECONDS is chosen as the smallest multiple of target spacing expected |
| 2176 | // to trigger a too-few-blocks alert only once in fifty years (this will be when 0 blocks are seen): |
| 2177 | // blocks cdf(blocks, 0) alertThreshold |
| 2178 | // 11 1.67017e-5 4.18569e-6 |
| 2179 | // 12 6.14421e-6 4.56621e-6 |
| 2180 | // 13 2.26033e-6 4.94673e-6 <--- min such that (cdf < threshold) |
| 2181 | // 14 8.31529e-7 5.32725e-6 |
| 2182 | // 15 3.05902e-7 5.70776e-6 |
| 2183 | //TODO find BLOCKS_EXPECTED dynamically, for correct timing of non-10-minute intervals |
| 2184 | const int FIFTY_YEARS = 50*365*24*60*60; |
| 2185 | const int BLOCKS_EXPECTED = 13; |
| 2186 | const int SPAN_SECONDS = BLOCKS_EXPECTED * nPowTargetSpacing; |
| 2187 | double alertThreshold = 1.0 / (FIFTY_YEARS / SPAN_SECONDS); |
| 2188 | |
| 2189 | if (bestHeader == NULL || initialDownloadCheck()) return SPAN_SECONDS; |
| 2190 | |
| 2191 | static int64_t lastAlertTime = 0; |
| 2192 | int64_t now = GetAdjustedTime(); |
| 2193 | if (lastAlertTime > now-60*60*24) return SPAN_SECONDS; // Alert at most once per day |
| 2194 | |
| 2195 | boost::math::poisson_distribution<double> poisson(BLOCKS_EXPECTED); |
| 2196 | |
| 2197 | std::string strWarning; |
| 2198 | int64_t startTime = GetAdjustedTime()-SPAN_SECONDS; |
| 2199 | |
| 2200 | LOCK(cs); |
| 2201 | const CBlockIndex* i = bestHeader; |
| 2202 | int nBlocks = 0; |
| 2203 | while (i->GetBlockTime() >= startTime) { |
| 2204 | ++nBlocks; |
| 2205 | i = i->pprev; |
| 2206 | if (i == NULL) return SPAN_SECONDS; // Ran out of chain, we must not be fully sync'ed |
| 2207 | } |
| 2208 | |
| 2209 | // How likely is it to find at least that many by chance? |
| 2210 | double pHigh = 1.0 - boost::math::cdf(poisson, std::max(0, nBlocks - 1)); |
| 2211 | // How likely is it to find at most that few by chance? |
| 2212 | double pLow = boost::math::cdf(poisson, nBlocks); |
| 2213 | |
| 2214 | LogPrint("partitioncheck", "%s: Found %d blocks in the last %d seconds\n", __func__, nBlocks, SPAN_SECONDS); |
| 2215 | LogPrint("partitioncheck", "%s: likelihood that many: %g, that few: %g\n", __func__, pHigh, pLow); |
| 2216 | |
| 2217 | if (pLow <= alertThreshold) |
| 2218 | { |
| 2219 | // Many fewer blocks than expected: alert! |
| 2220 | strWarning = strprintf(_("WARNING: check your network connection, %d blocks received in the last %d seconds (%d expected)"), |
| 2221 | nBlocks, SPAN_SECONDS, BLOCKS_EXPECTED); |
| 2222 | } |
| 2223 | else if (pHigh <= alertThreshold) |
| 2224 | { |
| 2225 | // Many more blocks than expected: alert! |
| 2226 | strWarning = strprintf(_("WARNING: abnormally high number of blocks generated, %d blocks received in the last %d seconds (%d expected)"), |
| 2227 | nBlocks, SPAN_SECONDS, BLOCKS_EXPECTED); |
| 2228 | } |