Skip to content

Commit 900e5ed

Browse files
committed
wallet: introduce "tx amount exceeds balance when fees are included" error
This was previously implemented at the GUI level but has been broken since #20640
1 parent a786fd2 commit 900e5ed

File tree

2 files changed

+31
-2
lines changed

2 files changed

+31
-2
lines changed

src/wallet/spend.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1131,7 +1131,19 @@ static util::Result<CreatedTransactionResult> CreateTransactionInternal(
11311131
if (!select_coins_res) {
11321132
// 'SelectCoins' either returns a specific error message or, if empty, means a general "Insufficient funds".
11331133
const bilingual_str& err = util::ErrorString(select_coins_res);
1134-
return util::Error{err.empty() ?_("Insufficient funds") : err};
1134+
if (!err.empty()) return util::Error{err};
1135+
1136+
// Check if we have enough balance but cannot cover the fees
1137+
CAmount available_balance = preset_inputs.total_amount + available_coins.GetTotalAmount();
1138+
if (available_balance >= recipients_sum) {
1139+
CAmount available_effective_balance = preset_inputs.total_amount + available_coins.GetEffectiveTotalAmount().value_or(available_coins.GetTotalAmount());
1140+
if (available_effective_balance < selection_target) {
1141+
return util::Error{_("The total transaction amount exceeds your balance when fees are included")};
1142+
}
1143+
}
1144+
1145+
// General failure description
1146+
return util::Error{_("Insufficient funds")};
11351147
}
11361148
const SelectionResult& result = *select_coins_res;
11371149
TRACE5(coin_selection, selected_coins,

test/functional/wallet_fundrawtransaction.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,7 @@ def run_test(self):
150150
self.test_feerate_rounding()
151151
self.test_input_confs_control()
152152
self.test_duplicate_outputs()
153+
self.test_cannot_cover_fees()
153154

154155
def test_duplicate_outputs(self):
155156
self.log.info("Test deserializing and funding a transaction with duplicate outputs")
@@ -1426,7 +1427,8 @@ def test_feerate_rounding(self):
14261427
# To test this does not happen, we subtract 202 sats from the input value. If working correctly, this should
14271428
# fail with insufficient funds rather than bitcoind asserting.
14281429
rawtx = w.createrawtransaction(inputs=[], outputs=[{self.nodes[0].getnewaddress(address_type="bech32"): 1 - 0.00000202}])
1429-
assert_raises_rpc_error(-4, "Insufficient funds", w.fundrawtransaction, rawtx, fee_rate=1.85)
1430+
expected_err_msg = "The total transaction amount exceeds your balance when fees are included"
1431+
assert_raises_rpc_error(-4, expected_err_msg, w.fundrawtransaction, rawtx, fee_rate=1.85)
14301432

14311433
def test_input_confs_control(self):
14321434
self.nodes[0].createwallet("minconf")
@@ -1489,5 +1491,20 @@ def test_input_confs_control(self):
14891491

14901492
wallet.unloadwallet()
14911493

1494+
def test_cannot_cover_fees(self):
1495+
self.log.info("Test tx amount exceeds available balance when fees are included")
1496+
1497+
self.nodes[1].createwallet("cannot_cover_fees")
1498+
wallet = self.nodes[1].get_wallet_rpc("cannot_cover_fees")
1499+
1500+
self.nodes[0].sendtoaddress(wallet.getnewaddress(), 0.3)
1501+
self.generate(self.nodes[0], 1)
1502+
1503+
rawtx = wallet.createrawtransaction(inputs=[], outputs=[{self.nodes[0].getnewaddress(): 0.3}])
1504+
expected_err_msg = "The total transaction amount exceeds your balance when fees are included"
1505+
assert_raises_rpc_error(-4, expected_err_msg, wallet.fundrawtransaction, rawtx)
1506+
wallet.unloadwallet()
1507+
1508+
14921509
if __name__ == '__main__':
14931510
RawTransactionsTest().main()

0 commit comments

Comments
 (0)