@@ -2682,8 +2682,8 @@ UniValue bumpfee(const JSONRPCRequest& request)
2682
2682
" By default, the new fee will be calculated automatically using estimatefee.\n "
2683
2683
" The user can specify a confirmation target for estimatefee.\n "
2684
2684
" Alternatively, the user can specify totalFee, or use RPC setpaytxfee to set a higher fee rate.\n "
2685
- " At a minimum, the new fee rate must be high enough to pay a new relay fee (relay fee amount returned \n "
2686
- " by getnetworkinfo RPC) and to enter the node's mempool.\n "
2685
+ " At a minimum, the new fee rate must be high enough to pay an additional new relay fee (incrementalfee \n "
2686
+ " returned by getnetworkinfo) to enter the node's mempool.\n "
2687
2687
" \n Arguments:\n "
2688
2688
" 1. txid (string, required) The txid to be bumped\n "
2689
2689
" 2. options (object, optional)\n "
@@ -2704,8 +2704,8 @@ UniValue bumpfee(const JSONRPCRequest& request)
2704
2704
" \n Result:\n "
2705
2705
" {\n "
2706
2706
" \" txid\" : \" value\" , (string) The id of the new transaction\n "
2707
- " \" oldfee \" : n, (numeric) Fee of the replaced transaction\n "
2708
- " \" fee\" : n, (numeric) Fee of the new transaction\n "
2707
+ " \" origfee \" : n, (numeric) Fee of the replaced transaction\n "
2708
+ " \" fee\" : n, (numeric) Fee of the new transaction\n "
2709
2709
" }\n "
2710
2710
" \n Examples:\n "
2711
2711
" \n Bump the fee, get the new transaction\' s txid\n " +
@@ -2769,6 +2769,10 @@ UniValue bumpfee(const JSONRPCRequest& request)
2769
2769
throw JSONRPCError (RPC_MISC_ERROR, " Transaction does not have a change output" );
2770
2770
}
2771
2771
2772
+ // signature sizes can vary by a byte, so add 1 for each input when calculating the new fee
2773
+ int64_t txSize = GetVirtualTransactionSize (*(wtx.tx ));
2774
+ const int64_t maxNewTxSize = txSize + wtx.tx ->vin .size ();
2775
+
2772
2776
// optional parameters
2773
2777
bool specifiedConfirmTarget = false ;
2774
2778
int newConfirmTarget = nTxConfirmTarget;
@@ -2794,10 +2798,11 @@ UniValue bumpfee(const JSONRPCRequest& request)
2794
2798
}
2795
2799
} else if (options.exists (" totalFee" )) {
2796
2800
totalFee = options[" totalFee" ].get_int64 ();
2797
- if (totalFee <= 0 ) {
2798
- throw JSONRPCError (RPC_INVALID_PARAMETER, " Invalid totalFee (cannot be <= 0)" );
2799
- } else if (totalFee > maxTxFee) {
2800
- throw JSONRPCError (RPC_INVALID_PARAMETER, " Invalid totalFee (cannot be higher than maxTxFee)" );
2801
+ CAmount requiredFee = CWallet::GetRequiredFee (maxNewTxSize);
2802
+ if (totalFee < requiredFee ) {
2803
+ throw JSONRPCError (RPC_INVALID_PARAMETER,
2804
+ strprintf (" Insufficient totalFee (cannot be less than required fee %s)" ,
2805
+ FormatMoney (requiredFee)));
2801
2806
}
2802
2807
}
2803
2808
@@ -2806,42 +2811,53 @@ UniValue bumpfee(const JSONRPCRequest& request)
2806
2811
}
2807
2812
}
2808
2813
2809
- // signature sizes can vary by a byte, so add 1 for each input when calculating the new fee
2810
- int64_t txSize = GetVirtualTransactionSize (*(wtx.tx ));
2811
- const int64_t maxNewTxSize = txSize + wtx.tx ->vin .size ();
2812
-
2813
2814
// calculate the old fee and fee-rate
2814
2815
CAmount nOldFee = wtx.GetDebit (ISMINE_SPENDABLE) - wtx.tx ->GetValueOut ();
2815
2816
CFeeRate nOldFeeRate (nOldFee, txSize);
2816
2817
CAmount nNewFee;
2817
2818
CFeeRate nNewFeeRate;
2819
+ // The wallet uses a conservative WALLET_INCREMENTAL_RELAY_FEE value to
2820
+ // future proof against changes to network wide policy for incremental relay
2821
+ // fee that our node may not be aware of.
2822
+ CFeeRate walletIncrementalRelayFee = CFeeRate (WALLET_INCREMENTAL_RELAY_FEE);
2823
+ if (::incrementalRelayFee > walletIncrementalRelayFee) {
2824
+ walletIncrementalRelayFee = ::incrementalRelayFee;
2825
+ }
2818
2826
2819
2827
if (totalFee > 0 ) {
2820
- CAmount minTotalFee = nOldFeeRate.GetFee (maxNewTxSize) + minRelayTxFee .GetFee (maxNewTxSize);
2828
+ CAmount minTotalFee = nOldFeeRate.GetFee (maxNewTxSize) + ::incrementalRelayFee .GetFee (maxNewTxSize);
2821
2829
if (totalFee < minTotalFee) {
2822
- throw JSONRPCError (RPC_INVALID_PARAMETER, strprintf (" Invalid totalFee, must be at least %s (oldFee %s + relayFee %s)" , FormatMoney (minTotalFee), nOldFeeRate.GetFee (maxNewTxSize), minRelayTxFee.GetFee (maxNewTxSize)));
2830
+ throw JSONRPCError (RPC_INVALID_PARAMETER, strprintf (" Insufficient totalFee, must be at least %s (oldFee %s + incrementalFee %s)" ,
2831
+ FormatMoney (minTotalFee), FormatMoney (nOldFeeRate.GetFee (maxNewTxSize)), FormatMoney (::incrementalRelayFee.GetFee (maxNewTxSize))));
2823
2832
}
2824
2833
nNewFee = totalFee;
2825
2834
nNewFeeRate = CFeeRate (totalFee, maxNewTxSize);
2826
2835
} else {
2827
- // use the user-defined payTxFee if possible, otherwise use smartfee / fallbackfee
2828
- if (!specifiedConfirmTarget && payTxFee.GetFeePerK () != 0 ) {
2829
- nNewFeeRate = payTxFee;
2830
- } else {
2831
- nNewFeeRate = mempool.estimateSmartFee (newConfirmTarget);
2836
+ // if user specified a confirm target then don't consider any global payTxFee
2837
+ if (specifiedConfirmTarget) {
2838
+ nNewFee = CWallet::GetMinimumFee (maxNewTxSize, newConfirmTarget, mempool, CAmount (0 ));
2832
2839
}
2833
- if (nNewFeeRate.GetFeePerK () == 0 ) {
2834
- nNewFeeRate = CWallet::fallbackFee;
2840
+ // otherwise use the regular wallet logic to select payTxFee or default confirm target
2841
+ else {
2842
+ nNewFee = CWallet::GetMinimumFee (maxNewTxSize, newConfirmTarget, mempool);
2835
2843
}
2836
2844
2837
- // new fee rate must be at least old rate + minimum relay rate
2838
- if (nNewFeeRate.GetFeePerK () < nOldFeeRate.GetFeePerK () + ::minRelayTxFee.GetFeePerK ()) {
2839
- nNewFeeRate = CFeeRate (nOldFeeRate.GetFeePerK () + ::minRelayTxFee.GetFeePerK ());
2840
- }
2845
+ nNewFeeRate = CFeeRate (nNewFee, maxNewTxSize);
2841
2846
2842
- nNewFee = nNewFeeRate.GetFee (maxNewTxSize);
2847
+ // New fee rate must be at least old rate + minimum incremental relay rate
2848
+ if (nNewFeeRate.GetFeePerK () < nOldFeeRate.GetFeePerK () + walletIncrementalRelayFee.GetFeePerK ()) {
2849
+ nNewFeeRate = CFeeRate (nOldFeeRate.GetFeePerK () + walletIncrementalRelayFee.GetFeePerK ());
2850
+ nNewFee = nNewFeeRate.GetFee (maxNewTxSize);
2851
+ }
2843
2852
}
2844
2853
2854
+ // Check that in all cases the new fee doesn't violate maxTxFee
2855
+ if (nNewFee > maxTxFee) {
2856
+ throw JSONRPCError (RPC_MISC_ERROR,
2857
+ strprintf (" Specified or calculated fee %s is too high (cannot be higher than maxTxFee %s)" ,
2858
+ FormatMoney (nNewFee), FormatMoney (maxTxFee)));
2859
+ }
2860
+
2845
2861
// check that fee rate is higher than mempool's minimum fee
2846
2862
// (no point in bumping fee if we know that the new tx won't be accepted to the mempool)
2847
2863
// This may occur if the user set TotalFee or paytxfee too low, if fallbackfee is too low, or, perhaps,
@@ -2864,7 +2880,7 @@ UniValue bumpfee(const JSONRPCRequest& request)
2864
2880
2865
2881
// If the output would become dust, discard it (converting the dust to fee)
2866
2882
poutput->nValue -= nDelta;
2867
- if (poutput->nValue <= poutput->GetDustThreshold (::minRelayTxFee )) {
2883
+ if (poutput->nValue <= poutput->GetDustThreshold (::dustRelayFee )) {
2868
2884
LogPrint (" rpc" , " Bumping fee and discarding dust output\n " );
2869
2885
nNewFee += poutput->nValue ;
2870
2886
tx.vout .erase (tx.vout .begin () + nOutput);
@@ -2913,7 +2929,7 @@ UniValue bumpfee(const JSONRPCRequest& request)
2913
2929
2914
2930
UniValue result (UniValue::VOBJ);
2915
2931
result.push_back (Pair (" txid" , wtxBumped.GetHash ().GetHex ()));
2916
- result.push_back (Pair (" oldfee " , ValueFromAmount (nOldFee)));
2932
+ result.push_back (Pair (" origfee " , ValueFromAmount (nOldFee)));
2917
2933
result.push_back (Pair (" fee" , ValueFromAmount (nNewFee)));
2918
2934
2919
2935
return result;
0 commit comments