mirror of
https://github.com/monero-project/monero.git
synced 2024-12-23 20:19:34 +00:00
wallet: add freeze/thaw/frozen commands
These commands let one freeze outputs by key image, so they do not appear in balance, nor are considered when creating a transaction, etc This is helpful when receiving an output from a suspected spy, who might try to track your other outputs by seeing with what other outputs it gets spent. The frozen command may be used without parameters to list all currently frozen outputs.
This commit is contained in:
parent
cd776b1933
commit
18faa6da0c
4 changed files with 188 additions and 16 deletions
|
@ -237,6 +237,9 @@ namespace
|
||||||
const char* USAGE_MARK_OUTPUT_SPENT("mark_output_spent <amount>/<offset> | <filename> [add]");
|
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_MARK_OUTPUT_UNSPENT("mark_output_unspent <amount>/<offset>");
|
||||||
const char* USAGE_IS_OUTPUT_SPENT("is_output_spent <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_VERSION("version");
|
||||||
const char* USAGE_HELP("help [<command>]");
|
const char* USAGE_HELP("help [<command>]");
|
||||||
|
|
||||||
|
@ -2025,6 +2028,74 @@ bool simple_wallet::save_known_rings(const std::vector<std::string> &args)
|
||||||
return true;
|
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)
|
bool simple_wallet::version(const std::vector<std::string> &args)
|
||||||
{
|
{
|
||||||
message_writer() << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")";
|
message_writer() << "Monero '" << MONERO_RELEASE_NAME << "' (v" << MONERO_VERSION_FULL << ")";
|
||||||
|
@ -2600,7 +2671,7 @@ simple_wallet::simple_wallet()
|
||||||
tr(USAGE_INCOMING_TRANSFERS),
|
tr(USAGE_INCOMING_TRANSFERS),
|
||||||
tr("Show the incoming transfers, all or filtered by availability and address index.\n\n"
|
tr("Show the incoming transfers, all or filtered by availability and address index.\n\n"
|
||||||
"Output format:\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",
|
m_cmd_binder.set_handler("payments",
|
||||||
boost::bind(&simple_wallet::show_payments, this, _1),
|
boost::bind(&simple_wallet::show_payments, this, _1),
|
||||||
tr(USAGE_PAYMENTS),
|
tr(USAGE_PAYMENTS),
|
||||||
|
@ -3012,6 +3083,18 @@ simple_wallet::simple_wallet()
|
||||||
boost::bind(&simple_wallet::blackballed, this, _1),
|
boost::bind(&simple_wallet::blackballed, this, _1),
|
||||||
tr(USAGE_IS_OUTPUT_SPENT),
|
tr(USAGE_IS_OUTPUT_SPENT),
|
||||||
tr("Checks whether an output is marked as 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",
|
m_cmd_binder.set_handler("version",
|
||||||
boost::bind(&simple_wallet::version, this, _1),
|
boost::bind(&simple_wallet::version, this, _1),
|
||||||
tr(USAGE_VERSION),
|
tr(USAGE_VERSION),
|
||||||
|
@ -4987,7 +5070,7 @@ bool simple_wallet::show_incoming_transfers(const std::vector<std::string>& args
|
||||||
boost::format("%21s%8s%12s%8s%16u%68s%16u%s") %
|
boost::format("%21s%8s%12s%8s%16u%68s%16u%s") %
|
||||||
print_money(td.amount()) %
|
print_money(td.amount()) %
|
||||||
(td.m_spent ? tr("T") : tr("F")) %
|
(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.is_rct() ? tr("RingCT") : tr("-")) %
|
||||||
td.m_global_output_index %
|
td.m_global_output_index %
|
||||||
td.m_txid %
|
td.m_txid %
|
||||||
|
|
|
@ -238,9 +238,12 @@ namespace cryptonote
|
||||||
bool blackball(const std::vector<std::string>& args);
|
bool blackball(const std::vector<std::string>& args);
|
||||||
bool unblackball(const std::vector<std::string>& args);
|
bool unblackball(const std::vector<std::string>& args);
|
||||||
bool blackballed(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 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);
|
uint64_t get_daemon_blockchain_height(std::string& err);
|
||||||
bool try_connect_to_daemon(bool silent = false, uint32_t* version = nullptr);
|
bool try_connect_to_daemon(bool silent = false, uint32_t* version = nullptr);
|
||||||
bool ask_wallet_create_if_needed();
|
bool ask_wallet_create_if_needed();
|
||||||
|
@ -253,6 +256,7 @@ namespace cryptonote
|
||||||
void key_images_sync_intern();
|
void key_images_sync_intern();
|
||||||
void on_refresh_finished(uint64_t start_height, uint64_t fetched_blocks, bool is_init, bool received_money);
|
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;
|
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
|
struct transfer_view
|
||||||
{
|
{
|
||||||
|
|
|
@ -1392,6 +1392,58 @@ void wallet2::set_unspent(size_t idx)
|
||||||
td.m_spent_height = 0;
|
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
|
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();
|
hw::device &hwdev = m_account.get_device();
|
||||||
|
@ -1809,6 +1861,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
|
||||||
td.m_mask = rct::identity();
|
td.m_mask = rct::identity();
|
||||||
td.m_rct = false;
|
td.m_rct = false;
|
||||||
}
|
}
|
||||||
|
td.m_frozen = false;
|
||||||
set_unspent(m_transfers.size()-1);
|
set_unspent(m_transfers.size()-1);
|
||||||
if (td.m_key_image_known)
|
if (td.m_key_image_known)
|
||||||
m_key_images[td.m_key_image] = m_transfers.size()-1;
|
m_key_images[td.m_key_image] = m_transfers.size()-1;
|
||||||
|
@ -3156,8 +3209,9 @@ void wallet2::detach_blockchain(uint64_t height)
|
||||||
wallet2::transfer_details &td = m_transfers[i];
|
wallet2::transfer_details &td = m_transfers[i];
|
||||||
if (td.m_spent && td.m_spent_height >= height)
|
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);
|
set_unspent(i);
|
||||||
|
thaw(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5331,7 +5385,7 @@ std::map<uint32_t, uint64_t> wallet2::balance_per_subaddress(uint32_t index_majo
|
||||||
std::map<uint32_t, uint64_t> amount_per_subaddr;
|
std::map<uint32_t, uint64_t> amount_per_subaddr;
|
||||||
for (const auto& td: m_transfers)
|
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);
|
auto found = amount_per_subaddr.find(td.m_subaddr_index.minor);
|
||||||
if (found == amount_per_subaddr.end())
|
if (found == amount_per_subaddr.end())
|
||||||
|
@ -5360,7 +5414,7 @@ std::map<uint32_t, uint64_t> wallet2::unlocked_balance_per_subaddress(uint32_t i
|
||||||
std::map<uint32_t, uint64_t> amount_per_subaddr;
|
std::map<uint32_t, uint64_t> amount_per_subaddr;
|
||||||
for(const transfer_details& td: m_transfers)
|
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);
|
auto found = amount_per_subaddr.find(td.m_subaddr_index.minor);
|
||||||
if (found == amount_per_subaddr.end())
|
if (found == amount_per_subaddr.end())
|
||||||
|
@ -8264,7 +8318,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)
|
for (size_t i = 0; i < m_transfers.size(); ++i)
|
||||||
{
|
{
|
||||||
const transfer_details& td = m_transfers[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()));
|
LOG_PRINT_L2("We can use " << i << " alone: " << print_money(td.amount()));
|
||||||
picks.push_back(i);
|
picks.push_back(i);
|
||||||
|
@ -8279,13 +8333,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)
|
for (size_t i = 0; i < m_transfers.size(); ++i)
|
||||||
{
|
{
|
||||||
const transfer_details& td = m_transfers[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()));
|
LOG_PRINT_L2("Considering input " << i << ", " << print_money(td.amount()));
|
||||||
for (size_t j = i + 1; j < m_transfers.size(); ++j)
|
for (size_t j = i + 1; j < m_transfers.size(); ++j)
|
||||||
{
|
{
|
||||||
const transfer_details& td2 = m_transfers[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
|
// update our picks if those outputs are less related than any we
|
||||||
// already found. If the same, don't update, and oldest suitable outputs
|
// already found. If the same, don't update, and oldest suitable outputs
|
||||||
|
@ -8512,6 +8566,7 @@ void wallet2::light_wallet_get_unspent_outs()
|
||||||
td.m_pk_index = 0;
|
td.m_pk_index = 0;
|
||||||
td.m_internal_output_index = o.index;
|
td.m_internal_output_index = o.index;
|
||||||
td.m_spent = spent;
|
td.m_spent = spent;
|
||||||
|
td.m_frozen = false;
|
||||||
|
|
||||||
tx_out txout;
|
tx_out txout;
|
||||||
txout.target = txout_to_key(public_key);
|
txout.target = txout_to_key(public_key);
|
||||||
|
@ -8986,7 +9041,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));
|
MDEBUG("Ignoring output " << i << " of amount " << print_money(td.amount()) << " which is below threshold " << print_money(fractional_threshold));
|
||||||
continue;
|
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;
|
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; };
|
auto find_predicate = [&index_minor](const std::pair<uint32_t, std::vector<size_t>>& x) { return x.first == index_minor; };
|
||||||
|
@ -9466,7 +9521,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_all(uint64_t below
|
||||||
for (size_t i = 0; i < m_transfers.size(); ++i)
|
for (size_t i = 0; i < m_transfers.size(); ++i)
|
||||||
{
|
{
|
||||||
const transfer_details& td = m_transfers[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;
|
fund_found = true;
|
||||||
if (below == 0 || td.amount() < below)
|
if (below == 0 || td.amount() < below)
|
||||||
|
@ -9514,7 +9569,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_single(const crypt
|
||||||
for (size_t i = 0; i < m_transfers.size(); ++i)
|
for (size_t i = 0; i < m_transfers.size(); ++i)
|
||||||
{
|
{
|
||||||
const transfer_details& td = m_transfers[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()))
|
if (td.is_rct() || is_valid_decomposed_amount(td.amount()))
|
||||||
unused_transfers_indices.push_back(i);
|
unused_transfers_indices.push_back(i);
|
||||||
|
@ -9846,6 +9901,8 @@ std::vector<size_t> wallet2::select_available_outputs(const std::function<bool(c
|
||||||
{
|
{
|
||||||
if (i->m_spent)
|
if (i->m_spent)
|
||||||
continue;
|
continue;
|
||||||
|
if (i->m_frozen)
|
||||||
|
continue;
|
||||||
if (i->m_key_image_partial)
|
if (i->m_key_image_partial)
|
||||||
continue;
|
continue;
|
||||||
if (!is_transfer_unlocked(*i))
|
if (!is_transfer_unlocked(*i))
|
||||||
|
@ -9861,7 +9918,7 @@ std::vector<uint64_t> wallet2::get_unspent_amounts_vector() const
|
||||||
std::set<uint64_t> set;
|
std::set<uint64_t> set;
|
||||||
for (const auto &td: m_transfers)
|
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());
|
set.insert(td.is_rct() ? 0 : td.amount());
|
||||||
}
|
}
|
||||||
std::vector<uint64_t> vector;
|
std::vector<uint64_t> vector;
|
||||||
|
@ -9987,7 +10044,7 @@ void wallet2::discard_unmixable_outputs()
|
||||||
std::vector<size_t> unmixable_outputs = select_available_unmixable_outputs();
|
std::vector<size_t> unmixable_outputs = select_available_unmixable_outputs();
|
||||||
for (size_t idx : unmixable_outputs)
|
for (size_t idx : unmixable_outputs)
|
||||||
{
|
{
|
||||||
m_transfers[idx].m_spent = true;
|
freeze(idx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -10770,7 +10827,7 @@ std::string wallet2::get_reserve_proof(const boost::optional<std::pair<uint32_t,
|
||||||
for (size_t i = 0; i < m_transfers.size(); ++i)
|
for (size_t i = 0; i < m_transfers.size(); ++i)
|
||||||
{
|
{
|
||||||
const transfer_details &td = m_transfers[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);
|
selected_transfers.push_back(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11517,6 +11574,8 @@ uint64_t wallet2::import_key_images(const std::vector<std::pair<crypto::key_imag
|
||||||
for(size_t i = 0; i < offset; ++i)
|
for(size_t i = 0; i < offset; ++i)
|
||||||
{
|
{
|
||||||
const transfer_details &td = m_transfers[i];
|
const transfer_details &td = m_transfers[i];
|
||||||
|
if (td.m_frozen)
|
||||||
|
continue;
|
||||||
uint64_t amount = td.amount();
|
uint64_t amount = td.amount();
|
||||||
if (td.m_spent)
|
if (td.m_spent)
|
||||||
spent += amount;
|
spent += amount;
|
||||||
|
@ -11528,6 +11587,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)
|
for(size_t i = 0; i < signed_key_images.size(); ++i)
|
||||||
{
|
{
|
||||||
const transfer_details &td = m_transfers[i + offset];
|
const transfer_details &td = m_transfers[i + offset];
|
||||||
|
if (td.m_frozen)
|
||||||
|
continue;
|
||||||
uint64_t amount = td.amount();
|
uint64_t amount = td.amount();
|
||||||
if (td.m_spent)
|
if (td.m_spent)
|
||||||
spent += amount;
|
spent += amount;
|
||||||
|
|
|
@ -265,6 +265,7 @@ namespace tools
|
||||||
size_t m_internal_output_index;
|
size_t m_internal_output_index;
|
||||||
uint64_t m_global_output_index;
|
uint64_t m_global_output_index;
|
||||||
bool m_spent;
|
bool m_spent;
|
||||||
|
bool m_frozen;
|
||||||
uint64_t m_spent_height;
|
uint64_t m_spent_height;
|
||||||
crypto::key_image m_key_image; //TODO: key_image stored twice :(
|
crypto::key_image m_key_image; //TODO: key_image stored twice :(
|
||||||
rct::key m_mask;
|
rct::key m_mask;
|
||||||
|
@ -290,6 +291,7 @@ namespace tools
|
||||||
FIELD(m_internal_output_index)
|
FIELD(m_internal_output_index)
|
||||||
FIELD(m_global_output_index)
|
FIELD(m_global_output_index)
|
||||||
FIELD(m_spent)
|
FIELD(m_spent)
|
||||||
|
FIELD(m_frozen)
|
||||||
FIELD(m_spent_height)
|
FIELD(m_spent_height)
|
||||||
FIELD(m_key_image)
|
FIELD(m_key_image)
|
||||||
FIELD(m_mask)
|
FIELD(m_mask)
|
||||||
|
@ -1243,6 +1245,14 @@ namespace tools
|
||||||
bool unblackball_output(const std::pair<uint64_t, uint64_t> &output);
|
bool unblackball_output(const std::pair<uint64_t, uint64_t> &output);
|
||||||
bool is_output_blackballed(const std::pair<uint64_t, uint64_t> &output) const;
|
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 -------------------------------------------------------------------------------------------------
|
||||||
mms::message_store& get_message_store() { return m_message_store; };
|
mms::message_store& get_message_store() { return m_message_store; };
|
||||||
const mms::message_store& get_message_store() const { return m_message_store; };
|
const mms::message_store& get_message_store() const { return m_message_store; };
|
||||||
|
@ -1325,6 +1335,7 @@ namespace tools
|
||||||
bool get_ring(const crypto::chacha_key &key, const crypto::key_image &key_image, std::vector<uint64_t> &outs);
|
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();
|
crypto::chacha_key get_ringdb_key();
|
||||||
void setup_keys(const epee::wipeable_string &password);
|
void setup_keys(const epee::wipeable_string &password);
|
||||||
|
size_t get_transfer_details(const crypto::key_image &ki) const;
|
||||||
|
|
||||||
void register_devices();
|
void register_devices();
|
||||||
hw::device& lookup_device(const std::string & device_descriptor);
|
hw::device& lookup_device(const std::string & device_descriptor);
|
||||||
|
@ -1479,7 +1490,7 @@ namespace tools
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
BOOST_CLASS_VERSION(tools::wallet2, 28)
|
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, 1)
|
||||||
BOOST_CLASS_VERSION(tools::wallet2::multisig_info::LR, 0)
|
BOOST_CLASS_VERSION(tools::wallet2::multisig_info::LR, 0)
|
||||||
BOOST_CLASS_VERSION(tools::wallet2::multisig_tx_set, 1)
|
BOOST_CLASS_VERSION(tools::wallet2::multisig_tx_set, 1)
|
||||||
|
@ -1541,6 +1552,10 @@ namespace boost
|
||||||
{
|
{
|
||||||
x.m_key_image_request = false;
|
x.m_key_image_request = false;
|
||||||
}
|
}
|
||||||
|
if (ver < 12)
|
||||||
|
{
|
||||||
|
x.m_frozen = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Archive>
|
template <class Archive>
|
||||||
|
@ -1629,8 +1644,17 @@ namespace boost
|
||||||
}
|
}
|
||||||
a & x.m_key_image_request;
|
a & x.m_key_image_request;
|
||||||
if (ver < 11)
|
if (ver < 11)
|
||||||
|
{
|
||||||
|
initialize_transfer_details(a, x, ver);
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
a & x.m_uses;
|
a & x.m_uses;
|
||||||
|
if (ver < 12)
|
||||||
|
{
|
||||||
|
initialize_transfer_details(a, x, ver);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
a & x.m_frozen;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Archive>
|
template <class Archive>
|
||||||
|
|
Loading…
Reference in a new issue