@@ -79,30 +79,27 @@ TxSize CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *walle
7979 return CalculateMaximumSignedTxSize (tx, wallet, txouts, coin_control);
8080}
8181
82- uint64_t CoinsResult::Size () const
82+ size_t CoinsResult::Size () const
8383{
84- return bech32m.size () + bech32.size () + P2SH_segwit.size () + legacy.size () + other.size ();
84+ size_t size{0 };
85+ for (const auto & it : coins) {
86+ size += it.second .size ();
87+ }
88+ return size;
8589}
8690
8791std::vector<COutput> CoinsResult::All () const
8892{
8993 std::vector<COutput> all;
90- all.reserve (this ->Size ());
91- all.insert (all.end (), bech32m.begin (), bech32m.end ());
92- all.insert (all.end (), bech32.begin (), bech32.end ());
93- all.insert (all.end (), P2SH_segwit.begin (), P2SH_segwit.end ());
94- all.insert (all.end (), legacy.begin (), legacy.end ());
95- all.insert (all.end (), other.begin (), other.end ());
94+ all.reserve (coins.size ());
95+ for (const auto & it : coins) {
96+ all.insert (all.end (), it.second .begin (), it.second .end ());
97+ }
9698 return all;
9799}
98100
99- void CoinsResult::Clear ()
100- {
101- bech32m.clear ();
102- bech32.clear ();
103- P2SH_segwit.clear ();
104- legacy.clear ();
105- other.clear ();
101+ void CoinsResult::Clear () {
102+ coins.clear ();
106103}
107104
108105void CoinsResult::Erase (std::set<COutPoint>& preset_coins)
@@ -263,51 +260,32 @@ CoinsResult AvailableCoins(const CWallet& wallet,
263260 // Filter by spendable outputs only
264261 if (!spendable && only_spendable) continue ;
265262
266- // When parsing a scriptPubKey, Solver returns the parsed pubkeys or hashes (depending on the script)
267- // We don't need those here, so we are leaving them in return_values_unused
268- std::vector<std::vector<uint8_t >> return_values_unused;
269- TxoutType type;
270- bool is_from_p2sh{false };
271-
272263 // If the Output is P2SH and spendable, we want to know if it is
273264 // a P2SH (legacy) or one of P2SH-P2WPKH, P2SH-P2WSH (P2SH-Segwit). We can determine
274265 // this from the redeemScript. If the Output is not spendable, it will be classified
275266 // as a P2SH (legacy), since we have no way of knowing otherwise without the redeemScript
267+ CScript script;
268+ bool is_from_p2sh{false };
276269 if (output.scriptPubKey .IsPayToScriptHash () && solvable) {
277- CScript redeemScript;
278270 CTxDestination destination;
279271 if (!ExtractDestination (output.scriptPubKey , destination))
280272 continue ;
281273 const CScriptID& hash = CScriptID (std::get<ScriptHash>(destination));
282- if (!provider->GetCScript (hash, redeemScript ))
274+ if (!provider->GetCScript (hash, script ))
283275 continue ;
284- type = Solver (redeemScript, return_values_unused);
285276 is_from_p2sh = true ;
286277 } else {
287- type = Solver ( output.scriptPubKey , return_values_unused) ;
278+ script = output.scriptPubKey ;
288279 }
289280
290281 COutput coin (outpoint, output, nDepth, input_bytes, spendable, solvable, safeTx, wtx.GetTxTime (), tx_from_me, feerate);
291- switch (type) {
292- case TxoutType::WITNESS_UNKNOWN:
293- case TxoutType::WITNESS_V1_TAPROOT:
294- result.bech32m .push_back (coin);
295- break ;
296- case TxoutType::WITNESS_V0_KEYHASH:
297- case TxoutType::WITNESS_V0_SCRIPTHASH:
298- if (is_from_p2sh) {
299- result.P2SH_segwit .push_back (coin);
300- break ;
301- }
302- result.bech32 .push_back (coin);
303- break ;
304- case TxoutType::SCRIPTHASH:
305- case TxoutType::PUBKEYHASH:
306- result.legacy .push_back (coin);
307- break ;
308- default :
309- result.other .push_back (coin);
310- };
282+
283+ // When parsing a scriptPubKey, Solver returns the parsed pubkeys or hashes (depending on the script)
284+ // We don't need those here, so we are leaving them in return_values_unused
285+ std::vector<std::vector<uint8_t >> return_values_unused;
286+ TxoutType type;
287+ type = Solver (script, return_values_unused);
288+ result.Add (GetOutputType (type, is_from_p2sh), coin);
311289
312290 // Cache total amount as we go
313291 result.total_amount += output.nValue ;
@@ -498,17 +476,10 @@ std::optional<SelectionResult> AttemptSelection(const CWallet& wallet, const CAm
498476{
499477 // Run coin selection on each OutputType and compute the Waste Metric
500478 std::vector<SelectionResult> results;
501- if (auto result{ChooseSelectionResult (wallet, nTargetValue, eligibility_filter, available_coins.legacy , coin_selection_params)}) {
502- results.push_back (*result);
503- }
504- if (auto result{ChooseSelectionResult (wallet, nTargetValue, eligibility_filter, available_coins.P2SH_segwit , coin_selection_params)}) {
505- results.push_back (*result);
506- }
507- if (auto result{ChooseSelectionResult (wallet, nTargetValue, eligibility_filter, available_coins.bech32 , coin_selection_params)}) {
508- results.push_back (*result);
509- }
510- if (auto result{ChooseSelectionResult (wallet, nTargetValue, eligibility_filter, available_coins.bech32m , coin_selection_params)}) {
511- results.push_back (*result);
479+ for (const auto & it : available_coins.coins ) {
480+ if (auto result{ChooseSelectionResult (wallet, nTargetValue, eligibility_filter, it.second , coin_selection_params)}) {
481+ results.push_back (*result);
482+ }
512483 }
513484
514485 // If we can't fund the transaction from any individual OutputType, run coin selection
@@ -633,11 +604,7 @@ std::optional<SelectionResult> SelectCoins(const CWallet& wallet, CoinsResult& a
633604
634605 // remove preset inputs from coins so that Coin Selection doesn't pick them.
635606 if (coin_control.HasSelected ()) {
636- 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 ());
637- 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 ());
638- 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 ());
639- 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 ());
640- 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 ());
607+ available_coins.Erase (preset_coins);
641608 }
642609
643610 unsigned int limit_ancestor_count = 0 ;
@@ -653,11 +620,7 @@ std::optional<SelectionResult> SelectCoins(const CWallet& wallet, CoinsResult& a
653620 // Cases where we have 101+ outputs all pointing to the same destination may result in
654621 // privacy leaks as they will potentially be deterministically sorted. We solve that by
655622 // explicitly shuffling the outputs before processing
656- Shuffle (available_coins.legacy .begin (), available_coins.legacy .end (), coin_selection_params.rng_fast );
657- Shuffle (available_coins.P2SH_segwit .begin (), available_coins.P2SH_segwit .end (), coin_selection_params.rng_fast );
658- Shuffle (available_coins.bech32 .begin (), available_coins.bech32 .end (), coin_selection_params.rng_fast );
659- Shuffle (available_coins.bech32m .begin (), available_coins.bech32m .end (), coin_selection_params.rng_fast );
660- Shuffle (available_coins.other .begin (), available_coins.other .end (), coin_selection_params.rng_fast );
623+ available_coins.Shuffle (coin_selection_params.rng_fast );
661624 }
662625
663626 // Coin Selection attempts to select inputs from a pool of eligible UTXOs to fund the
0 commit comments