aboutsummaryrefslogtreecommitdiff
path: root/src/wallet/wallet2.cpp
diff options
context:
space:
mode:
authormoneromooo-monero <moneromooo-monero@users.noreply.github.com>2019-03-13 21:51:41 +0000
committermoneromooo-monero <moneromooo-monero@users.noreply.github.com>2019-03-22 09:19:24 +0000
commit18faa6da0c868720d78d985e64cd60b30932b5c7 (patch)
treeebcdd15b491bf00801d11c65f973d8fd172dcf78 /src/wallet/wallet2.cpp
parentMerge pull request #5267 (diff)
downloadmonero-18faa6da0c868720d78d985e64cd60b30932b5c7.tar.xz
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.
Diffstat (limited to 'src/wallet/wallet2.cpp')
-rw-r--r--src/wallet/wallet2.cpp85
1 files changed, 73 insertions, 12 deletions
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp
index a46da42db..47f9b6de8 100644
--- a/src/wallet/wallet2.cpp
+++ b/src/wallet/wallet2.cpp
@@ -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;