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
|
int
|
||||||
main(int ac, const char* av[])
|
main(int ac, const char* av[])
|
||||||
{
|
{
|
||||||
|
|
||||||
// get command line options
|
// get command line options
|
||||||
xmreg::CmdLineOptions opts {ac, av};
|
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_mixin_details_opt = opts.get_option<bool>("enable-mixin-details");
|
||||||
auto enable_json_api_opt = opts.get_option<bool>("enable-json-api");
|
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_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 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");
|
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_mixin_details {*enable_mixin_details_opt};
|
||||||
bool enable_json_api {*enable_json_api_opt};
|
bool enable_json_api {*enable_json_api_opt};
|
||||||
bool enable_as_hex {*enable_as_hex_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 enable_emission_monitor {*enable_emission_monitor_opt};
|
||||||
bool show_cache_times {*show_cache_times_opt};
|
|
||||||
|
|
||||||
|
|
||||||
// set monero log output level
|
// set monero log output level
|
||||||
|
@ -279,9 +274,6 @@ main(int ac, const char* av[])
|
||||||
enable_output_key_checker,
|
enable_output_key_checker,
|
||||||
enable_autorefresh_option,
|
enable_autorefresh_option,
|
||||||
enable_mixin_details,
|
enable_mixin_details,
|
||||||
enable_tx_cache,
|
|
||||||
enable_block_cache,
|
|
||||||
show_cache_times,
|
|
||||||
no_blocks_on_index,
|
no_blocks_on_index,
|
||||||
mempool_info_timeout,
|
mempool_info_timeout,
|
||||||
*testnet_url,
|
*testnet_url,
|
||||||
|
|
|
@ -37,12 +37,6 @@ namespace xmreg
|
||||||
"enable outputs key file checker")
|
"enable outputs key file checker")
|
||||||
("enable-json-api", value<bool>()->default_value(false)->implicit_value(true),
|
("enable-json-api", value<bool>()->default_value(false)->implicit_value(true),
|
||||||
"enable JSON REST api")
|
"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-as-hex", value<bool>()->default_value(false)->implicit_value(true),
|
||||||
"enable links to provide hex represtations of a tx and a block")
|
"enable links to provide hex represtations of a tx and a block")
|
||||||
("enable-autorefresh-option", value<bool>()->default_value(false)->implicit_value(true),
|
("enable-autorefresh-option", value<bool>()->default_value(false)->implicit_value(true),
|
||||||
|
|
|
@ -137,8 +137,26 @@ MicroCore::get_tx(const crypto::hash& tx_hash, transaction& tx)
|
||||||
if (m_blockchain_storage.have_tx(tx_hash))
|
if (m_blockchain_storage.have_tx(tx_hash))
|
||||||
{
|
{
|
||||||
// get transaction with given hash
|
// get transaction with given hash
|
||||||
|
try
|
||||||
|
{
|
||||||
tx = m_blockchain_storage.get_db().get_tx(tx_hash);
|
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
|
else
|
||||||
{
|
{
|
||||||
cerr << "MicroCore::get_tx tx does not exist in blockchain: " << tx_hash << endl;
|
cerr << "MicroCore::get_tx tx does not exist in blockchain: " << tx_hash << endl;
|
||||||
|
|
399
src/page.h
399
src/page.h
|
@ -31,9 +31,6 @@
|
||||||
|
|
||||||
#include "../ext/json.hpp"
|
#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"
|
#include "../ext/mstch/src/visitor/render_node.hpp"
|
||||||
|
|
||||||
extern "C" uint64_t me_rx_seedheight(const uint64_t height);
|
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)
|
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
|
// helper to ignore any number of template parametrs
|
||||||
template<typename...> using VoidT = void;
|
template<typename...> using VoidT = void;
|
||||||
|
@ -147,22 +119,6 @@ struct OutputIndicesReturnVectOfVectT<
|
||||||
>>: std::true_type
|
>>: 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
|
* visitor to produce json representations of
|
||||||
|
@ -521,15 +477,10 @@ bool enable_pusher;
|
||||||
bool enable_key_image_checker;
|
bool enable_key_image_checker;
|
||||||
bool enable_output_key_checker;
|
bool enable_output_key_checker;
|
||||||
bool enable_mixins_details;
|
bool enable_mixins_details;
|
||||||
bool enable_tx_cache;
|
|
||||||
bool enable_block_cache;
|
|
||||||
bool enable_as_hex;
|
bool enable_as_hex;
|
||||||
bool show_cache_times;
|
|
||||||
|
|
||||||
|
|
||||||
bool enable_autorefresh_option;
|
bool enable_autorefresh_option;
|
||||||
|
|
||||||
|
|
||||||
uint64_t no_of_mempool_tx_of_frontpage;
|
uint64_t no_of_mempool_tx_of_frontpage;
|
||||||
uint64_t no_blocks_on_index;
|
uint64_t no_blocks_on_index;
|
||||||
uint64_t mempool_info_timeout;
|
uint64_t mempool_info_timeout;
|
||||||
|
@ -548,24 +499,6 @@ string js_html_files_all_in_one;
|
||||||
// read operation in OS
|
// read operation in OS
|
||||||
map<string, string> template_file;
|
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:
|
public:
|
||||||
|
|
||||||
page(MicroCore* _mcore,
|
page(MicroCore* _mcore,
|
||||||
|
@ -578,9 +511,6 @@ page(MicroCore* _mcore,
|
||||||
bool _enable_output_key_checker,
|
bool _enable_output_key_checker,
|
||||||
bool _enable_autorefresh_option,
|
bool _enable_autorefresh_option,
|
||||||
bool _enable_mixins_details,
|
bool _enable_mixins_details,
|
||||||
bool _enable_tx_cache,
|
|
||||||
bool _enable_block_cache,
|
|
||||||
bool _show_cache_times,
|
|
||||||
uint64_t _no_blocks_on_index,
|
uint64_t _no_blocks_on_index,
|
||||||
uint64_t _mempool_info_timeout,
|
uint64_t _mempool_info_timeout,
|
||||||
string _testnet_url,
|
string _testnet_url,
|
||||||
|
@ -597,16 +527,11 @@ page(MicroCore* _mcore,
|
||||||
enable_output_key_checker {_enable_output_key_checker},
|
enable_output_key_checker {_enable_output_key_checker},
|
||||||
enable_autorefresh_option {_enable_autorefresh_option},
|
enable_autorefresh_option {_enable_autorefresh_option},
|
||||||
enable_mixins_details {_enable_mixins_details},
|
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},
|
no_blocks_on_index {_no_blocks_on_index},
|
||||||
mempool_info_timeout {_mempool_info_timeout},
|
mempool_info_timeout {_mempool_info_timeout},
|
||||||
testnet_url {_testnet_url},
|
testnet_url {_testnet_url},
|
||||||
stagenet_url {_stagenet_url},
|
stagenet_url {_stagenet_url},
|
||||||
mainnet_url {_mainnet_url},
|
mainnet_url {_mainnet_url}
|
||||||
block_tx_cache(200),
|
|
||||||
tx_context_cache(1000)
|
|
||||||
{
|
{
|
||||||
mainnet = nettype == cryptonote::network_type::MAINNET;
|
mainnet = nettype == cryptonote::network_type::MAINNET;
|
||||||
testnet = nettype == cryptonote::network_type::TESTNET;
|
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_pusher" , enable_pusher},
|
||||||
{"enable_key_image_checker" , enable_key_image_checker},
|
{"enable_key_image_checker" , enable_key_image_checker},
|
||||||
{"enable_output_key_checker", enable_output_key_checker},
|
{"enable_output_key_checker", enable_output_key_checker},
|
||||||
{"enable_autorefresh_option", enable_autorefresh_option},
|
{"enable_autorefresh_option", enable_autorefresh_option}
|
||||||
{"show_cache_times" , show_cache_times}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
context.emplace("txs", mstch::array()); // will keep tx to show
|
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;
|
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
|
// loop index
|
||||||
int64_t i = end_height;
|
int64_t i = end_height;
|
||||||
|
|
||||||
|
@ -764,119 +682,6 @@ index2(uint64_t page_no = 0, bool refresh_page = false)
|
||||||
|
|
||||||
context["age_format"] = age.second;
|
context["age_format"] = age.second;
|
||||||
|
|
||||||
|
|
||||||
if (enable_block_cache && block_tx_cache.Contains(i))
|
|
||||||
{
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// this is new block. not in cashe.
|
|
||||||
// need to process its txs and add to cache
|
|
||||||
|
|
||||||
// start measure time here
|
// start measure time here
|
||||||
auto start = std::chrono::steady_clock::now();
|
auto start = std::chrono::steady_clock::now();
|
||||||
|
|
||||||
|
@ -895,7 +700,6 @@ index2(uint64_t page_no = 0, bool refresh_page = false)
|
||||||
|
|
||||||
uint64_t tx_i {0};
|
uint64_t tx_i {0};
|
||||||
|
|
||||||
// this vector will go into block_tx cache
|
|
||||||
// tx_hash , txd_map
|
// tx_hash , txd_map
|
||||||
vector<pair<crypto::hash, mstch::node>> txd_pairs;
|
vector<pair<crypto::hash, mstch::node>> txd_pairs;
|
||||||
|
|
||||||
|
@ -940,18 +744,6 @@ index2(uint64_t page_no = 0, bool refresh_page = false)
|
||||||
auto duration = std::chrono::duration_cast<std::chrono::microseconds>
|
auto duration = std::chrono::duration_cast<std::chrono::microseconds>
|
||||||
(std::chrono::steady_clock::now() - start);
|
(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))
|
|
||||||
|
|
||||||
--i; // go to next block number
|
--i; // go to next block number
|
||||||
|
|
||||||
} // while (i <= end_height)
|
} // while (i <= end_height)
|
||||||
|
@ -959,30 +751,20 @@ index2(uint64_t page_no = 0, bool refresh_page = false)
|
||||||
// calculate median size of the blocks shown
|
// calculate median size of the blocks shown
|
||||||
//double blk_size_median = xmreg::calc_median(blk_sizes.begin(), blk_sizes.end());
|
//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.
|
// get current network info from MemoryStatus thread.
|
||||||
MempoolStatus::network_info current_network_info
|
MempoolStatus::network_info current_network_info
|
||||||
= MempoolStatus::current_network_info;
|
= MempoolStatus::current_network_info;
|
||||||
|
|
||||||
// perapre network info mstch::map for the front page
|
// perapre network info mstch::map for the front page
|
||||||
string hash_rate;
|
string hash_rate;
|
||||||
|
|
||||||
double hr_d;
|
double hr_d;
|
||||||
char metric_prefix;
|
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);
|
get_metric_prefix(hr, hr_d, metric_prefix);
|
||||||
|
|
||||||
if (metric_prefix != 0)
|
if (metric_prefix != 0)
|
||||||
|
@ -1001,7 +783,7 @@ index2(uint64_t page_no = 0, bool refresh_page = false)
|
||||||
}
|
}
|
||||||
|
|
||||||
context["network_info"] = mstch::map {
|
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},
|
{"hash_rate" , hash_rate},
|
||||||
{"fee_per_kb" , print_money(current_network_info.fee_per_kb)},
|
{"fee_per_kb" , print_money(current_network_info.fee_per_kb)},
|
||||||
{"alt_blocks_no" , current_network_info.alt_blocks_count},
|
{"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
|
// initalise page tempate map with basic info about mempool
|
||||||
mstch::map context {
|
mstch::map context {
|
||||||
{"mempool_size" , static_cast<uint64_t>(total_no_of_mempool_tx)}, // total no of mempool txs
|
{"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}
|
{"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
|
// get reference to blocks template map to be field below
|
||||||
mstch::array& txs = boost::get<mstch::array>(context["mempooltxs"]);
|
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;
|
uint64_t local_copy_server_timestamp = server_timestamp;
|
||||||
|
|
||||||
// for each transaction in the memory pool
|
// 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]);
|
delta_time[3], delta_time[4]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// cout << "block_tx_json_cache from cache" << endl;
|
|
||||||
|
|
||||||
// set output page template map
|
// set output page template map
|
||||||
txs.push_back(mstch::map {
|
txs.push_back(mstch::map {
|
||||||
|
@ -1583,150 +1358,9 @@ show_tx(string tx_hash_str, uint16_t with_ring_signatures = 0, bool refresh_page
|
||||||
|
|
||||||
mstch::map tx_context;
|
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 = 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["show_more_details_link"] = show_more_details_link;
|
tx_context["show_more_details_link"] = show_more_details_link;
|
||||||
|
|
||||||
if (boost::get<bool>(tx_context["has_error"]))
|
if (boost::get<bool>(tx_context["has_error"]))
|
||||||
|
@ -1737,7 +1371,6 @@ show_tx(string tx_hash_str, uint16_t with_ring_signatures = 0, bool refresh_page
|
||||||
mstch::map context {
|
mstch::map context {
|
||||||
{"testnet" , this->testnet},
|
{"testnet" , this->testnet},
|
||||||
{"stagenet" , this->stagenet},
|
{"stagenet" , this->stagenet},
|
||||||
{"show_cache_times" , show_cache_times},
|
|
||||||
{"txs" , mstch::array{}},
|
{"txs" , mstch::array{}},
|
||||||
{"refresh" , refresh_page},
|
{"refresh" , refresh_page},
|
||||||
{"tx_hash" , tx_hash_str}
|
{"tx_hash" , tx_hash_str}
|
||||||
|
@ -4878,11 +4511,6 @@ json_transaction(string tx_hash_str)
|
||||||
no_confirmations = txd.no_confirmations;
|
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
|
// get basic tx info
|
||||||
j_data = get_tx_json(tx, txd);
|
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("")},
|
{"error_msg" , string("")},
|
||||||
{"have_raw_tx" , false},
|
{"have_raw_tx" , false},
|
||||||
{"show_more_details_link", true},
|
{"show_more_details_link", true},
|
||||||
{"from_cache" , false},
|
|
||||||
{"construction_time" , string {}},
|
{"construction_time" , string {}},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -6863,7 +6490,15 @@ get_tx_details(const transaction& tx,
|
||||||
tx_details txd;
|
tx_details txd;
|
||||||
|
|
||||||
// get tx hash
|
// get tx hash
|
||||||
|
|
||||||
|
if (!tx.pruned)
|
||||||
|
{
|
||||||
txd.hash = get_transaction_hash(tx);
|
txd.hash = get_transaction_hash(tx);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
txd.hash = get_pruned_transaction_hash(tx, tx.prunable_hash);
|
||||||
|
}
|
||||||
|
|
||||||
// get tx public key from extra
|
// get tx public key from extra
|
||||||
// this check if there are two public keys
|
// this check if there are two public keys
|
||||||
|
|
|
@ -111,14 +111,3 @@
|
||||||
|
|
||||||
</div>
|
</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}}
|
{{/with_ring_signatures}}
|
||||||
{{/have_raw_tx}}
|
{{/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>
|
</div>
|
||||||
|
|
Loading…
Reference in a new issue