mempool_accept.py raw

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