diff options
Diffstat (limited to 'src/simplewallet')
-rw-r--r-- | src/simplewallet/CMakeLists.txt | 1 | ||||
-rw-r--r-- | src/simplewallet/simplewallet.cpp | 197 | ||||
-rw-r--r-- | src/simplewallet/simplewallet.h | 1 |
3 files changed, 151 insertions, 48 deletions
diff --git a/src/simplewallet/CMakeLists.txt b/src/simplewallet/CMakeLists.txt index b56085b8f..4ecda12d0 100644 --- a/src/simplewallet/CMakeLists.txt +++ b/src/simplewallet/CMakeLists.txt @@ -48,7 +48,6 @@ target_link_libraries(simplewallet cncrypto common mnemonics - p2p version ${Boost_CHRONO_LIBRARY} ${Boost_PROGRAM_OPTIONS_LIBRARY} diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp index c936f481e..3d8d395db 100644 --- a/src/simplewallet/simplewallet.cpp +++ b/src/simplewallet/simplewallet.cpp @@ -49,7 +49,6 @@ #include "common/dns_utils.h" #include "common/base58.h" #include "common/scoped_message_writer.h" -#include "p2p/net_node.h" #include "cryptonote_protocol/cryptonote_protocol_handler.h" #include "simplewallet.h" #include "cryptonote_basic/cryptonote_format_utils.h" @@ -111,6 +110,7 @@ namespace const auto arg_wallet_file = wallet_args::arg_wallet_file(); const command_line::arg_descriptor<std::string> arg_generate_new_wallet = {"generate-new-wallet", sw::tr("Generate new wallet and save it to <arg>"), ""}; const command_line::arg_descriptor<std::string> arg_generate_from_view_key = {"generate-from-view-key", sw::tr("Generate incoming-only wallet from view key"), ""}; + const command_line::arg_descriptor<std::string> arg_generate_from_spend_key = {"generate-from-spend-key", sw::tr("Generate deterministic wallet from spend key"), ""}; const command_line::arg_descriptor<std::string> arg_generate_from_keys = {"generate-from-keys", sw::tr("Generate wallet from private keys"), ""}; const command_line::arg_descriptor<std::string> arg_generate_from_multisig_keys = {"generate-from-multisig-keys", sw::tr("Generate a master wallet from multisig wallet keys"), ""}; const auto arg_generate_from_json = wallet_args::arg_generate_from_json(); @@ -161,20 +161,50 @@ namespace return tools::scoped_message_writer(console_color_red, true, sw::tr("Error: "), el::Level::Error); } - bool is_it_true(const std::string& s) + bool parse_bool(const std::string& s, bool& result) { if (s == "1" || command_line::is_yes(s)) + { + result = true; + return true; + } + if (s == "0" || command_line::is_no(s)) + { + result = false; return true; + } boost::algorithm::is_iequal ignore_case{}; - if (boost::algorithm::equals("true", s, ignore_case)) + if (boost::algorithm::equals("true", s, ignore_case) || boost::algorithm::equals(simple_wallet::tr("true"), s, ignore_case)) + { + result = true; return true; - if (boost::algorithm::equals(simple_wallet::tr("true"), s, ignore_case)) + } + if (boost::algorithm::equals("false", s, ignore_case) || boost::algorithm::equals(simple_wallet::tr("false"), s, ignore_case)) + { + result = false; return true; + } return false; } + template <typename F> + bool parse_bool_and_use(const std::string& s, F func) + { + bool r; + if (parse_bool(s, r)) + { + func(r); + return true; + } + else + { + fail_msg_writer() << tr("invalid argument: must be either 0/1, true/false, y/n, yes/no"); + return false; + } + } + const struct { const char *name; @@ -507,8 +537,10 @@ bool simple_wallet::set_always_confirm_transfers(const std::vector<std::string> const auto pwd_container = get_and_verify_password(); if (pwd_container) { - m_wallet->always_confirm_transfers(is_it_true(args[1])); - m_wallet->rewrite(m_wallet_file, pwd_container->password()); + parse_bool_and_use(args[1], [&](bool r) { + m_wallet->always_confirm_transfers(r); + m_wallet->rewrite(m_wallet_file, pwd_container->password()); + }); } return true; } @@ -518,8 +550,10 @@ bool simple_wallet::set_print_ring_members(const std::vector<std::string> &args/ const auto pwd_container = get_and_verify_password(); if (pwd_container) { - m_wallet->print_ring_members(is_it_true(args[1])); - m_wallet->rewrite(m_wallet_file, pwd_container->password()); + parse_bool_and_use(args[1], [&](bool r) { + m_wallet->print_ring_members(r); + m_wallet->rewrite(m_wallet_file, pwd_container->password()); + }); } return true; } @@ -535,8 +569,10 @@ bool simple_wallet::set_store_tx_info(const std::vector<std::string> &args/* = s const auto pwd_container = get_and_verify_password(); if (pwd_container) { - m_wallet->store_tx_info(is_it_true(args[1])); - m_wallet->rewrite(m_wallet_file, pwd_container->password()); + parse_bool_and_use(args[1], [&](bool r) { + m_wallet->store_tx_info(r); + m_wallet->rewrite(m_wallet_file, pwd_container->password()); + }); } return true; } @@ -631,14 +667,15 @@ bool simple_wallet::set_auto_refresh(const std::vector<std::string> &args/* = st const auto pwd_container = get_and_verify_password(); if (pwd_container) { - const bool auto_refresh = is_it_true(args[1]); - m_wallet->auto_refresh(auto_refresh); - m_idle_mutex.lock(); - m_auto_refresh_enabled.store(auto_refresh, std::memory_order_relaxed); - m_idle_cond.notify_one(); - m_idle_mutex.unlock(); + parse_bool_and_use(args[1], [&](bool auto_refresh) { + m_wallet->auto_refresh(auto_refresh); + m_idle_mutex.lock(); + m_auto_refresh_enabled.store(auto_refresh, std::memory_order_relaxed); + m_idle_cond.notify_one(); + m_idle_mutex.unlock(); - m_wallet->rewrite(m_wallet_file, pwd_container->password()); + m_wallet->rewrite(m_wallet_file, pwd_container->password()); + }); } return true; } @@ -665,8 +702,10 @@ bool simple_wallet::set_confirm_missing_payment_id(const std::vector<std::string const auto pwd_container = get_and_verify_password(); if (pwd_container) { - m_wallet->confirm_missing_payment_id(is_it_true(args[1])); - m_wallet->rewrite(m_wallet_file, pwd_container->password()); + parse_bool_and_use(args[1], [&](bool r) { + m_wallet->confirm_missing_payment_id(r); + m_wallet->rewrite(m_wallet_file, pwd_container->password()); + }); } return true; } @@ -676,8 +715,10 @@ bool simple_wallet::set_ask_password(const std::vector<std::string> &args/* = st const auto pwd_container = get_and_verify_password(); if (pwd_container) { - m_wallet->ask_password(is_it_true(args[1])); - m_wallet->rewrite(m_wallet_file, pwd_container->password()); + parse_bool_and_use(args[1], [&](bool r) { + m_wallet->ask_password(r); + m_wallet->rewrite(m_wallet_file, pwd_container->password()); + }); } return true; } @@ -753,8 +794,10 @@ bool simple_wallet::set_merge_destinations(const std::vector<std::string> &args/ const auto pwd_container = get_and_verify_password(); if (pwd_container) { - m_wallet->merge_destinations(is_it_true(args[1])); - m_wallet->rewrite(m_wallet_file, pwd_container->password()); + parse_bool_and_use(args[1], [&](bool r) { + m_wallet->merge_destinations(r); + m_wallet->rewrite(m_wallet_file, pwd_container->password()); + }); } return true; } @@ -764,8 +807,10 @@ bool simple_wallet::set_confirm_backlog(const std::vector<std::string> &args/* = const auto pwd_container = get_and_verify_password(); if (pwd_container) { - m_wallet->confirm_backlog(is_it_true(args[1])); - m_wallet->rewrite(m_wallet_file, pwd_container->password()); + parse_bool_and_use(args[1], [&](bool r) { + m_wallet->confirm_backlog(r); + m_wallet->rewrite(m_wallet_file, pwd_container->password()); + }); } return true; } @@ -1077,12 +1122,12 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) if (!handle_command_line(vm)) return false; - if((!m_generate_new.empty()) + (!m_wallet_file.empty()) + (!m_generate_from_view_key.empty()) + (!m_generate_from_keys.empty()) + (!m_generate_from_multisig_keys.empty()) + (!m_generate_from_json.empty()) > 1) + if((!m_generate_new.empty()) + (!m_wallet_file.empty()) + (!m_generate_from_view_key.empty()) + (!m_generate_from_spend_key.empty()) + (!m_generate_from_keys.empty()) + (!m_generate_from_multisig_keys.empty()) + (!m_generate_from_json.empty()) > 1) { - fail_msg_writer() << tr("can't specify more than one of --generate-new-wallet=\"wallet_name\", --wallet-file=\"wallet_name\", --generate-from-view-key=\"wallet_name\", --generate-from-keys=\"wallet_name\", --generate-from-multisig-keys=\"wallet_name\" and --generate-from-json=\"jsonfilename\""); + fail_msg_writer() << tr("can't specify more than one of --generate-new-wallet=\"wallet_name\", --wallet-file=\"wallet_name\", --generate-from-view-key=\"wallet_name\", --generate-from-spend-key=\"wallet_name\", --generate-from-keys=\"wallet_name\", --generate-from-multisig-keys=\"wallet_name\" and --generate-from-json=\"jsonfilename\""); return false; } - else if (m_generate_new.empty() && m_wallet_file.empty() && m_generate_from_view_key.empty() && m_generate_from_keys.empty() && m_generate_from_multisig_keys.empty() && m_generate_from_json.empty()) + else if (m_generate_new.empty() && m_wallet_file.empty() && m_generate_from_view_key.empty() && m_generate_from_spend_key.empty() && m_generate_from_keys.empty() && m_generate_from_multisig_keys.empty() && m_generate_from_json.empty()) { if(!ask_wallet_create_if_needed()) return false; } @@ -1190,6 +1235,25 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm) bool r = new_wallet(vm, info.address, boost::none, viewkey); CHECK_AND_ASSERT_MES(r, false, tr("account creation failed")); } + else if (!m_generate_from_spend_key.empty()) + { + m_wallet_file = m_generate_from_spend_key; + // parse spend secret key + std::string spendkey_string = command_line::input_line("Secret spend key: "); + if (std::cin.eof()) + return false; + if (spendkey_string.empty()) { + fail_msg_writer() << tr("No data supplied, cancelled"); + return false; + } + if (!epee::string_tools::hex_to_pod(spendkey_string, m_recovery_key)) + { + fail_msg_writer() << tr("failed to parse spend key secret key"); + return false; + } + bool r = new_wallet(vm, m_recovery_key, true, false, ""); + CHECK_AND_ASSERT_MES(r, false, tr("account creation failed")); + } else if (!m_generate_from_keys.empty()) { m_wallet_file = m_generate_from_keys; @@ -1531,6 +1595,7 @@ bool simple_wallet::handle_command_line(const boost::program_options::variables_ m_wallet_file = command_line::get_arg(vm, arg_wallet_file); m_generate_new = command_line::get_arg(vm, arg_generate_new_wallet); m_generate_from_view_key = command_line::get_arg(vm, arg_generate_from_view_key); + m_generate_from_spend_key = command_line::get_arg(vm, arg_generate_from_spend_key); m_generate_from_keys = command_line::get_arg(vm, arg_generate_from_keys); m_generate_from_multisig_keys = command_line::get_arg(vm, arg_generate_from_multisig_keys); m_generate_from_json = command_line::get_arg(vm, arg_generate_from_json); @@ -1543,6 +1608,7 @@ bool simple_wallet::handle_command_line(const boost::program_options::variables_ m_restore_height = command_line::get_arg(vm, arg_restore_height); m_do_not_relay = command_line::get_arg(vm, arg_do_not_relay); m_restoring = !m_generate_from_view_key.empty() || + !m_generate_from_spend_key.empty() || !m_generate_from_keys.empty() || !m_generate_from_multisig_keys.empty() || !m_generate_from_json.empty() || @@ -1904,8 +1970,16 @@ bool simple_wallet::start_mining(const std::vector<std::string>& args) bool ok = true; size_t max_mining_threads_count = (std::max)(tools::get_max_concurrency(), static_cast<unsigned>(2)); size_t arg_size = args.size(); - if(arg_size >= 3) req.ignore_battery = is_it_true(args[2]); - if(arg_size >= 2) req.do_background_mining = is_it_true(args[1]); + if(arg_size >= 3) + { + if (!parse_bool_and_use(args[2], [&](bool r) { req.ignore_battery = r; })) + return true; + } + if(arg_size >= 2) + { + if (!parse_bool_and_use(args[1], [&](bool r) { req.do_background_mining = r; })) + return true; + } if(arg_size >= 1) { uint16_t num = 1; @@ -1988,7 +2062,7 @@ void simple_wallet::on_money_received(uint64_t height, const crypto::hash &txid, message_writer(console_color_green, false) << "\r" << tr("Height ") << height << ", " << tr("txid ") << txid << ", " << - print_money(amount) << tr(" XMR, ") << + print_money(amount) << tr("idx ") << subaddr_index; if (m_auto_refresh_refreshing) m_cmd_binder.print_prompt(); @@ -2510,12 +2584,23 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri if (fake_outs_count == 0) fake_outs_count = DEFAULT_MIX; } + else if (ring_size == 0) + { + fail_msg_writer() << tr("Ring size must not be 0"); + return true; + } else { fake_outs_count = ring_size - 1; local_args.erase(local_args.begin()); } } + uint64_t adjusted_fake_outs_count = m_wallet->adjust_mixin(fake_outs_count); + if (adjusted_fake_outs_count > fake_outs_count) + { + fail_msg_writer() << (boost::format(tr("ring size %u is too small, minimum is %u")) % (fake_outs_count+1) % (adjusted_fake_outs_count+1)).str(); + return true; + } const size_t min_args = (transfer_type == TransferLocked) ? 3 : 2; if(local_args.size() < min_args) @@ -3088,6 +3173,12 @@ bool simple_wallet::sweep_unmixable(const std::vector<std::string> &args_) bool simple_wallet::sweep_main(uint64_t below, const std::vector<std::string> &args_) { // sweep_all [index=<N1>[,<N2>,...]] [<ring_size>] <address> [<payment_id>] + if (args_.size() == 0) + { + fail_msg_writer() << tr("No address given"); + return true; + } + if (m_wallet->ask_password() && !get_and_verify_password()) { return true; } if (!try_connect_to_daemon()) return true; @@ -3115,12 +3206,23 @@ bool simple_wallet::sweep_main(uint64_t below, const std::vector<std::string> &a if (fake_outs_count == 0) fake_outs_count = DEFAULT_MIX; } + else if (ring_size == 0) + { + fail_msg_writer() << tr("Ring size must not be 0"); + return true; + } else { fake_outs_count = ring_size - 1; local_args.erase(local_args.begin()); } } + uint64_t adjusted_fake_outs_count = m_wallet->adjust_mixin(fake_outs_count); + if (adjusted_fake_outs_count > fake_outs_count) + { + fail_msg_writer() << (boost::format(tr("ring size %u is too small, minimum is %u")) % (fake_outs_count+1) % (adjusted_fake_outs_count+1)).str(); + return true; + } std::vector<uint8_t> extra; bool payment_id_seen = false; @@ -3159,12 +3261,6 @@ bool simple_wallet::sweep_main(uint64_t below, const std::vector<std::string> &a local_args.pop_back(); } - if (local_args.size() == 0) - { - fail_msg_writer() << tr("No address given"); - return true; - } - cryptonote::address_parse_info info; if (!cryptonote::get_account_address_from_str_or_url(info, m_wallet->testnet(), local_args[0], oa_prompter)) { @@ -3426,7 +3522,7 @@ bool simple_wallet::donate(const std::vector<std::string> &args_) local_args.push_back(amount_str); if (!payment_id_str.empty()) local_args.push_back(payment_id_str); - message_writer() << tr("Donating ") << amount_str << " XMR to The Monero Project (donate.getmonero.org/44AFFq5kSiGBoZ4NMDwYtN18obc8AemS33DBLWs3H7otXft3XjrpDtQGv7SqSsaBYBb98uNbr2VBBEt7f2wfn3RVGQBEP3A)."; + message_writer() << tr("Donating ") << amount_str << " to The Monero Project (donate.getmonero.org/44AFFq5kSiGBoZ4NMDwYtN18obc8AemS33DBLWs3H7otXft3XjrpDtQGv7SqSsaBYBb98uNbr2VBBEt7f2wfn3RVGQBEP3A)."; transfer_new(local_args); return true; } @@ -4415,15 +4511,18 @@ bool simple_wallet::show_transfers(const std::vector<std::string> &args_) try { m_wallet->update_pool_state(); - std::list<std::pair<crypto::hash, tools::wallet2::payment_details>> payments; + std::list<std::pair<crypto::hash, tools::wallet2::pool_payment_details>> payments; m_wallet->get_unconfirmed_payments(payments, m_current_subaddress_account, subaddr_indices); - for (std::list<std::pair<crypto::hash, tools::wallet2::payment_details>>::const_iterator i = payments.begin(); i != payments.end(); ++i) { - const tools::wallet2::payment_details &pd = i->second; + for (std::list<std::pair<crypto::hash, tools::wallet2::pool_payment_details>>::const_iterator i = payments.begin(); i != payments.end(); ++i) { + const tools::wallet2::payment_details &pd = i->second.m_pd; std::string payment_id = string_tools::pod_to_hex(i->first); if (payment_id.substr(16).find_first_not_of('0') == std::string::npos) payment_id = payment_id.substr(0,16); std::string note = m_wallet->get_tx_note(pd.m_tx_hash); - message_writer() << (boost::format("%8.8s %6.6s %16.16s %20.20s %s %s %d %s %s") % "pool" % "in" % get_human_readable_timestamp(pd.m_timestamp) % print_money(pd.m_amount) % string_tools::pod_to_hex(pd.m_tx_hash) % payment_id % pd.m_subaddr_index.minor % "-" % note).str(); + std::string double_spend_note; + if (i->second.m_double_spend_seen) + double_spend_note = tr("[Double spend seen on the network: this transaction may or may not end up being mined] "); + message_writer() << (boost::format("%8.8s %6.6s %16.16s %20.20s %s %s %d %s %s%s") % "pool" % "in" % get_human_readable_timestamp(pd.m_timestamp) % print_money(pd.m_amount) % string_tools::pod_to_hex(pd.m_tx_hash) % payment_id % pd.m_subaddr_index.minor % "-" % note % double_spend_note).str(); } } catch (const std::exception& e) @@ -4743,10 +4842,11 @@ bool simple_wallet::account(const std::vector<std::string> &args/* = std::vector //---------------------------------------------------------------------------------------------------- void simple_wallet::print_accounts() { - success_msg_writer() << boost::format("%15s %21s %21s %21s") % tr("Account") % tr("Balance") % tr("Unlocked balance") % tr("Label"); + success_msg_writer() << boost::format(" %15s %21s %21s %21s") % tr("Account") % tr("Balance") % tr("Unlocked balance") % tr("Label"); for (uint32_t account_index = 0; account_index < m_wallet->get_num_subaddress_accounts(); ++account_index) { - success_msg_writer() << boost::format(tr("%8u %6s %21s %21s %21s")) + success_msg_writer() << boost::format(tr(" %c%8u %6s %21s %21s %21s")) + % (m_current_subaddress_account == account_index ? '*' : ' ') % account_index % m_wallet->get_subaddress_as_str({account_index, 0}).substr(0, 6) % print_money(m_wallet->balance(account_index)) @@ -5439,10 +5539,10 @@ bool simple_wallet::show_transfer(const std::vector<std::string> &args) try { m_wallet->update_pool_state(); - std::list<std::pair<crypto::hash, tools::wallet2::payment_details>> pool_payments; + std::list<std::pair<crypto::hash, tools::wallet2::pool_payment_details>> pool_payments; m_wallet->get_unconfirmed_payments(pool_payments); - for (std::list<std::pair<crypto::hash, tools::wallet2::payment_details>>::const_iterator i = pool_payments.begin(); i != pool_payments.end(); ++i) { - const tools::wallet2::payment_details &pd = i->second; + for (std::list<std::pair<crypto::hash, tools::wallet2::pool_payment_details>>::const_iterator i = pool_payments.begin(); i != pool_payments.end(); ++i) { + const tools::wallet2::payment_details &pd = i->second.m_pd; if (pd.m_tx_hash == txid) { std::string payment_id = string_tools::pod_to_hex(i->first); @@ -5455,6 +5555,8 @@ bool simple_wallet::show_transfer(const std::vector<std::string> &args) success_msg_writer() << "Payment ID: " << payment_id; success_msg_writer() << "Address index: " << pd.m_subaddr_index.minor; success_msg_writer() << "Note: " << m_wallet->get_tx_note(txid); + if (i->second.m_double_spend_seen) + success_msg_writer() << tr("Double spend seen on the network: this transaction may or may not end up being mined"); return true; } } @@ -5546,6 +5648,7 @@ int main(int argc, char* argv[]) command_line::add_arg(desc_params, arg_wallet_file); command_line::add_arg(desc_params, arg_generate_new_wallet); command_line::add_arg(desc_params, arg_generate_from_view_key); + command_line::add_arg(desc_params, arg_generate_from_spend_key); command_line::add_arg(desc_params, arg_generate_from_keys); command_line::add_arg(desc_params, arg_generate_from_multisig_keys); command_line::add_arg(desc_params, arg_generate_from_json); diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h index 639cee642..8100fda55 100644 --- a/src/simplewallet/simplewallet.h +++ b/src/simplewallet/simplewallet.h @@ -281,6 +281,7 @@ namespace cryptonote std::string m_wallet_file; std::string m_generate_new; std::string m_generate_from_view_key; + std::string m_generate_from_spend_key; std::string m_generate_from_keys; std::string m_generate_from_multisig_keys; std::string m_generate_from_json; |