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