@@ -450,20 +450,26 @@ std::vector<OutputGroup> GroupOutputs(const CWallet& wallet, const std::vector<C
450
450
return groups_out;
451
451
}
452
452
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 ,
454
454
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)
455
461
{
456
462
// Vector of results. We will choose the best one based on waste.
457
463
std::vector<SelectionResult> results;
458
464
459
465
// 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 */ );
461
467
if (auto bnb_result{SelectCoinsBnB (positive_groups, nTargetValue, coin_selection_params.m_cost_of_change )}) {
462
468
results.push_back (*bnb_result);
463
469
}
464
470
465
471
// 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 */ );
467
473
CAmount target_with_change = nTargetValue;
468
474
// While nTargetValue includes the transaction fees for non-input things, it does not include the fee for creating a change output.
469
475
// 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
496
502
return best_result;
497
503
}
498
504
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)
500
506
{
501
- std::vector<COutput> vCoins (vAvailableCoins);
502
507
CAmount value_to_select = nTargetValue;
503
508
504
509
OutputGroup preset_inputs (coin_selection_params);
@@ -558,13 +563,13 @@ std::optional<SelectionResult> SelectCoins(const CWallet& wallet, const std::vec
558
563
return result;
559
564
}
560
565
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 ()) ;
568
573
}
569
574
570
575
unsigned int limit_ancestor_count = 0 ;
@@ -576,11 +581,15 @@ std::optional<SelectionResult> SelectCoins(const CWallet& wallet, const std::vec
576
581
577
582
// form groups from remaining coins; note that preset coins will not
578
583
// 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) {
580
585
// Cases where we have 101+ outputs all pointing to the same destination may result in
581
586
// privacy leaks as they will potentially be deterministically sorted. We solve that by
582
587
// 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 );
584
593
}
585
594
586
595
// 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
592
601
593
602
// If possible, fund the transaction with confirmed UTXOs only. Prefer at least six
594
603
// 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;
597
606
598
607
// Fall back to using zero confirmation change (but with as few ancestors in the mempool as
599
608
// possible) if we cannot fund the transaction otherwise.
600
609
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;
602
611
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)}) {
604
613
return r4;
605
614
}
606
615
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)}) {
608
617
return r5;
609
618
}
610
619
// If partial groups are allowed, relax the requirement of spending OutputGroups (groups
611
620
// of UTXOs sent to the same address, which are obviously controlled by a single wallet)
612
621
// in their entirety.
613
622
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)}) {
615
624
return r6;
616
625
}
617
626
// Try with unsafe inputs if they are allowed. This may spend unconfirmed outputs
618
627
// received from other wallets.
619
628
if (coin_control.m_include_unsafe_inputs ) {
620
629
if (auto r7{AttemptSelection (wallet, value_to_select,
621
630
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)}) {
623
632
return r7;
624
633
}
625
634
}
@@ -629,7 +638,7 @@ std::optional<SelectionResult> SelectCoins(const CWallet& wallet, const std::vec
629
638
if (!fRejectLongChains ) {
630
639
if (auto r8{AttemptSelection (wallet, value_to_select,
631
640
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)}) {
633
642
return r8;
634
643
}
635
644
}
@@ -849,7 +858,7 @@ static BResult<CreatedTransactionResult> CreateTransactionInternal(
849
858
CAmount selection_target = recipients_sum + not_input_fees;
850
859
851
860
// Get available coins
852
- auto res_available_coins = AvailableCoins (wallet,
861
+ auto available_coins = AvailableCoins (wallet,
853
862
&coin_control,
854
863
coin_selection_params.m_effective_feerate ,
855
864
1 , /* nMinimumAmount*/
@@ -858,7 +867,7 @@ static BResult<CreatedTransactionResult> CreateTransactionInternal(
858
867
0 ); /* nMaximumCount*/
859
868
860
869
// 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);
862
871
if (!result) {
863
872
return _ (" Insufficient funds" );
864
873
}
0 commit comments