p2p_tx_privacy.py raw

   1  #!/usr/bin/env python3
   2  # Copyright (c) 2022-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 that transaction announcements are only queued for peers that have
   7  successfully completed the version handshake.
   8  
   9  Topology:
  10  
  11    tx_originator ----> node[0] <---- spy
  12  
  13  We test that a transaction sent by tx_originator is only relayed to spy
  14  if it was received after spy's version handshake completed.
  15  
  16  1. Fully connect tx_originator
  17  2. Connect spy (no version handshake)
  18  3. tx_originator sends tx1
  19  4. spy completes the version handshake
  20  5. tx_originator sends tx2
  21  6. We check that only tx2 is announced on the spy interface
  22  """
  23  from test_framework.messages import (
  24      msg_wtxidrelay,
  25      msg_verack,
  26      msg_tx,
  27      CInv,
  28      MSG_WTX,
  29  )
  30  from test_framework.p2p import (
  31      P2PInterface,
  32  )
  33  from test_framework.test_framework import BitcoinTestFramework
  34  from test_framework.wallet import MiniWallet
  35  
  36  class P2PTxSpy(P2PInterface):
  37      def __init__(self):
  38          super().__init__()
  39          self.all_invs = []
  40  
  41      def on_version(self, message):
  42          self.send_without_ping(msg_wtxidrelay())
  43  
  44      def on_inv(self, message):
  45          self.all_invs += message.inv
  46  
  47      def wait_for_inv_match(self, expected_inv):
  48          self.wait_until(lambda: len(self.all_invs) == 1 and self.all_invs[0] == expected_inv)
  49  
  50  class TxPrivacyTest(BitcoinTestFramework):
  51      def set_test_params(self):
  52          self.num_nodes = 1
  53  
  54      def run_test(self):
  55          self.wallet = MiniWallet(self.nodes[0])
  56  
  57          tx_originator = self.nodes[0].add_p2p_connection(P2PInterface())
  58          spy = self.nodes[0].add_p2p_connection(P2PTxSpy(), wait_for_verack=False)
  59          spy.wait_for_verack()
  60  
  61          # tx_originator sends tx1
  62          tx1 = self.wallet.create_self_transfer()["tx"]
  63          tx_originator.send_and_ping(msg_tx(tx1))
  64  
  65          # Spy sends the verack
  66          spy.send_and_ping(msg_verack())
  67  
  68          # tx_originator sends tx2
  69          tx2 = self.wallet.create_self_transfer()["tx"]
  70          tx_originator.send_and_ping(msg_tx(tx2))
  71  
  72          # Spy should only get an inv for the second transaction as the first
  73          # one was received pre-verack with the spy
  74          spy.wait_for_inv_match(CInv(MSG_WTX, tx2.wtxid_int))
  75  
  76  if __name__ == '__main__':
  77      TxPrivacyTest(__file__).main()
  78