3
3
# Distributed under the MIT software license, see the accompanying
4
4
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
5
"""Test logic for limiting mempool and package ancestors/descendants."""
6
-
7
- from decimal import Decimal
8
-
9
6
from test_framework .blocktools import COINBASE_MATURITY
10
- from test_framework .test_framework import BitcoinTestFramework
11
7
from test_framework .messages import (
12
- COIN ,
13
8
WITNESS_SCALE_FACTOR ,
14
9
)
10
+ from test_framework .test_framework import BitcoinTestFramework
15
11
from test_framework .util import (
16
12
assert_equal ,
17
13
)
18
14
from test_framework .wallet import MiniWallet
19
15
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
+
20
41
class MempoolPackageLimitsTest (BitcoinTestFramework ):
21
42
def set_test_params (self ):
22
43
self .num_nodes = 1
@@ -40,9 +61,9 @@ def run_test(self):
40
61
self .test_anc_size_limits ()
41
62
self .test_desc_size_limits ()
42
63
64
+ @check_package_limits
43
65
def test_chain_limits_helper (self , mempool_count , package_count ):
44
66
node = self .nodes [0 ]
45
- assert_equal (0 , node .getmempoolinfo ()["size" ])
46
67
chain_hex = []
47
68
48
69
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):
51
72
tx = self .wallet .create_self_transfer (utxo_to_spend = chaintip_utxo )
52
73
chaintip_utxo = tx ["new_utxo" ]
53
74
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
61
76
62
77
def test_chain_limits (self ):
63
78
"""Create chains from mempool and package transactions that are longer than 25,
@@ -76,6 +91,7 @@ def test_chain_limits(self):
76
91
# 13 transactions in the mempool and 13 in the package.
77
92
self .test_chain_limits_helper (13 , 13 )
78
93
94
+ @check_package_limits
79
95
def test_desc_count_limits (self ):
80
96
"""Create an 'A' shaped package with 24 transactions in the mempool and 2 in the package:
81
97
M1
@@ -93,7 +109,6 @@ def test_desc_count_limits(self):
93
109
package transactions).
94
110
"""
95
111
node = self .nodes [0 ]
96
- assert_equal (0 , node .getmempoolinfo ()["size" ])
97
112
self .log .info ("Check that in-mempool and in-package descendants are calculated properly in packages" )
98
113
# Top parent in mempool, M1
99
114
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):
113
128
114
129
assert_equal (24 , node .getmempoolinfo ()["size" ])
115
130
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
123
132
133
+ @check_package_limits
124
134
def test_desc_count_limits_2 (self ):
125
135
"""Create a Package with 24 transaction in mempool and 2 transaction in package:
126
136
M1
@@ -157,15 +167,9 @@ def test_desc_count_limits_2(self):
157
167
158
168
assert_equal (24 , node .getmempoolinfo ()["size" ])
159
169
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
168
171
172
+ @check_package_limits
169
173
def test_anc_count_limits (self ):
170
174
"""Create a 'V' shaped chain with 24 transactions in the mempool and 3 in the package:
171
175
M1a M1b
@@ -183,7 +187,6 @@ def test_anc_count_limits(self):
183
187
and in-package ancestors are all considered together.
184
188
"""
185
189
node = self .nodes [0 ]
186
- assert_equal (0 , node .getmempoolinfo ()["size" ])
187
190
package_hex = []
188
191
pc_parent_utxos = []
189
192
@@ -203,14 +206,9 @@ def test_anc_count_limits(self):
203
206
204
207
assert_equal (24 , node .getmempoolinfo ()["size" ])
205
208
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
213
210
211
+ @check_package_limits
214
212
def test_anc_count_limits_2 (self ):
215
213
"""Create a 'Y' shaped chain with 24 transactions in the mempool and 2 in the package:
216
214
M1a M1b
@@ -228,7 +226,6 @@ def test_anc_count_limits_2(self):
228
226
and in-package ancestors are all considered together.
229
227
"""
230
228
node = self .nodes [0 ]
231
- assert_equal (0 , node .getmempoolinfo ()["size" ])
232
229
pc_parent_utxos = []
233
230
234
231
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):
245
242
pd_tx = self .wallet .create_self_transfer (utxo_to_spend = pc_tx ["new_utxos" ][0 ])
246
243
247
244
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" ]]
255
246
247
+ @check_package_limits
256
248
def test_anc_count_limits_bushy (self ):
257
249
"""Create a tree with 20 transactions in the mempool and 6 in the package:
258
250
M1...M4 M5...M8 M9...M12 M13...M16 M17...M20
@@ -265,7 +257,6 @@ def test_anc_count_limits_bushy(self):
265
257
combined, PC has 25 in-mempool and in-package parents.
266
258
"""
267
259
node = self .nodes [0 ]
268
- assert_equal (0 , node .getmempoolinfo ()["size" ])
269
260
package_hex = []
270
261
pc_parent_utxos = []
271
262
for _ in range (5 ): # Make package transactions P0 ... P4
@@ -282,14 +273,9 @@ def test_anc_count_limits_bushy(self):
282
273
283
274
assert_equal (20 , node .getmempoolinfo ()["size" ])
284
275
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
292
277
278
+ @check_package_limits
293
279
def test_anc_size_limits (self ):
294
280
"""Test Case with 2 independent transactions in the mempool and a parent + child in the
295
281
package, where the package parent is the child of both mempool transactions (30KvB each):
@@ -302,10 +288,10 @@ def test_anc_size_limits(self):
302
288
and in-package ancestors are all considered together.
303
289
"""
304
290
node = self .nodes [0 ]
305
- assert_equal (0 , node .getmempoolinfo ()["size" ])
306
291
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
309
295
self .log .info ("Check that in-mempool and in-package ancestor size limits are calculated properly in packages" )
310
296
# Mempool transactions A and B
311
297
for _ in range (2 ):
@@ -314,22 +300,17 @@ def test_anc_size_limits(self):
314
300
parent_utxos .append (bulked_tx ["new_utxo" ])
315
301
316
302
# 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 )
318
304
319
305
# Package transaction D
320
306
pd_tx = self .wallet .create_self_transfer (utxo_to_spend = pc_tx ["new_utxos" ][0 ], target_weight = target_weight )
321
307
322
308
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" ]]
330
310
311
+ @check_package_limits
331
312
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):
333
314
Ma
334
315
^ ^
335
316
Mb Mc
@@ -339,12 +320,12 @@ def test_desc_size_limits(self):
339
320
and in-package descendants are all considered together.
340
321
"""
341
322
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
345
326
self .log .info ("Check that in-mempool and in-package descendant sizes are calculated properly in packages" )
346
327
# 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 )
348
329
self .wallet .sendrawtransaction (from_node = node , tx_hex = ma_tx ["hex" ])
349
330
350
331
package_hex = []
@@ -359,13 +340,8 @@ def test_desc_size_limits(self):
359
340
360
341
assert_equal (3 , node .getmempoolinfo ()["size" ])
361
342
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
365
344
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 )])
369
345
370
346
if __name__ == "__main__" :
371
347
MempoolPackageLimitsTest ().main ()
0 commit comments