LCOV - code coverage report
Current view: top level - src/wallet - spend.cpp (source / functions) Hit Total Coverage
Test: test_dash_coverage.info Lines: 528 681 77.5 %
Date: 2026-06-25 07:23:51 Functions: 29 32 90.6 %

          Line data    Source code
       1             : // Copyright (c) 2021 The Bitcoin Core developers
       2             : // Distributed under the MIT software license, see the accompanying
       3             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       4             : 
       5             : #include <coinjoin/common.h>
       6             : #include <coinjoin/options.h>
       7             : #include <consensus/consensus.h>
       8             : #include <consensus/validation.h>
       9             : #include <evo/dmn_types.h>
      10             : #include <interfaces/chain.h>
      11             : #include <policy/policy.h>
      12             : #include <script/signingprovider.h>
      13             : #include <util/check.h>
      14             : #include <util/fees.h>
      15             : #include <util/moneystr.h>
      16             : #include <util/trace.h>
      17             : #include <util/translation.h>
      18             : #include <wallet/coincontrol.h>
      19             : #include <wallet/fees.h>
      20             : #include <wallet/receive.h>
      21             : #include <wallet/spend.h>
      22             : #include <wallet/transaction.h>
      23             : #include <wallet/wallet.h>
      24             : 
      25             : #include <cmath>
      26             : 
      27             : using interfaces::FoundBlock;
      28             : 
      29             : namespace wallet {
      30             : static constexpr size_t OUTPUT_GROUP_MAX_ENTRIES{100};
      31             : 
      32      112410 : int CalculateMaximumSignedInputSize(const CTxOut& txout, const COutPoint outpoint, const SigningProvider* provider, const CCoinControl* coin_control)
      33             : {
      34      112410 :     CMutableTransaction txn;
      35      112410 :     txn.vin.push_back(CTxIn(outpoint));
      36      112410 :     if (!provider || !DummySignInput(*provider, txn.vin[0], txout, coin_control)) {
      37      110008 :         return -1;
      38             :     }
      39        2402 :     return ::GetSerializeSize(txn.vin[0], PROTOCOL_VERSION);
      40      112410 : }
      41             : 
      42      110826 : int CalculateMaximumSignedInputSize(const CTxOut& txout, const CWallet* wallet, const CCoinControl* coin_control)
      43             : {
      44      110826 :     const std::unique_ptr<SigningProvider> provider = wallet->GetSolvingProvider(txout.scriptPubKey);
      45      110826 :     return CalculateMaximumSignedInputSize(txout, COutPoint(), provider.get(), coin_control);
      46      110826 : }
      47             : 
      48             : // txouts needs to be in the order of tx.vin
      49         262 : int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet, const std::vector<CTxOut>& txouts, const CCoinControl* coin_control)
      50             : {
      51         262 :     CMutableTransaction txNew(tx);
      52         262 :     if (!wallet->DummySignTx(txNew, txouts, coin_control)) {
      53           0 :         return -1;
      54             :     }
      55         262 :     return ::GetSerializeSize(txNew, PROTOCOL_VERSION);
      56         262 : }
      57             : 
      58         262 : int64_t CalculateMaximumSignedTxSize(const CTransaction &tx, const CWallet *wallet, const CCoinControl* coin_control)
      59             : {
      60         262 :     std::vector<CTxOut> txouts;
      61             :     // Look up the inputs. The inputs are either in the wallet, or in coin_control.
      62        1380 :     for (const CTxIn& input : tx.vin) {
      63        1118 :         const auto mi = wallet->mapWallet.find(input.prevout.hash);
      64             :         // Can not estimate size without knowing the input details
      65        1118 :         if (mi != wallet->mapWallet.end()) {
      66        1118 :             assert(input.prevout.n < mi->second.tx->vout.size());
      67        1118 :             txouts.emplace_back(mi->second.tx->vout.at(input.prevout.n));
      68        1118 :         } else if (coin_control) {
      69           0 :             const auto txout{coin_control->GetExternalOutput(input.prevout)};
      70           0 :             if (!txout) {
      71           0 :                 return -1;
      72             :             }
      73           0 :             txouts.emplace_back(*txout);
      74           0 :         } else {
      75           0 :             return -1;
      76             :         }
      77             :     }
      78         262 :     return CalculateMaximumSignedTxSize(tx, wallet, txouts, coin_control);
      79         262 : }
      80             : 
      81        5721 : uint64_t CoinsResult::size() const
      82             : {
      83        5721 :     return legacy.size() + other.size();
      84             : }
      85             : 
      86        5677 : std::vector<COutput> CoinsResult::all() const
      87             : {
      88        5677 :     std::vector<COutput> all;
      89        5677 :     all.reserve(this->size());
      90        5677 :     all.insert(all.end(), legacy.begin(), legacy.end());
      91        5677 :     all.insert(all.end(), other.begin(), other.end());
      92        5677 :     return all;
      93        5677 : }
      94             : 
      95         709 : void CoinsResult::clear()
      96             : {
      97         709 :     legacy.clear();
      98         709 :     other.clear();
      99         709 : }
     100             : 
     101         235 : CoinsResult AvailableCoins(const CWallet& wallet,
     102             :                            const CCoinControl* coinControl,
     103             :                            std::optional<CFeeRate> feerate,
     104             :                            const CAmount& nMinimumAmount,
     105             :                            const CAmount& nMaximumAmount,
     106             :                            const CAmount& nMinimumSumAmount,
     107             :                            const uint64_t nMaximumCount,
     108             :                            bool only_spendable)
     109             : {
     110         235 :     AssertLockHeld(wallet.cs_wallet);
     111             : 
     112         235 :     CoinType nCoinType = coinControl ? coinControl->nCoinType : CoinType::ALL_COINS;
     113             : 
     114         235 :     CoinsResult result;
     115             :     // Either the WALLET_FLAG_AVOID_REUSE flag is not set (in which case we always allow), or we default to avoiding, and only in the case where
     116             :     // a coin control object is provided, and has the avoid address reuse flag set to false, do we allow already used addresses
     117         235 :     bool allow_used_addresses = !wallet.IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE) || (coinControl && !coinControl->m_avoid_address_reuse);
     118         235 :     const int min_depth = {coinControl ? coinControl->m_min_depth : DEFAULT_MIN_DEPTH};
     119         235 :     const int max_depth = {coinControl ? coinControl->m_max_depth : DEFAULT_MAX_DEPTH};
     120         235 :     const bool only_safe = {coinControl ? !coinControl->m_include_unsafe_inputs : true};
     121             : 
     122         235 :     std::set<uint256> trusted_parents;
     123       24245 :     for (const auto* pwtx : wallet.GetSpendableTXs()) {
     124       24010 :         const uint256& wtxid = pwtx->GetHash();
     125       24010 :         const CWalletTx& wtx = *pwtx;
     126             : 
     127       24010 :         if (wallet.IsTxImmatureCoinBase(wtx))
     128       22891 :             continue;
     129             : 
     130        1119 :         int nDepth = wallet.GetTxDepthInMainChain(wtx);
     131             : 
     132             :         // We should not consider coins which aren't at least in our mempool
     133             :         // It's possible for these to be conflicted via ancestors which we may never be able to detect
     134        1119 :         if (nDepth == 0 && !wtx.InMempool())
     135           1 :             continue;
     136             : 
     137        1118 :         bool safeTx = CachedTxIsTrusted(wallet, wtx, trusted_parents);
     138             : 
     139        1118 :         if (only_safe && !safeTx) {
     140           1 :             continue;
     141             :         }
     142             : 
     143        1117 :         if (nDepth < min_depth || nDepth > max_depth) {
     144           0 :             continue;
     145             :         }
     146             : 
     147        1117 :         bool tx_from_me = CachedTxIsFromMe(wallet, wtx, ISMINE_ALL);
     148             : 
     149        5094 :         for (unsigned int i = 0; i < wtx.tx->vout.size(); i++) {
     150        3977 :             const CTxOut& output = wtx.tx->vout[i];
     151        3977 :             const COutPoint outpoint(wtxid, i);
     152             : 
     153        3977 :             bool found = false;
     154        3977 :             switch (nCoinType) {
     155             :                 case CoinType::ONLY_FULLY_MIXED: {
     156          39 :                     found = CoinJoin::IsDenominatedAmount(output.nValue) &&
     157           0 :                             wallet.IsFullyMixed(outpoint);
     158          39 :                     break;
     159             :                 }
     160             :                 case CoinType::ONLY_READY_TO_MIX: {
     161           0 :                     found = CoinJoin::IsDenominatedAmount(output.nValue) &&
     162           0 :                             !wallet.IsFullyMixed(outpoint);
     163           0 :                     break;
     164             :                 }
     165             :                 case CoinType::ONLY_NONDENOMINATED: {
     166             :                     // NOTE: do not use collateral amounts
     167          67 :                     found = !CoinJoin::IsCollateralAmount(output.nValue) &&
     168          28 :                             !CoinJoin::IsDenominatedAmount(output.nValue);
     169          39 :                     break;
     170             :                 }
     171             :                 case CoinType::ONLY_MASTERNODE_COLLATERAL: {
     172           0 :                     found = dmn_types::IsCollateralAmount(output.nValue);
     173           0 :                     break;
     174             :                 }
     175             :                 case CoinType::ONLY_COINJOIN_COLLATERAL: {
     176           0 :                     found = CoinJoin::IsCollateralAmount(output.nValue);
     177           0 :                     break;
     178             :                 }
     179             :                 case CoinType::ALL_COINS: {
     180        3899 :                     found = true;
     181        3899 :                     break;
     182             :                 }
     183             :             } // no default case, so the compiler can warn about missing cases
     184        3977 :             if (!found) continue;
     185             : 
     186        3927 :             if (output.nValue < nMinimumAmount || output.nValue > nMaximumAmount)
     187           0 :                 continue;
     188             : 
     189        3927 :             if (coinControl && coinControl->HasSelected() && !coinControl->m_allow_other_inputs && !coinControl->IsSelected(outpoint))
     190        1208 :                 continue;
     191             : 
     192        2719 :             if (wallet.IsLockedCoin(outpoint) && nCoinType != CoinType::ONLY_MASTERNODE_COLLATERAL)
     193         627 :                 continue;
     194             : 
     195        2092 :             if (wallet.IsSpent(outpoint))
     196         503 :                 continue;
     197             : 
     198        1589 :             isminetype mine = wallet.IsMine(output);
     199             : 
     200        1589 :             if (mine == ISMINE_NO) {
     201           5 :                 continue;
     202             :             }
     203             : 
     204        1584 :             if (!allow_used_addresses && wallet.IsSpentKey(output.scriptPubKey)) {
     205           0 :                 continue;
     206             :             }
     207             : 
     208        1584 :             std::unique_ptr<SigningProvider> provider = wallet.GetSolvingProvider(output.scriptPubKey);
     209             : 
     210        1584 :             int input_bytes = CalculateMaximumSignedInputSize(output, COutPoint(), provider.get(), coinControl);
     211             :             // Because CalculateMaximumSignedInputSize just uses ProduceSignature and makes a dummy signature,
     212             :             // it is safe to assume that this input is solvable if input_bytes is greater -1.
     213        1584 :             bool solvable = input_bytes > -1;
     214        1584 :             bool spendable = ((mine & ISMINE_SPENDABLE) != ISMINE_NO) || (((mine & ISMINE_WATCH_ONLY) != ISMINE_NO) && (coinControl && coinControl->fAllowWatchOnly && solvable));
     215             : 
     216             :             // Filter by spendable outputs only
     217        1584 :             if (!spendable && only_spendable) continue;
     218             : 
     219             :             // When parsing a scriptPubKey, Solver returns the parsed pubkeys or hashes (depending on the script)
     220             :             // We don't need those here, so we are leaving them in return_values_unused
     221        1584 :             std::vector<std::vector<uint8_t>> return_values_unused;
     222             :             TxoutType type;
     223             : 
     224             :             // If the Output is P2SH and spendable, we want to know if it is
     225             :             // a P2SH (legacy). We can determine this from the redeemScript.
     226             :             // If the Output is not spendable, it will be classified as a P2SH (legacy),
     227             :             // since we have no way of knowing otherwise without the redeemScript
     228        1584 :             if (output.scriptPubKey.IsPayToScriptHash() && solvable) {
     229           0 :                 CScript redeemScript;
     230           0 :                 CTxDestination destination;
     231           0 :                 if (!ExtractDestination(output.scriptPubKey, destination))
     232           0 :                     continue;
     233           0 :                 const CScriptID& hash = CScriptID(std::get<ScriptHash>(destination));
     234           0 :                 if (!provider->GetCScript(hash, redeemScript))
     235           0 :                     continue;
     236           0 :                 type = Solver(redeemScript, return_values_unused);
     237           0 :             } else {
     238        1584 :                 type = Solver(output.scriptPubKey, return_values_unused);
     239             :             }
     240             : 
     241        1584 :             COutput coin(outpoint, output, nDepth, input_bytes, spendable, solvable, safeTx, wtx.GetTxTime(), tx_from_me, feerate);
     242        1584 :             switch (type) {
     243             :             case TxoutType::SCRIPTHASH:
     244             :             case TxoutType::PUBKEYHASH:
     245        1477 :                 result.legacy.push_back(coin);
     246        1477 :                 break;
     247             :             default:
     248         107 :                 result.other.push_back(coin);
     249         107 :             };
     250             : 
     251             :             // Cache total amount as we go
     252        1584 :             result.total_amount += output.nValue;
     253             :             // Checks the sum amount of all UTXO's.
     254        1584 :             if (nMinimumSumAmount != MAX_MONEY) {
     255           0 :                 if (result.total_amount >= nMinimumSumAmount) {
     256           0 :                     return result;
     257             :                 }
     258           0 :             }
     259             : 
     260             :             // Checks the maximum number of UTXO's.
     261        1584 :             if (nMaximumCount > 0 && result.size() >= nMaximumCount) {
     262           0 :                 return result;
     263             :             }
     264        1584 :         }
     265             :     }
     266             : 
     267         235 :     return result;
     268         235 : }
     269             : 
     270           7 : CoinsResult AvailableCoinsListUnspent(const CWallet& wallet, const CCoinControl* coinControl, const CAmount& nMinimumAmount, const CAmount& nMaximumAmount, const CAmount& nMinimumSumAmount, const uint64_t nMaximumCount)
     271             : {
     272           7 :     return AvailableCoins(wallet, coinControl, /*feerate=*/ std::nullopt, nMinimumAmount, nMaximumAmount, nMinimumSumAmount, nMaximumCount, /*only_spendable=*/false);
     273             : }
     274             : 
     275           4 : CAmount GetAvailableBalance(const CWallet& wallet, const CCoinControl* coinControl)
     276             : {
     277           4 :     LOCK(wallet.cs_wallet);
     278           8 :     return AvailableCoins(wallet, coinControl,
     279           4 :             /*feerate=*/ std::nullopt,
     280           4 :             /*nMinimumAmount=*/ 1,
     281             :             /*nMaximumAmount=*/ MAX_MONEY,
     282             :             /*nMinimumSumAmount=*/ MAX_MONEY,
     283             :             /*nMaximumCount=*/ 0
     284           4 :     ).total_amount;
     285           4 : }
     286             : 
     287           5 : const CTxOut& FindNonChangeParentOutput(const CWallet& wallet, const CTransaction& tx, int output)
     288             : {
     289           5 :     AssertLockHeld(wallet.cs_wallet);
     290           5 :     const CTransaction* ptx = &tx;
     291           5 :     int n = output;
     292           7 :     while (OutputIsChange(wallet, ptx->vout[n]) && ptx->vin.size() > 0) {
     293           2 :         const COutPoint& prevout = ptx->vin[0].prevout;
     294           2 :         auto it = wallet.mapWallet.find(prevout.hash);
     295           2 :         if (it == wallet.mapWallet.end() || it->second.tx->vout.size() <= prevout.n ||
     296           2 :             !wallet.IsMine(it->second.tx->vout[prevout.n])) {
     297           0 :             break;
     298             :         }
     299           2 :         ptx = it->second.tx.get();
     300           2 :         n = prevout.n;
     301             :     }
     302           5 :     return ptx->vout[n];
     303             : }
     304             : 
     305           3 : const CTxOut& FindNonChangeParentOutput(const CWallet& wallet, const COutPoint& outpoint)
     306             : {
     307           3 :     AssertLockHeld(wallet.cs_wallet);
     308           3 :     return FindNonChangeParentOutput(wallet, *wallet.GetWalletTx(outpoint.hash)->tx, outpoint.n);
     309             : }
     310             : 
     311           3 : std::map<CTxDestination, std::vector<COutput>> ListCoins(const CWallet& wallet)
     312             : {
     313           3 :     AssertLockHeld(wallet.cs_wallet);
     314             : 
     315           3 :     std::map<CTxDestination, std::vector<COutput>> result;
     316             : 
     317           6 :     for (COutput& coin : AvailableCoinsListUnspent(wallet).all()) {
     318           3 :         CTxDestination address;
     319           6 :         if ((coin.spendable || (wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && coin.solvable)) &&
     320           3 :             ExtractDestination(FindNonChangeParentOutput(wallet, coin.outpoint).scriptPubKey, address)) {
     321           3 :             result[address].emplace_back(std::move(coin));
     322           3 :         }
     323             :     }
     324             : 
     325             :     // Include watch-only for LegacyScriptPubKeyMan wallets without private keys
     326           3 :     const bool include_watch_only = wallet.GetLegacyScriptPubKeyMan() && wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
     327           3 :     const isminetype is_mine_filter = include_watch_only ? ISMINE_WATCH_ONLY : ISMINE_SPENDABLE;
     328           5 :     for (const COutPoint& output : wallet.setLockedCoins) {
     329           2 :         auto it = wallet.mapWallet.find(output.hash);
     330           2 :         if (it != wallet.mapWallet.end()) {
     331           2 :             const auto& wtx = it->second;
     332           2 :             int depth = wallet.GetTxDepthInMainChain(wtx);
     333           4 :             if (depth >= 0 && output.n < wtx.tx->vout.size() &&
     334           2 :                 wallet.IsMine(wtx.tx->vout[output.n]) == is_mine_filter
     335             :             ) {
     336           2 :                 CTxDestination address;
     337           2 :                 if (ExtractDestination(FindNonChangeParentOutput(wallet, *wtx.tx, output.n).scriptPubKey, address)) {
     338           2 :                     const auto out = wtx.tx->vout.at(output.n);
     339           4 :                     result[address].emplace_back(
     340           2 :                             COutPoint(wtx.GetHash(), output.n), out, depth, CalculateMaximumSignedInputSize(out, &wallet, /*coin_control=*/nullptr), /*spendable=*/ true, /*solvable=*/ true, /*safe=*/ false, wtx.GetTxTime(), CachedTxIsFromMe(wallet, wtx, ISMINE_ALL));
     341           2 :                 }
     342           2 :             }
     343           2 :         }
     344             :     }
     345             : 
     346           3 :     return result;
     347           3 : }
     348             : 
     349      598529 : static bool isGroupISLocked(const OutputGroup& group, interfaces::Chain& chain)
     350             : {
     351     1197058 :     return std::all_of(group.m_outputs.begin(), group.m_outputs.end(), [&chain](const auto& output) {
     352      598529 :         return chain.isInstantSendLockedTx(output.outpoint.hash);
     353             :     });
     354             : }
     355             : 
     356        4036 : std::vector<OutputGroup> GroupOutputs(const CWallet& wallet, const std::vector<COutput>& outputs, const CoinSelectionParams& coin_sel_params, const CoinEligibilityFilter& filter, bool positive_only)
     357             : {
     358        4036 :     std::vector<OutputGroup> groups_out;
     359             : 
     360        4036 :     if (!coin_sel_params.m_avoid_partial_spends) {
     361             :         // Allowing partial spends  means no grouping. Each COutput gets its own OutputGroup.
     362      601627 :         for (const COutput& output : outputs) {
     363             :             // Skip outputs we cannot spend
     364      597713 :             if (!output.spendable) continue;
     365             : 
     366             :             size_t ancestors, descendants;
     367      597713 :             wallet.chain().getTransactionAncestry(output.outpoint.hash, ancestors, descendants);
     368             : 
     369             :             // Make an OutputGroup containing just this output
     370      597713 :             OutputGroup group{coin_sel_params};
     371      597713 :             group.Insert(output, ancestors, descendants, positive_only);
     372             : 
     373             :             // Check the OutputGroup's eligibility. Only add the eligible ones.
     374      597713 :             if (positive_only && group.GetSelectionAmount() <= 0) continue;
     375      597711 :             bool isISLocked = isGroupISLocked(group, wallet.chain());
     376      597711 :             if (group.m_outputs.size() > 0 && group.EligibleForSpending(filter, isISLocked)) groups_out.push_back(group);
     377      597713 :         }
     378        3914 :         return groups_out;
     379             :     }
     380             : 
     381             :     // We want to combine COutputs that have the same scriptPubKey into single OutputGroups
     382             :     // except when there are more than OUTPUT_GROUP_MAX_ENTRIES COutputs grouped in an OutputGroup.
     383             :     // To do this, we maintain a map where the key is the scriptPubKey and the value is a vector of OutputGroups.
     384             :     // For each COutput, we check if the scriptPubKey is in the map, and if it is, the COutput is added
     385             :     // to the last OutputGroup in the vector for the scriptPubKey. When the last OutputGroup has
     386             :     // OUTPUT_GROUP_MAX_ENTRIES COutputs, a new OutputGroup is added to the end of the vector.
     387         122 :     std::map<CScript, std::vector<OutputGroup>> spk_to_groups_map;
     388         952 :     for (const auto& output : outputs) {
     389             :         // Skip outputs we cannot spend
     390         830 :         if (!output.spendable) continue;
     391             : 
     392             :         size_t ancestors, descendants;
     393         830 :         wallet.chain().getTransactionAncestry(output.outpoint.hash, ancestors, descendants);
     394         830 :         CScript spk = output.txout.scriptPubKey;
     395             : 
     396         830 :         std::vector<OutputGroup>& groups = spk_to_groups_map[spk];
     397             : 
     398         830 :         if (groups.size() == 0) {
     399             :             // No OutputGroups for this scriptPubKey yet, add one
     400         818 :             groups.emplace_back(coin_sel_params);
     401         818 :         }
     402             : 
     403             :         // Get the last OutputGroup in the vector so that we can add the COutput to it
     404             :         // A pointer is used here so that group can be reassigned later if it is full.
     405         830 :         OutputGroup* group = &groups.back();
     406             : 
     407             :         // Check if this OutputGroup is full. We limit to OUTPUT_GROUP_MAX_ENTRIES when using -avoidpartialspends
     408             :         // to avoid surprising users with very high fees.
     409         830 :         if (group->m_outputs.size() >= OUTPUT_GROUP_MAX_ENTRIES) {
     410             :             // The last output group is full, add a new group to the vector and use that group for the insertion
     411           0 :             groups.emplace_back(coin_sel_params);
     412           0 :             group = &groups.back();
     413           0 :         }
     414             : 
     415             :         // Add the output to group
     416         830 :         group->Insert(output, ancestors, descendants, positive_only);
     417         830 :     }
     418             : 
     419             :     // Now we go through the entire map and pull out the OutputGroups
     420         940 :     for (const auto& spk_and_groups_pair: spk_to_groups_map) {
     421         818 :         const std::vector<OutputGroup>& groups_per_spk= spk_and_groups_pair.second;
     422             : 
     423             :         // Go through the vector backwards. This allows for the first item we deal with being the partial group.
     424        1636 :         for (auto group_it = groups_per_spk.rbegin(); group_it != groups_per_spk.rend(); group_it++) {
     425         818 :             const OutputGroup& group = *group_it;
     426             : 
     427             :             // Don't include partial groups if there are full groups too and we don't want partial groups
     428         818 :             if (group_it == groups_per_spk.rbegin() && groups_per_spk.size() > 1 && !filter.m_include_partial_groups) {
     429           0 :                 continue;
     430             :             }
     431             : 
     432             :             // Check the OutputGroup's eligibility. Only add the eligible ones.
     433         818 :             if (positive_only && group.GetSelectionAmount() <= 0) continue;
     434         818 :             bool isISLocked = isGroupISLocked(group, wallet.chain());
     435         818 :             if (group.m_outputs.size() > 0 && group.EligibleForSpending(filter, isISLocked)) groups_out.push_back(group);
     436         818 :         }
     437             :     }
     438             : 
     439         122 :     return groups_out;
     440        4036 : }
     441             : 
     442         256 : std::optional<SelectionResult> AttemptSelection(const CWallet& wallet, const CAmount& nTargetValue, const CoinEligibilityFilter& eligibility_filter, const CoinsResult& available_coins,
     443             :                                                 const CoinSelectionParams& coin_selection_params, bool allow_mixed_output_types, CoinType nCoinType)
     444             : {
     445             :     // Run coin selection on each OutputType and compute the Waste Metric
     446         256 :     std::vector<SelectionResult> results;
     447         424 :     if (auto result{ChooseSelectionResult(wallet, nTargetValue, eligibility_filter, available_coins.legacy, coin_selection_params, nCoinType)}) {
     448         168 :         results.push_back(*result);
     449         168 :     }
     450             : 
     451             :     // If we can't fund the transaction from any individual OutputType, run coin selection
     452             :     // over all available coins, else pick the best solution from the results
     453         256 :     if (results.size() == 0) {
     454          88 :         if (allow_mixed_output_types) {
     455          80 :             if (auto result{ChooseSelectionResult(wallet, nTargetValue, eligibility_filter, available_coins.all(), coin_selection_params, nCoinType)}) {
     456          20 :                 return result;
     457             :             }
     458          40 :         }
     459          68 :         return std::optional<SelectionResult>();
     460             :     };
     461         168 :     std::optional<SelectionResult> result{*std::min_element(results.begin(), results.end())};
     462         168 :     return result;
     463         424 : };
     464             : 
     465         316 : std::optional<SelectionResult> ChooseSelectionResult(const CWallet& wallet, const CAmount& nTargetValue, const CoinEligibilityFilter& eligibility_filter, const std::vector<COutput>& available_coins,
     466             :                                                      const CoinSelectionParams& coin_selection_params, CoinType nCoinType)
     467             : {
     468             :     // Vector of results. We will choose the best one based on waste.
     469         316 :     std::vector<SelectionResult> results;
     470             : 
     471         316 :     int max_inputs_weight = MAX_STANDARD_TX_SIZE - coin_selection_params.tx_noinputs_size;
     472             : 
     473             :     // Note that unlike KnapsackSolver, we do not include the fee for creating a change output as BnB will not create a change output.
     474         316 :     std::vector<OutputGroup> positive_groups = GroupOutputs(wallet, available_coins, coin_selection_params, eligibility_filter, true /* positive_only */);
     475         316 :     positive_groups.clear(); // Cleared to skip BnB and SRD as they're unaware of mixed coins
     476         316 :     if (auto bnb_result{SelectCoinsBnB(positive_groups, nTargetValue, coin_selection_params.m_cost_of_change, max_inputs_weight)}) {
     477           0 :         results.push_back(*bnb_result);
     478           0 :     }
     479             : 
     480         316 :     max_inputs_weight -= coin_selection_params.change_output_size;
     481             : 
     482             :     // 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.
     483         316 :     std::vector<OutputGroup> all_groups = GroupOutputs(wallet, available_coins, coin_selection_params, eligibility_filter, false /* positive_only */);
     484         316 :     CAmount target_with_change = nTargetValue;
     485             :     // While nTargetValue includes the transaction fees for non-input things, it does not include the fee for creating a change output.
     486             :     // So we need to include that for KnapsackSolver as well, as we are expecting to create a change output.
     487             :     // There is also no change output when spending fully mixed coins.
     488         316 :     if (!coin_selection_params.m_subtract_fee_outputs && nCoinType != CoinType::ONLY_FULLY_MIXED) {
     489         223 :         target_with_change += coin_selection_params.m_change_fee;
     490         223 :     }
     491         820 :     if (auto knapsack_result{KnapsackSolver(all_groups, target_with_change, coin_selection_params.m_min_change_target,
     492         316 :                                             coin_selection_params.rng_fast, max_inputs_weight, nCoinType == CoinType::ONLY_FULLY_MIXED,
     493         316 :                                             wallet.m_default_max_tx_fee)}) {
     494         188 :         knapsack_result->ComputeAndSetWaste(coin_selection_params.m_cost_of_change);
     495         188 :         results.push_back(*knapsack_result);
     496         188 :     }
     497             : 
     498             :     // Include change for SRD as we want to avoid making really small change if the selection just
     499             :     // barely meets the target. Just use the lower bound change target instead of the randomly
     500             :     // generated one, since SRD will result in a random change amount anyway; avoid making the
     501             :     // target needlessly large.
     502         316 :     const CAmount srd_target = target_with_change + CHANGE_LOWER;
     503         316 :     if (auto srd_result{SelectCoinsSRD(positive_groups, srd_target, coin_selection_params.rng_fast, max_inputs_weight)}) {
     504           0 :         srd_result->ComputeAndSetWaste(coin_selection_params.m_cost_of_change);
     505           0 :         results.push_back(*srd_result);
     506           0 :     }
     507             : 
     508         316 :     if (results.size() == 0) {
     509         128 :         return std::nullopt;
     510             :     }
     511             : 
     512             :     // Choose the result with the least waste
     513             :     // If the waste is the same, choose the one which spends more inputs.
     514         188 :     return *std::min_element(results.begin(), results.end());
     515         316 : }
     516             : 
     517         330 : std::optional<SelectionResult> SelectCoins(const CWallet& wallet, CoinsResult& available_coins, const CAmount& nTargetValue, const CCoinControl& coin_control, const CoinSelectionParams& coin_selection_params)
     518             : {
     519             :     // Note: this function should never be used for "always free" tx types like dstx
     520         330 :     CoinType nCoinType = coin_control.nCoinType;
     521         330 :     CAmount value_to_select = nTargetValue;
     522             : 
     523         330 :     OutputGroup preset_inputs(coin_selection_params);
     524             : 
     525             :     // calculate value from preset inputs and store them
     526         330 :     std::set<COutPoint> preset_coins;
     527             : 
     528         905 :     for (const COutPoint& outpoint : coin_control.ListSelected()) {
     529         575 :         int input_bytes = -1;
     530         575 :         CTxOut txout;
     531         575 :         auto ptr_wtx = wallet.GetWalletTx(outpoint.hash);
     532         575 :         if (ptr_wtx) {
     533             :             // Clearly invalid input, fail
     534         575 :             if (ptr_wtx->tx->vout.size() <= outpoint.n) {
     535           0 :                 return std::nullopt;
     536             :             }
     537         575 :             txout = ptr_wtx->tx->vout.at(outpoint.n);
     538         575 :             input_bytes = CalculateMaximumSignedInputSize(txout, &wallet, &coin_control);
     539         575 :         } else {
     540             :             // The input is external. We did not find the tx in mapWallet.
     541           0 :             const auto out{coin_control.GetExternalOutput(outpoint)};
     542           0 :             if (!out) {
     543           0 :                 return std::nullopt;
     544             :             }
     545           0 :             txout = *out;
     546           0 :         }
     547             : 
     548         575 :         if (input_bytes == -1) {
     549           0 :             input_bytes = CalculateMaximumSignedInputSize(txout, outpoint, &coin_control.m_external_provider, &coin_control);
     550           0 :         }
     551         575 :         if (nCoinType == CoinType::ONLY_FULLY_MIXED) {
     552             :             // Make sure to include mixed preset inputs only,
     553             :             // even if some non-mixed inputs were manually selected via CoinControl
     554           0 :             if (!wallet.IsFullyMixed(outpoint)) continue;
     555           0 :         }
     556             :         // If available, override calculated size with coin control specified size
     557         575 :         if (coin_control.HasInputWeight(outpoint)) {
     558           0 :             input_bytes = GetVirtualTransactionSize(coin_control.GetInputWeight(outpoint), 0, 0);
     559           0 :         }
     560             : 
     561         575 :         if (input_bytes == -1) {
     562           0 :             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         575 :         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         575 :         if (coin_selection_params.m_subtract_fee_outputs) {
     568         236 :             value_to_select -= output.txout.nValue;
     569         236 :         } else {
     570         339 :             value_to_select -= output.GetEffectiveValue();
     571             :         }
     572         575 :         preset_coins.insert(outpoint);
     573             :         /* Set ancestors and descendants to 0 as they don't matter for preset inputs since no actual selection is being done.
     574             :          * positive_only is set to false because we want to include all preset inputs, even if they are dust.
     575             :          */
     576         575 :         preset_inputs.Insert(output, /*ancestors=*/ 0, /*descendants=*/ 0, /*positive_only=*/ false);
     577         575 :     }
     578             : 
     579             :     // coin control -> return all selected outputs (we want all selected to go into the transaction for sure)
     580         330 :     if (coin_control.HasSelected() && !coin_control.m_allow_other_inputs) {
     581         134 :         SelectionResult result(nTargetValue, SelectionAlgorithm::MANUAL);
     582         134 :         bool all_inputs{coin_control.fRequireAllInputs};
     583         134 :         if (!all_inputs) {
     584             :             // Calculate the smallest set of inputs required to meet nTargetValue from available_coins
     585           1 :             bool success{false};
     586           1 :             OutputGroup preset_candidates(coin_selection_params);
     587           3 :             for (const COutput& out : available_coins.all()) {
     588           2 :                 if (!out.spendable) continue;
     589           2 :                 if (preset_coins.count(out.outpoint)) {
     590           2 :                     preset_candidates.Insert(out, /*ancestors=*/0, /*descendants=*/0, /*positive_only=*/false);
     591           2 :                 }
     592           2 :                 if (preset_candidates.GetSelectionAmount() >= nTargetValue) {
     593           1 :                     result.AddInput(preset_candidates);
     594           1 :                     success = true;
     595           1 :                     break;
     596             :                 }
     597             :             }
     598             :             // Couldn't meet target, add all inputs
     599           1 :             if (!success) all_inputs = true;
     600           1 :         }
     601         134 :         if (all_inputs) {
     602         133 :             result.AddInput(preset_inputs);
     603         133 :         }
     604         134 :         if (result.GetSelectedValue() < nTargetValue) return std::nullopt;
     605          98 :         result.ComputeAndSetWaste(coin_selection_params.m_cost_of_change);
     606          98 :         return result;
     607         134 :     }
     608             : 
     609             :     // remove preset inputs from coins so that Coin Selection doesn't pick them.
     610         196 :     if (coin_control.HasSelected()) {
     611           8 :         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());
     612           2 :         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());
     613           2 :     }
     614             : 
     615         196 :     unsigned int limit_ancestor_count = 0;
     616         196 :     unsigned int limit_descendant_count = 0;
     617         196 :     wallet.chain().getPackageLimits(limit_ancestor_count, limit_descendant_count);
     618         196 :     const size_t max_ancestors = (size_t)std::max<int64_t>(1, limit_ancestor_count);
     619         196 :     const size_t max_descendants = (size_t)std::max<int64_t>(1, limit_descendant_count);
     620         196 :     const bool fRejectLongChains = gArgs.GetBoolArg("-walletrejectlongchains", DEFAULT_WALLET_REJECT_LONG_CHAINS);
     621             : 
     622             :     // form groups from remaining coins; note that preset coins will not
     623             :     // automatically have their associated (same address) coins included
     624         196 :     if (coin_control.m_avoid_partial_spends && available_coins.size() > OUTPUT_GROUP_MAX_ENTRIES) {
     625             :         // Cases where we have 101+ outputs all pointing to the same destination may result in
     626             :         // privacy leaks as they will potentially be deterministically sorted. We solve that by
     627             :         // explicitly shuffling the outputs before processing
     628           0 :         Shuffle(available_coins.legacy.begin(), available_coins.legacy.end(), coin_selection_params.rng_fast);
     629           0 :         Shuffle(available_coins.other.begin(), available_coins.other.end(), coin_selection_params.rng_fast);
     630           0 :     }
     631             :     // Coin Selection attempts to select inputs from a pool of eligible UTXOs to fund the
     632             :     // transaction at a target feerate. If an attempt fails, more attempts may be made using a more
     633             :     // permissive CoinEligibilityFilter.
     634         392 :     std::optional<SelectionResult> res = [&] {
     635             :         // Pre-selected inputs already cover the target amount.
     636         196 :         if (value_to_select <= 0) return std::make_optional(SelectionResult(nTargetValue, SelectionAlgorithm::MANUAL));
     637             : 
     638             :         // If possible, fund the transaction with confirmed UTXOs only. Prefer at least six
     639             :         // confirmations on outputs received from other wallets and only spend confirmed change.
     640         196 :         if (auto r1{AttemptSelection(wallet, value_to_select, CoinEligibilityFilter(1, 6, 0), available_coins, coin_selection_params, /*allow_mixed_output_types=*/false, nCoinType)}) return r1;
     641             :         // Allow mixing only if no solution from any single output type can be found
     642          28 :         if (auto r2{AttemptSelection(wallet, value_to_select, CoinEligibilityFilter(1, 1, 0), available_coins, coin_selection_params, /*allow_mixed_output_types=*/true, nCoinType)}) return r2;
     643             : 
     644             :         // Fall back to using zero confirmation change (but with as few ancestors in the mempool as
     645             :         // possible) if we cannot fund the transaction otherwise.
     646           8 :         if (wallet.m_spend_zero_conf_change) {
     647           8 :             if (auto r3{AttemptSelection(wallet, value_to_select, CoinEligibilityFilter(0, 1, 2), available_coins, coin_selection_params, /*allow_mixed_output_types=*/true, nCoinType)}) return r3;
     648          16 :             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)),
     649           8 :                                          available_coins, coin_selection_params, /*allow_mixed_output_types=*/true, nCoinType)}) {
     650           0 :                 return r4;
     651             :             }
     652          16 :             if (auto r5{AttemptSelection(wallet, value_to_select, CoinEligibilityFilter(0, 1, max_ancestors/2, max_descendants/2),
     653           8 :                                          available_coins, coin_selection_params, /*allow_mixed_output_types=*/true, nCoinType)}) {
     654           0 :                 return r5;
     655             :             }
     656             :             // If partial groups are allowed, relax the requirement of spending OutputGroups (groups
     657             :             // of UTXOs sent to the same address, which are obviously controlled by a single wallet)
     658             :             // in their entirety.
     659          16 :             if (auto r6{AttemptSelection(wallet, value_to_select, CoinEligibilityFilter(0, 1, max_ancestors-1, max_descendants-1, true /* include_partial_groups */),
     660           8 :                                          available_coins, coin_selection_params, /*allow_mixed_output_types=*/true, nCoinType)}) {
     661           0 :                 return r6;
     662             :             }
     663             :             // Try with unsafe inputs if they are allowed. This may spend unconfirmed outputs
     664             :             // received from other wallets.
     665           8 :             if (coin_control.m_include_unsafe_inputs) {
     666           0 :                 if (auto r7{AttemptSelection(wallet, value_to_select,
     667           0 :                     CoinEligibilityFilter(0 /* conf_mine */, 0 /* conf_theirs */, max_ancestors-1, max_descendants-1, true /* include_partial_groups */),
     668           0 :                     available_coins, coin_selection_params, /*allow_mixed_output_types=*/true, nCoinType)}) {
     669           0 :                     return r7;
     670             :                 }
     671           0 :             }
     672             :             // Try with unlimited ancestors/descendants. The transaction will still need to meet
     673             :             // mempool ancestor/descendant policy to be accepted to mempool and broadcasted, but
     674             :             // OutputGroups use heuristics that may overestimate ancestor/descendant counts.
     675           8 :             if (!fRejectLongChains) {
     676           0 :                 if (auto r8{AttemptSelection(wallet, value_to_select,
     677           0 :                                       CoinEligibilityFilter(0, 1, std::numeric_limits<uint64_t>::max(), std::numeric_limits<uint64_t>::max(), true /* include_partial_groups */),
     678           0 :                                       available_coins, coin_selection_params, /*allow_mixed_output_types=*/true, nCoinType)}) {
     679           0 :                     return r8;
     680             :                 }
     681           0 :             }
     682           8 :         }
     683             :         // Coin Selection failed.
     684           8 :         return std::optional<SelectionResult>();
     685         196 :     }();
     686             : 
     687         196 :     if (!res) return std::nullopt;
     688             : 
     689             :     // Add preset inputs to result
     690         188 :     res->AddInput(preset_inputs);
     691         188 :     if (res->m_algo == SelectionAlgorithm::MANUAL) {
     692           0 :         res->ComputeAndSetWaste(coin_selection_params.m_cost_of_change);
     693           0 :     }
     694             : 
     695         188 :     return res;
     696         330 : }
     697             : 
     698         178 : static bool IsCurrentForAntiFeeSniping(interfaces::Chain& chain, const uint256& block_hash)
     699             : {
     700         178 :     if (chain.isInitialBlockDownload()) {
     701           0 :         return false;
     702             :     }
     703         178 :     constexpr int64_t MAX_ANTI_FEE_SNIPING_TIP_AGE = 8 * 60 * 60; // in seconds
     704             :     int64_t block_time;
     705         178 :     CHECK_NONFATAL(chain.findBlock(block_hash, FoundBlock().time(block_time)));
     706         178 :     if (block_time < (GetTime() - MAX_ANTI_FEE_SNIPING_TIP_AGE)) {
     707           0 :         return false;
     708             :     }
     709         178 :     return true;
     710         178 : }
     711             : 
     712             : /**
     713             :  * Set a height-based locktime for new transactions (uses the height of the
     714             :  * current chain tip unless we are not synced with the current chain
     715             :  */
     716         178 : static void DiscourageFeeSniping(CMutableTransaction& tx, FastRandomContext& rng_fast,
     717             :                                  interfaces::Chain& chain, const uint256& block_hash, int block_height)
     718             : {
     719             :     // All inputs must be added by now
     720         178 :     assert(!tx.vin.empty());
     721             :     // Discourage fee sniping.
     722             :     //
     723             :     // For a large miner the value of the transactions in the best block and
     724             :     // the mempool can exceed the cost of deliberately attempting to mine two
     725             :     // blocks to orphan the current best block. By setting nLockTime such that
     726             :     // only the next block can include the transaction, we discourage this
     727             :     // practice as the height restricted and limited blocksize gives miners
     728             :     // considering fee sniping fewer options for pulling off this attack.
     729             :     //
     730             :     // A simple way to think about this is from the wallet's point of view we
     731             :     // always want the blockchain to move forward. By setting nLockTime this
     732             :     // way we're basically making the statement that we only want this
     733             :     // transaction to appear in the next block; we don't want to potentially
     734             :     // encourage reorgs by allowing transactions to appear at lower heights
     735             :     // than the next block in forks of the best chain.
     736             :     //
     737             :     // Of course, the subsidy is high enough, and transaction volume low
     738             :     // enough, that fee sniping isn't a problem yet, but by implementing a fix
     739             :     // now we ensure code won't be written that makes assumptions about
     740             :     // nLockTime that preclude a fix later.
     741         178 :     if (IsCurrentForAntiFeeSniping(chain, block_hash)) {
     742         178 :         tx.nLockTime = block_height;
     743             : 
     744             :         // Secondly occasionally randomly pick a nLockTime even further back, so
     745             :         // that transactions that are delayed after signing for whatever reason,
     746             :         // e.g. high-latency mix networks and some CoinJoin implementations, have
     747             :         // better privacy.
     748         178 :         if (rng_fast.randrange(10) == 0) {
     749          18 :             tx.nLockTime = std::max(0, int(tx.nLockTime) - int(rng_fast.randrange(100)));
     750          18 :         }
     751         178 :     } else {
     752             :         // If our chain is lagging behind, we can't discourage fee sniping nor help
     753             :         // the privacy of high-latency transactions. To avoid leaking a potentially
     754             :         // unique "nLockTime fingerprint", set nLockTime to a constant.
     755           0 :         tx.nLockTime = 0;
     756             :     }
     757             :     // Sanity check all values
     758         178 :     assert(tx.nLockTime < LOCKTIME_THRESHOLD); // Type must be block height
     759         178 :     assert(tx.nLockTime <= uint64_t(block_height));
     760         882 :     for (const auto& in : tx.vin) {
     761             :         // Can not be FINAL for locktime to work
     762         704 :         assert(in.nSequence != CTxIn::SEQUENCE_FINAL);
     763             :         // May be MAX NONFINAL to disable BIP68
     764         704 :         if (in.nSequence == CTxIn::MAX_SEQUENCE_NONFINAL) continue;
     765             :         // The wallet does not support any other sequence-use right now.
     766           0 :         assert(false);
     767             :     }
     768         178 : }
     769             : 
     770         226 : static util::Result<CreatedTransactionResult> CreateTransactionInternal(
     771             :         CWallet& wallet,
     772             :         const std::vector<CRecipient>& vecSend,
     773             :         int change_pos,
     774             :         const CCoinControl& coin_control,
     775             :         bool sign,
     776             :         int nExtraPayloadSize) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
     777             : {
     778         226 :     AssertLockHeld(wallet.cs_wallet);
     779             : 
     780             :     // out variables, to be packed into returned result structure
     781             :     CAmount nFeeRet;
     782         226 :     int nChangePosInOut = change_pos;
     783             : 
     784         226 :     FastRandomContext rng_fast;
     785         226 :     CMutableTransaction txNew; // The resulting transaction that we make
     786             : 
     787         226 :     CoinSelectionParams coin_selection_params{rng_fast}; // Parameters for coin selection, init with dummy
     788         226 :     coin_selection_params.m_avoid_partial_spends = coin_control.m_avoid_partial_spends;
     789             : 
     790             :     // Set the long term feerate estimate to the wallet's consolidate feerate
     791         226 :     coin_selection_params.m_long_term_feerate = wallet.m_consolidate_feerate;
     792             : 
     793         226 :     CAmount recipients_sum = 0;
     794         226 :     ReserveDestination reservedest(&wallet);
     795         226 :     const bool sort_bip69{nChangePosInOut == -1};
     796         226 :     unsigned int outputs_to_subtract_fee_from = 0; // The number of outputs which we are subtracting the fee from
     797        9693 :     for (const auto& recipient : vecSend) {
     798        9467 :         recipients_sum += recipient.nAmount;
     799             : 
     800        9467 :         if (recipient.fSubtractFeeFromAmount) {
     801          91 :             outputs_to_subtract_fee_from++;
     802          91 :             coin_selection_params.m_subtract_fee_outputs = true;
     803          91 :         }
     804             :     }
     805         226 :     coin_selection_params.m_min_change_target = GenerateChangeTarget(std::floor(recipients_sum / vecSend.size()), rng_fast);
     806             : 
     807             :     // Create change script that will be used if we need change
     808         226 :     CScript scriptChange;
     809         226 :     bilingual_str error; // possible error str
     810             : 
     811             :     // coin control: send change to custom address
     812         226 :     if (!std::get_if<CNoDestination>(&coin_control.destChange)) {
     813          46 :         scriptChange = GetScriptForDestination(coin_control.destChange);
     814          46 :     } else { // no coin control: send change to newly generated address
     815             :         // Note: We use a new key here to keep it from being obvious which side is the change.
     816             :         //  The drawback is that by not reusing a previous key, the change may be lost if a
     817             :         //  backup is restored, if the backup doesn't have the new private key for the change.
     818             :         //  If we reused the old key, it would be possible to add code to look for and
     819             :         //  rediscover unknown transactions that were written with keys of ours to recover
     820             :         //  post-backup change.
     821             : 
     822             :         // Reserve a new key pair from key pool. If it fails, provide a dummy
     823             :         // destination in case we don't need change.
     824         180 :         CTxDestination dest;
     825         180 :         auto op_dest = reservedest.GetReservedDestination(true);
     826         180 :         if (!op_dest) {
     827           0 :             error = _("Transaction needs a change address, but we can't generate it.") + Untranslated(" ") + util::ErrorString(op_dest);
     828           0 :         } else {
     829         180 :             dest = *op_dest;
     830         180 :             scriptChange = GetScriptForDestination(dest);
     831             :         }
     832             :         // A valid destination implies a change script (and
     833             :         // vice-versa). An empty change script will abort later, if the
     834             :         // change keypool ran out, but change is required.
     835         180 :         CHECK_NONFATAL(IsValidDestination(dest) != scriptChange.empty());
     836         180 :     }
     837         226 :     CTxOut change_prototype_txout(0, scriptChange);
     838         226 :     coin_selection_params.change_output_size = GetSerializeSize(change_prototype_txout);
     839             : 
     840             :     // Get size of spending the change output
     841         226 :     int change_spend_size = CalculateMaximumSignedInputSize(change_prototype_txout, &wallet);
     842             :     // If the wallet doesn't know how to sign change output, assume p2sh-p2pkh
     843             :     // as lower-bound to allow BnB to do it's thing
     844         226 :     if (change_spend_size == -1) {
     845           0 :         coin_selection_params.change_spend_size = DUMMY_NESTED_P2PKH_INPUT_SIZE;
     846           0 :     } else {
     847         226 :         coin_selection_params.change_spend_size = (size_t)change_spend_size;
     848             :     }
     849             : 
     850             :     // Set discard feerate
     851         226 :     coin_selection_params.m_discard_feerate = coin_control.m_discard_feerate ? *coin_control.m_discard_feerate : GetDiscardRate(wallet);
     852             : 
     853             :     // Get the fee rate to use effective values in coin selection
     854         226 :     FeeCalculation feeCalc;
     855         226 :     coin_selection_params.m_effective_feerate = GetMinimumFeeRate(wallet, coin_control, &feeCalc);
     856             :     // Do not, ever, assume that it's fine to change the fee rate if the user has explicitly
     857             :     // provided one
     858         226 :     if (coin_control.m_feerate && coin_selection_params.m_effective_feerate > *coin_control.m_feerate) {
     859           0 :         return util::Error{strprintf(_("Fee rate (%s) is lower than the minimum fee rate setting (%s)"), coin_control.m_feerate->ToString(FeeEstimateMode::DUFF_B), coin_selection_params.m_effective_feerate.ToString(FeeEstimateMode::DUFF_B))};
     860             :     }
     861         226 :     if (feeCalc.reason == FeeReason::FALLBACK && !wallet.m_allow_fallback_fee) {
     862             :         // eventually allow a fallback fee
     863           0 :         return util::Error{strprintf(_("Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable %s."), "-fallbackfee")};
     864             :     }
     865             : 
     866             :     // Calculate the cost of change
     867             :     // Cost of change is the cost of creating the change output + cost of spending the change output in the future.
     868             :     // For creating the change output now, we use the effective feerate.
     869             :     // For spending the change output in the future, we use the discard feerate for now.
     870             :     // So cost of change = (change output size * effective feerate) + (size of spending change output * discard feerate)
     871         226 :     coin_selection_params.m_change_fee = coin_selection_params.m_effective_feerate.GetFee(coin_selection_params.change_output_size);
     872         226 :     coin_selection_params.m_cost_of_change = coin_selection_params.m_discard_feerate.GetFee(coin_selection_params.change_spend_size) + coin_selection_params.m_change_fee;
     873             : 
     874             :     // vouts to the payees
     875         226 :     if (!coin_selection_params.m_subtract_fee_outputs) {
     876         143 :         coin_selection_params.tx_noinputs_size = 9; // Static vsize overhead + outputs vsize. 4 nVersion, 4 nLocktime, 1 input count
     877         143 :         coin_selection_params.tx_noinputs_size += GetSizeOfCompactSize(vecSend.size()); // bytes for output count
     878         143 :     }
     879        9881 :     for (const auto& recipient : vecSend)
     880             :     {
     881        9659 :         CTxOut txout(recipient.nAmount, recipient.scriptPubKey);
     882             : 
     883             :         // Include the fee cost for outputs.
     884        9467 :         if (!coin_selection_params.m_subtract_fee_outputs) {
     885        9258 :             coin_selection_params.tx_noinputs_size += ::GetSerializeSize(txout, PROTOCOL_VERSION);
     886        9258 :         }
     887             : 
     888        9467 :         if (IsDust(txout, wallet.chain().relayDustFee())) {
     889           4 :             return util::Error{_("Transaction amount too small")};
     890             :         }
     891        9463 :         txNew.vout.push_back(txout);
     892        9467 :     }
     893             : 
     894             :     // Include the fees for things that aren't inputs, excluding the change output
     895         222 :     const CAmount not_input_fees = coin_selection_params.m_effective_feerate.GetFee(coin_selection_params.tx_noinputs_size);
     896         222 :     CAmount selection_target = recipients_sum + not_input_fees;
     897             : 
     898             :     // This can only happen if feerate is 0, and requested destinations are value of 0 (e.g. OP_RETURN)
     899             :     // and no pre-selected inputs. This will result in 0-input transaction, which is consensus-invalid anyways
     900         222 :     if (selection_target == 0 && !coin_control.HasSelected()) {
     901           0 :         return util::Error{_("Transaction requires one destination of non-0 value, a non-0 feerate, or a pre-selected input")};
     902             :     }
     903             : 
     904             :     // Get available coins
     905         222 :     auto available_coins = AvailableCoins(wallet,
     906         222 :                                               &coin_control,
     907         222 :                                               coin_selection_params.m_effective_feerate,
     908         222 :                                               1,            /*nMinimumAmount*/
     909             :                                               MAX_MONEY,    /*nMaximumAmount*/
     910             :                                               MAX_MONEY,    /*nMinimumSumAmount*/
     911             :                                               0);           /*nMaximumCount*/
     912             : 
     913             :     // Choose coins to use
     914         414 :     std::optional<SelectionResult> result = SelectCoins(wallet, available_coins, /*nTargetValue=*/selection_target, coin_control, coin_selection_params);
     915         414 :     if (!result) {
     916          43 :         if (coin_control.nCoinType == CoinType::ONLY_NONDENOMINATED) {
     917           1 :             return util::Error{_("Unable to locate enough non-denominated funds for this transaction.")};
     918          42 :         } else if (coin_control.nCoinType == CoinType::ONLY_FULLY_MIXED) {
     919           3 :             return util::Error{_("Unable to locate enough mixed funds for this transaction.") +
     920           2 :                                Untranslated(" ") + strprintf(_("%s uses exact denominated amounts to send funds, you might simply need to mix some more coins."), gCoinJoinName)};
     921             :         }
     922          41 :         return util::Error{_("Insufficient funds.")};
     923             :     }
     924             :     TRACE5(coin_selection, selected_coins, wallet.GetName().c_str(), GetAlgorithmName(result->m_algo).c_str(), result->m_target, result->GetWaste(), result->GetSelectedValue());
     925             : 
     926             :     // Always make a change output
     927             :     // We will reduce the fee from this change output later, and remove the output if it is too small.
     928         371 :     const CAmount change_and_fee = result->GetSelectedValue() - recipients_sum;
     929         179 :     assert(change_and_fee >= 0);
     930         179 :     CTxOut newTxOut(change_and_fee, scriptChange);
     931             : 
     932         371 :     if (nChangePosInOut == -1) {
     933             :         // Insert change txn at random position:
     934         354 :         nChangePosInOut = rng_fast.randrange(txNew.vout.size() + 1);
     935         354 :     }
     936          17 :     else if ((unsigned int)nChangePosInOut > txNew.vout.size()) {
     937           1 :         return util::Error{_("Transaction change output index out of range")};
     938             :     }
     939             : 
     940         370 :     assert(nChangePosInOut != -1);
     941         370 :     auto change_position = txNew.vout.insert(txNew.vout.begin() + nChangePosInOut, newTxOut);
     942             : 
     943             :     // We're making a copy of vecSend because it's const, sortedVecSend should be used
     944             :     // in place of vecSend in all subsequent usage.
     945         178 :     std::vector<CRecipient> sortedVecSend{vecSend};
     946         370 :     if (sort_bip69) {
     947         162 :         std::sort(txNew.vout.begin(), txNew.vout.end(), CompareOutputBIP69());
     948             :         // The output reduction loop uses vecSend to map to txNew.vout, we need to
     949             :         // shuffle them both to ensure this mapping remains consistent
     950         162 :         std::sort(sortedVecSend.begin(), sortedVecSend.end(),
     951      119909 :                     [](const CRecipient& a, const CRecipient& b) {
     952      119909 :                         return a.nAmount < b.nAmount || (a.nAmount == b.nAmount && a.scriptPubKey < b.scriptPubKey);
     953             :                     });
     954             : 
     955             :         // If there was a change output added before, we must update its position now
     956         162 :         if (const auto it = std::find(txNew.vout.begin(), txNew.vout.end(), newTxOut); it != txNew.vout.end()) {
     957         162 :             change_position = it;
     958         162 :             nChangePosInOut = std::distance(txNew.vout.begin(), change_position);
     959         162 :         }
     960         162 :     };
     961             : 
     962             :     // The sequence number is set to non-maxint so that DiscourageFeeSniping
     963             :     // works.
     964         370 :     const uint32_t nSequence{CTxIn::SEQUENCE_FINAL - 1};
     965        1074 :     for (const auto& coin : result->GetInputSet()) {
     966         704 :         txNew.vin.emplace_back(coin.outpoint, CScript(), nSequence);
     967             :     }
     968         178 :     DiscourageFeeSniping(txNew, rng_fast, wallet.chain(), wallet.GetLastBlockHash(), wallet.GetLastBlockHeight());
     969             : 
     970             :     // Fill in final vin and shuffle/sort it
     971         178 :     if (sort_bip69) { std::sort(txNew.vin.begin(), txNew.vin.end(), CompareInputBIP69()); }
     972          16 :     else { Shuffle(txNew.vin.begin(), txNew.vin.end(), coin_selection_params.rng_fast); }
     973             : 
     974             :     // Calculate the transaction fee
     975         178 :     int nBytes = CalculateMaximumSignedTxSize(CTransaction(txNew), &wallet, &coin_control);
     976         178 :     if (nBytes == -1) {
     977           0 :         return util::Error{_("Missing solving data for estimating transaction size")};
     978             :     }
     979             : 
     980         178 :     if (nExtraPayloadSize != 0) {
     981             :         // account for extra payload in fee calculation
     982           0 :         nBytes += GetSizeOfCompactSize(nExtraPayloadSize) + nExtraPayloadSize;
     983           0 :     }
     984             : 
     985         178 :     CAmount fee_needed = coin_selection_params.m_effective_feerate.GetFee(nBytes);
     986             : 
     987         178 :     if (!coin_selection_params.m_subtract_fee_outputs) {
     988         111 :         change_position->nValue -= fee_needed;
     989         111 :     }
     990             : 
     991             :     // We want to drop the change to fees if:
     992             :     // 1. The change output would be dust
     993             :     // 2. The change is within the (almost) exact match window, i.e. it is less than or equal to the cost of the change output (cost_of_change)
     994             :     // 3. We are working with fully mixed CoinJoin denominations
     995         178 :     CAmount change_amount = change_position->nValue;
     996         178 :     if (IsDust(*change_position, coin_selection_params.m_discard_feerate) || change_amount <= coin_selection_params.m_cost_of_change || coin_control.nCoinType == CoinType::ONLY_FULLY_MIXED)
     997             :     {
     998         178 :         nChangePosInOut = -1;
     999         178 :         change_amount = 0;
    1000         178 :         txNew.vout.erase(change_position);
    1001             : 
    1002          82 :         nBytes = CalculateMaximumSignedTxSize(CTransaction(txNew), &wallet, &coin_control);
    1003          82 :         fee_needed = coin_selection_params.m_effective_feerate.GetFee(nBytes);
    1004          82 :     }
    1005             : 
    1006          82 :     nFeeRet = result->GetSelectedValue() - recipients_sum - change_amount;
    1007             : 
    1008             :     // The only time that fee_needed should be less than the amount available for fees is when
    1009             :     // we are subtracting the fee from the outputs. If this occurs at any other time, it is a bug.
    1010         178 :     if (!coin_selection_params.m_subtract_fee_outputs && fee_needed > nFeeRet) {
    1011           7 :         return util::Error{Untranslated(STR_INTERNAL_BUG("Fee needed > fee paid"))};
    1012             :     }
    1013             : 
    1014             :     // Update nFeeRet in case fee_needed changed due to dropping the change output
    1015         171 :     if (fee_needed <= change_and_fee - change_amount) {
    1016         108 :         nFeeRet = change_and_fee - change_amount;
    1017         108 :     }
    1018             : 
    1019             :     // Reduce output values for subtractFeeFromAmount
    1020         171 :     if (coin_selection_params.m_subtract_fee_outputs) {
    1021          67 :         CAmount to_reduce = fee_needed + change_amount - change_and_fee;
    1022          67 :         int i = 0;
    1023          67 :         bool fFirst = true;
    1024         141 :         for (const auto& recipient : sortedVecSend)
    1025             :         {
    1026          87 :             if (i == nChangePosInOut) {
    1027           0 :                 ++i;
    1028           0 :             }
    1029          87 :             CTxOut& txout = txNew.vout[i];
    1030             : 
    1031          87 :             if (recipient.fSubtractFeeFromAmount)
    1032             :             {
    1033          69 :                 txout.nValue -= to_reduce / outputs_to_subtract_fee_from; // Subtract fee equally from each selected recipient
    1034             : 
    1035          69 :                 if (fFirst) // first receiver pays the remainder not divisible by output count
    1036             :                 {
    1037          67 :                     fFirst = false;
    1038          67 :                     txout.nValue -= to_reduce % outputs_to_subtract_fee_from;
    1039          67 :                 }
    1040             :                 // Error if this output is reduced to be below dust
    1041          69 :                 if (IsDust(txout, wallet.chain().relayDustFee())) {
    1042          13 :                     if (txout.nValue < 0) {
    1043          11 :                         return util::Error{_("The transaction amount is too small to pay the fee")};
    1044             :                     } else {
    1045           2 :                         return util::Error{_("The transaction amount is too small to send after the fee has been deducted")};
    1046             :                     }
    1047             :                 }
    1048          56 :             }
    1049          74 :             ++i;
    1050             :         }
    1051          54 :         nFeeRet = fee_needed;
    1052          54 :     }
    1053             : 
    1054             :     // Give up if change keypool ran out and change is required
    1055         158 :     if (scriptChange.empty() && nChangePosInOut != -1) {
    1056           0 :         return util::Error{error};
    1057             :     }
    1058             : 
    1059         158 :     if (sign && !wallet.SignTransaction(txNew)) {
    1060           0 :         return util::Error{_("Signing transaction failed")};
    1061             :     }
    1062             : 
    1063             :     // Return the constructed transaction data.
    1064         158 :     CTransactionRef tx = MakeTransactionRef(std::move(txNew));
    1065             : 
    1066             :     // Limit size
    1067         158 :     if ((sign && ::GetSerializeSize(*tx, PROTOCOL_VERSION) > MAX_STANDARD_TX_SIZE) ||
    1068         157 :         (!sign && static_cast<size_t>(nBytes) > MAX_STANDARD_TX_SIZE)) {
    1069           1 :         return util::Error{_("Transaction too large")};
    1070             :     }
    1071             : 
    1072         157 :     if (fee_needed > nFeeRet) {
    1073           0 :         return util::Error{_("Fee needed > fee paid")};
    1074             :     }
    1075             : 
    1076         157 :     if (nFeeRet > wallet.m_default_max_tx_fee) {
    1077           1 :         return util::Error{TransactionErrorString(TransactionError::MAX_FEE_EXCEEDED)};
    1078             :     }
    1079             : 
    1080         156 :     if (gArgs.GetBoolArg("-walletrejectlongchains", DEFAULT_WALLET_REJECT_LONG_CHAINS)) {
    1081             :         // Lastly, ensure this tx will pass the mempool's chain limits
    1082         156 :         if (!wallet.chain().checkChainLimits(tx)) {
    1083           0 :             return util::Error{_("Transaction has too long of a mempool chain")};
    1084             :         }
    1085         156 :     }
    1086             : 
    1087             :     // Before we return success, we assume any change key will be used to prevent
    1088             :     // accidental reuse.
    1089         156 :     reservedest.KeepDestination();
    1090             : 
    1091         312 :     wallet.WalletLogPrintf("Fee Calculation: Fee:%d Bytes:%u Tgt:%d (requested %d) Reason:\"%s\" Decay %.5f: Estimation: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out) Fail: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out)\n",
    1092         156 :               nFeeRet, nBytes, feeCalc.returnedTarget, feeCalc.desiredTarget, StringForFeeReason(feeCalc.reason), feeCalc.est.decay,
    1093         156 :               feeCalc.est.pass.start, feeCalc.est.pass.end,
    1094         156 :               (feeCalc.est.pass.totalConfirmed + feeCalc.est.pass.inMempool + feeCalc.est.pass.leftMempool) > 0.0 ? 100 * feeCalc.est.pass.withinTarget / (feeCalc.est.pass.totalConfirmed + feeCalc.est.pass.inMempool + feeCalc.est.pass.leftMempool) : 0.0,
    1095         156 :               feeCalc.est.pass.withinTarget, feeCalc.est.pass.totalConfirmed, feeCalc.est.pass.inMempool, feeCalc.est.pass.leftMempool,
    1096         156 :               feeCalc.est.fail.start, feeCalc.est.fail.end,
    1097         156 :               (feeCalc.est.fail.totalConfirmed + feeCalc.est.fail.inMempool + feeCalc.est.fail.leftMempool) > 0.0 ? 100 * feeCalc.est.fail.withinTarget / (feeCalc.est.fail.totalConfirmed + feeCalc.est.fail.inMempool + feeCalc.est.fail.leftMempool) : 0.0,
    1098         156 :               feeCalc.est.fail.withinTarget, feeCalc.est.fail.totalConfirmed, feeCalc.est.fail.inMempool, feeCalc.est.fail.leftMempool);
    1099         156 :     return CreatedTransactionResult(tx, nFeeRet, nChangePosInOut, feeCalc);
    1100        1946 : }
    1101             : 
    1102         150 : util::Result<CreatedTransactionResult> CreateTransaction(
    1103             :         CWallet& wallet,
    1104             :         const std::vector<CRecipient>& vecSend,
    1105             :         int change_pos,
    1106             :         const CCoinControl& coin_control,
    1107             :         bool sign,
    1108             :         int nExtraPayloadSize)
    1109             : {
    1110         150 :     if (vecSend.empty()) {
    1111           1 :         return util::Error{_("Transaction must have at least one recipient")};
    1112             :     }
    1113             : 
    1114        6451 :     if (std::any_of(vecSend.cbegin(), vecSend.cend(), [](const auto& recipient){ return recipient.nAmount < 0; })) {
    1115           1 :         return util::Error{_("Transaction amounts must not be negative")};
    1116             :     }
    1117             : 
    1118         148 :     LOCK(wallet.cs_wallet);
    1119             : 
    1120         148 :     auto res = CreateTransactionInternal(wallet, vecSend, change_pos, coin_control, sign, nExtraPayloadSize);
    1121             :     TRACE4(coin_selection, normal_create_tx_internal, wallet.GetName().c_str(), bool(res),
    1122             :            res ? res->fee : 0, res ? res->change_pos : 0);
    1123         148 :     if (!res) return res;
    1124          78 :     const auto& txr_ungrouped = *res;
    1125             :     // try with avoidpartialspends unless it's enabled already
    1126          78 :     if (txr_ungrouped.fee > 0 /* 0 means non-functional fee rate estimation */ && wallet.m_max_aps_fee > -1 && !coin_control.m_avoid_partial_spends) {
    1127             :         TRACE1(coin_selection, attempting_aps_create_tx, wallet.GetName().c_str());
    1128          78 :         CCoinControl tmp_cc = coin_control;
    1129          78 :         tmp_cc.m_avoid_partial_spends = true;
    1130             : 
    1131             :         // Reuse the change destination from the first creation attempt to avoid skipping BIP44 indexes
    1132          78 :         const int ungrouped_change_pos = txr_ungrouped.change_pos;
    1133          78 :         if (ungrouped_change_pos != -1) {
    1134          42 :             ExtractDestination(txr_ungrouped.tx->vout[ungrouped_change_pos].scriptPubKey, tmp_cc.destChange);
    1135          42 :         }
    1136             : 
    1137          78 :         auto txr_grouped = CreateTransactionInternal(wallet, vecSend, change_pos, tmp_cc, sign, nExtraPayloadSize);
    1138             :         // if fee of this alternative one is within the range of the max fee, we use this one
    1139          78 :         const bool use_aps{txr_grouped.has_value() ? (txr_grouped->fee <= txr_ungrouped.fee + wallet.m_max_aps_fee) : false};
    1140             :         TRACE5(coin_selection, aps_create_tx_internal, wallet.GetName().c_str(), use_aps, txr_grouped.has_value(),
    1141             :                txr_grouped.has_value() ? txr_grouped->fee : 0, txr_grouped.has_value() ? txr_grouped->change_pos : 0);
    1142          78 :         if (txr_grouped) {
    1143         156 :             wallet.WalletLogPrintf("Fee non-grouped = %lld, grouped = %lld, using %s\n",
    1144          78 :                 txr_ungrouped.fee, txr_grouped->fee, use_aps ? "grouped" : "non-grouped");
    1145          78 :             if (use_aps) return txr_grouped;
    1146           2 :         }
    1147          78 :     }
    1148           2 :     return res;
    1149         150 : }
    1150             : 
    1151           0 : bool FundTransaction(CWallet& wallet, CMutableTransaction& tx, CAmount& nFeeRet, int& nChangePosInOut, bilingual_str& error, bool lockUnspents, const std::set<int>& setSubtractFeeFromOutputs, CCoinControl coinControl)
    1152             : {
    1153           0 :     std::vector<CRecipient> vecSend;
    1154             : 
    1155             :     // If no specific change position was requested, apply BIP69
    1156           0 :     if (nChangePosInOut == -1) {
    1157           0 :         std::sort(tx.vin.begin(), tx.vin.end(), CompareInputBIP69());
    1158           0 :         std::sort(tx.vout.begin(), tx.vout.end(), CompareOutputBIP69());
    1159           0 :     }
    1160             : 
    1161             :     // Turn the txout set into a CRecipient vector.
    1162           0 :     for (size_t idx = 0; idx < tx.vout.size(); idx++) {
    1163           0 :         const CTxOut& txOut = tx.vout[idx];
    1164           0 :         CRecipient recipient = {txOut.scriptPubKey, txOut.nValue, setSubtractFeeFromOutputs.count(idx) == 1};
    1165           0 :         vecSend.push_back(recipient);
    1166           0 :     }
    1167             : 
    1168             :     // Acquire the locks to prevent races to the new locked unspents between the
    1169             :     // CreateTransaction call and LockCoin calls (when lockUnspents is true).
    1170           0 :     LOCK(wallet.cs_wallet);
    1171             : 
    1172             :     // Fetch specified UTXOs from the UTXO set to get the scriptPubKeys and values of the outputs being selected
    1173             :     // and to match with the given solving_data. Only used for non-wallet outputs.
    1174           0 :     std::map<COutPoint, Coin> coins;
    1175           0 :     for (const CTxIn& txin : tx.vin) {
    1176           0 :         coins[txin.prevout]; // Create empty map entry keyed by prevout.
    1177             :     }
    1178           0 :     wallet.chain().findCoins(coins);
    1179             : 
    1180           0 :     for (const CTxIn& txin : tx.vin) {
    1181           0 :         const auto& outPoint = txin.prevout;
    1182           0 :         if (wallet.IsMine(outPoint)) {
    1183             :             // The input was found in the wallet, so select as internal
    1184           0 :             coinControl.Select(outPoint);
    1185           0 :         } else if (coins[outPoint].out.IsNull()) {
    1186           0 :             error = _("Unable to find UTXO for external input");
    1187           0 :             return false;
    1188             :         } else {
    1189             :             // The input was not in the wallet, but is in the UTXO set, so select as external
    1190           0 :             coinControl.SelectExternal(outPoint, coins[outPoint].out);
    1191             :         }
    1192             :     }
    1193             : 
    1194           0 :     auto res = CreateTransaction(wallet, vecSend, nChangePosInOut, coinControl, /*sign=*/false, tx.vExtraPayload.size());
    1195           0 :     if (!res) {
    1196           0 :         error = util::ErrorString(res);
    1197           0 :         return false;
    1198             :     }
    1199           0 :     const auto& txr = *res;
    1200           0 :     CTransactionRef tx_new = txr.tx;
    1201           0 :     nFeeRet = txr.fee;
    1202           0 :     nChangePosInOut = txr.change_pos;
    1203             : 
    1204           0 :     if (nChangePosInOut != -1) {
    1205           0 :         tx.vout.insert(tx.vout.begin() + nChangePosInOut, tx_new->vout[nChangePosInOut]);
    1206           0 :     }
    1207             : 
    1208             :     // Copy output sizes from new transaction; they may have had the fee
    1209             :     // subtracted from them.
    1210           0 :     for (unsigned int idx = 0; idx < tx.vout.size(); idx++) {
    1211           0 :         tx.vout[idx].nValue = tx_new->vout[idx].nValue;
    1212           0 :     }
    1213             : 
    1214             :     // Add new txins while keeping original txin scriptSig/order.
    1215           0 :     for (const CTxIn& txin : tx_new->vin) {
    1216           0 :         if (!coinControl.IsSelected(txin.prevout)) {
    1217           0 :             tx.vin.push_back(txin);
    1218             : 
    1219           0 :         }
    1220           0 :         if (lockUnspents) {
    1221           0 :             wallet.LockCoin(txin.prevout);
    1222           0 :         }
    1223             : 
    1224             :     }
    1225             : 
    1226           0 :     return true;
    1227           0 : }
    1228             : 
    1229           0 : bool GenBudgetSystemCollateralTx(CWallet& wallet, CTransactionRef& tx, uint256 hash, CAmount amount, const COutPoint& outpoint)
    1230             : {
    1231           0 :     const CScript scriptChange{CScript() << OP_RETURN << ToByteVector(hash)};
    1232           0 :     const std::vector<CRecipient> vecSend{{scriptChange, amount, false}};
    1233             : 
    1234           0 :     CCoinControl coinControl;
    1235           0 :     if (!outpoint.IsNull()) {
    1236           0 :         coinControl.Select(outpoint);
    1237           0 :     }
    1238             : 
    1239           0 :     auto res{CreateTransaction(wallet, vecSend, RANDOM_CHANGE_POSITION, coinControl)};
    1240           0 :     if (!res) {
    1241           0 :         wallet.WalletLogPrintf("%s -- Error: %s\n", __func__, util::ErrorString(res).original);
    1242           0 :         return false;
    1243             :     }
    1244           0 :     tx = res->tx;
    1245           0 :     return true;
    1246           0 : }
    1247             : } // namespace wallet

Generated by: LCOV version 1.16