mirror of
https://github.com/monero-project/monero.git
synced 2024-10-01 11:49:47 -04:00
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
40530b294e
commit
58f28cadf8
@ -1030,6 +1030,16 @@ void wallet2::check_acc_out_precomp(const tx_out &o, const crypto::key_derivatio
|
|||||||
tx_scan_info.error = false;
|
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, 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, 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)
|
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;
|
crypto::secret_key scalar1;
|
||||||
@ -1110,7 +1120,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
|
// Don't try to extract tx public key if tx has no ouputs
|
||||||
size_t pk_index = 0;
|
size_t pk_index = 0;
|
||||||
std::vector<tx_scan_info_t> tx_scan_info(tx.vout.size());
|
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())
|
while (!tx.vout.empty())
|
||||||
{
|
{
|
||||||
// if tx.vout is not empty, we loop through all tx pubkeys
|
// if tx.vout is not empty, we loop through all tx pubkeys
|
||||||
@ -1126,13 +1136,6 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
int num_vouts_received = 0;
|
||||||
tx_pub_key = pub_key_field.pub_key;
|
tx_pub_key = pub_key_field.pub_key;
|
||||||
tools::threadpool& tpool = tools::threadpool::getInstance();
|
tools::threadpool& tpool = tools::threadpool::getInstance();
|
||||||
@ -1172,7 +1175,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
|
|||||||
}
|
}
|
||||||
else if (miner_tx && m_refresh_type == RefreshOptimizeCoinbase)
|
else if (miner_tx && m_refresh_type == RefreshOptimizeCoinbase)
|
||||||
{
|
{
|
||||||
check_acc_out_precomp(tx.vout[0], derivation, additional_derivations, 0, tx_scan_info[0]);
|
check_acc_out_precomp_once(tx.vout[0], derivation, additional_derivations, 0, 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());
|
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
|
// this assumes that the miner tx pays a single address
|
||||||
@ -1182,8 +1185,8 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
|
|||||||
// the first one was already checked
|
// the first one was already checked
|
||||||
for (size_t i = 1; i < tx.vout.size(); ++i)
|
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,
|
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::ref(tx_scan_info[i])));
|
std::ref(tx_scan_info[i]), std::ref(output_found[i])));
|
||||||
}
|
}
|
||||||
waiter.wait();
|
waiter.wait();
|
||||||
// then scan all outputs from 0
|
// then scan all outputs from 0
|
||||||
@ -1205,8 +1208,8 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
|
|||||||
{
|
{
|
||||||
for (size_t i = 0; i < tx.vout.size(); ++i)
|
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,
|
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::ref(tx_scan_info[i])));
|
std::ref(tx_scan_info[i]), std::ref(output_found[i])));
|
||||||
}
|
}
|
||||||
waiter.wait();
|
waiter.wait();
|
||||||
|
|
||||||
@ -1227,7 +1230,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote
|
|||||||
{
|
{
|
||||||
for (size_t i = 0; i < tx.vout.size(); ++i)
|
for (size_t i = 0; i < tx.vout.size(); ++i)
|
||||||
{
|
{
|
||||||
check_acc_out_precomp(tx.vout[i], derivation, additional_derivations, i, tx_scan_info[i]);
|
check_acc_out_precomp_once(tx.vout[i], derivation, additional_derivations, i, 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());
|
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)
|
if (tx_scan_info[i].received)
|
||||||
{
|
{
|
||||||
|
@ -1112,6 +1112,7 @@ namespace tools
|
|||||||
bool generate_chacha_key_from_secret_keys(crypto::chacha_key &key) const;
|
bool generate_chacha_key_from_secret_keys(crypto::chacha_key &key) const;
|
||||||
crypto::hash get_payment_id(const pending_tx &ptx) const;
|
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, 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, 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;
|
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;
|
uint64_t get_upper_transaction_size_limit() const;
|
||||||
std::vector<uint64_t> get_unspent_amounts_vector() const;
|
std::vector<uint64_t> get_unspent_amounts_vector() const;
|
||||||
|
Loading…
Reference in New Issue
Block a user