LCOV - code coverage report
Current view: top level - src/wallet - feebumper.cpp (source / functions) Hit Total Coverage
Test: fuzz_coverage.info Lines: 15 222 6.8 %
Date: 2023-09-26 12:08:55 Functions: 8 16 50.0 %

          Line data    Source code
       1             : // Copyright (c) 2017-2022 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 <common/system.h>
       6             : #include <consensus/validation.h>
       7             : #include <interfaces/chain.h>
       8             : #include <policy/fees.h>
       9             : #include <policy/policy.h>
      10             : #include <util/moneystr.h>
      11             : #include <util/rbf.h>
      12             : #include <util/translation.h>
      13             : #include <wallet/coincontrol.h>
      14             : #include <wallet/feebumper.h>
      15             : #include <wallet/fees.h>
      16             : #include <wallet/receive.h>
      17           2 : #include <wallet/spend.h>
      18           2 : #include <wallet/wallet.h>
      19             : 
      20             : namespace wallet {
      21             : //! Check whether transaction has descendant in wallet or mempool, or has been
      22             : //! mined, or conflicts with a mined transaction. Return a feebumper::Result.
      23           0 : static feebumper::Result PreconditionChecks(const CWallet& wallet, const CWalletTx& wtx, bool require_mine, std::vector<bilingual_str>& errors) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
      24             : {
      25           0 :     if (wallet.HasWalletSpend(wtx.tx)) {
      26           0 :         errors.push_back(Untranslated("Transaction has descendants in the wallet"));
      27           2 :         return feebumper::Result::INVALID_PARAMETER;
      28             :     }
      29             : 
      30             :     {
      31           0 :         if (wallet.chain().hasDescendantsInMempool(wtx.GetHash())) {
      32           0 :             errors.push_back(Untranslated("Transaction has descendants in the mempool"));
      33           0 :             return feebumper::Result::INVALID_PARAMETER;
      34             :         }
      35             :     }
      36             : 
      37           0 :     if (wallet.GetTxDepthInMainChain(wtx) != 0) {
      38           0 :         errors.push_back(Untranslated("Transaction has been mined, or is conflicted with a mined transaction"));
      39           0 :         return feebumper::Result::WALLET_ERROR;
      40             :     }
      41             : 
      42           0 :     if (!SignalsOptInRBF(*wtx.tx)) {
      43           0 :         errors.push_back(Untranslated("Transaction is not BIP 125 replaceable"));
      44           0 :         return feebumper::Result::WALLET_ERROR;
      45             :     }
      46             : 
      47           0 :     if (wtx.mapValue.count("replaced_by_txid")) {
      48           0 :         errors.push_back(strprintf(Untranslated("Cannot bump transaction %s which was already bumped by transaction %s"), wtx.GetHash().ToString(), wtx.mapValue.at("replaced_by_txid")));
      49           0 :         return feebumper::Result::WALLET_ERROR;
      50             :     }
      51             : 
      52           0 :     if (require_mine) {
      53           0 :         // check that original tx consists entirely of our inputs
      54             :         // if not, we can't bump the fee, because the wallet has no way of knowing the value of the other inputs (thus the fee)
      55           0 :         isminefilter filter = wallet.GetLegacyScriptPubKeyMan() && wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) ? ISMINE_WATCH_ONLY : ISMINE_SPENDABLE;
      56           0 :         if (!AllInputsMine(wallet, *wtx.tx, filter)) {
      57           0 :             errors.push_back(Untranslated("Transaction contains inputs that don't belong to this wallet"));
      58           0 :             return feebumper::Result::WALLET_ERROR;
      59             :         }
      60           0 :     }
      61             : 
      62           0 :     return feebumper::Result::OK;
      63           0 : }
      64             : 
      65             : //! Check if the user provided a valid feeRate
      66           0 : static feebumper::Result CheckFeeRate(const CWallet& wallet, const CMutableTransaction& mtx, const CFeeRate& newFeerate, const int64_t maxTxSize, CAmount old_fee, std::vector<bilingual_str>& errors)
      67             : {
      68             :     // check that fee rate is higher than mempool's minimum fee
      69             :     // (no point in bumping fee if we know that the new tx won't be accepted to the mempool)
      70             :     // This may occur if the user set fee_rate or paytxfee too low, if fallbackfee is too low, or, perhaps,
      71             :     // in a rare situation where the mempool minimum fee increased significantly since the fee estimation just a
      72             :     // moment earlier. In this case, we report an error to the user, who may adjust the fee.
      73           0 :     CFeeRate minMempoolFeeRate = wallet.chain().mempoolMinFee();
      74           2 : 
      75           0 :     if (newFeerate.GetFeePerK() < minMempoolFeeRate.GetFeePerK()) {
      76           0 :         errors.push_back(strprintf(
      77           0 :             Untranslated("New fee rate (%s) is lower than the minimum fee rate (%s) to get into the mempool -- "),
      78           0 :             FormatMoney(newFeerate.GetFeePerK()),
      79           0 :             FormatMoney(minMempoolFeeRate.GetFeePerK())));
      80           0 :         return feebumper::Result::WALLET_ERROR;
      81             :     }
      82             : 
      83           0 :     std::vector<COutPoint> reused_inputs;
      84           0 :     reused_inputs.reserve(mtx.vin.size());
      85           0 :     for (const CTxIn& txin : mtx.vin) {
      86           0 :         reused_inputs.push_back(txin.prevout);
      87             :     }
      88             : 
      89           0 :     std::optional<CAmount> combined_bump_fee = wallet.chain().CalculateCombinedBumpFee(reused_inputs, newFeerate);
      90           0 :     if (!combined_bump_fee.has_value()) {
      91           2 :         errors.push_back(strprintf(Untranslated("Failed to calculate bump fees, because unconfirmed UTXOs depend on enormous cluster of unconfirmed transactions.")));
      92           0 :     }
      93           0 :     CAmount new_total_fee = newFeerate.GetFee(maxTxSize) + combined_bump_fee.value();
      94             : 
      95           0 :     CFeeRate incrementalRelayFee = std::max(wallet.chain().relayIncrementalFee(), CFeeRate(WALLET_INCREMENTAL_RELAY_FEE));
      96             : 
      97             :     // Min total fee is old fee + relay fee
      98           0 :     CAmount minTotalFee = old_fee + incrementalRelayFee.GetFee(maxTxSize);
      99           2 : 
     100           0 :     if (new_total_fee < minTotalFee) {
     101           0 :         errors.push_back(strprintf(Untranslated("Insufficient total fee %s, must be at least %s (oldFee %s + incrementalFee %s)"),
     102           0 :             FormatMoney(new_total_fee), FormatMoney(minTotalFee), FormatMoney(old_fee), FormatMoney(incrementalRelayFee.GetFee(maxTxSize))));
     103           0 :         return feebumper::Result::INVALID_PARAMETER;
     104             :     }
     105             : 
     106           0 :     CAmount requiredFee = GetRequiredFee(wallet, maxTxSize);
     107           0 :     if (new_total_fee < requiredFee) {
     108           0 :         errors.push_back(strprintf(Untranslated("Insufficient total fee (cannot be less than required fee %s)"),
     109           0 :             FormatMoney(requiredFee)));
     110           0 :         return feebumper::Result::INVALID_PARAMETER;
     111             :     }
     112             : 
     113             :     // Check that in all cases the new fee doesn't violate maxTxFee
     114           0 :     const CAmount max_tx_fee = wallet.m_default_max_tx_fee;
     115           0 :     if (new_total_fee > max_tx_fee) {
     116           0 :         errors.push_back(strprintf(Untranslated("Specified or calculated fee %s is too high (cannot be higher than -maxtxfee %s)"),
     117           0 :             FormatMoney(new_total_fee), FormatMoney(max_tx_fee)));
     118           0 :         return feebumper::Result::WALLET_ERROR;
     119             :     }
     120             : 
     121           0 :     return feebumper::Result::OK;
     122           0 : }
     123             : 
     124           0 : static CFeeRate EstimateFeeRate(const CWallet& wallet, const CWalletTx& wtx, const CAmount old_fee, const CCoinControl& coin_control)
     125             : {
     126             :     // Get the fee rate of the original transaction. This is calculated from
     127             :     // the tx fee/vsize, so it may have been rounded down. Add 1 satoshi to the
     128             :     // result.
     129           0 :     int64_t txSize = GetVirtualTransactionSize(*(wtx.tx));
     130           0 :     CFeeRate feerate(old_fee, txSize);
     131           0 :     feerate += CFeeRate(1);
     132             : 
     133             :     // The node has a configurable incremental relay fee. Increment the fee by
     134             :     // the minimum of that and the wallet's conservative
     135             :     // WALLET_INCREMENTAL_RELAY_FEE value to future proof against changes to
     136             :     // network wide policy for incremental relay fee that our node may not be
     137             :     // aware of. This ensures we're over the required relay fee rate
     138             :     // (Rule 4).  The replacement tx will be at least as large as the
     139             :     // original tx, so the total fee will be greater (Rule 3)
     140           0 :     CFeeRate node_incremental_relay_fee = wallet.chain().relayIncrementalFee();
     141           0 :     CFeeRate wallet_incremental_relay_fee = CFeeRate(WALLET_INCREMENTAL_RELAY_FEE);
     142           0 :     feerate += std::max(node_incremental_relay_fee, wallet_incremental_relay_fee);
     143             : 
     144             :     // Fee rate must also be at least the wallet's GetMinimumFeeRate
     145           0 :     CFeeRate min_feerate(GetMinimumFeeRate(wallet, coin_control, /*feeCalc=*/nullptr));
     146             : 
     147             :     // Set the required fee rate for the replacement transaction in coin control.
     148           0 :     return std::max(feerate, min_feerate);
     149             : }
     150             : 
     151             : namespace feebumper {
     152             : 
     153           0 : bool TransactionCanBeBumped(const CWallet& wallet, const uint256& txid)
     154             : {
     155           0 :     LOCK(wallet.cs_wallet);
     156           0 :     const CWalletTx* wtx = wallet.GetWalletTx(txid);
     157           0 :     if (wtx == nullptr) return false;
     158             : 
     159           0 :     std::vector<bilingual_str> errors_dummy;
     160           0 :     feebumper::Result res = PreconditionChecks(wallet, *wtx, /* require_mine=*/ true, errors_dummy);
     161           0 :     return res == feebumper::Result::OK;
     162           0 : }
     163           2 : 
     164           2 : Result CreateRateBumpTransaction(CWallet& wallet, const uint256& txid, const CCoinControl& coin_control, std::vector<bilingual_str>& errors,
     165           2 :                                  CAmount& old_fee, CAmount& new_fee, CMutableTransaction& mtx, bool require_mine, const std::vector<CTxOut>& outputs, std::optional<uint32_t> reduce_output)
     166           2 : {
     167           2 :     // Cannot both specify new outputs and an output to reduce
     168           2 :     if (!outputs.empty() && reduce_output.has_value()) {
     169           2 :         errors.push_back(Untranslated("Cannot specify both new outputs to use and an output index to reduce"));
     170           2 :         return Result::INVALID_PARAMETER;
     171             :     }
     172             : 
     173             :     // We are going to modify coin control later, copy to re-use
     174           0 :     CCoinControl new_coin_control(coin_control);
     175             : 
     176           0 :     LOCK(wallet.cs_wallet);
     177           0 :     errors.clear();
     178           0 :     auto it = wallet.mapWallet.find(txid);
     179           0 :     if (it == wallet.mapWallet.end()) {
     180           0 :         errors.push_back(Untranslated("Invalid or non-wallet transaction id"));
     181           0 :         return Result::INVALID_ADDRESS_OR_KEY;
     182             :     }
     183           0 :     const CWalletTx& wtx = it->second;
     184             : 
     185             :     // Make sure that reduce_output is valid
     186           0 :     if (reduce_output.has_value() && reduce_output.value() >= wtx.tx->vout.size()) {
     187           0 :         errors.push_back(Untranslated("Change position is out of range"));
     188           0 :         return Result::INVALID_PARAMETER;
     189             :     }
     190             : 
     191             :     // Retrieve all of the UTXOs and add them to coin control
     192             :     // While we're here, calculate the input amount
     193           0 :     std::map<COutPoint, Coin> coins;
     194           0 :     CAmount input_value = 0;
     195           0 :     std::vector<CTxOut> spent_outputs;
     196           0 :     for (const CTxIn& txin : wtx.tx->vin) {
     197           0 :         coins[txin.prevout]; // Create empty map entry keyed by prevout.
     198             :     }
     199           0 :     wallet.chain().findCoins(coins);
     200           0 :     for (const CTxIn& txin : wtx.tx->vin) {
     201           0 :         const Coin& coin = coins.at(txin.prevout);
     202           0 :         if (coin.out.IsNull()) {
     203           0 :             errors.push_back(Untranslated(strprintf("%s:%u is already spent", txin.prevout.hash.GetHex(), txin.prevout.n)));
     204           0 :             return Result::MISC_ERROR;
     205             :         }
     206           0 :         if (wallet.IsMine(txin.prevout)) {
     207           0 :             new_coin_control.Select(txin.prevout);
     208           0 :         } else {
     209           0 :             new_coin_control.SelectExternal(txin.prevout, coin.out);
     210             :         }
     211           0 :         input_value += coin.out.nValue;
     212           0 :         spent_outputs.push_back(coin.out);
     213             :     }
     214             : 
     215             :     // Figure out if we need to compute the input weight, and do so if necessary
     216           0 :     PrecomputedTransactionData txdata;
     217           0 :     txdata.Init(*wtx.tx, std::move(spent_outputs), /* force=*/ true);
     218           0 :     for (unsigned int i = 0; i < wtx.tx->vin.size(); ++i) {
     219           0 :         const CTxIn& txin = wtx.tx->vin.at(i);
     220           0 :         const Coin& coin = coins.at(txin.prevout);
     221             : 
     222           0 :         if (new_coin_control.IsExternalSelected(txin.prevout)) {
     223             :             // For external inputs, we estimate the size using the size of this input
     224           0 :             int64_t input_weight = GetTransactionInputWeight(txin);
     225             :             // Because signatures can have different sizes, we need to figure out all of the
     226             :             // signature sizes and replace them with the max sized signature.
     227             :             // In order to do this, we verify the script with a special SignatureChecker which
     228             :             // will observe the signatures verified and record their sizes.
     229           0 :             SignatureWeights weights;
     230           0 :             TransactionSignatureChecker tx_checker(wtx.tx.get(), i, coin.out.nValue, txdata, MissingDataBehavior::FAIL);
     231           0 :             SignatureWeightChecker size_checker(weights, tx_checker);
     232           0 :             VerifyScript(txin.scriptSig, coin.out.scriptPubKey, &txin.scriptWitness, STANDARD_SCRIPT_VERIFY_FLAGS, size_checker);
     233             :             // Add the difference between max and current to input_weight so that it represents the largest the input could be
     234           0 :             input_weight += weights.GetWeightDiffToMax();
     235           0 :             new_coin_control.SetInputWeight(txin.prevout, input_weight);
     236           0 :         }
     237           0 :     }
     238             : 
     239           0 :     Result result = PreconditionChecks(wallet, wtx, require_mine, errors);
     240           0 :     if (result != Result::OK) {
     241           0 :         return result;
     242             :     }
     243             : 
     244             :     // Calculate the old output amount.
     245           0 :     CAmount output_value = 0;
     246           0 :     for (const auto& old_output : wtx.tx->vout) {
     247           0 :         output_value += old_output.nValue;
     248             :     }
     249             : 
     250           0 :     old_fee = input_value - output_value;
     251             : 
     252             :     // Fill in recipients (and preserve a single change key if there
     253             :     // is one). If outputs vector is non-empty, replace original
     254             :     // outputs with its contents, otherwise use original outputs.
     255           0 :     std::vector<CRecipient> recipients;
     256           0 :     CAmount new_outputs_value = 0;
     257           0 :     const auto& txouts = outputs.empty() ? wtx.tx->vout : outputs;
     258           0 :     for (size_t i = 0; i < txouts.size(); ++i) {
     259           0 :         const CTxOut& output = txouts.at(i);
     260           0 :         CTxDestination dest;
     261           0 :         ExtractDestination(output.scriptPubKey, dest);
     262           0 :         if (reduce_output.has_value() ?  reduce_output.value() == i : OutputIsChange(wallet, output)) {
     263           0 :             new_coin_control.destChange = dest;
     264           0 :         } else {
     265           0 :             CRecipient recipient = {dest, output.nValue, false};
     266           0 :             recipients.push_back(recipient);
     267           0 :         }
     268           0 :         new_outputs_value += output.nValue;
     269           0 :     }
     270           2 : 
     271             :     // If no recipients, means that we are sending coins to a change address
     272           0 :     if (recipients.empty()) {
     273             :         // Just as a sanity check, ensure that the change address exist
     274           0 :         if (std::get_if<CNoDestination>(&new_coin_control.destChange)) {
     275           0 :             errors.emplace_back(Untranslated("Unable to create transaction. Transaction must have at least one recipient"));
     276           0 :             return Result::INVALID_PARAMETER;
     277             :         }
     278             : 
     279             :         // Add change as recipient with SFFO flag enabled, so fees are deduced from it.
     280             :         // If the output differs from the original tx output (because the user customized it) a new change output will be created.
     281           0 :         recipients.emplace_back(CRecipient{new_coin_control.destChange, new_outputs_value, /*fSubtractFeeFromAmount=*/true});
     282           0 :         new_coin_control.destChange = CNoDestination();
     283           0 :     }
     284             : 
     285           0 :     if (coin_control.m_feerate) {
     286             :         // The user provided a feeRate argument.
     287             :         // We calculate this here to avoid compiler warning on the cs_wallet lock
     288             :         // We need to make a temporary transaction with no input witnesses as the dummy signer expects them to be empty for external inputs
     289           0 :         CMutableTransaction temp_mtx{*wtx.tx};
     290           0 :         for (auto& txin : temp_mtx.vin) {
     291           0 :             txin.scriptSig.clear();
     292           0 :             txin.scriptWitness.SetNull();
     293             :         }
     294           0 :         temp_mtx.vout = txouts;
     295           0 :         const int64_t maxTxSize{CalculateMaximumSignedTxSize(CTransaction(temp_mtx), &wallet, &new_coin_control).vsize};
     296           0 :         Result res = CheckFeeRate(wallet, temp_mtx, *new_coin_control.m_feerate, maxTxSize, old_fee, errors);
     297           0 :         if (res != Result::OK) {
     298           0 :             return res;
     299             :         }
     300           0 :     } else {
     301             :         // The user did not provide a feeRate argument
     302           0 :         new_coin_control.m_feerate = EstimateFeeRate(wallet, wtx, old_fee, new_coin_control);
     303             :     }
     304             : 
     305             :     // Fill in required inputs we are double-spending(all of them)
     306             :     // N.B.: bip125 doesn't require all the inputs in the replaced transaction to be
     307             :     // used in the replacement transaction, but it's very important for wallets to make
     308             :     // sure that happens. If not, it would be possible to bump a transaction A twice to
     309             :     // A2 and A3 where A2 and A3 don't conflict (or alternatively bump A to A2 and A2
     310             :     // to A3 where A and A3 don't conflict). If both later get confirmed then the sender
     311             :     // has accidentally double paid.
     312           0 :     for (const auto& inputs : wtx.tx->vin) {
     313           0 :         new_coin_control.Select(COutPoint(inputs.prevout));
     314             :     }
     315           0 :     new_coin_control.m_allow_other_inputs = true;
     316             : 
     317             :     // We cannot source new unconfirmed inputs(bip125 rule 2)
     318           0 :     new_coin_control.m_min_depth = 1;
     319             : 
     320           0 :     constexpr int RANDOM_CHANGE_POSITION = -1;
     321           0 :     auto res = CreateTransaction(wallet, recipients, RANDOM_CHANGE_POSITION, new_coin_control, false);
     322           0 :     if (!res) {
     323           0 :         errors.push_back(Untranslated("Unable to create transaction.") + Untranslated(" ") + util::ErrorString(res));
     324           0 :         return Result::WALLET_ERROR;
     325             :     }
     326             : 
     327           0 :     const auto& txr = *res;
     328             :     // Write back new fee if successful
     329           0 :     new_fee = txr.fee;
     330             : 
     331             :     // Write back transaction
     332           0 :     mtx = CMutableTransaction(*txr.tx);
     333             : 
     334           0 :     return Result::OK;
     335           0 : }
     336             : 
     337           0 : bool SignTransaction(CWallet& wallet, CMutableTransaction& mtx) {
     338           0 :     LOCK(wallet.cs_wallet);
     339             : 
     340           0 :     if (wallet.IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER)) {
     341             :         // Make a blank psbt
     342           0 :         PartiallySignedTransaction psbtx(mtx);
     343             : 
     344             :         // First fill transaction with our data without signing,
     345             :         // so external signers are not asked to sign more than once.
     346             :         bool complete;
     347           0 :         wallet.FillPSBT(psbtx, complete, SIGHASH_ALL, false /* sign */, true /* bip32derivs */);
     348           0 :         const TransactionError err = wallet.FillPSBT(psbtx, complete, SIGHASH_ALL, true /* sign */, false  /* bip32derivs */);
     349           0 :         if (err != TransactionError::OK) return false;
     350           0 :         complete = FinalizeAndExtractPSBT(psbtx, mtx);
     351           0 :         return complete;
     352           0 :     } else {
     353           0 :         return wallet.SignTransaction(mtx);
     354             :     }
     355           0 : }
     356             : 
     357           0 : Result CommitTransaction(CWallet& wallet, const uint256& txid, CMutableTransaction&& mtx, std::vector<bilingual_str>& errors, uint256& bumped_txid)
     358             : {
     359           0 :     LOCK(wallet.cs_wallet);
     360           0 :     if (!errors.empty()) {
     361           0 :         return Result::MISC_ERROR;
     362             :     }
     363           0 :     auto it = txid.IsNull() ? wallet.mapWallet.end() : wallet.mapWallet.find(txid);
     364           0 :     if (it == wallet.mapWallet.end()) {
     365           0 :         errors.push_back(Untranslated("Invalid or non-wallet transaction id"));
     366           0 :         return Result::MISC_ERROR;
     367             :     }
     368           0 :     const CWalletTx& oldWtx = it->second;
     369             : 
     370             :     // make sure the transaction still has no descendants and hasn't been mined in the meantime
     371           0 :     Result result = PreconditionChecks(wallet, oldWtx, /* require_mine=*/ false, errors);
     372           0 :     if (result != Result::OK) {
     373           0 :         return result;
     374             :     }
     375             : 
     376             :     // commit/broadcast the tx
     377           0 :     CTransactionRef tx = MakeTransactionRef(std::move(mtx));
     378           0 :     mapValue_t mapValue = oldWtx.mapValue;
     379           0 :     mapValue["replaces_txid"] = oldWtx.GetHash().ToString();
     380             : 
     381           0 :     wallet.CommitTransaction(tx, std::move(mapValue), oldWtx.vOrderForm);
     382             : 
     383             :     // mark the original tx as bumped
     384           0 :     bumped_txid = tx->GetHash();
     385           0 :     if (!wallet.MarkReplaced(oldWtx.GetHash(), bumped_txid)) {
     386           0 :         errors.push_back(Untranslated("Created new bumpfee transaction but could not mark the original transaction as replaced"));
     387           0 :     }
     388           0 :     return Result::OK;
     389           0 : }
     390             : 
     391             : } // namespace feebumper
     392             : } // namespace wallet

Generated by: LCOV version 1.14