Skip to content

Commit ba73735

Browse files
committed
[test] Add functional tests to test v2 P2P behaviour
1 parent 4115cf9 commit ba73735

File tree

2 files changed

+129
-0
lines changed

2 files changed

+129
-0
lines changed

test/functional/p2p_v2_encrypted.py

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
#!/usr/bin/env python3
2+
# Copyright (c) 2022 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 encrypted v2 p2p proposed in BIP 324
7+
"""
8+
from test_framework.blocktools import (
9+
create_block,
10+
create_coinbase,
11+
)
12+
from test_framework.p2p import (
13+
P2PDataStore,
14+
P2PInterface,
15+
)
16+
from test_framework.test_framework import BitcoinTestFramework
17+
from test_framework.util import (
18+
assert_equal,
19+
assert_greater_than,
20+
check_node_connections,
21+
)
22+
from test_framework.crypto.chacha20 import REKEY_INTERVAL
23+
24+
25+
class P2PEncrypted(BitcoinTestFramework):
26+
def set_test_params(self):
27+
self.num_nodes = 2
28+
self.extra_args = [["-v2transport=1"], ["-v2transport=1"]]
29+
30+
def setup_network(self):
31+
self.setup_nodes()
32+
33+
def generate_blocks(self, node, number):
34+
test_blocks = []
35+
last_block = node.getbestblockhash()
36+
tip = int(last_block, 16)
37+
tipheight = node.getblockcount()
38+
last_block_time = node.getblock(last_block)['time']
39+
for _ in range(number):
40+
# Create some blocks
41+
block = create_block(tip, create_coinbase(tipheight + 1), last_block_time + 1)
42+
block.solve()
43+
test_blocks.append(block)
44+
tip = block.sha256
45+
tipheight += 1
46+
last_block_time += 1
47+
return test_blocks
48+
49+
def create_test_block(self, txs):
50+
block = create_block(self.tip, create_coinbase(self.tipheight + 1), self.last_block_time + 600, txlist=txs)
51+
block.solve()
52+
return block
53+
54+
def run_test(self):
55+
node0, node1 = self.nodes[0], self.nodes[1]
56+
self.log.info("Check inbound connection to v2 TestNode from v2 P2PConnection is v2")
57+
peer1 = node0.add_p2p_connection(P2PInterface(), wait_for_verack=True, supports_v2_p2p=True)
58+
assert peer1.supports_v2_p2p
59+
assert_equal(node0.getpeerinfo()[-1]["transport_protocol_type"], "v2")
60+
61+
self.log.info("Check inbound connection to v2 TestNode from v1 P2PConnection is v1")
62+
peer2 = node0.add_p2p_connection(P2PInterface(), wait_for_verack=True, supports_v2_p2p=False)
63+
assert not peer2.supports_v2_p2p
64+
assert_equal(node0.getpeerinfo()[-1]["transport_protocol_type"], "v1")
65+
66+
self.log.info("Check outbound connection from v2 TestNode to v1 P2PConnection advertised as v1 is v1")
67+
peer3 = node0.add_outbound_p2p_connection(P2PInterface(), p2p_idx=0, supports_v2_p2p=False, advertise_v2_p2p=False)
68+
assert not peer3.supports_v2_p2p
69+
assert_equal(node0.getpeerinfo()[-1]["transport_protocol_type"], "v1")
70+
71+
self.log.info("Check outbound connection from v2 TestNode to v2 P2PConnection advertised as v2 is v2")
72+
peer5 = node0.add_outbound_p2p_connection(P2PInterface(), p2p_idx=2, supports_v2_p2p=True, advertise_v2_p2p=True)
73+
assert peer5.supports_v2_p2p
74+
assert_equal(node0.getpeerinfo()[-1]["transport_protocol_type"], "v2")
75+
76+
self.log.info("Check if version is sent and verack is received in inbound/outbound connections")
77+
assert_equal(len(node0.getpeerinfo()), 4) # check if above 4 connections are present in node0's getpeerinfo()
78+
for peer in node0.getpeerinfo():
79+
assert_greater_than(peer['bytessent_per_msg']['version'], 0)
80+
assert_greater_than(peer['bytesrecv_per_msg']['verack'], 0)
81+
82+
self.log.info("Testing whether blocks propagate - check if tips sync when number of blocks >= REKEY_INTERVAL")
83+
# tests whether rekeying (which happens every REKEY_INTERVAL packets) works correctly
84+
test_blocks = self.generate_blocks(node0, REKEY_INTERVAL+1)
85+
86+
for i in range(2):
87+
peer6 = node0.add_p2p_connection(P2PDataStore(), supports_v2_p2p=True)
88+
assert peer6.supports_v2_p2p
89+
assert_equal(node0.getpeerinfo()[-1]["transport_protocol_type"], "v2")
90+
91+
# Consider: node0 <-- peer6. node0 and node1 aren't connected here.
92+
# Construct the following topology: node1 <--> node0 <-- peer6
93+
# and test that blocks produced by peer6 will be received by node1 if sent normally
94+
# and won't be received by node1 if sent as decoy messages
95+
96+
# First, check whether blocks produced be peer6 are received by node0 if sent normally
97+
# and not received by node0 if sent as decoy messages.
98+
if i:
99+
# check that node0 receives blocks produced by peer6
100+
self.log.info("Check if blocks produced by node0's p2p connection is received by node0")
101+
peer6.send_blocks_and_test(test_blocks, node0, success=True) # node0's tip advances
102+
else:
103+
# check that node0 doesn't receive blocks produced by peer6 since they are sent as decoy messages
104+
self.log.info("Check if blocks produced by node0's p2p connection sent as decoys aren't received by node0")
105+
peer6.send_blocks_and_test(test_blocks, node0, success=False, is_decoy=True) # node0's tip doesn't advance
106+
107+
# Then, connect node0 and node1 using v2 and check whether the blocks are received by node1
108+
self.connect_nodes(0, 1, peer_advertises_v2=True)
109+
self.log.info("Wait for node1 to receive all the blocks from node0")
110+
self.sync_all()
111+
self.log.info("Make sure node0 and node1 have same block tips")
112+
assert_equal(node0.getbestblockhash(), node1.getbestblockhash())
113+
114+
self.disconnect_nodes(0, 1)
115+
116+
self.log.info("Check the connections opened as expected")
117+
check_node_connections(node=node0, num_in=4, num_out=2)
118+
119+
self.log.info("Check inbound connection to v1 TestNode from v2 P2PConnection is v1")
120+
self.restart_node(0, ["-v2transport=0"])
121+
peer1 = node0.add_p2p_connection(P2PInterface(), wait_for_verack=True, supports_v2_p2p=True)
122+
assert not peer1.supports_v2_p2p
123+
assert_equal(node0.getpeerinfo()[-1]["transport_protocol_type"], "v1")
124+
check_node_connections(node=node0, num_in=1, num_out=0)
125+
126+
127+
if __name__ == '__main__':
128+
P2PEncrypted().main()

test/functional/test_runner.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,7 @@
259259
'p2p_invalid_tx.py',
260260
'p2p_invalid_tx.py --v2transport',
261261
'p2p_v2_transport.py',
262+
'p2p_v2_encrypted.py',
262263
'example_test.py',
263264
'wallet_txn_doublespend.py --legacy-wallet',
264265
'wallet_multisig_descriptor_psbt.py --descriptors',

0 commit comments

Comments
 (0)