diff --git a/src/daemon/command_parser_executor.cpp b/src/daemon/command_parser_executor.cpp index 7381dd06f..9d28cd41e 100644 --- a/src/daemon/command_parser_executor.cpp +++ b/src/daemon/command_parser_executor.cpp @@ -511,4 +511,22 @@ bool t_command_parser_executor::alt_chain_info(const std::vector& a return m_executor.alt_chain_info(); } +bool t_command_parser_executor::print_blockchain_dynamic_stats(const std::vector& args) +{ + if(args.size() != 1) + { + std::cout << "Exactly one parameter is needed" << std::endl; + return false; + } + + uint64_t nblocks = 0; + if(!epee::string_tools::get_xtype_from_string(nblocks, args[0]) || nblocks == 0) + { + std::cout << "wrong number of blocks" << std::endl; + return false; + } + + return m_executor.print_blockchain_dynamic_stats(nblocks); +} + } // namespace daemonize diff --git a/src/daemon/command_parser_executor.h b/src/daemon/command_parser_executor.h index cc929db00..7763ebed0 100644 --- a/src/daemon/command_parser_executor.h +++ b/src/daemon/command_parser_executor.h @@ -121,6 +121,8 @@ public: bool print_coinbase_tx_sum(const std::vector& args); bool alt_chain_info(const std::vector& args); + + bool print_blockchain_dynamic_stats(const std::vector& args); }; } // namespace daemonize diff --git a/src/daemon/command_server.cpp b/src/daemon/command_server.cpp index 88c49d111..086478a47 100644 --- a/src/daemon/command_server.cpp +++ b/src/daemon/command_server.cpp @@ -230,6 +230,11 @@ t_command_server::t_command_server( , std::bind(&t_command_parser_executor::alt_chain_info, &m_parser, p::_1) , "Print information about alternative chains" ); + m_command_lookup.set_handler( + "bc_dyn_stats" + , std::bind(&t_command_parser_executor::print_blockchain_dynamic_stats, &m_parser, p::_1) + , "Print information about current blockchain dynamic state" + ); } bool t_command_server::process_command_str(const std::string& cmd) diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp index 447783d76..a4da13023 100644 --- a/src/daemon/rpc_command_executor.cpp +++ b/src/daemon/rpc_command_executor.cpp @@ -1406,5 +1406,108 @@ bool t_rpc_command_executor::alt_chain_info() return true; } +bool t_rpc_command_executor::print_blockchain_dynamic_stats(uint64_t nblocks) +{ + cryptonote::COMMAND_RPC_GET_INFO::request ireq; + cryptonote::COMMAND_RPC_GET_INFO::response ires; + cryptonote::COMMAND_RPC_GET_BLOCK_HEADERS_RANGE::request bhreq; + cryptonote::COMMAND_RPC_GET_BLOCK_HEADERS_RANGE::response bhres; + cryptonote::COMMAND_RPC_GET_PER_KB_FEE_ESTIMATE::request fereq; + cryptonote::COMMAND_RPC_GET_PER_KB_FEE_ESTIMATE::response feres; + epee::json_rpc::error error_resp; + + std::string fail_message = "Problem fetching info"; + + if (m_is_rpc) + { + if (!m_rpc_client->rpc_request(ireq, ires, "/getinfo", fail_message.c_str())) + { + return true; + } + if (!m_rpc_client->rpc_request(fereq, feres, "/get_fee_estimate", fail_message.c_str())) + { + return true; + } + } + else + { + if (!m_rpc_server->on_get_info(ireq, ires) || ires.status != CORE_RPC_STATUS_OK) + { + tools::fail_msg_writer() << fail_message.c_str(); + return true; + } + if (!m_rpc_server->on_get_per_kb_fee_estimate(fereq, feres, error_resp) || feres.status != CORE_RPC_STATUS_OK) + { + tools::fail_msg_writer() << fail_message.c_str(); + return true; + } + } + + tools::msg_writer() << "Height: " << ires.height << ", diff " << ires.difficulty << ", cum. diff " << ires.cumulative_difficulty + << ", target " << ires.target << " sec" << ", dyn fee " << cryptonote::print_money(feres.fee) << "/kB"; + + if (nblocks > 0) + { + if (nblocks > ires.height) + nblocks = ires.height; + + bhreq.start_height = ires.height - nblocks; + bhreq.end_height = ires.height - 1; + if (m_is_rpc) + { + if (!m_rpc_client->rpc_request(bhreq, bhres, "/getblockheadersrange", fail_message.c_str())) + { + return true; + } + } + else + { + if (!m_rpc_server->on_get_block_headers_range(bhreq, bhres, error_resp) || bhres.status != CORE_RPC_STATUS_OK) + { + tools::fail_msg_writer() << fail_message.c_str(); + return true; + } + } + + double avgdiff = 0; + double avgnumtxes = 0; + double avgreward = 0; + std::vector sizes; + sizes.reserve(nblocks); + std::vector major_versions(256, 0), minor_versions(256, 0); + for (const auto &bhr: bhres.headers) + { + avgdiff += bhr.difficulty; + avgnumtxes += bhr.num_txes; + avgreward += bhr.reward; + sizes.push_back(bhr.block_size); + static_assert(sizeof(bhr.major_version) == 1, "major_version expected to be uint8_t"); + static_assert(sizeof(bhr.minor_version) == 1, "major_version expected to be uint8_t"); + major_versions[(unsigned)bhr.major_version]++; + minor_versions[(unsigned)bhr.minor_version]++; + } + avgdiff /= nblocks; + avgnumtxes /= nblocks; + avgreward /= nblocks; + uint64_t median_block_size = epee::misc_utils::median(sizes); + tools::msg_writer() << "Last " << nblocks << ": avg. diff " << (uint64_t)avgdiff << ", avg num txes " << avgnumtxes + << ", avg. reward " << cryptonote::print_money(avgreward) << ", median block size " << median_block_size; + + unsigned int max_major = 256, max_minor = 256; + while (max_major > 0 && !major_versions[--max_major]); + while (max_minor > 0 && !minor_versions[--max_minor]); + std::string s = ""; + for (unsigned n = 0; n <= max_major; ++n) + if (major_versions[n]) + s += (s.empty() ? "" : ", ") + boost::lexical_cast(major_versions[n]) + std::string(" v") + boost::lexical_cast(n); + tools::msg_writer() << "Block versions: " << s; + s = ""; + for (unsigned n = 0; n <= max_minor; ++n) + if (minor_versions[n]) + s += (s.empty() ? "" : ", ") + boost::lexical_cast(minor_versions[n]) + std::string(" v") + boost::lexical_cast(n); + tools::msg_writer() << "Voting for: " << s; + } + return true; +} }// namespace daemonize diff --git a/src/daemon/rpc_command_executor.h b/src/daemon/rpc_command_executor.h index a6c712c04..af283c1f1 100644 --- a/src/daemon/rpc_command_executor.h +++ b/src/daemon/rpc_command_executor.h @@ -139,6 +139,8 @@ public: bool print_coinbase_tx_sum(uint64_t height, uint64_t count); bool alt_chain_info(); + + bool print_blockchain_dynamic_stats(uint64_t nblocks); }; } // namespace daemonize diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index ddf892cae..fc93b3a51 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -896,6 +896,7 @@ namespace cryptonote response.difficulty = m_core.get_blockchain_storage().block_difficulty(height); response.reward = get_block_reward(blk); response.block_size = m_core.get_blockchain_storage().get_db().get_block_size(height); + response.num_txes = blk.tx_hashes.size(); return true; } //------------------------------------------------------------------------------------------------------------------------------ diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h index fa86c08e4..49de94ad9 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 4 +#define CORE_RPC_VERSION_MINOR 5 #define CORE_RPC_VERSION (((CORE_RPC_VERSION_MAJOR)<<16)|(CORE_RPC_VERSION_MINOR)) struct COMMAND_RPC_GET_HEIGHT @@ -706,6 +706,7 @@ namespace cryptonote difficulty_type difficulty; uint64_t reward; uint64_t block_size; + uint64_t num_txes; BEGIN_KV_SERIALIZE_MAP() KV_SERIALIZE(major_version) @@ -720,6 +721,7 @@ namespace cryptonote KV_SERIALIZE(difficulty) KV_SERIALIZE(reward) KV_SERIALIZE(block_size) + KV_SERIALIZE(num_txes) END_KV_SERIALIZE_MAP() };