aboutsummaryrefslogtreecommitdiff
path: root/src/simplewallet
diff options
context:
space:
mode:
Diffstat (limited to 'src/simplewallet')
-rw-r--r--src/simplewallet/simplewallet.cpp230
-rw-r--r--src/simplewallet/simplewallet.h12
2 files changed, 227 insertions, 15 deletions
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index 9f7cc9c3b..4692f7d59 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -235,6 +235,7 @@ namespace
const char* USAGE_MMS_AUTO_CONFIG("mms auto_config <auto_config_token>");
const char* USAGE_PRINT_RING("print_ring <key_image> | <txid>");
const char* USAGE_SET_RING("set_ring <filename> | ( <key_image> absolute|relative <index> [<index>...] )");
+ const char* USAGE_UNSET_RING("unset_ring <txid> | ( <key_image> [<key_image>...] )");
const char* USAGE_SAVE_KNOWN_RINGS("save_known_rings");
const char* USAGE_MARK_OUTPUT_SPENT("mark_output_spent <amount>/<offset> | <filename> [add]");
const char* USAGE_MARK_OUTPUT_UNSPENT("mark_output_unspent <amount>/<offset>");
@@ -242,6 +243,7 @@ namespace
const char* USAGE_FREEZE("freeze <key_image>");
const char* USAGE_THAW("thaw <key_image>");
const char* USAGE_FROZEN("frozen <key_image>");
+ const char* USAGE_NET_STATS("net_stats");
const char* USAGE_VERSION("version");
const char* USAGE_HELP("help [<command>]");
@@ -1870,6 +1872,38 @@ bool simple_wallet::set_ring(const std::vector<std::string> &args)
return true;
}
+bool simple_wallet::unset_ring(const std::vector<std::string> &args)
+{
+ crypto::hash txid;
+ std::vector<crypto::key_image> key_images;
+
+ if (args.size() < 1)
+ {
+ PRINT_USAGE(USAGE_UNSET_RING);
+ return true;
+ }
+
+ key_images.resize(args.size());
+ for (size_t i = 0; i < args.size(); ++i)
+ {
+ if (!epee::string_tools::hex_to_pod(args[i], key_images[i]))
+ {
+ fail_msg_writer() << tr("Invalid key image or txid");
+ return true;
+ }
+ }
+ static_assert(sizeof(crypto::hash) == sizeof(crypto::key_image), "hash and key_image must have the same size");
+ memcpy(&txid, &key_images[0], sizeof(txid));
+
+ if (!m_wallet->unset_ring(key_images) && !m_wallet->unset_ring(txid))
+ {
+ fail_msg_writer() << tr("failed to unset ring");
+ return true;
+ }
+
+ return true;
+}
+
bool simple_wallet::blackball(const std::vector<std::string> &args)
{
uint64_t amount = std::numeric_limits<uint64_t>::max(), offset, num_offsets;
@@ -2098,6 +2132,13 @@ bool simple_wallet::frozen(const std::vector<std::string> &args)
return true;
}
+bool simple_wallet::net_stats(const std::vector<std::string> &args)
+{
+ message_writer() << std::to_string(m_wallet->get_bytes_sent()) + tr(" bytes sent");
+ message_writer() << std::to_string(m_wallet->get_bytes_received()) + tr(" bytes received");
+ return true;
+}
+
bool simple_wallet::version(const std::vector<std::string> &args)
{
message_writer() << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")";
@@ -2592,6 +2633,31 @@ bool simple_wallet::set_track_uses(const std::vector<std::string> &args/* = std:
return true;
}
+bool simple_wallet::set_setup_background_mining(const std::vector<std::string> &args/* = std::vector<std::string>()*/)
+{
+ const auto pwd_container = get_and_verify_password();
+ if (pwd_container)
+ {
+ tools::wallet2::BackgroundMiningSetupType setup = tools::wallet2::BackgroundMiningMaybe;
+ if (args[1] == "yes" || args[1] == "1")
+ setup = tools::wallet2::BackgroundMiningYes;
+ else if (args[1] == "no" || args[1] == "0")
+ setup = tools::wallet2::BackgroundMiningNo;
+ else
+ {
+ fail_msg_writer() << tr("invalid argument: must be either 1/yes or 0/no");
+ return true;
+ }
+ m_wallet->setup_background_mining(setup);
+ m_wallet->rewrite(m_wallet_file, pwd_container->password());
+ if (setup == tools::wallet2::BackgroundMiningYes)
+ start_background_mining();
+ else
+ stop_background_mining();
+ }
+ 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();
@@ -3069,6 +3135,10 @@ simple_wallet::simple_wallet()
boost::bind(&simple_wallet::set_ring, this, _1),
tr(USAGE_SET_RING),
tr("Set the ring used for a given key image, so it can be reused in a fork"));
+ m_cmd_binder.set_handler("unset_ring",
+ boost::bind(&simple_wallet::unset_ring, this, _1),
+ tr(USAGE_UNSET_RING),
+ tr("Unsets the ring used for a given key image or transaction"));
m_cmd_binder.set_handler("save_known_rings",
boost::bind(&simple_wallet::save_known_rings, this, _1),
tr(USAGE_SAVE_KNOWN_RINGS),
@@ -3097,6 +3167,10 @@ simple_wallet::simple_wallet()
boost::bind(&simple_wallet::frozen, this, _1),
tr(USAGE_FROZEN),
tr("Checks whether a given output is currently frozen by key image"));
+ m_cmd_binder.set_handler("net_stats",
+ boost::bind(&simple_wallet::net_stats, this, _1),
+ tr(USAGE_NET_STATS),
+ tr("Prints simple network stats"));
m_cmd_binder.set_handler("version",
boost::bind(&simple_wallet::version, this, _1),
tr(USAGE_VERSION),
@@ -3125,6 +3199,13 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
case tools::wallet2::AskPasswordOnAction: ask_password_string = "action"; break;
case tools::wallet2::AskPasswordToDecrypt: ask_password_string = "decrypt"; break;
}
+ std::string setup_background_mining_string = "invalid";
+ switch (m_wallet->setup_background_mining())
+ {
+ case tools::wallet2::BackgroundMiningMaybe: setup_background_mining_string = "maybe"; break;
+ case tools::wallet2::BackgroundMiningYes: setup_background_mining_string = "yes"; break;
+ case tools::wallet2::BackgroundMiningNo: setup_background_mining_string = "no"; break;
+ }
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();
@@ -3151,6 +3232,7 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
success_msg_writer() << "segregation-height = " << m_wallet->segregation_height();
success_msg_writer() << "ignore-fractional-outputs = " << m_wallet->ignore_fractional_outputs();
success_msg_writer() << "track-uses = " << m_wallet->track_uses();
+ success_msg_writer() << "setup-background-mining = " << setup_background_mining_string + tr(" (set this to support the network and to get a chance to receive new monero)");
success_msg_writer() << "device_name = " << m_wallet->device_name();
return true;
}
@@ -3208,6 +3290,7 @@ bool simple_wallet::set_variable(const std::vector<std::string> &args)
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("track-uses", set_track_uses, tr("0 or 1"));
+ CHECK_SIMPLE_VARIABLE("setup-background-mining", set_setup_background_mining, tr("1/yes or 0/no"));
CHECK_SIMPLE_VARIABLE("device-name", set_device_name, tr("<device_name[:device_spec]>"));
}
fail_msg_writer() << tr("set: unrecognized argument(s)");
@@ -3403,6 +3486,7 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
const network_type nettype = testnet ? TESTNET : stagenet ? STAGENET : MAINNET;
epee::wipeable_string multisig_keys;
+ epee::wipeable_string password;
if (!handle_command_line(vm))
return false;
@@ -3510,7 +3594,6 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
m_recovery_key = cryptonote::decrypt_key(m_recovery_key, seed_pass);
}
}
- epee::wipeable_string password;
if (!m_generate_from_view_key.empty())
{
m_wallet_file = m_generate_from_view_key;
@@ -3955,8 +4038,9 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
fail_msg_writer() << tr("can't specify --subaddress-lookahead and --wallet-file at the same time");
return false;
}
- bool r = open_wallet(vm);
+ auto r = open_wallet(vm);
CHECK_AND_ASSERT_MES(r, false, tr("failed to open account"));
+ password = *r;
}
if (!m_wallet)
{
@@ -3972,6 +4056,8 @@ bool simple_wallet::init(const boost::program_options::variables_map& vm)
m_wallet->callback(this);
+ check_background_mining(password);
+
return true;
}
//----------------------------------------------------------------------------------------------------
@@ -4341,12 +4427,12 @@ boost::optional<epee::wipeable_string> simple_wallet::new_wallet(const boost::pr
return std::move(password);
}
//----------------------------------------------------------------------------------------------------
-bool simple_wallet::open_wallet(const boost::program_options::variables_map& vm)
+boost::optional<epee::wipeable_string> simple_wallet::open_wallet(const boost::program_options::variables_map& vm)
{
if (!tools::wallet2::wallet_valid_path_format(m_wallet_file))
{
fail_msg_writer() << tr("wallet file path not valid: ") << m_wallet_file;
- return false;
+ return {};
}
bool keys_file_exists;
@@ -4356,7 +4442,7 @@ bool simple_wallet::open_wallet(const boost::program_options::variables_map& vm)
if(!keys_file_exists)
{
fail_msg_writer() << tr("Key file not found. Failed to open wallet");
- return false;
+ return {};
}
epee::wipeable_string password;
@@ -4367,7 +4453,7 @@ bool simple_wallet::open_wallet(const boost::program_options::variables_map& vm)
password = std::move(std::move(rc.second).password());
if (!m_wallet)
{
- return false;
+ return {};
}
m_wallet->callback(this);
@@ -4393,7 +4479,7 @@ bool simple_wallet::open_wallet(const boost::program_options::variables_map& vm)
{
bool is_deterministic;
{
- SCOPED_WALLET_UNLOCK();
+ SCOPED_WALLET_UNLOCK_ON_BAD_PASSWORD(return {};);
is_deterministic = m_wallet->is_deterministic();
}
if (is_deterministic)
@@ -4402,7 +4488,7 @@ bool simple_wallet::open_wallet(const boost::program_options::variables_map& vm)
"a deprecated version of the wallet. Please proceed to upgrade your wallet.\n");
std::string mnemonic_language = get_mnemonic_language();
if (mnemonic_language.empty())
- return false;
+ return {};
m_wallet->set_seed_language(mnemonic_language);
m_wallet->rewrite(m_wallet_file, password);
@@ -4434,14 +4520,14 @@ bool simple_wallet::open_wallet(const boost::program_options::variables_map& vm)
if (password_is_correct)
fail_msg_writer() << boost::format(tr("You may want to remove the file \"%s\" and try again")) % m_wallet_file;
}
- return false;
+ return {};
}
success_msg_writer() <<
"**********************************************************************\n" <<
tr("Use the \"help\" command to see the list of available commands.\n") <<
tr("Use \"help <command>\" to see a command's documentation.\n") <<
"**********************************************************************";
- return true;
+ return std::move(password);
}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::close_wallet()
@@ -4522,7 +4608,118 @@ bool simple_wallet::save_watch_only(const std::vector<std::string> &args/* = std
}
return true;
}
+//----------------------------------------------------------------------------------------------------
+void simple_wallet::start_background_mining()
+{
+ COMMAND_RPC_MINING_STATUS::request reqq;
+ COMMAND_RPC_MINING_STATUS::response resq;
+ bool r = m_wallet->invoke_http_json("/mining_status", reqq, resq);
+ std::string err = interpret_rpc_response(r, resq.status);
+ if (!r)
+ return;
+ if (!err.empty())
+ {
+ fail_msg_writer() << tr("Failed to query mining status: ") << err;
+ return;
+ }
+ if (!resq.is_background_mining_enabled)
+ {
+ COMMAND_RPC_START_MINING::request req;
+ COMMAND_RPC_START_MINING::response res;
+ req.miner_address = m_wallet->get_account().get_public_address_str(m_wallet->nettype());
+ req.threads_count = 1;
+ req.do_background_mining = true;
+ req.ignore_battery = false;
+ bool r = m_wallet->invoke_http_json("/start_mining", req, res);
+ std::string err = interpret_rpc_response(r, res.status);
+ if (!err.empty())
+ {
+ fail_msg_writer() << tr("Failed to setup background mining: ") << err;
+ return;
+ }
+ }
+ success_msg_writer() << tr("Background mining enabled. Thank you for supporting the Monero network.");
+}
+//----------------------------------------------------------------------------------------------------
+void simple_wallet::stop_background_mining()
+{
+ COMMAND_RPC_MINING_STATUS::request reqq;
+ COMMAND_RPC_MINING_STATUS::response resq;
+ bool r = m_wallet->invoke_http_json("/mining_status", reqq, resq);
+ if (!r)
+ return;
+ std::string err = interpret_rpc_response(r, resq.status);
+ if (!err.empty())
+ {
+ fail_msg_writer() << tr("Failed to query mining status: ") << err;
+ return;
+ }
+ if (resq.is_background_mining_enabled)
+ {
+ COMMAND_RPC_STOP_MINING::request req;
+ COMMAND_RPC_STOP_MINING::response res;
+ bool r = m_wallet->invoke_http_json("/stop_mining", req, res);
+ std::string err = interpret_rpc_response(r, res.status);
+ if (!err.empty())
+ {
+ fail_msg_writer() << tr("Failed to setup background mining: ") << err;
+ return;
+ }
+ }
+ message_writer(console_color_red, false) << tr("Background mining not enabled. Run \"set setup-background-mining 1\" to change.");
+}
+//----------------------------------------------------------------------------------------------------
+void simple_wallet::check_background_mining(const epee::wipeable_string &password)
+{
+ tools::wallet2::BackgroundMiningSetupType setup = m_wallet->setup_background_mining();
+ if (setup == tools::wallet2::BackgroundMiningNo)
+ {
+ message_writer(console_color_red, false) << tr("Background mining not enabled. Run \"set setup-background-mining 1\" to change.");
+ return;
+ }
+ if (!m_wallet->is_trusted_daemon())
+ {
+ message_writer() << tr("Using an untrusted daemon, skipping background mining check");
+ return;
+ }
+
+ COMMAND_RPC_MINING_STATUS::request req;
+ COMMAND_RPC_MINING_STATUS::response res;
+ bool r = m_wallet->invoke_http_json("/mining_status", req, res);
+ std::string err = interpret_rpc_response(r, res.status);
+ bool is_background_mining_enabled = false;
+ if (err.empty())
+ is_background_mining_enabled = res.is_background_mining_enabled;
+
+ if (is_background_mining_enabled)
+ {
+ // already active, nice
+ m_wallet->setup_background_mining(tools::wallet2::BackgroundMiningYes);
+ m_wallet->rewrite(m_wallet_file, password);
+ start_background_mining();
+ return;
+ }
+ if (res.active)
+ return;
+
+ if (setup == tools::wallet2::BackgroundMiningMaybe)
+ {
+ message_writer() << tr("The daemon is not set up to background mine.");
+ message_writer() << tr("With background mining enabled, the daemon will mine when idle and not on batttery.");
+ message_writer() << tr("Enabling this supports the network you are using, and makes you eligible for receiving new monero");
+ std::string accepted = input_line(tr("Do you want to do it now? (Y/Yes/N/No): "));
+ if (std::cin.eof() || !command_line::is_yes(accepted)) {
+ m_wallet->setup_background_mining(tools::wallet2::BackgroundMiningNo);
+ m_wallet->rewrite(m_wallet_file, password);
+ message_writer(console_color_red, false) << tr("Background mining not enabled. Set setup-background-mining to 1 to change.");
+ return;
+ }
+ m_wallet->setup_background_mining(tools::wallet2::BackgroundMiningYes);
+ m_wallet->rewrite(m_wallet_file, password);
+ start_background_mining();
+ }
+}
//----------------------------------------------------------------------------------------------------
bool simple_wallet::start_mining(const std::vector<std::string>& args)
{
@@ -4948,10 +5145,15 @@ bool simple_wallet::show_balance_unlocked(bool detailed)
success_msg_writer() << tr("Currently selected account: [") << m_current_subaddress_account << tr("] ") << m_wallet->get_subaddress_label({m_current_subaddress_account, 0});
const std::string tag = m_wallet->get_account_tags().second[m_current_subaddress_account];
success_msg_writer() << tr("Tag: ") << (tag.empty() ? std::string{tr("(No tag assigned)")} : tag);
+ uint64_t blocks_to_unlock;
+ uint64_t unlocked_balance = m_wallet->unlocked_balance(m_current_subaddress_account, &blocks_to_unlock);
+ std::string unlock_time_message;
+ if (blocks_to_unlock > 0)
+ unlock_time_message = (boost::format(" (%lu block(s) to unlock)") % blocks_to_unlock).str();
success_msg_writer() << tr("Balance: ") << print_money(m_wallet->balance(m_current_subaddress_account)) << ", "
- << tr("unlocked balance: ") << print_money(m_wallet->unlocked_balance(m_current_subaddress_account)) << extra;
+ << tr("unlocked balance: ") << print_money(unlocked_balance) << unlock_time_message << extra;
std::map<uint32_t, uint64_t> balance_per_subaddress = m_wallet->balance_per_subaddress(m_current_subaddress_account);
- std::map<uint32_t, uint64_t> unlocked_balance_per_subaddress = m_wallet->unlocked_balance_per_subaddress(m_current_subaddress_account);
+ std::map<uint32_t, std::pair<uint64_t, uint64_t>> unlocked_balance_per_subaddress = m_wallet->unlocked_balance_per_subaddress(m_current_subaddress_account);
if (!detailed || balance_per_subaddress.empty())
return true;
success_msg_writer() << tr("Balance per address:");
@@ -4963,7 +5165,7 @@ bool simple_wallet::show_balance_unlocked(bool detailed)
cryptonote::subaddress_index subaddr_index = {m_current_subaddress_account, i.first};
std::string address_str = m_wallet->get_subaddress_as_str(subaddr_index).substr(0, 6);
uint64_t num_unspent_outputs = std::count_if(transfers.begin(), transfers.end(), [&subaddr_index](const tools::wallet2::transfer_details& td) { return !td.m_spent && td.m_subaddr_index == subaddr_index; });
- success_msg_writer() << boost::format(tr("%8u %6s %21s %21s %7u %21s")) % i.first % address_str % print_money(i.second) % print_money(unlocked_balance_per_subaddress[i.first]) % num_unspent_outputs % m_wallet->get_subaddress_label(subaddr_index);
+ success_msg_writer() << boost::format(tr("%8u %6s %21s %21s %7u %21s")) % i.first % address_str % print_money(i.second) % print_money(unlocked_balance_per_subaddress[i.first].first) % num_unspent_outputs % m_wallet->get_subaddress_label(subaddr_index);
}
return true;
}
@@ -5297,7 +5499,7 @@ bool simple_wallet::print_ring_members(const std::vector<tools::wallet2::pending
}
const cryptonote::tx_source_entry& source = *sptr;
- ostr << boost::format(tr("\nInput %llu/%llu: amount=%s")) % (i + 1) % tx.vin.size() % print_money(source.amount);
+ ostr << boost::format(tr("\nInput %llu/%llu (%s): amount=%s")) % (i + 1) % tx.vin.size() % epee::string_tools::pod_to_hex(in_key.k_image) % print_money(source.amount);
// convert relative offsets of ring member keys into absolute offsets (indices) associated with the amount
std::vector<uint64_t> absolute_offsets = cryptonote::relative_output_offsets_to_absolute(in_key.key_offsets);
// get block heights from which those ring member keys originated
diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h
index c9a5c55e8..0cbb33cf9 100644
--- a/src/simplewallet/simplewallet.h
+++ b/src/simplewallet/simplewallet.h
@@ -102,7 +102,7 @@ namespace cryptonote
boost::optional<epee::wipeable_string> new_wallet(const boost::program_options::variables_map& vm,
const epee::wipeable_string &multisig_keys, const std::string &old_language);
boost::optional<epee::wipeable_string> new_wallet(const boost::program_options::variables_map& vm);
- bool open_wallet(const boost::program_options::variables_map& vm);
+ boost::optional<epee::wipeable_string> open_wallet(const boost::program_options::variables_map& vm);
bool close_wallet();
bool viewkey(const std::vector<std::string> &args = std::vector<std::string>());
@@ -143,6 +143,7 @@ namespace cryptonote
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_track_uses(const std::vector<std::string> &args = std::vector<std::string>());
+ bool set_setup_background_mining(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);
@@ -234,6 +235,7 @@ namespace cryptonote
bool mms(const std::vector<std::string>& args);
bool print_ring(const std::vector<std::string>& args);
bool set_ring(const std::vector<std::string>& args);
+ bool unset_ring(const std::vector<std::string>& args);
bool save_known_rings(const std::vector<std::string>& args);
bool blackball(const std::vector<std::string>& args);
bool unblackball(const std::vector<std::string>& args);
@@ -241,6 +243,7 @@ namespace cryptonote
bool freeze(const std::vector<std::string>& args);
bool thaw(const std::vector<std::string>& args);
bool frozen(const std::vector<std::string>& args);
+ bool net_stats(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);
@@ -297,6 +300,13 @@ namespace cryptonote
*/
void commit_or_save(std::vector<tools::wallet2::pending_tx>& ptx_vector, bool do_not_relay);
+ /*!
+ * \brief checks whether background mining is enabled, and asks to configure it if not
+ */
+ void check_background_mining(const epee::wipeable_string &password);
+ void start_background_mining();
+ void stop_background_mining();
+
//----------------- i_wallet2_callback ---------------------
virtual void on_new_block(uint64_t height, const cryptonote::block& block);
virtual void on_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index);