Skip to content

Commit fc642c3

Browse files
committedSep 30, 2024
Merge bitcoin#30718: test: switch MiniWallet padding unit from weight to vsize
940edd6 test: refactor: introduce and use `TRUC_CHILD_MAX_VSIZE` constant (Sebastian Falbesoner) c16ae71 test: switch MiniWallet padding unit from weight to vsize (Sebastian Falbesoner) Pull request description: This PR is a late follow-up for bitcoin#30162, where I retrospectively consider the padding unit of choice as a mistake. The weight unit is merely a consensus rule detail and is largely irrelevant from a user's perspective w.r.t. fee-rate calculations and mempool policy rules (e.g. for package relay and TRUC limits), so there doesn't seem to be any value of using a granularity that we can't even guarantee to reach exactly anyway. Switch to the more natural unit of vsize instead, which simplifies both the padding implementation (no "round up to the next multiple of 4" anymore) and the current tests that take use of this padding. The rather annoying multiplications by `WITNESS_SCALE_FACTOR` can then be removed and weird-looking magic numbers like `4004` can be replaced by numbers that are more connected to actual policy limit constants from the codebase, e.g. `1001` for exceeding `TRUC_CHILD_MAX_VSIZE` by one. The second commits introduces a constant for that. ACKs for top commit: glozow: reACK 940edd6 via range-diff instagibbs: reACK 940edd6 maflcko: re-ACK 940edd6 🍷 achow101: ACK 940edd6 Tree-SHA512: 35325f22bbe548664273051b705059b8f2f4316215be116c71b8c21dc87d190b3e8fcc4a48f04deaba2f3632a9c809d272b0bae654cf74d7492759554c0f0d14
2 parents d7f956a + 940edd6 commit fc642c3

6 files changed

+69
-78
lines changed
 

‎test/functional/feature_blocksxor.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ def run_test(self):
3131
node = self.nodes[0]
3232
wallet = MiniWallet(node)
3333
for _ in range(5):
34-
wallet.send_self_transfer(from_node=node, target_weight=80000)
34+
wallet.send_self_transfer(from_node=node, target_vsize=20000)
3535
self.generate(wallet, 1)
3636

3737
block_files = list(node.blocks_path.glob('blk[0-9][0-9][0-9][0-9][0-9].dat'))

‎test/functional/feature_framework_miniwallet.py

+7-9
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from test_framework.blocktools import COINBASE_MATURITY
1010
from test_framework.test_framework import BitcoinTestFramework
1111
from test_framework.util import (
12-
assert_greater_than_or_equal,
12+
assert_equal,
1313
)
1414
from test_framework.wallet import (
1515
MiniWallet,
@@ -22,17 +22,15 @@ def set_test_params(self):
2222
self.num_nodes = 1
2323

2424
def test_tx_padding(self):
25-
"""Verify that MiniWallet's transaction padding (`target_weight` parameter)
26-
works accurately enough (i.e. at most 3 WUs higher) with all modes."""
25+
"""Verify that MiniWallet's transaction padding (`target_vsize` parameter)
26+
works accurately with all modes."""
2727
for mode_name, wallet in self.wallets:
2828
self.log.info(f"Test tx padding with MiniWallet mode {mode_name}...")
2929
utxo = wallet.get_utxo(mark_as_spent=False)
30-
for target_weight in [1000, 2000, 5000, 10000, 20000, 50000, 100000, 200000, 4000000,
31-
989, 2001, 4337, 13371, 23219, 49153, 102035, 223419, 3999989]:
32-
tx = wallet.create_self_transfer(utxo_to_spend=utxo, target_weight=target_weight)["tx"]
33-
self.log.debug(f"-> target weight: {target_weight}, actual weight: {tx.get_weight()}")
34-
assert_greater_than_or_equal(tx.get_weight(), target_weight)
35-
assert_greater_than_or_equal(target_weight + 3, tx.get_weight())
30+
for target_vsize in [250, 500, 1250, 2500, 5000, 12500, 25000, 50000, 1000000,
31+
248, 501, 1085, 3343, 5805, 12289, 25509, 55855, 999998]:
32+
tx = wallet.create_self_transfer(utxo_to_spend=utxo, target_vsize=target_vsize)["tx"]
33+
assert_equal(tx.get_vsize(), target_vsize)
3634

3735
def test_wallet_tagging(self):
3836
"""Verify that tagged wallet instances are able to send funds."""

‎test/functional/mempool_limit.py

+17-14
Original file line numberDiff line numberDiff line change
@@ -55,28 +55,28 @@ def test_rbf_carveout_disallowed(self):
5555
self.generate(node, 1)
5656

5757
# tx_A needs to be RBF'd, set minfee at set size
58-
A_weight = 1000
58+
A_vsize = 250
5959
mempoolmin_feerate = node.getmempoolinfo()["mempoolminfee"]
6060
tx_A = self.wallet.send_self_transfer(
6161
from_node=node,
6262
fee_rate=mempoolmin_feerate,
63-
target_weight=A_weight,
63+
target_vsize=A_vsize,
6464
utxo_to_spend=rbf_utxo,
6565
confirmed_only=True
6666
)
6767

6868
# RBF's tx_A, is not yet submitted
6969
tx_B = self.wallet.create_self_transfer(
7070
fee=tx_A["fee"] * 4,
71-
target_weight=A_weight,
71+
target_vsize=A_vsize,
7272
utxo_to_spend=rbf_utxo,
7373
confirmed_only=True
7474
)
7575

7676
# Spends tx_B's output, too big for cpfp carveout (because that would also increase the descendant limit by 1)
77-
non_cpfp_carveout_weight = 40001 # EXTRA_DESCENDANT_TX_SIZE_LIMIT + 1
77+
non_cpfp_carveout_vsize = 10001 # EXTRA_DESCENDANT_TX_SIZE_LIMIT + 1
7878
tx_C = self.wallet.create_self_transfer(
79-
target_weight=non_cpfp_carveout_weight,
79+
target_vsize=non_cpfp_carveout_vsize,
8080
fee_rate=mempoolmin_feerate,
8181
utxo_to_spend=tx_B["new_utxo"],
8282
confirmed_only=True
@@ -103,14 +103,14 @@ def test_mid_package_eviction(self):
103103
# UTXOs to be spent by the ultimate child transaction
104104
parent_utxos = []
105105

106-
evicted_weight = 8000
106+
evicted_vsize = 2000
107107
# Mempool transaction which is evicted due to being at the "bottom" of the mempool when the
108108
# mempool overflows and evicts by descendant score. It's important that the eviction doesn't
109109
# happen in the middle of package evaluation, as it can invalidate the coins cache.
110110
mempool_evicted_tx = self.wallet.send_self_transfer(
111111
from_node=node,
112112
fee_rate=mempoolmin_feerate,
113-
target_weight=evicted_weight,
113+
target_vsize=evicted_vsize,
114114
confirmed_only=True
115115
)
116116
# Already in mempool when package is submitted.
@@ -132,14 +132,16 @@ def test_mid_package_eviction(self):
132132

133133
# Series of parents that don't need CPFP and are submitted individually. Each one is large and
134134
# high feerate, which means they should trigger eviction but not be evicted.
135-
parent_weight = 100000
135+
parent_vsize = 25000
136136
num_big_parents = 3
137-
assert_greater_than(parent_weight * num_big_parents, current_info["maxmempool"] - current_info["bytes"])
137+
# Need to be large enough to trigger eviction
138+
# (note that the mempool usage of a tx is about three times its vsize)
139+
assert_greater_than(parent_vsize * num_big_parents * 3, current_info["maxmempool"] - current_info["bytes"])
138140
parent_feerate = 100 * mempoolmin_feerate
139141

140142
big_parent_txids = []
141143
for i in range(num_big_parents):
142-
parent = self.wallet.create_self_transfer(fee_rate=parent_feerate, target_weight=parent_weight, confirmed_only=True)
144+
parent = self.wallet.create_self_transfer(fee_rate=parent_feerate, target_vsize=parent_vsize, confirmed_only=True)
143145
parent_utxos.append(parent["new_utxo"])
144146
package_hex.append(parent["hex"])
145147
big_parent_txids.append(parent["txid"])
@@ -311,17 +313,18 @@ def run_test(self):
311313
entry = node.getmempoolentry(txid)
312314
worst_feerate_btcvb = min(worst_feerate_btcvb, entry["fees"]["descendant"] / entry["descendantsize"])
313315
# Needs to be large enough to trigger eviction
314-
target_weight_each = 200000
315-
assert_greater_than(target_weight_each * 2, node.getmempoolinfo()["maxmempool"] - node.getmempoolinfo()["bytes"])
316+
# (note that the mempool usage of a tx is about three times its vsize)
317+
target_vsize_each = 50000
318+
assert_greater_than(target_vsize_each * 2 * 3, node.getmempoolinfo()["maxmempool"] - node.getmempoolinfo()["bytes"])
316319
# Should be a true CPFP: parent's feerate is just below mempool min feerate
317320
parent_feerate = mempoolmin_feerate - Decimal("0.000001") # 0.1 sats/vbyte below min feerate
318321
# Parent + child is above mempool minimum feerate
319322
child_feerate = (worst_feerate_btcvb * 1000) - Decimal("0.000001") # 0.1 sats/vbyte below worst feerate
320323
# However, when eviction is triggered, these transactions should be at the bottom.
321324
# This assertion assumes parent and child are the same size.
322325
miniwallet.rescan_utxos()
323-
tx_parent_just_below = miniwallet.create_self_transfer(fee_rate=parent_feerate, target_weight=target_weight_each)
324-
tx_child_just_above = miniwallet.create_self_transfer(utxo_to_spend=tx_parent_just_below["new_utxo"], fee_rate=child_feerate, target_weight=target_weight_each)
326+
tx_parent_just_below = miniwallet.create_self_transfer(fee_rate=parent_feerate, target_vsize=target_vsize_each)
327+
tx_child_just_above = miniwallet.create_self_transfer(utxo_to_spend=tx_parent_just_below["new_utxo"], fee_rate=child_feerate, target_vsize=target_vsize_each)
325328
# This package ranks below the lowest descendant package in the mempool
326329
package_fee = tx_parent_just_below["fee"] + tx_child_just_above["fee"]
327330
package_vsize = tx_parent_just_below["tx"].get_vsize() + tx_child_just_above["tx"].get_vsize()

‎test/functional/mempool_package_limits.py

+6-11
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,6 @@
44
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
55
"""Test logic for limiting mempool and package ancestors/descendants."""
66
from test_framework.blocktools import COINBASE_MATURITY
7-
from test_framework.messages import (
8-
WITNESS_SCALE_FACTOR,
9-
)
107
from test_framework.test_framework import BitcoinTestFramework
118
from test_framework.util import (
129
assert_equal,
@@ -290,19 +287,18 @@ def test_anc_size_limits(self):
290287
parent_utxos = []
291288
target_vsize = 30_000
292289
high_fee = 10 * target_vsize # 10 sats/vB
293-
target_weight = target_vsize * WITNESS_SCALE_FACTOR
294290
self.log.info("Check that in-mempool and in-package ancestor size limits are calculated properly in packages")
295291
# Mempool transactions A and B
296292
for _ in range(2):
297-
bulked_tx = self.wallet.create_self_transfer(target_weight=target_weight)
293+
bulked_tx = self.wallet.create_self_transfer(target_vsize=target_vsize)
298294
self.wallet.sendrawtransaction(from_node=node, tx_hex=bulked_tx["hex"])
299295
parent_utxos.append(bulked_tx["new_utxo"])
300296

301297
# Package transaction C
302-
pc_tx = self.wallet.create_self_transfer_multi(utxos_to_spend=parent_utxos, fee_per_output=high_fee, target_weight=target_weight)
298+
pc_tx = self.wallet.create_self_transfer_multi(utxos_to_spend=parent_utxos, fee_per_output=high_fee, target_vsize=target_vsize)
303299

304300
# Package transaction D
305-
pd_tx = self.wallet.create_self_transfer(utxo_to_spend=pc_tx["new_utxos"][0], target_weight=target_weight)
301+
pd_tx = self.wallet.create_self_transfer(utxo_to_spend=pc_tx["new_utxos"][0], target_vsize=target_vsize)
306302

307303
assert_equal(2, node.getmempoolinfo()["size"])
308304
return [pc_tx["hex"], pd_tx["hex"]]
@@ -321,20 +317,19 @@ def test_desc_size_limits(self):
321317
node = self.nodes[0]
322318
target_vsize = 21_000
323319
high_fee = 10 * target_vsize # 10 sats/vB
324-
target_weight = target_vsize * WITNESS_SCALE_FACTOR
325320
self.log.info("Check that in-mempool and in-package descendant sizes are calculated properly in packages")
326321
# Top parent in mempool, Ma
327-
ma_tx = self.wallet.create_self_transfer_multi(num_outputs=2, fee_per_output=high_fee // 2, target_weight=target_weight)
322+
ma_tx = self.wallet.create_self_transfer_multi(num_outputs=2, fee_per_output=high_fee // 2, target_vsize=target_vsize)
328323
self.wallet.sendrawtransaction(from_node=node, tx_hex=ma_tx["hex"])
329324

330325
package_hex = []
331326
for j in range(2): # Two legs (left and right)
332327
# Mempool transaction (Mb and Mc)
333-
mempool_tx = self.wallet.create_self_transfer(utxo_to_spend=ma_tx["new_utxos"][j], target_weight=target_weight)
328+
mempool_tx = self.wallet.create_self_transfer(utxo_to_spend=ma_tx["new_utxos"][j], target_vsize=target_vsize)
334329
self.wallet.sendrawtransaction(from_node=node, tx_hex=mempool_tx["hex"])
335330

336331
# Package transaction (Pd and Pe)
337-
package_tx = self.wallet.create_self_transfer(utxo_to_spend=mempool_tx["new_utxo"], target_weight=target_weight)
332+
package_tx = self.wallet.create_self_transfer(utxo_to_spend=mempool_tx["new_utxo"], target_vsize=target_vsize)
338333
package_hex.append(package_tx["hex"])
339334

340335
assert_equal(3, node.getmempoolinfo()["size"])

‎test/functional/mempool_truc.py

+25-24
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
from test_framework.messages import (
88
MAX_BIP125_RBF_SEQUENCE,
9-
WITNESS_SCALE_FACTOR,
109
)
1110
from test_framework.test_framework import BitcoinTestFramework
1211
from test_framework.util import (
@@ -23,6 +22,7 @@
2322

2423
MAX_REPLACEMENT_CANDIDATES = 100
2524
TRUC_MAX_VSIZE = 10000
25+
TRUC_CHILD_MAX_VSIZE = 1000
2626

2727
def cleanup(extra_args=None):
2828
def decorator(func):
@@ -55,14 +55,14 @@ def check_mempool(self, txids):
5555
def test_truc_max_vsize(self):
5656
node = self.nodes[0]
5757
self.log.info("Test TRUC-specific maximum transaction vsize")
58-
tx_v3_heavy = self.wallet.create_self_transfer(target_weight=(TRUC_MAX_VSIZE + 1) * WITNESS_SCALE_FACTOR, version=3)
58+
tx_v3_heavy = self.wallet.create_self_transfer(target_vsize=TRUC_MAX_VSIZE + 1, version=3)
5959
assert_greater_than_or_equal(tx_v3_heavy["tx"].get_vsize(), TRUC_MAX_VSIZE)
6060
expected_error_heavy = f"TRUC-violation, version=3 tx {tx_v3_heavy['txid']} (wtxid={tx_v3_heavy['wtxid']}) is too big"
6161
assert_raises_rpc_error(-26, expected_error_heavy, node.sendrawtransaction, tx_v3_heavy["hex"])
6262
self.check_mempool([])
6363

6464
# Ensure we are hitting the TRUC-specific limit and not something else
65-
tx_v2_heavy = self.wallet.send_self_transfer(from_node=node, target_weight=(TRUC_MAX_VSIZE + 1) * WITNESS_SCALE_FACTOR, version=2)
65+
tx_v2_heavy = self.wallet.send_self_transfer(from_node=node, target_vsize=TRUC_MAX_VSIZE + 1, version=2)
6666
self.check_mempool([tx_v2_heavy["txid"]])
6767

6868
@cleanup(extra_args=["-datacarriersize=1000"])
@@ -73,10 +73,10 @@ def test_truc_acceptance(self):
7373
self.check_mempool([tx_v3_parent_normal["txid"]])
7474
tx_v3_child_heavy = self.wallet.create_self_transfer(
7575
utxo_to_spend=tx_v3_parent_normal["new_utxo"],
76-
target_weight=4004,
76+
target_vsize=TRUC_CHILD_MAX_VSIZE + 1,
7777
version=3
7878
)
79-
assert_greater_than_or_equal(tx_v3_child_heavy["tx"].get_vsize(), 1000)
79+
assert_greater_than_or_equal(tx_v3_child_heavy["tx"].get_vsize(), TRUC_CHILD_MAX_VSIZE)
8080
expected_error_child_heavy = f"TRUC-violation, version=3 child tx {tx_v3_child_heavy['txid']} (wtxid={tx_v3_child_heavy['wtxid']}) is too big"
8181
assert_raises_rpc_error(-26, expected_error_child_heavy, node.sendrawtransaction, tx_v3_child_heavy["hex"])
8282
self.check_mempool([tx_v3_parent_normal["txid"]])
@@ -88,20 +88,21 @@ def test_truc_acceptance(self):
8888
from_node=node,
8989
fee_rate=DEFAULT_FEE,
9090
utxo_to_spend=tx_v3_parent_normal["new_utxo"],
91-
target_weight=3987,
91+
target_vsize=TRUC_CHILD_MAX_VSIZE - 3,
9292
version=3
9393
)
94-
assert_greater_than_or_equal(1000, tx_v3_child_almost_heavy["tx"].get_vsize())
94+
assert_greater_than_or_equal(TRUC_CHILD_MAX_VSIZE, tx_v3_child_almost_heavy["tx"].get_vsize())
9595
self.check_mempool([tx_v3_parent_normal["txid"], tx_v3_child_almost_heavy["txid"]])
9696
assert_equal(node.getmempoolentry(tx_v3_parent_normal["txid"])["descendantcount"], 2)
9797
tx_v3_child_almost_heavy_rbf = self.wallet.send_self_transfer(
9898
from_node=node,
9999
fee_rate=DEFAULT_FEE * 2,
100100
utxo_to_spend=tx_v3_parent_normal["new_utxo"],
101-
target_weight=3500,
101+
target_vsize=875,
102102
version=3
103103
)
104-
assert_greater_than_or_equal(tx_v3_child_almost_heavy["tx"].get_vsize() + tx_v3_child_almost_heavy_rbf["tx"].get_vsize(), 1000)
104+
assert_greater_than_or_equal(tx_v3_child_almost_heavy["tx"].get_vsize() + tx_v3_child_almost_heavy_rbf["tx"].get_vsize(),
105+
TRUC_CHILD_MAX_VSIZE)
105106
self.check_mempool([tx_v3_parent_normal["txid"], tx_v3_child_almost_heavy_rbf["txid"]])
106107
assert_equal(node.getmempoolentry(tx_v3_parent_normal["txid"])["descendantcount"], 2)
107108

@@ -199,8 +200,8 @@ def test_truc_reorg(self):
199200
self.check_mempool([])
200201
tx_v2_from_v3 = self.wallet.send_self_transfer(from_node=node, utxo_to_spend=tx_v3_block["new_utxo"], version=2)
201202
tx_v3_from_v2 = self.wallet.send_self_transfer(from_node=node, utxo_to_spend=tx_v2_block["new_utxo"], version=3)
202-
tx_v3_child_large = self.wallet.send_self_transfer(from_node=node, utxo_to_spend=tx_v3_block2["new_utxo"], target_weight=5000, version=3)
203-
assert_greater_than(node.getmempoolentry(tx_v3_child_large["txid"])["vsize"], 1000)
203+
tx_v3_child_large = self.wallet.send_self_transfer(from_node=node, utxo_to_spend=tx_v3_block2["new_utxo"], target_vsize=1250, version=3)
204+
assert_greater_than(node.getmempoolentry(tx_v3_child_large["txid"])["vsize"], TRUC_CHILD_MAX_VSIZE)
204205
self.check_mempool([tx_v2_from_v3["txid"], tx_v3_from_v2["txid"], tx_v3_child_large["txid"]])
205206
node.invalidateblock(block[0])
206207
self.check_mempool([tx_v3_block["txid"], tx_v2_block["txid"], tx_v3_block2["txid"], tx_v2_from_v3["txid"], tx_v3_from_v2["txid"], tx_v3_child_large["txid"]])
@@ -217,22 +218,22 @@ def test_nondefault_package_limits(self):
217218
"""
218219
node = self.nodes[0]
219220
self.log.info("Test that a decreased limitdescendantsize also applies to TRUC child")
220-
parent_target_weight = 9990 * WITNESS_SCALE_FACTOR
221-
child_target_weight = 500 * WITNESS_SCALE_FACTOR
221+
parent_target_vsize = 9990
222+
child_target_vsize = 500
222223
tx_v3_parent_large1 = self.wallet.send_self_transfer(
223224
from_node=node,
224-
target_weight=parent_target_weight,
225+
target_vsize=parent_target_vsize,
225226
version=3
226227
)
227228
tx_v3_child_large1 = self.wallet.create_self_transfer(
228229
utxo_to_spend=tx_v3_parent_large1["new_utxo"],
229-
target_weight=child_target_weight,
230+
target_vsize=child_target_vsize,
230231
version=3
231232
)
232233

233234
# Parent and child are within v3 limits, but parent's 10kvB descendant limit is exceeded
234235
assert_greater_than_or_equal(TRUC_MAX_VSIZE, tx_v3_parent_large1["tx"].get_vsize())
235-
assert_greater_than_or_equal(1000, tx_v3_child_large1["tx"].get_vsize())
236+
assert_greater_than_or_equal(TRUC_CHILD_MAX_VSIZE, tx_v3_child_large1["tx"].get_vsize())
236237
assert_greater_than(tx_v3_parent_large1["tx"].get_vsize() + tx_v3_child_large1["tx"].get_vsize(), 10000)
237238

238239
assert_raises_rpc_error(-26, f"too-long-mempool-chain, exceeds descendant size limit for tx {tx_v3_parent_large1['txid']}", node.sendrawtransaction, tx_v3_child_large1["hex"])
@@ -244,18 +245,18 @@ def test_nondefault_package_limits(self):
244245
self.restart_node(0, extra_args=["-limitancestorsize=10", "-datacarriersize=40000"])
245246
tx_v3_parent_large2 = self.wallet.send_self_transfer(
246247
from_node=node,
247-
target_weight=parent_target_weight,
248+
target_vsize=parent_target_vsize,
248249
version=3
249250
)
250251
tx_v3_child_large2 = self.wallet.create_self_transfer(
251252
utxo_to_spend=tx_v3_parent_large2["new_utxo"],
252-
target_weight=child_target_weight,
253+
target_vsize=child_target_vsize,
253254
version=3
254255
)
255256

256257
# Parent and child are within TRUC limits
257258
assert_greater_than_or_equal(TRUC_MAX_VSIZE, tx_v3_parent_large2["tx"].get_vsize())
258-
assert_greater_than_or_equal(1000, tx_v3_child_large2["tx"].get_vsize())
259+
assert_greater_than_or_equal(TRUC_CHILD_MAX_VSIZE, tx_v3_child_large2["tx"].get_vsize())
259260
assert_greater_than(tx_v3_parent_large2["tx"].get_vsize() + tx_v3_child_large2["tx"].get_vsize(), 10000)
260261

261262
assert_raises_rpc_error(-26, f"too-long-mempool-chain, exceeds ancestor size limit", node.sendrawtransaction, tx_v3_child_large2["hex"])
@@ -267,12 +268,12 @@ def test_truc_ancestors_package(self):
267268
node = self.nodes[0]
268269
tx_v3_parent_normal = self.wallet.create_self_transfer(
269270
fee_rate=0,
270-
target_weight=4004,
271+
target_vsize=1001,
271272
version=3
272273
)
273274
tx_v3_parent_2_normal = self.wallet.create_self_transfer(
274275
fee_rate=0,
275-
target_weight=4004,
276+
target_vsize=1001,
276277
version=3
277278
)
278279
tx_v3_child_multiparent = self.wallet.create_self_transfer_multi(
@@ -282,7 +283,7 @@ def test_truc_ancestors_package(self):
282283
)
283284
tx_v3_child_heavy = self.wallet.create_self_transfer_multi(
284285
utxos_to_spend=[tx_v3_parent_normal["new_utxo"]],
285-
target_weight=4004,
286+
target_vsize=TRUC_CHILD_MAX_VSIZE + 1,
286287
fee_per_output=10000,
287288
version=3
288289
)
@@ -294,7 +295,7 @@ def test_truc_ancestors_package(self):
294295

295296
self.check_mempool([])
296297
result = node.submitpackage([tx_v3_parent_normal["hex"], tx_v3_child_heavy["hex"]])
297-
# tx_v3_child_heavy is heavy based on weight, not sigops.
298+
# tx_v3_child_heavy is heavy based on vsize, not sigops.
298299
assert_equal(result['package_msg'], f"TRUC-violation, version=3 child tx {tx_v3_child_heavy['txid']} (wtxid={tx_v3_child_heavy['wtxid']}) is too big: {tx_v3_child_heavy['tx'].get_vsize()} > 1000 virtual bytes")
299300
self.check_mempool([])
300301

@@ -416,7 +417,7 @@ def test_truc_package_inheritance(self):
416417
node = self.nodes[0]
417418
tx_v3_parent = self.wallet.create_self_transfer(
418419
fee_rate=0,
419-
target_weight=4004,
420+
target_vsize=1001,
420421
version=3
421422
)
422423
tx_v2_child = self.wallet.create_self_transfer_multi(

‎test/functional/test_framework/wallet.py

+13-19
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
from copy import deepcopy
88
from decimal import Decimal
99
from enum import Enum
10-
import math
1110
from typing import (
1211
Any,
1312
Optional,
@@ -35,7 +34,6 @@
3534
CTxOut,
3635
hash256,
3736
ser_compact_size,
38-
WITNESS_SCALE_FACTOR,
3937
)
4038
from test_framework.script import (
4139
CScript,
@@ -119,20 +117,18 @@ def __init__(self, test_node, *, mode=MiniWalletMode.ADDRESS_OP_TRUE, tag_name=N
119117
def _create_utxo(self, *, txid, vout, value, height, coinbase, confirmations):
120118
return {"txid": txid, "vout": vout, "value": value, "height": height, "coinbase": coinbase, "confirmations": confirmations}
121119

122-
def _bulk_tx(self, tx, target_weight):
123-
"""Pad a transaction with extra outputs until it reaches a target weight (or higher).
120+
def _bulk_tx(self, tx, target_vsize):
121+
"""Pad a transaction with extra outputs until it reaches a target vsize.
124122
returns the tx
125123
"""
126124
tx.vout.append(CTxOut(nValue=0, scriptPubKey=CScript([OP_RETURN])))
127-
# determine number of needed padding bytes by converting weight difference to vbytes
128-
dummy_vbytes = (target_weight - tx.get_weight() + 3) // 4
125+
# determine number of needed padding bytes
126+
dummy_vbytes = target_vsize - tx.get_vsize()
129127
# compensate for the increase of the compact-size encoded script length
130128
# (note that the length encoding of the unpadded output script needs one byte)
131129
dummy_vbytes -= len(ser_compact_size(dummy_vbytes)) - 1
132130
tx.vout[-1].scriptPubKey = CScript([OP_RETURN] + [OP_1] * dummy_vbytes)
133-
# Actual weight should be at most 3 higher than target weight
134-
assert_greater_than_or_equal(tx.get_weight(), target_weight)
135-
assert_greater_than_or_equal(target_weight + 3, tx.get_weight())
131+
assert_equal(tx.get_vsize(), target_vsize)
136132

137133
def get_balance(self):
138134
return sum(u['value'] for u in self._utxos)
@@ -309,7 +305,7 @@ def create_self_transfer_multi(
309305
locktime=0,
310306
sequence=0,
311307
fee_per_output=1000,
312-
target_weight=0,
308+
target_vsize=0,
313309
confirmed_only=False,
314310
):
315311
"""
@@ -338,8 +334,8 @@ def create_self_transfer_multi(
338334

339335
self.sign_tx(tx)
340336

341-
if target_weight:
342-
self._bulk_tx(tx, target_weight)
337+
if target_vsize:
338+
self._bulk_tx(tx, target_vsize)
343339

344340
txid = tx.rehash()
345341
return {
@@ -364,7 +360,7 @@ def create_self_transfer(
364360
fee_rate=Decimal("0.003"),
365361
fee=Decimal("0"),
366362
utxo_to_spend=None,
367-
target_weight=0,
363+
target_vsize=0,
368364
confirmed_only=False,
369365
**kwargs,
370366
):
@@ -379,20 +375,18 @@ def create_self_transfer(
379375
vsize = Decimal(168) # P2PK (73 bytes scriptSig + 35 bytes scriptPubKey + 60 bytes other)
380376
else:
381377
assert False
382-
if target_weight and not fee: # respect fee_rate if target weight is passed
383-
# the actual weight might be off by 3 WUs, so calculate based on that (see self._bulk_tx)
384-
max_actual_weight = target_weight + 3
385-
fee = get_fee(math.ceil(max_actual_weight / WITNESS_SCALE_FACTOR), fee_rate)
378+
if target_vsize and not fee: # respect fee_rate if target vsize is passed
379+
fee = get_fee(target_vsize, fee_rate)
386380
send_value = utxo_to_spend["value"] - (fee or (fee_rate * vsize / 1000))
387381

388382
# create tx
389383
tx = self.create_self_transfer_multi(
390384
utxos_to_spend=[utxo_to_spend],
391385
amount_per_output=int(COIN * send_value),
392-
target_weight=target_weight,
386+
target_vsize=target_vsize,
393387
**kwargs,
394388
)
395-
if not target_weight:
389+
if not target_vsize:
396390
assert_equal(tx["tx"].get_vsize(), vsize)
397391
tx["new_utxo"] = tx.pop("new_utxos")[0]
398392

0 commit comments

Comments
 (0)
Please sign in to comment.