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 copy import deepcopy
6
7
from decimal import Decimal
7
8
from math import ceil
8
9
17
18
)
18
19
from test_framework .script import (
19
20
CScript ,
21
+ OP_2DUP ,
20
22
OP_CHECKMULTISIG ,
21
23
OP_CHECKSIG ,
24
+ OP_DROP ,
22
25
OP_ENDIF ,
23
26
OP_FALSE ,
24
27
OP_IF ,
28
+ OP_NOT ,
25
29
OP_RETURN ,
26
30
OP_TRUE ,
27
31
)
28
32
from test_framework .script_util import (
29
33
keys_to_multisig_script ,
30
34
script_to_p2wsh_script ,
35
+ script_to_p2sh_script ,
36
+ MAX_STD_LEGACY_SIGOPS ,
37
+ MAX_STD_P2SH_SIGOPS ,
31
38
)
32
39
from test_framework .test_framework import BitcoinTestFramework
33
40
from test_framework .util import (
34
41
assert_equal ,
35
42
assert_greater_than ,
36
43
assert_greater_than_or_equal ,
44
+ assert_raises_rpc_error ,
37
45
)
38
46
from test_framework .wallet import MiniWallet
39
47
from test_framework .wallet_util import generate_keypair
@@ -174,6 +182,42 @@ def create_bare_multisig_tx(utxo_to_spend=None):
174
182
# Transactions are tiny in weight
175
183
assert_greater_than (2000 , tx_parent .get_weight () + tx_child .get_weight ())
176
184
185
+ def test_legacy_sigops_stdness (self ):
186
+ self .log .info ("Test a transaction with too many legacy sigops in its inputs is non-standard." )
187
+
188
+ # Restart with the default settings
189
+ self .restart_node (0 )
190
+
191
+ # Create a P2SH script with 15 sigops.
192
+ _ , dummy_pubkey = generate_keypair ()
193
+ packed_redeem_script = [dummy_pubkey ]
194
+ for _ in range (MAX_STD_P2SH_SIGOPS - 1 ):
195
+ packed_redeem_script += [OP_2DUP , OP_CHECKSIG , OP_DROP ]
196
+ packed_redeem_script = CScript (packed_redeem_script + [OP_CHECKSIG , OP_NOT ])
197
+ packed_p2sh_script = script_to_p2sh_script (packed_redeem_script )
198
+
199
+ # Create enough outputs to reach the sigops limit when spending them all at once.
200
+ outpoints = []
201
+ for _ in range (int (MAX_STD_LEGACY_SIGOPS / MAX_STD_P2SH_SIGOPS ) + 1 ):
202
+ res = self .wallet .send_to (from_node = self .nodes [0 ], scriptPubKey = packed_p2sh_script , amount = 1_000 )
203
+ txid = int .from_bytes (bytes .fromhex (res ["txid" ]), byteorder = "big" )
204
+ outpoints .append (COutPoint (txid , res ["sent_vout" ]))
205
+ self .generate (self .nodes [0 ], 1 )
206
+
207
+ # Spending all these outputs at once accounts for 2505 legacy sigops and is non-standard.
208
+ nonstd_tx = CTransaction ()
209
+ nonstd_tx .vin = [CTxIn (op , CScript ([b"" , packed_redeem_script ])) for op in outpoints ]
210
+ nonstd_tx .vout = [CTxOut (0 , CScript ([OP_RETURN , b"" ]))]
211
+ assert_raises_rpc_error (- 26 , "bad-txns-nonstandard-inputs" , self .nodes [0 ].sendrawtransaction , nonstd_tx .serialize ().hex ())
212
+
213
+ # Spending one less accounts for 2490 legacy sigops and is standard.
214
+ std_tx = deepcopy (nonstd_tx )
215
+ std_tx .vin .pop ()
216
+ self .nodes [0 ].sendrawtransaction (std_tx .serialize ().hex ())
217
+
218
+ # Make sure the original, non-standard, transaction can be mined.
219
+ self .generateblock (self .nodes [0 ], output = "raw(42)" , transactions = [nonstd_tx .serialize ().hex ()])
220
+
177
221
def run_test (self ):
178
222
self .wallet = MiniWallet (self .nodes [0 ])
179
223
@@ -191,6 +235,7 @@ def run_test(self):
191
235
self .generate (self .wallet , 1 )
192
236
193
237
self .test_sigops_package ()
238
+ self .test_legacy_sigops_stdness ()
194
239
195
240
196
241
if __name__ == '__main__' :
0 commit comments