p2p_v2_encrypted.py
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 # v2 TestNode performs downgrading here 72 self.log.info("Check outbound connection from v2 TestNode to v1 P2PConnection advertised as v2 is v1") 73 peer4 = node0.add_outbound_p2p_connection(P2PInterface(), p2p_idx=1, supports_v2_p2p=False, advertise_v2_p2p=True) 74 assert not peer4.supports_v2_p2p 75 assert_equal(node0.getpeerinfo()[-1]["transport_protocol_type"], "v1") 76 77 self.log.info("Check outbound connection from v2 TestNode to v2 P2PConnection advertised as v2 is v2") 78 peer5 = node0.add_outbound_p2p_connection(P2PInterface(), p2p_idx=2, supports_v2_p2p=True, advertise_v2_p2p=True) 79 assert peer5.supports_v2_p2p 80 assert_equal(node0.getpeerinfo()[-1]["transport_protocol_type"], "v2") 81 82 self.log.info("Check if version is sent and verack is received in inbound/outbound connections") 83 assert_equal(len(node0.getpeerinfo()), 5) # check if above 5 connections are present in node0's getpeerinfo() 84 for peer in node0.getpeerinfo(): 85 assert_greater_than(peer['bytessent_per_msg']['version'], 0) 86 assert_greater_than(peer['bytesrecv_per_msg']['verack'], 0) 87 88 self.log.info("Testing whether blocks propagate - check if tips sync when number of blocks >= REKEY_INTERVAL") 89 # tests whether rekeying (which happens every REKEY_INTERVAL packets) works correctly 90 test_blocks = self.generate_blocks(node0, REKEY_INTERVAL+1) 91 92 for i in range(2): 93 peer6 = node0.add_p2p_connection(P2PDataStore(), supports_v2_p2p=True) 94 assert peer6.supports_v2_p2p 95 assert_equal(node0.getpeerinfo()[-1]["transport_protocol_type"], "v2") 96 97 # Consider: node0 <-- peer6. node0 and node1 aren't connected here. 98 # Construct the following topology: node1 <--> node0 <-- peer6 99 # and test that blocks produced by peer6 will be received by node1 if sent normally 100 # and won't be received by node1 if sent as decoy messages 101 102 # First, check whether blocks produced be peer6 are received by node0 if sent normally 103 # and not received by node0 if sent as decoy messages. 104 if i: 105 # check that node0 receives blocks produced by peer6 106 self.log.info("Check if blocks produced by node0's p2p connection is received by node0") 107 peer6.send_blocks_and_test(test_blocks, node0, success=True) # node0's tip advances 108 else: 109 # check that node0 doesn't receive blocks produced by peer6 since they are sent as decoy messages 110 self.log.info("Check if blocks produced by node0's p2p connection sent as decoys aren't received by node0") 111 peer6.send_blocks_and_test(test_blocks, node0, success=False, is_decoy=True) # node0's tip doesn't advance 112 113 # Then, connect node0 and node1 using v2 and check whether the blocks are received by node1 114 self.connect_nodes(0, 1, peer_advertises_v2=True) 115 self.log.info("Wait for node1 to receive all the blocks from node0") 116 self.sync_all() 117 self.log.info("Make sure node0 and node1 have same block tips") 118 assert_equal(node0.getbestblockhash(), node1.getbestblockhash()) 119 120 self.disconnect_nodes(0, 1) 121 122 self.log.info("Check the connections opened as expected") 123 check_node_connections(node=node0, num_in=4, num_out=3) 124 125 self.log.info("Check inbound connection to v1 TestNode from v2 P2PConnection is v1") 126 self.restart_node(0, ["-v2transport=0"]) 127 peer1 = node0.add_p2p_connection(P2PInterface(), wait_for_verack=True, supports_v2_p2p=True) 128 assert not peer1.supports_v2_p2p 129 assert_equal(node0.getpeerinfo()[-1]["transport_protocol_type"], "v1") 130 check_node_connections(node=node0, num_in=1, num_out=0) 131 132 133 if __name__ == '__main__': 134 P2PEncrypted().main()