diff options
Diffstat (limited to 'src/daemon/rpc_command_executor.cpp')
-rw-r--r-- | src/daemon/rpc_command_executor.cpp | 259 |
1 files changed, 167 insertions, 92 deletions
diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp index cca0f75f9..dbf0409e5 100644 --- a/src/daemon/rpc_command_executor.cpp +++ b/src/daemon/rpc_command_executor.cpp @@ -35,6 +35,7 @@ #include "daemon/rpc_command_executor.h" #include "rpc/core_rpc_server_commands_defs.h" #include "cryptonote_core/cryptonote_core.h" +#include "cryptonote_basic/difficulty.h" #include "cryptonote_basic/hardfork.h" #include <boost/format.hpp> #include <ctime> @@ -46,6 +47,19 @@ namespace daemonize { namespace { + const char *get_address_type_name(epee::net_utils::address_type address_type) + { + switch (address_type) + { + default: + case epee::net_utils::address_type::invalid: return "invalid"; + case epee::net_utils::address_type::ipv4: return "IPv4"; + case epee::net_utils::address_type::ipv6: return "IPv6"; + case epee::net_utils::address_type::i2p: return "I2P"; + case epee::net_utils::address_type::tor: return "Tor"; + } + } + void print_peer(std::string const & prefix, cryptonote::peer const & peer) { time_t now; @@ -54,8 +68,8 @@ namespace { std::string id_str; std::string port_str; - std::string elapsed = epee::misc_utils::get_time_interval_string(now - last_seen); - std::string ip_str = epee::string_tools::get_ip_string_from_int32(peer.ip); + std::string elapsed = peer.last_seen == 0 ? "never" : epee::misc_utils::get_time_interval_string(now - last_seen); + std::string ip_str = peer.ip != 0 ? epee::string_tools::get_ip_string_from_int32(peer.ip) : std::string("[") + peer.host + "]"; std::stringstream peer_id_str; peer_id_str << std::hex << std::setw(16) << peer.id; peer_id_str >> id_str; @@ -76,7 +90,7 @@ namespace { << "height: " << boost::lexical_cast<std::string>(header.height) << std::endl << "depth: " << boost::lexical_cast<std::string>(header.depth) << std::endl << "hash: " << header.hash << std::endl - << "difficulty: " << boost::lexical_cast<std::string>(header.difficulty) << std::endl + << "difficulty: " << header.wide_difficulty << std::endl << "POW hash: " << header.pow_hash << std::endl << "block size: " << header.block_size << std::endl << "block weight: " << header.block_weight << std::endl @@ -337,18 +351,41 @@ bool t_rpc_command_executor::show_difficulty() { tools::success_msg_writer() << "BH: " << res.height << ", TH: " << res.top_block_hash - << ", DIFF: " << res.difficulty - << ", HR: " << res.difficulty / res.target << " H/s"; + << ", DIFF: " << res.wide_difficulty + << ", CUM_DIFF: " << res.wide_cumulative_difficulty + << ", HR: " << cryptonote::difficulty_type(res.wide_difficulty) / res.target << " H/s"; return true; } -static std::string get_mining_speed(uint64_t hr) +static void get_metric_prefix(cryptonote::difficulty_type hr, double& hr_d, char& prefix) +{ + if (hr < 1000) + { + prefix = 0; + return; + } + static const char metric_prefixes[4] = { 'k', 'M', 'G', 'T' }; + for (size_t i = 0; i < sizeof(metric_prefixes); ++i) + { + if (hr < 1000000) + { + hr_d = hr.convert_to<double>() / 1000; + prefix = metric_prefixes[i]; + return; + } + hr /= 1000; + } + prefix = 0; +} + +static std::string get_mining_speed(cryptonote::difficulty_type hr) { - if (hr>1e9) return (boost::format("%.2f GH/s") % (hr/1e9)).str(); - if (hr>1e6) return (boost::format("%.2f MH/s") % (hr/1e6)).str(); - if (hr>1e3) return (boost::format("%.2f kH/s") % (hr/1e3)).str(); - return (boost::format("%.0f H/s") % hr).str(); + double hr_d; + char prefix; + get_metric_prefix(hr, hr_d, prefix); + if (prefix == 0) return (boost::format("%.0f H/s") % hr).str(); + return (boost::format("%.2f %cH/s") % hr_d % prefix).str(); } static std::string get_fork_extra_info(uint64_t t, uint64_t now, uint64_t block_time) @@ -465,7 +502,7 @@ bool t_rpc_command_executor::show_status() { % (ires.testnet ? "testnet" : ires.stagenet ? "stagenet" : "mainnet") % bootstrap_msg % (!has_mining_info ? "mining info unavailable" : mining_busy ? "syncing" : mres.active ? ( ( mres.is_background_mining_enabled ? "smart " : "" ) + std::string("mining at ") + get_mining_speed(mres.speed)) : "not mining") - % get_mining_speed(ires.difficulty / ires.target) + % get_mining_speed(cryptonote::difficulty_type(ires.wide_difficulty) / ires.target) % (unsigned)hfres.version % get_fork_extra_info(hfres.earliest_height, net_height, ires.target) % (hfres.state == cryptonote::HardFork::Ready ? "up to date" : hfres.state == cryptonote::HardFork::UpdateNeeded ? "update needed" : "out of date, likely forked") @@ -589,6 +626,7 @@ bool t_rpc_command_executor::print_connections() { } tools::msg_writer() << std::setw(30) << std::left << "Remote Host" + << std::setw(8) << "Type" << std::setw(6) << "SSL" << std::setw(20) << "Peer id" << std::setw(20) << "Support Flags" @@ -609,6 +647,7 @@ bool t_rpc_command_executor::print_connections() { tools::msg_writer() //<< std::setw(30) << std::left << in_out << std::setw(30) << std::left << address + << std::setw(8) << (get_address_type_name((epee::net_utils::address_type)info.address_type)) << std::setw(6) << (info.ssl ? "yes" : "no") << std::setw(20) << epee::string_tools::pad_string(info.peer_id, 16, '0', true) << std::setw(20) << info.support_flags @@ -726,7 +765,7 @@ bool t_rpc_command_executor::print_blockchain_info(uint64_t start_block_index, u << ", size: " << header.block_size << ", weight: " << header.block_weight << " (long term " << header.long_term_weight << "), transactions: " << header.num_txes << std::endl << "major version: " << (unsigned)header.major_version << ", minor version: " << (unsigned)header.minor_version << std::endl << "block id: " << header.hash << ", previous block id: " << header.prev_hash << std::endl - << "difficulty: " << header.difficulty << ", nonce " << header.nonce << ", reward " << cryptonote::print_money(header.reward) << std::endl; + << "difficulty: " << header.wide_difficulty << ", nonce " << header.nonce << ", reward " << cryptonote::print_money(header.reward) << std::endl; first = false; } @@ -1466,13 +1505,14 @@ bool t_rpc_command_executor::get_limit_down() return true; } -bool t_rpc_command_executor::out_peers(uint64_t limit) +bool t_rpc_command_executor::out_peers(bool set, uint32_t limit) { cryptonote::COMMAND_RPC_OUT_PEERS::request req; cryptonote::COMMAND_RPC_OUT_PEERS::response res; epee::json_rpc::error error_resp; + req.set = set; req.out_peers = limit; std::string fail_message = "Unsuccessful"; @@ -1493,18 +1533,20 @@ bool t_rpc_command_executor::out_peers(uint64_t limit) } } - tools::msg_writer() << "Max number of out peers set to " << limit << std::endl; + const std::string s = res.out_peers == (uint32_t)-1 ? "unlimited" : std::to_string(res.out_peers); + tools::msg_writer() << "Max number of out peers set to " << s << std::endl; return true; } -bool t_rpc_command_executor::in_peers(uint64_t limit) +bool t_rpc_command_executor::in_peers(bool set, uint32_t limit) { cryptonote::COMMAND_RPC_IN_PEERS::request req; cryptonote::COMMAND_RPC_IN_PEERS::response res; epee::json_rpc::error error_resp; + req.set = set; req.in_peers = limit; std::string fail_message = "Unsuccessful"; @@ -1525,64 +1567,12 @@ bool t_rpc_command_executor::in_peers(uint64_t limit) } } - tools::msg_writer() << "Max number of in peers set to " << limit << std::endl; + const std::string s = res.in_peers == (uint32_t)-1 ? "unlimited" : std::to_string(res.in_peers); + tools::msg_writer() << "Max number of in peers set to " << s << std::endl; return true; } -bool t_rpc_command_executor::start_save_graph() -{ - cryptonote::COMMAND_RPC_START_SAVE_GRAPH::request req; - cryptonote::COMMAND_RPC_START_SAVE_GRAPH::response res; - std::string fail_message = "Unsuccessful"; - - if (m_is_rpc) - { - if (!m_rpc_client->rpc_request(req, res, "/start_save_graph", fail_message.c_str())) - { - return true; - } - } - - else - { - if (!m_rpc_server->on_start_save_graph(req, res) || res.status != CORE_RPC_STATUS_OK) - { - tools::fail_msg_writer() << make_error(fail_message, res.status); - return true; - } - } - - tools::success_msg_writer() << "Saving graph is now on"; - return true; -} - -bool t_rpc_command_executor::stop_save_graph() -{ - cryptonote::COMMAND_RPC_STOP_SAVE_GRAPH::request req; - cryptonote::COMMAND_RPC_STOP_SAVE_GRAPH::response res; - std::string fail_message = "Unsuccessful"; - - if (m_is_rpc) - { - if (!m_rpc_client->rpc_request(req, res, "/stop_save_graph", fail_message.c_str())) - { - return true; - } - } - - else - { - if (!m_rpc_server->on_stop_save_graph(req, res) || res.status != CORE_RPC_STATUS_OK) - { - tools::fail_msg_writer() << make_error(fail_message, res.status); - return true; - } - } - tools::success_msg_writer() << "Saving graph is now off"; - return true; -} - bool t_rpc_command_executor::hard_fork_info(uint8_t version) { cryptonote::COMMAND_RPC_HARD_FORK_INFO::request req; @@ -1641,14 +1631,14 @@ bool t_rpc_command_executor::print_bans() for (auto i = res.bans.begin(); i != res.bans.end(); ++i) { - tools::msg_writer() << epee::string_tools::get_ip_string_from_int32(i->ip) << " banned for " << i->seconds << " seconds"; + tools::msg_writer() << i->host << " banned for " << i->seconds << " seconds"; } return true; } -bool t_rpc_command_executor::ban(const std::string &ip, time_t seconds) +bool t_rpc_command_executor::ban(const std::string &address, time_t seconds) { cryptonote::COMMAND_RPC_SETBANS::request req; cryptonote::COMMAND_RPC_SETBANS::response res; @@ -1656,11 +1646,8 @@ bool t_rpc_command_executor::ban(const std::string &ip, time_t seconds) epee::json_rpc::error error_resp; cryptonote::COMMAND_RPC_SETBANS::ban ban; - if (!epee::string_tools::get_ip_int32_from_string(ban.ip, ip)) - { - tools::fail_msg_writer() << "Invalid IP"; - return true; - } + ban.host = address; + ban.ip = 0; ban.ban = true; ban.seconds = seconds; req.bans.push_back(ban); @@ -1684,7 +1671,7 @@ bool t_rpc_command_executor::ban(const std::string &ip, time_t seconds) return true; } -bool t_rpc_command_executor::unban(const std::string &ip) +bool t_rpc_command_executor::unban(const std::string &address) { cryptonote::COMMAND_RPC_SETBANS::request req; cryptonote::COMMAND_RPC_SETBANS::response res; @@ -1692,11 +1679,8 @@ bool t_rpc_command_executor::unban(const std::string &ip) epee::json_rpc::error error_resp; cryptonote::COMMAND_RPC_SETBANS::ban ban; - if (!epee::string_tools::get_ip_int32_from_string(ban.ip, ip)) - { - tools::fail_msg_writer() << "Invalid IP"; - return true; - } + ban.host = address; + ban.ip = 0; ban.ban = false; ban.seconds = 0; req.bans.push_back(ban); @@ -1720,6 +1704,39 @@ bool t_rpc_command_executor::unban(const std::string &ip) return true; } +bool t_rpc_command_executor::banned(const std::string &address) +{ + cryptonote::COMMAND_RPC_BANNED::request req; + cryptonote::COMMAND_RPC_BANNED::response res; + std::string fail_message = "Unsuccessful"; + epee::json_rpc::error error_resp; + + req.address = address; + + if (m_is_rpc) + { + if (!m_rpc_client->json_rpc_request(req, res, "banned", fail_message.c_str())) + { + return true; + } + } + else + { + if (!m_rpc_server->on_banned(req, res, error_resp) || res.status != CORE_RPC_STATUS_OK) + { + tools::fail_msg_writer() << make_error(fail_message, res.status); + return true; + } + } + + if (res.banned) + tools::msg_writer() << address << " is banned for " << res.seconds << " seconds"; + else + tools::msg_writer() << address << " is not banned"; + + return true; +} + bool t_rpc_command_executor::flush_txpool(const std::string &txid) { cryptonote::COMMAND_RPC_FLUSH_TRANSACTION_POOL::request req; @@ -1824,7 +1841,7 @@ bool t_rpc_command_executor::print_coinbase_tx_sum(uint64_t height, uint64_t cou return true; } -bool t_rpc_command_executor::alt_chain_info(const std::string &tip) +bool t_rpc_command_executor::alt_chain_info(const std::string &tip, size_t above, uint64_t last_blocks) { cryptonote::COMMAND_RPC_GET_INFO::request ireq; cryptonote::COMMAND_RPC_GET_INFO::response ires; @@ -1861,16 +1878,31 @@ bool t_rpc_command_executor::alt_chain_info(const std::string &tip) if (tip.empty()) { - tools::msg_writer() << boost::lexical_cast<std::string>(res.chains.size()) << " alternate chains found:"; - for (const auto &chain: res.chains) + auto chains = res.chains; + std::sort(chains.begin(), chains.end(), [](const cryptonote::COMMAND_RPC_GET_ALTERNATE_CHAINS::chain_info &info0, cryptonote::COMMAND_RPC_GET_ALTERNATE_CHAINS::chain_info &info1){ return info0.height < info1.height; }); + std::vector<size_t> display; + for (size_t i = 0; i < chains.size(); ++i) { - uint64_t start_height = (chain.height - chain.length + 1); + const auto &chain = chains[i]; + if (chain.length <= above) + continue; + const uint64_t start_height = (chain.height - chain.length + 1); + if (last_blocks > 0 && ires.height - 1 - start_height >= last_blocks) + continue; + display.push_back(i); + } + tools::msg_writer() << boost::lexical_cast<std::string>(display.size()) << " alternate chains found:"; + for (const size_t idx: display) + { + const auto &chain = chains[idx]; + const uint64_t start_height = (chain.height - chain.length + 1); tools::msg_writer() << chain.length << " blocks long, from height " << start_height << " (" << (ires.height - start_height - 1) - << " deep), diff " << chain.difficulty << ": " << chain.block_hash; + << " deep), diff " << chain.wide_difficulty << ": " << chain.block_hash; } } else { + const uint64_t now = time(NULL); const auto i = std::find_if(res.chains.begin(), res.chains.end(), [&tip](cryptonote::COMMAND_RPC_GET_ALTERNATE_CHAINS::chain_info &info){ return info.block_hash == tip; }); if (i != res.chains.end()) { @@ -1878,10 +1910,53 @@ bool t_rpc_command_executor::alt_chain_info(const std::string &tip) tools::success_msg_writer() << "Found alternate chain with tip " << tip; uint64_t start_height = (chain.height - chain.length + 1); tools::msg_writer() << chain.length << " blocks long, from height " << start_height << " (" << (ires.height - start_height - 1) - << " deep), diff " << chain.difficulty << ":"; + << " deep), diff " << chain.wide_difficulty << ":"; for (const std::string &block_id: chain.block_hashes) tools::msg_writer() << " " << block_id; tools::msg_writer() << "Chain parent on main chain: " << chain.main_chain_parent_block; + cryptonote::COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH::request bhreq; + cryptonote::COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH::response bhres; + bhreq.hashes = chain.block_hashes; + bhreq.hashes.push_back(chain.main_chain_parent_block); + bhreq.fill_pow_hash = false; + if (m_is_rpc) + { + if (!m_rpc_client->json_rpc_request(bhreq, bhres, "getblockheaderbyhash", fail_message.c_str())) + { + return true; + } + } + else + { + if (!m_rpc_server->on_get_block_header_by_hash(bhreq, bhres, error_resp)) + { + tools::fail_msg_writer() << make_error(fail_message, res.status); + return true; + } + } + if (bhres.block_headers.size() != chain.length + 1) + { + tools::fail_msg_writer() << "Failed to get block header info for alt chain"; + return true; + } + uint64_t t0 = bhres.block_headers.front().timestamp, t1 = t0; + for (const cryptonote::block_header_response &block_header: bhres.block_headers) + { + t0 = std::min<uint64_t>(t0, block_header.timestamp); + t1 = std::max<uint64_t>(t1, block_header.timestamp); + } + const uint64_t dt = t1 - t0; + const uint64_t age = std::max(dt, t0 < now ? now - t0 : 0); + tools::msg_writer() << "Age: " << tools::get_human_readable_timespan(age); + if (chain.length > 1) + { + tools::msg_writer() << "Time span: " << tools::get_human_readable_timespan(dt); + cryptonote::difficulty_type start_difficulty = bhres.block_headers.back().difficulty; + if (start_difficulty > 0) + tools::msg_writer() << "Approximated " << 100.f * DIFFICULTY_TARGET_V2 * chain.length / dt << "% of network hash rate"; + else + tools::fail_msg_writer() << "Bad cmumulative difficulty reported by dameon"; + } } else tools::fail_msg_writer() << "Block hash " << tip << " is not the tip of any known alternate chain"; @@ -1939,7 +2014,7 @@ bool t_rpc_command_executor::print_blockchain_dynamic_stats(uint64_t nblocks) } } - tools::msg_writer() << "Height: " << ires.height << ", diff " << ires.difficulty << ", cum. diff " << ires.cumulative_difficulty + tools::msg_writer() << "Height: " << ires.height << ", diff " << ires.wide_difficulty << ", cum. diff " << ires.wide_cumulative_difficulty << ", target " << ires.target << " sec" << ", dyn fee " << cryptonote::print_money(feres.fee) << "/" << (hfres.enabled ? "byte" : "kB"); if (nblocks > 0) @@ -1966,7 +2041,7 @@ bool t_rpc_command_executor::print_blockchain_dynamic_stats(uint64_t nblocks) } } - double avgdiff = 0; + cryptonote::difficulty_type avgdiff = 0; double avgnumtxes = 0; double avgreward = 0; std::vector<uint64_t> weights; @@ -1975,7 +2050,7 @@ bool t_rpc_command_executor::print_blockchain_dynamic_stats(uint64_t nblocks) std::vector<unsigned> major_versions(256, 0), minor_versions(256, 0); for (const auto &bhr: bhres.headers) { - avgdiff += bhr.difficulty; + avgdiff += cryptonote::difficulty_type(bhr.wide_difficulty); avgnumtxes += bhr.num_txes; avgreward += bhr.reward; weights.push_back(bhr.block_weight); @@ -1990,7 +2065,7 @@ bool t_rpc_command_executor::print_blockchain_dynamic_stats(uint64_t nblocks) avgnumtxes /= nblocks; avgreward /= nblocks; uint64_t median_block_weight = epee::misc_utils::median(weights); - tools::msg_writer() << "Last " << nblocks << ": avg. diff " << (uint64_t)avgdiff << ", " << (latest - earliest) / nblocks << " avg sec/block, avg num txes " << avgnumtxes + tools::msg_writer() << "Last " << nblocks << ": avg. diff " << avgdiff << ", " << (latest - earliest) / nblocks << " avg sec/block, avg num txes " << avgnumtxes << ", avg. reward " << cryptonote::print_money(avgreward) << ", median block weight " << median_block_weight; unsigned int max_major = 256, max_minor = 256; |