wallet2: ensure outputs are processed only once
This should be proof against any way one might get to multiple processing, such as generating the same derivation from the same pubkey, etc
This commit is contained in:
parent
eed4dba880
commit
fc39d3b23c
@ -1057,6 +1057,16 @@ void wallet2::check_acc_out_precomp(const tx_out &o, const crypto::key_derivatio
|
||||
tx_scan_info.error = false;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
void wallet2::check_acc_out_precomp_once(const tx_out &o, const crypto::key_derivation &derivation, const std::vector<crypto::key_derivation> &additional_derivations, size_t i, const is_out_data *is_out_data, tx_scan_info_t &tx_scan_info, bool &already_seen) const
|
||||
{
|
||||
tx_scan_info.received = boost::none;
|
||||
if (already_seen)
|
||||
return;
|
||||
check_acc_out_precomp(o, derivation, additional_derivations, i, is_out_data, tx_scan_info);
|
||||
if (tx_scan_info.received)
|
||||
already_seen = true;
|
||||
}
|
||||
//----------------------------------------------------------------------------------------------------
|
||||
static uint64_t decodeRct(const rct::rctSig & rv, const crypto::key_derivation &derivation, unsigned int i, rct::key & mask, hw::device &hwdev)
|
||||
{
|
||||
crypto::secret_key scalar1;
|
||||
@ -1173,7 +1183,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
|
||||
// Don't try to extract tx public key if tx has no ouputs
|
||||
size_t pk_index = 0;
|
||||
std::vector<tx_scan_info_t> tx_scan_info(tx.vout.size());
|
||||
std::unordered_set<crypto::public_key> public_keys_seen;
|
||||
std::deque<bool> output_found(tx.vout.size(), false);
|
||||
while (!tx.vout.empty())
|
||||
{
|
||||
// if tx.vout is not empty, we loop through all tx pubkeys
|
||||
@ -1194,13 +1204,6 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
|
||||
error::wallet_internal_error, "tx_cache_data is out of sync");
|
||||
}
|
||||
|
||||
if (public_keys_seen.find(pub_key_field.pub_key) != public_keys_seen.end())
|
||||
{
|
||||
MWARNING("The same transaction pubkey is present more than once, ignoring extra instance");
|
||||
continue;
|
||||
}
|
||||
public_keys_seen.insert(pub_key_field.pub_key);
|
||||
|
||||
int num_vouts_received = 0;
|
||||
tx_pub_key = pub_key_field.pub_key;
|
||||
tools::threadpool& tpool = tools::threadpool::getInstance();
|
||||
@ -1264,7 +1267,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
|
||||
}
|
||||
else if (miner_tx && m_refresh_type == RefreshOptimizeCoinbase)
|
||||
{
|
||||
check_acc_out_precomp(tx.vout[0], derivation, additional_derivations, 0, is_out_data_ptr, tx_scan_info[0]);
|
||||
check_acc_out_precomp_once(tx.vout[0], derivation, additional_derivations, 0, is_out_data_ptr, tx_scan_info[0], output_found[0]);
|
||||
THROW_WALLET_EXCEPTION_IF(tx_scan_info[0].error, error::acc_outs_lookup_error, tx, tx_pub_key, m_account.get_keys());
|
||||
|
||||
// this assumes that the miner tx pays a single address
|
||||
@ -1274,8 +1277,8 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
|
||||
// the first one was already checked
|
||||
for (size_t i = 1; i < tx.vout.size(); ++i)
|
||||
{
|
||||
tpool.submit(&waiter, boost::bind(&wallet2::check_acc_out_precomp, this, std::cref(tx.vout[i]), std::cref(derivation), std::cref(additional_derivations), i,
|
||||
std::cref(is_out_data_ptr), std::ref(tx_scan_info[i])), true);
|
||||
tpool.submit(&waiter, boost::bind(&wallet2::check_acc_out_precomp_once, this, std::cref(tx.vout[i]), std::cref(derivation), std::cref(additional_derivations), i,
|
||||
std::cref(is_out_data_ptr), std::ref(tx_scan_info[i]), std::ref(output_found[i])), true);
|
||||
}
|
||||
waiter.wait(&tpool);
|
||||
// then scan all outputs from 0
|
||||
@ -1297,8 +1300,8 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
|
||||
{
|
||||
for (size_t i = 0; i < tx.vout.size(); ++i)
|
||||
{
|
||||
tpool.submit(&waiter, boost::bind(&wallet2::check_acc_out_precomp, this, std::cref(tx.vout[i]), std::cref(derivation), std::cref(additional_derivations), i,
|
||||
std::cref(is_out_data_ptr), std::ref(tx_scan_info[i])), true);
|
||||
tpool.submit(&waiter, boost::bind(&wallet2::check_acc_out_precomp_once, this, std::cref(tx.vout[i]), std::cref(derivation), std::cref(additional_derivations), i,
|
||||
std::cref(is_out_data_ptr), std::ref(tx_scan_info[i]), std::ref(output_found[i])), true);
|
||||
}
|
||||
waiter.wait(&tpool);
|
||||
|
||||
@ -1319,7 +1322,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
|
||||
{
|
||||
for (size_t i = 0; i < tx.vout.size(); ++i)
|
||||
{
|
||||
check_acc_out_precomp(tx.vout[i], derivation, additional_derivations, i, is_out_data_ptr, tx_scan_info[i]);
|
||||
check_acc_out_precomp_once(tx.vout[i], derivation, additional_derivations, i, is_out_data_ptr, tx_scan_info[i], output_found[i]);
|
||||
THROW_WALLET_EXCEPTION_IF(tx_scan_info[i].error, error::acc_outs_lookup_error, tx, tx_pub_key, m_account.get_keys());
|
||||
if (tx_scan_info[i].received)
|
||||
{
|
||||
|
@ -1181,6 +1181,7 @@ namespace tools
|
||||
crypto::hash get_payment_id(const pending_tx &ptx) const;
|
||||
void check_acc_out_precomp(const cryptonote::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 check_acc_out_precomp(const cryptonote::tx_out &o, const crypto::key_derivation &derivation, const std::vector<crypto::key_derivation> &additional_derivations, size_t i, const is_out_data *is_out_data, tx_scan_info_t &tx_scan_info) const;
|
||||
void check_acc_out_precomp_once(const cryptonote::tx_out &o, const crypto::key_derivation &derivation, const std::vector<crypto::key_derivation> &additional_derivations, size_t i, const is_out_data *is_out_data, tx_scan_info_t &tx_scan_info, bool &already_seen) const;
|
||||
void parse_block_round(const cryptonote::blobdata &blob, cryptonote::block &bl, crypto::hash &bl_id, bool &error) const;
|
||||
uint64_t get_upper_transaction_size_limit() const;
|
||||
std::vector<uint64_t> get_unspent_amounts_vector() const;
|
||||
|
Loading…
Reference in New Issue
Block a user