From 9b687c7873f297b23e643a43b09193d2bdb5e095 Mon Sep 17 00:00:00 2001
From: moneromooo-monero <moneromooo-monero@users.noreply.github.com>
Date: Tue, 26 Mar 2019 11:51:13 +0000
Subject: [PATCH 1/2] blockchain: simple cache for the long term block weights

---
 src/cryptonote_core/blockchain.cpp  | 22 ++++++++++++++++++++++
 src/cryptonote_core/blockchain.h    |  2 ++
 tests/block_weight/block_weight.cpp |  5 +++++
 3 files changed, 29 insertions(+)

diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp
index f5bd9bbb5..8346d5d00 100644
--- a/src/cryptonote_core/blockchain.cpp
+++ b/src/cryptonote_core/blockchain.cpp
@@ -178,6 +178,7 @@ Blockchain::Blockchain(tx_memory_pool& tx_pool) :
   m_enforce_dns_checkpoints(false), m_max_prepare_blocks_threads(4), m_db_sync_on_blocks(true), m_db_sync_threshold(1), m_db_sync_mode(db_async), m_db_default_sync(false), m_fast_sync(true), m_show_time_stats(false), m_sync_counter(0), m_bytes_to_sync(0), m_cancel(false),
   m_long_term_block_weights_window(CRYPTONOTE_LONG_TERM_BLOCK_WEIGHT_WINDOW_SIZE),
   m_long_term_effective_median_block_weight(0),
+  m_long_term_block_weights_cache_tip_hash(crypto::null_hash),
   m_difficulty_for_next_block_top_hash(crypto::null_hash),
   m_difficulty_for_next_block(1),
   m_btc_valid(false)
@@ -1279,7 +1280,28 @@ void Blockchain::get_long_term_block_weights(std::vector<uint64_t>& weights, uin
   LOG_PRINT_L3("Blockchain::" << __func__);
   CRITICAL_REGION_LOCAL(m_blockchain_lock);
 
+  if (count == 0)
+    return;
+
+  bool cached = false;
+  uint64_t blockchain_height = m_db->height();
+  uint64_t tip_height = start_height + count - 1;
+  crypto::hash tip_hash = crypto::null_hash;
+  if (tip_height < blockchain_height && count == m_long_term_block_weights_cache.size())
+  {
+    tip_hash = m_db->get_block_hash_from_height(tip_height);
+    cached = tip_hash == m_long_term_block_weights_cache_tip_hash;
+  }
+
+  if (cached)
+  {
+    weights = m_long_term_block_weights_cache;
+    return;
+  }
+
   weights = m_db->get_long_term_block_weights(start_height, count);
+  m_long_term_block_weights_cache = weights;
+  m_long_term_block_weights_cache_tip_hash = tip_hash;
 }
 //------------------------------------------------------------------
 uint64_t Blockchain::get_current_cumulative_block_weight_limit() const
diff --git a/src/cryptonote_core/blockchain.h b/src/cryptonote_core/blockchain.h
index 3b8169764..6b4d74cfe 100644
--- a/src/cryptonote_core/blockchain.h
+++ b/src/cryptonote_core/blockchain.h
@@ -1060,6 +1060,8 @@ namespace cryptonote
     uint64_t m_timestamps_and_difficulties_height;
     uint64_t m_long_term_block_weights_window;
     uint64_t m_long_term_effective_median_block_weight;
+    mutable crypto::hash m_long_term_block_weights_cache_tip_hash;
+    mutable std::vector<uint64_t> m_long_term_block_weights_cache;
 
     epee::critical_section m_difficulty_lock;
     crypto::hash m_difficulty_for_next_block_top_hash;
diff --git a/tests/block_weight/block_weight.cpp b/tests/block_weight/block_weight.cpp
index 1e8974b78..7b3fdfe57 100644
--- a/tests/block_weight/block_weight.cpp
+++ b/tests/block_weight/block_weight.cpp
@@ -84,6 +84,11 @@ public:
     while (count-- && start_height < blocks.size()) ret.push_back(blocks[start_height++].long_term_weight);
     return ret;
   }
+  virtual crypto::hash get_block_hash_from_height(const uint64_t &height) const override {
+    crypto::hash hash = crypto::null_hash;
+    *(uint64_t*)&hash = height;
+    return hash;
+  }
   virtual crypto::hash top_block_hash(uint64_t *block_height = NULL) const override {
     uint64_t h = height();
     crypto::hash top = crypto::null_hash;

From ae6885f6b4d426d17d55b8415074eead04450264 Mon Sep 17 00:00:00 2001
From: moneromooo-monero <moneromooo-monero@users.noreply.github.com>
Date: Tue, 26 Mar 2019 12:15:08 +0000
Subject: [PATCH 2/2] blockchain: incremental long term block weight cache

---
 src/cryptonote_core/blockchain.cpp | 22 ++++++++++++++++++++++
 1 file changed, 22 insertions(+)

diff --git a/src/cryptonote_core/blockchain.cpp b/src/cryptonote_core/blockchain.cpp
index 8346d5d00..0813ef698 100644
--- a/src/cryptonote_core/blockchain.cpp
+++ b/src/cryptonote_core/blockchain.cpp
@@ -1280,6 +1280,8 @@ void Blockchain::get_long_term_block_weights(std::vector<uint64_t>& weights, uin
   LOG_PRINT_L3("Blockchain::" << __func__);
   CRITICAL_REGION_LOCAL(m_blockchain_lock);
 
+  PERF_TIMER(get_long_term_block_weights);
+
   if (count == 0)
     return;
 
@@ -1295,10 +1297,30 @@ void Blockchain::get_long_term_block_weights(std::vector<uint64_t>& weights, uin
 
   if (cached)
   {
+    MTRACE("requesting " << count << " from " << start_height << ", cached");
     weights = m_long_term_block_weights_cache;
     return;
   }
 
+  // in the vast majority of uncached cases, most is still cached,
+  // as we just move the window one block up:
+  if (tip_height > 0 && count == m_long_term_block_weights_cache.size() && tip_height < blockchain_height)
+  {
+    crypto::hash old_tip_hash = m_db->get_block_hash_from_height(tip_height - 1);
+    if (old_tip_hash == m_long_term_block_weights_cache_tip_hash)
+    {
+      weights = m_long_term_block_weights_cache;
+      for (size_t i = 1; i < weights.size(); ++i)
+        weights[i - 1] = weights[i];
+      MTRACE("requesting " << count << " from " << start_height << ", incremental");
+      weights.back() = m_db->get_block_long_term_weight(tip_height);
+      m_long_term_block_weights_cache = weights;
+      m_long_term_block_weights_cache_tip_hash = tip_hash;
+      return;
+    }
+  }
+
+  MTRACE("requesting " << count << " from " << start_height << ", uncached");
   weights = m_db->get_long_term_block_weights(start_height, count);
   m_long_term_block_weights_cache = weights;
   m_long_term_block_weights_cache_tip_hash = tip_hash;