Skip to content

Commit 328087d

Browse files
committed
Merge bitcoin/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
2 parents d4833e9 + e669833 commit 328087d

File tree

1 file changed

+51
-75
lines changed

1 file changed

+51
-75
lines changed

test/functional/mempool_package_limits.py

Lines changed: 51 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,41 @@
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
10-
from test_framework.test_framework import BitcoinTestFramework
117
from test_framework.messages import (
12-
COIN,
138
WITNESS_SCALE_FACTOR,
149
)
10+
from test_framework.test_framework import BitcoinTestFramework
1511
from test_framework.util import (
1612
assert_equal,
1713
)
1814
from test_framework.wallet import MiniWallet
1915

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

64+
@check_package_limits
4365
def test_chain_limits_helper(self, mempool_count, package_count):
4466
node = self.nodes[0]
45-
assert_equal(0, node.getmempoolinfo()["size"])
4667
chain_hex = []
4768

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

6277
def test_chain_limits(self):
6378
"""Create chains from mempool and package transactions that are longer than 25,
@@ -76,6 +91,7 @@ def test_chain_limits(self):
7691
# 13 transactions in the mempool and 13 in the package.
7792
self.test_chain_limits_helper(13, 13)
7893

94+
@check_package_limits
7995
def test_desc_count_limits(self):
8096
"""Create an 'A' shaped package with 24 transactions in the mempool and 2 in the package:
8197
M1
@@ -93,7 +109,6 @@ def test_desc_count_limits(self):
93109
package transactions).
94110
"""
95111
node = self.nodes[0]
96-
assert_equal(0, node.getmempoolinfo()["size"])
97112
self.log.info("Check that in-mempool and in-package descendants are calculated properly in packages")
98113
# Top parent in mempool, M1
99114
m1_utxos = self.wallet.send_self_transfer_multi(from_node=node, num_outputs=2)['new_utxos']
@@ -113,14 +128,9 @@ def test_desc_count_limits(self):
113128

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

133+
@check_package_limits
124134
def test_desc_count_limits_2(self):
125135
"""Create a Package with 24 transaction in mempool and 2 transaction in package:
126136
M1
@@ -157,15 +167,9 @@ def test_desc_count_limits_2(self):
157167

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

172+
@check_package_limits
169173
def test_anc_count_limits(self):
170174
"""Create a 'V' shaped chain with 24 transactions in the mempool and 3 in the package:
171175
M1a M1b
@@ -183,7 +187,6 @@ def test_anc_count_limits(self):
183187
and in-package ancestors are all considered together.
184188
"""
185189
node = self.nodes[0]
186-
assert_equal(0, node.getmempoolinfo()["size"])
187190
package_hex = []
188191
pc_parent_utxos = []
189192

@@ -203,14 +206,9 @@ def test_anc_count_limits(self):
203206

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

211+
@check_package_limits
214212
def test_anc_count_limits_2(self):
215213
"""Create a 'Y' shaped chain with 24 transactions in the mempool and 2 in the package:
216214
M1a M1b
@@ -228,7 +226,6 @@ def test_anc_count_limits_2(self):
228226
and in-package ancestors are all considered together.
229227
"""
230228
node = self.nodes[0]
231-
assert_equal(0, node.getmempoolinfo()["size"])
232229
pc_parent_utxos = []
233230

234231
self.log.info("Check that in-mempool and in-package ancestors are calculated properly in packages")
@@ -245,14 +242,9 @@ def test_anc_count_limits_2(self):
245242
pd_tx = self.wallet.create_self_transfer(utxo_to_spend=pc_tx["new_utxos"][0])
246243

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

247+
@check_package_limits
256248
def test_anc_count_limits_bushy(self):
257249
"""Create a tree with 20 transactions in the mempool and 6 in the package:
258250
M1...M4 M5...M8 M9...M12 M13...M16 M17...M20
@@ -265,7 +257,6 @@ def test_anc_count_limits_bushy(self):
265257
combined, PC has 25 in-mempool and in-package parents.
266258
"""
267259
node = self.nodes[0]
268-
assert_equal(0, node.getmempoolinfo()["size"])
269260
package_hex = []
270261
pc_parent_utxos = []
271262
for _ in range(5): # Make package transactions P0 ... P4
@@ -282,14 +273,9 @@ def test_anc_count_limits_bushy(self):
282273

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

278+
@check_package_limits
293279
def test_anc_size_limits(self):
294280
"""Test Case with 2 independent transactions in the mempool and a parent + child in the
295281
package, where the package parent is the child of both mempool transactions (30KvB each):
@@ -302,10 +288,10 @@ def test_anc_size_limits(self):
302288
and in-package ancestors are all considered together.
303289
"""
304290
node = self.nodes[0]
305-
assert_equal(0, node.getmempoolinfo()["size"])
306291
parent_utxos = []
307-
target_weight = WITNESS_SCALE_FACTOR * 1000 * 30 # 30KvB
308-
high_fee = Decimal("0.003") # 10 sats/vB
292+
target_vsize = 30_000
293+
high_fee = 10 * target_vsize # 10 sats/vB
294+
target_weight = target_vsize * WITNESS_SCALE_FACTOR
309295
self.log.info("Check that in-mempool and in-package ancestor size limits are calculated properly in packages")
310296
# Mempool transactions A and B
311297
for _ in range(2):
@@ -314,22 +300,17 @@ def test_anc_size_limits(self):
314300
parent_utxos.append(bulked_tx["new_utxo"])
315301

316302
# 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)
303+
pc_tx = self.wallet.create_self_transfer_multi(utxos_to_spend=parent_utxos, fee_per_output=high_fee, target_weight=target_weight)
318304

319305
# Package transaction D
320306
pd_tx = self.wallet.create_self_transfer(utxo_to_spend=pc_tx["new_utxos"][0], target_weight=target_weight)
321307

322308
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"]])])
309+
return [pc_tx["hex"], pd_tx["hex"]]
330310

311+
@check_package_limits
331312
def test_desc_size_limits(self):
332-
"""Create 3 mempool transactions and 2 package transactions (25KvB each):
313+
"""Create 3 mempool transactions and 2 package transactions (21KvB each):
333314
Ma
334315
^ ^
335316
Mb Mc
@@ -339,12 +320,12 @@ def test_desc_size_limits(self):
339320
and in-package descendants are all considered together.
340321
"""
341322
node = self.nodes[0]
342-
assert_equal(0, node.getmempoolinfo()["size"])
343-
target_weight = 21 * 1000 * WITNESS_SCALE_FACTOR
344-
high_fee = Decimal("0.0021") # 10 sats/vB
323+
target_vsize = 21_000
324+
high_fee = 10 * target_vsize # 10 sats/vB
325+
target_weight = target_vsize * WITNESS_SCALE_FACTOR
345326
self.log.info("Check that in-mempool and in-package descendant sizes are calculated properly in packages")
346327
# 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)
328+
ma_tx = self.wallet.create_self_transfer_multi(num_outputs=2, fee_per_output=high_fee // 2, target_weight=target_weight)
348329
self.wallet.sendrawtransaction(from_node=node, tx_hex=ma_tx["hex"])
349330

350331
package_hex = []
@@ -359,13 +340,8 @@ def test_desc_size_limits(self):
359340

360341
assert_equal(3, node.getmempoolinfo()["size"])
361342
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")
343+
return package_hex
365344

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)])
369345

370346
if __name__ == "__main__":
371347
MempoolPackageLimitsTest().main()

0 commit comments

Comments
 (0)