diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index 01d052ce..ed3ab447 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -364,6 +364,7 @@ simple_wallet::simple_wallet() m_cmd_binder.set_handler("spendkey", boost::bind(&simple_wallet::spendkey, this, _1), tr("Get spendkey")); m_cmd_binder.set_handler("seed", boost::bind(&simple_wallet::seed, this, _1), tr("Get deterministic seed")); m_cmd_binder.set_handler("set", boost::bind(&simple_wallet::set_variable, this, _1), tr("available options: seed language - Set wallet seed langage; always-confirm-transfers <1|0> - whether to confirm unsplit txes")); + m_cmd_binder.set_handler("rescan_spent", boost::bind(&simple_wallet::rescan_spent, this, _1), tr("Rescan blockchain for spent outputs")); m_cmd_binder.set_handler("help", boost::bind(&simple_wallet::help, this, _1), tr("Show this help")); } //---------------------------------------------------------------------------------------------------- @@ -1253,7 +1254,46 @@ bool simple_wallet::show_blockchain_height(const std::vector& args) fail_msg_writer() << tr("failed to get blockchain height: ") << err; return true; } +//---------------------------------------------------------------------------------------------------- +bool simple_wallet::rescan_spent(const std::vector &args) +{ + if (!try_connect_to_daemon()) + return true; + try + { + m_wallet->rescan_spent(); + } + catch (const tools::error::daemon_busy&) + { + fail_msg_writer() << tr("daemon is busy. Please try later"); + } + catch (const tools::error::no_connection_to_daemon&) + { + fail_msg_writer() << tr("no connection to daemon. Please, make sure daemon is running."); + } + catch (const tools::error::is_key_image_spent_error&) + { + fail_msg_writer() << tr("failed to get spent status"); + } + catch (const tools::error::wallet_rpc_error& e) + { + LOG_ERROR("Unknown RPC error: " << e.to_string()); + fail_msg_writer() << tr("RPC error: ") << e.what(); + } + catch (const std::exception& e) + { + LOG_ERROR("unexpected error: " << e.what()); + fail_msg_writer() << tr("unexpected error: ") << e.what(); + } + catch (...) + { + LOG_ERROR("Unknown error"); + fail_msg_writer() << tr("unknown error"); + } + + return true; +} //---------------------------------------------------------------------------------------------------- bool simple_wallet::transfer_main(bool new_algorithm, const std::vector &args_) { diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index 883d0c43..8aca9321 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -120,6 +120,7 @@ namespace cryptonote bool save(const std::vector &args); bool save_watch_only(const std::vector &args); bool set_variable(const std::vector &args); + bool rescan_spent(const std::vector &args); bool set_log(const std::vector &args); uint64_t get_daemon_blockchain_height(std::string& err); diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 3d3f1e4d..11ea4678 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -961,6 +961,47 @@ void wallet2::get_payments(std::list key_images; + + // make a list of key images for all our outputs + for (size_t i = 0; i < m_transfers.size(); ++i) + { + const transfer_details& td = m_transfers[i]; + key_images.push_back(string_tools::pod_to_hex(td.m_key_image)); + } + + COMMAND_RPC_IS_KEY_IMAGE_SPENT::request req = AUTO_VAL_INIT(req); + COMMAND_RPC_IS_KEY_IMAGE_SPENT::response daemon_resp = AUTO_VAL_INIT(daemon_resp); + req.key_images = key_images; + bool r = epee::net_utils::invoke_http_json_remote_command2(m_daemon_address + "/is_key_image_spent", req, daemon_resp, m_http_client, 200000); + THROW_WALLET_EXCEPTION_IF(!r, error::no_connection_to_daemon, "is_key_image_spent"); + THROW_WALLET_EXCEPTION_IF(daemon_resp.status == CORE_RPC_STATUS_BUSY, error::daemon_busy, "is_key_image_spent"); + THROW_WALLET_EXCEPTION_IF(daemon_resp.status != CORE_RPC_STATUS_OK, error::is_key_image_spent_error, daemon_resp.status); + THROW_WALLET_EXCEPTION_IF(daemon_resp.spent_status.size() != key_images.size(), error::wallet_internal_error, + "daemon returned wrong response for is_key_image_spent, wrong amounts count = " + + std::to_string(daemon_resp.spent_status.size()) + ", expected " + std::to_string(key_images.size())); + + // update spent status + for (size_t i = 0; i < m_transfers.size(); ++i) + { + transfer_details& td = m_transfers[i]; + if (td.m_spent != daemon_resp.spent_status[i]) + { + if (td.m_spent) + { + LOG_PRINT_L1("Marking output " << i << " as unspent, it was marked as spent"); + } + else + { + LOG_PRINT_L1("Marking output " << i << " as spent, it was marked as unspent"); + } + td.m_spent = daemon_resp.spent_status[i]; + } + } +} +//---------------------------------------------------------------------------------------------------- bool wallet2::is_transfer_unlocked(const transfer_details& td) const { if(!is_tx_spendtime_unlocked(td.m_tx.unlock_time)) diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index eee6aa58..ffe9ad0e 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -235,6 +235,7 @@ namespace tools 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) const; uint64_t get_blockchain_current_height() const { return m_local_bc_height; } + void rescan_spent(); template inline void serialize(t_archive &a, const unsigned int ver) { diff --git a/src/wallet/wallet_errors.h b/src/wallet/wallet_errors.h index bf520c36..94518e69 100644 --- a/src/wallet/wallet_errors.h +++ b/src/wallet/wallet_errors.h @@ -73,6 +73,7 @@ namespace tools // wallet_rpc_error * // daemon_busy // no_connection_to_daemon + // is_key_image_spent_error // wallet_files_doesnt_correspond // // * - class with protected ctor @@ -574,6 +575,14 @@ namespace tools } }; //---------------------------------------------------------------------------------------------------- + struct is_key_image_spent_error : public wallet_rpc_error + { + explicit is_key_image_spent_error(std::string&& loc, const std::string& request) + : wallet_rpc_error(std::move(loc), "error from is_key_image_spent call", request) + { + } + }; + //---------------------------------------------------------------------------------------------------- struct wallet_files_doesnt_correspond : public wallet_logic_error { explicit wallet_files_doesnt_correspond(std::string&& loc, const std::string& keys_file, const std::string& wallet_file)