aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRiccardo Spagni <ric@spagni.net>2019-04-01 17:36:15 +0200
committerRiccardo Spagni <ric@spagni.net>2019-04-01 17:36:16 +0200
commit286dec012d2d7f11dea6a4dba9388623cbb642f6 (patch)
tree7c8eaa5cfaefe59d8e62c7c2cd0fbf8694b5215b
parentMerge pull request #5332 (diff)
parentwallet: add freeze/thaw/frozen commands (diff)
downloadmonero-286dec012d2d7f11dea6a4dba9388623cbb642f6.tar.xz
Merge pull request #5333
18faa6da wallet: add freeze/thaw/frozen commands (moneromooo-monero)
Diffstat (limited to '')
-rw-r--r--src/simplewallet/simplewallet.cpp87
-rw-r--r--src/simplewallet/simplewallet.h6
-rw-r--r--src/wallet/wallet2.cpp85
-rw-r--r--src/wallet/wallet2.h26
4 files changed, 188 insertions, 16 deletions
diff --git a/src/simplewallet/simplewallet.cpp b/src/simplewallet/simplewallet.cpp
index 25d40e5fb..8974bd1e0 100644
--- a/src/simplewallet/simplewallet.cpp
+++ b/src/simplewallet/simplewallet.cpp
@@ -239,6 +239,9 @@ namespace
const char* USAGE_MARK_OUTPUT_SPENT("mark_output_spent <amount>/<offset> | <filename> [add]");
const char* USAGE_MARK_OUTPUT_UNSPENT("mark_output_unspent <amount>/<offset>");
const char* USAGE_IS_OUTPUT_SPENT("is_output_spent <amount>/<offset>");
+ const char* USAGE_FREEZE("freeze <key_image>");
+ const char* USAGE_THAW("thaw <key_image>");
+ const char* USAGE_FROZEN("frozen <key_image>");
const char* USAGE_VERSION("version");
const char* USAGE_HELP("help [<command>]");
@@ -2027,6 +2030,74 @@ bool simple_wallet::save_known_rings(const std::vector<std::string> &args)
return true;
}
+bool simple_wallet::freeze_thaw(const std::vector<std::string> &args, bool freeze)
+{
+ if (args.empty())
+ {
+ fail_msg_writer() << boost::format(tr("usage: %s <key_image>|<pubkey>")) % (freeze ? "freeze" : "thaw");
+ return true;
+ }
+ crypto::key_image ki;
+ if (!epee::string_tools::hex_to_pod(args[0], ki))
+ {
+ fail_msg_writer() << tr("failed to parse key image");
+ return true;
+ }
+ try
+ {
+ if (freeze)
+ m_wallet->freeze(ki);
+ else
+ m_wallet->thaw(ki);
+ }
+ catch (const std::exception &e)
+ {
+ fail_msg_writer() << e.what();
+ return true;
+ }
+
+ return true;
+}
+
+bool simple_wallet::freeze(const std::vector<std::string> &args)
+{
+ return freeze_thaw(args, true);
+}
+
+bool simple_wallet::thaw(const std::vector<std::string> &args)
+{
+ return freeze_thaw(args, false);
+}
+
+bool simple_wallet::frozen(const std::vector<std::string> &args)
+{
+ if (args.empty())
+ {
+ size_t ntd = m_wallet->get_num_transfer_details();
+ for (size_t i = 0; i < ntd; ++i)
+ {
+ if (!m_wallet->frozen(i))
+ continue;
+ const tools::wallet2::transfer_details &td = m_wallet->get_transfer_details(i);
+ message_writer() << tr("Frozen: ") << td.m_key_image << " " << cryptonote::print_money(td.amount());
+ }
+ }
+ else
+ {
+ crypto::key_image ki;
+ if (!epee::string_tools::hex_to_pod(args[0], ki))
+ {
+ fail_msg_writer() << tr("failed to parse key image");
+ return true;
+ }
+ if (m_wallet->frozen(ki))
+ message_writer() << tr("Frozen: ") << ki;
+ else
+ message_writer() << tr("Not frozen: ") << ki;
+ }
+ return true;
+}
+
bool simple_wallet::version(const std::vector<std::string> &args)
{
message_writer() << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")";
@@ -2602,7 +2673,7 @@ simple_wallet::simple_wallet()
tr(USAGE_INCOMING_TRANSFERS),
tr("Show the incoming transfers, all or filtered by availability and address index.\n\n"
"Output format:\n"
- "Amount, Spent(\"T\"|\"F\"), \"locked\"|\"unlocked\", RingCT, Global Index, Transaction Hash, Address Index, [Public Key, Key Image] "));
+ "Amount, Spent(\"T\"|\"F\"), \"frozen\"|\"locked\"|\"unlocked\", RingCT, Global Index, Transaction Hash, Address Index, [Public Key, Key Image] "));
m_cmd_binder.set_handler("payments",
boost::bind(&simple_wallet::show_payments, this, _1),
tr(USAGE_PAYMENTS),
@@ -3014,6 +3085,18 @@ simple_wallet::simple_wallet()
boost::bind(&simple_wallet::blackballed, this, _1),
tr(USAGE_IS_OUTPUT_SPENT),
tr("Checks whether an output is marked as spent"));
+ m_cmd_binder.set_handler("freeze",
+ boost::bind(&simple_wallet::freeze, this, _1),
+ tr(USAGE_FREEZE),
+ tr("Freeze a single output by key image so it will not be used"));
+ m_cmd_binder.set_handler("thaw",
+ boost::bind(&simple_wallet::thaw, this, _1),
+ tr(USAGE_THAW),
+ tr("Thaw a single output by key image so it may be used again"));
+ m_cmd_binder.set_handler("frozen",
+ 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("version",
boost::bind(&simple_wallet::version, this, _1),
tr(USAGE_VERSION),
@@ -4989,7 +5072,7 @@ bool simple_wallet::show_incoming_transfers(const std::vector<std::string>& args
boost::format("%21s%8s%12s%8s%16u%68s%16u%s") %
print_money(td.amount()) %
(td.m_spent ? tr("T") : tr("F")) %
- (m_wallet->is_transfer_unlocked(td) ? tr("unlocked") : tr("locked")) %
+ (m_wallet->frozen(td) ? tr("[frozen]") : m_wallet->is_transfer_unlocked(td) ? tr("unlocked") : tr("locked")) %
(td.is_rct() ? tr("RingCT") : tr("-")) %
td.m_global_output_index %
td.m_txid %
diff --git a/src/simplewallet/simplewallet.h b/src/simplewallet/simplewallet.h
index 7bcb92190..c9a5c55e8 100644
--- a/src/simplewallet/simplewallet.h
+++ b/src/simplewallet/simplewallet.h
@@ -238,9 +238,12 @@ namespace cryptonote
bool blackball(const std::vector<std::string>& args);
bool unblackball(const std::vector<std::string>& args);
bool blackballed(const std::vector<std::string>& args);
+ 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 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);
+ bool cold_sign_tx(const std::vector<tools::wallet2::pending_tx>& ptx_vector, tools::wallet2::signed_tx_set &exported_txs, std::vector<cryptonote::address_parse_info> &dsts_info, std::function<bool(const tools::wallet2::signed_tx_set &)> accept_func);
uint64_t get_daemon_blockchain_height(std::string& err);
bool try_connect_to_daemon(bool silent = false, uint32_t* version = nullptr);
bool ask_wallet_create_if_needed();
@@ -253,6 +256,7 @@ namespace cryptonote
void key_images_sync_intern();
void on_refresh_finished(uint64_t start_height, uint64_t fetched_blocks, bool is_init, bool received_money);
std::pair<std::string, std::string> show_outputs_line(const std::vector<uint64_t> &heights, uint64_t blockchain_height, uint64_t highlight_height = std::numeric_limits<uint64_t>::max()) const;
+ bool freeze_thaw(const std::vector<std::string>& args, bool freeze);
struct transfer_view
{
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index 4679a1697..d59ded49f 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -1441,6 +1441,58 @@ void wallet2::set_unspent(size_t idx)
td.m_spent_height = 0;
}
//----------------------------------------------------------------------------------------------------
+void wallet2::freeze(size_t idx)
+{
+ CHECK_AND_ASSERT_THROW_MES(idx < m_transfers.size(), "Invalid transfer_details index");
+ transfer_details &td = m_transfers[idx];
+ td.m_frozen = true;
+}
+//----------------------------------------------------------------------------------------------------
+void wallet2::thaw(size_t idx)
+{
+ CHECK_AND_ASSERT_THROW_MES(idx < m_transfers.size(), "Invalid transfer_details index");
+ transfer_details &td = m_transfers[idx];
+ td.m_frozen = false;
+}
+//----------------------------------------------------------------------------------------------------
+bool wallet2::frozen(size_t idx) const
+{
+ CHECK_AND_ASSERT_THROW_MES(idx < m_transfers.size(), "Invalid transfer_details index");
+ const transfer_details &td = m_transfers[idx];
+ return td.m_frozen;
+}
+//----------------------------------------------------------------------------------------------------
+void wallet2::freeze(const crypto::key_image &ki)
+{
+ freeze(get_transfer_details(ki));
+}
+//----------------------------------------------------------------------------------------------------
+void wallet2::thaw(const crypto::key_image &ki)
+{
+ thaw(get_transfer_details(ki));
+}
+//----------------------------------------------------------------------------------------------------
+bool wallet2::frozen(const crypto::key_image &ki) const
+{
+ return frozen(get_transfer_details(ki));
+}
+//----------------------------------------------------------------------------------------------------
+size_t wallet2::get_transfer_details(const crypto::key_image &ki) const
+{
+ for (size_t idx = 0; idx < m_transfers.size(); ++idx)
+ {
+ const transfer_details &td = m_transfers[idx];
+ if (td.m_key_image_known && td.m_key_image == ki)
+ return idx;
+ }
+ CHECK_AND_ASSERT_THROW_MES(false, "Key image not found");
+}
+//----------------------------------------------------------------------------------------------------
+bool wallet2::frozen(const transfer_details &td) const
+{
+ return td.m_frozen;
+}
+//----------------------------------------------------------------------------------------------------
void wallet2::check_acc_out_precomp(const tx_out &o, const crypto::key_derivation &derivation, const std::vector<crypto::key_derivation> &additional_derivations, size_t i, tx_scan_info_t &tx_scan_info) const
{
hw::device &hwdev = m_account.get_device();
@@ -1858,6 +1910,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
td.m_mask = rct::identity();
td.m_rct = false;
}
+ td.m_frozen = false;
set_unspent(m_transfers.size()-1);
if (td.m_key_image_known)
m_key_images[td.m_key_image] = m_transfers.size()-1;
@@ -3205,8 +3258,9 @@ void wallet2::detach_blockchain(uint64_t height, std::map<std::pair<uint64_t, ui
wallet2::transfer_details &td = m_transfers[i];
if (td.m_spent && td.m_spent_height >= height)
{
- LOG_PRINT_L1("Resetting spent status for output " << i << ": " << td.m_key_image);
+ LOG_PRINT_L1("Resetting spent/frozen status for output " << i << ": " << td.m_key_image);
set_unspent(i);
+ thaw(i);
}
}
@@ -5391,7 +5445,7 @@ std::map<uint32_t, uint64_t> wallet2::balance_per_subaddress(uint32_t index_majo
std::map<uint32_t, uint64_t> amount_per_subaddr;
for (const auto& td: m_transfers)
{
- if (td.m_subaddr_index.major == index_major && !td.m_spent)
+ if (td.m_subaddr_index.major == index_major && !td.m_spent && !td.m_frozen)
{
auto found = amount_per_subaddr.find(td.m_subaddr_index.minor);
if (found == amount_per_subaddr.end())
@@ -5420,7 +5474,7 @@ std::map<uint32_t, uint64_t> wallet2::unlocked_balance_per_subaddress(uint32_t i
std::map<uint32_t, uint64_t> amount_per_subaddr;
for(const transfer_details& td: m_transfers)
{
- if(td.m_subaddr_index.major == index_major && !td.m_spent && is_transfer_unlocked(td))
+ if(td.m_subaddr_index.major == index_major && !td.m_spent && !td.m_frozen && is_transfer_unlocked(td))
{
auto found = amount_per_subaddr.find(td.m_subaddr_index.minor);
if (found == amount_per_subaddr.end())
@@ -8314,7 +8368,7 @@ std::vector<size_t> wallet2::pick_preferred_rct_inputs(uint64_t needed_money, ui
for (size_t i = 0; i < m_transfers.size(); ++i)
{
const transfer_details& td = m_transfers[i];
- if (!td.m_spent && td.is_rct() && td.amount() >= needed_money && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && subaddr_indices.count(td.m_subaddr_index.minor) == 1)
+ if (!td.m_spent && !td.m_frozen && td.is_rct() && td.amount() >= needed_money && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && subaddr_indices.count(td.m_subaddr_index.minor) == 1)
{
LOG_PRINT_L2("We can use " << i << " alone: " << print_money(td.amount()));
picks.push_back(i);
@@ -8329,13 +8383,13 @@ std::vector<size_t> wallet2::pick_preferred_rct_inputs(uint64_t needed_money, ui
for (size_t i = 0; i < m_transfers.size(); ++i)
{
const transfer_details& td = m_transfers[i];
- if (!td.m_spent && !td.m_key_image_partial && td.is_rct() && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && subaddr_indices.count(td.m_subaddr_index.minor) == 1)
+ if (!td.m_spent && !td.m_frozen && !td.m_key_image_partial && td.is_rct() && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && subaddr_indices.count(td.m_subaddr_index.minor) == 1)
{
LOG_PRINT_L2("Considering input " << i << ", " << print_money(td.amount()));
for (size_t j = i + 1; j < m_transfers.size(); ++j)
{
const transfer_details& td2 = m_transfers[j];
- if (!td2.m_spent && !td.m_key_image_partial && td2.is_rct() && td.amount() + td2.amount() >= needed_money && is_transfer_unlocked(td2) && td2.m_subaddr_index == td.m_subaddr_index)
+ if (!td2.m_spent && !td2.m_frozen && !td.m_key_image_partial && td2.is_rct() && td.amount() + td2.amount() >= needed_money && is_transfer_unlocked(td2) && td2.m_subaddr_index == td.m_subaddr_index)
{
// update our picks if those outputs are less related than any we
// already found. If the same, don't update, and oldest suitable outputs
@@ -8562,6 +8616,7 @@ void wallet2::light_wallet_get_unspent_outs()
td.m_pk_index = 0;
td.m_internal_output_index = o.index;
td.m_spent = spent;
+ td.m_frozen = false;
tx_out txout;
txout.target = txout_to_key(public_key);
@@ -9036,7 +9091,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp
MDEBUG("Ignoring output " << i << " of amount " << print_money(td.amount()) << " which is below threshold " << print_money(fractional_threshold));
continue;
}
- if (!td.m_spent && !td.m_key_image_partial && (use_rct ? true : !td.is_rct()) && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && subaddr_indices.count(td.m_subaddr_index.minor) == 1)
+ if (!td.m_spent && !td.m_frozen && !td.m_key_image_partial && (use_rct ? true : !td.is_rct()) && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && subaddr_indices.count(td.m_subaddr_index.minor) == 1)
{
const uint32_t index_minor = td.m_subaddr_index.minor;
auto find_predicate = [&index_minor](const std::pair<uint32_t, std::vector<size_t>>& x) { return x.first == index_minor; };
@@ -9516,7 +9571,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_all(uint64_t below
for (size_t i = 0; i < m_transfers.size(); ++i)
{
const transfer_details& td = m_transfers[i];
- if (!td.m_spent && !td.m_key_image_partial && (use_rct ? true : !td.is_rct()) && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && (subaddr_indices.empty() || subaddr_indices.count(td.m_subaddr_index.minor) == 1))
+ if (!td.m_spent && !td.m_frozen && !td.m_key_image_partial && (use_rct ? true : !td.is_rct()) && is_transfer_unlocked(td) && td.m_subaddr_index.major == subaddr_account && (subaddr_indices.empty() || subaddr_indices.count(td.m_subaddr_index.minor) == 1))
{
fund_found = true;
if (below == 0 || td.amount() < below)
@@ -9564,7 +9619,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_single(const crypt
for (size_t i = 0; i < m_transfers.size(); ++i)
{
const transfer_details& td = m_transfers[i];
- if (td.m_key_image_known && td.m_key_image == ki && !td.m_spent && (use_rct ? true : !td.is_rct()) && is_transfer_unlocked(td))
+ if (td.m_key_image_known && td.m_key_image == ki && !td.m_spent && !td.m_frozen && (use_rct ? true : !td.is_rct()) && is_transfer_unlocked(td))
{
if (td.is_rct() || is_valid_decomposed_amount(td.amount()))
unused_transfers_indices.push_back(i);
@@ -9902,6 +9957,8 @@ std::vector<size_t> wallet2::select_available_outputs(const std::function<bool(c
{
if (i->m_spent)
continue;
+ if (i->m_frozen)
+ continue;
if (i->m_key_image_partial)
continue;
if (!is_transfer_unlocked(*i))
@@ -9917,7 +9974,7 @@ std::vector<uint64_t> wallet2::get_unspent_amounts_vector() const
std::set<uint64_t> set;
for (const auto &td: m_transfers)
{
- if (!td.m_spent)
+ if (!td.m_spent && !td.m_frozen)
set.insert(td.is_rct() ? 0 : td.amount());
}
std::vector<uint64_t> vector;
@@ -10043,7 +10100,7 @@ void wallet2::discard_unmixable_outputs()
std::vector<size_t> unmixable_outputs = select_available_unmixable_outputs();
for (size_t idx : unmixable_outputs)
{
- m_transfers[idx].m_spent = true;
+ freeze(idx);
}
}
@@ -10834,7 +10891,7 @@ std::string wallet2::get_reserve_proof(const boost::optional<std::pair<uint32_t,
for (size_t i = 0; i < m_transfers.size(); ++i)
{
const transfer_details &td = m_transfers[i];
- if (!td.m_spent && (!account_minreserve || account_minreserve->first == td.m_subaddr_index.major))
+ if (!td.m_spent && !td.m_frozen && (!account_minreserve || account_minreserve->first == td.m_subaddr_index.major))
selected_transfers.push_back(i);
}
@@ -11581,6 +11638,8 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag
for(size_t i = 0; i < offset; ++i)
{
const transfer_details &td = m_transfers[i];
+ if (td.m_frozen)
+ continue;
uint64_t amount = td.amount();
if (td.m_spent)
spent += amount;
@@ -11592,6 +11651,8 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag
for(size_t i = 0; i < signed_key_images.size(); ++i)
{
const transfer_details &td = m_transfers[i + offset];
+ if (td.m_frozen)
+ continue;
uint64_t amount = td.amount();
if (td.m_spent)
spent += amount;
diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h
index 28ebd6704..5a67c20d0 100644
--- a/src/wallet/wallet2.h
+++ b/src/wallet/wallet2.h
@@ -266,6 +266,7 @@ namespace tools
size_t m_internal_output_index;
uint64_t m_global_output_index;
bool m_spent;
+ bool m_frozen;
uint64_t m_spent_height;
crypto::key_image m_key_image; //TODO: key_image stored twice :(
rct::key m_mask;
@@ -291,6 +292,7 @@ namespace tools
FIELD(m_internal_output_index)
FIELD(m_global_output_index)
FIELD(m_spent)
+ FIELD(m_frozen)
FIELD(m_spent_height)
FIELD(m_key_image)
FIELD(m_mask)
@@ -1246,6 +1248,14 @@ namespace tools
bool unblackball_output(const std::pair<uint64_t, uint64_t> &output);
bool is_output_blackballed(const std::pair<uint64_t, uint64_t> &output) const;
+ void freeze(size_t idx);
+ void thaw(size_t idx);
+ bool frozen(size_t idx) const;
+ void freeze(const crypto::key_image &ki);
+ void thaw(const crypto::key_image &ki);
+ bool frozen(const crypto::key_image &ki) const;
+ bool frozen(const transfer_details &td) const;
+
// MMS -------------------------------------------------------------------------------------------------
mms::message_store& get_message_store() { return m_message_store; };
const mms::message_store& get_message_store() const { return m_message_store; };
@@ -1328,6 +1338,7 @@ namespace tools
bool get_ring(const crypto::chacha_key &key, const crypto::key_image &key_image, std::vector<uint64_t> &outs);
crypto::chacha_key get_ringdb_key();
void setup_keys(const epee::wipeable_string &password);
+ size_t get_transfer_details(const crypto::key_image &ki) const;
void register_devices();
hw::device& lookup_device(const std::string & device_descriptor);
@@ -1482,7 +1493,7 @@ namespace tools
};
}
BOOST_CLASS_VERSION(tools::wallet2, 28)
-BOOST_CLASS_VERSION(tools::wallet2::transfer_details, 11)
+BOOST_CLASS_VERSION(tools::wallet2::transfer_details, 12)
BOOST_CLASS_VERSION(tools::wallet2::multisig_info, 1)
BOOST_CLASS_VERSION(tools::wallet2::multisig_info::LR, 0)
BOOST_CLASS_VERSION(tools::wallet2::multisig_tx_set, 1)
@@ -1544,6 +1555,10 @@ namespace boost
{
x.m_key_image_request = false;
}
+ if (ver < 12)
+ {
+ x.m_frozen = false;
+ }
}
template <class Archive>
@@ -1632,8 +1647,17 @@ namespace boost
}
a & x.m_key_image_request;
if (ver < 11)
+ {
+ initialize_transfer_details(a, x, ver);
return;
+ }
a & x.m_uses;
+ if (ver < 12)
+ {
+ initialize_transfer_details(a, x, ver);
+ return;
+ }
+ a & x.m_frozen;
}
template <class Archive>