aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRiccardo Spagni <ric@spagni.net>2018-10-26 22:18:41 +0200
committerRiccardo Spagni <ric@spagni.net>2018-10-26 22:18:41 +0200
commit557c17e206c697174982d28636a29c149f07f630 (patch)
tree1c7766b3b639478d8582b3616568df0dd4e2fc25 /src
parentMerge pull request #4308 (diff)
parentcryptonote_core: warn when the block rate deviates from expectations (diff)
downloadmonero-557c17e206c697174982d28636a29c149f07f630.tar.xz
Merge pull request #4408
341b3931 cryptonote_core: warn when the block rate deviates from expectations (moneromooo-monero)
Diffstat (limited to '')
-rw-r--r--src/cryptonote_core/blockchain.cpp9
-rw-r--r--src/cryptonote_core/blockchain.h5
-rw-r--r--src/cryptonote_core/cryptonote_core.cpp47
-rw-r--r--src/cryptonote_core/cryptonote_core.h8
4 files changed, 69 insertions, 0 deletions
diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp
index 1ec2366e4..5c6819fa9 100644
--- a/src/cryptonote_core/blockchain.cpp
+++ b/src/cryptonote_core/blockchain.cpp
@@ -886,6 +886,15 @@ difficulty_type Blockchain::get_difficulty_for_next_block()
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
// position where the blockchain switch started and then re-adds the blocks
// that had been removed.
diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h
index ab66fac8b..8ebe7b5ce 100644
--- a/src/cryptonote_core/blockchain.h
+++ b/src/cryptonote_core/blockchain.h
@@ -952,6 +952,11 @@ namespace cryptonote
*/
void on_new_tx_from_block(const cryptonote::transaction &tx);
+ /**
+ * @brief returns the timestamps of the last N blocks
+ */
+ std::vector<time_t> get_last_block_timestamps(unsigned int blocks) const;
+
private:
// TODO: evaluate whether or not each of these typedefs are left over from blockchain_storage
diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp
index 2fec6b613..735309aa9 100644
--- a/src/cryptonote_core/cryptonote_core.cpp
+++ b/src/cryptonote_core/cryptonote_core.cpp
@@ -1494,6 +1494,7 @@ namespace cryptonote
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_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_mempool.on_idle();
return true;
@@ -1682,6 +1683,52 @@ namespace cryptonote
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)
{
m_target_blockchain_height = target_blockchain_height;
diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h
index 58fe5b7b5..225edc137 100644
--- a/src/cryptonote_core/cryptonote_core.h
+++ b/src/cryptonote_core/cryptonote_core.h
@@ -945,6 +945,13 @@ namespace cryptonote
*/
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)
uint64_t m_test_drop_download_height = 0; //!< height under which to drop incoming blocks, if doing so
@@ -969,6 +976,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*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<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?