@@ -79,6 +79,32 @@ TxSize CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *walle
7979 return CalculateMaximumSignedTxSize (tx, wallet, txouts, coin_control);
8080}
8181
82+ uint64_t CoinsResult::size () const
83+ {
84+ return bech32m.size () + bech32.size () + P2SH_segwit.size () + legacy.size () + other.size ();
85+ }
86+
87+ std::vector<COutput> CoinsResult::all () const
88+ {
89+ 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 ());
96+ return all;
97+ }
98+
99+ void CoinsResult::clear ()
100+ {
101+ bech32m.clear ();
102+ bech32.clear ();
103+ P2SH_segwit.clear ();
104+ legacy.clear ();
105+ other.clear ();
106+ }
107+
82108CoinsResult AvailableCoins (const CWallet& wallet,
83109 const CCoinControl* coinControl,
84110 std::optional<CFeeRate> feerate,
@@ -193,10 +219,55 @@ CoinsResult AvailableCoins(const CWallet& wallet,
193219 // Filter by spendable outputs only
194220 if (!spendable && only_spendable) continue ;
195221
222+ // When parsing a scriptPubKey, Solver returns the parsed pubkeys or hashes (depending on the script)
223+ // We don't need those here, so we are leaving them in return_values_unused
224+ std::vector<std::vector<uint8_t >> return_values_unused;
225+ TxoutType type;
226+ bool is_from_p2sh{false };
227+
228+ // If the Output is P2SH and spendable, we want to know if it is
229+ // a P2SH (legacy) or one of P2SH-P2WPKH, P2SH-P2WSH (P2SH-Segwit). We can determine
230+ // this from the redeemScript. If the Output is not spendable, it will be classified
231+ // as a P2SH (legacy), since we have no way of knowing otherwise without the redeemScript
232+ if (output.scriptPubKey .IsPayToScriptHash () && solvable) {
233+ CScript redeemScript;
234+ CTxDestination destination;
235+ if (!ExtractDestination (output.scriptPubKey , destination))
236+ continue ;
237+ const CScriptID& hash = CScriptID (std::get<ScriptHash>(destination));
238+ if (!provider->GetCScript (hash, redeemScript))
239+ continue ;
240+ type = Solver (redeemScript, return_values_unused);
241+ is_from_p2sh = true ;
242+ } else {
243+ type = Solver (output.scriptPubKey , return_values_unused);
244+ }
245+
196246 int input_bytes = CalculateMaximumSignedInputSize (output, COutPoint (), provider.get (), coinControl);
197- result.coins .emplace_back (outpoint, output, nDepth, input_bytes, spendable, solvable, safeTx, wtx.GetTxTime (), tx_from_me, feerate);
247+ COutput coin (outpoint, output, nDepth, input_bytes, spendable, solvable, safeTx, wtx.GetTxTime (), tx_from_me, feerate);
248+ switch (type) {
249+ case TxoutType::WITNESS_UNKNOWN:
250+ case TxoutType::WITNESS_V1_TAPROOT:
251+ result.bech32m .push_back (coin);
252+ break ;
253+ case TxoutType::WITNESS_V0_KEYHASH:
254+ case TxoutType::WITNESS_V0_SCRIPTHASH:
255+ if (is_from_p2sh) {
256+ result.P2SH_segwit .push_back (coin);
257+ break ;
258+ }
259+ result.bech32 .push_back (coin);
260+ break ;
261+ case TxoutType::SCRIPTHASH:
262+ case TxoutType::PUBKEYHASH:
263+ result.legacy .push_back (coin);
264+ break ;
265+ default :
266+ result.other .push_back (coin);
267+ };
268+
269+ // Cache total amount as we go
198270 result.total_amount += output.nValue ;
199-
200271 // Checks the sum amount of all UTXO's.
201272 if (nMinimumSumAmount != MAX_MONEY) {
202273 if (result.total_amount >= nMinimumSumAmount) {
@@ -205,7 +276,7 @@ CoinsResult AvailableCoins(const CWallet& wallet,
205276 }
206277
207278 // Checks the maximum number of UTXO's.
208- if (nMaximumCount > 0 && result.coins . size () >= nMaximumCount) {
279+ if (nMaximumCount > 0 && result.size () >= nMaximumCount) {
209280 return result;
210281 }
211282 }
@@ -261,7 +332,7 @@ std::map<CTxDestination, std::vector<COutput>> ListCoins(const CWallet& wallet)
261332
262333 std::map<CTxDestination, std::vector<COutput>> result;
263334
264- for (const COutput& coin : AvailableCoinsListUnspent (wallet).coins ) {
335+ for (const COutput& coin : AvailableCoinsListUnspent (wallet).all () ) {
265336 CTxDestination address;
266337 if ((coin.spendable || (wallet.IsWalletFlagSet (WALLET_FLAG_DISABLE_PRIVATE_KEYS) && coin.solvable )) &&
267338 ExtractDestination (FindNonChangeParentOutput (wallet, coin.outpoint ).scriptPubKey , address)) {
@@ -787,7 +858,7 @@ static BResult<CreatedTransactionResult> CreateTransactionInternal(
787858 0 ); /* nMaximumCount*/
788859
789860 // Choose coins to use
790- std::optional<SelectionResult> result = SelectCoins (wallet, res_available_coins.coins , /* nTargetValue=*/ selection_target, coin_control, coin_selection_params);
861+ std::optional<SelectionResult> result = SelectCoins (wallet, res_available_coins.all () , /* nTargetValue=*/ selection_target, coin_control, coin_selection_params);
791862 if (!result) {
792863 return _ (" Insufficient funds" );
793864 }
0 commit comments