From 96cbecffd7235c1cf7ff5717fabe2d94d3192736 Mon Sep 17 00:00:00 2001 From: Thomas Winget Date: Thu, 5 Feb 2015 04:11:20 -0500 Subject: [PATCH] RPC calls for background daemon added in The RPC calls the daemon executable uses to talk to the running daemon instance have mostly been added back in. Rate limiting has not been added in upstream, but is on its way in a separate effort, so those calls are still NOPed out. --- src/cryptonote_core/cryptonote_core.cpp | 5 + src/cryptonote_core/cryptonote_core.h | 2 + src/daemon/command_server.cpp | 7 +- src/daemon/main.cpp | 49 +++---- src/daemon/rpc_command_executor.cpp | 33 +---- src/rpc/core_rpc_server.cpp | 69 ++++++++++ src/rpc/core_rpc_server.h | 11 ++ src/rpc/core_rpc_server_commands_defs.h | 175 +++++++++++++++++++++++- 8 files changed, 300 insertions(+), 51 deletions(-) diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp index 39c7fe92..11127290 100644 --- a/src/cryptonote_core/cryptonote_core.cpp +++ b/src/cryptonote_core/cryptonote_core.cpp @@ -110,6 +110,11 @@ namespace cryptonote return res; } //----------------------------------------------------------------------------------- + void core::stop() + { + graceful_exit(); + } + //----------------------------------------------------------------------------------- void core::init_options(boost::program_options::options_description& /*desc*/) { } diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h index 12405e08..1921ef14 100644 --- a/src/cryptonote_core/cryptonote_core.h +++ b/src/cryptonote_core/cryptonote_core.h @@ -125,6 +125,8 @@ namespace cryptonote bool update_checkpoints(); + void stop(); + private: bool add_new_tx(const transaction& tx, const crypto::hash& tx_hash, const crypto::hash& tx_prefix_hash, size_t blob_size, tx_verification_context& tvc, bool keeped_by_block); bool add_new_tx(const transaction& tx, tx_verification_context& tvc, bool keeped_by_block); diff --git a/src/daemon/command_server.cpp b/src/daemon/command_server.cpp index ed92fd34..bedceffe 100644 --- a/src/daemon/command_server.cpp +++ b/src/daemon/command_server.cpp @@ -155,7 +155,12 @@ bool t_command_server::process_command_str(const std::string& cmd) bool t_command_server::process_command_vec(const std::vector& cmd) { - return m_command_lookup.process_command_vec(cmd); + bool result = m_command_lookup.process_command_vec(cmd); + if (!result) + { + help(std::vector()); + } + return result; } bool t_command_server::help(const std::vector& args) diff --git a/src/daemon/main.cpp b/src/daemon/main.cpp index a2b38929..2f95370c 100644 --- a/src/daemon/main.cpp +++ b/src/daemon/main.cpp @@ -156,34 +156,37 @@ int main(int argc, char const * argv[]) po::notify(vm); // If there are positional options, we're running a daemon command - if (command_line::has_arg(vm, daemon_args::arg_command)) { auto command = command_line::get_arg(vm, daemon_args::arg_command); - auto rpc_ip_str = command_line::get_arg(vm, cryptonote::core_rpc_server::arg_rpc_bind_ip); - auto rpc_port_str = command_line::get_arg(vm, cryptonote::core_rpc_server::arg_rpc_bind_port); - uint32_t rpc_ip; - uint16_t rpc_port; - if (!epee::string_tools::get_ip_int32_from_string(rpc_ip, rpc_ip_str)) + if (command.size()) { - std::cerr << "Invalid IP: " << rpc_ip_str << std::endl; - return 1; - } - if (!epee::string_tools::get_xtype_from_string(rpc_port, rpc_port_str)) - { - std::cerr << "Invalid port: " << rpc_port_str << std::endl; - return 1; - } + auto rpc_ip_str = command_line::get_arg(vm, cryptonote::core_rpc_server::arg_rpc_bind_ip); + auto rpc_port_str = command_line::get_arg(vm, cryptonote::core_rpc_server::arg_rpc_bind_port); - daemonize::t_command_server rpc_commands{rpc_ip, rpc_port}; - if (rpc_commands.process_command_vec(command)) - { - return 0; - } - else - { - std::cerr << "Unknown command" << std::endl; - return 1; + uint32_t rpc_ip; + uint16_t rpc_port; + if (!epee::string_tools::get_ip_int32_from_string(rpc_ip, rpc_ip_str)) + { + std::cerr << "Invalid IP: " << rpc_ip_str << std::endl; + return 1; + } + if (!epee::string_tools::get_xtype_from_string(rpc_port, rpc_port_str)) + { + std::cerr << "Invalid port: " << rpc_port_str << std::endl; + return 1; + } + + daemonize::t_command_server rpc_commands{rpc_ip, rpc_port}; + if (rpc_commands.process_command_vec(command)) + { + return 0; + } + else + { + std::cerr << "Unknown command" << std::endl; + return 1; + } } } diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp index bdad28f6..02bef927 100644 --- a/src/daemon/rpc_command_executor.cpp +++ b/src/daemon/rpc_command_executor.cpp @@ -38,7 +38,6 @@ namespace daemonize { namespace { - /* void print_peer(std::string const & prefix, cryptonote::peer const & peer) { time_t now; @@ -54,7 +53,6 @@ namespace { std::string addr_str = ip_str + ":" + port_str; tools::msg_writer() << boost::format("%-10s %-25s %-25s %s") % prefix % id_str % addr_str % elapsed; } - */ void print_block_header(cryptonote::block_header_responce const & header) { @@ -79,7 +77,6 @@ t_rpc_command_executor::t_rpc_command_executor( {} bool t_rpc_command_executor::print_peer_list() { -/* cryptonote::COMMAND_RPC_GET_PEER_LIST::request req; cryptonote::COMMAND_RPC_GET_PEER_LIST::response res; @@ -97,7 +94,6 @@ bool t_rpc_command_executor::print_peer_list() { print_peer("gray", peer); } -*/ return true; } @@ -114,7 +110,6 @@ bool t_rpc_command_executor::save_blockchain() { } bool t_rpc_command_executor::show_hash_rate() { -/* cryptonote::COMMAND_RPC_SET_LOG_HASH_RATE::request req; cryptonote::COMMAND_RPC_SET_LOG_HASH_RATE::response res; req.visible = true; @@ -124,12 +119,10 @@ bool t_rpc_command_executor::show_hash_rate() { tools::success_msg_writer() << "Hash rate logging is on"; } -*/ return true; } bool t_rpc_command_executor::hide_hash_rate() { -/* cryptonote::COMMAND_RPC_SET_LOG_HASH_RATE::request req; cryptonote::COMMAND_RPC_SET_LOG_HASH_RATE::response res; req.visible = false; @@ -139,7 +132,6 @@ bool t_rpc_command_executor::hide_hash_rate() { tools::success_msg_writer() << "Hash rate logging is off"; } -*/ return true; } @@ -175,7 +167,6 @@ bool t_rpc_command_executor::print_connections() { } bool t_rpc_command_executor::print_blockchain_info(uint64_t start_block_index, uint64_t end_block_index) { -/* cryptonote::COMMAND_RPC_GET_BLOCK_HEADERS_RANGE::request req; cryptonote::COMMAND_RPC_GET_BLOCK_HEADERS_RANGE::response res; @@ -186,23 +177,20 @@ bool t_rpc_command_executor::print_blockchain_info(uint64_t start_block_index, u { for (auto & header : res.headers) { - std::cout << "height " << header.height - << ", timestamp " << header.timestamp - << ", cumul_dif " << header.cumulative_difficulty - << ", cumul_size " << header.cumulative_size << std::endl - << "id " << header.hash << std::endl - << "difficulty " << header.difficulty - << ", nonce " << header.nonce - << ", tx_count " << header.tx_count << std::endl; + std::cout + << "major version: " << header.major_version << std::endl + << "minor version: " << header.minor_version << std::endl + << "height: " << header.height << ", timestamp: " << header.timestamp << ", difficulty: " << header.difficulty << std::endl + << "block id: " << header.hash << std::endl + << "previous block id: " << header.prev_hash << std::endl + << "difficulty: " << header.difficulty << ", nonce " << header.nonce << std::endl; } } -*/ return true; } bool t_rpc_command_executor::set_log_level(int8_t level) { -/* cryptonote::COMMAND_RPC_SET_LOG_LEVEL::request req; cryptonote::COMMAND_RPC_SET_LOG_LEVEL::response res; req.level = level; @@ -212,7 +200,6 @@ bool t_rpc_command_executor::set_log_level(int8_t level) { tools::success_msg_writer() << "Log level is now " << boost::lexical_cast(level); } -*/ return true; } @@ -276,7 +263,6 @@ bool t_rpc_command_executor::print_transaction(crypto::hash transaction_hash) { } bool t_rpc_command_executor::print_transaction_pool_long() { -/* cryptonote::COMMAND_RPC_GET_TRANSACTION_POOL::request req; cryptonote::COMMAND_RPC_GET_TRANSACTION_POOL::response res; @@ -299,12 +285,10 @@ bool t_rpc_command_executor::print_transaction_pool_long() { } } -*/ return true; } bool t_rpc_command_executor::print_transaction_pool_short() { -/* cryptonote::COMMAND_RPC_GET_TRANSACTION_POOL::request req; cryptonote::COMMAND_RPC_GET_TRANSACTION_POOL::response res; @@ -328,7 +312,6 @@ bool t_rpc_command_executor::print_transaction_pool_short() { } } -*/ return true; } @@ -359,7 +342,6 @@ bool t_rpc_command_executor::stop_mining() { bool t_rpc_command_executor::stop_daemon() { -/* cryptonote::COMMAND_RPC_STOP_DAEMON::request req; cryptonote::COMMAND_RPC_STOP_DAEMON::response res; @@ -381,7 +363,6 @@ bool t_rpc_command_executor::stop_daemon() { tools::success_msg_writer() << "Stop signal sent"; } -*/ return true; } diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 1c13719c..32bfb8c6 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -347,6 +347,75 @@ namespace cryptonote return true; } //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_get_peer_list(const COMMAND_RPC_GET_PEER_LIST::request& req, COMMAND_RPC_GET_PEER_LIST::response& res, connection_context& cntx) + { + /* + std::list white_list; + std::list gray_list; + m_p2p.get_peerlist(white_list, gray_list); + + for (auto & entry : white_list) + { + res.white_list.emplace_back(entry.id, entry.adr.ip, entry.adr.port, entry.last_seen); + } + + for (auto & entry : gray_list) + { + res.gray_list.emplace_back(entry.id, entry.adr.ip, entry.adr.port, entry.last_seen); + } + + */ + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_set_log_hash_rate(const COMMAND_RPC_SET_LOG_HASH_RATE::request& req, COMMAND_RPC_SET_LOG_HASH_RATE::response& res, connection_context& cntx) + { + if(m_core.get_miner().is_mining()) + { + m_core.get_miner().do_print_hashrate(req.visible); + res.status = CORE_RPC_STATUS_OK; + } + else + { + res.status = CORE_RPC_STATUS_NOT_MINING; + } + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_set_log_level(const COMMAND_RPC_SET_LOG_LEVEL::request& req, COMMAND_RPC_SET_LOG_LEVEL::response& res, connection_context& cntx) + { + if (req.level < LOG_LEVEL_MIN || req.level > LOG_LEVEL_MAX) + { + res.status = "Error: log level not valid"; + } + else + { + epee::log_space::log_singletone::get_set_log_detalisation_level(true, req.level); + res.status = CORE_RPC_STATUS_OK; + } + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_get_transaction_pool(const COMMAND_RPC_GET_TRANSACTION_POOL::request& req, COMMAND_RPC_GET_TRANSACTION_POOL::response& res, connection_context& cntx) + { + /* + CHECK_CORE_BUSY(); + res.transactions = m_core.transaction_pool_info(); + */ + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_stop_daemon(const COMMAND_RPC_STOP_DAEMON::request& req, COMMAND_RPC_STOP_DAEMON::response& res, connection_context& cntx) + { + // FIXME: replace back to original m_p2p.send_stop_signal() after + // investigating why that isn't working quite right. + m_core.stop(); + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ bool core_rpc_server::on_getblockcount(const COMMAND_RPC_GETBLOCKCOUNT::request& req, COMMAND_RPC_GETBLOCKCOUNT::response& res, connection_context& cntx) { CHECK_CORE_BUSY(); diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h index a8e725b0..aaddba44 100644 --- a/src/rpc/core_rpc_server.h +++ b/src/rpc/core_rpc_server.h @@ -82,6 +82,12 @@ namespace cryptonote MAP_URI_AUTO_JON2("/stop_mining", on_stop_mining, COMMAND_RPC_STOP_MINING) MAP_URI_AUTO_JON2("/mining_status", on_mining_status, COMMAND_RPC_MINING_STATUS) MAP_URI_AUTO_JON2("/save_bc", on_save_bc, COMMAND_RPC_SAVE_BC) + MAP_URI_AUTO_JON2("/get_peer_list", on_get_peer_list, COMMAND_RPC_GET_PEER_LIST) + MAP_URI_AUTO_JON2("/set_log_hash_rate", on_set_log_hash_rate, COMMAND_RPC_SET_LOG_HASH_RATE) + MAP_URI_AUTO_JON2("/set_log_level", on_set_log_level, COMMAND_RPC_SET_LOG_LEVEL) + MAP_URI_AUTO_JON2("/get_transaction_pool", on_get_transaction_pool, COMMAND_RPC_GET_TRANSACTION_POOL) + MAP_URI_AUTO_JON2("/get_transaction_pool", on_get_transaction_pool, COMMAND_RPC_GET_TRANSACTION_POOL) + MAP_URI_AUTO_JON2("/stop_daemon", on_stop_daemon, COMMAND_RPC_STOP_DAEMON) MAP_URI_AUTO_JON2("/getinfo", on_get_info, COMMAND_RPC_GET_INFO) BEGIN_JSON_RPC_MAP("/json_rpc") MAP_JON_RPC("getblockcount", on_getblockcount, COMMAND_RPC_GETBLOCKCOUNT) @@ -107,6 +113,11 @@ namespace cryptonote bool on_get_random_outs(const COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::request& req, COMMAND_RPC_GET_RANDOM_OUTPUTS_FOR_AMOUNTS::response& res, connection_context& cntx); bool on_get_info(const COMMAND_RPC_GET_INFO::request& req, COMMAND_RPC_GET_INFO::response& res, connection_context& cntx); bool on_save_bc(const COMMAND_RPC_SAVE_BC::request& req, COMMAND_RPC_SAVE_BC::response& res, connection_context& cntx); + bool on_get_peer_list(const COMMAND_RPC_GET_PEER_LIST::request& req, COMMAND_RPC_GET_PEER_LIST::response& res, connection_context& cntx); + bool on_set_log_hash_rate(const COMMAND_RPC_SET_LOG_HASH_RATE::request& req, COMMAND_RPC_SET_LOG_HASH_RATE::response& res, connection_context& cntx); + bool on_set_log_level(const COMMAND_RPC_SET_LOG_LEVEL::request& req, COMMAND_RPC_SET_LOG_LEVEL::response& res, connection_context& cntx); + bool on_get_transaction_pool(const COMMAND_RPC_GET_TRANSACTION_POOL::request& req, COMMAND_RPC_GET_TRANSACTION_POOL::response& res, connection_context& cntx); + bool on_stop_daemon(const COMMAND_RPC_STOP_DAEMON::request& req, COMMAND_RPC_STOP_DAEMON::response& res, connection_context& cntx); //json_rpc bool on_getblockcount(const COMMAND_RPC_GETBLOCKCOUNT::request& req, COMMAND_RPC_GETBLOCKCOUNT::response& res, connection_context& cntx); diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h index 9fea933c..5cb54752 100644 --- a/src/rpc/core_rpc_server_commands_defs.h +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -39,6 +39,7 @@ namespace cryptonote //----------------------------------------------- #define CORE_RPC_STATUS_OK "OK" #define CORE_RPC_STATUS_BUSY "BUSY" +#define CORE_RPC_STATUS_NOT_MINING "NOT MINING" struct COMMAND_RPC_GET_HEIGHT { @@ -440,7 +441,7 @@ namespace cryptonote KV_SERIALIZE(reward) END_KV_SERIALIZE_MAP() }; - + struct COMMAND_RPC_GET_LAST_BLOCK_HEADER { struct request @@ -510,6 +511,135 @@ namespace cryptonote }; + struct peer { + uint64_t id; + uint32_t ip; + uint16_t port; + uint64_t last_seen; + + peer() = default; + + peer(uint64_t id, uint32_t ip, uint16_t port, uint64_t last_seen) + : id(id), ip(ip), port(port), last_seen(last_seen) + {} + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(id) + KV_SERIALIZE(ip) + KV_SERIALIZE(port) + KV_SERIALIZE(last_seen) + END_KV_SERIALIZE_MAP() + }; + + struct COMMAND_RPC_GET_PEER_LIST + { + struct request + { + BEGIN_KV_SERIALIZE_MAP() + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string status; + std::vector white_list; + std::vector gray_list; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(status) + KV_SERIALIZE(white_list) + KV_SERIALIZE(gray_list) + END_KV_SERIALIZE_MAP() + }; + }; + + struct COMMAND_RPC_SET_LOG_HASH_RATE + { + struct request + { + bool visible; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(visible) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string status; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(status) + END_KV_SERIALIZE_MAP() + }; + }; + + struct COMMAND_RPC_SET_LOG_LEVEL + { + struct request + { + int8_t level; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(level) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string status; + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(status) + END_KV_SERIALIZE_MAP() + }; + }; + + struct tx_info + { + std::string id_hash; + std::string tx_json; // TODO - expose this data directly + uint64_t blob_size; + uint64_t fee; + std::string max_used_block_id_hash; + uint64_t max_used_block_height; + bool kept_by_block; + uint64_t last_failed_height; + std::string last_failed_id_hash; + uint64_t receive_time; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(id_hash) + KV_SERIALIZE(tx_json) + KV_SERIALIZE(blob_size) + KV_SERIALIZE(fee) + KV_SERIALIZE(max_used_block_id_hash) + KV_SERIALIZE(max_used_block_height) + KV_SERIALIZE(kept_by_block) + KV_SERIALIZE(last_failed_height) + KV_SERIALIZE(last_failed_id_hash) + KV_SERIALIZE(receive_time) + END_KV_SERIALIZE_MAP() + }; + + struct COMMAND_RPC_GET_TRANSACTION_POOL + { + struct request + { + BEGIN_KV_SERIALIZE_MAP() + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string status; + std::vector transactions; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(status) + KV_SERIALIZE(transactions) + END_KV_SERIALIZE_MAP() + }; + }; + struct COMMAND_RPC_GET_CONNECTIONS { struct request @@ -530,5 +660,48 @@ namespace cryptonote }; }; + + struct COMMAND_RPC_GET_BLOCK_HEADERS_RANGE + { + struct request + { + uint64_t start_height; + uint64_t end_height; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(start_height) + KV_SERIALIZE(end_height) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string status; + std::vector headers; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(status) + KV_SERIALIZE(headers) + END_KV_SERIALIZE_MAP() + }; + }; + + struct COMMAND_RPC_STOP_DAEMON + { + struct request + { + BEGIN_KV_SERIALIZE_MAP() + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string status; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(status) + END_KV_SERIALIZE_MAP() + }; + }; }