@@ -373,11 +373,9 @@ std::vector<OutputGroup> GroupOutputs(const CWallet& wallet, const std::vector<C
373373 return groups_out;
374374}
375375
376- bool AttemptSelection (const CWallet& wallet, const CAmount& nTargetValue, const CoinEligibilityFilter& eligibility_filter, std::vector<COutput> coins,
377- std::set<CInputCoin>& setCoinsRet, CAmount& nValueRet, const CoinSelectionParams& coin_selection_params)
376+ std::optional<SelectionResult> AttemptSelection (const CWallet& wallet, const CAmount& nTargetValue, const CoinEligibilityFilter& eligibility_filter, std::vector<COutput> coins,
377+ const CoinSelectionParams& coin_selection_params)
378378{
379- setCoinsRet.clear ();
380- nValueRet = 0 ;
381379 // Vector of results. We will choose the best one based on waste.
382380 std::vector<SelectionResult> results;
383381
@@ -407,15 +405,13 @@ bool AttemptSelection(const CWallet& wallet, const CAmount& nTargetValue, const
407405
408406 if (results.size () == 0 ) {
409407 // No solution found
410- return false ;
408+ return std:: nullopt ;
411409 }
412410
413411 // Choose the result with the least waste
414412 // If the waste is the same, choose the one which spends more inputs.
415413 auto & best_result = *std::min_element (results.begin (), results.end ());
416- setCoinsRet = best_result.GetInputSet ();
417- nValueRet = best_result.GetSelectedValue ();
418- return true ;
414+ return best_result;
419415}
420416
421417bool SelectCoins (const CWallet& wallet, const std::vector<COutput>& vAvailableCoins, const CAmount& nTargetValue, std::set<CInputCoin>& setCoinsRet, CAmount& nValueRet, const CCoinControl& coin_control, CoinSelectionParams& coin_selection_params)
@@ -438,7 +434,6 @@ bool SelectCoins(const CWallet& wallet, const std::vector<COutput>& vAvailableCo
438434
439435 // calculate value from preset inputs and store them
440436 std::set<CInputCoin> setPresetCoins;
441- CAmount nValueFromPresetInputs = 0 ;
442437 OutputGroup preset_inputs (coin_selection_params);
443438
444439 std::vector<COutPoint> vPresetInputs;
@@ -466,7 +461,6 @@ bool SelectCoins(const CWallet& wallet, const std::vector<COutput>& vAvailableCo
466461 }
467462
468463 CInputCoin coin (outpoint, txout, input_bytes);
469- nValueFromPresetInputs += coin.txout .nValue ;
470464 if (coin.m_input_bytes == -1 ) {
471465 return false ; // Not solvable, can't estimate size for fee
472466 }
@@ -511,62 +505,67 @@ bool SelectCoins(const CWallet& wallet, const std::vector<COutput>& vAvailableCo
511505 // Coin Selection attempts to select inputs from a pool of eligible UTXOs to fund the
512506 // transaction at a target feerate. If an attempt fails, more attempts may be made using a more
513507 // permissive CoinEligibilityFilter.
514- const bool res = [&] {
508+ std::optional<SelectionResult> res = [&] {
515509 // Pre-selected inputs already cover the target amount.
516- if (value_to_select <= 0 ) return true ;
510+ if (value_to_select <= 0 ) return std::make_optional ( SelectionResult (nTargetValue)) ;
517511
518512 // If possible, fund the transaction with confirmed UTXOs only. Prefer at least six
519513 // confirmations on outputs received from other wallets and only spend confirmed change.
520- if (AttemptSelection (wallet, value_to_select, CoinEligibilityFilter (1 , 6 , 0 ), vCoins, setCoinsRet, nValueRet, coin_selection_params)) return true ;
521- if (AttemptSelection (wallet, value_to_select, CoinEligibilityFilter (1 , 1 , 0 ), vCoins, setCoinsRet, nValueRet, coin_selection_params)) return true ;
514+ if (auto r1{ AttemptSelection (wallet, value_to_select, CoinEligibilityFilter (1 , 6 , 0 ), vCoins, coin_selection_params)} ) return r1 ;
515+ if (auto r2{ AttemptSelection (wallet, value_to_select, CoinEligibilityFilter (1 , 1 , 0 ), vCoins, coin_selection_params)} ) return r2 ;
522516
523517 // Fall back to using zero confirmation change (but with as few ancestors in the mempool as
524518 // possible) if we cannot fund the transaction otherwise.
525519 if (wallet.m_spend_zero_conf_change ) {
526- if (AttemptSelection (wallet, value_to_select, CoinEligibilityFilter (0 , 1 , 2 ), vCoins, setCoinsRet, nValueRet, coin_selection_params)) return true ;
527- if (AttemptSelection (wallet, value_to_select, CoinEligibilityFilter (0 , 1 , std::min ((size_t )4 , max_ancestors/3 ), std::min ((size_t )4 , max_descendants/3 )),
528- vCoins, setCoinsRet, nValueRet, coin_selection_params)) {
529- return true ;
520+ if (auto r3{ AttemptSelection (wallet, value_to_select, CoinEligibilityFilter (0 , 1 , 2 ), vCoins, coin_selection_params)} ) return r3 ;
521+ 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 )),
522+ vCoins, coin_selection_params)} ) {
523+ return r4 ;
530524 }
531- if (AttemptSelection (wallet, value_to_select, CoinEligibilityFilter (0 , 1 , max_ancestors/2 , max_descendants/2 ),
532- vCoins, setCoinsRet, nValueRet, coin_selection_params)) {
533- return true ;
525+ if (auto r5{ AttemptSelection (wallet, value_to_select, CoinEligibilityFilter (0 , 1 , max_ancestors/2 , max_descendants/2 ),
526+ vCoins, coin_selection_params)} ) {
527+ return r5 ;
534528 }
535529 // If partial groups are allowed, relax the requirement of spending OutputGroups (groups
536530 // of UTXOs sent to the same address, which are obviously controlled by a single wallet)
537531 // in their entirety.
538- if (AttemptSelection (wallet, value_to_select, CoinEligibilityFilter (0 , 1 , max_ancestors-1 , max_descendants-1 , true /* include_partial_groups */ ),
539- vCoins, setCoinsRet, nValueRet, coin_selection_params)) {
540- return true ;
532+ if (auto r6{ AttemptSelection (wallet, value_to_select, CoinEligibilityFilter (0 , 1 , max_ancestors-1 , max_descendants-1 , true /* include_partial_groups */ ),
533+ vCoins, coin_selection_params)} ) {
534+ return r6 ;
541535 }
542536 // Try with unsafe inputs if they are allowed. This may spend unconfirmed outputs
543537 // received from other wallets.
544- if (coin_control.m_include_unsafe_inputs
545- && AttemptSelection (wallet, value_to_select,
538+ if (coin_control.m_include_unsafe_inputs ) {
539+ if ( auto r7{ AttemptSelection (wallet, value_to_select,
546540 CoinEligibilityFilter (0 /* conf_mine */ , 0 /* conf_theirs */ , max_ancestors-1 , max_descendants-1 , true /* include_partial_groups */ ),
547- vCoins, setCoinsRet, nValueRet, coin_selection_params)) {
548- return true ;
541+ vCoins, coin_selection_params)}) {
542+ return r7;
543+ }
549544 }
550545 // Try with unlimited ancestors/descendants. The transaction will still need to meet
551546 // mempool ancestor/descendant policy to be accepted to mempool and broadcasted, but
552547 // OutputGroups use heuristics that may overestimate ancestor/descendant counts.
553- if (!fRejectLongChains && AttemptSelection (wallet, value_to_select,
548+ if (!fRejectLongChains ) {
549+ if (auto r8{AttemptSelection (wallet, value_to_select,
554550 CoinEligibilityFilter (0 , 1 , std::numeric_limits<uint64_t >::max (), std::numeric_limits<uint64_t >::max (), true /* include_partial_groups */ ),
555- vCoins, setCoinsRet, nValueRet, coin_selection_params)) {
556- return true ;
551+ vCoins, coin_selection_params)}) {
552+ return r8;
553+ }
557554 }
558555 }
559556 // Coin Selection failed.
560- return false ;
557+ return std::optional<SelectionResult>() ;
561558 }();
562559
563- // AttemptSelection clears setCoinsRet, so add the preset inputs from coin_control to the coinset
564- util::insert (setCoinsRet, setPresetCoins);
560+ if (!res) return false ;
565561
566- // add preset inputs to the total value selected
567- nValueRet += nValueFromPresetInputs ;
562+ // Add preset inputs to result
563+ res-> AddInput (preset_inputs) ;
568564
569- return res;
565+ setCoinsRet = res->GetInputSet ();
566+ nValueRet = res->GetSelectedValue ();
567+
568+ return true ;
570569}
571570
572571static bool IsCurrentForAntiFeeSniping (interfaces::Chain& chain, const uint256& block_hash)
0 commit comments