From 6b563cae92957dc30dc35103a7c321fdb0115ef3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aur=C3=A8le=20Oul=C3=A8s?= Date: Tue, 4 Oct 2022 14:17:11 +0200 Subject: wallet: Check max tx weight in coin selector Co-authored-by: Andrew Chow --- src/wallet/coinselection.cpp | 14 ++++++++++++++ src/wallet/coinselection.h | 7 +++++++ src/wallet/spend.cpp | 29 +++++++++++++++++++---------- 3 files changed, 40 insertions(+), 10 deletions(-) (limited to 'src/wallet') diff --git a/src/wallet/coinselection.cpp b/src/wallet/coinselection.cpp index b889d31928..ba1d60fe44 100644 --- a/src/wallet/coinselection.cpp +++ b/src/wallet/coinselection.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -354,6 +355,10 @@ void OutputGroup::Insert(const COutput& output, size_t ancestors, size_t descend // descendants is the count as seen from the top ancestor, not the descendants as seen from the // coin itself; thus, this value is counted as the max, not the sum m_descendants = std::max(m_descendants, descendants); + + if (output.input_bytes > 0) { + m_weight += output.input_bytes * WITNESS_SCALE_FACTOR; + } } bool OutputGroup::EligibleForSpending(const CoinEligibilityFilter& eligibility_filter) const @@ -436,18 +441,25 @@ void SelectionResult::Clear() { m_selected_inputs.clear(); m_waste.reset(); + m_weight = 0; } void SelectionResult::AddInput(const OutputGroup& group) { util::insert(m_selected_inputs, group.m_outputs); m_use_effective = !group.m_subtract_fee_outputs; + + m_weight += group.m_weight; } void SelectionResult::AddInputs(const std::set& inputs, bool subtract_fee_outputs) { util::insert(m_selected_inputs, inputs); m_use_effective = !subtract_fee_outputs; + + m_weight += std::accumulate(inputs.cbegin(), inputs.cend(), 0, [](int sum, const auto& coin) { + return sum + std::max(coin.input_bytes, 0) * WITNESS_SCALE_FACTOR; + }); } void SelectionResult::Merge(const SelectionResult& other) @@ -462,6 +474,8 @@ void SelectionResult::Merge(const SelectionResult& other) } util::insert(m_selected_inputs, other.m_selected_inputs); assert(m_selected_inputs.size() == expected_count); + + m_weight += other.m_weight; } const std::set& SelectionResult::GetInputSet() const diff --git a/src/wallet/coinselection.h b/src/wallet/coinselection.h index 2ab4061a9b..ecfc5bfd6b 100644 --- a/src/wallet/coinselection.h +++ b/src/wallet/coinselection.h @@ -6,6 +6,7 @@ #define BITCOIN_WALLET_COINSELECTION_H #include +#include #include #include #include @@ -223,6 +224,8 @@ struct OutputGroup /** Indicate that we are subtracting the fee from outputs. * When true, the value that is used for coin selection is the UTXO's real value rather than effective value */ bool m_subtract_fee_outputs{false}; + /** Total weight of the UTXOs in this group. */ + int m_weight{0}; OutputGroup() {} OutputGroup(const CoinSelectionParams& params) : @@ -295,6 +298,8 @@ private: bool m_use_effective{false}; /** The computed waste */ std::optional m_waste; + /** Total weight of the selected inputs */ + int m_weight{0}; public: explicit SelectionResult(const CAmount target, SelectionAlgorithm algo) @@ -353,6 +358,8 @@ public: CAmount GetTarget() const { return m_target; } SelectionAlgorithm GetAlgo() const { return m_algo; } + + int GetWeight() const { return m_weight; } }; std::optional SelectCoinsBnB(std::vector& utxo_pool, const CAmount& selection_target, const CAmount& cost_of_change); diff --git a/src/wallet/spend.cpp b/src/wallet/spend.cpp index 52d10b74b5..1724b11268 100644 --- a/src/wallet/spend.cpp +++ b/src/wallet/spend.cpp @@ -2,9 +2,11 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include #include #include #include +#include #include #include