@@ -197,17 +197,19 @@ static std::string LabelFromValue(const UniValue& value)
197
197
/* *
198
198
* Update coin control with fee estimation based on the given parameters
199
199
*
200
- * @param[in] pwallet Wallet pointer
201
- * @param[in,out] cc Coin control which is to be updated
202
- * @param[in] conf_target UniValue integer, confirmation target in blocks, values between 1 and 1008 are valid per policy/fees.h;
203
- * if a fee_rate is present, 0 is allowed here as a no-op positional placeholder
204
- * @param[in] estimate_mode UniValue string, fee estimation mode, valid values are "unset", "economical" or "conservative";
205
- * if a fee_rate is present, "" is allowed here as a no-op positional placeholder
206
- * @param[in] fee_rate UniValue real, fee rate in sat/vB;
207
- * if a fee_rate is present, both conf_target and estimate_mode must either be null, or no-op values
200
+ * @param[in] pwallet Wallet pointer
201
+ * @param[in,out] cc Coin control to be updated
202
+ * @param[in] conf_target UniValue integer; confirmation target in blocks, values between 1 and 1008 are valid per policy/fees.h;
203
+ * if a fee_rate is present, 0 is allowed here as a no-op positional placeholder
204
+ * @param[in] estimate_mode UniValue string; fee estimation mode, valid values are "unset", "economical" or "conservative";
205
+ * if a fee_rate is present, "" is allowed here as a no-op positional placeholder
206
+ * @param[in] fee_rate UniValue real; fee rate in sat/vB;
207
+ * if a fee_rate is present, both conf_target and estimate_mode must either be null, or no-op
208
+ * @param[in] override_min_fee bool; whether to set fOverrideFeeRate to true to disable minimum fee rate checks and instead
209
+ * verify only that fee_rate is greater than 0
208
210
* @throws a JSONRPCError if conf_target, estimate_mode, or fee_rate contain invalid values or are in conflict
209
211
*/
210
- static void SetFeeEstimateMode (const CWallet* pwallet, CCoinControl& cc, const UniValue& conf_target, const UniValue& estimate_mode, const UniValue& fee_rate)
212
+ static void SetFeeEstimateMode (const CWallet* pwallet, CCoinControl& cc, const UniValue& conf_target, const UniValue& estimate_mode, const UniValue& fee_rate, bool override_min_fee )
211
213
{
212
214
if (!fee_rate.isNull ()) {
213
215
if (!conf_target.isNull () && conf_target.get_int () > 0 ) {
@@ -216,7 +218,14 @@ static void SetFeeEstimateMode(const CWallet* pwallet, CCoinControl& cc, const U
216
218
if (!estimate_mode.isNull () && !estimate_mode.get_str ().empty ()) {
217
219
throw JSONRPCError (RPC_INVALID_PARAMETER, " Cannot specify both estimate_mode and fee_rate" );
218
220
}
219
- cc.m_feerate = CFeeRate (AmountFromValue (fee_rate), COIN);
221
+ CFeeRate fee_rate_in_sat_vb{CFeeRate (AmountFromValue (fee_rate), COIN)};
222
+ if (override_min_fee) {
223
+ if (fee_rate_in_sat_vb <= CFeeRate (0 )) {
224
+ throw JSONRPCError (RPC_INVALID_PARAMETER, strprintf (" Invalid fee_rate %s (must be greater than 0)" , fee_rate_in_sat_vb.ToString (FeeEstimateMode::SAT_VB)));
225
+ }
226
+ cc.fOverrideFeeRate = true ;
227
+ }
228
+ cc.m_feerate = fee_rate_in_sat_vb;
220
229
// Default RBF to true for explicit fee_rate, if unset.
221
230
if (cc.m_signal_bip125_rbf == nullopt) cc.m_signal_bip125_rbf = true ;
222
231
return ;
@@ -504,7 +513,7 @@ static RPCHelpMan sendtoaddress()
504
513
// We also enable partial spend avoidance if reuse avoidance is set.
505
514
coin_control.m_avoid_partial_spends |= coin_control.m_avoid_address_reuse ;
506
515
507
- SetFeeEstimateMode (pwallet, coin_control, /* conf_target */ request.params [6 ], /* estimate_mode */ request.params [7 ], /* fee_rate */ request.params [9 ]);
516
+ SetFeeEstimateMode (pwallet, coin_control, /* conf_target */ request.params [6 ], /* estimate_mode */ request.params [7 ], /* fee_rate */ request.params [9 ], /* override_min_fee */ false );
508
517
509
518
EnsureWalletIsUnlocked (pwallet);
510
519
@@ -932,7 +941,7 @@ static RPCHelpMan sendmany()
932
941
coin_control.m_signal_bip125_rbf = request.params [5 ].get_bool ();
933
942
}
934
943
935
- SetFeeEstimateMode (pwallet, coin_control, /* conf_target */ request.params [6 ], /* estimate_mode */ request.params [7 ], /* fee_rate */ request.params [8 ]);
944
+ SetFeeEstimateMode (pwallet, coin_control, /* conf_target */ request.params [6 ], /* estimate_mode */ request.params [7 ], /* fee_rate */ request.params [8 ], /* override_min_fee */ false );
936
945
937
946
std::vector<CRecipient> recipients;
938
947
ParseRecipients (sendTo, subtractFeeFromAmount, recipients);
@@ -3049,7 +3058,7 @@ static RPCHelpMan listunspent()
3049
3058
};
3050
3059
}
3051
3060
3052
- void FundTransaction (CWallet* const pwallet, CMutableTransaction& tx, CAmount& fee_out, int & change_position, const UniValue& options, CCoinControl& coinControl)
3061
+ void FundTransaction (CWallet* const pwallet, CMutableTransaction& tx, CAmount& fee_out, int & change_position, const UniValue& options, CCoinControl& coinControl, bool override_min_fee )
3053
3062
{
3054
3063
// Make sure the results are valid at least up to the most recent block
3055
3064
// the user could have gotten from another RPC command prior to now
@@ -3154,7 +3163,7 @@ void FundTransaction(CWallet* const pwallet, CMutableTransaction& tx, CAmount& f
3154
3163
if (options.exists (" replaceable" )) {
3155
3164
coinControl.m_signal_bip125_rbf = options[" replaceable" ].get_bool ();
3156
3165
}
3157
- SetFeeEstimateMode (pwallet, coinControl, options[" conf_target" ], options[" estimate_mode" ], options[" fee_rate" ]);
3166
+ SetFeeEstimateMode (pwallet, coinControl, options[" conf_target" ], options[" estimate_mode" ], options[" fee_rate" ], override_min_fee );
3158
3167
}
3159
3168
} else {
3160
3169
// if options is null and not a bool
@@ -3275,7 +3284,7 @@ static RPCHelpMan fundrawtransaction()
3275
3284
CCoinControl coin_control;
3276
3285
// Automatically select (additional) coins. Can be overridden by options.add_inputs.
3277
3286
coin_control.m_add_inputs = true ;
3278
- FundTransaction (pwallet, tx, fee, change_position, request.params [1 ], coin_control);
3287
+ FundTransaction (pwallet, tx, fee, change_position, request.params [1 ], coin_control, /* override_min_fee */ true );
3279
3288
3280
3289
UniValue result (UniValue::VOBJ);
3281
3290
result.pushKV (" hex" , EncodeHexTx (CTransaction (tx)));
@@ -3482,7 +3491,7 @@ static RPCHelpMan bumpfee_helper(std::string method_name)
3482
3491
if (options.exists (" replaceable" )) {
3483
3492
coin_control.m_signal_bip125_rbf = options[" replaceable" ].get_bool ();
3484
3493
}
3485
- SetFeeEstimateMode (pwallet, coin_control, conf_target, options[" estimate_mode" ], options[" fee_rate" ]);
3494
+ SetFeeEstimateMode (pwallet, coin_control, conf_target, options[" estimate_mode" ], options[" fee_rate" ], /* override_min_fee */ false );
3486
3495
}
3487
3496
3488
3497
// Make sure the results are valid at least up to the most recent block
@@ -4146,7 +4155,7 @@ static RPCHelpMan send()
4146
4155
// Automatically select coins, unless at least one is manually selected. Can
4147
4156
// be overridden by options.add_inputs.
4148
4157
coin_control.m_add_inputs = rawTx.vin .size () == 0 ;
4149
- FundTransaction (pwallet, rawTx, fee, change_position, options, coin_control);
4158
+ FundTransaction (pwallet, rawTx, fee, change_position, options, coin_control, /* override_min_fee */ false );
4150
4159
4151
4160
bool add_to_wallet = true ;
4152
4161
if (options.exists (" add_to_wallet" )) {
@@ -4433,7 +4442,7 @@ static RPCHelpMan walletcreatefundedpsbt()
4433
4442
// Automatically select coins, unless at least one is manually selected. Can
4434
4443
// be overridden by options.add_inputs.
4435
4444
coin_control.m_add_inputs = rawTx.vin .size () == 0 ;
4436
- FundTransaction (pwallet, rawTx, fee, change_position, request.params [3 ], coin_control);
4445
+ FundTransaction (pwallet, rawTx, fee, change_position, request.params [3 ], coin_control, /* override_min_fee */ true );
4437
4446
4438
4447
// Make a blank psbt
4439
4448
PartiallySignedTransaction psbtx (rawTx);
0 commit comments