aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/simplewallet/simplewallet.cpp144
-rw-r--r--src/simplewallet/simplewallet.h2
-rw-r--r--src/wallet/wallet2.cpp97
-rw-r--r--src/wallet/wallet2.h20
4 files changed, 188 insertions, 75 deletions
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index e23fb3836..e7dd1474d 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -113,6 +113,14 @@ typedef cryptonote::simple_wallet sw;
#define PRINT_USAGE(usage_help) fail_msg_writer() << boost::format(tr("usage: %s")) % usage_help;
+#define LONG_PAYMENT_ID_SUPPORT_CHECK() \
+ do { \
+ if (!m_long_payment_id_support) { \
+ fail_msg_writer() << tr("Long payment IDs are obsolete. Use --long-payment-id-support if you really must use one."); \
+ return true; \
+ } \
+ } while(0)
+
enum TransferType {
Transfer,
TransferLocked,
@@ -141,6 +149,7 @@ namespace
const command_line::arg_descriptor<bool> arg_create_address_file = {"create-address-file", sw::tr("Create an address file for new wallets"), false};
const command_line::arg_descriptor<std::string> arg_subaddress_lookahead = {"subaddress-lookahead", tools::wallet2::tr("Set subaddress lookahead sizes to <major>:<minor>"), ""};
const command_line::arg_descriptor<bool> arg_use_english_language_names = {"use-english-language-names", sw::tr("Display English language names"), false};
+ const command_line::arg_descriptor<bool> arg_long_payment_id_support = {"long-payment-id-support", sw::tr("Support obsolete long (unencrypted) payment ids"), false};
const command_line::arg_descriptor< std::vector<std::string> > arg_command = {"command", ""};
@@ -151,12 +160,12 @@ namespace
const char* USAGE_PAYMENTS("payments <PID_1> [<PID_2> ... <PID_N>]");
const char* USAGE_PAYMENT_ID("payment_id");
const char* USAGE_TRANSFER("transfer [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] (<URI> | <address> <amount>) [<payment_id>]");
- const char* USAGE_LOCKED_TRANSFER("locked_transfer [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] (<URI> | <addr> <amount>) <lockblocks> [<payment_id>]");
- const char* USAGE_LOCKED_SWEEP_ALL("locked_sweep_all [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> <lockblocks> [<payment_id>]");
- const char* USAGE_SWEEP_ALL("sweep_all [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] [outputs=<N>] <address> [<payment_id>]");
- const char* USAGE_SWEEP_BELOW("sweep_below <amount_threshold> [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> [<payment_id>]");
- const char* USAGE_SWEEP_SINGLE("sweep_single [<priority>] [<ring_size>] [outputs=<N>] <key_image> <address> [<payment_id>]");
- const char* USAGE_DONATE("donate [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <amount> [<payment_id>]");
+ const char* USAGE_LOCKED_TRANSFER("locked_transfer [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] (<URI> | <addr> <amount>) <lockblocks> [<payment_id (obsolete)>]");
+ const char* USAGE_LOCKED_SWEEP_ALL("locked_sweep_all [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> <lockblocks> [<payment_id (obsolete)>]");
+ const char* USAGE_SWEEP_ALL("sweep_all [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] [outputs=<N>] <address> [<payment_id (obsolete)>]");
+ const char* USAGE_SWEEP_BELOW("sweep_below <amount_threshold> [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> [<payment_id (obsolete)>]");
+ const char* USAGE_SWEEP_SINGLE("sweep_single [<priority>] [<ring_size>] [outputs=<N>] <key_image> <address> [<payment_id (obsolete)>]");
+ const char* USAGE_DONATE("donate [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <amount> [<payment_id (obsolete)>]");
const char* USAGE_SIGN_TRANSFER("sign_transfer [export_raw]");
const char* USAGE_SET_LOG("set_log <level>|{+,-,}<categories>");
const char* USAGE_ACCOUNT("account\n"
@@ -231,12 +240,15 @@ namespace
const char* USAGE_VERSION("version");
const char* USAGE_HELP("help [<command>]");
- std::string input_line(const std::string& prompt)
+ std::string input_line(const std::string& prompt, bool yesno = false)
{
#ifdef HAVE_READLINE
rdln::suspend_readline pause_readline;
#endif
std::cout << prompt;
+ if (yesno)
+ std::cout << " (Y/Yes/N/No)";
+ std::cout << ": " << std::flush;
std::string buf;
#ifdef _WIN32
@@ -248,12 +260,12 @@ namespace
return epee::string_tools::trim(buf);
}
- epee::wipeable_string input_secure_line(const std::string& prompt)
+ epee::wipeable_string input_secure_line(const char *prompt)
{
#ifdef HAVE_READLINE
rdln::suspend_readline pause_readline;
#endif
- auto pwd_container = tools::password_container::prompt(false, prompt.c_str(), false);
+ auto pwd_container = tools::password_container::prompt(false, prompt, false);
if (!pwd_container)
{
MERROR("Failed to read secure line");
@@ -426,10 +438,10 @@ namespace
<< ", " << dnssec_str << std::endl
<< sw::tr(" Monero Address = ") << addresses[0]
<< std::endl
- << sw::tr("Is this OK? (Y/n) ")
+ << sw::tr("Is this OK?")
;
// prompt the user for confirmation given the dns query and dnssec status
- std::string confirm_dns_ok = input_line(prompt.str());
+ std::string confirm_dns_ok = input_line(prompt.str(), true);
if (std::cin.eof())
{
return {};
@@ -597,7 +609,7 @@ namespace
fail_msg_writer() << boost::format(sw::tr("File %s likely stores wallet private keys! Use a different file name.")) % filename;
return false;
}
- return command_line::is_yes(input_line((boost::format(sw::tr("File %s already exists. Are you sure to overwrite it? (Y/Yes/N/No): ")) % filename).str()));
+ return command_line::is_yes(input_line((boost::format(sw::tr("File %s already exists. Are you sure to overwrite it?")) % filename).str(), true));
}
return true;
}
@@ -861,6 +873,8 @@ bool simple_wallet::change_password(const std::vector<std::string> &args)
bool simple_wallet::payment_id(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
{
+ LONG_PAYMENT_ID_SUPPORT_CHECK();
+
crypto::hash payment_id;
if (args.size() > 0)
{
@@ -2223,6 +2237,8 @@ bool simple_wallet::set_refresh_type(const std::vector<std::string> &args/* = st
bool simple_wallet::set_confirm_missing_payment_id(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
{
+ LONG_PAYMENT_ID_SUPPORT_CHECK();
+
const auto pwd_container = get_and_verify_password();
if (pwd_container)
{
@@ -2783,7 +2799,7 @@ simple_wallet::simple_wallet()
m_cmd_binder.set_handler("rescan_bc",
boost::bind(&simple_wallet::rescan_blockchain, this, _1),
tr(USAGE_RESCAN_BC),
- tr("Rescan the blockchain from scratch, losing any information which can not be recovered from the blockchain itself."));
+ tr("Rescan the blockchain from scratch. If \"hard\" is specified, you will lose any information which can not be recovered from the blockchain itself."));
m_cmd_binder.set_handler("set_tx_note",
boost::bind(&simple_wallet::set_tx_note, this, _1),
tr(USAGE_SET_TX_NOTE),
@@ -2848,7 +2864,7 @@ simple_wallet::simple_wallet()
m_cmd_binder.set_handler("payment_id",
boost::bind(&simple_wallet::payment_id, this, _1),
tr(USAGE_PAYMENT_ID),
- tr("Generate a new random full size payment id. These will be unencrypted on the blockchain, see integrated_address for encrypted short payment ids."));
+ tr("Generate a new random full size payment id (obsolete). These will be unencrypted on the blockchain, see integrated_address for encrypted short payment ids."));
m_cmd_binder.set_handler("fee",
boost::bind(&simple_wallet::print_fee_info, this, _1),
tr("Print the information about the current fee and transaction backlog."));
@@ -3154,9 +3170,9 @@ bool simple_wallet::ask_wallet_create_if_needed()
LOG_PRINT_L3("User asked to specify wallet file name.");
wallet_path = input_line(
tr(m_restoring ? "Specify a new wallet file name for your restored wallet (e.g., MyWallet).\n"
- "Wallet file name (or Ctrl-C to quit): " :
+ "Wallet file name (or Ctrl-C to quit)" :
"Specify wallet file name (e.g., MyWallet). If the wallet doesn't exist, it will be created.\n"
- "Wallet file name (or Ctrl-C to quit): ")
+ "Wallet file name (or Ctrl-C to quit)")
);
if(std::cin.eof())
{
@@ -3203,7 +3219,7 @@ bool simple_wallet::ask_wallet_create_if_needed()
if (!m_restoring)
{
message_writer() << tr("No wallet found with that name. Confirm creation of new wallet named: ") << wallet_path;
- confirm_creation = input_line(tr("(Y/Yes/N/No): "));
+ confirm_creation = input_line("", true);
if(std::cin.eof())
{
LOG_ERROR("Unexpected std::cin.eof() - Exited simple_wallet::ask_wallet_create_if_needed()");
@@ -3412,7 +3428,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
{
m_wallet_file = m_generate_from_view_key;
// parse address
- std::string address_string = input_line("Standard address: ");
+ std::string address_string = input_line("Standard address");
if (std::cin.eof())
return false;
if (address_string.empty()) {
@@ -3432,7 +3448,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
}
// parse view secret key
- epee::wipeable_string viewkey_string = input_secure_line("Secret view key: ");
+ epee::wipeable_string viewkey_string = input_secure_line("Secret view key");
if (std::cin.eof())
return false;
if (viewkey_string.empty()) {
@@ -3467,7 +3483,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
{
m_wallet_file = m_generate_from_spend_key;
// parse spend secret key
- epee::wipeable_string spendkey_string = input_secure_line("Secret spend key: ");
+ epee::wipeable_string spendkey_string = input_secure_line("Secret spend key");
if (std::cin.eof())
return false;
if (spendkey_string.empty()) {
@@ -3487,7 +3503,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
{
m_wallet_file = m_generate_from_keys;
// parse address
- std::string address_string = input_line("Standard address: ");
+ std::string address_string = input_line("Standard address");
if (std::cin.eof())
return false;
if (address_string.empty()) {
@@ -3507,7 +3523,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
}
// parse spend secret key
- epee::wipeable_string spendkey_string = input_secure_line("Secret spend key: ");
+ epee::wipeable_string spendkey_string = input_secure_line("Secret spend key");
if (std::cin.eof())
return false;
if (spendkey_string.empty()) {
@@ -3522,7 +3538,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
}
// parse view secret key
- epee::wipeable_string viewkey_string = input_secure_line("Secret view key: ");
+ epee::wipeable_string viewkey_string = input_secure_line("Secret view key");
if (std::cin.eof())
return false;
if (viewkey_string.empty()) {
@@ -3569,7 +3585,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
unsigned int multisig_n;
// parse multisig type
- std::string multisig_type_string = input_line("Multisig type (input as M/N with M <= N and M > 1): ");
+ std::string multisig_type_string = input_line("Multisig type (input as M/N with M <= N and M > 1)");
if (std::cin.eof())
return false;
if (multisig_type_string.empty())
@@ -3595,7 +3611,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
message_writer() << boost::format(tr("Generating master wallet from %u of %u multisig wallet keys")) % multisig_m % multisig_n;
// parse multisig address
- std::string address_string = input_line("Multisig wallet address: ");
+ std::string address_string = input_line("Multisig wallet address");
if (std::cin.eof())
return false;
if (address_string.empty()) {
@@ -3610,7 +3626,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
}
// parse secret view key
- epee::wipeable_string viewkey_string = input_secure_line("Secret view key: ");
+ epee::wipeable_string viewkey_string = input_secure_line("Secret view key");
if (std::cin.eof())
return false;
if (viewkey_string.empty())
@@ -3649,7 +3665,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
// get N secret spend keys from user
for(unsigned int i=0; i<multisig_n; ++i)
{
- spendkey_string = input_secure_line(tr((boost::format(tr("Secret spend key (%u of %u):")) % (i+1) % multisig_m).str().c_str()));
+ spendkey_string = input_secure_line(tr((boost::format(tr("Secret spend key (%u of %u)")) % (i+1) % multisig_m).str().c_str()));
if (std::cin.eof())
return false;
if (spendkey_string.empty())
@@ -3726,7 +3742,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
wrt << tr("Assumed you are creating a new account, restore will be done from current estimated blockchain height.");
wrt << tr("Use --restore-height or --restore-date if you want to restore an already setup account from a specific height");
}
- std::string confirm = input_line(tr("Is this okay? (Y/Yes/N/No): "));
+ std::string confirm = input_line(tr("Is this okay?"), true);
if (std::cin.eof() || !command_line::is_yes(confirm))
CHECK_AND_ASSERT_MES(false, false, tr("account creation aborted"));
@@ -3782,9 +3798,9 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
{
std::string heightstr;
if (!connected || version < MAKE_CORE_RPC_VERSION(1, 6))
- heightstr = input_line("Restore from specific blockchain height (optional, default 0): ");
+ heightstr = input_line("Restore from specific blockchain height (optional, default 0)");
else
- heightstr = input_line("Restore from specific blockchain height (optional, default 0),\nor alternatively from specific date (YYYY-MM-DD): ");
+ heightstr = input_line("Restore from specific blockchain height (optional, default 0),\nor alternatively from specific date (YYYY-MM-DD)");
if (std::cin.eof())
return false;
if (heightstr.empty())
@@ -3813,7 +3829,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
return false;
m_restore_height = m_wallet->get_blockchain_height_by_date(year, month, day);
success_msg_writer() << tr("Restore height is: ") << m_restore_height;
- std::string confirm = input_line(tr("Is this okay? (Y/Yes/N/No): "));
+ std::string confirm = input_line(tr("Is this okay?"), true);
if (std::cin.eof())
return false;
if(command_line::is_yes(confirm))
@@ -3836,7 +3852,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
if (m_restore_height >= estimate_height)
{
success_msg_writer() << tr("Restore height ") << m_restore_height << (" is not yet reached. The current estimated height is ") << estimate_height;
- std::string confirm = input_line(tr("Still apply restore height? (Y/Yes/N/No): "));
+ std::string confirm = input_line(tr("Still apply restore height?"), true);
if (std::cin.eof() || command_line::is_no(confirm))
m_restore_height = 0;
}
@@ -3901,6 +3917,7 @@ bool simple_wallet::handle_command_line(const boost::program_options::variables_
m_do_not_relay = command_line::get_arg(vm, arg_do_not_relay);
m_subaddress_lookahead = command_line::get_arg(vm, arg_subaddress_lookahead);
m_use_english_language_names = command_line::get_arg(vm, arg_use_english_language_names);
+ m_long_payment_id_support = command_line::get_arg(vm, arg_long_payment_id_support);
m_restoring = !m_generate_from_view_key.empty() ||
!m_generate_from_spend_key.empty() ||
!m_generate_from_keys.empty() ||
@@ -3968,7 +3985,7 @@ std::string simple_wallet::get_mnemonic_language()
}
while (language_number < 0)
{
- language_choice = input_line(tr("Enter the number corresponding to the language of your choice: "));
+ language_choice = input_line(tr("Enter the number corresponding to the language of your choice"));
if (std::cin.eof())
return std::string();
try
@@ -4614,7 +4631,7 @@ void simple_wallet::on_money_received(uint64_t height, const crypto::hash &txid,
tr("NOTE: this transaction uses an encrypted payment ID: consider using subaddresses instead");
else if (get_payment_id_from_tx_extra_nonce(extra_nonce.nonce, payment_id))
message_writer(console_color_red, false) <<
- tr("WARNING: this transaction uses an unencrypted payment ID: consider using subaddresses instead");
+ (m_long_payment_id_support ? tr("WARNING: this transaction uses an unencrypted payment ID: consider using subaddresses instead.") : tr("WARNING: this transaction uses an unencrypted payment ID: these are obsolete. Support will be withdrawn in the future. Use subaddresses instead."));
}
}
if (m_auto_refresh_refreshing)
@@ -5313,6 +5330,8 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
bool r = true;
if (tools::wallet2::parse_long_payment_id(payment_id_str, payment_id))
{
+ LONG_PAYMENT_ID_SUPPORT_CHECK();
+
std::string extra_nonce;
set_payment_id_to_tx_extra_nonce(extra_nonce, payment_id);
r = add_extra_nonce_to_tx_extra(extra, extra_nonce);
@@ -5423,6 +5442,7 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
}
else if (tools::wallet2::parse_payment_id(payment_id_uri, payment_id))
{
+ LONG_PAYMENT_ID_SUPPORT_CHECK();
set_payment_id_to_tx_extra_nonce(extra_nonce, payment_id);
message_writer() << tr("Unencrypted payment IDs are bad for privacy: ask the recipient to use subaddresses instead");
}
@@ -5444,9 +5464,9 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
}
// prompt is there is no payment id and confirmation is required
- if (!payment_id_seen && m_wallet->confirm_missing_payment_id() && dsts.size() > num_subaddresses)
+ if (m_long_payment_id_support && !payment_id_seen && m_wallet->confirm_missing_payment_id() && dsts.size() > num_subaddresses)
{
- std::string accepted = input_line(tr("No payment id is included with this transaction. Is this okay? (Y/Yes/N/No): "));
+ std::string accepted = input_line(tr("No payment id is included with this transaction. Is this okay?"), true);
if (std::cin.eof())
return false;
if (!command_line::is_yes(accepted))
@@ -5510,23 +5530,23 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
std::vector<std::pair<uint64_t, uint64_t>> nblocks = m_wallet->estimate_backlog({std::make_pair(worst_fee_per_byte, worst_fee_per_byte)});
if (nblocks.size() != 1)
{
- prompt << "Internal error checking for backlog. " << tr("Is this okay anyway? (Y/Yes/N/No): ");
+ prompt << "Internal error checking for backlog. " << tr("Is this okay anyway?");
}
else
{
if (nblocks[0].first > m_wallet->get_confirm_backlog_threshold())
- prompt << (boost::format(tr("There is currently a %u block backlog at that fee level. Is this okay? (Y/Yes/N/No): ")) % nblocks[0].first).str();
+ prompt << (boost::format(tr("There is currently a %u block backlog at that fee level. Is this okay?")) % nblocks[0].first).str();
}
}
catch (const std::exception &e)
{
- prompt << tr("Failed to check for backlog: ") << e.what() << ENDL << tr("Is this okay anyway? (Y/Yes/N/No): ");
+ prompt << tr("Failed to check for backlog: ") << e.what() << ENDL << tr("Is this okay anyway?");
}
std::string prompt_str = prompt.str();
if (!prompt_str.empty())
{
- std::string accepted = input_line(prompt_str);
+ std::string accepted = input_line(prompt_str, true);
if (std::cin.eof())
return false;
if (!command_line::is_yes(accepted))
@@ -5612,9 +5632,9 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
{
prompt << tr("WARNING: this is a non default ring size, which may harm your privacy. Default is recommended.");
}
- prompt << ENDL << tr("Is this okay? (Y/Yes/N/No): ");
+ prompt << ENDL << tr("Is this okay?");
- std::string accepted = input_line(prompt.str());
+ std::string accepted = input_line(prompt.str(), true);
if (std::cin.eof())
return false;
if (!command_line::is_yes(accepted))
@@ -5752,17 +5772,17 @@ bool simple_wallet::sweep_unmixable(const std::vector<std::string> &args_)
std::string prompt_str = tr("Sweeping ") + print_money(total_unmixable);
if (ptx_vector.size() > 1) {
- prompt_str = (boost::format(tr("Sweeping %s in %llu transactions for a total fee of %s. Is this okay? (Y/Yes/N/No): ")) %
+ prompt_str = (boost::format(tr("Sweeping %s in %llu transactions for a total fee of %s. Is this okay?")) %
print_money(total_unmixable) %
((unsigned long long)ptx_vector.size()) %
print_money(total_fee)).str();
}
else {
- prompt_str = (boost::format(tr("Sweeping %s for a total fee of %s. Is this okay? (Y/Yes/N/No): ")) %
+ prompt_str = (boost::format(tr("Sweeping %s for a total fee of %s. Is this okay?")) %
print_money(total_unmixable) %
print_money(total_fee)).str();
}
- std::string accepted = input_line(prompt_str);
+ std::string accepted = input_line(prompt_str, true);
if (std::cin.eof())
return true;
if (!command_line::is_yes(accepted))
@@ -5805,7 +5825,7 @@ bool simple_wallet::sweep_unmixable(const std::vector<std::string> &args_)
catch (const tools::error::not_enough_unlocked_money& e)
{
fail_msg_writer() << tr("Not enough money in unlocked balance");
- std::string accepted = input_line((boost::format(tr("Discarding %s of unmixable outputs that cannot be spent, which can be undone by \"rescan_spent\". Is this okay? (Y/Yes/N/No): ")) % print_money(e.available())).str());
+ std::string accepted = input_line((boost::format(tr("Discarding %s of unmixable outputs that cannot be spent, which can be undone by \"rescan_spent\". Is this okay?")) % print_money(e.available())).str(), true);
if (std::cin.eof())
return true;
if (command_line::is_yes(accepted))
@@ -5967,6 +5987,8 @@ bool simple_wallet::sweep_main(uint64_t below, bool locked, const std::vector<st
bool r = tools::wallet2::parse_long_payment_id(payment_id_str, payment_id);
if(r)
{
+ LONG_PAYMENT_ID_SUPPORT_CHECK();
+
std::string extra_nonce;
set_payment_id_to_tx_extra_nonce(extra_nonce, payment_id);
r = add_extra_nonce_to_tx_extra(extra, extra_nonce);
@@ -6011,9 +6033,9 @@ bool simple_wallet::sweep_main(uint64_t below, bool locked, const std::vector<st
}
// prompt is there is no payment id and confirmation is required
- if (!payment_id_seen && m_wallet->confirm_missing_payment_id() && !info.is_subaddress)
+ if (m_long_payment_id_support && !payment_id_seen && m_wallet->confirm_missing_payment_id() && !info.is_subaddress)
{
- std::string accepted = input_line(tr("No payment id is included with this transaction. Is this okay? (Y/Yes/N/No): "));
+ std::string accepted = input_line(tr("No payment id is included with this transaction. Is this okay?"), true);
if (std::cin.eof())
return true;
if (!command_line::is_yes(accepted))
@@ -6061,17 +6083,17 @@ bool simple_wallet::sweep_main(uint64_t below, bool locked, const std::vector<st
if (m_wallet->print_ring_members() && !print_ring_members(ptx_vector, prompt))
return true;
if (ptx_vector.size() > 1) {
- prompt << boost::format(tr("Sweeping %s in %llu transactions for a total fee of %s. Is this okay? (Y/Yes/N/No): ")) %
+ prompt << boost::format(tr("Sweeping %s in %llu transactions for a total fee of %s. Is this okay?")) %
print_money(total_sent) %
((unsigned long long)ptx_vector.size()) %
print_money(total_fee);
}
else {
- prompt << boost::format(tr("Sweeping %s for a total fee of %s. Is this okay? (Y/Yes/N/No): ")) %
+ prompt << boost::format(tr("Sweeping %s for a total fee of %s. Is this okay?")) %
print_money(total_sent) %
print_money(total_fee);
}
- std::string accepted = input_line(prompt.str());
+ std::string accepted = input_line(prompt.str(), true);
if (std::cin.eof())
return true;
if (!command_line::is_yes(accepted))
@@ -6222,6 +6244,7 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_)
std::string extra_nonce;
if (tools::wallet2::parse_long_payment_id(local_args.back(), payment_id))
{
+ LONG_PAYMENT_ID_SUPPORT_CHECK();
set_payment_id_to_tx_extra_nonce(extra_nonce, payment_id);
}
else
@@ -6279,9 +6302,9 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_)
}
// prompt if there is no payment id and confirmation is required
- if (!payment_id_seen && m_wallet->confirm_missing_payment_id() && !info.is_subaddress)
+ if (m_long_payment_id_support && !payment_id_seen && m_wallet->confirm_missing_payment_id() && !info.is_subaddress)
{
- std::string accepted = input_line(tr("No payment id is included with this transaction. Is this okay? (Y/Yes/N/No): "));
+ std::string accepted = input_line(tr("No payment id is included with this transaction. Is this okay?"), true);
if (std::cin.eof())
return true;
if (!command_line::is_yes(accepted))
@@ -6323,10 +6346,10 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_)
std::ostringstream prompt;
if (!print_ring_members(ptx_vector, prompt))
return true;
- prompt << boost::format(tr("Sweeping %s for a total fee of %s. Is this okay? (Y/Yes/N/No): ")) %
+ prompt << boost::format(tr("Sweeping %s for a total fee of %s. Is this okay?")) %
print_money(total_sent) %
print_money(total_fee);
- std::string accepted = input_line(prompt.str());
+ std::string accepted = input_line(prompt.str(), true);
if (std::cin.eof())
return true;
if (!command_line::is_yes(accepted))
@@ -6495,6 +6518,7 @@ bool simple_wallet::accept_loaded_tx(const std::function<size_t()> get_num_txes,
if (!payment_id_string.empty())
payment_id_string += ", ";
payment_id_string = std::string("unencrypted payment ID ") + epee::string_tools::pod_to_hex(payment_id);
+ payment_id_string += " (OBSOLETE)";
}
}
}
@@ -6590,8 +6614,8 @@ bool simple_wallet::accept_loaded_tx(const std::function<size_t()> get_num_txes,
change_string += tr("no change");
uint64_t fee = amount - amount_to_dests;
- std::string prompt_str = (boost::format(tr("Loaded %lu transactions, for %s, fee %s, %s, %s, with min ring size %lu, %s. %sIs this okay? (Y/Yes/N/No): ")) % (unsigned long)get_num_txes() % print_money(amount) % print_money(fee) % dest_string % change_string % (unsigned long)min_ring_size % payment_id_string % extra_message).str();
- return command_line::is_yes(input_line(prompt_str));
+ std::string prompt_str = (boost::format(tr("Loaded %lu transactions, for %s, fee %s, %s, %s, with min ring size %lu, %s. %sIs this okay?")) % (unsigned long)get_num_txes() % print_money(amount) % print_money(fee) % dest_string % change_string % (unsigned long)min_ring_size % payment_id_string % extra_message).str();
+ return command_line::is_yes(input_line(prompt_str, true));
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::accept_loaded_tx(const tools::wallet2::unsigned_tx_set &txs)
@@ -7749,7 +7773,7 @@ bool simple_wallet::rescan_blockchain(const std::vector<std::string> &args_)
{
message_writer() << tr("Warning: this will lose any information which can not be recovered from the blockchain.");
message_writer() << tr("This includes destination addresses, tx secret keys, tx notes, etc");
- std::string confirm = input_line(tr("Rescan anyway ? (Y/Yes/N/No): "));
+ std::string confirm = input_line(tr("Rescan anyway?"), true);
if(!std::cin.eof())
{
if (!command_line::is_yes(confirm))
@@ -8223,6 +8247,7 @@ bool simple_wallet::address_book(const std::vector<std::string> &args/* = std::v
{
if (tools::wallet2::parse_long_payment_id(args[3], payment_id))
{
+ LONG_PAYMENT_ID_SUPPORT_CHECK();
description_start += 2;
}
else if (tools::wallet2::parse_short_payment_id(args[3], info.payment_id))
@@ -8266,7 +8291,7 @@ bool simple_wallet::address_book(const std::vector<std::string> &args/* = std::v
auto& row = address_book[i];
success_msg_writer() << tr("Index: ") << i;
success_msg_writer() << tr("Address: ") << get_account_address_as_str(m_wallet->nettype(), row.m_is_subaddress, row.m_address);
- success_msg_writer() << tr("Payment ID: ") << row.m_payment_id;
+ success_msg_writer() << tr("Payment ID: ") << row.m_payment_id << " (OBSOLETE)";
success_msg_writer() << tr("Description: ") << row.m_description << "\n";
}
}
@@ -8949,6 +8974,7 @@ int main(int argc, char* argv[])
command_line::add_arg(desc_params, arg_create_address_file);
command_line::add_arg(desc_params, arg_subaddress_lookahead);
command_line::add_arg(desc_params, arg_use_english_language_names);
+ command_line::add_arg(desc_params, arg_long_payment_id_support);
po::positional_options_description positional_options;
positional_options.add(arg_command.name, -1);
diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h
index f364df2ff..c3dc16d96 100644
--- a/src/simplewallet/simplewallet.h
+++ b/src/simplewallet/simplewallet.h
@@ -398,6 +398,8 @@ namespace cryptonote
bool m_auto_refresh_refreshing;
std::atomic<bool> m_in_manual_refresh;
uint32_t m_current_subaddress_account;
+
+ bool m_long_payment_id_support;
// MMS
mms::message_store& get_message_store() const { return m_wallet->get_message_store(); };
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index 8b2735b01..c6b70ee2e 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -1681,7 +1681,25 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
td.m_txid = txid;
td.m_key_image = tx_scan_info[o].ki;
td.m_key_image_known = !m_watch_only && !m_multisig;
- td.m_key_image_requested = false;
+ if (!td.m_key_image_known)
+ {
+ // we might have cold signed, and have a mapping to key images
+ std::unordered_map<crypto::public_key, crypto::key_image>::const_iterator i = m_cold_key_images.find(tx_scan_info[o].in_ephemeral.pub);
+ if (i != m_cold_key_images.end())
+ {
+ td.m_key_image = i->second;
+ td.m_key_image_known = true;
+ }
+ }
+ if (m_watch_only)
+ {
+ // for view wallets, that flag means "we want to request it"
+ td.m_key_image_request = true;
+ }
+ else
+ {
+ td.m_key_image_request = false;
+ }
td.m_key_image_partial = m_multisig;
td.m_amount = amount;
td.m_pk_index = pk_index - 1;
@@ -1703,7 +1721,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
td.m_rct = false;
}
set_unspent(m_transfers.size()-1);
- if (!m_multisig && !m_watch_only)
+ if (td.m_key_image_known)
m_key_images[td.m_key_image] = m_transfers.size()-1;
m_pub_keys[tx_scan_info[o].in_ephemeral.pub] = m_transfers.size()-1;
if (output_tracker_cache)
@@ -5924,6 +5942,61 @@ bool wallet2::sign_tx(unsigned_tx_set &exported_txs, std::vector<wallet2::pendin
txs.back().additional_tx_keys = additional_tx_keys;
}
+ // add key image mapping for these txes
+ const account_keys &keys = get_account().get_keys();
+ hw::device &hwdev = m_account.get_device();
+ for (size_t n = 0; n < exported_txs.txes.size(); ++n)
+ {
+ const cryptonote::transaction &tx = signed_txes.ptx[n].tx;
+
+ crypto::key_derivation derivation;
+ std::vector<crypto::key_derivation> additional_derivations;
+
+ // compute public keys from out secret keys
+ crypto::public_key tx_pub_key;
+ crypto::secret_key_to_public_key(txs[n].tx_key, tx_pub_key);
+ std::vector<crypto::public_key> additional_tx_pub_keys;
+ for (const crypto::secret_key &skey: txs[n].additional_tx_keys)
+ {
+ additional_tx_pub_keys.resize(additional_tx_pub_keys.size() + 1);
+ crypto::secret_key_to_public_key(skey, additional_tx_pub_keys.back());
+ }
+
+ // compute derivations
+ hwdev.set_mode(hw::device::TRANSACTION_PARSE);
+ if (!hwdev.generate_key_derivation(tx_pub_key, keys.m_view_secret_key, derivation))
+ {
+ MWARNING("Failed to generate key derivation from tx pubkey in " << cryptonote::get_transaction_hash(tx) << ", skipping");
+ static_assert(sizeof(derivation) == sizeof(rct::key), "Mismatched sizes of key_derivation and rct::key");
+ memcpy(&derivation, rct::identity().bytes, sizeof(derivation));
+ }
+ for (size_t i = 0; i < additional_tx_pub_keys.size(); ++i)
+ {
+ additional_derivations.push_back({});
+ if (!hwdev.generate_key_derivation(additional_tx_pub_keys[i], keys.m_view_secret_key, additional_derivations.back()))
+ {
+ MWARNING("Failed to generate key derivation from additional tx pubkey in " << cryptonote::get_transaction_hash(tx) << ", skipping");
+ memcpy(&additional_derivations.back(), rct::identity().bytes, sizeof(crypto::key_derivation));
+ }
+ }
+
+ for (size_t i = 0; i < tx.vout.size(); ++i)
+ {
+ if (tx.vout[i].target.type() != typeid(cryptonote::txout_to_key))
+ continue;
+ const cryptonote::txout_to_key &out = boost::get<cryptonote::txout_to_key>(tx.vout[i].target);
+ // if this output is back to this wallet, we can calculate its key image already
+ if (!is_out_to_acc_precomp(m_subaddresses, out.key, derivation, additional_derivations, i, hwdev))
+ continue;
+ crypto::key_image ki;
+ cryptonote::keypair in_ephemeral;
+ if (generate_key_image_helper(keys, m_subaddresses, out.key, tx_pub_key, additional_tx_pub_keys, i, in_ephemeral, ki, hwdev))
+ signed_txes.tx_key_images[out.key] = ki;
+ else
+ MERROR("Failed to calculate key image");
+ }
+ }
+
// add key images
signed_txes.key_images.resize(m_transfers.size());
for (size_t i = 0; i < m_transfers.size(); ++i)
@@ -6086,6 +6159,10 @@ bool wallet2::parse_tx_from_str(const std::string &signed_tx_st, std::vector<too
bool r = import_key_images(signed_txs.key_images);
if (!r) return false;
+ // remember key images for this tx, for when we get those txes from the blockchain
+ for (const auto &e: signed_txs.tx_key_images)
+ m_cold_key_images.insert(e);
+
ptx = signed_txs.ptx;
return true;
@@ -8284,7 +8361,7 @@ void wallet2::light_wallet_get_unspent_outs()
td.m_key_image = unspent_key_image;
td.m_key_image_known = !m_watch_only && !m_multisig;
- td.m_key_image_requested = false;
+ td.m_key_image_request = false;
td.m_key_image_partial = m_multisig;
td.m_amount = o.amount;
td.m_pk_index = 0;
@@ -10894,7 +10971,7 @@ std::pair<size_t, std::vector<std::pair<crypto::key_image, crypto::signature>>>
size_t offset = 0;
if (!all)
{
- while (offset < m_transfers.size() && !m_transfers[offset].m_key_image_requested)
+ while (offset < m_transfers.size() && !m_transfers[offset].m_key_image_request)
++offset;
}
@@ -11054,7 +11131,7 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag
m_transfers[n + offset].m_key_image = signed_key_images[n].first;
m_key_images[m_transfers[n + offset].m_key_image] = n + offset;
m_transfers[n + offset].m_key_image_known = true;
- m_transfers[n + offset].m_key_image_requested = false;
+ m_transfers[n + offset].m_key_image_request = false;
m_transfers[n + offset].m_key_image_partial = false;
}
PERF_TIMER_STOP(import_key_images_B);
@@ -11273,7 +11350,7 @@ bool wallet2::import_key_images(std::vector<crypto::key_image> key_images)
td.m_key_image = key_images[i];
m_key_images[m_transfers[i].m_key_image] = i;
td.m_key_image_known = true;
- td.m_key_image_requested = false;
+ td.m_key_image_request = false;
td.m_key_image_partial = false;
m_pub_keys[m_transfers[i].get_public_key()] = i;
}
@@ -11345,7 +11422,7 @@ std::pair<size_t, std::vector<tools::wallet2::transfer_details>> wallet2::export
std::vector<tools::wallet2::transfer_details> outs;
size_t offset = 0;
- while (offset < m_transfers.size() && m_transfers[offset].m_key_image_known)
+ while (offset < m_transfers.size() && (m_transfers[offset].m_key_image_known && !m_transfers[offset].m_key_image_request))
++offset;
outs.reserve(m_transfers.size() - offset);
@@ -11389,7 +11466,7 @@ size_t wallet2::import_outputs(const std::pair<size_t, std::vector<tools::wallet
const size_t original_size = m_transfers.size();
m_transfers.resize(offset + outputs.second.size());
for (size_t i = 0; i < offset; ++i)
- m_transfers[i].m_key_image_requested = false;
+ m_transfers[i].m_key_image_request = false;
for (size_t i = 0; i < outputs.second.size(); ++i)
{
transfer_details td = outputs.second[i];
@@ -11430,7 +11507,7 @@ process:
THROW_WALLET_EXCEPTION_IF(!r, error::wallet_internal_error, "Failed to generate key image");
expand_subaddresses(td.m_subaddr_index);
td.m_key_image_known = true;
- td.m_key_image_requested = true;
+ td.m_key_image_request = true;
td.m_key_image_partial = false;
THROW_WALLET_EXCEPTION_IF(in_ephemeral.pub != out_key,
error::wallet_internal_error, "key_image generated ephemeral public key not matched with output_key at index " + boost::lexical_cast<std::string>(i + offset));
@@ -11676,7 +11753,7 @@ void wallet2::update_multisig_rescan_info(const std::vector<std::vector<rct::key
m_key_images.erase(td.m_key_image);
td.m_key_image = get_multisig_composite_key_image(n);
td.m_key_image_known = true;
- td.m_key_image_requested = false;
+ td.m_key_image_request = false;
td.m_key_image_partial = false;
td.m_multisig_k = multisig_k[n];
m_key_images[td.m_key_image] = n;
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index 364e31483..ed92aec19 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -267,7 +267,7 @@ namespace tools
uint64_t m_amount;
bool m_rct;
bool m_key_image_known;
- bool m_key_image_requested;
+ bool m_key_image_request; // view wallets: we want to request it; cold wallets: it was requested
size_t m_pk_index;
cryptonote::subaddress_index m_subaddr_index;
bool m_key_image_partial;
@@ -292,7 +292,7 @@ namespace tools
FIELD(m_amount)
FIELD(m_rct)
FIELD(m_key_image_known)
- FIELD(m_key_image_requested)
+ FIELD(m_key_image_request)
FIELD(m_pk_index)
FIELD(m_subaddr_index)
FIELD(m_key_image_partial)
@@ -448,6 +448,7 @@ namespace tools
{
std::vector<pending_tx> ptx;
std::vector<crypto::key_image> key_images;
+ std::unordered_map<crypto::public_key, crypto::key_image> tx_key_images;
};
struct multisig_tx_set
@@ -927,6 +928,9 @@ namespace tools
if(ver < 27)
return;
a & m_device_last_key_image_sync;
+ if(ver < 28)
+ return;
+ a & m_cold_key_images;
}
/*!
@@ -1358,6 +1362,7 @@ namespace tools
uint64_t m_upper_transaction_weight_limit; //TODO: auto-calc this value or request from daemon, now use some fixed value
const std::vector<std::vector<tools::wallet2::multisig_info>> *m_multisig_rescan_info;
const std::vector<std::vector<rct::key>> *m_multisig_rescan_k;
+ std::unordered_map<crypto::public_key, crypto::key_image> m_cold_key_images;
std::atomic<bool> m_run;
@@ -1452,7 +1457,7 @@ namespace tools
std::unique_ptr<wallet_device_callback> m_device_callback;
};
}
-BOOST_CLASS_VERSION(tools::wallet2, 27)
+BOOST_CLASS_VERSION(tools::wallet2, 28)
BOOST_CLASS_VERSION(tools::wallet2::transfer_details, 11)
BOOST_CLASS_VERSION(tools::wallet2::multisig_info, 1)
BOOST_CLASS_VERSION(tools::wallet2::multisig_info::LR, 0)
@@ -1464,7 +1469,7 @@ BOOST_CLASS_VERSION(tools::wallet2::confirmed_transfer_details, 6)
BOOST_CLASS_VERSION(tools::wallet2::address_book_row, 17)
BOOST_CLASS_VERSION(tools::wallet2::reserve_proof_entry, 0)
BOOST_CLASS_VERSION(tools::wallet2::unsigned_tx_set, 0)
-BOOST_CLASS_VERSION(tools::wallet2::signed_tx_set, 0)
+BOOST_CLASS_VERSION(tools::wallet2::signed_tx_set, 1)
BOOST_CLASS_VERSION(tools::wallet2::tx_construction_data, 3)
BOOST_CLASS_VERSION(tools::wallet2::pending_tx, 3)
BOOST_CLASS_VERSION(tools::wallet2::multisig_sig, 0)
@@ -1513,7 +1518,7 @@ namespace boost
}
if (ver < 10)
{
- x.m_key_image_requested = false;
+ x.m_key_image_request = false;
}
}
@@ -1601,7 +1606,7 @@ namespace boost
initialize_transfer_details(a, x, ver);
return;
}
- a & x.m_key_image_requested;
+ a & x.m_key_image_request;
if (ver < 11)
return;
a & x.m_uses;
@@ -1801,6 +1806,9 @@ namespace boost
{
a & x.ptx;
a & x.key_images;
+ if (ver < 1)
+ return;
+ a & x.tx_key_images;
}
template <class Archive>