Repository: bitcoin/bitcoin (language: cpp)

Issue:
bump: ignore WALLET_INCREMENTAL_RELAY_FEE when user specifies fee rate
Noticed while testing https://github.com/bitcoin/bitcoin/pull/26467#issuecomment-1401954296.

`WALLET_INCREMENTAL_RELAY_FEE` was introduced in #9615 presumably to account for a situation where the users mempool was less full than that of most peers. Bumping by exactly `DEFAULT_INCREMENTAL_RELAY_FEE` might then cause the bumped transaction to not get relayed.

In addition, because the GUI doesn't let the user specify the new fee rate yet (https://github.com/bitcoin-core/gui/issues/647), it would be very annoying to have to bump 20 times to increment by 20 sat/vbyte.

However, when you use the `bumpfee` RPC and manually specify `fee_rate` this is a needless restriction. 


Discussion / hints:

Fix patch:
diff --git a/src/wallet/feebumper.cpp b/src/wallet/feebumper.cpp
index 6a8453965be71..c65133006f1f3 100644
--- a/src/wallet/feebumper.cpp
+++ b/src/wallet/feebumper.cpp
@@ -92,7 +92,7 @@ static feebumper::Result CheckFeeRate(const CWallet& wallet, const CMutableTrans
     }
     CAmount new_total_fee = newFeerate.GetFee(maxTxSize) + combined_bump_fee.value();
 
-    CFeeRate incrementalRelayFee = std::max(wallet.chain().relayIncrementalFee(), CFeeRate(WALLET_INCREMENTAL_RELAY_FEE));
+    CFeeRate incrementalRelayFee = wallet.chain().relayIncrementalFee();
 
     // Min total fee is old fee + relay fee
     CAmount minTotalFee = old_fee + incrementalRelayFee.GetFee(maxTxSize);


Test patch:
diff --git a/test/functional/wallet_bumpfee.py b/test/functional/wallet_bumpfee.py
index fea933a93b2b8..dd3559f20dddf 100755
--- a/test/functional/wallet_bumpfee.py
+++ b/test/functional/wallet_bumpfee.py
@@ -116,6 +116,7 @@ def run_test(self):
 
         # Context independent tests
         test_feerate_checks_replaced_outputs(self, rbf_node, peer_node)
+        test_bumpfee_with_feerate_ignores_walletincrementalrelayfee(self, rbf_node, peer_node)
 
     def test_invalid_parameters(self, rbf_node, peer_node, dest_address):
         self.log.info('Test invalid parameters')
@@ -815,7 +816,7 @@ def test_feerate_checks_replaced_outputs(self, rbf_node, peer_node):
     # Since the bumped tx will replace all of the outputs with a single output, we can estimate that its size will 31 * (len(outputs) - 1) bytes smaller
     tx_size = tx_details["decoded"]["vsize"]
     est_bumped_size = tx_size - (len(tx_details["decoded"]["vout"]) - 1) * 31
-    inc_fee_rate = max(rbf_node.getmempoolinfo()["incrementalrelayfee"], Decimal(0.00005000)) # Wallet has a fixed incremental relay fee of 5 sat/vb
+    inc_fee_rate = rbf_node.getmempoolinfo()["incrementalrelayfee"]
     # RPC gives us fee as negative
     min_fee = (-tx_details["fee"] + get_fee(est_bumped_size, inc_fee_rate)) * Decimal(1e8)
     min_fee_rate = (min_fee / est_bumped_size).quantize(Decimal("1.000"))
@@ -829,5 +830,27 @@ def test_feerate_checks_replaced_outputs(self, rbf_node, peer_node):
     self.clear_mempool()
 
 
+def test_bumpfee_with_feerate_ignores_walletincrementalrelayfee(self, rbf_node, peer_node):
+    self.log.info('Test that bumpfee with fee_rate ignores walletincrementalrelayfee')
+    # Make sure there is enough balance
+    peer_node.sendtoaddress(rbf_node.getnewaddress(), 2)
+    self.generate(peer_node, 1)
+
+    dest_address = peer_node.getnewaddress(address_type="bech32")
+    tx = rbf_node.send(outputs=[{dest_address: 1}], fee_rate=2)
+
+    # Ensure you can not fee bump with a fee_rate below or equal to the original fee_rate
+    assert_raises_rpc_error(-8, "Insufficient total fee", rbf_node.bumpfee, tx["txid"], {"fee_rate": 1})
+    assert_raises_rpc_error(-8, "Insufficient total fee", rbf_node.bumpfee, tx["txid"], {"fee_rate": 2})
+
+    # Ensure you can not fee bump if the fee_rate is more than original fee_rate but the total fee from new fee_rate is
+    # less than (original fee + incrementalrelayfee)
+    assert_raises_rpc_error(-8, "Insufficient total fee", rbf_node.bumpfee, tx["txid"], {"fee_rate": 2.8})
+
+    # You can fee bump as long as the new fee set from fee_rate is atleast (original fee + incrementalrelayfee)
+    rbf_node.bumpfee(tx["txid"], {"fee_rate": 3})
+    self.clear_mempool()
+
+
 if __name__ == "__main__":
     BumpFeeTest().main()