Check if the user provided a valid feeRate
| 60 | |
| 61 | //! Check if the user provided a valid feeRate |
| 62 | 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) |
| 63 | { |
| 64 | // check that fee rate is higher than mempool's minimum fee |
| 65 | // (no point in bumping fee if we know that the new tx won't be accepted to the mempool) |
| 66 | // This may occur if fallbackfee is too low, or, perhaps, |
| 67 | // in a rare situation where the mempool minimum fee increased significantly since the fee estimation just a |
| 68 | // moment earlier. In this case, we report an error to the user, who may adjust the fee. |
| 69 | CFeeRate minMempoolFeeRate = wallet.chain().mempoolMinFee(); |
| 70 | |
| 71 | if (newFeerate.GetFeePerK() < minMempoolFeeRate.GetFeePerK()) { |
| 72 | errors.push_back(Untranslated( |
| 73 | strprintf("New fee rate (%s) is lower than the minimum fee rate (%s) to get into the mempool -- ", |
| 74 | FormatMoney(newFeerate.GetFeePerK()), |
| 75 | FormatMoney(minMempoolFeeRate.GetFeePerK())))); |
| 76 | return feebumper::Result::WALLET_ERROR; |
| 77 | } |
| 78 | |
| 79 | std::vector<COutPoint> reused_inputs; |
| 80 | reused_inputs.reserve(mtx.vin.size()); |
| 81 | for (const CTxIn& txin : mtx.vin) { |
| 82 | reused_inputs.push_back(txin.prevout); |
| 83 | } |
| 84 | |
| 85 | const std::optional<CAmount> combined_bump_fee = wallet.chain().calculateCombinedBumpFee(reused_inputs, newFeerate); |
| 86 | if (!combined_bump_fee.has_value()) { |
| 87 | errors.push_back(Untranslated(strprintf("Failed to calculate bump fees, because unconfirmed UTXOs depend on an enormous cluster of unconfirmed transactions."))); |
| 88 | return feebumper::Result::WALLET_ERROR; |
| 89 | } |
| 90 | CAmount new_total_fee = newFeerate.GetFee(maxTxSize) + combined_bump_fee.value(); |
| 91 | |
| 92 | CFeeRate incrementalRelayFee = wallet.chain().relayIncrementalFee(); |
| 93 | |
| 94 | // Min total fee is old fee + relay fee |
| 95 | CAmount minTotalFee = old_fee + incrementalRelayFee.GetFee(maxTxSize); |
| 96 | |
| 97 | if (new_total_fee < minTotalFee) { |
| 98 | errors.push_back(Untranslated(strprintf("Insufficient total fee %s, must be at least %s (oldFee %s + incrementalFee %s)", |
| 99 | FormatMoney(new_total_fee), FormatMoney(minTotalFee), FormatMoney(old_fee), FormatMoney(incrementalRelayFee.GetFee(maxTxSize))))); |
| 100 | return feebumper::Result::INVALID_PARAMETER; |
| 101 | } |
| 102 | |
| 103 | CAmount requiredFee = GetRequiredFee(wallet, maxTxSize); |
| 104 | if (new_total_fee < requiredFee) { |
| 105 | errors.push_back(Untranslated(strprintf("Insufficient total fee (cannot be less than required fee %s)", |
| 106 | FormatMoney(requiredFee)))); |
| 107 | return feebumper::Result::INVALID_PARAMETER; |
| 108 | } |
| 109 | |
| 110 | // Check that in all cases the new fee doesn't violate maxTxFee |
| 111 | const CAmount max_tx_fee = wallet.m_default_max_tx_fee; |
| 112 | if (new_total_fee > max_tx_fee) { |
| 113 | errors.push_back(Untranslated(strprintf("Specified or calculated fee %s is too high (cannot be higher than -maxtxfee %s)", |
| 114 | FormatMoney(new_total_fee), FormatMoney(max_tx_fee)))); |
| 115 | return feebumper::Result::WALLET_ERROR; |
| 116 | } |
| 117 | |
| 118 | return feebumper::Result::OK; |
| 119 | } |
no test coverage detected