mirror of
				https://git.wownero.com/wownero/onion-wownero-blockchain-explorer.git
				synced 2024-08-15 00:33:12 +00:00 
			
		
		
		
	Merge pull request #194 from moneroexamples/remove_caches
block and tx caches removed
This commit is contained in:
		
						commit
						69df5ef4b1
					
				
					 11 changed files with 87 additions and 880 deletions
				
			
		| 
						 | 
				
			
			@ -1,138 +0,0 @@
 | 
			
		|||
#ifndef CACHE_HPP
 | 
			
		||||
#define CACHE_HPP
 | 
			
		||||
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <limits>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <mutex>
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
#include "cache_policy.hpp"
 | 
			
		||||
 | 
			
		||||
namespace caches
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
// Base class for caching algorithms
 | 
			
		||||
template <typename Key, typename Value, typename Policy = NoCachePolicy<Key>>
 | 
			
		||||
class fixed_sized_cache
 | 
			
		||||
{
 | 
			
		||||
 public:
 | 
			
		||||
 | 
			
		||||
  using iterator = typename std::unordered_map<Key, Value>::iterator;
 | 
			
		||||
 | 
			
		||||
  using const_iterator =
 | 
			
		||||
      typename std::unordered_map<Key, Value>::const_iterator;
 | 
			
		||||
 | 
			
		||||
  using operation_guard = typename std::lock_guard<std::mutex>;
 | 
			
		||||
 | 
			
		||||
  fixed_sized_cache(
 | 
			
		||||
          size_t max_size,
 | 
			
		||||
          const Policy& policy = Policy())
 | 
			
		||||
      : max_cache_size{max_size},
 | 
			
		||||
        cache_policy(policy)
 | 
			
		||||
  {
 | 
			
		||||
    if (max_cache_size == 0)
 | 
			
		||||
    {
 | 
			
		||||
      max_cache_size = std::numeric_limits<size_t>::max();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void Put(const Key& key, const Value& value)
 | 
			
		||||
  {
 | 
			
		||||
    operation_guard{safe_op};
 | 
			
		||||
    auto elem_it = FindElem(key);
 | 
			
		||||
 | 
			
		||||
    if (elem_it == cache_items_map.end())
 | 
			
		||||
    {
 | 
			
		||||
      // add new element to the cache
 | 
			
		||||
      if (Size() + 1 > max_cache_size)
 | 
			
		||||
      {
 | 
			
		||||
        auto disp_candidate_key = cache_policy.ReplCandidate();
 | 
			
		||||
 | 
			
		||||
        Erase(disp_candidate_key);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      Insert(key, value);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
      // update previous value
 | 
			
		||||
      Update(key, value);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  bool Contains(const Key& key)
 | 
			
		||||
  {
 | 
			
		||||
    operation_guard{safe_op};
 | 
			
		||||
    auto elem_it = FindElem(key);
 | 
			
		||||
    return elem_it != cache_items_map.end();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const Value& Get(const Key& key) const
 | 
			
		||||
  {
 | 
			
		||||
    operation_guard{safe_op};
 | 
			
		||||
    auto elem_it = FindElem(key);
 | 
			
		||||
 | 
			
		||||
    if (elem_it == cache_items_map.end())
 | 
			
		||||
    {
 | 
			
		||||
      throw std::range_error{"No such element in the cache"};
 | 
			
		||||
    }
 | 
			
		||||
    cache_policy.Touch(key);
 | 
			
		||||
 | 
			
		||||
    return elem_it->second;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const size_t Size() const
 | 
			
		||||
  {
 | 
			
		||||
    operation_guard{safe_op};
 | 
			
		||||
 | 
			
		||||
    return cache_items_map.size();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // return a key of a displacement candidate
 | 
			
		||||
  void Clear()
 | 
			
		||||
  {
 | 
			
		||||
    operation_guard{safe_op};
 | 
			
		||||
 | 
			
		||||
    cache_policy.Clear();
 | 
			
		||||
    cache_items_map.clear();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 protected:
 | 
			
		||||
 | 
			
		||||
  void Insert(const Key& key, const Value& value)
 | 
			
		||||
  {
 | 
			
		||||
    cache_policy.Insert(key);
 | 
			
		||||
    cache_items_map.emplace(std::make_pair(key, value));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void Erase(const Key& key)
 | 
			
		||||
  {
 | 
			
		||||
    cache_policy.Erase(key);
 | 
			
		||||
    cache_items_map.erase(key);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void Update(const Key& key, const Value& value)
 | 
			
		||||
  {
 | 
			
		||||
    cache_policy.Touch(key);
 | 
			
		||||
    cache_items_map[key] = value;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const_iterator FindElem(const Key& key) const
 | 
			
		||||
  {
 | 
			
		||||
    return cache_items_map.find(key);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
 | 
			
		||||
  std::unordered_map<Key, Value> cache_items_map;
 | 
			
		||||
 | 
			
		||||
  mutable Policy cache_policy;
 | 
			
		||||
  mutable std::mutex safe_op;
 | 
			
		||||
 | 
			
		||||
  size_t max_cache_size;
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif  // CACHE_HPP
 | 
			
		||||
| 
						 | 
				
			
			@ -1,77 +0,0 @@
 | 
			
		|||
#ifndef CACHE_POLICY_HPP
 | 
			
		||||
#define CACHE_POLICY_HPP
 | 
			
		||||
 | 
			
		||||
#include <unordered_set>
 | 
			
		||||
 | 
			
		||||
namespace caches
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
template <typename Key>
 | 
			
		||||
 | 
			
		||||
class ICachePolicy
 | 
			
		||||
{
 | 
			
		||||
 public:
 | 
			
		||||
 | 
			
		||||
  virtual ~ICachePolicy() {}
 | 
			
		||||
 | 
			
		||||
  // handle element insertion in a cache
 | 
			
		||||
  virtual void Insert(const Key& key) = 0;
 | 
			
		||||
 | 
			
		||||
  // handle request to the key-element in a cache
 | 
			
		||||
  virtual void Touch(const Key& key) = 0;
 | 
			
		||||
 | 
			
		||||
  // handle element deletion from a cache
 | 
			
		||||
  virtual void Erase(const Key& key) = 0;
 | 
			
		||||
 | 
			
		||||
  // return a key of a replacement candidate
 | 
			
		||||
  virtual const Key& ReplCandidate() const = 0;
 | 
			
		||||
 | 
			
		||||
  // clear the cache
 | 
			
		||||
  virtual void Clear() = 0;
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
template <typename Key>
 | 
			
		||||
class NoCachePolicy : public ICachePolicy<Key>
 | 
			
		||||
{
 | 
			
		||||
 public:
 | 
			
		||||
 | 
			
		||||
  NoCachePolicy() = default;
 | 
			
		||||
 | 
			
		||||
  ~NoCachePolicy() override = default;
 | 
			
		||||
 | 
			
		||||
  void Insert(const Key& key) override
 | 
			
		||||
  {
 | 
			
		||||
    key_storage.emplace(key);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void Touch(const Key& key) override
 | 
			
		||||
  {
 | 
			
		||||
    // do not do anything
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void Erase(const Key& key) override
 | 
			
		||||
  {
 | 
			
		||||
    key_storage.erase(key);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // return a key of a displacement candidate
 | 
			
		||||
  const Key& ReplCandidate() const override
 | 
			
		||||
  {
 | 
			
		||||
    return *key_storage.crbegin();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // return a key of a displacement candidate
 | 
			
		||||
  void Clear() override
 | 
			
		||||
  {
 | 
			
		||||
    key_storage.clear();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 private:
 | 
			
		||||
 | 
			
		||||
  std::unordered_set<Key> key_storage;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
}  // namespace caches
 | 
			
		||||
 | 
			
		||||
#endif  // CACHE_POLICY_HPP
 | 
			
		||||
| 
						 | 
				
			
			@ -1,53 +0,0 @@
 | 
			
		|||
#ifndef FIFO_CACHE_POLICY_HPP
 | 
			
		||||
#define FIFO_CACHE_POLICY_HPP
 | 
			
		||||
 | 
			
		||||
#include <list>
 | 
			
		||||
#include "cache_policy.hpp"
 | 
			
		||||
 | 
			
		||||
namespace caches
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
template <typename Key>
 | 
			
		||||
class FIFOCachePolicy : public ICachePolicy<Key>
 | 
			
		||||
{
 | 
			
		||||
 public:
 | 
			
		||||
 | 
			
		||||
  FIFOCachePolicy() = default;
 | 
			
		||||
  ~FIFOCachePolicy() = default;
 | 
			
		||||
 | 
			
		||||
  void Insert(const Key& key) override
 | 
			
		||||
  {
 | 
			
		||||
    fifo_queue.emplace_front(key);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // handle request to the key-element in a cache
 | 
			
		||||
  void Touch(const Key& key) override
 | 
			
		||||
  {
 | 
			
		||||
    // nothing to do here in the FIFO strategy
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // handle element deletion from a cache
 | 
			
		||||
  void Erase(const Key& key) override
 | 
			
		||||
  {
 | 
			
		||||
    fifo_queue.pop_back();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // return a key of a replacement candidate
 | 
			
		||||
  const Key& ReplCandidate() const override
 | 
			
		||||
  {
 | 
			
		||||
    return fifo_queue.back();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // return a key of a displacement candidate
 | 
			
		||||
  void Clear() override
 | 
			
		||||
  {
 | 
			
		||||
    fifo_queue.clear();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
 | 
			
		||||
  std::list<Key> fifo_queue;
 | 
			
		||||
};
 | 
			
		||||
} // namespace caches
 | 
			
		||||
 | 
			
		||||
#endif // FIFO_CACHE_POLICY_HPP
 | 
			
		||||
| 
						 | 
				
			
			@ -1,76 +0,0 @@
 | 
			
		|||
#ifndef LFU_CACHE_POLICY_HPP
 | 
			
		||||
#define LFU_CACHE_POLICY_HPP
 | 
			
		||||
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
#include <map>
 | 
			
		||||
#include <iostream>
 | 
			
		||||
#include "cache_policy.hpp"
 | 
			
		||||
 | 
			
		||||
namespace caches
 | 
			
		||||
{
 | 
			
		||||
template <typename Key>
 | 
			
		||||
class LFUCachePolicy : public ICachePolicy<Key>
 | 
			
		||||
{
 | 
			
		||||
 public:
 | 
			
		||||
 | 
			
		||||
  using lfu_iterator = typename std::multimap<std::size_t, Key>::iterator;
 | 
			
		||||
 | 
			
		||||
  LFUCachePolicy() = default;
 | 
			
		||||
 | 
			
		||||
  ~LFUCachePolicy() override = default;
 | 
			
		||||
 | 
			
		||||
  void Insert(const Key& key) override
 | 
			
		||||
  {
 | 
			
		||||
    constexpr std::size_t INIT_VAL = 1;
 | 
			
		||||
 | 
			
		||||
    // all new value initialized with the frequency 1
 | 
			
		||||
    lfu_storage[key] = frequency_storage.emplace_hint(
 | 
			
		||||
            frequency_storage.cbegin(), INIT_VAL, key);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void Touch(const Key& key) override
 | 
			
		||||
  {
 | 
			
		||||
    // get the previous frequency value of a key
 | 
			
		||||
    auto elem_for_update = lfu_storage[key];
 | 
			
		||||
 | 
			
		||||
    auto updated_elem = std::make_pair(
 | 
			
		||||
            elem_for_update->first + 1, elem_for_update->second);
 | 
			
		||||
 | 
			
		||||
    // update the previous value
 | 
			
		||||
    frequency_storage.erase(elem_for_update);
 | 
			
		||||
 | 
			
		||||
    lfu_storage[key] = frequency_storage.emplace_hint(
 | 
			
		||||
            frequency_storage.cend(), std::move(updated_elem));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  void Erase(const Key& key) override
 | 
			
		||||
  {
 | 
			
		||||
    frequency_storage.erase(lfu_storage[key]);
 | 
			
		||||
    lfu_storage.erase(key);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const Key& ReplCandidate() const override
 | 
			
		||||
  {
 | 
			
		||||
    // at the beginning of the frequency_storage we have the
 | 
			
		||||
    // least frequency used value
 | 
			
		||||
    return frequency_storage.cbegin()->second;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // return a key of a displacement candidate
 | 
			
		||||
  void Clear() override
 | 
			
		||||
  {
 | 
			
		||||
    frequency_storage.clear();
 | 
			
		||||
    lfu_storage.clear();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 private:
 | 
			
		||||
 | 
			
		||||
  std::multimap<std::size_t, Key> frequency_storage;
 | 
			
		||||
 | 
			
		||||
  std::unordered_map<Key, lfu_iterator> lfu_storage;
 | 
			
		||||
};
 | 
			
		||||
} // namespace caches
 | 
			
		||||
 | 
			
		||||
#endif // LFU_CACHE_POLICY_HPP
 | 
			
		||||
| 
						 | 
				
			
			@ -1,63 +0,0 @@
 | 
			
		|||
#ifndef LRU_CACHE_POLICY_HPP
 | 
			
		||||
#define LRU_CACHE_POLICY_HPP
 | 
			
		||||
 | 
			
		||||
#include <list>
 | 
			
		||||
#include <unordered_map>
 | 
			
		||||
#include "cache_policy.hpp"
 | 
			
		||||
 | 
			
		||||
namespace caches
 | 
			
		||||
{
 | 
			
		||||
template <typename Key>
 | 
			
		||||
class LRUCachePolicy : public ICachePolicy<Key>
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
 public:
 | 
			
		||||
 | 
			
		||||
  using lru_iterator = typename std::list<Key>::const_iterator;
 | 
			
		||||
  
 | 
			
		||||
  LRUCachePolicy() = default;
 | 
			
		||||
  ~LRUCachePolicy() = default;
 | 
			
		||||
  
 | 
			
		||||
  void Insert(const Key& key) override
 | 
			
		||||
  {
 | 
			
		||||
    lru_queue.emplace_front(key);
 | 
			
		||||
    key_finder[key] = lru_queue.cbegin();
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  void Touch(const Key& key) override
 | 
			
		||||
  {
 | 
			
		||||
    // move the touched element at the beginning of the lru_queue 
 | 
			
		||||
    lru_queue.splice(lru_queue.cbegin(), lru_queue, key_finder[key]);
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  void Erase(const Key& key) override
 | 
			
		||||
  {
 | 
			
		||||
    // remove the least recently used element
 | 
			
		||||
    key_finder.erase(lru_queue.back());
 | 
			
		||||
 | 
			
		||||
    lru_queue.pop_back();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // return a key of a displacement candidate
 | 
			
		||||
  const Key& ReplCandidate() const override
 | 
			
		||||
  {
 | 
			
		||||
    return lru_queue.back();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // return a key of a displacement candidate
 | 
			
		||||
  void Clear() override
 | 
			
		||||
  {
 | 
			
		||||
      lru_queue.clear();
 | 
			
		||||
      key_finder.clear();
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
 private:
 | 
			
		||||
 | 
			
		||||
  std::list<Key> lru_queue;
 | 
			
		||||
 | 
			
		||||
  std::unordered_map<Key, lru_iterator> key_finder; 
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace caches
 | 
			
		||||
 | 
			
		||||
#endif // LRU_CACHE_POLICY_HPP
 | 
			
		||||
							
								
								
									
										10
									
								
								main.cpp
									
										
									
									
									
								
							
							
						
						
									
										10
									
								
								main.cpp
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -41,6 +41,7 @@ struct jsonresponse: public crow::response
 | 
			
		|||
int
 | 
			
		||||
main(int ac, const char* av[])
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
    // get command line options
 | 
			
		||||
    xmreg::CmdLineOptions opts {ac, av};
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -73,10 +74,7 @@ main(int ac, const char* av[])
 | 
			
		|||
    auto enable_mixin_details_opt      = opts.get_option<bool>("enable-mixin-details");
 | 
			
		||||
    auto enable_json_api_opt           = opts.get_option<bool>("enable-json-api");
 | 
			
		||||
    auto enable_as_hex_opt             = opts.get_option<bool>("enable-as-hex");
 | 
			
		||||
    auto enable_tx_cache_opt           = opts.get_option<bool>("enable-tx-cache");
 | 
			
		||||
    auto concurrency_opt               = opts.get_option<size_t>("concurrency");
 | 
			
		||||
    auto enable_block_cache_opt        = opts.get_option<bool>("enable-block-cache");
 | 
			
		||||
    auto show_cache_times_opt          = opts.get_option<bool>("show-cache-times");
 | 
			
		||||
    auto enable_emission_monitor_opt   = opts.get_option<bool>("enable-emission-monitor");
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -101,10 +99,7 @@ main(int ac, const char* av[])
 | 
			
		|||
    bool enable_mixin_details         {*enable_mixin_details_opt};
 | 
			
		||||
    bool enable_json_api              {*enable_json_api_opt};
 | 
			
		||||
    bool enable_as_hex                {*enable_as_hex_opt};
 | 
			
		||||
    bool enable_tx_cache              {*enable_tx_cache_opt};
 | 
			
		||||
    bool enable_block_cache           {*enable_block_cache_opt};
 | 
			
		||||
    bool enable_emission_monitor      {*enable_emission_monitor_opt};
 | 
			
		||||
    bool show_cache_times             {*show_cache_times_opt};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // set  monero log output level
 | 
			
		||||
| 
						 | 
				
			
			@ -279,9 +274,6 @@ main(int ac, const char* av[])
 | 
			
		|||
                          enable_output_key_checker,
 | 
			
		||||
                          enable_autorefresh_option,
 | 
			
		||||
                          enable_mixin_details,
 | 
			
		||||
                          enable_tx_cache,
 | 
			
		||||
                          enable_block_cache,
 | 
			
		||||
                          show_cache_times,
 | 
			
		||||
                          no_blocks_on_index,
 | 
			
		||||
                          mempool_info_timeout,
 | 
			
		||||
                          *testnet_url,
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -37,12 +37,6 @@ namespace xmreg
 | 
			
		|||
                 "enable outputs key file checker")
 | 
			
		||||
                ("enable-json-api", value<bool>()->default_value(false)->implicit_value(true),
 | 
			
		||||
                 "enable JSON REST api")
 | 
			
		||||
                ("enable-tx-cache", value<bool>()->default_value(false)->implicit_value(true),
 | 
			
		||||
                 "enable caching of transaction details")
 | 
			
		||||
                ("show-cache-times", value<bool>()->default_value(false)->implicit_value(true),
 | 
			
		||||
                 "show times of getting data from cache vs no cache")
 | 
			
		||||
                ("enable-block-cache", value<bool>()->default_value(false)->implicit_value(true),
 | 
			
		||||
                 "enable caching of block details")
 | 
			
		||||
                ("enable-as-hex", value<bool>()->default_value(false)->implicit_value(true),
 | 
			
		||||
                 "enable links to provide hex represtations of a tx and a block")
 | 
			
		||||
                ("enable-autorefresh-option", value<bool>()->default_value(false)->implicit_value(true),
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -137,13 +137,31 @@ MicroCore::get_tx(const crypto::hash& tx_hash, transaction& tx)
 | 
			
		|||
    if (m_blockchain_storage.have_tx(tx_hash))
 | 
			
		||||
    {
 | 
			
		||||
        // get transaction with given hash
 | 
			
		||||
        tx = m_blockchain_storage.get_db().get_tx(tx_hash);
 | 
			
		||||
        try
 | 
			
		||||
        {
 | 
			
		||||
            tx = m_blockchain_storage.get_db().get_tx(tx_hash);
 | 
			
		||||
        }
 | 
			
		||||
        catch (TX_DNE const& e)
 | 
			
		||||
        {
 | 
			
		||||
            try 
 | 
			
		||||
            {
 | 
			
		||||
                // coinbase txs are not considered pruned
 | 
			
		||||
                tx = m_blockchain_storage.get_db().get_pruned_tx(tx_hash);
 | 
			
		||||
                return true;
 | 
			
		||||
            }
 | 
			
		||||
            catch (TX_DNE const& e)
 | 
			
		||||
            {
 | 
			
		||||
                cerr << "MicroCore::get_tx: " << e.what() << endl;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        cerr << "MicroCore::get_tx tx does not exist in blockchain: " << tx_hash << endl;
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
    }     
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    return true;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										497
									
								
								src/page.h
									
										
									
									
									
								
							
							
						
						
									
										497
									
								
								src/page.h
									
										
									
									
									
								
							| 
						 | 
				
			
			@ -31,9 +31,6 @@
 | 
			
		|||
 | 
			
		||||
#include "../ext/json.hpp"
 | 
			
		||||
 | 
			
		||||
#include "../ext/vpetrigocaches/cache.hpp"
 | 
			
		||||
#include "../ext/vpetrigocaches/lru_cache_policy.hpp"
 | 
			
		||||
#include "../ext/vpetrigocaches/fifo_cache_policy.hpp"
 | 
			
		||||
#include "../ext/mstch/src/visitor/render_node.hpp"
 | 
			
		||||
 | 
			
		||||
extern "C" uint64_t me_rx_seedheight(const uint64_t height);
 | 
			
		||||
| 
						 | 
				
			
			@ -85,31 +82,6 @@ extern  __thread randomx_vm *rx_vm;
 | 
			
		|||
    MAKE_ONIONEXPLORER_RPC_VERSION(ONIONEXPLORER_RPC_VERSION_MAJOR, ONIONEXPLORER_RPC_VERSION_MINOR)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// basic info about tx to be stored in cashe.
 | 
			
		||||
// we need to store block_no and timestamp,
 | 
			
		||||
// as this time and number of confirmation needs
 | 
			
		||||
// to be updated between requests. Just cant
 | 
			
		||||
// get it from cash, as it will be old very soon
 | 
			
		||||
struct tx_info_cache
 | 
			
		||||
{
 | 
			
		||||
    uint64_t   block_no;
 | 
			
		||||
    uint64_t   timestamp;
 | 
			
		||||
    mstch::map tx_map;
 | 
			
		||||
 | 
			
		||||
    // custom key for use in cache.
 | 
			
		||||
    // cache uses unordeded map for keys
 | 
			
		||||
    struct key
 | 
			
		||||
    {
 | 
			
		||||
        crypto::hash tx_hash;
 | 
			
		||||
        bool detailed;
 | 
			
		||||
 | 
			
		||||
        bool operator==(const key &other) const
 | 
			
		||||
        {
 | 
			
		||||
            return (tx_hash == other.tx_hash && detailed == other.detailed);
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// helper to ignore any number of template parametrs
 | 
			
		||||
template<typename...> using VoidT = void;
 | 
			
		||||
| 
						 | 
				
			
			@ -147,22 +119,6 @@ struct OutputIndicesReturnVectOfVectT<
 | 
			
		|||
    >>: std::true_type 
 | 
			
		||||
{};
 | 
			
		||||
 | 
			
		||||
// indect overload of hash for tx_info_cache::key
 | 
			
		||||
namespace std
 | 
			
		||||
{
 | 
			
		||||
    template<>
 | 
			
		||||
    struct hash<tx_info_cache::key>
 | 
			
		||||
    {
 | 
			
		||||
        size_t operator()(const tx_info_cache::key& k) const
 | 
			
		||||
        {
 | 
			
		||||
            size_t const h1 ( std::hash<crypto::hash>{}(k.tx_hash) );
 | 
			
		||||
            size_t const h2 ( std::hash<bool>{}(k.detailed) );
 | 
			
		||||
            return h1 ^ (h2 << 1);
 | 
			
		||||
        };
 | 
			
		||||
    };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * visitor to produce json representations of
 | 
			
		||||
| 
						 | 
				
			
			@ -521,15 +477,10 @@ bool enable_pusher;
 | 
			
		|||
bool enable_key_image_checker;
 | 
			
		||||
bool enable_output_key_checker;
 | 
			
		||||
bool enable_mixins_details;
 | 
			
		||||
bool enable_tx_cache;
 | 
			
		||||
bool enable_block_cache;
 | 
			
		||||
bool enable_as_hex;
 | 
			
		||||
bool show_cache_times;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
bool enable_autorefresh_option;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
uint64_t no_of_mempool_tx_of_frontpage;
 | 
			
		||||
uint64_t no_blocks_on_index;
 | 
			
		||||
uint64_t mempool_info_timeout;
 | 
			
		||||
| 
						 | 
				
			
			@ -548,24 +499,6 @@ string js_html_files_all_in_one;
 | 
			
		|||
// read operation in OS
 | 
			
		||||
map<string, string> template_file;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// alias for easy class typing
 | 
			
		||||
template <typename Key, typename Value>
 | 
			
		||||
using lru_cache_t = caches::fixed_sized_cache<Key, Value, caches::LRUCachePolicy<Key>>;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// alias for easy class typing
 | 
			
		||||
template <typename Key, typename Value>
 | 
			
		||||
using fifo_cache_t = caches::fixed_sized_cache<Key, Value, caches::FIFOCachePolicy<Key>>;
 | 
			
		||||
 | 
			
		||||
// cache of txs_map of txs in blocks. this is useful for
 | 
			
		||||
// index2 page, so that we dont parse txs in each block
 | 
			
		||||
// for each request.
 | 
			
		||||
fifo_cache_t<uint64_t, vector<pair<crypto::hash, mstch::node>>> block_tx_cache;
 | 
			
		||||
 | 
			
		||||
lru_cache_t<tx_info_cache::key, tx_info_cache> tx_context_cache;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
 | 
			
		||||
page(MicroCore* _mcore,
 | 
			
		||||
| 
						 | 
				
			
			@ -578,9 +511,6 @@ page(MicroCore* _mcore,
 | 
			
		|||
     bool _enable_output_key_checker,
 | 
			
		||||
     bool _enable_autorefresh_option,
 | 
			
		||||
     bool _enable_mixins_details,
 | 
			
		||||
     bool _enable_tx_cache,
 | 
			
		||||
     bool _enable_block_cache,
 | 
			
		||||
     bool _show_cache_times,
 | 
			
		||||
     uint64_t _no_blocks_on_index,
 | 
			
		||||
     uint64_t _mempool_info_timeout,
 | 
			
		||||
     string _testnet_url,
 | 
			
		||||
| 
						 | 
				
			
			@ -597,16 +527,11 @@ page(MicroCore* _mcore,
 | 
			
		|||
          enable_output_key_checker {_enable_output_key_checker},
 | 
			
		||||
          enable_autorefresh_option {_enable_autorefresh_option},
 | 
			
		||||
          enable_mixins_details {_enable_mixins_details},
 | 
			
		||||
          enable_tx_cache {_enable_tx_cache},
 | 
			
		||||
          enable_block_cache {_enable_block_cache},
 | 
			
		||||
          show_cache_times {_show_cache_times},
 | 
			
		||||
          no_blocks_on_index {_no_blocks_on_index},
 | 
			
		||||
          mempool_info_timeout {_mempool_info_timeout},
 | 
			
		||||
          testnet_url {_testnet_url},
 | 
			
		||||
          stagenet_url {_stagenet_url},
 | 
			
		||||
          mainnet_url {_mainnet_url},
 | 
			
		||||
          block_tx_cache(200),
 | 
			
		||||
          tx_context_cache(1000)
 | 
			
		||||
          mainnet_url {_mainnet_url}
 | 
			
		||||
{
 | 
			
		||||
    mainnet = nettype == cryptonote::network_type::MAINNET;
 | 
			
		||||
    testnet = nettype == cryptonote::network_type::TESTNET;
 | 
			
		||||
| 
						 | 
				
			
			@ -705,8 +630,7 @@ index2(uint64_t page_no = 0, bool refresh_page = false)
 | 
			
		|||
            {"enable_pusher"            , enable_pusher},
 | 
			
		||||
            {"enable_key_image_checker" , enable_key_image_checker},
 | 
			
		||||
            {"enable_output_key_checker", enable_output_key_checker},
 | 
			
		||||
            {"enable_autorefresh_option", enable_autorefresh_option},
 | 
			
		||||
            {"show_cache_times"         , show_cache_times}
 | 
			
		||||
            {"enable_autorefresh_option", enable_autorefresh_option}
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    context.emplace("txs", mstch::array()); // will keep tx to show
 | 
			
		||||
| 
						 | 
				
			
			@ -724,12 +648,6 @@ index2(uint64_t page_no = 0, bool refresh_page = false)
 | 
			
		|||
 | 
			
		||||
    vector<double> blk_sizes;
 | 
			
		||||
 | 
			
		||||
    // measure time of cache based execution, and non-cached execution
 | 
			
		||||
    double duration_cached     {0.0};
 | 
			
		||||
    double duration_non_cached {0.0};
 | 
			
		||||
    uint64_t cache_hits   {0};
 | 
			
		||||
    uint64_t cache_misses {0};
 | 
			
		||||
 | 
			
		||||
    // loop index
 | 
			
		||||
    int64_t i = end_height;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -764,193 +682,67 @@ index2(uint64_t page_no = 0, bool refresh_page = false)
 | 
			
		|||
 | 
			
		||||
        context["age_format"] = age.second;
 | 
			
		||||
 | 
			
		||||
        // start measure time here
 | 
			
		||||
        auto start = std::chrono::steady_clock::now();
 | 
			
		||||
 | 
			
		||||
        if (enable_block_cache && block_tx_cache.Contains(i))
 | 
			
		||||
        // get all transactions in the block found
 | 
			
		||||
        // initialize the first list with transaction for solving
 | 
			
		||||
        // the block i.e. coinbase.
 | 
			
		||||
        vector<cryptonote::transaction> blk_txs {blk.miner_tx};
 | 
			
		||||
        vector<crypto::hash> missed_txs;
 | 
			
		||||
 | 
			
		||||
        if (!core_storage->get_transactions(blk.tx_hashes, blk_txs, missed_txs))
 | 
			
		||||
        {
 | 
			
		||||
            // get txs info in the ith block from
 | 
			
		||||
            // our cache
 | 
			
		||||
 | 
			
		||||
            // start measure time here
 | 
			
		||||
            auto start = std::chrono::steady_clock::now();
 | 
			
		||||
 | 
			
		||||
            const vector<pair<crypto::hash, mstch::node>>& txd_pairs
 | 
			
		||||
                    = block_tx_cache.Get(i);
 | 
			
		||||
 | 
			
		||||
            // copy tx maps from txs_maps_tmp into txs array,
 | 
			
		||||
            // that will go to templates
 | 
			
		||||
            for (const pair<crypto::hash, mstch::node>& txd_pair: txd_pairs)
 | 
			
		||||
            {
 | 
			
		||||
                // we need to check if the given transaction is still
 | 
			
		||||
                // in the same block as when it was cached. it is possible
 | 
			
		||||
                // the block got orphaned, and this tx is in mempool
 | 
			
		||||
                // or different block, and what we have in cache
 | 
			
		||||
                // is thus wrong
 | 
			
		||||
 | 
			
		||||
                // but we do this only for first top blocks. no sense
 | 
			
		||||
                // doing it for all blocks
 | 
			
		||||
 | 
			
		||||
                bool is_tx_still_in_block_as_expected {true};
 | 
			
		||||
 | 
			
		||||
                if (i + CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE > height)
 | 
			
		||||
                {
 | 
			
		||||
                    const crypto::hash& tx_hash = txd_pair.first;
 | 
			
		||||
 | 
			
		||||
                    if (core_storage->have_tx(tx_hash))
 | 
			
		||||
                    {
 | 
			
		||||
                        try
 | 
			
		||||
                        {
 | 
			
		||||
                            uint64_t tx_height_in_blockchain =
 | 
			
		||||
                                    core_storage->get_db().get_tx_block_height(tx_hash);
 | 
			
		||||
 | 
			
		||||
                            // check if height of the given tx that we have in cache,
 | 
			
		||||
                            // denoted by i, is same as what is acctually stored
 | 
			
		||||
                            // in blockchain
 | 
			
		||||
                            if (tx_height_in_blockchain == i)
 | 
			
		||||
                            {
 | 
			
		||||
                                is_tx_still_in_block_as_expected = true;
 | 
			
		||||
                            }
 | 
			
		||||
                            else
 | 
			
		||||
                            {
 | 
			
		||||
                                // if no tx in the given block, just stop
 | 
			
		||||
                                // any futher search. no need. we are going
 | 
			
		||||
                                // to ditch the cache, in a monent
 | 
			
		||||
                                is_tx_still_in_block_as_expected = false;
 | 
			
		||||
                                break;
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        catch (const TX_DNE& e)
 | 
			
		||||
                        {
 | 
			
		||||
                            cerr << "Tx from cache" << pod_to_hex(tx_hash)
 | 
			
		||||
                                 << " is no longer in the blockchain "
 | 
			
		||||
                                 << endl;
 | 
			
		||||
 | 
			
		||||
                            is_tx_still_in_block_as_expected = false;
 | 
			
		||||
                            break;
 | 
			
		||||
                        }
 | 
			
		||||
                    }
 | 
			
		||||
                    else
 | 
			
		||||
                    {
 | 
			
		||||
                        is_tx_still_in_block_as_expected = false;
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                } // if (i + CRYPTONOTE_DEFAULT_TX_SPENDABLE_AGE > height)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                if (!is_tx_still_in_block_as_expected)
 | 
			
		||||
                {
 | 
			
		||||
                    // if some tx in cache is not in blockchain
 | 
			
		||||
                    // where it should be, its probably better to
 | 
			
		||||
                    // ditch entire cache, as redo it below.
 | 
			
		||||
 | 
			
		||||
                    block_tx_cache.Clear();
 | 
			
		||||
                    txs.clear();
 | 
			
		||||
                    i = end_height;
 | 
			
		||||
                    continue; // reado the main loop
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                // if we got to here, it means that everything went fine
 | 
			
		||||
                // and no unexpeced things happended.
 | 
			
		||||
                mstch::map txd_map = boost::get<mstch::map>(txd_pair.second);
 | 
			
		||||
 | 
			
		||||
                // now we need to update age of txs from cashe
 | 
			
		||||
                if (!boost::get<string>(txd_map["age"]).empty())
 | 
			
		||||
                {
 | 
			
		||||
                    txd_map["age"] = age.first;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                txs.push_back(txd_map);
 | 
			
		||||
 | 
			
		||||
            }  // for (const pair<crypto::hash, mstch::map>& txd_pair: txd_pairs)
 | 
			
		||||
 | 
			
		||||
            auto duration = std::chrono::duration_cast<std::chrono::microseconds>
 | 
			
		||||
                    (std::chrono::steady_clock::now() - start);
 | 
			
		||||
 | 
			
		||||
            // cout << "block_tx_json_cache from cache" << endl;
 | 
			
		||||
 | 
			
		||||
            duration_cached += duration.count();
 | 
			
		||||
 | 
			
		||||
            ++cache_hits;
 | 
			
		||||
            cerr << "Cant get transactions in block: " << i << endl;
 | 
			
		||||
            --i;
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
 | 
			
		||||
        uint64_t tx_i {0};
 | 
			
		||||
 | 
			
		||||
        //          tx_hash     , txd_map
 | 
			
		||||
        vector<pair<crypto::hash, mstch::node>> txd_pairs;
 | 
			
		||||
 | 
			
		||||
        for(auto it = blk_txs.begin(); it != blk_txs.end(); ++it)
 | 
			
		||||
        {
 | 
			
		||||
            // this is new block. not in cashe.
 | 
			
		||||
            // need to process its txs and add to cache
 | 
			
		||||
            const cryptonote::transaction& tx = *it;
 | 
			
		||||
 | 
			
		||||
            // start measure time here
 | 
			
		||||
            auto start = std::chrono::steady_clock::now();
 | 
			
		||||
            const tx_details& txd = get_tx_details(tx, false, i, height);
 | 
			
		||||
 | 
			
		||||
            // get all transactions in the block found
 | 
			
		||||
            // initialize the first list with transaction for solving
 | 
			
		||||
            // the block i.e. coinbase.
 | 
			
		||||
            vector<cryptonote::transaction> blk_txs {blk.miner_tx};
 | 
			
		||||
            vector<crypto::hash> missed_txs;
 | 
			
		||||
            mstch::map txd_map = txd.get_mstch_map();
 | 
			
		||||
 | 
			
		||||
            if (!core_storage->get_transactions(blk.tx_hashes, blk_txs, missed_txs))
 | 
			
		||||
            //add age to the txd mstch map
 | 
			
		||||
            txd_map.insert({"height"    , i});
 | 
			
		||||
            txd_map.insert({"blk_hash"  , blk_hash_str});
 | 
			
		||||
            txd_map.insert({"age"       , age.first});
 | 
			
		||||
            txd_map.insert({"is_ringct" , (tx.version > 1)});
 | 
			
		||||
            txd_map.insert({"rct_type"  , tx.rct_signatures.type});
 | 
			
		||||
            txd_map.insert({"blk_size"  , blk_size_str});
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            // do not show block info for other than first tx in a block
 | 
			
		||||
            if (tx_i > 0)
 | 
			
		||||
            {
 | 
			
		||||
                cerr << "Cant get transactions in block: " << i << endl;
 | 
			
		||||
                --i;
 | 
			
		||||
                continue;
 | 
			
		||||
                txd_map["height"]     = string("");
 | 
			
		||||
                txd_map["age"]        = string("");
 | 
			
		||||
                txd_map["blk_size"]   = string("");
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            uint64_t tx_i {0};
 | 
			
		||||
            txd_pairs.emplace_back(txd.hash, txd_map);
 | 
			
		||||
 | 
			
		||||
            // this vector will go into block_tx cache
 | 
			
		||||
            //          tx_hash     , txd_map
 | 
			
		||||
            vector<pair<crypto::hash, mstch::node>> txd_pairs;
 | 
			
		||||
            ++tx_i;
 | 
			
		||||
 | 
			
		||||
            for(auto it = blk_txs.begin(); it != blk_txs.end(); ++it)
 | 
			
		||||
            {
 | 
			
		||||
                const cryptonote::transaction& tx = *it;
 | 
			
		||||
        } // for(list<cryptonote::transaction>::reverse_iterator rit = blk_txs.rbegin();
 | 
			
		||||
 | 
			
		||||
                const tx_details& txd = get_tx_details(tx, false, i, height);
 | 
			
		||||
        // copy tx maps from txs_maps_tmp into txs array,
 | 
			
		||||
        // that will go to templates
 | 
			
		||||
        for (const pair<crypto::hash, mstch::node>& txd_pair: txd_pairs)
 | 
			
		||||
        {
 | 
			
		||||
            txs.push_back(boost::get<mstch::map>(txd_pair.second));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
                mstch::map txd_map = txd.get_mstch_map();
 | 
			
		||||
 | 
			
		||||
                //add age to the txd mstch map
 | 
			
		||||
                txd_map.insert({"height"    , i});
 | 
			
		||||
                txd_map.insert({"blk_hash"  , blk_hash_str});
 | 
			
		||||
                txd_map.insert({"age"       , age.first});
 | 
			
		||||
                txd_map.insert({"is_ringct" , (tx.version > 1)});
 | 
			
		||||
                txd_map.insert({"rct_type"  , tx.rct_signatures.type});
 | 
			
		||||
                txd_map.insert({"blk_size"  , blk_size_str});
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
                // do not show block info for other than first tx in a block
 | 
			
		||||
                if (tx_i > 0)
 | 
			
		||||
                {
 | 
			
		||||
                    txd_map["height"]     = string("");
 | 
			
		||||
                    txd_map["age"]        = string("");
 | 
			
		||||
                    txd_map["blk_size"]   = string("");
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                txd_pairs.emplace_back(txd.hash, txd_map);
 | 
			
		||||
 | 
			
		||||
                ++tx_i;
 | 
			
		||||
 | 
			
		||||
            } // for(list<cryptonote::transaction>::reverse_iterator rit = blk_txs.rbegin();
 | 
			
		||||
 | 
			
		||||
            // copy tx maps from txs_maps_tmp into txs array,
 | 
			
		||||
            // that will go to templates
 | 
			
		||||
            for (const pair<crypto::hash, mstch::node>& txd_pair: txd_pairs)
 | 
			
		||||
            {
 | 
			
		||||
                txs.push_back(boost::get<mstch::map>(txd_pair.second));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            auto duration = std::chrono::duration_cast<std::chrono::microseconds>
 | 
			
		||||
                    (std::chrono::steady_clock::now() - start);
 | 
			
		||||
 | 
			
		||||
            duration_non_cached += duration.count();
 | 
			
		||||
 | 
			
		||||
            ++cache_misses;
 | 
			
		||||
 | 
			
		||||
            if (enable_block_cache)
 | 
			
		||||
            {
 | 
			
		||||
                // save in block_tx cache
 | 
			
		||||
                block_tx_cache.Put(i, txd_pairs);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        } // else if (block_tx_json_cache.Contains(i))
 | 
			
		||||
        auto duration = std::chrono::duration_cast<std::chrono::microseconds>
 | 
			
		||||
                (std::chrono::steady_clock::now() - start);
 | 
			
		||||
 | 
			
		||||
        --i; // go to next block number
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -959,30 +751,20 @@ index2(uint64_t page_no = 0, bool refresh_page = false)
 | 
			
		|||
    // calculate median size of the blocks shown
 | 
			
		||||
    //double blk_size_median = xmreg::calc_median(blk_sizes.begin(), blk_sizes.end());
 | 
			
		||||
 | 
			
		||||
    // save computational times for disply in the frontend
 | 
			
		||||
 | 
			
		||||
    context["construction_time_cached"] = fmt::format(
 | 
			
		||||
            "{:0.4f}", duration_cached/1.0e6);
 | 
			
		||||
 | 
			
		||||
    context["construction_time_non_cached"] = fmt::format(
 | 
			
		||||
            "{:0.4f}", duration_non_cached/1.0e6);
 | 
			
		||||
 | 
			
		||||
    context["construction_time_total"] = fmt::format(
 | 
			
		||||
            "{:0.4f}", (duration_non_cached+duration_cached)/1.0e6);
 | 
			
		||||
 | 
			
		||||
    context["cache_hits"]   = cache_hits;
 | 
			
		||||
    context["cache_misses"] = cache_misses;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    // get current network info from MemoryStatus thread.
 | 
			
		||||
    MempoolStatus::network_info current_network_info
 | 
			
		||||
        = MempoolStatus::current_network_info;
 | 
			
		||||
 | 
			
		||||
    // perapre network info mstch::map for the front page
 | 
			
		||||
    string hash_rate;
 | 
			
		||||
 | 
			
		||||
    double hr_d;
 | 
			
		||||
    char metric_prefix;
 | 
			
		||||
    cryptonote::difficulty_type hr = make_difficulty(current_network_info.hash_rate, current_network_info.hash_rate_top64);
 | 
			
		||||
 | 
			
		||||
    cryptonote::difficulty_type hr = make_difficulty(
 | 
			
		||||
            current_network_info.hash_rate, 
 | 
			
		||||
            current_network_info.hash_rate_top64);
 | 
			
		||||
 | 
			
		||||
    get_metric_prefix(hr, hr_d, metric_prefix);
 | 
			
		||||
 | 
			
		||||
    if (metric_prefix != 0)
 | 
			
		||||
| 
						 | 
				
			
			@ -1001,7 +783,7 @@ index2(uint64_t page_no = 0, bool refresh_page = false)
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    context["network_info"] = mstch::map {
 | 
			
		||||
            {"difficulty"        , make_difficulty(current_network_info.difficulty, current_network_info.difficulty_top64).str()},
 | 
			
		||||
            {"difficulty"        , current_network_info.difficulty},
 | 
			
		||||
            {"hash_rate"         , hash_rate},
 | 
			
		||||
            {"fee_per_kb"        , print_money(current_network_info.fee_per_kb)},
 | 
			
		||||
            {"alt_blocks_no"     , current_network_info.alt_blocks_count},
 | 
			
		||||
| 
						 | 
				
			
			@ -1101,7 +883,6 @@ mempool(bool add_header_and_footer = false, uint64_t no_of_mempool_tx = 25)
 | 
			
		|||
    // initalise page tempate map with basic info about mempool
 | 
			
		||||
    mstch::map context {
 | 
			
		||||
            {"mempool_size"          , static_cast<uint64_t>(total_no_of_mempool_tx)}, // total no of mempool txs
 | 
			
		||||
            {"show_cache_times"      , show_cache_times},
 | 
			
		||||
            {"mempool_refresh_time"  , MempoolStatus::mempool_refresh_time}
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1110,11 +891,6 @@ mempool(bool add_header_and_footer = false, uint64_t no_of_mempool_tx = 25)
 | 
			
		|||
    // get reference to blocks template map to be field below
 | 
			
		||||
    mstch::array& txs = boost::get<mstch::array>(context["mempooltxs"]);
 | 
			
		||||
 | 
			
		||||
    double duration_cached     {0.0};
 | 
			
		||||
    double duration_non_cached {0.0};
 | 
			
		||||
    uint64_t cache_hits   {0};
 | 
			
		||||
    uint64_t cache_misses {0};
 | 
			
		||||
 | 
			
		||||
    uint64_t local_copy_server_timestamp = server_timestamp;
 | 
			
		||||
 | 
			
		||||
    // for each transaction in the memory pool
 | 
			
		||||
| 
						 | 
				
			
			@ -1145,7 +921,6 @@ mempool(bool add_header_and_footer = false, uint64_t no_of_mempool_tx = 25)
 | 
			
		|||
                                  delta_time[3], delta_time[4]);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // cout << "block_tx_json_cache from cache" << endl;
 | 
			
		||||
 | 
			
		||||
        // set output page template map
 | 
			
		||||
        txs.push_back(mstch::map {
 | 
			
		||||
| 
						 | 
				
			
			@ -1583,149 +1358,8 @@ show_tx(string tx_hash_str, uint16_t with_ring_signatures = 0, bool refresh_page
 | 
			
		|||
 | 
			
		||||
    mstch::map tx_context;
 | 
			
		||||
 | 
			
		||||
    if (enable_tx_cache && tx_context_cache.Contains({tx_hash, static_cast<bool>(with_ring_signatures)}))
 | 
			
		||||
    {
 | 
			
		||||
        // with_ring_signatures == 0 means that cache is not used
 | 
			
		||||
        // when obtaining detailed information about tx is requested.
 | 
			
		||||
 | 
			
		||||
        // we are going to measure time for the construction of the
 | 
			
		||||
        // tx context from cashe. just for fun, to see if cache is any faster.
 | 
			
		||||
        auto start = std::chrono::steady_clock::now();
 | 
			
		||||
 | 
			
		||||
        const tx_info_cache& tx_info_cashed
 | 
			
		||||
                = tx_context_cache.Get({tx_hash, static_cast<bool>(with_ring_signatures)});
 | 
			
		||||
 | 
			
		||||
        tx_context = tx_info_cashed.tx_map;
 | 
			
		||||
 | 
			
		||||
        //cout << "get tx from cash: " << tx_hash_str <<endl;
 | 
			
		||||
        //cout << " - tx_blk_height: " << boost::get<uint64_t>(tx_context["tx_blk_height"]) <<endl;
 | 
			
		||||
        //cout << " - blk_timestamp_uint: " << boost::get<uint64_t>(tx_context["blk_timestamp_uint"]) <<endl;
 | 
			
		||||
 | 
			
		||||
        // now have to update age and confirmation numbers of the tx.
 | 
			
		||||
 | 
			
		||||
        uint64_t tx_blk_height      = boost::get<uint64_t>(tx_context["tx_blk_height"]);
 | 
			
		||||
        uint64_t blk_timestamp_uint = boost::get<uint64_t>(tx_context["blk_timestamp_uint"]);
 | 
			
		||||
 | 
			
		||||
        if (tx_blk_height > 0)
 | 
			
		||||
        {
 | 
			
		||||
            // seems to be in blockchain. off course it could have been orphaned
 | 
			
		||||
            // so double check if its for sure in blockchain
 | 
			
		||||
 | 
			
		||||
            if (core_storage->have_tx(tx_hash))
 | 
			
		||||
            {
 | 
			
		||||
                // ok, it is still in blockchain
 | 
			
		||||
                // update its age and number of confirmations
 | 
			
		||||
 | 
			
		||||
                pair<string, string> age
 | 
			
		||||
                        = get_age(std::time(nullptr),
 | 
			
		||||
                                  blk_timestamp_uint,
 | 
			
		||||
                                  FULL_AGE_FORMAT);
 | 
			
		||||
 | 
			
		||||
                tx_context["delta_time"] = age.first;
 | 
			
		||||
 | 
			
		||||
                uint64_t bc_height = core_storage->get_current_blockchain_height();
 | 
			
		||||
 | 
			
		||||
                tx_context["confirmations"] = bc_height - (tx_blk_height - 1);
 | 
			
		||||
 | 
			
		||||
                // marke it as from cashe. useful if we want to show
 | 
			
		||||
                // info about cashed/not cashed in frontend.
 | 
			
		||||
                tx_context["from_cache"] = true;
 | 
			
		||||
 | 
			
		||||
                auto duration = std::chrono::duration_cast<std::chrono::microseconds>
 | 
			
		||||
                        (std::chrono::steady_clock::now() - start);
 | 
			
		||||
 | 
			
		||||
                tx_context["construction_time"] = fmt::format(
 | 
			
		||||
                        "{:0.4f}", static_cast<double>(duration.count())/1.0e6);
 | 
			
		||||
 | 
			
		||||
                // normally we should update this into in the cache.
 | 
			
		||||
                // but since we make this check all the time,
 | 
			
		||||
                // we can skip updating cashed version
 | 
			
		||||
 | 
			
		||||
            } // if (core_storage->have_tx(tx_hash))
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                // its not in blockchain, but it was there when we cashed it.
 | 
			
		||||
                // so we update it in cash, as it should be back in mempool
 | 
			
		||||
 | 
			
		||||
                tx_context = construct_tx_context(tx, static_cast<bool>(with_ring_signatures));
 | 
			
		||||
 | 
			
		||||
                tx_context_cache.Put(
 | 
			
		||||
                        {tx_hash, static_cast<bool>(with_ring_signatures)},
 | 
			
		||||
                        tx_info_cache {
 | 
			
		||||
                                boost::get<uint64_t>(tx_context["tx_blk_height"]),
 | 
			
		||||
                                boost::get<uint64_t>(tx_context["blk_timestamp_uint"]),
 | 
			
		||||
                                tx_context}
 | 
			
		||||
                );
 | 
			
		||||
            }
 | 
			
		||||
        } //  if (tx_blk_height > 0)
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            // the tx was cashed when in mempool.
 | 
			
		||||
            // since then, it might have been included in some block.
 | 
			
		||||
            // so we check it.
 | 
			
		||||
 | 
			
		||||
            if (core_storage->have_tx(tx_hash))
 | 
			
		||||
            {
 | 
			
		||||
                // checking if in blockchain already
 | 
			
		||||
                // it was before in mempool, but now maybe already in blockchain
 | 
			
		||||
 | 
			
		||||
                tx_context = construct_tx_context(tx, static_cast<bool>(with_ring_signatures));
 | 
			
		||||
 | 
			
		||||
                tx_context_cache.Put(
 | 
			
		||||
                        {tx_hash, static_cast<bool>(with_ring_signatures)},
 | 
			
		||||
                        tx_info_cache {
 | 
			
		||||
                                boost::get<uint64_t>(tx_context["tx_blk_height"]),
 | 
			
		||||
                                boost::get<uint64_t>(tx_context["blk_timestamp_uint"]),
 | 
			
		||||
                                tx_context});
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
            } // if (core_storage->have_tx(tx_hash))
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                // still seems to be in mempool only.
 | 
			
		||||
                // so just get its time duration, as its read only
 | 
			
		||||
                // from cache
 | 
			
		||||
 | 
			
		||||
                tx_context["from_cache"] = true;
 | 
			
		||||
 | 
			
		||||
                auto duration = std::chrono::duration_cast<std::chrono::microseconds>
 | 
			
		||||
                        (std::chrono::steady_clock::now() - start);
 | 
			
		||||
 | 
			
		||||
                tx_context["construction_time"] = fmt::format(
 | 
			
		||||
                        "{:0.4f}", static_cast<double>(duration.count())/1.0e6);
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
        }  // else if (tx_blk_height > 0)
 | 
			
		||||
 | 
			
		||||
    } // if (tx_context_cache.Contains(tx_hash))
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
        // we are going to measure time for the construction of the
 | 
			
		||||
        // tx context. just for fun, to see if cache is any faster.
 | 
			
		||||
        auto start = std::chrono::steady_clock::now();
 | 
			
		||||
 | 
			
		||||
        tx_context = construct_tx_context(tx, static_cast<bool>(with_ring_signatures));
 | 
			
		||||
 | 
			
		||||
        auto duration = std::chrono::duration_cast<std::chrono::microseconds>
 | 
			
		||||
                (std::chrono::steady_clock::now() - start);
 | 
			
		||||
 | 
			
		||||
        if (enable_tx_cache)
 | 
			
		||||
        {
 | 
			
		||||
            tx_context_cache.Put(
 | 
			
		||||
                    {tx_hash, static_cast<bool>(with_ring_signatures)},
 | 
			
		||||
                    tx_info_cache {
 | 
			
		||||
                            boost::get<uint64_t>(tx_context["tx_blk_height"]),
 | 
			
		||||
                            boost::get<uint64_t>(tx_context["blk_timestamp_uint"]),
 | 
			
		||||
                            tx_context});
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        tx_context["construction_time"] = fmt::format(
 | 
			
		||||
                "{:0.4f}", static_cast<double>(duration.count())/1.0e6);
 | 
			
		||||
 | 
			
		||||
    } // else if (tx_context_cache.Contains(tx_hash))
 | 
			
		||||
 | 
			
		||||
    tx_context = construct_tx_context(tx, static_cast<bool>(with_ring_signatures));
 | 
			
		||||
 | 
			
		||||
    tx_context["show_more_details_link"] = show_more_details_link;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -1737,7 +1371,6 @@ show_tx(string tx_hash_str, uint16_t with_ring_signatures = 0, bool refresh_page
 | 
			
		|||
    mstch::map context {
 | 
			
		||||
            {"testnet"          , this->testnet},
 | 
			
		||||
            {"stagenet"         , this->stagenet},
 | 
			
		||||
            {"show_cache_times" , show_cache_times},
 | 
			
		||||
            {"txs"              , mstch::array{}},
 | 
			
		||||
            {"refresh"          , refresh_page},
 | 
			
		||||
            {"tx_hash"          , tx_hash_str}
 | 
			
		||||
| 
						 | 
				
			
			@ -4878,11 +4511,6 @@ json_transaction(string tx_hash_str)
 | 
			
		|||
        no_confirmations = txd.no_confirmations;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // get tx from tx fetched. can be use to double check
 | 
			
		||||
    // if what we return in the json response agrees with
 | 
			
		||||
    // what tx_hash was requested
 | 
			
		||||
    string tx_hash_str_again = pod_to_hex(get_transaction_hash(tx));
 | 
			
		||||
 | 
			
		||||
    // get basic tx info
 | 
			
		||||
    j_data = get_tx_json(tx, txd);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -6447,7 +6075,6 @@ construct_tx_context(transaction tx, uint16_t with_ring_signatures = 0)
 | 
			
		|||
            {"error_msg"             , string("")},
 | 
			
		||||
            {"have_raw_tx"           , false},
 | 
			
		||||
            {"show_more_details_link", true},
 | 
			
		||||
            {"from_cache"            , false},
 | 
			
		||||
            {"construction_time"     , string {}},
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -6863,7 +6490,15 @@ get_tx_details(const transaction& tx,
 | 
			
		|||
    tx_details txd;
 | 
			
		||||
 | 
			
		||||
    // get tx hash
 | 
			
		||||
    txd.hash = get_transaction_hash(tx);
 | 
			
		||||
    
 | 
			
		||||
    if (!tx.pruned)
 | 
			
		||||
    {
 | 
			
		||||
        txd.hash = get_transaction_hash(tx);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        txd.hash = get_pruned_transaction_hash(tx, tx.prunable_hash);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // get tx public key from extra
 | 
			
		||||
    // this check if there are two public keys
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -111,14 +111,3 @@
 | 
			
		|||
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
{{#show_cache_times}}
 | 
			
		||||
    <div class="center">
 | 
			
		||||
        <h6 style="margin-top: 1px;color:#949490">
 | 
			
		||||
            Tx details construction time: {{construction_time_total}} s
 | 
			
		||||
            <br/>
 | 
			
		||||
            includes {{construction_time_cached}} s from block cache ({{cache_hits}} hits)
 | 
			
		||||
            and {{construction_time_non_cached}} s from non cache ({{cache_misses}} misses)
 | 
			
		||||
        </h6>
 | 
			
		||||
    </div>
 | 
			
		||||
{{/show_cache_times}}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -300,18 +300,4 @@
 | 
			
		|||
    {{/with_ring_signatures}}
 | 
			
		||||
{{/have_raw_tx}}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
{{#show_cache_times}}
 | 
			
		||||
    <div class="center">
 | 
			
		||||
        {{#construction_time}}
 | 
			
		||||
            <h6 style="margin-top: 1px;color:#949490">
 | 
			
		||||
                Tx details construction time: {{construction_time}} s
 | 
			
		||||
                {{#from_cache}}
 | 
			
		||||
                    <br/>Tx read from the tx cache
 | 
			
		||||
                {{/from_cache}}
 | 
			
		||||
            </h6>
 | 
			
		||||
        {{/construction_time}}
 | 
			
		||||
    </div>
 | 
			
		||||
{{/show_cache_times}}
 | 
			
		||||
 | 
			
		||||
</div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue