6
6
7
7
from decimal import Decimal
8
8
9
+ from test_framework .blocktools import COINBASE_MATURITY
9
10
from test_framework .test_framework import BitcoinTestFramework
10
- from test_framework .util import assert_equal , assert_greater_than , assert_raises_rpc_error , create_confirmed_utxos , create_lots_of_big_transactions , gen_return_txouts
11
+ from test_framework .util import assert_equal , assert_greater_than , assert_raises_rpc_error , gen_return_txouts
12
+ from test_framework .wallet import MiniWallet
13
+
11
14
12
15
class MempoolLimitTest (BitcoinTestFramework ):
13
16
def set_test_params (self ):
@@ -20,55 +23,58 @@ def set_test_params(self):
20
23
]]
21
24
self .supports_cli = False
22
25
23
- def skip_test_if_missing_module (self ):
24
- self .skip_if_no_wallet ()
26
+ def send_large_txs (self , miniwallet , txouts , fee_rate , tx_batch_size ):
27
+ for _ in range (tx_batch_size ):
28
+ tx = miniwallet .create_self_transfer (from_node = self .nodes [0 ], fee_rate = fee_rate )['tx' ]
29
+ for txout in txouts :
30
+ tx .vout .append (txout )
31
+ miniwallet .sendrawtransaction (from_node = self .nodes [0 ], tx_hex = tx .serialize ().hex ())
25
32
26
33
def run_test (self ):
27
34
txouts = gen_return_txouts ()
35
+ miniwallet = MiniWallet (self .nodes [0 ])
28
36
relayfee = self .nodes [0 ].getnetworkinfo ()['relayfee' ]
29
37
30
38
self .log .info ('Check that mempoolminfee is minrelytxfee' )
31
39
assert_equal (self .nodes [0 ].getmempoolinfo ()['minrelaytxfee' ], Decimal ('0.00001000' ))
32
40
assert_equal (self .nodes [0 ].getmempoolinfo ()['mempoolminfee' ], Decimal ('0.00001000' ))
33
41
34
- txids = []
35
- utxos = create_confirmed_utxos (self , relayfee , self .nodes [0 ], 91 )
42
+ tx_batch_size = 25
43
+ num_of_batches = 3
44
+ # Generate UTXOs to flood the mempool
45
+ # 1 to create a tx initially that will be evicted from the mempool later
46
+ # 3 batches of multiple transactions with a fee rate much higher than the previous UTXO
47
+ # And 1 more to verify that this tx does not get added to the mempool with a fee rate less than the mempoolminfee
48
+ self .generate (miniwallet , 1 + (num_of_batches * tx_batch_size ) + 1 )
49
+
50
+ # Mine 99 blocks so that the UTXOs are allowed to be spent
51
+ self .generate (self .nodes [0 ], COINBASE_MATURITY - 1 )
36
52
37
53
self .log .info ('Create a mempool tx that will be evicted' )
38
- us0 = utxos .pop ()
39
- inputs = [{ "txid" : us0 ["txid" ], "vout" : us0 ["vout" ]}]
40
- outputs = {self .nodes [0 ].getnewaddress () : 0.0001 }
41
- tx = self .nodes [0 ].createrawtransaction (inputs , outputs )
42
- self .nodes [0 ].settxfee (relayfee ) # specifically fund this tx with low fee
43
- txF = self .nodes [0 ].fundrawtransaction (tx )
44
- self .nodes [0 ].settxfee (0 ) # return to automatic fee selection
45
- txFS = self .nodes [0 ].signrawtransactionwithwallet (txF ['hex' ])
46
- txid = self .nodes [0 ].sendrawtransaction (txFS ['hex' ])
54
+ tx_to_be_evicted_id = miniwallet .send_self_transfer (from_node = self .nodes [0 ], fee_rate = relayfee )["txid" ]
47
55
48
- relayfee = self .nodes [0 ].getnetworkinfo ()['relayfee' ]
49
- base_fee = relayfee * 100
50
- for i in range (3 ):
51
- txids .append ([])
52
- txids [i ] = create_lots_of_big_transactions (self .nodes [0 ], txouts , utxos [30 * i :30 * i + 30 ], 30 , (i + 1 )* base_fee )
56
+ # Increase the tx fee rate massively to give the subsequent transactions a higher priority in the mempool
57
+ base_fee = relayfee * 1000
58
+
59
+ self .log .info ("Fill up the mempool with txs with higher fee rate" )
60
+ for batch_of_txid in range (num_of_batches ):
61
+ fee_rate = (batch_of_txid + 1 ) * base_fee
62
+ self .send_large_txs (miniwallet , txouts , fee_rate , tx_batch_size )
53
63
54
64
self .log .info ('The tx should be evicted by now' )
55
- assert txid not in self .nodes [0 ].getrawmempool ()
56
- txdata = self .nodes [0 ].gettransaction (txid )
57
- assert txdata ['confirmations' ] == 0 #confirmation should still be 0
65
+ # The number of transactions created should be greater than the ones present in the mempool
66
+ assert_greater_than (tx_batch_size * num_of_batches , len (self .nodes [0 ].getrawmempool ()))
67
+ # Initial tx created should not be present in the mempool anymore as it had a lower fee rate
68
+ assert tx_to_be_evicted_id not in self .nodes [0 ].getrawmempool ()
58
69
59
70
self .log .info ('Check that mempoolminfee is larger than minrelytxfee' )
60
71
assert_equal (self .nodes [0 ].getmempoolinfo ()['minrelaytxfee' ], Decimal ('0.00001000' ))
61
72
assert_greater_than (self .nodes [0 ].getmempoolinfo ()['mempoolminfee' ], Decimal ('0.00001000' ))
62
73
74
+ # Deliberately try to create a tx with a fee less than the minimum mempool fee to assert that it does not get added to the mempool
63
75
self .log .info ('Create a mempool tx that will not pass mempoolminfee' )
64
- us0 = utxos .pop ()
65
- inputs = [{ "txid" : us0 ["txid" ], "vout" : us0 ["vout" ]}]
66
- outputs = {self .nodes [0 ].getnewaddress () : 0.0001 }
67
- tx = self .nodes [0 ].createrawtransaction (inputs , outputs )
68
- # specifically fund this tx with a fee < mempoolminfee, >= than minrelaytxfee
69
- txF = self .nodes [0 ].fundrawtransaction (tx , {'feeRate' : relayfee })
70
- txFS = self .nodes [0 ].signrawtransactionwithwallet (txF ['hex' ])
71
- assert_raises_rpc_error (- 26 , "mempool min fee not met" , self .nodes [0 ].sendrawtransaction , txFS ['hex' ])
76
+ assert_raises_rpc_error (- 26 , "mempool min fee not met" , miniwallet .send_self_transfer , from_node = self .nodes [0 ], fee_rate = relayfee , mempool_valid = False )
77
+
72
78
73
79
if __name__ == '__main__' :
74
80
MempoolLimitTest ().main ()
0 commit comments