From fa2fbc3917774ee9615e1bcf1437d57ab400018f Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Thu, 28 Feb 2019 18:44:35 +0000 Subject: [PATCH] wallet2: fix mishandling rct outputs in coinbase tx Reported by cutcoin --- src/wallet/wallet2.cpp | 18 ++++++++++++------ src/wallet/wallet2.h | 2 +- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index c02d10ab4..9b976e55f 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -1426,7 +1426,7 @@ static uint64_t decodeRct(const rct::rctSig & rv, const crypto::key_derivation & } } //---------------------------------------------------------------------------------------------------- -void wallet2::scan_output(const cryptonote::transaction &tx, const crypto::public_key &tx_pub_key, size_t i, tx_scan_info_t &tx_scan_info, int &num_vouts_received, std::unordered_map &tx_money_got_in_outs, std::vector &outs, bool pool) +void wallet2::scan_output(const cryptonote::transaction &tx, bool miner_tx, const crypto::public_key &tx_pub_key, size_t i, tx_scan_info_t &tx_scan_info, int &num_vouts_received, std::unordered_map &tx_money_got_in_outs, std::vector &outs, bool pool) { THROW_WALLET_EXCEPTION_IF(i >= tx.vout.size(), error::wallet_internal_error, "Invalid vout index"); @@ -1459,11 +1459,14 @@ void wallet2::scan_output(const cryptonote::transaction &tx, const crypto::publi error::wallet_internal_error, "key_image generated ephemeral public key not matched with output_key"); } + THROW_WALLET_EXCEPTION_IF(std::find(outs.begin(), outs.end(), i) != outs.end(), error::wallet_internal_error, "Same output cannot be added twice"); outs.push_back(i); - if (tx_scan_info.money_transfered == 0) + if (tx_scan_info.money_transfered == 0 && !miner_tx) { tx_scan_info.money_transfered = tools::decodeRct(tx.rct_signatures, tx_scan_info.received->derivation, i, tx_scan_info.mask, m_account.get_device()); } + THROW_WALLET_EXCEPTION_IF(tx_money_got_in_outs[tx_scan_info.received->index] >= std::numeric_limits::max() - tx_scan_info.money_transfered, + error::wallet_internal_error, "Overflow in received amounts"); tx_money_got_in_outs[tx_scan_info.received->index] += tx_scan_info.money_transfered; tx_scan_info.amount = tx_scan_info.money_transfered; ++num_vouts_received; @@ -1641,7 +1644,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote if (tx_scan_info[i].received) { hwdev.conceal_derivation(tx_scan_info[i].received->derivation, tx_pub_key, additional_tx_pub_keys.data, derivation, additional_derivations); - scan_output(tx, tx_pub_key, i, tx_scan_info[i], num_vouts_received, tx_money_got_in_outs, outs, pool); + scan_output(tx, miner_tx, tx_pub_key, i, tx_scan_info[i], num_vouts_received, tx_money_got_in_outs, outs, pool); } } } @@ -1664,7 +1667,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote if (tx_scan_info[i].received) { hwdev.conceal_derivation(tx_scan_info[i].received->derivation, tx_pub_key, additional_tx_pub_keys.data, derivation, additional_derivations); - scan_output(tx, tx_pub_key, i, tx_scan_info[i], num_vouts_received, tx_money_got_in_outs, outs, pool); + scan_output(tx, miner_tx, tx_pub_key, i, tx_scan_info[i], num_vouts_received, tx_money_got_in_outs, outs, pool); } } } @@ -1680,7 +1683,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote boost::unique_lock hwdev_lock (hwdev); hwdev.set_mode(hw::device::NONE); hwdev.conceal_derivation(tx_scan_info[i].received->derivation, tx_pub_key, additional_tx_pub_keys.data, derivation, additional_derivations); - scan_output(tx, tx_pub_key, i, tx_scan_info[i], num_vouts_received, tx_money_got_in_outs, outs, pool); + scan_output(tx, miner_tx, tx_pub_key, i, tx_scan_info[i], num_vouts_received, tx_money_got_in_outs, outs, pool); } } } @@ -11308,6 +11311,7 @@ uint64_t wallet2::import_key_images(const std::vectorderivation, output_index, mask, hwdev); } + THROW_WALLET_EXCEPTION_IF(tx_money_got_in_outs >= std::numeric_limits::max() - tx_scan_info.money_transfered, + error::wallet_internal_error, "Overflow in received amounts"); tx_money_got_in_outs += tx_scan_info.money_transfered; } ++output_index; diff --git a/src/wallet/wallet2.h b/src/wallet/wallet2.h index 3b2dd6076..df080be86 100644 --- a/src/wallet/wallet2.h +++ b/src/wallet/wallet2.h @@ -1292,7 +1292,7 @@ namespace tools bool tx_add_fake_output(std::vector> &outs, uint64_t global_index, const crypto::public_key& tx_public_key, const rct::key& mask, uint64_t real_index, bool unlocked) const; bool should_pick_a_second_output(bool use_rct, size_t n_transfers, const std::vector &unused_transfers_indices, const std::vector &unused_dust_indices) const; std::vector get_only_rct(const std::vector &unused_dust_indices, const std::vector &unused_transfers_indices) const; - void scan_output(const cryptonote::transaction &tx, const crypto::public_key &tx_pub_key, size_t i, tx_scan_info_t &tx_scan_info, int &num_vouts_received, std::unordered_map &tx_money_got_in_outs, std::vector &outs, bool pool); + void scan_output(const cryptonote::transaction &tx, bool miner_tx, const crypto::public_key &tx_pub_key, size_t i, tx_scan_info_t &tx_scan_info, int &num_vouts_received, std::unordered_map &tx_money_got_in_outs, std::vector &outs, bool pool); void trim_hashchain(); crypto::key_image get_multisig_composite_key_image(size_t n) const; rct::multisig_kLRki get_multisig_composite_kLRki(size_t n, const std::unordered_set &ignore_set, std::unordered_set &used_L, std::unordered_set &new_used_L) const;