@@ -450,20 +450,26 @@ std::vector<OutputGroup> GroupOutputs(const CWallet& wallet, const std::vector<C
450450 return groups_out;
451451}
452452
453- std::optional<SelectionResult> AttemptSelection (const CWallet& wallet, const CAmount& nTargetValue, const CoinEligibilityFilter& eligibility_filter, std::vector<COutput> coins ,
453+ std::optional<SelectionResult> AttemptSelection (const CWallet& wallet, const CAmount& nTargetValue, const CoinEligibilityFilter& eligibility_filter, const CoinsResult& available_coins ,
454454 const CoinSelectionParams& coin_selection_params)
455+ {
456+ std::optional<SelectionResult> result = ChooseSelectionResult (wallet, nTargetValue, eligibility_filter, available_coins.all (), coin_selection_params);
457+ return result;
458+ };
459+
460+ std::optional<SelectionResult> ChooseSelectionResult (const CWallet& wallet, const CAmount& nTargetValue, const CoinEligibilityFilter& eligibility_filter, const std::vector<COutput>& available_coins, const CoinSelectionParams& coin_selection_params)
455461{
456462 // Vector of results. We will choose the best one based on waste.
457463 std::vector<SelectionResult> results;
458464
459465 // Note that unlike KnapsackSolver, we do not include the fee for creating a change output as BnB will not create a change output.
460- std::vector<OutputGroup> positive_groups = GroupOutputs (wallet, coins , coin_selection_params, eligibility_filter, true /* positive_only */ );
466+ std::vector<OutputGroup> positive_groups = GroupOutputs (wallet, available_coins , coin_selection_params, eligibility_filter, true /* positive_only */ );
461467 if (auto bnb_result{SelectCoinsBnB (positive_groups, nTargetValue, coin_selection_params.m_cost_of_change )}) {
462468 results.push_back (*bnb_result);
463469 }
464470
465471 // The knapsack solver has some legacy behavior where it will spend dust outputs. We retain this behavior, so don't filter for positive only here.
466- std::vector<OutputGroup> all_groups = GroupOutputs (wallet, coins , coin_selection_params, eligibility_filter, false /* positive_only */ );
472+ std::vector<OutputGroup> all_groups = GroupOutputs (wallet, available_coins , coin_selection_params, eligibility_filter, false /* positive_only */ );
467473 CAmount target_with_change = nTargetValue;
468474 // While nTargetValue includes the transaction fees for non-input things, it does not include the fee for creating a change output.
469475 // So we need to include that for KnapsackSolver and SRD as well, as we are expecting to create a change output.
@@ -496,9 +502,8 @@ std::optional<SelectionResult> AttemptSelection(const CWallet& wallet, const CAm
496502 return best_result;
497503}
498504
499- std::optional<SelectionResult> SelectCoins (const CWallet& wallet, const std::vector<COutput>& vAvailableCoins , const CAmount& nTargetValue, const CCoinControl& coin_control, const CoinSelectionParams& coin_selection_params)
505+ std::optional<SelectionResult> SelectCoins (const CWallet& wallet, CoinsResult& available_coins , const CAmount& nTargetValue, const CCoinControl& coin_control, const CoinSelectionParams& coin_selection_params)
500506{
501- std::vector<COutput> vCoins (vAvailableCoins);
502507 CAmount value_to_select = nTargetValue;
503508
504509 OutputGroup preset_inputs (coin_selection_params);
@@ -558,13 +563,13 @@ std::optional<SelectionResult> SelectCoins(const CWallet& wallet, const std::vec
558563 return result;
559564 }
560565
561- // remove preset inputs from vCoins so that Coin Selection doesn't pick them.
562- for (std::vector<COutput>::iterator it = vCoins. begin (); it != vCoins. end () && coin_control.HasSelected ();)
563- {
564- if ( preset_coins.count (it-> outpoint ))
565- it = vCoins. erase (it );
566- else
567- ++it ;
566+ // remove preset inputs from coins so that Coin Selection doesn't pick them.
567+ if ( coin_control.HasSelected ()) {
568+ available_coins. legacy . erase ( remove_if (available_coins. legacy . begin (), available_coins. legacy . end (), [&]( const COutput& c) { return preset_coins. count (c. outpoint ); }), available_coins. legacy . end ());
569+ available_coins. P2SH_segwit . erase ( remove_if (available_coins. P2SH_segwit . begin (), available_coins. P2SH_segwit . end (), [&]( const COutput& c) { return preset_coins.count (c. outpoint ); }), available_coins. P2SH_segwit . end ());
570+ available_coins. bech32 . erase ( remove_if (available_coins. bech32 . begin (), available_coins. bech32 . end (), [&]( const COutput& c) { return preset_coins. count (c. outpoint ); }), available_coins. bech32 . end () );
571+ available_coins. bech32m . erase ( remove_if (available_coins. bech32m . begin (), available_coins. bech32m . end (), [&]( const COutput& c) { return preset_coins. count (c. outpoint ); }), available_coins. bech32m . end ());
572+ available_coins. other . erase ( remove_if (available_coins. other . begin (), available_coins. other . end (), [&]( const COutput& c) { return preset_coins. count (c. outpoint ); }), available_coins. other . end ()) ;
568573 }
569574
570575 unsigned int limit_ancestor_count = 0 ;
@@ -576,11 +581,15 @@ std::optional<SelectionResult> SelectCoins(const CWallet& wallet, const std::vec
576581
577582 // form groups from remaining coins; note that preset coins will not
578583 // automatically have their associated (same address) coins included
579- if (coin_control.m_avoid_partial_spends && vCoins .size () > OUTPUT_GROUP_MAX_ENTRIES) {
584+ if (coin_control.m_avoid_partial_spends && available_coins .size () > OUTPUT_GROUP_MAX_ENTRIES) {
580585 // Cases where we have 101+ outputs all pointing to the same destination may result in
581586 // privacy leaks as they will potentially be deterministically sorted. We solve that by
582587 // explicitly shuffling the outputs before processing
583- Shuffle (vCoins.begin (), vCoins.end (), coin_selection_params.rng_fast );
588+ Shuffle (available_coins.legacy .begin (), available_coins.legacy .end (), coin_selection_params.rng_fast );
589+ Shuffle (available_coins.P2SH_segwit .begin (), available_coins.P2SH_segwit .end (), coin_selection_params.rng_fast );
590+ Shuffle (available_coins.bech32 .begin (), available_coins.bech32 .end (), coin_selection_params.rng_fast );
591+ Shuffle (available_coins.bech32m .begin (), available_coins.bech32m .end (), coin_selection_params.rng_fast );
592+ Shuffle (available_coins.other .begin (), available_coins.other .end (), coin_selection_params.rng_fast );
584593 }
585594
586595 // Coin Selection attempts to select inputs from a pool of eligible UTXOs to fund the
@@ -592,34 +601,34 @@ std::optional<SelectionResult> SelectCoins(const CWallet& wallet, const std::vec
592601
593602 // If possible, fund the transaction with confirmed UTXOs only. Prefer at least six
594603 // confirmations on outputs received from other wallets and only spend confirmed change.
595- if (auto r1{AttemptSelection (wallet, value_to_select, CoinEligibilityFilter (1 , 6 , 0 ), vCoins , coin_selection_params)}) return r1;
596- if (auto r2{AttemptSelection (wallet, value_to_select, CoinEligibilityFilter (1 , 1 , 0 ), vCoins , coin_selection_params)}) return r2;
604+ if (auto r1{AttemptSelection (wallet, value_to_select, CoinEligibilityFilter (1 , 6 , 0 ), available_coins , coin_selection_params)}) return r1;
605+ if (auto r2{AttemptSelection (wallet, value_to_select, CoinEligibilityFilter (1 , 1 , 0 ), available_coins , coin_selection_params)}) return r2;
597606
598607 // Fall back to using zero confirmation change (but with as few ancestors in the mempool as
599608 // possible) if we cannot fund the transaction otherwise.
600609 if (wallet.m_spend_zero_conf_change ) {
601- if (auto r3{AttemptSelection (wallet, value_to_select, CoinEligibilityFilter (0 , 1 , 2 ), vCoins , coin_selection_params)}) return r3;
610+ if (auto r3{AttemptSelection (wallet, value_to_select, CoinEligibilityFilter (0 , 1 , 2 ), available_coins , coin_selection_params)}) return r3;
602611 if (auto r4{AttemptSelection (wallet, value_to_select, CoinEligibilityFilter (0 , 1 , std::min ((size_t )4 , max_ancestors/3 ), std::min ((size_t )4 , max_descendants/3 )),
603- vCoins , coin_selection_params)}) {
612+ available_coins , coin_selection_params)}) {
604613 return r4;
605614 }
606615 if (auto r5{AttemptSelection (wallet, value_to_select, CoinEligibilityFilter (0 , 1 , max_ancestors/2 , max_descendants/2 ),
607- vCoins , coin_selection_params)}) {
616+ available_coins , coin_selection_params)}) {
608617 return r5;
609618 }
610619 // If partial groups are allowed, relax the requirement of spending OutputGroups (groups
611620 // of UTXOs sent to the same address, which are obviously controlled by a single wallet)
612621 // in their entirety.
613622 if (auto r6{AttemptSelection (wallet, value_to_select, CoinEligibilityFilter (0 , 1 , max_ancestors-1 , max_descendants-1 , true /* include_partial_groups */ ),
614- vCoins , coin_selection_params)}) {
623+ available_coins , coin_selection_params)}) {
615624 return r6;
616625 }
617626 // Try with unsafe inputs if they are allowed. This may spend unconfirmed outputs
618627 // received from other wallets.
619628 if (coin_control.m_include_unsafe_inputs ) {
620629 if (auto r7{AttemptSelection (wallet, value_to_select,
621630 CoinEligibilityFilter (0 /* conf_mine */ , 0 /* conf_theirs */ , max_ancestors-1 , max_descendants-1 , true /* include_partial_groups */ ),
622- vCoins , coin_selection_params)}) {
631+ available_coins , coin_selection_params)}) {
623632 return r7;
624633 }
625634 }
@@ -629,7 +638,7 @@ std::optional<SelectionResult> SelectCoins(const CWallet& wallet, const std::vec
629638 if (!fRejectLongChains ) {
630639 if (auto r8{AttemptSelection (wallet, value_to_select,
631640 CoinEligibilityFilter (0 , 1 , std::numeric_limits<uint64_t >::max (), std::numeric_limits<uint64_t >::max (), true /* include_partial_groups */ ),
632- vCoins , coin_selection_params)}) {
641+ available_coins , coin_selection_params)}) {
633642 return r8;
634643 }
635644 }
@@ -849,7 +858,7 @@ static BResult<CreatedTransactionResult> CreateTransactionInternal(
849858 CAmount selection_target = recipients_sum + not_input_fees;
850859
851860 // Get available coins
852- auto res_available_coins = AvailableCoins (wallet,
861+ auto available_coins = AvailableCoins (wallet,
853862 &coin_control,
854863 coin_selection_params.m_effective_feerate ,
855864 1 , /* nMinimumAmount*/
@@ -858,7 +867,7 @@ static BResult<CreatedTransactionResult> CreateTransactionInternal(
858867 0 ); /* nMaximumCount*/
859868
860869 // Choose coins to use
861- std::optional<SelectionResult> result = SelectCoins (wallet, res_available_coins. all () , /* nTargetValue=*/ selection_target, coin_control, coin_selection_params);
870+ std::optional<SelectionResult> result = SelectCoins (wallet, available_coins , /* nTargetValue=*/ selection_target, coin_control, coin_selection_params);
862871 if (!result) {
863872 return _ (" Insufficient funds" );
864873 }
0 commit comments