diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index ca18e7e09..35200c5f9 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 2d936df51..3d50c77be 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("get_bans", 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 392c7501f..63167e249 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 1862173b9..2bcd8ae4c 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; @@ -3209,7 +3221,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; @@ -3221,6 +3234,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) @@ -3350,7 +3366,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; @@ -3511,6 +3527,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 97f30834a..7d8e7730c 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -147,7 +147,7 @@ namespace cryptonote bool verify(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); @@ -240,6 +240,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 6d676c6bd..d18681f36 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -1436,22 +1436,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 ca5cec43c..d004b7da9 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;