@@ -373,11 +373,9 @@ std::vector<OutputGroup> GroupOutputs(const CWallet& wallet, const std::vector<C
373
373
return groups_out;
374
374
}
375
375
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)
378
378
{
379
- setCoinsRet.clear ();
380
- nValueRet = 0 ;
381
379
// Vector of results. We will choose the best one based on waste.
382
380
std::vector<SelectionResult> results;
383
381
@@ -407,15 +405,13 @@ bool AttemptSelection(const CWallet& wallet, const CAmount& nTargetValue, const
407
405
408
406
if (results.size () == 0 ) {
409
407
// No solution found
410
- return false ;
408
+ return std::nullopt ;
411
409
}
412
410
413
411
// Choose the result with the least waste
414
412
// If the waste is the same, choose the one which spends more inputs.
415
413
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;
419
415
}
420
416
421
417
bool 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
438
434
439
435
// calculate value from preset inputs and store them
440
436
std::set<CInputCoin> setPresetCoins;
441
- CAmount nValueFromPresetInputs = 0 ;
442
437
OutputGroup preset_inputs (coin_selection_params);
443
438
444
439
std::vector<COutPoint> vPresetInputs;
@@ -466,7 +461,6 @@ bool SelectCoins(const CWallet& wallet, const std::vector<COutput>& vAvailableCo
466
461
}
467
462
468
463
CInputCoin coin (outpoint, txout, input_bytes);
469
- nValueFromPresetInputs += coin.txout .nValue ;
470
464
if (coin.m_input_bytes == -1 ) {
471
465
return false ; // Not solvable, can't estimate size for fee
472
466
}
@@ -511,62 +505,67 @@ bool SelectCoins(const CWallet& wallet, const std::vector<COutput>& vAvailableCo
511
505
// Coin Selection attempts to select inputs from a pool of eligible UTXOs to fund the
512
506
// transaction at a target feerate. If an attempt fails, more attempts may be made using a more
513
507
// permissive CoinEligibilityFilter.
514
- const bool res = [&] {
508
+ std::optional<SelectionResult> res = [&] {
515
509
// 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)) ;
517
511
518
512
// If possible, fund the transaction with confirmed UTXOs only. Prefer at least six
519
513
// 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 ;
522
516
523
517
// Fall back to using zero confirmation change (but with as few ancestors in the mempool as
524
518
// possible) if we cannot fund the transaction otherwise.
525
519
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 ;
530
524
}
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 ;
534
528
}
535
529
// If partial groups are allowed, relax the requirement of spending OutputGroups (groups
536
530
// of UTXOs sent to the same address, which are obviously controlled by a single wallet)
537
531
// 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 ;
541
535
}
542
536
// Try with unsafe inputs if they are allowed. This may spend unconfirmed outputs
543
537
// 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,
546
540
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
+ }
549
544
}
550
545
// Try with unlimited ancestors/descendants. The transaction will still need to meet
551
546
// mempool ancestor/descendant policy to be accepted to mempool and broadcasted, but
552
547
// 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,
554
550
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
+ }
557
554
}
558
555
}
559
556
// Coin Selection failed.
560
- return false ;
557
+ return std::optional<SelectionResult>() ;
561
558
}();
562
559
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 ;
565
561
566
- // add preset inputs to the total value selected
567
- nValueRet += nValueFromPresetInputs ;
562
+ // Add preset inputs to result
563
+ res-> AddInput (preset_inputs) ;
568
564
569
- return res;
565
+ setCoinsRet = res->GetInputSet ();
566
+ nValueRet = res->GetSelectedValue ();
567
+
568
+ return true ;
570
569
}
571
570
572
571
static bool IsCurrentForAntiFeeSniping (interfaces::Chain& chain, const uint256& block_hash)
0 commit comments