mempool_accept.py raw

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