69 std::vector<bool> curr_selection;
70 curr_selection.reserve(utxo_pool.size());
73 CAmount curr_available_value = 0;
76 assert(utxo.GetSelectionAmount() > 0);
77 curr_available_value += utxo.GetSelectionAmount();
79 if (curr_available_value < selection_target) {
84 std::sort(utxo_pool.begin(), utxo_pool.end(),
descending);
87 std::vector<bool> best_selection;
93 bool backtrack =
false;
94 if (curr_value + curr_available_value < selection_target ||
95 curr_value > selection_target + cost_of_change ||
96 (curr_waste > best_waste && (utxo_pool.at(0).fee - utxo_pool.at(0).long_term_fee) > 0)) {
98 }
else if (curr_value >= selection_target) {
99 curr_waste += (curr_value - selection_target);
104 if (curr_waste <= best_waste) {
105 best_selection = curr_selection;
106 best_selection.resize(utxo_pool.size());
107 best_waste = curr_waste;
108 if (best_waste == 0) {
112 curr_waste -= (curr_value - selection_target);
119 while (!curr_selection.empty() && !curr_selection.back()) {
120 curr_selection.pop_back();
121 curr_available_value += utxo_pool.at(curr_selection.size()).GetSelectionAmount();
124 if (curr_selection.empty()) {
129 curr_selection.back() =
false;
130 OutputGroup& utxo = utxo_pool.at(curr_selection.size() - 1);
134 OutputGroup& utxo = utxo_pool.at(curr_selection.size());
141 if (!curr_selection.empty() && !curr_selection.back() &&
142 utxo.
GetSelectionAmount() == utxo_pool.at(curr_selection.size() - 1).GetSelectionAmount() &&
143 utxo.
fee == utxo_pool.at(curr_selection.size() - 1).fee) {
144 curr_selection.push_back(
false);
147 curr_selection.push_back(
true);
155 if (best_selection.empty()) {
161 for (
size_t i = 0; i < best_selection.size(); ++i) {
162 if (best_selection.at(i)) {
164 value_ret += utxo_pool.at(i).m_value;
172 std::vector<char>& vfBest,
CAmount& nBest,
int iterations = 1000)
174 std::vector<char> vfIncluded;
176 vfBest.assign(groups.size(),
true);
181 for (
int nRep = 0; nRep < iterations && nBest != nTargetValue; nRep++)
183 vfIncluded.assign(groups.size(),
false);
185 bool fReachedTarget =
false;
186 for (
int nPass = 0; nPass < 2 && !fReachedTarget; nPass++)
188 for (
unsigned int i = 0; i < groups.size(); i++)
196 if (nPass == 0 ? insecure_rand.
randbool() : !vfIncluded[i])
198 nTotal += groups[i].GetSelectionAmount();
199 vfIncluded[i] =
true;
200 if (nTotal >= nTargetValue)
202 fReachedTarget =
true;
208 nTotal -= groups[i].GetSelectionAmount();
209 vfIncluded[i] =
false;
223 std::optional<OutputGroup> lowest_larger;
224 std::vector<OutputGroup> applicable_groups;
230 if (group.GetSelectionAmount() == nTargetValue) {
232 nValueRet += group.m_value;
234 }
else if (group.GetSelectionAmount() < nTargetValue +
MIN_CHANGE) {
235 applicable_groups.push_back(group);
236 nTotalLower += group.GetSelectionAmount();
237 }
else if (!lowest_larger || group.GetSelectionAmount() < lowest_larger->GetSelectionAmount()) {
238 lowest_larger = group;
242 if (nTotalLower == nTargetValue) {
243 for (
const auto& group : applicable_groups) {
245 nValueRet += group.m_value;
250 if (nTotalLower < nTargetValue) {
251 if (!lowest_larger)
return false;
253 nValueRet += lowest_larger->m_value;
258 std::sort(applicable_groups.begin(), applicable_groups.end(),
descending);
259 std::vector<char> vfBest;
263 if (nBest != nTargetValue && nTotalLower >= nTargetValue +
MIN_CHANGE) {
270 ((nBest != nTargetValue && nBest < nTargetValue +
MIN_CHANGE) || lowest_larger->GetSelectionAmount() <= nBest)) {
272 nValueRet += lowest_larger->m_value;
274 for (
unsigned int i = 0; i < applicable_groups.size(); i++) {
276 util::insert(setCoinsRet, applicable_groups[i].m_outputs);
277 nValueRet += applicable_groups[i].m_value;
283 for (
unsigned int i = 0; i < applicable_groups.size(); i++) {
307 if (positive_only && ev <= 0)
return;
312 coin.
m_fee = coin_fee;
#define LogPrint(category,...)
bool m_from_me
Whether the UTXOs were sent by the wallet to itself.
const int conf_theirs
Minimum number of confirmations for outputs received from a different wallet.
size_t m_descendants
The maximum count of descendants of a single UTXO in this output group.
void Insert(const CInputCoin &output, int depth, bool from_me, size_t ancestors, size_t descendants, bool positive_only)
static const CAmount MAX_MONEY
No amount larger than this (in satoshi) is valid.
static constexpr CAmount MIN_CHANGE
target minimum change amount
void insert(Tdst &dst, const Tsrc &src)
Simplification of std insertion.
const uint64_t max_descendants
Maximum number of descendants that a single UTXO in the OutputGroup may have.
bool SelectCoinsBnB(std::vector< OutputGroup > &utxo_pool, const CAmount &selection_target, const CAmount &cost_of_change, std::set< CInputCoin > &out_set, CAmount &value_ret)
int64_t CAmount
Amount in satoshis (Can be negative)
CAmount fee
The fee to spend these UTXOs at the effective feerate.
Parameters for filtering which OutputGroups we may use in coin selection.
const uint64_t max_ancestors
Maximum number of unconfirmed ancestors aggregated across all UTXOs in an OutputGroup.
CFeeRate m_effective_feerate
The target feerate of the transaction we're trying to build.
A group of UTXOs paid to the same output script.
std::vector< CInputCoin > m_outputs
The list of UTXOs contained in this output group.
CAmount long_term_fee
The fee to spend these UTXOs at the long term feerate.
CAmount m_value
The total value of the UTXOs in sum.
static bool LogAcceptCategory(BCLog::LogFlags category)
Return true if log accepts specified category.
size_t m_ancestors
The aggregated count of unconfirmed ancestors of all UTXOs in this group.
int m_depth
The minimum number of confirmations the UTXOs in the group have.
std::string FormatMoney(const CAmount n)
Money parsing/formatting utilities.
void Shuffle(I first, I last, R &&rng)
More efficient than using std::shuffle on a FastRandomContext.
bool EligibleForSpending(const CoinEligibilityFilter &eligibility_filter) const
const int conf_mine
Minimum number of confirmations for outputs that we sent to ourselves.
CAmount effective_value
The value of the UTXOs after deducting the cost of spending them at the effective feerate...
CAmount GetSelectionAmount() const
bool randbool() noexcept
Generate a random boolean.
bool KnapsackSolver(const CAmount &nTargetValue, std::vector< OutputGroup > &groups, std::set< CInputCoin > &setCoinsRet, CAmount &nValueRet)
static const size_t TOTAL_TRIES
CAmount GetFee(uint32_t num_bytes) const
Return the fee in satoshis for the given size in bytes.
static void ApproximateBestSubset(const std::vector< OutputGroup > &groups, const CAmount &nTotalLower, const CAmount &nTargetValue, std::vector< char > &vfBest, CAmount &nBest, int iterations=1000)
bool m_subtract_fee_outputs
Indicate that we are subtracting the fee from outputs.
CFeeRate m_long_term_feerate
The feerate for spending a created change output eventually (i.e.