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 sigop limit mempool policy (`-bytespersigop` parameter)"""
6
+ from decimal import Decimal
6
7
from math import ceil
7
8
8
9
from test_framework .messages import (
25
26
OP_TRUE ,
26
27
)
27
28
from test_framework .script_util import (
29
+ keys_to_multisig_script ,
28
30
script_to_p2wsh_script ,
29
31
)
30
32
from test_framework .test_framework import BitcoinTestFramework
31
33
from test_framework .util import (
32
34
assert_equal ,
33
35
assert_greater_than ,
34
36
assert_greater_than_or_equal ,
37
+ assert_raises_rpc_error ,
35
38
)
36
39
from test_framework .wallet import MiniWallet
37
-
40
+ from test_framework . wallet_util import generate_keypair
38
41
39
42
DEFAULT_BYTES_PER_SIGOP = 20 # default setting
40
43
@@ -133,6 +136,48 @@ def test_sigops_limit(self, bytes_per_sigop, num_sigops):
133
136
assert_equal (entry_parent ['descendantcount' ], 2 )
134
137
assert_equal (entry_parent ['descendantsize' ], parent_tx .get_vsize () + sigop_equivalent_vsize )
135
138
139
+ def test_sigops_package (self ):
140
+ # Make a 2-transaction package which fails vbyte checks even though
141
+ # separately they would work.
142
+ self .restart_node (0 , extra_args = ["-bytespersigop=5000" ] + self .extra_args [0 ])
143
+
144
+ _ , pubkey = generate_keypair ()
145
+ amount_for_bare = 50000
146
+ tx_parent_dict = self .wallet .create_self_transfer (fee = Decimal ("3" ))
147
+ tx_parent_utxo = tx_parent_dict ["new_utxo" ]
148
+ tx_parent = tx_parent_dict ["tx" ]
149
+ tx_parent .vout .append (CTxOut (amount_for_bare , keys_to_multisig_script ([pubkey ], k = 1 )))
150
+ tx_parent .vout [0 ].nValue -= amount_for_bare
151
+ tx_parent .calc_sha256 ()
152
+ tx_parent_utxo ["txid" ] = tx_parent .hash
153
+ tx_parent_utxo ["value" ] -= Decimal ("0.00005000" )
154
+
155
+ tx_child_dict = self .wallet .create_self_transfer (utxo_to_spend = tx_parent_utxo , fee = Decimal ("3" ))
156
+ tx_child_utxo = tx_child_dict ["new_utxo" ]
157
+ tx_child = tx_child_dict ["tx" ]
158
+ tx_child .vout .append (CTxOut (amount_for_bare , keys_to_multisig_script ([pubkey ], k = 1 )))
159
+ tx_child .vout [0 ].nValue -= amount_for_bare
160
+ tx_child .calc_sha256 ()
161
+ tx_child_utxo ["txid" ] = tx_child .hash
162
+ tx_child_utxo ["value" ] -= Decimal ("0.00005000" )
163
+
164
+ # Separately, the parent tx is ok
165
+ parent_individual_testres = self .nodes [0 ].testmempoolaccept ([tx_parent .serialize ().hex ()])[0 ]
166
+ assert parent_individual_testres ["allowed" ]
167
+ # Multisig is counted as MAX_PUBKEYS_PER_MULTISIG = 20 sigops
168
+ assert_equal (parent_individual_testres ["vsize" ], 5000 * 20 )
169
+
170
+ # But together, it's exceeding limits
171
+ packet_test = self .nodes [0 ].testmempoolaccept ([tx_parent .serialize ().hex (), tx_child .serialize ().hex ()])
172
+ assert_equal ([x ["package-error" ] for x in packet_test ], ["package-mempool-limits" , "package-mempool-limits" ])
173
+
174
+ # When we actually try to submit, the parent makes it into the mempool, but the child would exceed ancestor vsize limits
175
+ assert_raises_rpc_error (- 26 , "too-long-mempool-chain" , self .nodes [0 ].submitpackage , [tx_parent .serialize ().hex (), tx_child .serialize ().hex ()])
176
+ assert tx_parent .rehash () in self .nodes [0 ].getrawmempool ()
177
+
178
+ # Transactions are tiny in weight
179
+ assert_greater_than (2000 , tx_parent .get_weight () + tx_child .get_weight ())
180
+
136
181
def run_test (self ):
137
182
self .wallet = MiniWallet (self .nodes [0 ])
138
183
@@ -149,6 +194,8 @@ def run_test(self):
149
194
150
195
self .generate (self .wallet , 1 )
151
196
197
+ self .test_sigops_package ()
198
+
152
199
153
200
if __name__ == '__main__' :
154
201
BytesPerSigOpTest ().main ()
0 commit comments