aboutsummaryrefslogtreecommitdiff
path: root/src/simplewallet
diff options
context:
space:
mode:
Diffstat (limited to 'src/simplewallet')
-rw-r--r--src/simplewallet/simplewallet.cpp352
-rw-r--r--src/simplewallet/simplewallet.h2
2 files changed, 225 insertions, 129 deletions
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index 09b965e74..20ee0468f 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -86,9 +86,9 @@ typedef cryptonote::simple_wallet sw;
#define EXTENDED_LOGS_FILE "wallet_details.log"
-#define DEFAULT_MIX 6
+#define DEFAULT_MIX 10
-#define MIN_RING_SIZE 7 // Used to inform user about min ring size -- does not track actual protocol
+#define MIN_RING_SIZE 11 // Used to inform user about min ring size -- does not track actual protocol
#define LOCK_IDLE_SCOPE() \
bool auto_refresh_enabled = m_auto_refresh_enabled.load(std::memory_order_relaxed); \
@@ -129,8 +129,6 @@ namespace
const command_line::arg_descriptor<bool> arg_restore_deterministic_wallet = {"restore-deterministic-wallet", sw::tr("Recover wallet using Electrum-style mnemonic seed"), false};
const command_line::arg_descriptor<bool> arg_restore_multisig_wallet = {"restore-multisig-wallet", sw::tr("Recover multisig wallet using Electrum-style mnemonic seed"), false};
const command_line::arg_descriptor<bool> arg_non_deterministic = {"non-deterministic", sw::tr("Generate non-deterministic view and spend keys"), false};
- const command_line::arg_descriptor<bool> arg_trusted_daemon = {"trusted-daemon", sw::tr("Enable commands which rely on a trusted daemon"), false};
- const command_line::arg_descriptor<bool> arg_untrusted_daemon = {"untrusted-daemon", sw::tr("Disable commands which rely on a trusted daemon"), false};
const command_line::arg_descriptor<bool> 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<uint64_t> arg_restore_height = {"restore-height", sw::tr("Restore from specific blockchain height"), 0};
const command_line::arg_descriptor<bool> arg_do_not_relay = {"do-not-relay", sw::tr("The newly created transaction will not be relayed to the monero network"), false};
@@ -447,7 +445,7 @@ namespace
LOG_ERROR("RPC error: " << e.to_string());
fail_msg_writer() << tr("RPC error: ") << e.what();
}
- catch (const tools::error::get_random_outs_error &e)
+ catch (const tools::error::get_outs_error &e)
{
fail_msg_writer() << tr("failed to get random outputs to mix: ") << e.what();
}
@@ -581,6 +579,18 @@ bool parse_priority(const std::string& arg, uint32_t& priority)
return false;
}
+std::string join_priority_strings(const char *delimiter)
+{
+ std::string s;
+ for (size_t n = 0; n < allowed_priority_strings.size(); ++n)
+ {
+ if (!s.empty())
+ s += delimiter;
+ s += allowed_priority_strings[n];
+ }
+ return s;
+}
+
std::string simple_wallet::get_commands_str()
{
std::stringstream ss;
@@ -819,21 +829,24 @@ bool simple_wallet::print_fee_info(const std::vector<std::string> &args/* = std:
fail_msg_writer() << tr("Cannot connect to daemon");
return true;
}
- const uint64_t per_kb_fee = m_wallet->get_per_kb_fee();
- const uint64_t typical_size_kb = 13;
- message_writer() << (boost::format(tr("Current fee is %s %s per kB")) % print_money(per_kb_fee) % cryptonote::get_unit(cryptonote::get_default_decimal_point())).str();
+ const bool per_byte = m_wallet->use_fork_rules(HF_VERSION_PER_BYTE_FEE);
+ const uint64_t base_fee = m_wallet->get_base_fee();
+ const char *base = per_byte ? "byte" : "kB";
+ const uint64_t typical_size = per_byte ? 2500 : 13;
+ const uint64_t size_granularity = per_byte ? 1 : 1024;
+ message_writer() << (boost::format(tr("Current fee is %s %s per %s")) % print_money(base_fee) % cryptonote::get_unit(cryptonote::get_default_decimal_point()) % base).str();
std::vector<uint64_t> fees;
for (uint32_t priority = 1; priority <= 4; ++priority)
{
uint64_t mult = m_wallet->get_fee_multiplier(priority);
- fees.push_back(per_kb_fee * typical_size_kb * mult);
+ fees.push_back(base_fee * typical_size * mult);
}
std::vector<std::pair<uint64_t, uint64_t>> blocks;
try
{
- uint64_t base_size = typical_size_kb * 1024;
- blocks = m_wallet->estimate_backlog(base_size, base_size + 1023, fees);
+ uint64_t base_size = typical_size * size_granularity;
+ blocks = m_wallet->estimate_backlog(base_size, base_size + size_granularity - 1, fees);
}
catch (const std::exception &e)
{
@@ -1137,7 +1150,7 @@ bool simple_wallet::import_multisig(const std::vector<std::string> &args)
fail_msg_writer() << tr("Failed to import multisig info: ") << e.what();
return true;
}
- if (is_daemon_trusted())
+ if (m_wallet->is_trusted_daemon())
{
try
{
@@ -1291,7 +1304,7 @@ bool simple_wallet::submit_multisig(const std::vector<std::string> &args)
}
catch (const std::exception &e)
{
- handle_transfer_exception(std::current_exception(), is_daemon_trusted());
+ handle_transfer_exception(std::current_exception(), m_wallet->is_trusted_daemon());
}
catch (...)
{
@@ -1614,23 +1627,23 @@ bool simple_wallet::set_ring(const std::vector<std::string> &args)
bool simple_wallet::blackball(const std::vector<std::string> &args)
{
- crypto::public_key output;
+ uint64_t amount = std::numeric_limits<uint64_t>::max(), offset, num_offsets;
if (args.size() == 0)
{
- fail_msg_writer() << tr("usage: blackball <output_public_key> | <filename> [add]");
+ fail_msg_writer() << tr("usage: blackball <amount>/<offset> | <filename> [add]");
return true;
}
try
{
- if (epee::string_tools::hex_to_pod(args[0], output))
+ if (sscanf(args[0].c_str(), "%" PRIu64 "/%" PRIu64, &amount, &offset) == 2)
{
- m_wallet->blackball_output(output);
+ m_wallet->blackball_output(std::make_pair(amount, offset));
}
else if (epee::file_io_utils::is_file_exist(args[0]))
{
- std::vector<crypto::public_key> outputs;
- char str[65];
+ std::vector<std::pair<uint64_t, uint64_t>> outputs;
+ char str[256];
std::unique_ptr<FILE, tools::close_file> f(fopen(args[0].c_str(), "r"));
if (f)
@@ -1644,10 +1657,27 @@ bool simple_wallet::blackball(const std::vector<std::string> &args)
str[len - 1] = 0;
if (!str[0])
continue;
- outputs.push_back(crypto::public_key());
- if (!epee::string_tools::hex_to_pod(str, outputs.back()))
+ if (sscanf(str, "@%" PRIu64, &amount) == 1)
+ {
+ continue;
+ }
+ if (amount == std::numeric_limits<uint64_t>::max())
{
- fail_msg_writer() << tr("Invalid public key: ") << str;
+ fail_msg_writer() << tr("First line is not an amount");
+ return true;
+ }
+ if (sscanf(str, "%" PRIu64 "*%" PRIu64, &offset, &num_offsets) == 2 && num_offsets <= std::numeric_limits<uint64_t>::max() - offset)
+ {
+ while (num_offsets--)
+ outputs.push_back(std::make_pair(amount, offset++));
+ }
+ else if (sscanf(str, "%" PRIu64, &offset) == 1)
+ {
+ outputs.push_back(std::make_pair(amount, offset));
+ }
+ else
+ {
+ fail_msg_writer() << tr("Invalid output: ") << str;
return true;
}
}
@@ -1672,7 +1702,7 @@ bool simple_wallet::blackball(const std::vector<std::string> &args)
}
else
{
- fail_msg_writer() << tr("Invalid public key, and file doesn't exist");
+ fail_msg_writer() << tr("Invalid output key, and file doesn't exist");
return true;
}
}
@@ -1686,16 +1716,16 @@ bool simple_wallet::blackball(const std::vector<std::string> &args)
bool simple_wallet::unblackball(const std::vector<std::string> &args)
{
- crypto::public_key output;
+ std::pair<uint64_t, uint64_t> output;
if (args.size() != 1)
{
- fail_msg_writer() << tr("usage: unblackball <output_public_key>");
+ fail_msg_writer() << tr("usage: unblackball <amount>/<offset>");
return true;
}
- if (!epee::string_tools::hex_to_pod(args[0], output))
+ if (sscanf(args[0].c_str(), "%" PRIu64 "/%" PRIu64, &output.first, &output.second) != 2)
{
- fail_msg_writer() << tr("Invalid public key");
+ fail_msg_writer() << tr("Invalid output");
return true;
}
@@ -1713,25 +1743,25 @@ bool simple_wallet::unblackball(const std::vector<std::string> &args)
bool simple_wallet::blackballed(const std::vector<std::string> &args)
{
- crypto::public_key output;
+ std::pair<uint64_t, uint64_t> output;
if (args.size() != 1)
{
- fail_msg_writer() << tr("usage: blackballed <output_public_key>");
+ fail_msg_writer() << tr("usage: blackballed <amount>/<offset>");
return true;
}
- if (!epee::string_tools::hex_to_pod(args[0], output))
+ if (sscanf(args[0].c_str(), "%" PRIu64 "/%" PRIu64, &output.first, &output.second) != 2)
{
- fail_msg_writer() << tr("Invalid public key");
+ fail_msg_writer() << tr("Invalid output");
return true;
}
try
{
if (m_wallet->is_output_blackballed(output))
- message_writer() << tr("Blackballed: ") << output;
+ message_writer() << tr("Blackballed: ") << output.first << "/" << output.second;
else
- message_writer() << tr("not blackballed: ") << output;
+ message_writer() << tr("not blackballed: ") << output.first << "/" << output.second;
}
catch (const std::exception &e)
{
@@ -1829,6 +1859,8 @@ bool simple_wallet::set_default_ring_size(const std::vector<std::string> &args/*
if (ring_size != 0 && ring_size != DEFAULT_MIX+1)
message_writer() << tr("WARNING: this is a non default ring size, which may harm your privacy. Default is recommended.");
+ else if (ring_size == DEFAULT_MIX)
+ message_writer() << tr("WARNING: from v8, ring size will be fixed and this setting will be ignored.");
const auto pwd_container = get_and_verify_password();
if (pwd_container)
@@ -1852,12 +1884,12 @@ bool simple_wallet::set_default_ring_size(const std::vector<std::string> &args/*
bool simple_wallet::set_default_priority(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
{
- int priority = 0;
+ uint32_t priority = 0;
try
{
if (strchr(args[1].c_str(), '-'))
{
- fail_msg_writer() << tr("priority must be 0, 1, 2, 3, or 4 ");
+ fail_msg_writer() << tr("priority must be either 0, 1, 2, 3, or 4, or one of: ") << join_priority_strings(", ");
return true;
}
if (args[1] == "0")
@@ -1866,11 +1898,23 @@ bool simple_wallet::set_default_priority(const std::vector<std::string> &args/*
}
else
{
- priority = boost::lexical_cast<int>(args[1]);
- if (priority < 1 || priority > 4)
+ bool found = false;
+ for (size_t n = 0; n < allowed_priority_strings.size(); ++n)
{
- fail_msg_writer() << tr("priority must be 0, 1, 2, 3, or 4");
- return true;
+ if (allowed_priority_strings[n] == args[1])
+ {
+ found = true;
+ priority = n;
+ }
+ }
+ if (!found)
+ {
+ priority = boost::lexical_cast<int>(args[1]);
+ if (priority < 1 || priority > 4)
+ {
+ fail_msg_writer() << tr("priority must be either 0, 1, 2, 3, or 4, or one of: ") << join_priority_strings(", ");
+ return true;
+ }
}
}
@@ -1884,7 +1928,7 @@ bool simple_wallet::set_default_priority(const std::vector<std::string> &args/*
}
catch(const boost::bad_lexical_cast &)
{
- fail_msg_writer() << tr("priority must be 0, 1, 2, 3, or 4");
+ fail_msg_writer() << tr("priority must be either 0, 1, 2, 3, or 4, or one of: ") << join_priority_strings(", ");
return true;
}
catch(...)
@@ -2244,15 +2288,15 @@ simple_wallet::simple_wallet()
tr("Show the blockchain height."));
m_cmd_binder.set_handler("transfer_original",
boost::bind(&simple_wallet::transfer, this, _1),
- tr("transfer_original [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> <amount> [<payment_id>]"),
- tr("Transfer <amount> to <address> using an older transaction building algorithm. If the parameter \"index=<N1>[,<N2>,...]\" is specified, the wallet uses outputs received by addresses of those indices. If omitted, the wallet randomly chooses address indices to be used. In any case, it tries its best not to combine outputs across multiple addresses. <priority> is the priority of the transaction. The higher the priority, the higher the transaction fee. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command \"set priority\") is used. <ring_size> is the number of inputs to include for untraceability. Multiple payments can be made at once by adding <address_2> <amount_2> etcetera (before the payment ID, if it's included)"));
+ tr("transfer_original [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] (<URI> | <address> <amount>) [<payment_id>]"),
+ tr("Transfer <amount> to <address> using an older transaction building algorithm. If the parameter \"index=<N1>[,<N2>,...]\" is specified, the wallet uses outputs received by addresses of those indices. If omitted, the wallet randomly chooses address indices to be used. In any case, it tries its best not to combine outputs across multiple addresses. <priority> is the priority of the transaction. The higher the priority, the higher the transaction fee. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command \"set priority\") is used. <ring_size> is the number of inputs to include for untraceability. Multiple payments can be made at once by adding URI_2 or <address_2> <amount_2> etcetera (before the payment ID, if it's included)"));
m_cmd_binder.set_handler("transfer", boost::bind(&simple_wallet::transfer_new, this, _1),
- tr("transfer [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> <amount> [<payment_id>]"),
- tr("Transfer <amount> to <address>. If the parameter \"index=<N1>[,<N2>,...]\" is specified, the wallet uses outputs received by addresses of those indices. If omitted, the wallet randomly chooses address indices to be used. In any case, it tries its best not to combine outputs across multiple addresses. <priority> is the priority of the transaction. The higher the priority, the higher the transaction fee. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command \"set priority\") is used. <ring_size> is the number of inputs to include for untraceability. Multiple payments can be made at once by adding <address_2> <amount_2> etcetera (before the payment ID, if it's included)"));
+ tr("transfer [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] (<URI> | <address> <amount>) [<payment_id>]"),
+ tr("Transfer <amount> to <address>. If the parameter \"index=<N1>[,<N2>,...]\" is specified, the wallet uses outputs received by addresses of those indices. If omitted, the wallet randomly chooses address indices to be used. In any case, it tries its best not to combine outputs across multiple addresses. <priority> is the priority of the transaction. The higher the priority, the higher the transaction fee. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command \"set priority\") is used. <ring_size> is the number of inputs to include for untraceability. Multiple payments can be made at once by adding URI_2 or <address_2> <amount_2> etcetera (before the payment ID, if it's included)"));
m_cmd_binder.set_handler("locked_transfer",
boost::bind(&simple_wallet::locked_transfer, this, _1),
- tr("locked_transfer [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <addr> <amount> <lockblocks> [<payment_id>]"),
- tr("Transfer <amount> to <address> and lock it for <lockblocks> (max. 1000000). If the parameter \"index=<N1>[,<N2>,...]\" is specified, the wallet uses outputs received by addresses of those indices. If omitted, the wallet randomly chooses address indices to be used. In any case, it tries its best not to combine outputs across multiple addresses. <priority> is the priority of the transaction. The higher the priority, the higher the transaction fee. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command \"set priority\") is used. <ring_size> is the number of inputs to include for untraceability. Multiple payments can be made at once by adding <address_2> <amount_2> etcetera (before the payment ID, if it's included)"));
+ tr("locked_transfer [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] (<URI> | <addr> <amount>) <lockblocks> [<payment_id>]"),
+ tr("Transfer <amount> to <address> and lock it for <lockblocks> (max. 1000000). If the parameter \"index=<N1>[,<N2>,...]\" is specified, the wallet uses outputs received by addresses of those indices. If omitted, the wallet randomly chooses address indices to be used. In any case, it tries its best not to combine outputs across multiple addresses. <priority> is the priority of the transaction. The higher the priority, the higher the transaction fee. Valid values in priority order (from lowest to highest) are: unimportant, normal, elevated, priority. If omitted, the default value (see the command \"set priority\") is used. <ring_size> is the number of inputs to include for untraceability. Multiple payments can be made at once by adding URI_2 or <address_2> <amount_2> etcetera (before the payment ID, if it's included)"));
m_cmd_binder.set_handler("locked_sweep_all",
boost::bind(&simple_wallet::locked_sweep_all, this, _1),
tr("locked_sweep_all [index=<N1>[,<N2>,...]] [<priority>] [<ring_size>] <address> <lockblocks> [<payment_id>]"),
@@ -2532,15 +2576,15 @@ simple_wallet::simple_wallet()
tr("Save known rings to the shared rings database"));
m_cmd_binder.set_handler("blackball",
boost::bind(&simple_wallet::blackball, this, _1),
- tr("blackball <output public key> | <filename> [add]"),
+ tr("blackball <amount>/<offset> | <filename> [add]"),
tr("Blackball output(s) so they never get selected as fake outputs in a ring"));
m_cmd_binder.set_handler("unblackball",
boost::bind(&simple_wallet::unblackball, this, _1),
- tr("unblackball <output public key>"),
+ tr("unblackball <amount>/<offset>"),
tr("Unblackballs an output so it may get selected as a fake output in a ring"));
m_cmd_binder.set_handler("blackballed",
boost::bind(&simple_wallet::blackballed, this, _1),
- tr("blackballed <output public key>"),
+ tr("blackballed <amount>/<offset>"),
tr("Checks whether an output is blackballed"));
m_cmd_binder.set_handler("version",
boost::bind(&simple_wallet::version, this, _1),
@@ -2559,6 +2603,10 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
std::string seed_language = m_wallet->get_seed_language();
if (m_use_english_language_names)
seed_language = crypto::ElectrumWords::get_english_name_for(seed_language);
+ std::string priority_string = "invalid";
+ uint32_t priority = m_wallet->get_default_priority();
+ if (priority < allowed_priority_strings.size())
+ priority_string = allowed_priority_strings[priority];
success_msg_writer() << "seed = " << seed_language;
success_msg_writer() << "always-confirm-transfers = " << m_wallet->always_confirm_transfers();
success_msg_writer() << "print-ring-members = " << m_wallet->print_ring_members();
@@ -2566,7 +2614,7 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
success_msg_writer() << "default-ring-size = " << (m_wallet->default_mixin() ? m_wallet->default_mixin() + 1 : 0);
success_msg_writer() << "auto-refresh = " << m_wallet->auto_refresh();
success_msg_writer() << "refresh-type = " << get_refresh_type_name(m_wallet->get_refresh_type());
- success_msg_writer() << "priority = " << m_wallet->get_default_priority();
+ success_msg_writer() << "priority = " << priority<< " (" << priority_string << ")";
success_msg_writer() << "confirm-missing-payment-id = " << m_wallet->confirm_missing_payment_id();
success_msg_writer() << "ask-password = " << m_wallet->ask_password();
success_msg_writer() << "unit = " << cryptonote::get_unit(cryptonote::get_default_decimal_point());
@@ -2622,7 +2670,7 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
CHECK_SIMPLE_VARIABLE("default-ring-size", set_default_ring_size, tr("integer >= ") << MIN_RING_SIZE);
CHECK_SIMPLE_VARIABLE("auto-refresh", set_auto_refresh, tr("0 or 1"));
CHECK_SIMPLE_VARIABLE("refresh-type", set_refresh_type, tr("full (slowest, no assumptions); optimize-coinbase (fast, assumes the whole coinbase is paid to a single address); no-coinbase (fastest, assumes we receive no coinbase transaction), default (same as optimize-coinbase)"));
- CHECK_SIMPLE_VARIABLE("priority", set_default_priority, tr("0, 1, 2, 3, or 4"));
+ CHECK_SIMPLE_VARIABLE("priority", set_default_priority, tr("0, 1, 2, 3, or 4, or one of ") << join_priority_strings(", "));
CHECK_SIMPLE_VARIABLE("confirm-missing-payment-id", set_confirm_missing_payment_id, tr("0 or 1"));
CHECK_SIMPLE_VARIABLE("ask-password", set_ask_password, tr("0 or 1"));
CHECK_SIMPLE_VARIABLE("unit", set_unit, tr("monero, millinero, micronero, nanonero, piconero"));
@@ -3363,22 +3411,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
return false;
}
- // set --trusted-daemon if local and not overridden
- if (!m_trusted_daemon)
- {
- try
- {
- m_trusted_daemon = false;
- if (tools::is_local_address(m_wallet->get_daemon_address()))
- {
- MINFO(tr("Daemon is local, assuming trusted"));
- m_trusted_daemon = true;
- }
- }
- catch (const std::exception &e) { }
- }
-
- if (!is_daemon_trusted())
+ if (!m_wallet->is_trusted_daemon())
message_writer() << (boost::format(tr("Warning: using an untrusted daemon at %s, privacy will be lessened")) % m_wallet->get_daemon_address()).str();
if (m_wallet->get_ring_database().empty())
@@ -3412,10 +3445,6 @@ bool simple_wallet::handle_command_line(const boost::program_options::variables_
m_restore_deterministic_wallet = command_line::get_arg(vm, arg_restore_deterministic_wallet);
m_restore_multisig_wallet = command_line::get_arg(vm, arg_restore_multisig_wallet);
m_non_deterministic = command_line::get_arg(vm, arg_non_deterministic);
- if (!command_line::is_arg_defaulted(vm, arg_trusted_daemon) || !command_line::is_arg_defaulted(vm, arg_untrusted_daemon))
- m_trusted_daemon = command_line::get_arg(vm, arg_trusted_daemon) && !command_line::get_arg(vm, arg_untrusted_daemon);
- if (!command_line::is_arg_defaulted(vm, arg_trusted_daemon) && !command_line::is_arg_defaulted(vm, arg_untrusted_daemon))
- message_writer() << tr("--trusted-daemon and --untrusted-daemon are both seen, assuming untrusted");
m_allow_mismatched_daemon_version = command_line::get_arg(vm, arg_allow_mismatched_daemon_version);
m_restore_height = command_line::get_arg(vm, arg_restore_height);
m_do_not_relay = command_line::get_arg(vm, arg_do_not_relay);
@@ -3928,7 +3957,7 @@ bool simple_wallet::save_watch_only(const std::vector<std::string> &args/* = std
//----------------------------------------------------------------------------------------------------
bool simple_wallet::start_mining(const std::vector<std::string>& args)
{
- if (!is_daemon_trusted())
+ if (!m_wallet->is_trusted_daemon())
{
fail_msg_writer() << tr("this command requires a trusted daemon. Enable with --trusted-daemon");
return true;
@@ -4041,29 +4070,29 @@ bool simple_wallet::set_daemon(const std::vector<std::string>& args)
if (args.size() == 2)
{
if (args[1] == "trusted")
- m_trusted_daemon = true;
+ m_wallet->set_trusted_daemon(true);
else if (args[1] == "untrusted")
- m_trusted_daemon = false;
+ m_wallet->set_trusted_daemon(false);
else
{
fail_msg_writer() << tr("Expected trusted or untrusted, got ") << args[1] << ": assuming untrusted";
- m_trusted_daemon = false;
+ m_wallet->set_trusted_daemon(false);
}
}
else
{
- m_trusted_daemon = false;
+ m_wallet->set_trusted_daemon(false);
try
{
if (tools::is_local_address(m_wallet->get_daemon_address()))
{
MINFO(tr("Daemon is local, assuming trusted"));
- m_trusted_daemon = true;
+ m_wallet->set_trusted_daemon(true);
}
}
catch (const std::exception &e) { }
}
- success_msg_writer() << boost::format("Daemon set to %s, %s") % daemon_url % (*m_trusted_daemon ? tr("trusted") : tr("untrusted"));
+ success_msg_writer() << boost::format("Daemon set to %s, %s") % daemon_url % (m_wallet->is_trusted_daemon() ? tr("trusted") : tr("untrusted"));
} else {
fail_msg_writer() << tr("This does not seem to be a valid daemon URL.");
}
@@ -4199,7 +4228,7 @@ bool simple_wallet::refresh_main(uint64_t start_height, bool reset, bool is_init
{
m_in_manual_refresh.store(true, std::memory_order_relaxed);
epee::misc_utils::auto_scope_leave_caller scope_exit_handler = epee::misc_utils::create_scope_leave_handler([&](){m_in_manual_refresh.store(false, std::memory_order_relaxed);});
- m_wallet->refresh(is_daemon_trusted(), start_height, fetched_blocks);
+ m_wallet->refresh(m_wallet->is_trusted_daemon(), start_height, fetched_blocks);
ok = true;
// Clear line "Height xxx of xxx"
std::cout << "\r \r";
@@ -4490,7 +4519,7 @@ bool simple_wallet::show_blockchain_height(const std::vector<std::string>& args)
//----------------------------------------------------------------------------------------------------
bool simple_wallet::rescan_spent(const std::vector<std::string> &args)
{
- if (!is_daemon_trusted())
+ if (!m_wallet->is_trusted_daemon())
{
fail_msg_writer() << tr("this command requires a trusted daemon. Enable with --trusted-daemon");
return true;
@@ -4698,8 +4727,13 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
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;
}
+ if (adjusted_fake_outs_count < fake_outs_count)
+ {
+ fail_msg_writer() << (boost::format(tr("ring size %u is too large, maximum is %u")) % (fake_outs_count+1) % (adjusted_fake_outs_count+1)).str();
+ return true;
+ }
- const size_t min_args = (transfer_type == TransferLocked) ? 3 : 2;
+ const size_t min_args = (transfer_type == TransferLocked) ? 2 : 1;
if(local_args.size() < min_args)
{
fail_msg_writer() << tr("wrong number of arguments");
@@ -4708,39 +4742,38 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
std::vector<uint8_t> extra;
bool payment_id_seen = false;
- bool expect_even = (transfer_type == TransferLocked);
- if ((expect_even ? 0 : 1) == local_args.size() % 2)
+ if (!local_args.empty())
{
std::string payment_id_str = local_args.back();
- local_args.pop_back();
-
crypto::hash payment_id;
- bool r = tools::wallet2::parse_long_payment_id(payment_id_str, payment_id);
- if(r)
+ bool r = true;
+ if (tools::wallet2::parse_long_payment_id(payment_id_str, payment_id))
{
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);
+ local_args.pop_back();
+ payment_id_seen = true;
+ message_writer() << tr("Unencrypted payment IDs are bad for privacy: ask the recipient to use subaddresses instead");
}
else
{
crypto::hash8 payment_id8;
- r = tools::wallet2::parse_short_payment_id(payment_id_str, payment_id8);
- if(r)
+ if (tools::wallet2::parse_short_payment_id(payment_id_str, payment_id8))
{
std::string extra_nonce;
set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, payment_id8);
r = add_extra_nonce_to_tx_extra(extra, extra_nonce);
+ local_args.pop_back();
+ payment_id_seen = true;
}
}
if(!r)
{
- fail_msg_writer() << tr("payment id has invalid format, expected 16 or 64 character hex string: ") << payment_id_str;
+ fail_msg_writer() << tr("payment id failed to encode");
return true;
}
- payment_id_seen = true;
- message_writer() << tr("Unencrypted payment IDs are bad for privacy: ask the recipient to use subaddresses instead");
}
uint64_t locked_blocks = 0;
@@ -4765,11 +4798,54 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
vector<cryptonote::tx_destination_entry> dsts;
size_t num_subaddresses = 0;
- for (size_t i = 0; i < local_args.size(); i += 2)
+ for (size_t i = 0; i < local_args.size(); )
{
- cryptonote::address_parse_info info;
cryptonote::tx_destination_entry de;
- if (!cryptonote::get_account_address_from_str_or_url(info, m_wallet->nettype(), local_args[i], oa_prompter))
+ cryptonote::address_parse_info info;
+ bool r = true;
+
+ // check for a URI
+ std::string address_uri, payment_id_uri, tx_description, recipient_name, error;
+ std::vector<std::string> unknown_parameters;
+ uint64_t amount = 0;
+ bool has_uri = m_wallet->parse_uri(local_args[i], address_uri, payment_id_uri, amount, tx_description, recipient_name, unknown_parameters, error);
+ if (has_uri)
+ {
+ r = cryptonote::get_account_address_from_str_or_url(info, m_wallet->nettype(), address_uri, oa_prompter);
+ if (payment_id_uri.size() == 16)
+ {
+ if (!tools::wallet2::parse_short_payment_id(payment_id_uri, info.payment_id))
+ {
+ fail_msg_writer() << tr("failed to parse short payment ID from URI");
+ return true;
+ }
+ info.has_payment_id = true;
+ }
+ de.amount = amount;
+ ++i;
+ }
+ else if (i + 1 < local_args.size())
+ {
+ r = cryptonote::get_account_address_from_str_or_url(info, m_wallet->nettype(), local_args[i], oa_prompter);
+ bool ok = cryptonote::parse_amount(de.amount, local_args[i + 1]);
+ if(!ok || 0 == de.amount)
+ {
+ fail_msg_writer() << tr("amount is wrong: ") << local_args[i] << ' ' << local_args[i + 1] <<
+ ", " << tr("expected number from 0 to ") << print_money(std::numeric_limits<uint64_t>::max());
+ return true;
+ }
+ i += 2;
+ }
+ else
+ {
+ if (boost::starts_with(local_args[i], "monero:"))
+ fail_msg_writer() << tr("Invalid last argument: ") << local_args.back() << ": " << error;
+ else
+ fail_msg_writer() << tr("Invalid last argument: ") << local_args.back();
+ return true;
+ }
+
+ if (!r)
{
fail_msg_writer() << tr("failed to parse address");
return true;
@@ -4778,16 +4854,30 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
de.is_subaddress = info.is_subaddress;
num_subaddresses += info.is_subaddress;
- if (info.has_payment_id)
+ if (info.has_payment_id || !payment_id_uri.empty())
{
if (payment_id_seen)
{
- fail_msg_writer() << tr("a single transaction cannot use more than one payment id: ") << local_args[i];
+ fail_msg_writer() << tr("a single transaction cannot use more than one payment id");
return true;
}
+ crypto::hash payment_id;
std::string extra_nonce;
- set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, info.payment_id);
+ if (info.has_payment_id)
+ {
+ set_encrypted_payment_id_to_tx_extra_nonce(extra_nonce, info.payment_id);
+ }
+ else if (tools::wallet2::parse_payment_id(payment_id_uri, payment_id))
+ {
+ 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");
+ }
+ else
+ {
+ fail_msg_writer() << tr("failed to parse payment id, though it was detected");
+ return true;
+ }
bool r = add_extra_nonce_to_tx_extra(extra, extra_nonce);
if(!r)
{
@@ -4797,14 +4887,6 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
payment_id_seen = true;
}
- bool ok = cryptonote::parse_amount(de.amount, local_args[i + 1]);
- if(!ok || 0 == de.amount)
- {
- fail_msg_writer() << tr("amount is wrong: ") << local_args[i] << ' ' << local_args[i + 1] <<
- ", " << tr("expected number from 0 to ") << print_money(std::numeric_limits<uint64_t>::max());
- return true;
- }
-
dsts.push_back(de);
}
@@ -4838,17 +4920,14 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
return true;
}
unlock_block = bc_height + locked_blocks;
- ptx_vector = m_wallet->create_transactions_2(dsts, fake_outs_count, unlock_block /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices, is_daemon_trusted());
- break;
- case TransferNew:
- ptx_vector = m_wallet->create_transactions_2(dsts, fake_outs_count, 0 /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices, is_daemon_trusted());
+ ptx_vector = m_wallet->create_transactions_2(dsts, fake_outs_count, unlock_block /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices);
break;
default:
- LOG_ERROR("Unknown transfer method, using original");
+ LOG_ERROR("Unknown transfer method, using default");
/* FALLTHRU */
- case TransferOriginal:
- ptx_vector = m_wallet->create_transactions(dsts, fake_outs_count, 0 /* unlock_time */, priority, extra, is_daemon_trusted());
- break;
+ case TransferNew:
+ ptx_vector = m_wallet->create_transactions_2(dsts, fake_outs_count, 0 /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices);
+ break;
}
if (ptx_vector.empty())
@@ -5023,7 +5102,7 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
}
catch (const std::exception &e)
{
- handle_transfer_exception(std::current_exception(), is_daemon_trusted());
+ handle_transfer_exception(std::current_exception(), m_wallet->is_trusted_daemon());
}
catch (...)
{
@@ -5065,7 +5144,7 @@ bool simple_wallet::sweep_unmixable(const std::vector<std::string> &args_)
try
{
// figure out what tx will be necessary
- auto ptx_vector = m_wallet->create_unmixable_sweep_transactions(is_daemon_trusted());
+ auto ptx_vector = m_wallet->create_unmixable_sweep_transactions();
if (ptx_vector.empty())
{
@@ -5144,13 +5223,13 @@ bool simple_wallet::sweep_unmixable(const std::vector<std::string> &args_)
{
try
{
- m_wallet->discard_unmixable_outputs(is_daemon_trusted());
+ m_wallet->discard_unmixable_outputs();
} catch (...) {}
}
}
catch (const std::exception &e)
{
- handle_transfer_exception(std::current_exception(), is_daemon_trusted());
+ handle_transfer_exception(std::current_exception(), m_wallet->is_trusted_daemon());
}
catch (...)
{
@@ -5222,6 +5301,11 @@ bool simple_wallet::sweep_main(uint64_t below, bool locked, const std::vector<st
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;
}
+ if (adjusted_fake_outs_count < fake_outs_count)
+ {
+ fail_msg_writer() << (boost::format(tr("ring size %u is too large, maximum is %u")) % (fake_outs_count+1) % (adjusted_fake_outs_count+1)).str();
+ return true;
+ }
uint64_t unlock_block = 0;
if (locked) {
@@ -5342,7 +5426,7 @@ bool simple_wallet::sweep_main(uint64_t below, bool locked, const std::vector<st
try
{
// figure out what tx will be necessary
- auto ptx_vector = m_wallet->create_transactions_all(below, info.address, info.is_subaddress, fake_outs_count, unlock_block /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices, is_daemon_trusted());
+ auto ptx_vector = m_wallet->create_transactions_all(below, info.address, info.is_subaddress, fake_outs_count, unlock_block /* unlock_time */, priority, extra, m_current_subaddress_account, subaddr_indices);
if (ptx_vector.empty())
{
@@ -5426,7 +5510,7 @@ bool simple_wallet::sweep_main(uint64_t below, bool locked, const std::vector<st
}
catch (const std::exception& e)
{
- handle_transfer_exception(std::current_exception(), is_daemon_trusted());
+ handle_transfer_exception(std::current_exception(), m_wallet->is_trusted_daemon());
}
catch (...)
{
@@ -5460,12 +5544,28 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_)
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;
+ }
+ if (adjusted_fake_outs_count < fake_outs_count)
+ {
+ fail_msg_writer() << (boost::format(tr("ring size %u is too large, maximum is %u")) % (fake_outs_count+1) % (adjusted_fake_outs_count+1)).str();
+ return true;
+ }
std::vector<uint8_t> extra;
bool payment_id_seen = false;
@@ -5555,7 +5655,7 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_)
try
{
// figure out what tx will be necessary
- auto ptx_vector = m_wallet->create_transactions_single(ki, info.address, info.is_subaddress, fake_outs_count, 0 /* unlock_time */, priority, extra, is_daemon_trusted());
+ auto ptx_vector = m_wallet->create_transactions_single(ki, info.address, info.is_subaddress, fake_outs_count, 0 /* unlock_time */, priority, extra);
if (ptx_vector.empty())
{
@@ -5625,7 +5725,7 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_)
}
catch (const std::exception& e)
{
- handle_transfer_exception(std::current_exception(), is_daemon_trusted());
+ handle_transfer_exception(std::current_exception(), m_wallet->is_trusted_daemon());
}
catch (...)
{
@@ -5931,7 +6031,7 @@ bool simple_wallet::submit_transfer(const std::vector<std::string> &args_)
}
catch (const std::exception& e)
{
- handle_transfer_exception(std::current_exception(), is_daemon_trusted());
+ handle_transfer_exception(std::current_exception(), m_wallet->is_trusted_daemon());
}
catch (...)
{
@@ -6844,7 +6944,7 @@ void simple_wallet::wallet_idle_thread()
{
uint64_t fetched_blocks;
if (try_connect_to_daemon(true))
- m_wallet->refresh(is_daemon_trusted(), 0, fetched_blocks);
+ m_wallet->refresh(m_wallet->is_trusted_daemon(), 0, fetched_blocks);
}
catch(...) {}
m_auto_refresh_refreshing = false;
@@ -7592,7 +7692,7 @@ bool simple_wallet::import_key_images(const std::vector<std::string> &args)
fail_msg_writer() << tr("command not supported by HW wallet");
return true;
}
- if (!is_daemon_trusted())
+ if (!m_wallet->is_trusted_daemon())
{
fail_msg_writer() << tr("this command requires a trusted daemon. Enable with --trusted-daemon");
return true;
@@ -7923,8 +8023,6 @@ int main(int argc, char* argv[])
command_line::add_arg(desc_params, arg_restore_multisig_wallet );
command_line::add_arg(desc_params, arg_non_deterministic );
command_line::add_arg(desc_params, arg_electrum_seed );
- command_line::add_arg(desc_params, arg_trusted_daemon);
- command_line::add_arg(desc_params, arg_untrusted_daemon);
command_line::add_arg(desc_params, arg_allow_mismatched_daemon_version);
command_line::add_arg(desc_params, arg_restore_height);
command_line::add_arg(desc_params, arg_do_not_relay);
diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h
index 99fc19c00..bfbe633ac 100644
--- a/src/simplewallet/simplewallet.h
+++ b/src/simplewallet/simplewallet.h
@@ -233,7 +233,6 @@ namespace cryptonote
bool print_ring_members(const std::vector<tools::wallet2::pending_tx>& ptx_vector, std::ostream& ostr);
std::string get_prompt() const;
bool print_seed(bool encrypted);
- bool is_daemon_trusted() const { return *m_trusted_daemon; }
/*!
* \brief Prints the seed with a nice message
@@ -337,7 +336,6 @@ namespace cryptonote
bool m_restore_deterministic_wallet; // recover flag
bool m_restore_multisig_wallet; // recover flag
bool m_non_deterministic; // old 2-random generation
- boost::optional<bool> m_trusted_daemon;
bool m_allow_mismatched_daemon_version;
bool m_restoring; // are we restoring, by whatever method?
uint64_t m_restore_height; // optional