diff options
author | Alex Opie <alex.opie@cryptopia.co.nz> | 2021-01-22 11:38:18 +1300 |
---|---|---|
committer | Alex Opie <alex.opie@cryptopia.co.nz> | 2021-01-25 10:01:38 +1300 |
commit | b587ffa1fdc8cf235dae591ac4c7cf8beccfa76d (patch) | |
tree | 43ea75f194333c03e3917d372b36f3921a593403 | |
parent | Merge pull request #7260 (diff) | |
download | monero-b587ffa1fdc8cf235dae591ac4c7cf8beccfa76d.tar.xz |
Stop adding more outputs than bulletproof allows
If more outputs are requested, they are split across
multiple transactions.
#7322
-rw-r--r-- | src/wallet/wallet2.cpp | 42 |
1 files changed, 35 insertions, 7 deletions
diff --git a/src/wallet/wallet2.cpp b/src/wallet/wallet2.cpp index d80335db8..909a224b9 100644 --- a/src/wallet/wallet2.cpp +++ b/src/wallet/wallet2.cpp @@ -9778,13 +9778,18 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp TX() : weight(0), needed_fee(0) {} - void add(const cryptonote::tx_destination_entry &de, uint64_t amount, unsigned int original_output_index, bool merge_destinations) { + /* Add an output to the transaction. + * Returns True if the output was added, False if there are no more available output slots. + */ + bool add(const cryptonote::tx_destination_entry &de, uint64_t amount, unsigned int original_output_index, bool merge_destinations, size_t max_dsts) { if (merge_destinations) { std::vector<cryptonote::tx_destination_entry>::iterator i; i = std::find_if(dsts.begin(), dsts.end(), [&](const cryptonote::tx_destination_entry &d) { return !memcmp (&d.addr, &de.addr, sizeof(de.addr)); }); if (i == dsts.end()) { + if (dsts.size() >= max_dsts) + return false; dsts.push_back(de); i = dsts.end() - 1; i->amount = 0; @@ -9797,12 +9802,15 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp std::string("original_output_index too large: ") + std::to_string(original_output_index) + " > " + std::to_string(dsts.size())); if (original_output_index == dsts.size()) { + if (dsts.size() >= max_dsts) + return false; dsts.push_back(de); dsts.back().amount = 0; } THROW_WALLET_EXCEPTION_IF(memcmp(&dsts[original_output_index].addr, &de.addr, sizeof(de.addr)), error::wallet_internal_error, "Mismatched destination address"); dsts[original_output_index].amount += amount; } + return true; } }; std::vector<TX> txes; @@ -10072,6 +10080,7 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp // clear any fake outs we'd already gathered, since we'll need a new set outs.clear(); + bool out_slots_exhausted = false; if (adding_fee) { LOG_PRINT_L2("We need more fee, adding it to fee"); @@ -10084,20 +10093,32 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp // we can fully pay that destination LOG_PRINT_L2("We can fully pay " << get_account_address_as_str(m_nettype, dsts[0].is_subaddress, dsts[0].addr) << " for " << print_money(dsts[0].amount)); - tx.add(dsts[0], dsts[0].amount, original_output_index, m_merge_destinations); + if (!tx.add(dsts[0], dsts[0].amount, original_output_index, m_merge_destinations, BULLETPROOF_MAX_OUTPUTS-1)) + { + LOG_PRINT_L2("Didn't pay: ran out of output slots"); + out_slots_exhausted = true; + break; + } available_amount -= dsts[0].amount; dsts[0].amount = 0; pop_index(dsts, 0); ++original_output_index; } - if (available_amount > 0 && !dsts.empty() && estimate_tx_weight(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size()+1, extra.size(), bulletproof, clsag) < TX_WEIGHT_TARGET(upper_transaction_weight_limit)) { + if (!out_slots_exhausted && available_amount > 0 && !dsts.empty() && estimate_tx_weight(use_rct, tx.selected_transfers.size(), fake_outs_count, tx.dsts.size()+1, extra.size(), bulletproof, clsag) < TX_WEIGHT_TARGET(upper_transaction_weight_limit)) { // we can partially fill that destination LOG_PRINT_L2("We can partially pay " << get_account_address_as_str(m_nettype, dsts[0].is_subaddress, dsts[0].addr) << " for " << print_money(available_amount) << "/" << print_money(dsts[0].amount)); - tx.add(dsts[0], available_amount, original_output_index, m_merge_destinations); - dsts[0].amount -= available_amount; - available_amount = 0; + if (tx.add(dsts[0], available_amount, original_output_index, m_merge_destinations, BULLETPROOF_MAX_OUTPUTS-1)) + { + dsts[0].amount -= available_amount; + available_amount = 0; + } + else + { + LOG_PRINT_L2("Didn't pay: ran out of output slots"); + out_slots_exhausted = true; + } } } @@ -10105,8 +10126,15 @@ std::vector<wallet2::pending_tx> wallet2::create_transactions_2(std::vector<cryp LOG_PRINT_L2("Considering whether to create a tx now, " << tx.selected_transfers.size() << " inputs, tx limit " << upper_transaction_weight_limit); bool try_tx = false; + + // If the new transaction is full, create it and start a new one + if (out_slots_exhausted) + { + LOG_PRINT_L2("Transaction is full, will create it and start a new tx"); + try_tx = true; + } // if we have preferred picks, but haven't yet used all of them, continue - if (preferred_inputs.empty()) + else if (preferred_inputs.empty()) { if (adding_fee) { |