@@ -414,27 +414,31 @@ std::optional<SelectionResult> AttemptSelection(const CWallet& wallet, const CAm
414
414
return best_result;
415
415
}
416
416
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)
417
+ std::optional<SelectionResult> SelectCoins (const CWallet& wallet, const std::vector<COutput>& vAvailableCoins, const CAmount& nTargetValue, const CCoinControl& coin_control, const CoinSelectionParams& coin_selection_params)
418
418
{
419
419
std::vector<COutput> vCoins (vAvailableCoins);
420
420
CAmount value_to_select = nTargetValue;
421
421
422
+ OutputGroup preset_inputs (coin_selection_params);
423
+
422
424
// coin control -> return all selected outputs (we want all selected to go into the transaction for sure)
423
425
if (coin_control.HasSelected () && !coin_control.fAllowOtherInputs )
424
426
{
425
- for (const COutput& out : vCoins)
426
- {
427
- if (!out. fSpendable )
428
- continue ;
429
- nValueRet += out. tx -> tx -> vout [out. i ]. nValue ;
430
- setCoinsRet. insert (out.GetInputCoin ());
427
+ for (const COutput& out : vCoins) {
428
+ if (!out. fSpendable ) continue ;
429
+ /* Set depth, from_me, ancestors, and descendants to 0 or false as these don't matter for preset inputs as no actual selection is being done.
430
+ * positive_only is set to false because we want to include all preset inputs, even if they are dust.
431
+ */
432
+ preset_inputs. Insert (out.GetInputCoin (), 0 , false , 0 , 0 , false );
431
433
}
432
- return (nValueRet >= nTargetValue);
434
+ SelectionResult result (nTargetValue);
435
+ result.AddInput (preset_inputs);
436
+ if (result.GetSelectedValue () < nTargetValue) return std::nullopt;
437
+ return result;
433
438
}
434
439
435
440
// calculate value from preset inputs and store them
436
441
std::set<CInputCoin> setPresetCoins;
437
- OutputGroup preset_inputs (coin_selection_params);
438
442
439
443
std::vector<COutPoint> vPresetInputs;
440
444
coin_control.ListSelected (vPresetInputs);
@@ -446,7 +450,7 @@ bool SelectCoins(const CWallet& wallet, const std::vector<COutput>& vAvailableCo
446
450
const CWalletTx& wtx = it->second ;
447
451
// Clearly invalid input, fail
448
452
if (wtx.tx ->vout .size () <= outpoint.n ) {
449
- return false ;
453
+ return std::nullopt ;
450
454
}
451
455
input_bytes = GetTxSpendSize (wallet, wtx, outpoint.n , false );
452
456
txout = wtx.tx ->vout .at (outpoint.n );
@@ -455,14 +459,14 @@ bool SelectCoins(const CWallet& wallet, const std::vector<COutput>& vAvailableCo
455
459
// The input is external. We either did not find the tx in mapWallet, or we did but couldn't compute the input size with wallet data
456
460
if (!coin_control.GetExternalOutput (outpoint, txout)) {
457
461
// Not ours, and we don't have solving data.
458
- return false ;
462
+ return std::nullopt ;
459
463
}
460
464
input_bytes = CalculateMaximumSignedInputSize (txout, &coin_control.m_external_provider , /* use_max_sig */ true );
461
465
}
462
466
463
467
CInputCoin coin (outpoint, txout, input_bytes);
464
468
if (coin.m_input_bytes == -1 ) {
465
- return false ; // Not solvable, can't estimate size for fee
469
+ return std::nullopt ; // Not solvable, can't estimate size for fee
466
470
}
467
471
coin.effective_value = coin.txout .nValue - coin_selection_params.m_effective_feerate .GetFee (coin.m_input_bytes );
468
472
if (coin_selection_params.m_subtract_fee_outputs ) {
@@ -557,15 +561,12 @@ bool SelectCoins(const CWallet& wallet, const std::vector<COutput>& vAvailableCo
557
561
return std::optional<SelectionResult>();
558
562
}();
559
563
560
- if (!res) return false ;
564
+ if (!res) return std::nullopt ;
561
565
562
566
// Add preset inputs to result
563
567
res->AddInput (preset_inputs);
564
568
565
- setCoinsRet = res->GetInputSet ();
566
- nValueRet = res->GetSelectedValue ();
567
-
568
- return true ;
569
+ return res;
569
570
}
570
571
571
572
static bool IsCurrentForAntiFeeSniping (interfaces::Chain& chain, const uint256& block_hash)
@@ -761,17 +762,15 @@ static bool CreateTransactionInternal(
761
762
AvailableCoins (wallet, vAvailableCoins, &coin_control, 1 , MAX_MONEY, MAX_MONEY, 0 );
762
763
763
764
// Choose coins to use
764
- CAmount inputs_sum = 0 ;
765
- std::set<CInputCoin> setCoins;
766
- if (!SelectCoins (wallet, vAvailableCoins, /* nTargetValue */ selection_target, setCoins, inputs_sum, coin_control, coin_selection_params))
767
- {
765
+ std::optional<SelectionResult> result = SelectCoins (wallet, vAvailableCoins, /* nTargetValue */ selection_target, coin_control, coin_selection_params);
766
+ if (!result) {
768
767
error = _ (" Insufficient funds" );
769
768
return false ;
770
769
}
771
770
772
771
// Always make a change output
773
772
// We will reduce the fee from this change output later, and remove the output if it is too small.
774
- const CAmount change_and_fee = inputs_sum - recipients_sum;
773
+ const CAmount change_and_fee = result-> GetSelectedValue () - recipients_sum;
775
774
assert (change_and_fee >= 0 );
776
775
CTxOut newTxOut (change_and_fee, scriptChange);
777
776
@@ -790,8 +789,7 @@ static bool CreateTransactionInternal(
790
789
auto change_position = txNew.vout .insert (txNew.vout .begin () + nChangePosInOut, newTxOut);
791
790
792
791
// Shuffle selected coins and fill in final vin
793
- std::vector<CInputCoin> selected_coins (setCoins.begin (), setCoins.end ());
794
- Shuffle (selected_coins.begin (), selected_coins.end (), FastRandomContext ());
792
+ std::vector<CInputCoin> selected_coins = result->GetShuffledInputVector ();
795
793
796
794
// Note how the sequence number is set to non-maxint so that
797
795
// the nLockTime set above actually works.
0 commit comments