Skip to content

Commit c16ae71

Browse files
committed
test: switch MiniWallet padding unit from weight to vsize
The weight unit is merely a consensus rule detail and is largely irrelevant for 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 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.
1 parent d812cf1 commit c16ae71

File tree

6 files changed

+61
-72
lines changed

6 files changed

+61
-72
lines changed

test/functional/feature_blocksxor.py

Lines changed: 1 addition & 1 deletion
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

Lines changed: 7 additions & 9 deletions
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

Lines changed: 17 additions & 14 deletions
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

Lines changed: 6 additions & 11 deletions
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

Lines changed: 17 additions & 18 deletions
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 (
@@ -55,14 +54,14 @@ def check_mempool(self, txids):
5554
def test_truc_max_vsize(self):
5655
node = self.nodes[0]
5756
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)
57+
tx_v3_heavy = self.wallet.create_self_transfer(target_vsize=TRUC_MAX_VSIZE + 1, version=3)
5958
assert_greater_than_or_equal(tx_v3_heavy["tx"].get_vsize(), TRUC_MAX_VSIZE)
6059
expected_error_heavy = f"TRUC-violation, version=3 tx {tx_v3_heavy['txid']} (wtxid={tx_v3_heavy['wtxid']}) is too big"
6160
assert_raises_rpc_error(-26, expected_error_heavy, node.sendrawtransaction, tx_v3_heavy["hex"])
6261
self.check_mempool([])
6362

6463
# 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)
64+
tx_v2_heavy = self.wallet.send_self_transfer(from_node=node, target_vsize=TRUC_MAX_VSIZE + 1, version=2)
6665
self.check_mempool([tx_v2_heavy["txid"]])
6766

6867
@cleanup(extra_args=["-datacarriersize=1000"])
@@ -73,7 +72,7 @@ def test_truc_acceptance(self):
7372
self.check_mempool([tx_v3_parent_normal["txid"]])
7473
tx_v3_child_heavy = self.wallet.create_self_transfer(
7574
utxo_to_spend=tx_v3_parent_normal["new_utxo"],
76-
target_weight=4004,
75+
target_vsize=1001,
7776
version=3
7877
)
7978
assert_greater_than_or_equal(tx_v3_child_heavy["tx"].get_vsize(), 1000)
@@ -88,7 +87,7 @@ def test_truc_acceptance(self):
8887
from_node=node,
8988
fee_rate=DEFAULT_FEE,
9089
utxo_to_spend=tx_v3_parent_normal["new_utxo"],
91-
target_weight=3987,
90+
target_vsize=997,
9291
version=3
9392
)
9493
assert_greater_than_or_equal(1000, tx_v3_child_almost_heavy["tx"].get_vsize())
@@ -98,7 +97,7 @@ def test_truc_acceptance(self):
9897
from_node=node,
9998
fee_rate=DEFAULT_FEE * 2,
10099
utxo_to_spend=tx_v3_parent_normal["new_utxo"],
101-
target_weight=3500,
100+
target_vsize=875,
102101
version=3
103102
)
104103
assert_greater_than_or_equal(tx_v3_child_almost_heavy["tx"].get_vsize() + tx_v3_child_almost_heavy_rbf["tx"].get_vsize(), 1000)
@@ -199,7 +198,7 @@ def test_truc_reorg(self):
199198
self.check_mempool([])
200199
tx_v2_from_v3 = self.wallet.send_self_transfer(from_node=node, utxo_to_spend=tx_v3_block["new_utxo"], version=2)
201200
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)
201+
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)
203202
assert_greater_than(node.getmempoolentry(tx_v3_child_large["txid"])["vsize"], 1000)
204203
self.check_mempool([tx_v2_from_v3["txid"], tx_v3_from_v2["txid"], tx_v3_child_large["txid"]])
205204
node.invalidateblock(block[0])
@@ -217,16 +216,16 @@ def test_nondefault_package_limits(self):
217216
"""
218217
node = self.nodes[0]
219218
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
219+
parent_target_vsize = 9990
220+
child_target_vsize = 500
222221
tx_v3_parent_large1 = self.wallet.send_self_transfer(
223222
from_node=node,
224-
target_weight=parent_target_weight,
223+
target_vsize=parent_target_vsize,
225224
version=3
226225
)
227226
tx_v3_child_large1 = self.wallet.create_self_transfer(
228227
utxo_to_spend=tx_v3_parent_large1["new_utxo"],
229-
target_weight=child_target_weight,
228+
target_vsize=child_target_vsize,
230229
version=3
231230
)
232231

@@ -244,12 +243,12 @@ def test_nondefault_package_limits(self):
244243
self.restart_node(0, extra_args=["-limitancestorsize=10", "-datacarriersize=40000"])
245244
tx_v3_parent_large2 = self.wallet.send_self_transfer(
246245
from_node=node,
247-
target_weight=parent_target_weight,
246+
target_vsize=parent_target_vsize,
248247
version=3
249248
)
250249
tx_v3_child_large2 = self.wallet.create_self_transfer(
251250
utxo_to_spend=tx_v3_parent_large2["new_utxo"],
252-
target_weight=child_target_weight,
251+
target_vsize=child_target_vsize,
253252
version=3
254253
)
255254

@@ -267,12 +266,12 @@ def test_truc_ancestors_package(self):
267266
node = self.nodes[0]
268267
tx_v3_parent_normal = self.wallet.create_self_transfer(
269268
fee_rate=0,
270-
target_weight=4004,
269+
target_vsize=1001,
271270
version=3
272271
)
273272
tx_v3_parent_2_normal = self.wallet.create_self_transfer(
274273
fee_rate=0,
275-
target_weight=4004,
274+
target_vsize=1001,
276275
version=3
277276
)
278277
tx_v3_child_multiparent = self.wallet.create_self_transfer_multi(
@@ -282,7 +281,7 @@ def test_truc_ancestors_package(self):
282281
)
283282
tx_v3_child_heavy = self.wallet.create_self_transfer_multi(
284283
utxos_to_spend=[tx_v3_parent_normal["new_utxo"]],
285-
target_weight=4004,
284+
target_vsize=1001,
286285
fee_per_output=10000,
287286
version=3
288287
)
@@ -294,7 +293,7 @@ def test_truc_ancestors_package(self):
294293

295294
self.check_mempool([])
296295
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.
296+
# tx_v3_child_heavy is heavy based on vsize, not sigops.
298297
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")
299298
self.check_mempool([])
300299

@@ -416,7 +415,7 @@ def test_truc_package_inheritance(self):
416415
node = self.nodes[0]
417416
tx_v3_parent = self.wallet.create_self_transfer(
418417
fee_rate=0,
419-
target_weight=4004,
418+
target_vsize=1001,
420419
version=3
421420
)
422421
tx_v2_child = self.wallet.create_self_transfer_multi(

0 commit comments

Comments
 (0)