mirror of
https://github.com/monero-project/monero.git
synced 2026-07-30 23:50:24 -07: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:
+73
-12
@@ -1392,6 +1392,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();
|
||||
@@ -1809,6 +1861,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;
|
||||
@@ -3156,8 +3209,9 @@ void wallet2::detach_blockchain(uint64_t height)
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
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())
|
||||
@@ -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;
|
||||
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())
|
||||
@@ -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)
|
||||
{
|
||||
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);
|
||||
@@ -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)
|
||||
{
|
||||
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
|
||||
@@ -8512,6 +8566,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);
|
||||
@@ -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));
|
||||
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; };
|
||||
@@ -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)
|
||||
{
|
||||
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)
|
||||
@@ -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)
|
||||
{
|
||||
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);
|
||||
@@ -9846,6 +9901,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))
|
||||
@@ -9861,7 +9918,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;
|
||||
@@ -9987,7 +10044,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
const transfer_details &td = m_transfers[i];
|
||||
if (td.m_frozen)
|
||||
continue;
|
||||
uint64_t amount = td.amount();
|
||||
if (td.m_spent)
|
||||
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)
|
||||
{
|
||||
const transfer_details &td = m_transfers[i + offset];
|
||||
if (td.m_frozen)
|
||||
continue;
|
||||
uint64_t amount = td.amount();
|
||||
if (td.m_spent)
|
||||
spent += amount;
|
||||
|
||||
Reference in New Issue
Block a user