simplewallet: warn about correlations if print-ring-members is not set

The warning about spending more than one output with similar creation
time was skipped if print-ring-members was not set, and it defaults to
false, which means most people probably aren't getting this warning if
they spend correlated outputs.

Reported by SeventhAlpaca.
This commit is contained in:
moneromooo-monero 2020-01-21 19:56:23 +00:00
parent 72262b348a
commit 9989cb087e
No known key found for this signature in database
GPG key ID: 686F07454D6CEFC3
2 changed files with 18 additions and 14 deletions

View file

@ -6064,11 +6064,14 @@ std::pair<std::string, std::string> simple_wallet::show_outputs_line(const std::
return std::make_pair(ostr.str(), ring_str); return std::make_pair(ostr.str(), ring_str);
} }
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
bool simple_wallet::print_ring_members(const std::vector<tools::wallet2::pending_tx>& ptx_vector, std::ostream& ostr) bool simple_wallet::process_ring_members(const std::vector<tools::wallet2::pending_tx>& ptx_vector, std::ostream& ostr, bool verbose)
{ {
uint32_t version; uint32_t version;
if (!try_connect_to_daemon(false, &version)) if (!try_connect_to_daemon(false, &version))
{
fail_msg_writer() << tr("failed to connect to daemon");
return false; return false;
}
// available for RPC version 1.4 or higher // available for RPC version 1.4 or higher
if (version < MAKE_CORE_RPC_VERSION(1, 4)) if (version < MAKE_CORE_RPC_VERSION(1, 4))
return true; return true;
@ -6084,6 +6087,7 @@ bool simple_wallet::print_ring_members(const std::vector<tools::wallet2::pending
{ {
const cryptonote::transaction& tx = ptx_vector[n].tx; const cryptonote::transaction& tx = ptx_vector[n].tx;
const tools::wallet2::tx_construction_data& construction_data = ptx_vector[n].construction_data; const tools::wallet2::tx_construction_data& construction_data = ptx_vector[n].construction_data;
if (verbose)
ostr << boost::format(tr("\nTransaction %llu/%llu: txid=%s")) % (n + 1) % ptx_vector.size() % cryptonote::get_transaction_hash(tx); ostr << boost::format(tr("\nTransaction %llu/%llu: txid=%s")) % (n + 1) % ptx_vector.size() % cryptonote::get_transaction_hash(tx);
// for each input // for each input
std::vector<uint64_t> spent_key_height(tx.vin.size()); std::vector<uint64_t> spent_key_height(tx.vin.size());
@ -6105,6 +6109,7 @@ bool simple_wallet::print_ring_members(const std::vector<tools::wallet2::pending
} }
const cryptonote::tx_source_entry& source = *sptr; const cryptonote::tx_source_entry& source = *sptr;
if (verbose)
ostr << boost::format(tr("\nInput %llu/%llu (%s): amount=%s")) % (i + 1) % tx.vin.size() % epee::string_tools::pod_to_hex(in_key.k_image) % print_money(source.amount); ostr << boost::format(tr("\nInput %llu/%llu (%s): amount=%s")) % (i + 1) % tx.vin.size() % epee::string_tools::pod_to_hex(in_key.k_image) % print_money(source.amount);
// convert relative offsets of ring member keys into absolute offsets (indices) associated with the amount // convert relative offsets of ring member keys into absolute offsets (indices) associated with the amount
std::vector<uint64_t> absolute_offsets = cryptonote::relative_output_offsets_to_absolute(in_key.key_offsets); std::vector<uint64_t> absolute_offsets = cryptonote::relative_output_offsets_to_absolute(in_key.key_offsets);
@ -6135,6 +6140,7 @@ bool simple_wallet::print_ring_members(const std::vector<tools::wallet2::pending
return false; return false;
} }
} }
if (verbose)
ostr << tr("\nOriginating block heights: "); ostr << tr("\nOriginating block heights: ");
spent_key_height[i] = res.outs[source.real_output].height; spent_key_height[i] = res.outs[source.real_output].height;
spent_key_txid [i] = res.outs[source.real_output].txid; spent_key_txid [i] = res.outs[source.real_output].txid;
@ -6144,6 +6150,7 @@ bool simple_wallet::print_ring_members(const std::vector<tools::wallet2::pending
heights[j] = res.outs[j].height; heights[j] = res.outs[j].height;
} }
std::pair<std::string, std::string> ring_str = show_outputs_line(heights, blockchain_height, source.real_output); std::pair<std::string, std::string> ring_str = show_outputs_line(heights, blockchain_height, source.real_output);
if (verbose)
ostr << ring_str.first << tr("\n|") << ring_str.second << tr("|\n"); ostr << ring_str.first << tr("\n|") << ring_str.second << tr("|\n");
} }
// warn if rings contain keys originating from the same tx or temporally very close block heights // warn if rings contain keys originating from the same tx or temporally very close block heights
@ -6163,7 +6170,7 @@ bool simple_wallet::print_ring_members(const std::vector<tools::wallet2::pending
ostr ostr
<< tr("\nWarning: Some input keys being spent are from ") << tr("\nWarning: Some input keys being spent are from ")
<< (are_keys_from_same_tx ? tr("the same transaction") : tr("blocks that are temporally very close")) << (are_keys_from_same_tx ? tr("the same transaction") : tr("blocks that are temporally very close"))
<< tr(", which can break the anonymity of ring signature. Make sure this is intentional!"); << tr(", which can break the anonymity of ring signatures. Make sure this is intentional!");
} }
ostr << ENDL; ostr << ENDL;
} }
@ -6604,11 +6611,8 @@ bool simple_wallet::transfer_main(int transfer_type, const std::vector<std::stri
float days = locked_blocks / 720.0f; float days = locked_blocks / 720.0f;
prompt << boost::format(tr(".\nThis transaction (including %s change) will unlock on block %llu, in approximately %s days (assuming 2 minutes per block)")) % cryptonote::print_money(change) % ((unsigned long long)unlock_block) % days; prompt << boost::format(tr(".\nThis transaction (including %s change) will unlock on block %llu, in approximately %s days (assuming 2 minutes per block)")) % cryptonote::print_money(change) % ((unsigned long long)unlock_block) % days;
} }
if (m_wallet->print_ring_members()) if (!process_ring_members(ptx_vector, prompt, m_wallet->print_ring_members()))
{
if (!print_ring_members(ptx_vector, prompt))
return false; return false;
}
bool default_ring_size = true; bool default_ring_size = true;
for (const auto &ptx: ptx_vector) for (const auto &ptx: ptx_vector)
{ {
@ -7064,7 +7068,7 @@ bool simple_wallet::sweep_main(uint64_t below, bool locked, const std::vector<st
if (subaddr_indices.size() > 1) if (subaddr_indices.size() > 1)
prompt << tr("WARNING: Outputs of multiple addresses are being used together, which might potentially compromise your privacy.\n"); prompt << tr("WARNING: Outputs of multiple addresses are being used together, which might potentially compromise your privacy.\n");
} }
if (m_wallet->print_ring_members() && !print_ring_members(ptx_vector, prompt)) if (!process_ring_members(ptx_vector, prompt, m_wallet->print_ring_members()))
return true; return true;
if (ptx_vector.size() > 1) { if (ptx_vector.size() > 1) {
prompt << boost::format(tr("Sweeping %s in %llu transactions for a total fee of %s. Is this okay?")) % prompt << boost::format(tr("Sweeping %s in %llu transactions for a total fee of %s. Is this okay?")) %
@ -7308,7 +7312,7 @@ bool simple_wallet::sweep_single(const std::vector<std::string> &args_)
uint64_t total_fee = ptx_vector[0].fee; uint64_t total_fee = ptx_vector[0].fee;
uint64_t total_sent = m_wallet->get_transfer_details(ptx_vector[0].selected_transfers.front()).amount(); uint64_t total_sent = m_wallet->get_transfer_details(ptx_vector[0].selected_transfers.front()).amount();
std::ostringstream prompt; std::ostringstream prompt;
if (!print_ring_members(ptx_vector, prompt)) if (!process_ring_members(ptx_vector, prompt, m_wallet->print_ring_members()))
return true; return true;
prompt << boost::format(tr("Sweeping %s for a total fee of %s. Is this okay?")) % prompt << boost::format(tr("Sweeping %s for a total fee of %s. Is this okay?")) %
print_money(total_sent) % print_money(total_sent) %

View file

@ -270,7 +270,7 @@ namespace cryptonote
bool accept_loaded_tx(const std::function<size_t()> get_num_txes, const std::function<const tools::wallet2::tx_construction_data&(size_t)> &get_tx, const std::string &extra_message = std::string()); bool accept_loaded_tx(const std::function<size_t()> get_num_txes, const std::function<const tools::wallet2::tx_construction_data&(size_t)> &get_tx, const std::string &extra_message = std::string());
bool accept_loaded_tx(const tools::wallet2::unsigned_tx_set &txs); bool accept_loaded_tx(const tools::wallet2::unsigned_tx_set &txs);
bool accept_loaded_tx(const tools::wallet2::signed_tx_set &txs); bool accept_loaded_tx(const tools::wallet2::signed_tx_set &txs);
bool print_ring_members(const std::vector<tools::wallet2::pending_tx>& ptx_vector, std::ostream& ostr); bool process_ring_members(const std::vector<tools::wallet2::pending_tx>& ptx_vector, std::ostream& ostr, bool verbose);
std::string get_prompt() const; std::string get_prompt() const;
bool print_seed(bool encrypted); bool print_seed(bool encrypted);
void key_images_sync_intern(); void key_images_sync_intern();