aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorfurszy <matiasfurszyfer@protonmail.com>2024-06-19 14:27:35 -0300
committerfurszy <matiasfurszyfer@protonmail.com>2024-06-21 18:13:22 -0300
commit72b226882fe2348a9a66aee1d8d21b4e2d275e68 (patch)
tree89b670577a3b1e5516331cb0e13b758d9d410096
parent2d21060af831fa8f8f1791b4464961d5f28a88cb (diff)
wallet: notify when preset + automatic inputs exceed max weight
This also avoids signing all inputs prior to erroring out.
-rw-r--r--src/wallet/spend.cpp7
-rwxr-xr-xtest/functional/wallet_fundrawtransaction.py33
-rwxr-xr-xtest/functional/wallet_send.py34
3 files changed, 74 insertions, 0 deletions
diff --git a/src/wallet/spend.cpp b/src/wallet/spend.cpp
index 4cbcfdb60f..2fce051f54 100644
--- a/src/wallet/spend.cpp
+++ b/src/wallet/spend.cpp
@@ -799,6 +799,13 @@ util::Result<SelectionResult> SelectCoins(const CWallet& wallet, CoinsResult& av
op_selection_result->RecalculateWaste(coin_selection_params.min_viable_change,
coin_selection_params.m_cost_of_change,
coin_selection_params.m_change_fee);
+
+ // Verify we haven't exceeded the maximum allowed weight
+ int max_inputs_weight = MAX_STANDARD_TX_WEIGHT - (coin_selection_params.tx_noinputs_size * WITNESS_SCALE_FACTOR);
+ if (op_selection_result->GetWeight() > max_inputs_weight) {
+ return util::Error{_("The combination of the pre-selected inputs and the wallet automatic inputs selection exceeds the transaction maximum weight. "
+ "Please try sending a smaller amount or manually consolidating your wallet's UTXOs")};
+ }
}
return op_selection_result;
}
diff --git a/test/functional/wallet_fundrawtransaction.py b/test/functional/wallet_fundrawtransaction.py
index 71c883f166..3c1b2deb1d 100755
--- a/test/functional/wallet_fundrawtransaction.py
+++ b/test/functional/wallet_fundrawtransaction.py
@@ -114,6 +114,7 @@ class RawTransactionsTest(BitcoinTestFramework):
self.test_add_inputs_default_value()
self.test_preset_inputs_selection()
self.test_weight_calculation()
+ self.test_weight_limits()
self.test_change_position()
self.test_simple()
self.test_simple_two_coins()
@@ -1312,6 +1313,38 @@ class RawTransactionsTest(BitcoinTestFramework):
self.nodes[2].unloadwallet("test_weight_calculation")
+ def test_weight_limits(self):
+ self.log.info("Test weight limits")
+
+ self.nodes[2].createwallet("test_weight_limits")
+ wallet = self.nodes[2].get_wallet_rpc("test_weight_limits")
+
+ outputs = []
+ for _ in range(1472):
+ outputs.append({wallet.getnewaddress(address_type="legacy"): 0.1})
+ txid = self.nodes[0].send(outputs=outputs)["txid"]
+ self.generate(self.nodes[0], 1)
+
+ # 272 WU per input (273 when high-s); picking 1471 inputs will exceed the max standard tx weight.
+ rawtx = wallet.createrawtransaction([], [{wallet.getnewaddress(): 0.1 * 1471}])
+
+ # 1) Try to fund transaction only using the preset inputs
+ input_weights = []
+ for i in range(1471):
+ input_weights.append({"txid": txid, "vout": i, "weight": 273})
+ assert_raises_rpc_error(-4, "Transaction too large", wallet.fundrawtransaction, hexstring=rawtx, input_weights=input_weights)
+
+ # 2) Let the wallet fund the transaction
+ assert_raises_rpc_error(-4, "The inputs size exceeds the maximum weight. Please try sending a smaller amount or manually consolidating your wallet's UTXOs",
+ wallet.fundrawtransaction, hexstring=rawtx)
+
+ # 3) Pre-select some inputs and let the wallet fill-up the remaining amount
+ inputs = input_weights[0:1000]
+ assert_raises_rpc_error(-4, "The combination of the pre-selected inputs and the wallet automatic inputs selection exceeds the transaction maximum weight. Please try sending a smaller amount or manually consolidating your wallet's UTXOs",
+ wallet.fundrawtransaction, hexstring=rawtx, input_weights=inputs)
+
+ self.nodes[2].unloadwallet("test_weight_limits")
+
def test_include_unsafe(self):
self.log.info("Test fundrawtxn with unsafe inputs")
diff --git a/test/functional/wallet_send.py b/test/functional/wallet_send.py
index 0a0a8dba0d..bbb0d658d9 100755
--- a/test/functional/wallet_send.py
+++ b/test/functional/wallet_send.py
@@ -577,5 +577,39 @@ class WalletSendTest(BitcoinTestFramework):
# but rounded to nearest integer, it should be the same as the target fee rate
assert_equal(round(actual_fee_rate_sat_vb), target_fee_rate_sat_vb)
+ # Check tx creation size limits
+ self.test_weight_limits()
+
+ def test_weight_limits(self):
+ self.log.info("Test weight limits")
+
+ self.nodes[1].createwallet("test_weight_limits")
+ wallet = self.nodes[1].get_wallet_rpc("test_weight_limits")
+
+ # Generate future inputs; 272 WU per input (273 when high-s).
+ # Picking 1471 inputs will exceed the max standard tx weight.
+ outputs = []
+ for _ in range(1472):
+ outputs.append({wallet.getnewaddress(address_type="legacy"): 0.1})
+ self.nodes[0].send(outputs=outputs)
+ self.generate(self.nodes[0], 1)
+
+ # 1) Try to fund transaction only using the preset inputs
+ inputs = wallet.listunspent()
+ assert_raises_rpc_error(-4, "Transaction too large",
+ wallet.send, outputs=[{wallet.getnewaddress(): 0.1 * 1471}], options={"inputs": inputs, "add_inputs": False})
+
+ # 2) Let the wallet fund the transaction
+ assert_raises_rpc_error(-4, "The inputs size exceeds the maximum weight. Please try sending a smaller amount or manually consolidating your wallet's UTXOs",
+ wallet.send, outputs=[{wallet.getnewaddress(): 0.1 * 1471}])
+
+ # 3) Pre-select some inputs and let the wallet fill-up the remaining amount
+ inputs = inputs[0:1000]
+ assert_raises_rpc_error(-4, "The combination of the pre-selected inputs and the wallet automatic inputs selection exceeds the transaction maximum weight. Please try sending a smaller amount or manually consolidating your wallet's UTXOs",
+ wallet.send, outputs=[{wallet.getnewaddress(): 0.1 * 1471}], options={"inputs": inputs, "add_inputs": True})
+
+ self.nodes[1].unloadwallet("test_weight_limits")
+
+
if __name__ == '__main__':
WalletSendTest().main()