mirror of
https://github.com/bitcoin/bitcoin.git
synced 2024-11-20 10:38:42 +01:00
Merge bitcoin/bitcoin#30309: wallet: notify when preset + automatic inputs exceed max weight
72b226882f
wallet: notify when preset + automatic inputs exceed max weight (furszy) Pull request description: Small change. Found it while finishing my review on #29523. This does not interfere with it. Basically, we are erroring out early when the automatic coin selection process exceeds the maximum weight, but we are not doing so when the user-preselected inputs combined with the wallet-selected inputs exceed the maximum weight. This change avoids signing all inputs before erroring out and introduces test coverage for `fundrawtransaction`. ACKs for top commit: achow101: ACK72b226882f
tdb3: re ACK for72b226882f
rkrux: tACK [72b2268
](72b226882f
) ismaelsadeeq: utACK72b226882f
Tree-SHA512: d77be19231023383a9c79a5d66b642dcbc6ebfc31a363e0b9f063c44898720a7859ec211cdbc0914ac7a3bfdf15e52fb8fc20d97f171431f70492c0f159dbc36
This commit is contained in:
commit
1d00601b9b
@ -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;
|
||||
}
|
||||
|
@ -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")
|
||||
|
||||
|
@ -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()
|
||||
|
Loading…
Reference in New Issue
Block a user