From 014f3a0d39e5314c13ae7420283b1ea5eb593517 Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Sun, 10 Jul 2016 16:49:40 +0100 Subject: [PATCH] Add a daemon RPC version, and make simplewallet check it If the version is different, simplewallet will refuse to use that daemon, unless --allow-mismatched-daemon-version is used. --- src/rpc/core_rpc_server.cpp | 7 +++++ src/rpc/core_rpc_server.h | 2 ++ src/rpc/core_rpc_server_commands_defs.h | 22 +++++++++++++++ src/simplewallet/simplewallet.cpp | 33 ++++++++++++++++------ src/simplewallet/simplewallet.h | 3 +- src/wallet/wallet2.cpp | 37 ++++++++++++++++++------- src/wallet/wallet2.h | 2 +- 7 files changed, 86 insertions(+), 20 deletions(-) diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index ca18e7e0..35200c5f 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -1146,6 +1146,13 @@ namespace cryptonote return true; } //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_get_version(const COMMAND_RPC_GET_VERSION::request& req, COMMAND_RPC_GET_VERSION::response& res, epee::json_rpc::error& error_resp) + { + res.version = CORE_RPC_VERSION; + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ bool core_rpc_server::on_fast_exit(const COMMAND_RPC_FAST_EXIT::request& req, COMMAND_RPC_FAST_EXIT::response& res) { cryptonote::core::set_fast_exit(); diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h index a7a54b59..54723c7e 100644 --- a/src/rpc/core_rpc_server.h +++ b/src/rpc/core_rpc_server.h @@ -111,6 +111,7 @@ namespace cryptonote MAP_JON_RPC_WE_IF("getbans", on_get_bans, COMMAND_RPC_GETBANS, !m_restricted) MAP_JON_RPC_WE_IF("flush_txpool", on_flush_txpool, COMMAND_RPC_FLUSH_TRANSACTION_POOL, !m_restricted) MAP_JON_RPC_WE("get_output_histogram", on_get_output_histogram, COMMAND_RPC_GET_OUTPUT_HISTOGRAM) + MAP_JON_RPC_WE("get_version", on_get_version, COMMAND_RPC_GET_VERSION) END_JSON_RPC_MAP() END_URI_MAP2() @@ -153,6 +154,7 @@ namespace cryptonote bool on_get_bans(const COMMAND_RPC_GETBANS::request& req, COMMAND_RPC_GETBANS::response& res, epee::json_rpc::error& error_resp); bool on_flush_txpool(const COMMAND_RPC_FLUSH_TRANSACTION_POOL::request& req, COMMAND_RPC_FLUSH_TRANSACTION_POOL::response& res, epee::json_rpc::error& error_resp); bool on_get_output_histogram(const COMMAND_RPC_GET_OUTPUT_HISTOGRAM::request& req, COMMAND_RPC_GET_OUTPUT_HISTOGRAM::response& res, epee::json_rpc::error& error_resp); + bool on_get_version(const COMMAND_RPC_GET_VERSION::request& req, COMMAND_RPC_GET_VERSION::response& res, epee::json_rpc::error& error_resp); //----------------------- private: diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h index 392c7501..63167e24 100644 --- a/src/rpc/core_rpc_server_commands_defs.h +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -41,6 +41,8 @@ namespace cryptonote #define CORE_RPC_STATUS_BUSY "BUSY" #define CORE_RPC_STATUS_NOT_MINING "NOT MINING" +#define CORE_RPC_VERSION 1 + struct COMMAND_RPC_GET_HEIGHT { struct request @@ -1102,5 +1104,25 @@ namespace cryptonote END_KV_SERIALIZE_MAP() }; }; + + struct COMMAND_RPC_GET_VERSION + { + struct request + { + BEGIN_KV_SERIALIZE_MAP() + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string status; + uint32_t version; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(status) + KV_SERIALIZE(version) + END_KV_SERIALIZE_MAP() + }; + }; } diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 4a7a70b8..acd12729 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -115,6 +115,7 @@ namespace const command_line::arg_descriptor arg_testnet = {"testnet", sw::tr("For testnet. Daemon must also be launched with --testnet flag"), false}; const command_line::arg_descriptor arg_restricted = {"restricted-rpc", sw::tr("Restricts RPC to view-only commands"), false}; const command_line::arg_descriptor arg_trusted_daemon = {"trusted-daemon", sw::tr("Enable commands which rely on a trusted daemon"), false}; + const command_line::arg_descriptor arg_allow_mismatched_daemon_version = {"allow-mismatched-daemon-version", sw::tr("Allow communicating with a daemon that uses a different RPC version"), false}; const command_line::arg_descriptor arg_restore_height = {"restore-height", sw::tr("Restore from specific blockchain height"), 0}; const command_line::arg_descriptor< std::vector > arg_command = {"command", ""}; @@ -623,7 +624,8 @@ bool simple_wallet::help(const std::vector &args/* = std::vectorcheck_connection()) + bool same_version = false; + if (!m_wallet->check_connection(&same_version)) { - fail_msg_writer() << tr("wallet failed to connect to daemon: ") << m_daemon_address << ". " << - tr("Daemon either is not started or wrong port was passed. " - "Please make sure daemon is running or restart the wallet with the correct daemon address."); + if (!silent) + fail_msg_writer() << tr("wallet failed to connect to daemon: ") << m_daemon_address << ". " << + tr("Daemon either is not started or wrong port was passed. " + "Please make sure daemon is running or restart the wallet with the correct daemon address."); + return false; + } + if (!m_allow_mismatched_daemon_version && !same_version) + { + if (!silent) + fail_msg_writer() << tr("Daemon uses a different RPC version that the wallet: ") << m_daemon_address << ". " << + tr("Either update one of them, or use --allow-mismatched-daemon-version."); return false; } return true; @@ -3207,7 +3219,8 @@ void simple_wallet::wallet_refresh_thread() try { uint64_t fetched_blocks; - m_wallet->refresh(0, fetched_blocks); + if (try_connect_to_daemon(true)) + m_wallet->refresh(0, fetched_blocks); } catch(...) {} m_auto_refresh_refreshing = false; @@ -3219,6 +3232,9 @@ void simple_wallet::wallet_refresh_thread() //---------------------------------------------------------------------------------------------------- bool simple_wallet::run() { + // check and display warning, but go on anyway + try_connect_to_daemon(); + std::string addr_start = m_wallet->get_account().get_public_address_str(m_wallet->testnet()).substr(0, 6); m_auto_refresh_run = m_wallet->auto_refresh(); if (m_auto_refresh_run) @@ -3348,7 +3364,7 @@ bool simple_wallet::get_tx_note(const std::vector &args) bool simple_wallet::status(const std::vector &args) { uint64_t local_height = m_wallet->get_blockchain_current_height(); - if (!m_wallet->check_connection()) + if (!try_connect_to_daemon()) { success_msg_writer() << "Refreshed " << local_height << "/?, no daemon connected"; return true; @@ -3444,6 +3460,7 @@ int main(int argc, char* argv[]) command_line::add_arg(desc_params, arg_testnet); command_line::add_arg(desc_params, arg_restricted); command_line::add_arg(desc_params, arg_trusted_daemon); + command_line::add_arg(desc_params, arg_allow_mismatched_daemon_version); command_line::add_arg(desc_params, arg_restore_height); tools::wallet_rpc_server::init_options(desc_params); diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index e0478eb6..aba93544 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -145,7 +145,7 @@ namespace cryptonote bool set_default_fee_multiplier(const std::vector &args); uint64_t get_daemon_blockchain_height(std::string& err); - bool try_connect_to_daemon(); + bool try_connect_to_daemon(bool silent = false); bool ask_wallet_create_if_needed(); bool get_address_from_str(const std::string &str, cryptonote::account_public_address &address, bool &has_payment_id, crypto::hash8 &payment_id); @@ -238,6 +238,7 @@ namespace cryptonote bool m_restore_deterministic_wallet; // recover flag bool m_non_deterministic; // old 2-random generation bool m_trusted_daemon; + bool m_allow_mismatched_daemon_version; uint64_t m_restore_height; // optional std::string m_daemon_address; diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index a153967c..d784d81e 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -1435,22 +1435,39 @@ bool wallet2::prepare_file_names(const std::string& file_path) return true; } //---------------------------------------------------------------------------------------------------- -bool wallet2::check_connection() +bool wallet2::check_connection(bool *same_version) { boost::lock_guard lock(m_daemon_rpc_mutex); - if(m_http_client.is_connected()) - return true; - - net_utils::http::url_content u; - net_utils::parse_url(m_daemon_address, u); - - if(!u.port) + if(!m_http_client.is_connected()) { - u.port = m_testnet ? config::testnet::RPC_DEFAULT_PORT : config::RPC_DEFAULT_PORT; + net_utils::http::url_content u; + net_utils::parse_url(m_daemon_address, u); + + if(!u.port) + { + u.port = m_testnet ? config::testnet::RPC_DEFAULT_PORT : config::RPC_DEFAULT_PORT; + } + + if (!m_http_client.connect(u.host, std::to_string(u.port), WALLET_RCP_CONNECTION_TIMEOUT)) + return false; } - return m_http_client.connect(u.host, std::to_string(u.port), WALLET_RCP_CONNECTION_TIMEOUT); + if (same_version) + { + epee::json_rpc::request req_t = AUTO_VAL_INIT(req_t); + epee::json_rpc::response resp_t = AUTO_VAL_INIT(resp_t); + req_t.jsonrpc = "2.0"; + req_t.id = epee::serialization::storage_entry(0); + req_t.method = "get_version"; + bool r = net_utils::invoke_http_json_remote_command2(m_daemon_address + "/json_rpc", req_t, resp_t, m_http_client); + if (!r || resp_t.result.status != CORE_RPC_STATUS_OK) + *same_version = false; + else + *same_version = resp_t.result.version == CORE_RPC_VERSION; + } + + return true; } //---------------------------------------------------------------------------------------------------- bool wallet2::generate_chacha8_key_from_secret_keys(crypto::chacha8_key &key) const diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index c5149a10..d61a3485 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -296,7 +296,7 @@ namespace tools std::vector create_transactions_2(std::vector dsts, const size_t fake_outs_count, const uint64_t unlock_time, uint64_t fee_multiplier, const std::vector extra, bool trusted_daemon); std::vector create_transactions_all(const cryptonote::account_public_address &address, const size_t fake_outs_count, const uint64_t unlock_time, uint64_t fee_multiplier, const std::vector extra, bool trusted_daemon); std::vector create_unmixable_sweep_transactions(bool trusted_daemon); - bool check_connection(); + bool check_connection(bool *same_version = NULL); void get_transfers(wallet2::transfer_container& incoming_transfers) const; void get_payments(const crypto::hash& payment_id, std::list& payments, uint64_t min_height = 0) const; void get_payments(std::list>& payments, uint64_t min_height, uint64_t max_height = (uint64_t)-1) const;