p2p_tx_privacy.py
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()