cryptonote_core: warn when the block rate deviates from expectations
The warning threshold is set to allow a false positive every ten days on average.
This commit is contained in:
parent
842a5d8bbe
commit
1168e8d5d5
|
@ -900,6 +900,15 @@ difficulty_type Blockchain::get_difficulty_for_next_block()
|
||||||
return diff;
|
return diff;
|
||||||
}
|
}
|
||||||
//------------------------------------------------------------------
|
//------------------------------------------------------------------
|
||||||
|
std::vector<time_t> Blockchain::get_last_block_timestamps(unsigned int blocks) const
|
||||||
|
{
|
||||||
|
std::vector<time_t> timestamps(blocks);
|
||||||
|
uint64_t height = m_db->height();
|
||||||
|
while (blocks--)
|
||||||
|
timestamps[blocks] = m_db->get_block_timestamp(height - blocks - 1);
|
||||||
|
return timestamps;
|
||||||
|
}
|
||||||
|
//------------------------------------------------------------------
|
||||||
// This function removes blocks from the blockchain until it gets to the
|
// This function removes blocks from the blockchain until it gets to the
|
||||||
// position where the blockchain switch started and then re-adds the blocks
|
// position where the blockchain switch started and then re-adds the blocks
|
||||||
// that had been removed.
|
// that had been removed.
|
||||||
|
|
|
@ -965,13 +965,6 @@ namespace cryptonote
|
||||||
*/
|
*/
|
||||||
std::vector<time_t> get_last_block_timestamps(unsigned int blocks) const;
|
std::vector<time_t> get_last_block_timestamps(unsigned int blocks) const;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief removes blocks from the top of the blockchain
|
|
||||||
*
|
|
||||||
* @param nblocks number of blocks to be removed
|
|
||||||
*/
|
|
||||||
void pop_blocks(uint64_t nblocks);
|
|
||||||
|
|
||||||
#ifndef IN_UNIT_TESTS
|
#ifndef IN_UNIT_TESTS
|
||||||
private:
|
private:
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1495,6 +1495,7 @@ namespace cryptonote
|
||||||
m_txpool_auto_relayer.do_call(boost::bind(&core::relay_txpool_transactions, this));
|
m_txpool_auto_relayer.do_call(boost::bind(&core::relay_txpool_transactions, this));
|
||||||
m_check_updates_interval.do_call(boost::bind(&core::check_updates, this));
|
m_check_updates_interval.do_call(boost::bind(&core::check_updates, this));
|
||||||
m_check_disk_space_interval.do_call(boost::bind(&core::check_disk_space, this));
|
m_check_disk_space_interval.do_call(boost::bind(&core::check_disk_space, this));
|
||||||
|
m_block_rate_interval.do_call(boost::bind(&core::check_block_rate, this));
|
||||||
m_miner.on_idle();
|
m_miner.on_idle();
|
||||||
m_mempool.on_idle();
|
m_mempool.on_idle();
|
||||||
return true;
|
return true;
|
||||||
|
@ -1683,6 +1684,52 @@ namespace cryptonote
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
//-----------------------------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------------------------
|
||||||
|
double factorial(unsigned int n)
|
||||||
|
{
|
||||||
|
if (n <= 1)
|
||||||
|
return 1.0;
|
||||||
|
double f = n;
|
||||||
|
while (n-- > 1)
|
||||||
|
f *= n;
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------------------------
|
||||||
|
static double probability(unsigned int blocks, unsigned int expected)
|
||||||
|
{
|
||||||
|
// https://www.umass.edu/wsp/resources/poisson/#computing
|
||||||
|
return pow(expected, blocks) / (factorial(blocks) * exp(expected));
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------------------------
|
||||||
|
bool core::check_block_rate()
|
||||||
|
{
|
||||||
|
if (m_offline || m_target_blockchain_height > get_current_blockchain_height())
|
||||||
|
{
|
||||||
|
MDEBUG("Not checking block rate, offline or syncing");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr double threshold = 1. / (864000 / DIFFICULTY_TARGET_V2); // one false positive every 10 days
|
||||||
|
|
||||||
|
const time_t now = time(NULL);
|
||||||
|
const std::vector<time_t> timestamps = m_blockchain_storage.get_last_block_timestamps(60);
|
||||||
|
|
||||||
|
static const unsigned int seconds[] = { 5400, 1800, 600 };
|
||||||
|
for (size_t n = 0; n < sizeof(seconds)/sizeof(seconds[0]); ++n)
|
||||||
|
{
|
||||||
|
unsigned int b = 0;
|
||||||
|
for (time_t ts: timestamps) b += ts >= now - seconds[n];
|
||||||
|
const double p = probability(b, seconds[n] / DIFFICULTY_TARGET_V2);
|
||||||
|
MDEBUG("blocks in the last " << seconds[n] / 60 << " minutes: " << b << " (probability " << p << ")");
|
||||||
|
if (p < threshold)
|
||||||
|
{
|
||||||
|
MWARNING("There were " << b << " blocks in the last " << seconds[n] / 60 << " minutes, there might be large hash rate changes, or we might be partitioned, cut off from the Monero network or under attack. Or it could be just sheer bad luck.");
|
||||||
|
break; // no need to look further
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//-----------------------------------------------------------------------------------------------
|
||||||
void core::set_target_blockchain_height(uint64_t target_blockchain_height)
|
void core::set_target_blockchain_height(uint64_t target_blockchain_height)
|
||||||
{
|
{
|
||||||
m_target_blockchain_height = target_blockchain_height;
|
m_target_blockchain_height = target_blockchain_height;
|
||||||
|
|
|
@ -946,6 +946,13 @@ namespace cryptonote
|
||||||
*/
|
*/
|
||||||
bool check_disk_space();
|
bool check_disk_space();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief checks block rate, and warns if it's too slow
|
||||||
|
*
|
||||||
|
* @return true on success, false otherwise
|
||||||
|
*/
|
||||||
|
bool check_block_rate();
|
||||||
|
|
||||||
bool m_test_drop_download = true; //!< whether or not to drop incoming blocks (for testing)
|
bool m_test_drop_download = true; //!< whether or not to drop incoming blocks (for testing)
|
||||||
|
|
||||||
uint64_t m_test_drop_download_height = 0; //!< height under which to drop incoming blocks, if doing so
|
uint64_t m_test_drop_download_height = 0; //!< height under which to drop incoming blocks, if doing so
|
||||||
|
@ -970,6 +977,7 @@ namespace cryptonote
|
||||||
epee::math_helper::once_a_time_seconds<60*2, false> m_txpool_auto_relayer; //!< interval for checking re-relaying txpool transactions
|
epee::math_helper::once_a_time_seconds<60*2, false> m_txpool_auto_relayer; //!< interval for checking re-relaying txpool transactions
|
||||||
epee::math_helper::once_a_time_seconds<60*60*12, true> m_check_updates_interval; //!< interval for checking for new versions
|
epee::math_helper::once_a_time_seconds<60*60*12, true> m_check_updates_interval; //!< interval for checking for new versions
|
||||||
epee::math_helper::once_a_time_seconds<60*10, true> m_check_disk_space_interval; //!< interval for checking for disk space
|
epee::math_helper::once_a_time_seconds<60*10, true> m_check_disk_space_interval; //!< interval for checking for disk space
|
||||||
|
epee::math_helper::once_a_time_seconds<90, false> m_block_rate_interval; //!< interval for checking block rate
|
||||||
|
|
||||||
std::atomic<bool> m_starter_message_showed; //!< has the "daemon will sync now" message been shown?
|
std::atomic<bool> m_starter_message_showed; //!< has the "daemon will sync now" message been shown?
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue