@@ -143,6 +143,51 @@ static OutputType GetOutputType(TxoutType type, bool is_from_p2sh)
143
143
}
144
144
}
145
145
146
+ // Fetch and validate the coin control selected inputs.
147
+ // Coins could be internal (from the wallet) or external.
148
+ util::Result<PreSelectedInputs> FetchSelectedInputs (const CWallet& wallet, const CCoinControl& coin_control,
149
+ const CoinSelectionParams& coin_selection_params) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
150
+ {
151
+ PreSelectedInputs result;
152
+ std::vector<COutPoint> vPresetInputs;
153
+ coin_control.ListSelected (vPresetInputs);
154
+ for (const COutPoint& outpoint : vPresetInputs) {
155
+ int input_bytes = -1 ;
156
+ CTxOut txout;
157
+ if (auto ptr_wtx = wallet.GetWalletTx (outpoint.hash )) {
158
+ // Clearly invalid input, fail
159
+ if (ptr_wtx->tx ->vout .size () <= outpoint.n ) {
160
+ return util::Error{strprintf (_ (" Invalid pre-selected input %s" ), outpoint.ToString ())};
161
+ }
162
+ txout = ptr_wtx->tx ->vout .at (outpoint.n );
163
+ input_bytes = CalculateMaximumSignedInputSize (txout, &wallet, &coin_control);
164
+ } else {
165
+ // The input is external. We did not find the tx in mapWallet.
166
+ if (!coin_control.GetExternalOutput (outpoint, txout)) {
167
+ return util::Error{strprintf (_ (" Not found pre-selected input %s" ), outpoint.ToString ())};
168
+ }
169
+ }
170
+
171
+ if (input_bytes == -1 ) {
172
+ input_bytes = CalculateMaximumSignedInputSize (txout, outpoint, &coin_control.m_external_provider , &coin_control);
173
+ }
174
+
175
+ // If available, override calculated size with coin control specified size
176
+ if (coin_control.HasInputWeight (outpoint)) {
177
+ input_bytes = GetVirtualTransactionSize (coin_control.GetInputWeight (outpoint), 0 , 0 );
178
+ }
179
+
180
+ if (input_bytes == -1 ) {
181
+ return util::Error{strprintf (_ (" Not solvable pre-selected input %s" ), outpoint.ToString ())}; // Not solvable, can't estimate size for fee
182
+ }
183
+
184
+ /* Set some defaults for depth, spendable, solvable, safe, time, and from_me as these don't matter for preset inputs since no selection is being done. */
185
+ COutput output (outpoint, txout, /* depth=*/ 0 , input_bytes, /* spendable=*/ true , /* solvable=*/ true , /* safe=*/ true , /* time=*/ 0 , /* from_me=*/ false , coin_selection_params.m_effective_feerate );
186
+ result.Insert (output, coin_selection_params.m_subtract_fee_outputs );
187
+ }
188
+ return result;
189
+ }
190
+
146
191
CoinsResult AvailableCoins (const CWallet& wallet,
147
192
const CCoinControl* coinControl,
148
193
std::optional<CFeeRate> feerate,
@@ -527,58 +572,14 @@ std::optional<SelectionResult> SelectCoins(const CWallet& wallet, CoinsResult& a
527
572
{
528
573
CAmount value_to_select = nTargetValue;
529
574
530
- OutputGroup preset_inputs (coin_selection_params);
575
+ util::Result<PreSelectedInputs> pre_selected_inputs = FetchSelectedInputs (wallet, coin_control, coin_selection_params);
576
+ if (!pre_selected_inputs) return std::nullopt;
577
+ PreSelectedInputs inputs = *pre_selected_inputs;
531
578
532
- std::vector<COutPoint> vPresetInputs;
533
- coin_control.ListSelected (vPresetInputs);
534
- for (const COutPoint& outpoint : vPresetInputs) {
535
- int input_bytes = -1 ;
536
- CTxOut txout;
537
- auto ptr_wtx = wallet.GetWalletTx (outpoint.hash );
538
- if (ptr_wtx) {
539
- // Clearly invalid input, fail
540
- if (ptr_wtx->tx ->vout .size () <= outpoint.n ) {
541
- return std::nullopt;
542
- }
543
- txout = ptr_wtx->tx ->vout .at (outpoint.n );
544
- input_bytes = CalculateMaximumSignedInputSize (txout, &wallet, &coin_control);
545
- } else {
546
- // The input is external. We did not find the tx in mapWallet.
547
- if (!coin_control.GetExternalOutput (outpoint, txout)) {
548
- return std::nullopt;
549
- }
550
- }
551
-
552
- if (input_bytes == -1 ) {
553
- input_bytes = CalculateMaximumSignedInputSize (txout, outpoint, &coin_control.m_external_provider , &coin_control);
554
- }
555
-
556
- // If available, override calculated size with coin control specified size
557
- if (coin_control.HasInputWeight (outpoint)) {
558
- input_bytes = GetVirtualTransactionSize (coin_control.GetInputWeight (outpoint), 0 , 0 );
559
- }
560
-
561
- if (input_bytes == -1 ) {
562
- return std::nullopt; // Not solvable, can't estimate size for fee
563
- }
564
-
565
- /* Set some defaults for depth, spendable, solvable, safe, time, and from_me as these don't matter for preset inputs since no selection is being done. */
566
- COutput output (outpoint, txout, /* depth=*/ 0 , input_bytes, /* spendable=*/ true , /* solvable=*/ true , /* safe=*/ true , /* time=*/ 0 , /* from_me=*/ false , coin_selection_params.m_effective_feerate );
567
- if (coin_selection_params.m_subtract_fee_outputs ) {
568
- value_to_select -= output.txout .nValue ;
569
- } else {
570
- value_to_select -= output.GetEffectiveValue ();
571
- }
572
- /* Set ancestors and descendants to 0 as they don't matter for preset inputs since no actual selection is being done.
573
- * positive_only is set to false because we want to include all preset inputs, even if they are dust.
574
- */
575
- preset_inputs.Insert (output, /* ancestors=*/ 0 , /* descendants=*/ 0 , /* positive_only=*/ false );
576
- }
577
-
578
- // coin control -> return all selected outputs (we want all selected to go into the transaction for sure)
579
+ // If automatic coin selection was disabled, we just want to return the preset inputs result
579
580
if (!coin_control.m_allow_other_inputs ) {
580
581
SelectionResult result (nTargetValue, SelectionAlgorithm::MANUAL);
581
- result.AddInput (preset_inputs );
582
+ result.AddInputs (inputs. coins , coin_selection_params. m_subtract_fee_outputs );
582
583
583
584
if (!coin_selection_params.m_subtract_fee_outputs && result.GetSelectedEffectiveValue () < nTargetValue) {
584
585
return std::nullopt;
@@ -590,6 +591,9 @@ std::optional<SelectionResult> SelectCoins(const CWallet& wallet, CoinsResult& a
590
591
return result;
591
592
}
592
593
594
+ // Decrease the already selected amount
595
+ value_to_select -= inputs.total_amount ;
596
+
593
597
unsigned int limit_ancestor_count = 0 ;
594
598
unsigned int limit_descendant_count = 0 ;
595
599
wallet.chain ().getPackageLimits (limit_ancestor_count, limit_descendant_count);
@@ -606,8 +610,8 @@ std::optional<SelectionResult> SelectCoins(const CWallet& wallet, CoinsResult& a
606
610
available_coins.Shuffle (coin_selection_params.rng_fast );
607
611
}
608
612
609
- SelectionResult preselected (preset_inputs. GetSelectionAmount () , SelectionAlgorithm::MANUAL);
610
- preselected.AddInput (preset_inputs );
613
+ SelectionResult preselected (inputs. total_amount , SelectionAlgorithm::MANUAL);
614
+ preselected.AddInputs (inputs. coins , coin_selection_params. m_subtract_fee_outputs );
611
615
612
616
// Coin Selection attempts to select inputs from a pool of eligible UTXOs to fund the
613
617
// transaction at a target feerate. If an attempt fails, more attempts may be made using a more
0 commit comments