diff options
Diffstat (limited to 'src/wallet/wallet2.cpp')
-rw-r--r-- | src/wallet/wallet2.cpp | 71 |
1 files changed, 60 insertions, 11 deletions
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index 00b40fef8..33699cb79 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -1344,6 +1344,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote size_t pk_index = 0; std::vector<tx_scan_info_t> tx_scan_info(tx.vout.size()); std::deque<bool> output_found(tx.vout.size(), false); + uint64_t total_received_1 = 0; while (!tx.vout.empty()) { // if tx.vout is not empty, we loop through all tx pubkeys @@ -1518,6 +1519,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote + ", m_transfers.size() is " + boost::lexical_cast<std::string>(m_transfers.size())); if (kit == m_pub_keys.end()) { + uint64_t amount = tx.vout[o].amount ? tx.vout[o].amount : tx_scan_info[o].amount; if (!pool) { m_transfers.push_back(boost::value_initialized<transfer_details>()); @@ -1530,14 +1532,13 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote td.m_key_image = tx_scan_info[o].ki; td.m_key_image_known = !m_watch_only && !m_multisig; td.m_key_image_partial = m_multisig; - td.m_amount = tx.vout[o].amount; + td.m_amount = amount; td.m_pk_index = pk_index - 1; td.m_subaddr_index = tx_scan_info[o].received->index; expand_subaddresses(tx_scan_info[o].received->index); - if (td.m_amount == 0) + if (tx.vout[o].amount == 0) { td.m_mask = tx_scan_info[o].mask; - td.m_amount = tx_scan_info[o].amount; td.m_rct = true; } else if (miner_tx && tx.version == 2) @@ -1565,6 +1566,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote if (0 != m_callback) m_callback->on_money_received(height, txid, tx, td.m_amount, td.m_subaddr_index); } + total_received_1 += amount; } else if (m_transfers[kit->second].m_spent || m_transfers[kit->second].amount() >= tx_scan_info[o].amount) { @@ -1572,6 +1574,9 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote << " from received " << print_money(tx_scan_info[o].amount) << " output already exists with " << (m_transfers[kit->second].m_spent ? "spent" : "unspent") << " " << print_money(m_transfers[kit->second].amount()) << " in tx " << m_transfers[kit->second].m_txid << ", received output ignored"); + THROW_WALLET_EXCEPTION_IF(tx_money_got_in_outs[tx_scan_info[o].received->index] < tx_scan_info[o].amount, + error::wallet_internal_error, "Unexpected values of new and old outputs"); + tx_money_got_in_outs[tx_scan_info[o].received->index] -= tx_scan_info[o].amount; } else { @@ -1579,8 +1584,14 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote << " from received " << print_money(tx_scan_info[o].amount) << " output already exists with " << print_money(m_transfers[kit->second].amount()) << ", replacing with new output"); // The new larger output replaced a previous smaller one - tx_money_got_in_outs[tx_scan_info[o].received->index] -= tx_scan_info[o].amount; - + THROW_WALLET_EXCEPTION_IF(tx_money_got_in_outs[tx_scan_info[o].received->index] < tx_scan_info[o].amount, + error::wallet_internal_error, "Unexpected values of new and old outputs"); + THROW_WALLET_EXCEPTION_IF(m_transfers[kit->second].amount() > tx_scan_info[o].amount, + error::wallet_internal_error, "Unexpected values of new and old outputs"); + tx_money_got_in_outs[tx_scan_info[o].received->index] -= m_transfers[kit->second].amount(); + + uint64_t amount = tx.vout[o].amount ? tx.vout[o].amount : tx_scan_info[o].amount; + uint64_t extra_amount = amount - m_transfers[kit->second].amount(); if (!pool) { transfer_details &td = m_transfers[kit->second]; @@ -1589,14 +1600,13 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote td.m_global_output_index = o_indices[o]; td.m_tx = (const cryptonote::transaction_prefix&)tx; td.m_txid = txid; - td.m_amount = tx.vout[o].amount; + td.m_amount = amount; td.m_pk_index = pk_index - 1; td.m_subaddr_index = tx_scan_info[o].received->index; expand_subaddresses(tx_scan_info[o].received->index); - if (td.m_amount == 0) + if (tx.vout[o].amount == 0) { td.m_mask = tx_scan_info[o].mask; - td.m_amount = tx_scan_info[o].amount; td.m_rct = true; } else if (miner_tx && tx.version == 2) @@ -1623,6 +1633,7 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote if (0 != m_callback) m_callback->on_money_received(height, txid, tx, td.m_amount, td.m_subaddr_index); } + total_received_1 += extra_amount; } } } @@ -1744,6 +1755,20 @@ void wallet2::process_new_transaction(const crypto::hash &txid, const cryptonote } } + uint64_t total_received_2 = 0; + for (const auto& i : tx_money_got_in_outs) + total_received_2 += i.second; + if (total_received_1 != total_received_2) + { + const el::Level level = el::Level::Warning; + MCLOG_RED(level, "global", "**********************************************************************"); + MCLOG_RED(level, "global", "Consistency failure in amounts received"); + MCLOG_RED(level, "global", "Check transaction " << txid); + MCLOG_RED(level, "global", "**********************************************************************"); + exit(1); + return; + } + for (const auto& i : tx_money_got_in_outs) { payment_details payment; @@ -6698,11 +6723,23 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>> } // while we still need more mixins + uint64_t num_usable_outs = num_outs; + bool allow_blackballed = false; while (num_found < requested_outputs_count) { // if we've gone through every possible output, we've gotten all we can - if (seen_indices.size() == num_outs) - break; + if (seen_indices.size() == num_usable_outs) + { + // there is a first pass which rejects blackballed outputs, then a second pass + // which allows them if we don't have enough non blackballed outputs to reach + // the required amount of outputs (since consensus does not care about blackballed + // outputs, we still need to reach the minimum ring size) + if (allow_blackballed) + break; + MINFO("Not enough non blackballed outputs, we'll allow blackballed ones"); + allow_blackballed = true; + num_usable_outs = num_outs; + } // get a random output index from the DB. If we've already seen it, // return to the top of the loop and try again, otherwise add it to the @@ -6776,14 +6813,26 @@ void wallet2::get_outs(std::vector<std::vector<tools::wallet2::get_outs_entry>> if (seen_indices.count(i)) continue; - if (is_output_blackballed(std::make_pair(amount, i))) // don't add blackballed outputs + if (!allow_blackballed && is_output_blackballed(std::make_pair(amount, i))) // don't add blackballed outputs + { + --num_usable_outs; continue; + } seen_indices.emplace(i); LOG_PRINT_L2("picking " << i << " as " << type); req.outputs.push_back({amount, i}); ++num_found; } + + // if we had enough unusable outputs, we might fall off here and still + // have too few outputs, so we stuff with one to keep counts good, and + // we'll error out later + while (num_found < requested_outputs_count) + { + req.outputs.push_back({amount, 0}); + ++num_found; + } } // sort the subsection, to ensure the daemon doesn't know which output is ours |