@@ -57,6 +57,58 @@ static feebumper::Result PreconditionChecks(interfaces::Chain::Lock& locked_chai
57
57
return feebumper::Result::OK;
58
58
}
59
59
60
+ // ! Check if the user provided a valid feeRate
61
+ static feebumper::Result CheckFeeRate (const CWallet* wallet, const CWalletTx& wtx, const CFeeRate& newFeerate, const int64_t maxTxSize, std::vector<std::string>& errors) {
62
+ // check that fee rate is higher than mempool's minimum fee
63
+ // (no point in bumping fee if we know that the new tx won't be accepted to the mempool)
64
+ // This may occur if the user set FeeRate, TotalFee or paytxfee too low, if fallbackfee is too low, or, perhaps,
65
+ // in a rare situation where the mempool minimum fee increased significantly since the fee estimation just a
66
+ // moment earlier. In this case, we report an error to the user, who may adjust the fee.
67
+ CFeeRate minMempoolFeeRate = wallet->chain ().mempoolMinFee ();
68
+
69
+ if (newFeerate.GetFeePerK () < minMempoolFeeRate.GetFeePerK ()) {
70
+ errors.push_back (strprintf (
71
+ " New fee rate (%s) is lower than the minimum fee rate (%s) to get into the mempool -- " ,
72
+ FormatMoney (newFeerate.GetFeePerK ()),
73
+ FormatMoney (minMempoolFeeRate.GetFeePerK ())));
74
+ return feebumper::Result::WALLET_ERROR;
75
+ }
76
+
77
+ CAmount new_total_fee = newFeerate.GetFee (maxTxSize);
78
+
79
+ CFeeRate incrementalRelayFee = std::max (wallet->chain ().relayIncrementalFee (), CFeeRate (WALLET_INCREMENTAL_RELAY_FEE));
80
+
81
+ // Given old total fee and transaction size, calculate the old feeRate
82
+ CAmount old_fee = wtx.GetDebit (ISMINE_SPENDABLE) - wtx.tx ->GetValueOut ();
83
+ const int64_t txSize = GetVirtualTransactionSize (*(wtx.tx ));
84
+ CFeeRate nOldFeeRate (old_fee, txSize);
85
+ // Min total fee is old fee + relay fee
86
+ CAmount minTotalFee = nOldFeeRate.GetFee (maxTxSize) + incrementalRelayFee.GetFee (maxTxSize);
87
+
88
+ if (new_total_fee < minTotalFee) {
89
+ errors.push_back (strprintf (" Insufficient total fee %s, must be at least %s (oldFee %s + incrementalFee %s)" ,
90
+ FormatMoney (new_total_fee), FormatMoney (minTotalFee), FormatMoney (nOldFeeRate.GetFee (maxTxSize)), FormatMoney (incrementalRelayFee.GetFee (maxTxSize))));
91
+ return feebumper::Result::INVALID_PARAMETER;
92
+ }
93
+
94
+ CAmount requiredFee = GetRequiredFee (*wallet, maxTxSize);
95
+ if (new_total_fee < requiredFee) {
96
+ errors.push_back (strprintf (" Insufficient total fee (cannot be less than required fee %s)" ,
97
+ FormatMoney (requiredFee)));
98
+ return feebumper::Result::INVALID_PARAMETER;
99
+ }
100
+
101
+ // Check that in all cases the new fee doesn't violate maxTxFee
102
+ const CAmount max_tx_fee = wallet->m_default_max_tx_fee ;
103
+ if (new_total_fee > max_tx_fee) {
104
+ errors.push_back (strprintf (" Specified or calculated fee %s is too high (cannot be higher than -maxtxfee %s)" ,
105
+ FormatMoney (new_total_fee), FormatMoney (max_tx_fee)));
106
+ return feebumper::Result::WALLET_ERROR;
107
+ }
108
+
109
+ return feebumper::Result::OK;
110
+ }
111
+
60
112
static CFeeRate EstimateFeeRate (CWallet* wallet, const CWalletTx& wtx, CCoinControl& coin_control, CAmount& old_fee)
61
113
{
62
114
// Get the fee rate of the original transaction. This is calculated from
@@ -260,6 +312,12 @@ Result CreateRateBumpTransaction(CWallet* wallet, const uint256& txid, const CCo
260
312
261
313
if (coin_control.m_feerate ) {
262
314
// The user provided a feeRate argument.
315
+ // We calculate this here to avoid compiler warning on the cs_wallet lock
316
+ const int64_t maxTxSize = CalculateMaximumSignedTxSize (*wtx.tx , wallet);
317
+ Result res = CheckFeeRate (wallet, wtx, *(new_coin_control.m_feerate ), maxTxSize, errors);
318
+ if (res != Result::OK) {
319
+ return res;
320
+ }
263
321
} else {
264
322
// The user did not provide a feeRate argument
265
323
new_coin_control.m_feerate = EstimateFeeRate (wallet, wtx, new_coin_control, old_fee);
0 commit comments