aboutsummaryrefslogtreecommitdiff
path: root/src/simplewallet
diff options
context:
space:
mode:
Diffstat (limited to 'src/simplewallet')
-rw-r--r--src/simplewallet/simplewallet.cpp187
-rw-r--r--src/simplewallet/simplewallet.h3
2 files changed, 172 insertions, 18 deletions
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index ef13bc889..702ff22cb 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -1801,6 +1801,27 @@ bool simple_wallet::version(const std::vector<std::string> &args)
return true;
}
+bool simple_wallet::cold_sign_tx(const std::vector<tools::wallet2::pending_tx>& ptx_vector, tools::wallet2::signed_tx_set &exported_txs, std::vector<cryptonote::address_parse_info> &dsts_info, std::function<bool(const tools::wallet2::signed_tx_set &)> accept_func)
+{
+ std::vector<std::string> tx_aux;
+
+ message_writer(console_color_white, false) << tr("Please confirm the transaction on the device");
+
+ m_wallet->cold_sign_tx(ptx_vector, exported_txs, dsts_info, tx_aux);
+
+ if (accept_func && !accept_func(exported_txs))
+ {
+ MERROR("Transactions rejected by callback");
+ return false;
+ }
+
+ // aux info
+ m_wallet->cold_tx_aux_import(exported_txs.ptx, tx_aux);
+
+ // import key images
+ return m_wallet->import_key_images(exported_txs.key_images);
+}
+
bool simple_wallet::set_always_confirm_transfers(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
{
const auto pwd_container = get_and_verify_password();
@@ -2253,6 +2274,33 @@ bool simple_wallet::set_ignore_fractional_outputs(const std::vector<std::string>
return true;
}
+bool simple_wallet::set_device_name(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
+{
+ const auto pwd_container = get_and_verify_password();
+ if (pwd_container)
+ {
+ if (args.size() == 0){
+ fail_msg_writer() << tr("Device name not specified");
+ return true;
+ }
+
+ m_wallet->device_name(args[0]);
+ bool r = false;
+ try {
+ r = m_wallet->reconnect_device();
+ if (!r){
+ fail_msg_writer() << tr("Device reconnect failed");
+ }
+
+ } catch(const std::exception & e){
+ MWARNING("Device reconnect failed: " << e.what());
+ fail_msg_writer() << tr("Device reconnect failed: ") << e.what();
+ }
+
+ }
+ return true;
+}
+
bool simple_wallet::help(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
{
if(args.empty())
@@ -2484,7 +2532,15 @@ simple_wallet::simple_wallet()
m_cmd_binder.set_handler("show_transfers",
boost::bind(&simple_wallet::show_transfers, this, _1),
tr("show_transfers [in|out|pending|failed|pool|coinbase] [index=<N1>[,<N2>,...]] [<min_height> [<max_height>]]"),
- tr("Show the incoming/outgoing transfers within an optional height range."));
+ // Seemingly broken formatting to compensate for the backslash before the quotes.
+ tr("Show the incoming/outgoing transfers within an optional height range.\n\n"
+ "Output format:\n"
+ "In or Coinbase: Block Number, \"block\"|\"in\", Time, Amount, Transaction Hash, Payment ID, Subaddress Index, \"-\", Note\n"
+ "Out: Block Number, \"out\", Time, Amount*, Transaction Hash, Payment ID, Fee, Destinations, Input addresses**, \"-\", Note\n"
+ "Pool: \"pool\", \"in\", Time, Amount, Transaction Hash, Payment Id, Subaddress Index, \"-\", Note, Double Spend Note\n"
+ "Pending or Failed: \"failed\"|\"pending\", \"out\", Time, Amount*, Transaction Hash, Payment ID, Fee, Input addresses**, \"-\", Note\n\n"
+ "* Excluding change and fee.\n"
+ "** Set of address indices used as inputs in this transfer."));
m_cmd_binder.set_handler("unspent_outputs",
boost::bind(&simple_wallet::unspent_outputs, this, _1),
tr("unspent_outputs [index=<N1>[,<N2>,...]] [<min_amount> [<max_amount>]]"),
@@ -2530,6 +2586,10 @@ simple_wallet::simple_wallet()
boost::bind(&simple_wallet::import_key_images, this, _1),
tr("import_key_images <file>"),
tr("Import a signed key images list and verify their spent status."));
+ m_cmd_binder.set_handler("hw_key_images_sync",
+ boost::bind(&simple_wallet::hw_key_images_sync, this, _1),
+ tr("hw_key_images_sync"),
+ tr("Synchronizes key images with the hw wallet."));
m_cmd_binder.set_handler("hw_reconnect",
boost::bind(&simple_wallet::hw_reconnect, this, _1),
tr("hw_reconnect"),
@@ -2721,6 +2781,7 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
CHECK_SIMPLE_VARIABLE("subaddress-lookahead", set_subaddress_lookahead, tr("<major>:<minor>"));
CHECK_SIMPLE_VARIABLE("segregation-height", set_segregation_height, tr("unsigned integer"));
CHECK_SIMPLE_VARIABLE("ignore-fractional-outputs", set_ignore_fractional_outputs, tr("0 or 1"));
+ CHECK_SIMPLE_VARIABLE("device-name", set_device_name, tr("<device_name[:device_spec]>"));
}
fail_msg_writer() << tr("set: unrecognized argument(s)");
return true;
@@ -4423,7 +4484,7 @@ bool simple_wallet::show_incoming_transfers(const std::vector<std::string>& args
tools::wallet2::transfer_container transfers;
m_wallet->get_transfers(transfers);
- bool transfers_found = false;
+ size_t transfers_found = 0;
for (const auto& td : transfers)
{
if (!filter || available != td.m_spent)
@@ -4436,7 +4497,6 @@ bool simple_wallet::show_incoming_transfers(const std::vector<std::string>& args
if (verbose)
verbose_string = (boost::format("%68s%68s") % tr("pubkey") % tr("key image")).str();
message_writer() << boost::format("%21s%8s%12s%8s%16s%68s%16s%s") % tr("amount") % tr("spent") % tr("unlocked") % tr("ringct") % tr("global index") % tr("tx id") % tr("addr index") % verbose_string;
- transfers_found = true;
}
std::string verbose_string;
if (verbose)
@@ -4451,6 +4511,7 @@ bool simple_wallet::show_incoming_transfers(const std::vector<std::string>& args
td.m_txid %
td.m_subaddr_index.minor %
verbose_string;
+ ++transfers_found;
}
}
@@ -4469,6 +4530,10 @@ bool simple_wallet::show_incoming_transfers(const std::vector<std::string>& args
success_msg_writer() << tr("No incoming unavailable transfers");
}
}
+ else
+ {
+ success_msg_writer() << boost::format("Found %u/%u transfers") % transfers_found % transfers.size();
+ }
return true;
}
@@ -4716,8 +4781,6 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
if (!try_connect_to_daemon())
return true;
- SCOPED_WALLET_UNLOCK();
-
std::vector<std::string> local_args = args_;
std::set<uint32_t> subaddr_indices;
@@ -4829,12 +4892,14 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
local_args.pop_back();
}
+ vector<cryptonote::address_parse_info> dsts_info;
vector<cryptonote::tx_destination_entry> dsts;
size_t num_subaddresses = 0;
for (size_t i = 0; i < local_args.size(); )
{
+ dsts_info.emplace_back();
+ cryptonote::address_parse_info & info = dsts_info.back();
cryptonote::tx_destination_entry de;
- cryptonote::address_parse_info info;
bool r = true;
// check for a URI
@@ -4937,6 +5002,8 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
}
}
+ SCOPED_WALLET_UNLOCK();
+
try
{
// figure out what tx will be necessary
@@ -5116,6 +5183,28 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
success_msg_writer(true) << tr("Unsigned transaction(s) successfully written to file: ") << "multisig_monero_tx";
}
}
+ else if (m_wallet->get_account().get_device().has_tx_cold_sign())
+ {
+ try
+ {
+ tools::wallet2::signed_tx_set signed_tx;
+ if (!cold_sign_tx(ptx_vector, signed_tx, dsts_info, [&](const tools::wallet2::signed_tx_set &tx){ return accept_loaded_tx(tx); })){
+ fail_msg_writer() << tr("Failed to cold sign transaction with HW wallet");
+ return true;
+ }
+
+ commit_or_save(signed_tx.ptx, m_do_not_relay);
+ }
+ catch (const std::exception& e)
+ {
+ handle_transfer_exception(std::current_exception(), m_wallet->is_trusted_daemon());
+ }
+ catch (...)
+ {
+ LOG_ERROR("Unknown error");
+ fail_msg_writer() << tr("unknown error");
+ }
+ }
else if (m_wallet->watch_only())
{
bool r = m_wallet->save_tx(ptx_vector, "unsigned_monero_tx");
@@ -5538,6 +5627,31 @@ bool simple_wallet::sweep_main(uint64_t below, bool locked, const std::vector<st
success_msg_writer(true) << tr("Unsigned transaction(s) successfully written to file: ") << "multisig_monero_tx";
}
}
+ else if (m_wallet->get_account().get_device().has_tx_cold_sign())
+ {
+ try
+ {
+ tools::wallet2::signed_tx_set signed_tx;
+ std::vector<cryptonote::address_parse_info> dsts_info;
+ dsts_info.push_back(info);
+
+ if (!cold_sign_tx(ptx_vector, signed_tx, dsts_info, [&](const tools::wallet2::signed_tx_set &tx){ return accept_loaded_tx(tx); })){
+ fail_msg_writer() << tr("Failed to cold sign transaction with HW wallet");
+ return true;
+ }
+
+ commit_or_save(signed_tx.ptx, m_do_not_relay);
+ }
+ catch (const std::exception& e)
+ {
+ handle_transfer_exception(std::current_exception(), m_wallet->is_trusted_daemon());
+ }
+ catch (...)
+ {
+ LOG_ERROR("Unknown error");
+ fail_msg_writer() << tr("unknown error");
+ }
+ }
else if (m_wallet->watch_only())
{
bool r = m_wallet->save_tx(ptx_vector, "unsigned_monero_tx");
@@ -5996,8 +6110,8 @@ bool simple_wallet::accept_loaded_tx(const std::function<size_t()> get_num_txes,
bool simple_wallet::accept_loaded_tx(const tools::wallet2::unsigned_tx_set &txs)
{
std::string extra_message;
- if (!txs.transfers.empty())
- extra_message = (boost::format("%u outputs to import. ") % (unsigned)txs.transfers.size()).str();
+ if (!txs.transfers.second.empty())
+ extra_message = (boost::format("%u outputs to import. ") % (unsigned)txs.transfers.second.size()).str();
return accept_loaded_tx([&txs](){return txs.txes.size();}, [&txs](size_t n)->const tools::wallet2::tx_construction_data&{return txs.txes[n];}, extra_message);
}
//----------------------------------------------------------------------------------------------------
@@ -6750,7 +6864,8 @@ bool simple_wallet::show_transfers(const std::vector<std::string> &args_)
payment_id = payment_id.substr(0,16);
std::string note = m_wallet->get_tx_note(pd.m_tx_hash);
const std::string type = pd.m_coinbase ? tr("block") : tr("in");
- output.insert(std::make_pair(pd.m_block_height, std::make_tuple(epee::console_color_green, type, (boost::format("%25.25s %20.20s %s %s %d %s %s") % 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())));
+ const bool unlocked = m_wallet->is_tx_spendtime_unlocked(pd.m_unlock_time, pd.m_block_height);
+ output.insert(std::make_pair(pd.m_block_height, std::make_tuple(epee::console_color_green, type, (boost::format("%8.8s %25.25s %20.20s %s %s %d %s %s") % (unlocked ? "unlocked" : "locked") % 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())));
}
}
@@ -6783,7 +6898,7 @@ bool simple_wallet::show_transfers(const std::vector<std::string> &args_)
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(i->first);
- output.insert(std::make_pair(pd.m_block_height, std::make_tuple(epee::console_color_magenta, tr("out"), (boost::format("%25.25s %20.20s %s %s %14.14s %s %s - %s") % get_human_readable_timestamp(pd.m_timestamp) % print_money(pd.m_amount_in - change - fee) % string_tools::pod_to_hex(i->first) % payment_id % print_money(fee) % dests % print_subaddr_indices(pd.m_subaddr_indices) % note).str())));
+ output.insert(std::make_pair(pd.m_block_height, std::make_tuple(epee::console_color_magenta, tr("out"), (boost::format("%8.8s %25.25s %20.20s %s %s %14.14s %s %s - %s") % "-" % get_human_readable_timestamp(pd.m_timestamp) % print_money(pd.m_amount_in - change - fee) % string_tools::pod_to_hex(i->first) % payment_id % print_money(fee) % dests % print_subaddr_indices(pd.m_subaddr_indices) % note).str())));
}
}
@@ -6812,7 +6927,7 @@ bool simple_wallet::show_transfers(const std::vector<std::string> &args_)
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 %25.25s %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();
+ message_writer() << (boost::format("%8.8s %6.6s %8.8s %25.25s %20.20s %s %s %d %s %s%s") % "pool" % "in" % "locked" % 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)
@@ -6835,7 +6950,7 @@ bool simple_wallet::show_transfers(const std::vector<std::string> &args_)
std::string note = m_wallet->get_tx_note(i->first);
bool is_failed = pd.m_state == tools::wallet2::unconfirmed_transfer_details::failed;
if ((failed && is_failed) || (!is_failed && pending)) {
- message_writer() << (boost::format("%8.8s %6.6s %25.25s %20.20s %s %s %14.14s %s - %s") % (is_failed ? tr("failed") : tr("pending")) % tr("out") % get_human_readable_timestamp(pd.m_timestamp) % print_money(amount - pd.m_change - fee) % string_tools::pod_to_hex(i->first) % payment_id % print_money(fee) % print_subaddr_indices(pd.m_subaddr_indices) % note).str();
+ message_writer() << (boost::format("%8.8s %6.6s %8.8s %25.25s %20.20s %s %s %14.14s %s - %s") % (is_failed ? tr("failed") : tr("pending")) % tr("out") % "-" % get_human_readable_timestamp(pd.m_timestamp) % print_money(amount - pd.m_change - fee) % string_tools::pod_to_hex(i->first) % payment_id % print_money(fee) % print_subaddr_indices(pd.m_subaddr_indices) % note).str();
}
}
}
@@ -7065,12 +7180,6 @@ bool simple_wallet::run()
void simple_wallet::stop()
{
m_cmd_binder.stop_handling();
-
- m_idle_run.store(false, std::memory_order_relaxed);
- m_wallet->stop();
- // make the background refresh thread quit
- boost::unique_lock<boost::mutex> lock(m_idle_mutex);
- m_idle_cond.notify_one();
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::account(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
@@ -7807,6 +7916,48 @@ bool simple_wallet::import_key_images(const std::vector<std::string> &args)
return true;
}
//----------------------------------------------------------------------------------------------------
+bool simple_wallet::hw_key_images_sync(const std::vector<std::string> &args)
+{
+ if (!m_wallet->key_on_device())
+ {
+ fail_msg_writer() << tr("command only supported by HW wallet");
+ return true;
+ }
+ if (!m_wallet->get_account().get_device().has_ki_cold_sync())
+ {
+ fail_msg_writer() << tr("hw wallet does not support cold KI sync");
+ return true;
+ }
+ if (!m_wallet->is_trusted_daemon())
+ {
+ fail_msg_writer() << tr("this command requires a trusted daemon. Enable with --trusted-daemon");
+ return true;
+ }
+
+ LOCK_IDLE_SCOPE();
+ try
+ {
+ message_writer(console_color_white, false) << tr("Please confirm the key image sync on the device");
+
+ uint64_t spent = 0, unspent = 0;
+ uint64_t height = m_wallet->cold_key_image_sync(spent, unspent);
+ if (height > 0)
+ {
+ success_msg_writer() << tr("Signed key images imported to height ") << height << ", "
+ << print_money(spent) << tr(" spent, ") << print_money(unspent) << tr(" unspent");
+ } else {
+ fail_msg_writer() << tr("Failed to import key images");
+ }
+ }
+ catch (const std::exception &e)
+ {
+ fail_msg_writer() << tr("Failed to import key images: ") << e.what();
+ return true;
+ }
+
+ return true;
+}
+//----------------------------------------------------------------------------------------------------
bool simple_wallet::hw_reconnect(const std::vector<std::string> &args)
{
if (!m_wallet->key_on_device())
diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h
index 6eedef4a2..26d51a431 100644
--- a/src/simplewallet/simplewallet.h
+++ b/src/simplewallet/simplewallet.h
@@ -142,6 +142,7 @@ namespace cryptonote
bool set_subaddress_lookahead(const std::vector<std::string> &args = std::vector<std::string>());
bool set_segregation_height(const std::vector<std::string> &args = std::vector<std::string>());
bool set_ignore_fractional_outputs(const std::vector<std::string> &args = std::vector<std::string>());
+ bool set_device_name(const std::vector<std::string> &args = std::vector<std::string>());
bool help(const std::vector<std::string> &args = std::vector<std::string>());
bool start_mining(const std::vector<std::string> &args);
bool stop_mining(const std::vector<std::string> &args);
@@ -203,6 +204,7 @@ namespace cryptonote
bool verify(const std::vector<std::string> &args);
bool export_key_images(const std::vector<std::string> &args);
bool import_key_images(const std::vector<std::string> &args);
+ bool hw_key_images_sync(const std::vector<std::string> &args);
bool hw_reconnect(const std::vector<std::string> &args);
bool export_outputs(const std::vector<std::string> &args);
bool import_outputs(const std::vector<std::string> &args);
@@ -227,6 +229,7 @@ namespace cryptonote
bool unblackball(const std::vector<std::string>& args);
bool blackballed(const std::vector<std::string>& args);
bool version(const std::vector<std::string>& args);
+ bool cold_sign_tx(const std::vector<tools::wallet2::pending_tx>& ptx_vector, tools::wallet2::signed_tx_set &exported_txs, std::vector<cryptonote::address_parse_info> &dsts_info, std::function<bool(const tools::wallet2::signed_tx_set &)> accept_func);
uint64_t get_daemon_blockchain_height(std::string& err);
bool try_connect_to_daemon(bool silent = false, uint32_t* version = nullptr);