simplewallet: add churn command
This commit is contained in:
parent
8058facbb3
commit
0742c615e2
|
@ -64,6 +64,9 @@
|
||||||
#include "wallet/wallet_args.h"
|
#include "wallet/wallet_args.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
#include <boost/locale.hpp>
|
#include <boost/locale.hpp>
|
||||||
|
@ -2655,8 +2658,14 @@ simple_wallet::simple_wallet()
|
||||||
tr("Show simplified help section."));
|
tr("Show simplified help section."));
|
||||||
m_cmd_binder.set_handler("help_advanced",
|
m_cmd_binder.set_handler("help_advanced",
|
||||||
boost::bind(&simple_wallet::help_advanced, this, _1),
|
boost::bind(&simple_wallet::help_advanced, this, _1),
|
||||||
tr("help_advanced [<command>]"),
|
tr("help_advanced"),
|
||||||
tr("Show the advanced help section or the documentation about a <command>."));
|
tr("Show the help section or the documentation about a <command>."));
|
||||||
|
m_cmd_binder.set_handler("churn",
|
||||||
|
boost::bind(&simple_wallet::churn, this, _1),
|
||||||
|
tr("churn"),
|
||||||
|
tr("Churning can enhance privacy by increasing the distance of your funds from the source. This is especially\n"
|
||||||
|
"important if your funds come from an exchange or a pool that shares public mining data. Each churn also helps\n"
|
||||||
|
"create more decoy outputs, which is good for constructing stronger ring signatures."));
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
bool simple_wallet::set_variable(const std::vector<std::string> &args)
|
bool simple_wallet::set_variable(const std::vector<std::string> &args)
|
||||||
|
@ -4220,11 +4229,13 @@ void simple_wallet::on_money_received(uint64_t height, const crypto::hash &txid,
|
||||||
(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."));
|
(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_wallet->auto_confirm_churn() == 0) {
|
||||||
if (m_auto_refresh_refreshing)
|
if (m_auto_refresh_refreshing)
|
||||||
m_cmd_binder.print_prompt();
|
m_cmd_binder.print_prompt();
|
||||||
else
|
else
|
||||||
m_refresh_progress_reporter.update(height, true);
|
m_refresh_progress_reporter.update(height, true);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
void simple_wallet::on_unconfirmed_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index)
|
void simple_wallet::on_unconfirmed_money_received(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx, uint64_t amount, const cryptonote::subaddress_index& subaddr_index)
|
||||||
{
|
{
|
||||||
|
@ -4233,16 +4244,19 @@ void simple_wallet::on_unconfirmed_money_received(uint64_t height, const crypto:
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
void simple_wallet::on_money_spent(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& in_tx, uint64_t amount, const cryptonote::transaction& spend_tx, const cryptonote::subaddress_index& subaddr_index)
|
void simple_wallet::on_money_spent(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& in_tx, uint64_t amount, const cryptonote::transaction& spend_tx, const cryptonote::subaddress_index& subaddr_index)
|
||||||
{
|
{
|
||||||
|
|
||||||
message_writer(console_color_magenta, false) << "\r" <<
|
message_writer(console_color_magenta, false) << "\r" <<
|
||||||
tr("Height ") << height << ", " <<
|
tr("Height ") << height << ", " <<
|
||||||
tr("txid ") << txid << ", " <<
|
tr("txid ") << txid << ", " <<
|
||||||
tr("spent ") << print_money(amount) << ", " <<
|
tr("spent ") << print_money(amount) << ", " <<
|
||||||
tr("idx ") << subaddr_index;
|
tr("idx ") << subaddr_index;
|
||||||
|
if (m_wallet->auto_confirm_churn() == 0) {
|
||||||
if (m_auto_refresh_refreshing)
|
if (m_auto_refresh_refreshing)
|
||||||
m_cmd_binder.print_prompt();
|
m_cmd_binder.print_prompt();
|
||||||
else
|
else
|
||||||
m_refresh_progress_reporter.update(height, true);
|
m_refresh_progress_reporter.update(height, true);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
void simple_wallet::on_skip_transaction(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx)
|
void simple_wallet::on_skip_transaction(uint64_t height, const crypto::hash &txid, const cryptonote::transaction& tx)
|
||||||
{
|
{
|
||||||
|
@ -4371,11 +4385,12 @@ bool simple_wallet::show_balance_unlocked(bool detailed)
|
||||||
extra = tr(" (Some owned outputs have partial key images - import_multisig_info needed)");
|
extra = tr(" (Some owned outputs have partial key images - import_multisig_info needed)");
|
||||||
else if (m_wallet->has_unknown_key_images())
|
else if (m_wallet->has_unknown_key_images())
|
||||||
extra += tr(" (Some owned outputs have missing key images - import_key_images needed)");
|
extra += tr(" (Some owned outputs have missing key images - import_key_images needed)");
|
||||||
|
if (m_wallet->auto_confirm_churn() == 0) {
|
||||||
success_msg_writer() << tr("Currently selected account: [") << m_current_subaddress_account << tr("] ") << m_wallet->get_subaddress_label({m_current_subaddress_account, 0});
|
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];
|
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);
|
success_msg_writer() << tr("Tag: ") << (tag.empty() ? std::string{tr("(No tag assigned)")} : tag);
|
||||||
success_msg_writer() << tr("Balance: ") << print_money(m_wallet->balance(m_current_subaddress_account)) << ", "
|
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(m_wallet->unlocked_balance(m_current_subaddress_account)) << 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> 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, uint64_t> unlocked_balance_per_subaddress = m_wallet->unlocked_balance_per_subaddress(m_current_subaddress_account);
|
||||||
if (!detailed || balance_per_subaddress.empty())
|
if (!detailed || balance_per_subaddress.empty())
|
||||||
|
@ -5473,6 +5488,8 @@ bool simple_wallet::sweep_main(uint64_t below, bool locked, const std::vector<st
|
||||||
payment_id_seen = true;
|
payment_id_seen = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const bool is_wallet_address = m_wallet->get_address() == info.address;
|
||||||
|
|
||||||
// prompt is there is no payment id and confirmation is required
|
// prompt is there is no payment id and confirmation is required
|
||||||
if (m_long_payment_id_support && !payment_id_seen && m_wallet->confirm_missing_payment_id() && !info.is_subaddress && !is_wallet_address)
|
if (m_long_payment_id_support && !payment_id_seen && m_wallet->confirm_missing_payment_id() && !info.is_subaddress && !is_wallet_address)
|
||||||
{
|
{
|
||||||
|
@ -5501,6 +5518,9 @@ bool simple_wallet::sweep_main(uint64_t below, bool locked, const std::vector<st
|
||||||
}
|
}
|
||||||
|
|
||||||
// give user total and fee, and prompt to confirm
|
// give user total and fee, and prompt to confirm
|
||||||
|
|
||||||
|
if (m_wallet->auto_confirm_churn() == 0)
|
||||||
|
{
|
||||||
uint64_t total_fee = 0, total_sent = 0;
|
uint64_t total_fee = 0, total_sent = 0;
|
||||||
for (size_t n = 0; n < ptx_vector.size(); ++n)
|
for (size_t n = 0; n < ptx_vector.size(); ++n)
|
||||||
{
|
{
|
||||||
|
@ -5543,6 +5563,7 @@ bool simple_wallet::sweep_main(uint64_t below, bool locked, const std::vector<st
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// actually commit the transactions
|
// actually commit the transactions
|
||||||
if (m_wallet->multisig())
|
if (m_wallet->multisig())
|
||||||
|
@ -8080,6 +8101,89 @@ bool simple_wallet::process_command(const std::vector<std::string> &args)
|
||||||
return m_cmd_binder.process_command_vec(args);
|
return m_cmd_binder.process_command_vec(args);
|
||||||
}
|
}
|
||||||
//----------------------------------------------------------------------------------------------------
|
//----------------------------------------------------------------------------------------------------
|
||||||
|
bool simple_wallet::churn(const std::vector<std::string> &args_)
|
||||||
|
{
|
||||||
|
// Check if wallet is on MAINNET
|
||||||
|
if (m_wallet->nettype() != cryptonote::MAINNET)
|
||||||
|
{
|
||||||
|
fail_msg_writer() << tr("Churning is only possible on Mainnet, operation cancelled.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check balance
|
||||||
|
if (m_wallet->unlocked_balance(m_current_subaddress_account) < 2)
|
||||||
|
{
|
||||||
|
fail_msg_writer() << tr("You need to have an unlocked balance of more than 2 WOW, operation cancelled.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warning
|
||||||
|
std::string warning = input_line(tr("Warning: Churning requires your wallet to be open for a few hours. If wallet is left unattended, make sure your computer is in a secure location. Continue?"));
|
||||||
|
if (std::cin.eof() || !command_line::is_yes(warning))
|
||||||
|
{
|
||||||
|
message_writer() << tr("Operation cancelled.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate pseudo-random integers for the number of churns and interval pause
|
||||||
|
int churn_number, pause_time, i;
|
||||||
|
srand (time(NULL)); // seed RNG with current time
|
||||||
|
churn_number = rand()%(8 + 1 - 2) + 2; // churn between 2 to 8 times
|
||||||
|
pause_time = rand()%(120 + 1 - 60) + 60; // wait between 1 to 2 hours per interval
|
||||||
|
float total_time = static_cast<float>(churn_number*pause_time)/60; // calculate how long churning will take in hours
|
||||||
|
|
||||||
|
// Calculate fee
|
||||||
|
float churn_fee = m_wallet->use_fork_rules(HF_VERSION_PER_BYTE_FEE) ? static_cast<float>(churn_number * 0.015) : static_cast<float>(churn_number * 0.032654); // usual 2/2 tx fee
|
||||||
|
|
||||||
|
// Prompt confirmation
|
||||||
|
printf ("----------------\nNumber of churns: %d\nTotal duration: %.2f hours\nEstimated cost: %.2f WOW\n----------------\n", churn_number, total_time, churn_fee);
|
||||||
|
std::string confirm_churn = input_line(tr("Continue?"));
|
||||||
|
if (std::cin.eof() || !command_line::is_yes(confirm_churn))
|
||||||
|
{
|
||||||
|
message_writer() << tr("Operation cancelled.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get main address
|
||||||
|
std::vector<std::string> local_args = args_;
|
||||||
|
std::string address_str;
|
||||||
|
address_str = m_wallet->get_account().get_public_address_str(m_wallet->nettype());
|
||||||
|
local_args.push_back(address_str);
|
||||||
|
message_writer() << tr("Sweeping entire wallet balance to your main address:");
|
||||||
|
message_writer(console_color_white, true) << address_str;
|
||||||
|
|
||||||
|
// Disable wallet confirmations to allow for automation
|
||||||
|
m_wallet->auto_confirm_churn(1);
|
||||||
|
m_wallet->ask_password(tools::wallet2::AskPasswordNever);
|
||||||
|
m_wallet->always_confirm_transfers(0);
|
||||||
|
m_wallet->auto_refresh(0);
|
||||||
|
|
||||||
|
// Loop sweep_all to main address for churn_number times with pause_time each interval
|
||||||
|
for (i = 1; i <= churn_number; ++i) {
|
||||||
|
refresh(local_args);
|
||||||
|
sweep_all(local_args);
|
||||||
|
message_writer(console_color_magenta, true) << tr("\n---------------- ") << i << tr(" out of ") << churn_number << tr(" churns ----------------");
|
||||||
|
|
||||||
|
if (i == churn_number)
|
||||||
|
{
|
||||||
|
success_msg_writer() << tr("\nChurning compete.");
|
||||||
|
|
||||||
|
// Re-enable confirmations
|
||||||
|
m_wallet->auto_confirm_churn(0);
|
||||||
|
m_wallet->ask_password(tools::wallet2::AskPasswordOnAction);
|
||||||
|
m_wallet->always_confirm_transfers(1);
|
||||||
|
m_wallet->auto_refresh(1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
message_writer() << tr("\nInterval pause, please wait...\n");
|
||||||
|
sleep(pause_time*60);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//----------------------------------------------------------------------------------------------------
|
||||||
void simple_wallet::interrupt()
|
void simple_wallet::interrupt()
|
||||||
{
|
{
|
||||||
if (m_in_manual_refresh.load(std::memory_order_relaxed))
|
if (m_in_manual_refresh.load(std::memory_order_relaxed))
|
||||||
|
@ -8112,9 +8216,14 @@ void simple_wallet::commit_or_save(std::vector<tools::wallet2::pending_tx>& ptx_
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
if (m_wallet->auto_confirm_churn() == 0) {
|
||||||
m_wallet->commit_tx(ptx);
|
m_wallet->commit_tx(ptx);
|
||||||
success_msg_writer(true) << tr("Transaction successfully submitted, transaction ") << txid << ENDL
|
success_msg_writer(true) << tr("Transaction successfully submitted, transaction ") << txid << ENDL
|
||||||
<< tr("You can check its status by using the `show_transfers` command.");
|
<< tr("You can check its status by using the `show_transfers` command.");
|
||||||
|
} else {
|
||||||
|
m_wallet->commit_tx(ptx);
|
||||||
|
success_msg_writer(true) << tr("Churn successfully executed, transaction ") << txid;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// if no exception, remove element from vector
|
// if no exception, remove element from vector
|
||||||
ptx_vector.pop_back();
|
ptx_vector.pop_back();
|
||||||
|
|
|
@ -141,6 +141,7 @@ namespace cryptonote
|
||||||
bool set_ignore_fractional_outputs(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 help(const std::vector<std::string> &args = std::vector<std::string>());
|
bool help(const std::vector<std::string> &args = std::vector<std::string>());
|
||||||
bool help_advanced(const std::vector<std::string> &args = std::vector<std::string>());
|
bool help_advanced(const std::vector<std::string> &args = std::vector<std::string>());
|
||||||
|
bool churn(const std::vector<std::string> &args);
|
||||||
bool start_mining(const std::vector<std::string> &args);
|
bool start_mining(const std::vector<std::string> &args);
|
||||||
bool stop_mining(const std::vector<std::string> &args);
|
bool stop_mining(const std::vector<std::string> &args);
|
||||||
bool set_daemon(const std::vector<std::string> &args);
|
bool set_daemon(const std::vector<std::string> &args);
|
||||||
|
|
|
@ -816,6 +816,7 @@ wallet2::wallet2(network_type nettype, uint64_t kdf_rounds, bool unattended):
|
||||||
m_nettype(nettype),
|
m_nettype(nettype),
|
||||||
m_multisig_rounds_passed(0),
|
m_multisig_rounds_passed(0),
|
||||||
m_always_confirm_transfers(true),
|
m_always_confirm_transfers(true),
|
||||||
|
m_auto_confirm_churn(false),
|
||||||
m_print_ring_members(false),
|
m_print_ring_members(false),
|
||||||
m_store_tx_info(true),
|
m_store_tx_info(true),
|
||||||
m_default_mixin(0),
|
m_default_mixin(0),
|
||||||
|
|
|
@ -913,6 +913,8 @@ namespace tools
|
||||||
|
|
||||||
bool always_confirm_transfers() const { return m_always_confirm_transfers; }
|
bool always_confirm_transfers() const { return m_always_confirm_transfers; }
|
||||||
void always_confirm_transfers(bool always) { m_always_confirm_transfers = always; }
|
void always_confirm_transfers(bool always) { m_always_confirm_transfers = always; }
|
||||||
|
bool auto_confirm_churn() const { return m_auto_confirm_churn; }
|
||||||
|
void auto_confirm_churn(bool always) { m_auto_confirm_churn = always; }
|
||||||
bool print_ring_members() const { return m_print_ring_members; }
|
bool print_ring_members() const { return m_print_ring_members; }
|
||||||
void print_ring_members(bool value) { m_print_ring_members = value; }
|
void print_ring_members(bool value) { m_print_ring_members = value; }
|
||||||
bool store_tx_info() const { return m_store_tx_info; }
|
bool store_tx_info() const { return m_store_tx_info; }
|
||||||
|
@ -1316,6 +1318,7 @@ namespace tools
|
||||||
uint32_t m_multisig_rounds_passed;
|
uint32_t m_multisig_rounds_passed;
|
||||||
std::vector<crypto::public_key> m_multisig_derivations;
|
std::vector<crypto::public_key> m_multisig_derivations;
|
||||||
bool m_always_confirm_transfers;
|
bool m_always_confirm_transfers;
|
||||||
|
bool m_auto_confirm_churn;
|
||||||
bool m_print_ring_members;
|
bool m_print_ring_members;
|
||||||
bool m_store_tx_info; /*!< request txkey to be returned in RPC, and store in the wallet cache file */
|
bool m_store_tx_info; /*!< request txkey to be returned in RPC, and store in the wallet cache file */
|
||||||
uint32_t m_default_mixin;
|
uint32_t m_default_mixin;
|
||||||
|
|
Loading…
Reference in New Issue