Skip to content

Commit b21e0a6

Browse files
glozowknst
authored andcommitted
Merge bitcoin#27350: test: refactor: dedup mempool_package_limits.py subtests via decorator
e669833 test: dedup package limit checks via decorator in mempool_package_limits.py (Sebastian Falbesoner) 72f25e2 test: refactor: use Satoshis for fees in mempool_package_limits.py (Sebastian Falbesoner) Pull request description: The subtests in the functional test mempool_package_limits.py all follow the same pattern: 1. first, check that the mempool is currently empty 2. create and submit certain single txs to the mempool, prepare list of hex transactions 3. check that `testmempoolaccept` on the package hex fails with a "package-mempool-limits" error on each tx result 4. after mining a block, check that submitting the package succeeds Note that steps 1,3,4 are identical for each of the subtests and only step 2 varies, so this might be a nice opportunity to deduplicate code by using a newly introduced decorator which executes the necessary before and after the essential part of the subtest. This also makes it easier to add new subtests without having to copy-paste those parts once again. In addition, the first commit switches the fee unit from BTC to Satoshis, which allows to get rid of some imports (`COIN` and `Decimal`) and a comment for the `test_desc_size_limits` subtest is fixed (s/25KvB/21KvB/). ACKs for top commit: ismaelsadeeq: ACK e669833 glozow: utACK e669833 Tree-SHA512: 84a85e739de7387391c13bd46aeb015a74302ea7c6f0ca3d4e2b1b487d38df390dc118eb5b1c11d3e4206bff316a4dab60ef6b25d8feced672345d4e36ffd205
1 parent b8daa9b commit b21e0a6

File tree

1 file changed

+50
-77
lines changed

1 file changed

+50
-77
lines changed

test/functional/mempool_package_limits.py

Lines changed: 50 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,38 @@
33
# Distributed under the MIT software license, see the accompanying
44
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
55
"""Test logic for limiting mempool and package ancestors/descendants."""
6-
7-
from decimal import Decimal
8-
96
from test_framework.blocktools import COINBASE_MATURITY
107
from test_framework.test_framework import BitcoinTestFramework
11-
from test_framework.messages import (
12-
COIN,
13-
)
148
from test_framework.util import (
159
assert_equal,
1610
)
1711
from test_framework.wallet import MiniWallet
1812

13+
# Decorator to
14+
# 1) check that mempool is empty at the start of a subtest
15+
# 2) run the subtest, which may submit some transaction(s) to the mempool and
16+
# create a list of hex transactions
17+
# 3) testmempoolaccept the package hex and check that it fails with the error
18+
# "package-mempool-limits" for each tx
19+
# 4) after mining a block, clearing the pre-submitted transactions from mempool,
20+
# check that submitting the created package succeeds
21+
def check_package_limits(func):
22+
def func_wrapper(self, *args, **kwargs):
23+
node = self.nodes[0]
24+
assert_equal(0, node.getmempoolinfo()["size"])
25+
package_hex = func(self, *args, **kwargs)
26+
testres_error_expected = node.testmempoolaccept(rawtxs=package_hex)
27+
assert_equal(len(testres_error_expected), len(package_hex))
28+
for txres in testres_error_expected:
29+
assert_equal(txres["package-error"], "package-mempool-limits")
30+
31+
# Clear mempool and check that the package passes now
32+
self.generate(node, 1)
33+
assert all([res["allowed"] for res in node.testmempoolaccept(rawtxs=package_hex)])
34+
35+
return func_wrapper
36+
37+
1938
class MempoolPackageLimitsTest(BitcoinTestFramework):
2039
def set_test_params(self):
2140
self.num_nodes = 1
@@ -39,9 +58,9 @@ def run_test(self):
3958
self.test_anc_size_limits()
4059
self.test_desc_size_limits()
4160

61+
@check_package_limits
4262
def test_chain_limits_helper(self, mempool_count, package_count):
4363
node = self.nodes[0]
44-
assert_equal(0, node.getmempoolinfo()["size"])
4564
chain_hex = []
4665

4766
chaintip_utxo = self.wallet.send_self_transfer_chain(from_node=node, chain_length=mempool_count)[-1]["new_utxo"]
@@ -50,13 +69,7 @@ def test_chain_limits_helper(self, mempool_count, package_count):
5069
tx = self.wallet.create_self_transfer(utxo_to_spend=chaintip_utxo)
5170
chaintip_utxo = tx["new_utxo"]
5271
chain_hex.append(tx["hex"])
53-
testres_too_long = node.testmempoolaccept(rawtxs=chain_hex)
54-
for txres in testres_too_long:
55-
assert_equal(txres["package-error"], "package-mempool-limits")
56-
57-
# Clear mempool and check that the package passes now
58-
self.generate(node, 1)
59-
assert all([res["allowed"] for res in node.testmempoolaccept(rawtxs=chain_hex)])
72+
return chain_hex
6073

6174
def test_chain_limits(self):
6275
"""Create chains from mempool and package transactions that are longer than 25,
@@ -75,6 +88,7 @@ def test_chain_limits(self):
7588
# 13 transactions in the mempool and 13 in the package.
7689
self.test_chain_limits_helper(13, 13)
7790

91+
@check_package_limits
7892
def test_desc_count_limits(self):
7993
"""Create an 'A' shaped package with 24 transactions in the mempool and 2 in the package:
8094
M1
@@ -92,7 +106,6 @@ def test_desc_count_limits(self):
92106
package transactions).
93107
"""
94108
node = self.nodes[0]
95-
assert_equal(0, node.getmempoolinfo()["size"])
96109
self.log.info("Check that in-mempool and in-package descendants are calculated properly in packages")
97110
# Top parent in mempool, M1
98111
m1_utxos = self.wallet.send_self_transfer_multi(from_node=node, num_outputs=2)['new_utxos']
@@ -112,14 +125,9 @@ def test_desc_count_limits(self):
112125

113126
assert_equal(24, node.getmempoolinfo()["size"])
114127
assert_equal(2, len(package_hex))
115-
testres_too_long = node.testmempoolaccept(rawtxs=package_hex)
116-
for txres in testres_too_long:
117-
assert_equal(txres["package-error"], "package-mempool-limits")
118-
119-
# Clear mempool and check that the package passes now
120-
self.generate(node, 1)
121-
assert all([res["allowed"] for res in node.testmempoolaccept(rawtxs=package_hex)])
128+
return package_hex
122129

130+
@check_package_limits
123131
def test_desc_count_limits_2(self):
124132
"""Create a Package with 24 transaction in mempool and 2 transaction in package:
125133
M1
@@ -156,15 +164,9 @@ def test_desc_count_limits_2(self):
156164

157165
assert_equal(24, node.getmempoolinfo()["size"])
158166
assert_equal(2, len(package_hex))
159-
testres = node.testmempoolaccept(rawtxs=package_hex)
160-
assert_equal(len(testres), len(package_hex))
161-
for txres in testres:
162-
assert_equal(txres["package-error"], "package-mempool-limits")
163-
164-
# Clear mempool and check that the package passes now
165-
self.generate(node, 1)
166-
assert all([res["allowed"] for res in node.testmempoolaccept(rawtxs=package_hex)])
167+
return package_hex
167168

169+
@check_package_limits
168170
def test_anc_count_limits(self):
169171
"""Create a 'V' shaped chain with 24 transactions in the mempool and 3 in the package:
170172
M1a M1b
@@ -182,7 +184,6 @@ def test_anc_count_limits(self):
182184
and in-package ancestors are all considered together.
183185
"""
184186
node = self.nodes[0]
185-
assert_equal(0, node.getmempoolinfo()["size"])
186187
package_hex = []
187188
pc_parent_utxos = []
188189

@@ -202,14 +203,9 @@ def test_anc_count_limits(self):
202203

203204
assert_equal(24, node.getmempoolinfo()["size"])
204205
assert_equal(3, len(package_hex))
205-
testres_too_long = node.testmempoolaccept(rawtxs=package_hex)
206-
for txres in testres_too_long:
207-
assert_equal(txres["package-error"], "package-mempool-limits")
208-
209-
# Clear mempool and check that the package passes now
210-
self.generate(node, 1)
211-
assert all([res["allowed"] for res in node.testmempoolaccept(rawtxs=package_hex)])
206+
return package_hex
212207

208+
@check_package_limits
213209
def test_anc_count_limits_2(self):
214210
"""Create a 'Y' shaped chain with 24 transactions in the mempool and 2 in the package:
215211
M1a M1b
@@ -227,7 +223,6 @@ def test_anc_count_limits_2(self):
227223
and in-package ancestors are all considered together.
228224
"""
229225
node = self.nodes[0]
230-
assert_equal(0, node.getmempoolinfo()["size"])
231226
pc_parent_utxos = []
232227

233228
self.log.info("Check that in-mempool and in-package ancestors are calculated properly in packages")
@@ -244,14 +239,9 @@ def test_anc_count_limits_2(self):
244239
pd_tx = self.wallet.create_self_transfer(utxo_to_spend=pc_tx["new_utxos"][0])
245240

246241
assert_equal(24, node.getmempoolinfo()["size"])
247-
testres_too_long = node.testmempoolaccept(rawtxs=[pc_tx["hex"], pd_tx["hex"]])
248-
for txres in testres_too_long:
249-
assert_equal(txres["package-error"], "package-mempool-limits")
250-
251-
# Clear mempool and check that the package passes now
252-
self.generate(node, 1)
253-
assert all([res["allowed"] for res in node.testmempoolaccept(rawtxs=[pc_tx["hex"], pd_tx["hex"]])])
242+
return [pc_tx["hex"], pd_tx["hex"]]
254243

244+
@check_package_limits
255245
def test_anc_count_limits_bushy(self):
256246
"""Create a tree with 20 transactions in the mempool and 6 in the package:
257247
M1...M4 M5...M8 M9...M12 M13...M16 M17...M20
@@ -264,7 +254,6 @@ def test_anc_count_limits_bushy(self):
264254
combined, PC has 25 in-mempool and in-package parents.
265255
"""
266256
node = self.nodes[0]
267-
assert_equal(0, node.getmempoolinfo()["size"])
268257
package_hex = []
269258
pc_parent_utxos = []
270259
for _ in range(5): # Make package transactions P0 ... P4
@@ -281,14 +270,9 @@ def test_anc_count_limits_bushy(self):
281270

282271
assert_equal(20, node.getmempoolinfo()["size"])
283272
assert_equal(6, len(package_hex))
284-
testres = node.testmempoolaccept(rawtxs=package_hex)
285-
for txres in testres:
286-
assert_equal(txres["package-error"], "package-mempool-limits")
287-
288-
# Clear mempool and check that the package passes now
289-
self.generate(node, 1)
290-
assert all([res["allowed"] for res in node.testmempoolaccept(rawtxs=package_hex)])
273+
return package_hex
291274

275+
@check_package_limits
292276
def test_anc_size_limits(self):
293277
"""Test Case with 2 independent transactions in the mempool and a parent + child in the
294278
package, where the package parent is the child of both mempool transactions (30KvB each):
@@ -302,10 +286,9 @@ def test_anc_size_limits(self):
302286
"""
303287
node = self.nodes[0]
304288
parent_utxos = []
305-
assert_equal(0, node.getmempoolinfo()["size"])
306-
parents_tx = []
307-
target_weight = 1000 * 30 # 30KvB
308-
high_fee = Decimal("0.003") # 10 sats/vB
289+
target_vsize = 30_000
290+
high_fee = 10 * target_vsize # 10 sats/vB
291+
target_weight = target_vsize
309292
self.log.info("Check that in-mempool and in-package ancestor size limits are calculated properly in packages")
310293
# Mempool transactions A and B
311294
for _ in range(2):
@@ -314,22 +297,17 @@ def test_anc_size_limits(self):
314297
parent_utxos.append(bulked_tx["new_utxo"])
315298

316299
# Package transaction C
317-
pc_tx = self.wallet.create_self_transfer_multi(utxos_to_spend=parent_utxos, fee_per_output=int(high_fee * COIN), target_weight=target_weight)
300+
pc_tx = self.wallet.create_self_transfer_multi(utxos_to_spend=parent_utxos, fee_per_output=high_fee, target_weight=target_weight)
318301

319302
# Package transaction D
320303
pd_tx = self.wallet.create_self_transfer(utxo_to_spend=pc_tx["new_utxos"][0], target_weight=target_weight)
321304

322305
assert_equal(2, node.getmempoolinfo()["size"])
323-
testres_too_heavy = node.testmempoolaccept(rawtxs=[pc_tx["hex"], pd_tx["hex"]])
324-
for txres in testres_too_heavy:
325-
assert_equal(txres["package-error"], "package-mempool-limits")
326-
327-
# Clear mempool and check that the package passes now
328-
self.generate(node, 1)
329-
assert all([res["allowed"] for res in node.testmempoolaccept(rawtxs=[pc_tx["hex"], pd_tx["hex"]])])
306+
return [pc_tx["hex"], pd_tx["hex"]]
330307

308+
@check_package_limits
331309
def test_desc_size_limits(self):
332-
"""Create 3 mempool transactions and 2 package transactions (25KvB each):
310+
"""Create 3 mempool transactions and 2 package transactions (21KvB each):
333311
Ma
334312
^ ^
335313
Mb Mc
@@ -339,12 +317,12 @@ def test_desc_size_limits(self):
339317
and in-package descendants are all considered together.
340318
"""
341319
node = self.nodes[0]
342-
assert_equal(0, node.getmempoolinfo()["size"])
343-
target_weight = 21 * 1000
344-
high_fee = Decimal("0.0021") # 10 sats/vB
320+
target_vsize = 21_000
321+
high_fee = 10 * target_vsize # 10 sats/vB
322+
target_weight = target_vsize
345323
self.log.info("Check that in-mempool and in-package descendant sizes are calculated properly in packages")
346324
# Top parent in mempool, Ma
347-
ma_tx = self.wallet.create_self_transfer_multi(num_outputs=2, fee_per_output=int(high_fee / 2 * COIN), target_weight=target_weight)
325+
ma_tx = self.wallet.create_self_transfer_multi(num_outputs=2, fee_per_output=high_fee // 2, target_weight=target_weight)
348326
self.wallet.sendrawtransaction(from_node=node, tx_hex=ma_tx["hex"])
349327

350328
package_hex = []
@@ -359,13 +337,8 @@ def test_desc_size_limits(self):
359337

360338
assert_equal(3, node.getmempoolinfo()["size"])
361339
assert_equal(2, len(package_hex))
362-
testres_too_heavy = node.testmempoolaccept(rawtxs=package_hex)
363-
for txres in testres_too_heavy:
364-
assert_equal(txres["package-error"], "package-mempool-limits")
340+
return package_hex
365341

366-
# Clear mempool and check that the package passes now
367-
self.generate(node, 1)
368-
assert all([res["allowed"] for res in node.testmempoolaccept(rawtxs=package_hex)])
369342

370343
if __name__ == "__main__":
371344
MempoolPackageLimitsTest().main()

0 commit comments

Comments
 (0)