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-
96from test_framework .blocktools import COINBASE_MATURITY
107from test_framework .test_framework import BitcoinTestFramework
11- from test_framework .messages import (
12- COIN ,
13- )
148from test_framework .util import (
159 assert_equal ,
1610)
1711from 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+
1938class 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
370343if __name__ == "__main__" :
371344 MempoolPackageLimitsTest ().main ()
0 commit comments