aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/cryptonote_core/tx_pool.cpp48
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.inl4
-rw-r--r--src/daemon/rpc_command_executor.cpp43
-rw-r--r--src/rpc/core_rpc_server_commands_defs.h17
-rw-r--r--src/wallet/wallet2.cpp4
-rw-r--r--src/wallet/wallet2.h5
-rw-r--r--src/wallet/wallet_errors.h10
7 files changed, 123 insertions, 8 deletions
diff --git a/src/cryptonote_core/tx_pool.cpp b/src/cryptonote_core/tx_pool.cpp
index 515918cfa..589162a3e 100644
--- a/src/cryptonote_core/tx_pool.cpp
+++ b/src/cryptonote_core/tx_pool.cpp
@@ -556,8 +556,9 @@ namespace cryptonote
CRITICAL_REGION_LOCAL(m_transactions_lock);
CRITICAL_REGION_LOCAL1(m_blockchain);
const uint64_t now = time(NULL);
+ std::map<uint64_t, txpool_histo> agebytes;
stats.txs_total = m_blockchain.get_txpool_tx_count();
- m_blockchain.for_all_txpool_txes([&stats, now](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *bd){
+ m_blockchain.for_all_txpool_txes([&stats, now, &agebytes](const crypto::hash &txid, const txpool_tx_meta_t &meta, const cryptonote::blobdata *bd){
stats.bytes_total += meta.blob_size;
if (!stats.bytes_min || meta.blob_size < stats.bytes_min)
stats.bytes_min = meta.blob_size;
@@ -572,8 +573,53 @@ namespace cryptonote
stats.num_10m++;
if (meta.last_failed_height)
stats.num_failing++;
+ uint64_t age = now - meta.receive_time;
+ agebytes[age].txs++;
+ agebytes[age].bytes += meta.blob_size;
return true;
});
+ if (stats.txs_total > 1)
+ {
+ /* looking for 98th percentile */
+ size_t end = stats.txs_total * 0.02;
+ uint64_t delta, factor;
+ std::map<uint64_t, txpool_histo>::iterator it, i2;
+ if (end)
+ {
+ /* If enough txs, spread the first 98% of results across
+ * the first 9 bins, drop final 2% in last bin.
+ */
+ it=agebytes.end();
+ for (size_t n=0; n <= end; n++, it--);
+ stats.histo_98pc = it->first;
+ factor = 9;
+ delta = it->first;
+ stats.histo.resize(10);
+ } else
+ {
+ /* If not enough txs, don't reserve the last slot;
+ * spread evenly across all 10 bins.
+ */
+ stats.histo_98pc = 0;
+ it = agebytes.end();
+ factor = stats.txs_total > 9 ? 10 : stats.txs_total;
+ delta = now - stats.oldest;
+ stats.histo.resize(factor);
+ }
+ if (!delta)
+ delta = 1;
+ for (i2 = agebytes.begin(); i2 != it; i2++)
+ {
+ size_t i = (i2->first * factor - 1) / delta;
+ stats.histo[i].txs += i2->second.txs;
+ stats.histo[i].bytes += i2->second.bytes;
+ }
+ for (; i2 != agebytes.end(); i2++)
+ {
+ stats.histo[factor].txs += i2->second.txs;
+ stats.histo[factor].bytes += i2->second.bytes;
+ }
+ }
}
//------------------------------------------------------------------
//TODO: investigate whether boolean return is appropriate
diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
index 465932e18..0b99aa7bd 100644
--- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl
+++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl
@@ -647,9 +647,6 @@ namespace cryptonote
return 1;
}
- for (auto txidx: arg.missing_tx_indices)
- MDEBUG(" tx " << b.tx_hashes[txidx]);
-
std::vector<crypto::hash> txids;
NOTIFY_NEW_FLUFFY_BLOCK::request fluffy_response;
fluffy_response.b.block = t_serializable_object_to_blob(b);
@@ -659,6 +656,7 @@ namespace cryptonote
{
if(tx_idx < b.tx_hashes.size())
{
+ MDEBUG(" tx " << b.tx_hashes[tx_idx]);
txids.push_back(b.tx_hashes[tx_idx]);
}
else
diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp
index d5bde7f09..1c9cd714d 100644
--- a/src/daemon/rpc_command_executor.cpp
+++ b/src/daemon/rpc_command_executor.cpp
@@ -92,6 +92,19 @@ namespace {
return s + " " + (t > now ? "in the future" : "ago");
}
+ std::string get_time_hms(time_t t)
+ {
+ unsigned int hours, minutes, seconds;
+ char buffer[24];
+ hours = t / 3600;
+ t %= 3600;
+ minutes = t / 60;
+ t %= 60;
+ seconds = t;
+ snprintf(buffer, sizeof(buffer), "%02u:%02u:%02u", hours, minutes, seconds);
+ return std::string(buffer);
+ }
+
std::string make_error(const std::string &base, const std::string &status)
{
if (status == CORE_RPC_STATUS_OK)
@@ -939,7 +952,35 @@ bool t_rpc_command_executor::print_transaction_pool_stats() {
tools::msg_writer() << n_transactions << " tx(es), " << res.pool_stats.bytes_total << " bytes total (min " << res.pool_stats.bytes_min << ", max " << res.pool_stats.bytes_max << ", avg " << avg_bytes << ")" << std::endl
<< "fees " << cryptonote::print_money(res.pool_stats.fee_total) << " (avg " << cryptonote::print_money(n_transactions ? res.pool_stats.fee_total / n_transactions : 0) << " per tx" << ", " << cryptonote::print_money(res.pool_stats.bytes_total ? res.pool_stats.fee_total / res.pool_stats.bytes_total : 0) << " per byte )" << std::endl
- << res.pool_stats.num_not_relayed << " not relayed, " << res.pool_stats.num_failing << " failing, " << res.pool_stats.num_10m << " older than 10 minutes (oldest " << (res.pool_stats.oldest == 0 ? "-" : get_human_time_ago(res.pool_stats.oldest, now)) << ")" << std::endl;
+ << res.pool_stats.num_not_relayed << " not relayed, " << res.pool_stats.num_failing << " failing, " << res.pool_stats.num_10m << " older than 10 minutes (oldest " << (res.pool_stats.oldest == 0 ? "-" : get_human_time_ago(res.pool_stats.oldest, now)) << ")";
+
+ if (n_transactions > 1 && res.pool_stats.histo.size())
+ {
+ std::vector<uint64_t> times;
+ uint64_t numer;
+ size_t i, n = res.pool_stats.histo.size(), denom;
+ times.resize(n);
+ if (res.pool_stats.histo_98pc)
+ {
+ numer = res.pool_stats.histo_98pc;
+ denom = n-1;
+ for (i=0; i<denom; i++)
+ times[i] = i * numer / denom;
+ times[i] = res.pool_stats.oldest;
+ } else
+ {
+ numer = now - res.pool_stats.oldest;
+ denom = n;
+ for (i=0; i<denom; i++)
+ times[i] = i * numer / denom;
+ }
+ tools::msg_writer() << " Age Txes Bytes";
+ for (i=0; i<n; i++)
+ {
+ tools::msg_writer() << get_time_hms(times[i]) << setw(8) << res.pool_stats.histo[i].txs << setw(12) << res.pool_stats.histo[i].bytes;
+ }
+ }
+ tools::msg_writer();
return true;
}
diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h
index f5fe46375..7a1f5a963 100644
--- a/src/rpc/core_rpc_server_commands_defs.h
+++ b/src/rpc/core_rpc_server_commands_defs.h
@@ -49,7 +49,7 @@ namespace cryptonote
// advance which version they will stop working with
// Don't go over 32767 for any of these
#define CORE_RPC_VERSION_MAJOR 1
-#define CORE_RPC_VERSION_MINOR 11
+#define CORE_RPC_VERSION_MINOR 12
#define MAKE_CORE_RPC_VERSION(major,minor) (((major)<<16)|(minor))
#define CORE_RPC_VERSION MAKE_CORE_RPC_VERSION(CORE_RPC_VERSION_MAJOR, CORE_RPC_VERSION_MINOR)
@@ -1052,6 +1052,17 @@ namespace cryptonote
};
};
+ struct txpool_histo
+ {
+ uint32_t txs;
+ uint64_t bytes;
+
+ BEGIN_KV_SERIALIZE_MAP()
+ KV_SERIALIZE(txs)
+ KV_SERIALIZE(bytes)
+ END_KV_SERIALIZE_MAP()
+ };
+
struct txpool_stats
{
uint64_t bytes_total;
@@ -1063,6 +1074,8 @@ namespace cryptonote
uint32_t num_failing;
uint32_t num_10m;
uint32_t num_not_relayed;
+ uint64_t histo_98pc;
+ std::vector<txpool_histo> histo;
BEGIN_KV_SERIALIZE_MAP()
KV_SERIALIZE(bytes_total)
@@ -1074,6 +1087,8 @@ namespace cryptonote
KV_SERIALIZE(num_failing)
KV_SERIALIZE(num_10m)
KV_SERIALIZE(num_not_relayed)
+ KV_SERIALIZE(histo_98pc)
+ KV_SERIALIZE_CONTAINER_POD_AS_BLOB(histo)
END_KV_SERIALIZE_MAP()
};
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index 96ba04c47..ee2b6055c 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -511,6 +511,7 @@ bool wallet2::init(std::string daemon_address, boost::optional<epee::net_utils::
{
if(m_http_client.is_connected())
m_http_client.disconnect();
+ m_is_initialized = true;
m_upper_transaction_size_limit = upper_transaction_size_limit;
m_daemon_address = std::move(daemon_address);
m_daemon_login = std::move(daemon_login);
@@ -1845,6 +1846,7 @@ void wallet2::detach_blockchain(uint64_t height)
//----------------------------------------------------------------------------------------------------
bool wallet2::deinit()
{
+ m_is_initialized=false;
return true;
}
//----------------------------------------------------------------------------------------------------
@@ -2361,6 +2363,8 @@ bool wallet2::prepare_file_names(const std::string& file_path)
//----------------------------------------------------------------------------------------------------
bool wallet2::check_connection(uint32_t *version, uint32_t timeout)
{
+ THROW_WALLET_EXCEPTION_IF(!m_is_initialized, error::wallet_not_initialized);
+
boost::lock_guard<boost::mutex> lock(m_daemon_rpc_mutex);
if(!m_http_client.is_connected())
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index bde233b33..e7692badb 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -105,7 +105,7 @@ namespace tools
};
private:
- wallet2(const wallet2&) : m_run(true), m_callback(0), m_testnet(false), m_always_confirm_transfers(true), m_print_ring_members(false), m_store_tx_info(true), m_default_mixin(0), m_default_priority(0), m_refresh_type(RefreshOptimizeCoinbase), m_auto_refresh(true), m_refresh_from_block_height(0), m_confirm_missing_payment_id(true), m_ask_password(true), m_min_output_count(0), m_min_output_value(0), m_merge_destinations(false), m_node_rpc_proxy(m_http_client, m_daemon_rpc_mutex) {}
+ wallet2(const wallet2&) : m_run(true), m_callback(0), m_testnet(false), m_always_confirm_transfers(true), m_print_ring_members(false), m_store_tx_info(true), m_default_mixin(0), m_default_priority(0), m_refresh_type(RefreshOptimizeCoinbase), m_auto_refresh(true), m_refresh_from_block_height(0), m_confirm_missing_payment_id(true), m_ask_password(true), m_min_output_count(0), m_min_output_value(0), m_merge_destinations(false), m_is_initialized(false),m_node_rpc_proxy(m_http_client, m_daemon_rpc_mutex) {}
public:
static const char* tr(const char* str);
@@ -129,7 +129,7 @@ namespace tools
//! Just parses variables.
static std::unique_ptr<wallet2> make_dummy(const boost::program_options::variables_map& vm);
- wallet2(bool testnet = false, bool restricted = false) : m_run(true), m_callback(0), m_testnet(testnet), m_always_confirm_transfers(true), m_print_ring_members(false), m_store_tx_info(true), m_default_mixin(0), m_default_priority(0), m_refresh_type(RefreshOptimizeCoinbase), m_auto_refresh(true), m_refresh_from_block_height(0), m_confirm_missing_payment_id(true), m_ask_password(true), m_min_output_count(0), m_min_output_value(0), m_merge_destinations(false), m_restricted(restricted), is_old_file_format(false), m_node_rpc_proxy(m_http_client, m_daemon_rpc_mutex) {}
+ wallet2(bool testnet = false, bool restricted = false) : m_run(true), m_callback(0), m_testnet(testnet), m_always_confirm_transfers(true), m_print_ring_members(false), m_store_tx_info(true), m_default_mixin(0), m_default_priority(0), m_refresh_type(RefreshOptimizeCoinbase), m_auto_refresh(true), m_refresh_from_block_height(0), m_confirm_missing_payment_id(true), m_ask_password(true), m_min_output_count(0), m_min_output_value(0), m_merge_destinations(false), m_is_initialized(false), m_restricted(restricted), is_old_file_format(false), m_node_rpc_proxy(m_http_client, m_daemon_rpc_mutex) {}
struct transfer_details
{
@@ -695,6 +695,7 @@ namespace tools
uint32_t m_min_output_count;
uint64_t m_min_output_value;
bool m_merge_destinations;
+ bool m_is_initialized;
NodeRPCProxy m_node_rpc_proxy;
std::unordered_set<crypto::hash> m_scanned_pool_txs[2];
};
diff --git a/src/wallet/wallet_errors.h b/src/wallet/wallet_errors.h
index 3e3578149..16807e045 100644
--- a/src/wallet/wallet_errors.h
+++ b/src/wallet/wallet_errors.h
@@ -49,6 +49,7 @@ namespace tools
// wallet_runtime_error *
// wallet_internal_error
// unexpected_txin_type
+ // wallet_not_initialized
// std::logic_error
// wallet_logic_error *
// file_exists
@@ -177,6 +178,15 @@ namespace tools
cryptonote::transaction m_tx;
};
//----------------------------------------------------------------------------------------------------
+ struct wallet_not_initialized : public wallet_internal_error
+ {
+ explicit wallet_not_initialized(std::string&& loc)
+ : wallet_internal_error(std::move(loc), "wallet is not initialized")
+ {
+ }
+ };
+
+ //----------------------------------------------------------------------------------------------------
const char* const file_error_messages[] = {
"file already exists",
"file not found",