mirror of
https://github.com/Retropex/bitcoin.git
synced 2025-05-29 21:42:32 +02:00
Merge 8501 via old_stats_rpc-26
This commit is contained in:
commit
05ce9a10ca
@ -280,6 +280,7 @@ BITCOIN_CORE_H = \
|
|||||||
script/solver.h \
|
script/solver.h \
|
||||||
shutdown.h \
|
shutdown.h \
|
||||||
signet.h \
|
signet.h \
|
||||||
|
stats/stats.h \
|
||||||
streams.h \
|
streams.h \
|
||||||
support/allocators/pool.h \
|
support/allocators/pool.h \
|
||||||
support/allocators/secure.h \
|
support/allocators/secure.h \
|
||||||
@ -466,6 +467,8 @@ libbitcoin_node_a_SOURCES = \
|
|||||||
script/sigcache.cpp \
|
script/sigcache.cpp \
|
||||||
shutdown.cpp \
|
shutdown.cpp \
|
||||||
signet.cpp \
|
signet.cpp \
|
||||||
|
stats/rpc_stats.cpp \
|
||||||
|
stats/stats.cpp \
|
||||||
timedata.cpp \
|
timedata.cpp \
|
||||||
torcontrol.cpp \
|
torcontrol.cpp \
|
||||||
txdb.cpp \
|
txdb.cpp \
|
||||||
|
@ -169,6 +169,9 @@ BITCOIN_TESTS =\
|
|||||||
test/versionbits_tests.cpp \
|
test/versionbits_tests.cpp \
|
||||||
test/xoroshiro128plusplus_tests.cpp
|
test/xoroshiro128plusplus_tests.cpp
|
||||||
|
|
||||||
|
BITCOIN_TESTS += \
|
||||||
|
stats/test/stats_tests.cpp
|
||||||
|
|
||||||
if ENABLE_WALLET
|
if ENABLE_WALLET
|
||||||
BITCOIN_TESTS += \
|
BITCOIN_TESTS += \
|
||||||
wallet/test/feebumper_tests.cpp \
|
wallet/test/feebumper_tests.cpp \
|
||||||
|
@ -652,6 +652,9 @@ std::string ArgsManager::GetHelpMessage() const
|
|||||||
case OptionsCategory::REGISTER_COMMANDS:
|
case OptionsCategory::REGISTER_COMMANDS:
|
||||||
usage += HelpMessageGroup("Register Commands:");
|
usage += HelpMessageGroup("Register Commands:");
|
||||||
break;
|
break;
|
||||||
|
case OptionsCategory::STATS:
|
||||||
|
usage += HelpMessageGroup("Statistic options:");
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -63,6 +63,7 @@ enum class OptionsCategory {
|
|||||||
GUI,
|
GUI,
|
||||||
COMMANDS,
|
COMMANDS,
|
||||||
REGISTER_COMMANDS,
|
REGISTER_COMMANDS,
|
||||||
|
STATS,
|
||||||
|
|
||||||
HIDDEN // Always the last option to avoid printing these in the help
|
HIDDEN // Always the last option to avoid printing these in the help
|
||||||
};
|
};
|
||||||
|
@ -67,6 +67,7 @@
|
|||||||
#include <scheduler.h>
|
#include <scheduler.h>
|
||||||
#include <script/sigcache.h>
|
#include <script/sigcache.h>
|
||||||
#include <shutdown.h>
|
#include <shutdown.h>
|
||||||
|
#include <stats/stats.h>
|
||||||
#include <sync.h>
|
#include <sync.h>
|
||||||
#include <timedata.h>
|
#include <timedata.h>
|
||||||
#include <torcontrol.h>
|
#include <torcontrol.h>
|
||||||
@ -650,6 +651,8 @@ void SetupServerArgs(ArgsManager& argsman)
|
|||||||
hidden_args.emplace_back("-daemonwait");
|
hidden_args.emplace_back("-daemonwait");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
CStats::AddStatsOptions();
|
||||||
|
|
||||||
// Add the hidden options
|
// Add the hidden options
|
||||||
argsman.AddHiddenArgs(hidden_args);
|
argsman.AddHiddenArgs(hidden_args);
|
||||||
}
|
}
|
||||||
@ -1034,6 +1037,8 @@ bool AppInitParameterInteraction(const ArgsManager& args)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!CStats::parameterInteraction()) return false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,6 +20,7 @@ void RegisterRawTransactionRPCCommands(CRPCTable &tableRPC);
|
|||||||
void RegisterSignMessageRPCCommands(CRPCTable&);
|
void RegisterSignMessageRPCCommands(CRPCTable&);
|
||||||
void RegisterSignerRPCCommands(CRPCTable &tableRPC);
|
void RegisterSignerRPCCommands(CRPCTable &tableRPC);
|
||||||
void RegisterTxoutProofRPCCommands(CRPCTable&);
|
void RegisterTxoutProofRPCCommands(CRPCTable&);
|
||||||
|
void RegisterStatsRPCCommands(CRPCTable&);
|
||||||
|
|
||||||
static inline void RegisterAllCoreRPCCommands(CRPCTable &t)
|
static inline void RegisterAllCoreRPCCommands(CRPCTable &t)
|
||||||
{
|
{
|
||||||
@ -36,6 +37,7 @@ static inline void RegisterAllCoreRPCCommands(CRPCTable &t)
|
|||||||
RegisterSignerRPCCommands(t);
|
RegisterSignerRPCCommands(t);
|
||||||
#endif // ENABLE_EXTERNAL_SIGNER
|
#endif // ENABLE_EXTERNAL_SIGNER
|
||||||
RegisterTxoutProofRPCCommands(t);
|
RegisterTxoutProofRPCCommands(t);
|
||||||
|
RegisterStatsRPCCommands(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // BITCOIN_RPC_REGISTER_H
|
#endif // BITCOIN_RPC_REGISTER_H
|
||||||
|
79
src/stats/rpc_stats.cpp
Normal file
79
src/stats/rpc_stats.cpp
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
// Copyright (c) 2016 The Bitcoin Core developers
|
||||||
|
// Distributed under the MIT software license, see the accompanying
|
||||||
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#include <rpc/server.h>
|
||||||
|
#include <rpc/util.h>
|
||||||
|
#include <stats/stats.h>
|
||||||
|
#include <util/strencodings.h>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <univalue.h>
|
||||||
|
|
||||||
|
static RPCHelpMan getmempoolstats()
|
||||||
|
{
|
||||||
|
return RPCHelpMan{"getmempoolstats",
|
||||||
|
"\nReturns the collected mempool statistics (non-linear non-interpolated samples).\n",
|
||||||
|
{},
|
||||||
|
RPCResult{
|
||||||
|
RPCResult::Type::OBJ, "", "",
|
||||||
|
{
|
||||||
|
{RPCResult::Type::NUM_TIME, "time_from", "Timestamp, first sample"},
|
||||||
|
{RPCResult::Type::NUM_TIME, "time_to", "Timestamp, last sample"},
|
||||||
|
{RPCResult::Type::ARR, "samples", "",
|
||||||
|
{
|
||||||
|
{RPCResult::Type::ARR_FIXED, "", "",
|
||||||
|
{
|
||||||
|
{RPCResult::Type::NUM, "", "Sample time in seconds (relative to other sample times only)"},
|
||||||
|
{RPCResult::Type::NUM, "", "Number of transactions in the memory pool"},
|
||||||
|
{RPCResult::Type::NUM, "", "Memory usage by memory pool"},
|
||||||
|
{RPCResult::Type::NUM, "", "Minimum fee per kB"},
|
||||||
|
}},
|
||||||
|
}},
|
||||||
|
}},
|
||||||
|
RPCExamples{
|
||||||
|
HelpExampleCli("getmempoolstats", "")
|
||||||
|
+ HelpExampleRpc("getmempoolstats", "")
|
||||||
|
},
|
||||||
|
[&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
|
||||||
|
{
|
||||||
|
// get stats from the core stats model
|
||||||
|
uint64_t timeFrom = 0;
|
||||||
|
uint64_t timeTo = 0;
|
||||||
|
mempoolSamples_t samples = CStats::DefaultStats()->mempoolGetValuesInRange(timeFrom, timeTo);
|
||||||
|
|
||||||
|
// use "flat" json encoding for performance reasons
|
||||||
|
UniValue samplesObj(UniValue::VARR);
|
||||||
|
for (struct CStatsMempoolSample& sample : samples) {
|
||||||
|
UniValue singleSample(UniValue::VARR);
|
||||||
|
singleSample.push_back(UniValue((uint64_t)sample.m_time_delta));
|
||||||
|
singleSample.push_back(UniValue(sample.m_tx_count));
|
||||||
|
singleSample.push_back(UniValue(sample.m_dyn_mem_usage));
|
||||||
|
singleSample.push_back(UniValue(sample.m_min_fee_per_k));
|
||||||
|
samplesObj.push_back(singleSample);
|
||||||
|
}
|
||||||
|
|
||||||
|
UniValue result(UniValue::VOBJ);
|
||||||
|
result.pushKV("time_from", timeFrom);
|
||||||
|
result.pushKV("time_to", timeTo);
|
||||||
|
result.pushKV("samples", samplesObj);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void RegisterStatsRPCCommands(CRPCTable& t)
|
||||||
|
{
|
||||||
|
// clang-format off
|
||||||
|
static const CRPCCommand commands[] =
|
||||||
|
{ // category actor (function)
|
||||||
|
// --------------------- ------------------------
|
||||||
|
{ "stats", &getmempoolstats, },
|
||||||
|
};
|
||||||
|
// clang-format on
|
||||||
|
for (const auto& c : commands) {
|
||||||
|
t.appendCommand(c.name, &c);
|
||||||
|
}
|
||||||
|
}
|
144
src/stats/stats.cpp
Normal file
144
src/stats/stats.cpp
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
// Copyright (c) 2016 The Bitcoin Core developers
|
||||||
|
// Distributed under the MIT software license, see the accompanying
|
||||||
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#include <stats/stats.h>
|
||||||
|
|
||||||
|
#include <common/args.h>
|
||||||
|
#include <memusage.h>
|
||||||
|
#include <util/time.h>
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
static const uint32_t SAMPLE_MIN_DELTA_IN_SEC = 2;
|
||||||
|
static const int CLEANUP_SAMPLES_THRESHOLD = 100;
|
||||||
|
size_t CStats::maxStatsMemory = 0;
|
||||||
|
const size_t CStats::DEFAULT_MAX_STATS_MEMORY = 10 * 1024 * 1024; //10 MB
|
||||||
|
const bool CStats::DEFAULT_STATISTICS_ENABLED = false;
|
||||||
|
std::atomic<bool> CStats::m_stats_enabled(false); //disable stats by default
|
||||||
|
|
||||||
|
CStats* CStats::m_shared_instance{nullptr};
|
||||||
|
|
||||||
|
CStats* CStats::DefaultStats()
|
||||||
|
{
|
||||||
|
if (!m_shared_instance)
|
||||||
|
m_shared_instance = new CStats();
|
||||||
|
|
||||||
|
return m_shared_instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CStats::addMempoolSample(int64_t txcount, int64_t dynUsage, int64_t currentMinRelayFee)
|
||||||
|
{
|
||||||
|
if (!m_stats_enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint64_t now = GetTime();
|
||||||
|
{
|
||||||
|
LOCK(cs_stats);
|
||||||
|
|
||||||
|
// set the mempool stats start time if this is the first sample
|
||||||
|
if (m_mempool_stats.m_start_time == 0)
|
||||||
|
m_mempool_stats.m_start_time = now;
|
||||||
|
|
||||||
|
// ensure the minimum time delta between samples
|
||||||
|
if (m_mempool_stats.m_samples.size() && m_mempool_stats.m_start_time + m_mempool_stats.m_samples.back().m_time_delta + SAMPLE_MIN_DELTA_IN_SEC >= now) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// calculate the current time delta and add a sample
|
||||||
|
uint32_t timeDelta = now - m_mempool_stats.m_start_time; //truncate to uint32_t should be sufficient
|
||||||
|
m_mempool_stats.m_samples.push_back({timeDelta, txcount, dynUsage, currentMinRelayFee});
|
||||||
|
m_mempool_stats.m_cleanup_counter++;
|
||||||
|
|
||||||
|
// check if we should cleanup the container
|
||||||
|
if (m_mempool_stats.m_cleanup_counter >= CLEANUP_SAMPLES_THRESHOLD) {
|
||||||
|
//check memory usage
|
||||||
|
if (memusage::DynamicUsage(m_mempool_stats.m_samples) > maxStatsMemory && m_mempool_stats.m_samples.size() > 1) {
|
||||||
|
// only shrink if the vector.capacity() is > the target for performance reasons
|
||||||
|
m_mempool_stats.m_samples.shrink_to_fit();
|
||||||
|
const size_t memUsage = memusage::DynamicUsage(m_mempool_stats.m_samples);
|
||||||
|
// calculate the amount of samples we need to remove
|
||||||
|
size_t itemsToRemove = (memUsage - maxStatsMemory + sizeof(m_mempool_stats.m_samples[0]) - 1) / sizeof(m_mempool_stats.m_samples[0]);
|
||||||
|
|
||||||
|
// sanity check; always keep the most recent sample we just added
|
||||||
|
if (m_mempool_stats.m_samples.size() <= itemsToRemove) {
|
||||||
|
itemsToRemove = m_mempool_stats.m_samples.size() - 1;
|
||||||
|
}
|
||||||
|
m_mempool_stats.m_samples.erase(m_mempool_stats.m_samples.begin(), m_mempool_stats.m_samples.begin() + itemsToRemove);
|
||||||
|
}
|
||||||
|
// shrink vector
|
||||||
|
m_mempool_stats.m_samples.shrink_to_fit();
|
||||||
|
m_mempool_stats.m_cleanup_counter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// fire signal
|
||||||
|
MempoolStatsDidChange();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mempoolSamples_t CStats::mempoolGetValuesInRange(uint64_t& fromTime, uint64_t& toTime)
|
||||||
|
{
|
||||||
|
if (!m_stats_enabled)
|
||||||
|
return mempoolSamples_t();
|
||||||
|
|
||||||
|
LOCK(cs_stats);
|
||||||
|
|
||||||
|
// if empty, return directly
|
||||||
|
if (!m_mempool_stats.m_samples.size())
|
||||||
|
return m_mempool_stats.m_samples;
|
||||||
|
|
||||||
|
|
||||||
|
if (!(fromTime == 0 && toTime == 0) && (fromTime > m_mempool_stats.m_start_time + m_mempool_stats.m_samples.front().m_time_delta || toTime < m_mempool_stats.m_start_time + m_mempool_stats.m_samples.back().m_time_delta)) {
|
||||||
|
mempoolSamples_t::iterator fromSample = m_mempool_stats.m_samples.begin();
|
||||||
|
mempoolSamples_t::iterator toSample = std::prev(m_mempool_stats.m_samples.end());
|
||||||
|
|
||||||
|
// create subset of samples
|
||||||
|
bool fromSet = false;
|
||||||
|
for (mempoolSamples_t::iterator it = m_mempool_stats.m_samples.begin(); it != m_mempool_stats.m_samples.end(); ++it) {
|
||||||
|
if (m_mempool_stats.m_start_time + (*it).m_time_delta >= fromTime && !fromSet) {
|
||||||
|
fromSample = it;
|
||||||
|
fromSet = true;
|
||||||
|
}
|
||||||
|
else if (m_mempool_stats.m_start_time + (*it).m_time_delta > toTime) {
|
||||||
|
toSample = std::prev(it);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mempoolSamples_t subset(fromSample, toSample + 1);
|
||||||
|
|
||||||
|
// set the fromTime and toTime pass-by-ref parameters
|
||||||
|
fromTime = m_mempool_stats.m_start_time + (*fromSample).m_time_delta;
|
||||||
|
toTime = m_mempool_stats.m_start_time + (*toSample).m_time_delta;
|
||||||
|
|
||||||
|
// return subset
|
||||||
|
return subset;
|
||||||
|
}
|
||||||
|
|
||||||
|
// return all available samples
|
||||||
|
fromTime = m_mempool_stats.m_start_time + m_mempool_stats.m_samples.front().m_time_delta;
|
||||||
|
toTime = m_mempool_stats.m_start_time + m_mempool_stats.m_samples.back().m_time_delta;
|
||||||
|
return m_mempool_stats.m_samples;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CStats::setMaxMemoryUsageTarget(size_t maxMem)
|
||||||
|
{
|
||||||
|
m_stats_enabled = (maxMem > 0);
|
||||||
|
|
||||||
|
LOCK(cs_stats);
|
||||||
|
maxStatsMemory = maxMem;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CStats::AddStatsOptions()
|
||||||
|
{
|
||||||
|
gArgs.AddArg("-statsenable", strprintf("Enable statistics (default: %u)", DEFAULT_STATISTICS_ENABLED), ArgsManager::ALLOW_ANY, OptionsCategory::STATS);
|
||||||
|
gArgs.AddArg("-statsmaxmemorytarget=<n>", strprintf("Set the memory limit target for statistics in bytes (default: %u)", DEFAULT_MAX_STATS_MEMORY), ArgsManager::ALLOW_ANY, OptionsCategory::STATS);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CStats::parameterInteraction()
|
||||||
|
{
|
||||||
|
if (gArgs.GetBoolArg("-statsenable", DEFAULT_STATISTICS_ENABLED))
|
||||||
|
DefaultStats()->setMaxMemoryUsageTarget(gArgs.GetIntArg("-statsmaxmemorytarget", DEFAULT_MAX_STATS_MEMORY));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
77
src/stats/stats.h
Normal file
77
src/stats/stats.h
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
// Copyright (c) 2016 The Bitcoin Core developers
|
||||||
|
// Distributed under the MIT software license, see the accompanying
|
||||||
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#ifndef BITCOIN_STATS_STATS_H
|
||||||
|
#define BITCOIN_STATS_STATS_H
|
||||||
|
|
||||||
|
#include <sync.h>
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include <boost/signals2/signal.hpp>
|
||||||
|
|
||||||
|
struct CStatsMempoolSample {
|
||||||
|
uint32_t m_time_delta; //use 32bit time delta to save memory
|
||||||
|
int64_t m_tx_count; //transaction count
|
||||||
|
int64_t m_dyn_mem_usage; //dynamic mempool usage
|
||||||
|
int64_t m_min_fee_per_k; //min fee per Kb
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::vector<struct CStatsMempoolSample> mempoolSamples_t;
|
||||||
|
|
||||||
|
// simple mempool stats container
|
||||||
|
class CStatsMempool
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
uint64_t m_start_time; //start time of the container
|
||||||
|
mempoolSamples_t m_samples;
|
||||||
|
uint64_t m_cleanup_counter; //internal counter to trogger cleanups
|
||||||
|
|
||||||
|
CStatsMempool()
|
||||||
|
{
|
||||||
|
m_start_time = 0;
|
||||||
|
m_cleanup_counter = 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Class that manages various types of statistics and its memory consumption
|
||||||
|
class CStats
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
static size_t maxStatsMemory; //maximum amount of memory to use for the stats
|
||||||
|
|
||||||
|
static CStats* m_shared_instance;
|
||||||
|
mutable RecursiveMutex cs_stats;
|
||||||
|
|
||||||
|
CStatsMempool m_mempool_stats; //mempool stats container
|
||||||
|
|
||||||
|
public:
|
||||||
|
static const size_t DEFAULT_MAX_STATS_MEMORY; //default maximum of memory to use
|
||||||
|
static const bool DEFAULT_STATISTICS_ENABLED; //default value for enabling statistics
|
||||||
|
|
||||||
|
static std::atomic<bool> m_stats_enabled; //if enabled, stats will be collected
|
||||||
|
static CStats* DefaultStats(); //shared instance
|
||||||
|
|
||||||
|
/* signals */
|
||||||
|
boost::signals2::signal<void(void)> MempoolStatsDidChange; //mempool stats update signal
|
||||||
|
|
||||||
|
/* add a mempool stats sample */
|
||||||
|
void addMempoolSample(int64_t txcount, int64_t dynUsage, int64_t currentMinRelayFee);
|
||||||
|
|
||||||
|
/* get all mempool samples in range */
|
||||||
|
mempoolSamples_t mempoolGetValuesInRange(uint64_t& fromTime, uint64_t& toTime);
|
||||||
|
|
||||||
|
/* set the target for the maximum memory consumption (in bytes) */
|
||||||
|
void setMaxMemoryUsageTarget(size_t maxMem);
|
||||||
|
|
||||||
|
/* register the statistics module help strings */
|
||||||
|
static void AddStatsOptions();
|
||||||
|
|
||||||
|
/* access the parameters and map it to the internal model */
|
||||||
|
static bool parameterInteraction();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // BITCOIN_STATS_STATS_H
|
76
src/stats/test/stats_tests.cpp
Normal file
76
src/stats/test/stats_tests.cpp
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
// Copyright (c) 2016 The Bitcoin Core developers
|
||||||
|
// Distributed under the MIT software license, see the accompanying
|
||||||
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
||||||
|
|
||||||
|
#include <stats/stats.h>
|
||||||
|
|
||||||
|
#include <test/util/setup_common.h>
|
||||||
|
#include <util/time.h>
|
||||||
|
|
||||||
|
#include <boost/test/unit_test.hpp>
|
||||||
|
|
||||||
|
BOOST_FIXTURE_TEST_SUITE(stats_tests, BasicTestingSetup)
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(stats)
|
||||||
|
{
|
||||||
|
CStats::DefaultStats()->setMaxMemoryUsageTarget(CStats::DEFAULT_MAX_STATS_MEMORY);
|
||||||
|
|
||||||
|
uint64_t start = GetTime();
|
||||||
|
SetMockTime(start);
|
||||||
|
|
||||||
|
CStats::DefaultStats()->addMempoolSample(0, 1, 1);
|
||||||
|
SetMockTime(start + 1);
|
||||||
|
CStats::DefaultStats()->addMempoolSample(0, 2, 2); //1second should be to short
|
||||||
|
SetMockTime(start + 5);
|
||||||
|
CStats::DefaultStats()->addMempoolSample(3, 4, 3);
|
||||||
|
|
||||||
|
uint64_t queryFromTime = start;
|
||||||
|
uint64_t queryToTime = start + 3600;
|
||||||
|
mempoolSamples_t samples = CStats::DefaultStats()->mempoolGetValuesInRange(queryFromTime, queryToTime);
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(samples[0].m_time_delta, 0U);
|
||||||
|
BOOST_CHECK_EQUAL(samples[1].m_time_delta, 5U);
|
||||||
|
BOOST_CHECK_EQUAL(samples[1].m_tx_count, 3);
|
||||||
|
BOOST_CHECK_EQUAL(samples[1].m_dyn_mem_usage, 4);
|
||||||
|
|
||||||
|
// check retrieving a subset of the available samples
|
||||||
|
queryFromTime = start;
|
||||||
|
queryToTime = start;
|
||||||
|
samples = CStats::DefaultStats()->mempoolGetValuesInRange(queryFromTime, queryToTime);
|
||||||
|
BOOST_CHECK_EQUAL(samples.size(), 1U);
|
||||||
|
|
||||||
|
// add some samples
|
||||||
|
for (int i = 0; i < 10000; i++) {
|
||||||
|
SetMockTime(start + 10 + i * 5);
|
||||||
|
CStats::DefaultStats()->addMempoolSample(i, i + 1, i + 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
queryFromTime = start + 3600;
|
||||||
|
queryToTime = start + 3600;
|
||||||
|
samples = CStats::DefaultStats()->mempoolGetValuesInRange(queryFromTime, queryToTime);
|
||||||
|
BOOST_CHECK_EQUAL(samples.size(), 1U); //get a single sample
|
||||||
|
|
||||||
|
queryFromTime = start;
|
||||||
|
queryToTime = start + 3600;
|
||||||
|
samples = CStats::DefaultStats()->mempoolGetValuesInRange(queryFromTime, queryToTime);
|
||||||
|
BOOST_CHECK(samples.size() >= 3600 / 5);
|
||||||
|
|
||||||
|
// reduce max memory and add 100 samples to ensure it triggers the cleanup
|
||||||
|
CStats::DefaultStats()->setMaxMemoryUsageTarget(10 * 1024);
|
||||||
|
for (int i = 10000; i < 10100; i++) {
|
||||||
|
SetMockTime(start + 10 + i * 5);
|
||||||
|
CStats::DefaultStats()->addMempoolSample(i, i + 1, i + 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
queryFromTime = start;
|
||||||
|
queryToTime = start + 100;
|
||||||
|
samples = CStats::DefaultStats()->mempoolGetValuesInRange(queryFromTime, queryToTime);
|
||||||
|
BOOST_CHECK_EQUAL(samples.size(), 1U);
|
||||||
|
|
||||||
|
queryFromTime = 0; // no range limits
|
||||||
|
queryToTime = 0; // no range limits
|
||||||
|
samples = CStats::DefaultStats()->mempoolGetValuesInRange(queryFromTime, queryToTime);
|
||||||
|
BOOST_CHECK_EQUAL(samples.size() < 1000U, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_SUITE_END()
|
@ -137,6 +137,7 @@ const std::vector<std::string> RPC_COMMANDS_SAFE_FOR_FUZZING{
|
|||||||
"getmempoolancestors",
|
"getmempoolancestors",
|
||||||
"getmempooldescendants",
|
"getmempooldescendants",
|
||||||
"getmempoolentry",
|
"getmempoolentry",
|
||||||
|
"getmempoolstats",
|
||||||
"getmempoolinfo",
|
"getmempoolinfo",
|
||||||
"getmininginfo",
|
"getmininginfo",
|
||||||
"getnettotals",
|
"getnettotals",
|
||||||
|
@ -43,6 +43,7 @@
|
|||||||
#include <script/script.h>
|
#include <script/script.h>
|
||||||
#include <script/sigcache.h>
|
#include <script/sigcache.h>
|
||||||
#include <signet.h>
|
#include <signet.h>
|
||||||
|
#include <stats/stats.h>
|
||||||
#include <tinyformat.h>
|
#include <tinyformat.h>
|
||||||
#include <txdb.h>
|
#include <txdb.h>
|
||||||
#include <txmempool.h>
|
#include <txmempool.h>
|
||||||
@ -1220,6 +1221,8 @@ MempoolAcceptResult MemPoolAccept::AcceptSingleTransaction(const CTransactionRef
|
|||||||
AssertLockHeld(cs_main);
|
AssertLockHeld(cs_main);
|
||||||
LOCK(m_pool.cs); // mempool "read lock" (held through GetMainSignals().TransactionAddedToMempool())
|
LOCK(m_pool.cs); // mempool "read lock" (held through GetMainSignals().TransactionAddedToMempool())
|
||||||
|
|
||||||
|
const CFeeRate mempool_min_fee_rate = m_pool.GetMinFee();
|
||||||
|
|
||||||
Workspace ws(ptx);
|
Workspace ws(ptx);
|
||||||
|
|
||||||
if (!PreChecks(args, ws)) return MempoolAcceptResult::Failure(ws.m_state);
|
if (!PreChecks(args, ws)) return MempoolAcceptResult::Failure(ws.m_state);
|
||||||
@ -1244,6 +1247,9 @@ MempoolAcceptResult MemPoolAccept::AcceptSingleTransaction(const CTransactionRef
|
|||||||
|
|
||||||
GetMainSignals().TransactionAddedToMempool(ptx, m_pool.GetAndIncrementSequence());
|
GetMainSignals().TransactionAddedToMempool(ptx, m_pool.GetAndIncrementSequence());
|
||||||
|
|
||||||
|
// update mempool stats cache
|
||||||
|
CStats::DefaultStats()->addMempoolSample(m_pool.size(), m_pool.DynamicMemoryUsage(), mempool_min_fee_rate.GetFeePerK());
|
||||||
|
|
||||||
return MempoolAcceptResult::Success(std::move(ws.m_replaced_transactions), ws.m_vsize, ws.m_base_fees,
|
return MempoolAcceptResult::Success(std::move(ws.m_replaced_transactions), ws.m_vsize, ws.m_base_fees,
|
||||||
effective_feerate, single_wtxid);
|
effective_feerate, single_wtxid);
|
||||||
}
|
}
|
||||||
@ -2813,6 +2819,12 @@ bool Chainstate::DisconnectTip(BlockValidationState& state, DisconnectedBlockTra
|
|||||||
// Let wallets know transactions went from 1-confirmed to
|
// Let wallets know transactions went from 1-confirmed to
|
||||||
// 0-confirmed or conflicted:
|
// 0-confirmed or conflicted:
|
||||||
GetMainSignals().BlockDisconnected(pblock, pindexDelete);
|
GetMainSignals().BlockDisconnected(pblock, pindexDelete);
|
||||||
|
|
||||||
|
if (m_mempool) {
|
||||||
|
// add mempool stats sample
|
||||||
|
CStats::DefaultStats()->addMempoolSample(m_mempool->size(), m_mempool->DynamicMemoryUsage(), m_mempool->GetMinFee().GetFeePerK());
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2938,6 +2950,11 @@ bool Chainstate::ConnectTip(BlockValidationState& state, CBlockIndex* pindexNew,
|
|||||||
m_chain.SetTip(*pindexNew);
|
m_chain.SetTip(*pindexNew);
|
||||||
UpdateTip(pindexNew);
|
UpdateTip(pindexNew);
|
||||||
|
|
||||||
|
if (m_mempool) {
|
||||||
|
// add mempool stats sample
|
||||||
|
CStats::DefaultStats()->addMempoolSample(m_mempool->size(), m_mempool->DynamicMemoryUsage(), m_mempool->GetMinFee().GetFeePerK());
|
||||||
|
}
|
||||||
|
|
||||||
const auto time_6{SteadyClock::now()};
|
const auto time_6{SteadyClock::now()};
|
||||||
time_post_connect += time_6 - time_5;
|
time_post_connect += time_6 - time_5;
|
||||||
time_total += time_6 - time_1;
|
time_total += time_6 - time_1;
|
||||||
|
@ -103,7 +103,7 @@ class HelpRpcTest(BitcoinTestFramework):
|
|||||||
# command titles
|
# command titles
|
||||||
titles = [line[3:-3] for line in node.help().splitlines() if line.startswith('==')]
|
titles = [line[3:-3] for line in node.help().splitlines() if line.startswith('==')]
|
||||||
|
|
||||||
components = ['Blockchain', 'Control', 'Mining', 'Network', 'Rawtransactions', 'Util']
|
components = ['Blockchain', 'Control', 'Mining', 'Network', 'Rawtransactions', 'Stats', 'Util']
|
||||||
|
|
||||||
if self.is_wallet_compiled():
|
if self.is_wallet_compiled():
|
||||||
components.append('Wallet')
|
components.append('Wallet')
|
||||||
|
Loading…
Reference in New Issue
Block a user