mempool_accept_wtxid.py raw

   1  #!/usr/bin/env python3
   2  # Copyright (c) 2021-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  """
   6  Test mempool acceptance in case of an already known transaction
   7  with identical non-witness data but different witness.
   8  """
   9  
  10  from test_framework.p2p import P2PTxInvStore
  11  from test_framework.script_util import build_malleated_tx_package
  12  from test_framework.test_framework import BitcoinTestFramework
  13  from test_framework.util import (
  14      assert_not_equal,
  15      assert_equal,
  16  )
  17  from test_framework.wallet import (
  18      MiniWallet,
  19  )
  20  
  21  class MempoolWtxidTest(BitcoinTestFramework):
  22      def set_test_params(self):
  23          self.num_nodes = 1
  24  
  25      def run_test(self):
  26          node = self.nodes[0]
  27          mini_wallet = MiniWallet(node)
  28          self.log.info('Start with pre-generated blocks')
  29  
  30          assert_equal(node.getmempoolinfo()['size'], 0)
  31  
  32          self.log.info("Submit parent with multiple script branches to mempool")
  33  
  34          parent = mini_wallet.create_self_transfer()["tx"]
  35          parent_amount = parent.vout[0].nValue - 10000
  36          child_amount = parent_amount - 10000
  37          parent, child_one, child_two = build_malleated_tx_package(
  38              parent=parent,
  39              rebalance_parent_output_amount=parent_amount,
  40              child_amount=child_amount
  41          )
  42  
  43          mini_wallet.sendrawtransaction(from_node=node, tx_hex=parent.serialize().hex())
  44  
  45          self.generate(node, 1)
  46  
  47          peer_wtxid_relay = node.add_p2p_connection(P2PTxInvStore())
  48  
  49          assert_equal(child_one.txid_hex, child_two.txid_hex)
  50          assert_not_equal(child_one.wtxid_hex, child_two.wtxid_hex)
  51  
  52          self.log.info("Submit child_one to the mempool")
  53          txid_submitted = node.sendrawtransaction(child_one.serialize().hex())
  54          assert_equal(node.getmempoolentry(txid_submitted)['wtxid'], child_one.wtxid_hex)
  55          peer_wtxid_relay.wait_for_broadcast([child_one.wtxid_hex])
  56          assert_equal(node.getmempoolinfo()["unbroadcastcount"], 0)
  57  
  58          # testmempoolaccept reports the "already in mempool" error
  59          assert_equal(node.testmempoolaccept([child_one.serialize().hex()]), [{
  60              "txid": child_one.txid_hex,
  61              "wtxid": child_one.wtxid_hex,
  62              "allowed": False,
  63              "reject-reason": "txn-already-in-mempool",
  64              "reject-details": "txn-already-in-mempool"
  65          }])
  66          assert_equal(node.testmempoolaccept([child_two.serialize().hex()])[0], {
  67              "txid": child_two.txid_hex,
  68              "wtxid": child_two.wtxid_hex,
  69              "allowed": False,
  70              "reject-reason": "txn-same-nonwitness-data-in-mempool",
  71              "reject-details": "txn-same-nonwitness-data-in-mempool"
  72          })
  73  
  74          # sendrawtransaction will not throw but quits early when the exact same transaction is already in mempool
  75          node.sendrawtransaction(child_one.serialize().hex())
  76  
  77          self.log.info("Connect another peer that hasn't seen child_one before")
  78          peer_wtxid_relay_2 = node.add_p2p_connection(P2PTxInvStore())
  79  
  80          self.log.info("Submit child_two to the mempool")
  81          # sendrawtransaction will not throw but quits early when a transaction with the same non-witness data is already in mempool
  82          node.sendrawtransaction(child_two.serialize().hex())
  83  
  84          # The node should rebroadcast the transaction using the wtxid of the correct transaction
  85          # (child_one, which is in its mempool).
  86          peer_wtxid_relay_2.wait_for_broadcast([child_one.wtxid_hex])
  87          assert_equal(node.getmempoolinfo()["unbroadcastcount"], 0)
  88  
  89  if __name__ == '__main__':
  90      MempoolWtxidTest(__file__).main()
  91