/ test / functional / mempool_accept.py
mempool_accept.py
  1  #!/usr/bin/env python3
  2  # Copyright (c) 2017-2022 The Bitcoin Core developers
  3  # Distributed under the MIT software license, see the accompanying
  4  # file COPYING or http://www.opensource.org/licenses/mit-license.php.
  5  """Test mempool acceptance of raw transactions."""
  6  
  7  from copy import deepcopy
  8  from decimal import Decimal
  9  import math
 10  
 11  from test_framework.test_framework import BitcoinTestFramework
 12  from test_framework.messages import (
 13      MAX_BIP125_RBF_SEQUENCE,
 14      COIN,
 15      COutPoint,
 16      CTransaction,
 17      CTxIn,
 18      CTxInWitness,
 19      CTxOut,
 20      MAX_BLOCK_WEIGHT,
 21      WITNESS_SCALE_FACTOR,
 22      MAX_MONEY,
 23      SEQUENCE_FINAL,
 24      tx_from_hex,
 25  )
 26  from test_framework.script import (
 27      CScript,
 28      OP_0,
 29      OP_HASH160,
 30      OP_RETURN,
 31      OP_TRUE,
 32      SIGHASH_ALL,
 33      sign_input_legacy,
 34  )
 35  from test_framework.script_util import (
 36      DUMMY_MIN_OP_RETURN_SCRIPT,
 37      keys_to_multisig_script,
 38      MIN_PADDING,
 39      MIN_STANDARD_TX_NONWITNESS_SIZE,
 40      PAY_TO_ANCHOR,
 41      script_to_p2sh_script,
 42      script_to_p2wsh_script,
 43  )
 44  from test_framework.util import (
 45      assert_equal,
 46      assert_greater_than,
 47      assert_raises_rpc_error,
 48      sync_txindex,
 49  )
 50  from test_framework.wallet import MiniWallet
 51  from test_framework.wallet_util import generate_keypair
 52  
 53  
 54  class MempoolAcceptanceTest(BitcoinTestFramework):
 55      def set_test_params(self):
 56          self.num_nodes = 1
 57          self.extra_args = [[
 58              '-txindex','-permitbaremultisig=0',
 59          ]] * self.num_nodes
 60          self.supports_cli = False
 61  
 62      def check_mempool_result(self, result_expected, *args, **kwargs):
 63          """Wrapper to check result of testmempoolaccept on node_0's mempool"""
 64          result_test = self.nodes[0].testmempoolaccept(*args, **kwargs)
 65          for r in result_test:
 66              # Skip these checks for now
 67              r.pop('wtxid')
 68              if "fees" in r:
 69                  r["fees"].pop("effective-feerate")
 70                  r["fees"].pop("effective-includes")
 71              if "reject-details" in r:
 72                  r.pop("reject-details")
 73          assert_equal(result_expected, result_test)
 74          assert_equal(self.nodes[0].getmempoolinfo()['size'], self.mempool_size)  # Must not change mempool state
 75  
 76      def run_test(self):
 77          node = self.nodes[0]
 78          self.wallet = MiniWallet(node)
 79  
 80          self.log.info('Start with empty mempool, and 200 blocks')
 81          self.mempool_size = 0
 82          assert_equal(node.getblockcount(), 200)
 83          assert_equal(node.getmempoolinfo()['size'], self.mempool_size)
 84  
 85          self.log.info('Should not accept garbage to testmempoolaccept')
 86          assert_raises_rpc_error(-3, 'JSON value of type string is not of expected type array', lambda: node.testmempoolaccept(rawtxs='ff00baar'))
 87          assert_raises_rpc_error(-8, 'Array must contain between 1 and 25 transactions.', lambda: node.testmempoolaccept(rawtxs=['ff22']*26))
 88          assert_raises_rpc_error(-8, 'Array must contain between 1 and 25 transactions.', lambda: node.testmempoolaccept(rawtxs=[]))
 89          assert_raises_rpc_error(-22, 'TX decode failed', lambda: node.testmempoolaccept(rawtxs=['ff00baar']))
 90  
 91          self.log.info('A transaction already in the blockchain')
 92          tx = self.wallet.create_self_transfer()['tx']  # Pick a random coin(base) to spend
 93          tx.vout.append(deepcopy(tx.vout[0]))
 94          tx.vout[0].nValue = int(0.3 * COIN)
 95          tx.vout[1].nValue = int(49 * COIN)
 96          raw_tx_in_block = tx.serialize().hex()
 97          txid_in_block = self.wallet.sendrawtransaction(from_node=node, tx_hex=raw_tx_in_block)
 98          self.generate(node, 1)
 99          self.mempool_size = 0
100          # Also check feerate. 1BTC/kvB fails
101          assert_raises_rpc_error(-8, "Fee rates larger than or equal to 1BTC/kvB are not accepted", lambda: self.check_mempool_result(
102              result_expected=None,
103              rawtxs=[raw_tx_in_block],
104              maxfeerate=1,
105          ))
106          # Check negative feerate
107          assert_raises_rpc_error(-3, "Amount out of range", lambda: self.check_mempool_result(
108              result_expected=None,
109              rawtxs=[raw_tx_in_block],
110              maxfeerate=-0.01,
111          ))
112          # ... 0.99 passes
113          self.check_mempool_result(
114              result_expected=[{'txid': txid_in_block, 'allowed': False, 'reject-reason': 'txn-already-known'}],
115              rawtxs=[raw_tx_in_block],
116              maxfeerate=0.99,
117          )
118  
119          self.log.info('A transaction not in the mempool')
120          fee = Decimal('0.000007')
121          utxo_to_spend = self.wallet.get_utxo(txid=txid_in_block)  # use 0.3 BTC UTXO
122          tx = self.wallet.create_self_transfer(utxo_to_spend=utxo_to_spend, sequence=MAX_BIP125_RBF_SEQUENCE)['tx']
123          tx.vout[0].nValue = int((Decimal('0.3') - fee) * COIN)
124          raw_tx_0 = tx.serialize().hex()
125          txid_0 = tx.rehash()
126          self.check_mempool_result(
127              result_expected=[{'txid': txid_0, 'allowed': True, 'vsize': tx.get_vsize(), 'fees': {'base': fee}}],
128              rawtxs=[raw_tx_0],
129          )
130  
131          self.log.info('A final transaction not in the mempool')
132          output_amount = Decimal('0.025')
133          tx = self.wallet.create_self_transfer(
134              sequence=SEQUENCE_FINAL,
135              locktime=node.getblockcount() + 2000,  # Can be anything
136          )['tx']
137          tx.vout[0].nValue = int(output_amount * COIN)
138          raw_tx_final = tx.serialize().hex()
139          tx = tx_from_hex(raw_tx_final)
140          fee_expected = Decimal('50.0') - output_amount
141          self.check_mempool_result(
142              result_expected=[{'txid': tx.rehash(), 'allowed': True, 'vsize': tx.get_vsize(), 'fees': {'base': fee_expected}}],
143              rawtxs=[tx.serialize().hex()],
144              maxfeerate=0,
145          )
146          node.sendrawtransaction(hexstring=raw_tx_final, maxfeerate=0)
147          self.mempool_size += 1
148  
149          self.log.info('A transaction in the mempool')
150          node.sendrawtransaction(hexstring=raw_tx_0)
151          self.mempool_size += 1
152          self.check_mempool_result(
153              result_expected=[{'txid': txid_0, 'allowed': False, 'reject-reason': 'txn-already-in-mempool'}],
154              rawtxs=[raw_tx_0],
155          )
156  
157          self.log.info('A transaction that replaces a mempool transaction')
158          tx = tx_from_hex(raw_tx_0)
159          tx.vout[0].nValue -= int(fee * COIN)  # Double the fee
160          raw_tx_0 = tx.serialize().hex()
161          txid_0 = tx.rehash()
162          self.check_mempool_result(
163              result_expected=[{'txid': txid_0, 'allowed': True, 'vsize': tx.get_vsize(), 'fees': {'base': (2 * fee)}}],
164              rawtxs=[raw_tx_0],
165          )
166          node.sendrawtransaction(hexstring=tx.serialize().hex(), maxfeerate=0)
167  
168          self.log.info('A transaction with missing inputs, that never existed')
169          tx = tx_from_hex(raw_tx_0)
170          tx.vin[0].prevout = COutPoint(hash=int('ff' * 32, 16), n=14)
171          self.check_mempool_result(
172              result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'missing-inputs'}],
173              rawtxs=[tx.serialize().hex()],
174          )
175  
176          self.log.info('A transaction with missing inputs, that existed once in the past')
177          tx = tx_from_hex(raw_tx_0)
178          tx.vin[0].prevout.n = 1  # Set vout to 1, to spend the other outpoint (49 coins) of the in-chain-tx we want to double spend
179          raw_tx_1 = tx.serialize().hex()
180          txid_1 = node.sendrawtransaction(hexstring=raw_tx_1, maxfeerate=0)
181          # Now spend both to "clearly hide" the outputs, ie. remove the coins from the utxo set by spending them
182          tx = self.wallet.create_self_transfer()['tx']
183          tx.vin.append(deepcopy(tx.vin[0]))
184          tx.wit.vtxinwit.append(deepcopy(tx.wit.vtxinwit[0]))
185          tx.vin[0].prevout = COutPoint(hash=int(txid_0, 16), n=0)
186          tx.vin[1].prevout = COutPoint(hash=int(txid_1, 16), n=0)
187          tx.vout[0].nValue = int(0.1 * COIN)
188          raw_tx_spend_both = tx.serialize().hex()
189          txid_spend_both = self.wallet.sendrawtransaction(from_node=node, tx_hex=raw_tx_spend_both)
190          self.generate(node, 1)
191          self.mempool_size = 0
192          # Now see if we can add the coins back to the utxo set by sending the exact txs again
193          self.check_mempool_result(
194              result_expected=[{'txid': txid_0, 'allowed': False, 'reject-reason': 'missing-inputs'}],
195              rawtxs=[raw_tx_0],
196          )
197          self.check_mempool_result(
198              result_expected=[{'txid': txid_1, 'allowed': False, 'reject-reason': 'missing-inputs'}],
199              rawtxs=[raw_tx_1],
200          )
201  
202          self.log.info('Create a "reference" tx for later use')
203          utxo_to_spend = self.wallet.get_utxo(txid=txid_spend_both)
204          tx = self.wallet.create_self_transfer(utxo_to_spend=utxo_to_spend, sequence=SEQUENCE_FINAL)['tx']
205          tx.vout[0].nValue = int(0.05 * COIN)
206          raw_tx_reference = tx.serialize().hex()
207          # Reference tx should be valid on itself
208          self.check_mempool_result(
209              result_expected=[{'txid': tx.rehash(), 'allowed': True, 'vsize': tx.get_vsize(), 'fees': { 'base': Decimal('0.1') - Decimal('0.05')}}],
210              rawtxs=[tx.serialize().hex()],
211              maxfeerate=0,
212          )
213  
214          self.log.info('A transaction with no outputs')
215          tx = tx_from_hex(raw_tx_reference)
216          tx.vout = []
217          self.check_mempool_result(
218              result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'bad-txns-vout-empty'}],
219              rawtxs=[tx.serialize().hex()],
220          )
221  
222          self.log.info('A really large transaction')
223          tx = tx_from_hex(raw_tx_reference)
224          tx.vin = [tx.vin[0]] * math.ceil((MAX_BLOCK_WEIGHT // WITNESS_SCALE_FACTOR) / len(tx.vin[0].serialize()))
225          self.check_mempool_result(
226              result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'bad-txns-oversize'}],
227              rawtxs=[tx.serialize().hex()],
228          )
229  
230          self.log.info('A transaction with negative output value')
231          tx = tx_from_hex(raw_tx_reference)
232          tx.vout[0].nValue *= -1
233          self.check_mempool_result(
234              result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'bad-txns-vout-negative'}],
235              rawtxs=[tx.serialize().hex()],
236          )
237  
238          # The following two validations prevent overflow of the output amounts (see CVE-2010-5139).
239          self.log.info('A transaction with too large output value')
240          tx = tx_from_hex(raw_tx_reference)
241          tx.vout[0].nValue = MAX_MONEY + 1
242          self.check_mempool_result(
243              result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'bad-txns-vout-toolarge'}],
244              rawtxs=[tx.serialize().hex()],
245          )
246  
247          self.log.info('A transaction with too large sum of output values')
248          tx = tx_from_hex(raw_tx_reference)
249          tx.vout = [tx.vout[0]] * 2
250          tx.vout[0].nValue = MAX_MONEY
251          self.check_mempool_result(
252              result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'bad-txns-txouttotal-toolarge'}],
253              rawtxs=[tx.serialize().hex()],
254          )
255  
256          self.log.info('A transaction with duplicate inputs')
257          tx = tx_from_hex(raw_tx_reference)
258          tx.vin = [tx.vin[0]] * 2
259          self.check_mempool_result(
260              result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'bad-txns-inputs-duplicate'}],
261              rawtxs=[tx.serialize().hex()],
262          )
263  
264          self.log.info('A non-coinbase transaction with coinbase-like outpoint')
265          tx = tx_from_hex(raw_tx_reference)
266          tx.vin.append(CTxIn(COutPoint(hash=0, n=0xffffffff)))
267          self.check_mempool_result(
268              result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'bad-txns-prevout-null'}],
269              rawtxs=[tx.serialize().hex()],
270          )
271  
272          self.log.info('A coinbase transaction')
273          # Pick the input of the first tx we created, so it has to be a coinbase tx
274          sync_txindex(self, node)
275          raw_tx_coinbase_spent = node.getrawtransaction(txid=node.decoderawtransaction(hexstring=raw_tx_in_block)['vin'][0]['txid'])
276          tx = tx_from_hex(raw_tx_coinbase_spent)
277          self.check_mempool_result(
278              result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'coinbase'}],
279              rawtxs=[tx.serialize().hex()],
280          )
281  
282          self.log.info('Some nonstandard transactions')
283          tx = tx_from_hex(raw_tx_reference)
284          tx.version = 4  # A version currently non-standard
285          self.check_mempool_result(
286              result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'version'}],
287              rawtxs=[tx.serialize().hex()],
288          )
289          tx = tx_from_hex(raw_tx_reference)
290          tx.vout[0].scriptPubKey = CScript([OP_0])  # Some non-standard script
291          self.check_mempool_result(
292              result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'scriptpubkey'}],
293              rawtxs=[tx.serialize().hex()],
294          )
295          tx = tx_from_hex(raw_tx_reference)
296          _, pubkey = generate_keypair()
297          tx.vout[0].scriptPubKey = keys_to_multisig_script([pubkey] * 3, k=2)  # Some bare multisig script (2-of-3)
298          self.check_mempool_result(
299              result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'bare-multisig'}],
300              rawtxs=[tx.serialize().hex()],
301          )
302          tx = tx_from_hex(raw_tx_reference)
303          tx.vin[0].scriptSig = CScript([OP_HASH160])  # Some not-pushonly scriptSig
304          self.check_mempool_result(
305              result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'scriptsig-not-pushonly'}],
306              rawtxs=[tx.serialize().hex()],
307          )
308          tx = tx_from_hex(raw_tx_reference)
309          tx.vin[0].scriptSig = CScript([b'a' * 1648]) # Some too large scriptSig (>1650 bytes)
310          self.check_mempool_result(
311              result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'scriptsig-size'}],
312              rawtxs=[tx.serialize().hex()],
313          )
314          tx = tx_from_hex(raw_tx_reference)
315          output_p2sh_burn = CTxOut(nValue=540, scriptPubKey=script_to_p2sh_script(b'burn'))
316          num_scripts = 100000 // len(output_p2sh_burn.serialize())  # Use enough outputs to make the tx too large for our policy
317          tx.vout = [output_p2sh_burn] * num_scripts
318          self.check_mempool_result(
319              result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'tx-size'}],
320              rawtxs=[tx.serialize().hex()],
321          )
322          tx = tx_from_hex(raw_tx_reference)
323          tx.vout[0] = output_p2sh_burn
324          tx.vout[0].nValue -= 1  # Make output smaller, such that it is dust for our policy
325          self.check_mempool_result(
326              result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'dust'}],
327              rawtxs=[tx.serialize().hex()],
328          )
329          tx = tx_from_hex(raw_tx_reference)
330          tx.vout[0].scriptPubKey = CScript([OP_RETURN, b'\xff'])
331          tx.vout = [tx.vout[0]] * 2
332          self.check_mempool_result(
333              result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'multi-op-return'}],
334              rawtxs=[tx.serialize().hex()],
335          )
336  
337          self.log.info('A timelocked transaction')
338          tx = tx_from_hex(raw_tx_reference)
339          tx.vin[0].nSequence -= 1  # Should be non-max, so locktime is not ignored
340          tx.nLockTime = node.getblockcount() + 1
341          self.check_mempool_result(
342              result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'non-final'}],
343              rawtxs=[tx.serialize().hex()],
344          )
345  
346          self.log.info('A transaction that is locked by BIP68 sequence logic')
347          tx = tx_from_hex(raw_tx_reference)
348          tx.vin[0].nSequence = 2  # We could include it in the second block mined from now, but not the very next one
349          self.check_mempool_result(
350              result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'non-BIP68-final'}],
351              rawtxs=[tx.serialize().hex()],
352              maxfeerate=0,
353          )
354  
355          # Prep for tiny-tx tests with wsh(OP_TRUE) output
356          seed_tx = self.wallet.send_to(from_node=node, scriptPubKey=script_to_p2wsh_script(CScript([OP_TRUE])), amount=COIN)
357          self.generate(node, 1)
358  
359          self.log.info('A tiny transaction(in non-witness bytes) that is disallowed')
360          tx = CTransaction()
361          tx.vin.append(CTxIn(COutPoint(int(seed_tx["txid"], 16), seed_tx["sent_vout"]), b"", SEQUENCE_FINAL))
362          tx.wit.vtxinwit = [CTxInWitness()]
363          tx.wit.vtxinwit[0].scriptWitness.stack = [CScript([OP_TRUE])]
364          tx.vout.append(CTxOut(0, CScript([OP_RETURN] + ([OP_0] * (MIN_PADDING - 2)))))
365          # Note it's only non-witness size that matters!
366          assert_equal(len(tx.serialize_without_witness()), 64)
367          assert_equal(MIN_STANDARD_TX_NONWITNESS_SIZE - 1, 64)
368          assert_greater_than(len(tx.serialize()), 64)
369  
370          self.check_mempool_result(
371              result_expected=[{'txid': tx.rehash(), 'allowed': False, 'reject-reason': 'tx-size-small'}],
372              rawtxs=[tx.serialize().hex()],
373              maxfeerate=0,
374          )
375  
376          self.log.info('Minimally-small transaction(in non-witness bytes) that is allowed')
377          tx.vout[0] = CTxOut(COIN - 1000, DUMMY_MIN_OP_RETURN_SCRIPT)
378          assert_equal(len(tx.serialize_without_witness()), MIN_STANDARD_TX_NONWITNESS_SIZE)
379          self.check_mempool_result(
380              result_expected=[{'txid': tx.rehash(), 'allowed': True, 'vsize': tx.get_vsize(), 'fees': { 'base': Decimal('0.00001000')}}],
381              rawtxs=[tx.serialize().hex()],
382              maxfeerate=0,
383          )
384  
385          self.log.info('OP_1 <0x4e73> is able to be created and spent')
386          anchor_value = 10000
387          create_anchor_tx = self.wallet.send_to(from_node=node, scriptPubKey=PAY_TO_ANCHOR, amount=anchor_value)
388          self.generate(node, 1)
389  
390          # First spend has non-empty witness, will be rejected to prevent third party wtxid malleability
391          anchor_nonempty_wit_spend = CTransaction()
392          anchor_nonempty_wit_spend.vin.append(CTxIn(COutPoint(int(create_anchor_tx["txid"], 16), create_anchor_tx["sent_vout"]), b""))
393          anchor_nonempty_wit_spend.vout.append(CTxOut(anchor_value - int(fee*COIN), script_to_p2wsh_script(CScript([OP_TRUE]))))
394          anchor_nonempty_wit_spend.wit.vtxinwit.append(CTxInWitness())
395          anchor_nonempty_wit_spend.wit.vtxinwit[0].scriptWitness.stack.append(b"f")
396          anchor_nonempty_wit_spend.rehash()
397  
398          self.check_mempool_result(
399              result_expected=[{'txid': anchor_nonempty_wit_spend.rehash(), 'allowed': False, 'reject-reason': 'bad-witness-nonstandard'}],
400              rawtxs=[anchor_nonempty_wit_spend.serialize().hex()],
401              maxfeerate=0,
402          )
403  
404          # but is consensus-legal
405          self.generateblock(node, self.wallet.get_address(), [anchor_nonempty_wit_spend.serialize().hex()])
406  
407          # Without witness elements it is standard
408          create_anchor_tx = self.wallet.send_to(from_node=node, scriptPubKey=PAY_TO_ANCHOR, amount=anchor_value)
409          self.generate(node, 1)
410  
411          anchor_spend = CTransaction()
412          anchor_spend.vin.append(CTxIn(COutPoint(int(create_anchor_tx["txid"], 16), create_anchor_tx["sent_vout"]), b""))
413          anchor_spend.vout.append(CTxOut(anchor_value - int(fee*COIN), script_to_p2wsh_script(CScript([OP_TRUE]))))
414          anchor_spend.wit.vtxinwit.append(CTxInWitness())
415          # It's "segwit" but txid == wtxid since there is no witness data
416          assert_equal(anchor_spend.rehash(), anchor_spend.getwtxid())
417  
418          self.check_mempool_result(
419              result_expected=[{'txid': anchor_spend.rehash(), 'allowed': True, 'vsize': anchor_spend.get_vsize(), 'fees': { 'base': Decimal('0.00000700')}}],
420              rawtxs=[anchor_spend.serialize().hex()],
421              maxfeerate=0,
422          )
423  
424          self.log.info('But cannot be spent if nested sh()')
425          nested_anchor_tx = self.wallet.create_self_transfer(sequence=SEQUENCE_FINAL)['tx']
426          nested_anchor_tx.vout[0].scriptPubKey = script_to_p2sh_script(PAY_TO_ANCHOR)
427          nested_anchor_tx.rehash()
428          self.generateblock(node, self.wallet.get_address(), [nested_anchor_tx.serialize().hex()])
429  
430          nested_anchor_spend = CTransaction()
431          nested_anchor_spend.vin.append(CTxIn(COutPoint(nested_anchor_tx.sha256, 0), b""))
432          nested_anchor_spend.vin[0].scriptSig = CScript([bytes(PAY_TO_ANCHOR)])
433          nested_anchor_spend.vout.append(CTxOut(nested_anchor_tx.vout[0].nValue - int(fee*COIN), script_to_p2wsh_script(CScript([OP_TRUE]))))
434          nested_anchor_spend.rehash()
435  
436          self.check_mempool_result(
437              result_expected=[{'txid': nested_anchor_spend.rehash(), 'allowed': False, 'reject-reason': 'non-mandatory-script-verify-flag (Witness version reserved for soft-fork upgrades)'}],
438              rawtxs=[nested_anchor_spend.serialize().hex()],
439              maxfeerate=0,
440          )
441          # but is consensus-legal
442          self.generateblock(node, self.wallet.get_address(), [nested_anchor_spend.serialize().hex()])
443  
444          self.log.info('Spending a confirmed bare multisig is okay')
445          address = self.wallet.get_address()
446          tx = tx_from_hex(raw_tx_reference)
447          privkey, pubkey = generate_keypair()
448          tx.vout[0].scriptPubKey = keys_to_multisig_script([pubkey] * 3, k=1)  # Some bare multisig script (1-of-3)
449          tx.rehash()
450          self.generateblock(node, address, [tx.serialize().hex()])
451          tx_spend = CTransaction()
452          tx_spend.vin.append(CTxIn(COutPoint(tx.sha256, 0), b""))
453          tx_spend.vout.append(CTxOut(tx.vout[0].nValue - int(fee*COIN), script_to_p2wsh_script(CScript([OP_TRUE]))))
454          tx_spend.rehash()
455          sign_input_legacy(tx_spend, 0, tx.vout[0].scriptPubKey, privkey, sighash_type=SIGHASH_ALL)
456          tx_spend.vin[0].scriptSig = bytes(CScript([OP_0])) + tx_spend.vin[0].scriptSig
457          self.check_mempool_result(
458              result_expected=[{'txid': tx_spend.rehash(), 'allowed': True, 'vsize': tx_spend.get_vsize(), 'fees': { 'base': Decimal('0.00000700')}}],
459              rawtxs=[tx_spend.serialize().hex()],
460              maxfeerate=0,
461          )
462  
463  if __name__ == '__main__':
464      MempoolAcceptanceTest(__file__).main()