66
77import os
88
9- from test_framework .p2p import P2PInterface
9+ from test_framework .p2p import P2PInterface , P2P_SERVICES
10+ from test_framework .socks5 import Socks5Configuration , Socks5Server
11+ from test_framework .messages import CAddress , hash256
1012from test_framework .test_framework import BitcoinTestFramework
11- from test_framework .util import check_node_connections
13+ from test_framework .util import check_node_connections , assert_equal , p2p_port
1214
1315INBOUND_CONNECTIONS = 5
1416BLOCK_RELAY_CONNECTIONS = 2
17+ ONION_ADDR = "pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion:8333"
1518
1619
1720class AnchorsTest (BitcoinTestFramework ):
@@ -54,7 +57,7 @@ def run_test(self):
5457 else :
5558 inbound_nodes_port .append (hex (int (addr_split [1 ]))[2 :])
5659
57- self .log .info ("Stop node 0 " )
60+ self .log .debug ("Stop node" )
5861 self .stop_node (0 )
5962
6063 # It should contain only the block-relay-only addresses
@@ -78,12 +81,64 @@ def run_test(self):
7881 tweaked_contents [20 :20 ] = b'1'
7982 out_file_handler .write (bytes (tweaked_contents ))
8083
81- self .log .info ("Start node" )
84+ self .log .debug ("Start node" )
8285 self .start_node (0 )
8386
8487 self .log .info ("When node starts, check if anchors.dat doesn't exist anymore" )
8588 assert not os .path .exists (node_anchors_path )
8689
90+ self .log .info ("Ensure addrv2 support" )
91+ # Use proxies to catch outbound connections to networks with 256-bit addresses
92+ onion_conf = Socks5Configuration ()
93+ onion_conf .auth = True
94+ onion_conf .unauth = True
95+ onion_conf .addr = ('127.0.0.1' , p2p_port (self .num_nodes ))
96+ onion_conf .keep_alive = True
97+ onion_proxy = Socks5Server (onion_conf )
98+ onion_proxy .start ()
99+ self .restart_node (0 , extra_args = [f"-onion={ onion_conf .addr [0 ]} :{ onion_conf .addr [1 ]} " ])
100+
101+ self .log .info ("Add 256-bit-address block-relay-only connections to node" )
102+ self .nodes [0 ].addconnection (ONION_ADDR , 'block-relay-only' )
103+
104+ self .log .debug ("Stop node" )
105+ with self .nodes [0 ].assert_debug_log ([f"DumpAnchors: Flush 1 outbound block-relay-only peer addresses to anchors.dat" ]):
106+ self .stop_node (0 )
107+ # Manually close keep_alive proxy connection
108+ onion_proxy .stop ()
109+
110+ self .log .info ("Check for addrv2 addresses in anchors.dat" )
111+ caddr = CAddress ()
112+ caddr .net = CAddress .NET_TORV3
113+ caddr .ip , port_str = ONION_ADDR .split (":" )
114+ caddr .port = int (port_str )
115+ # TorV3 addrv2 serialization:
116+ # time(4) | services(1) | networkID(1) | address length(1) | address(32)
117+ expected_pubkey = caddr .serialize_v2 ()[7 :39 ].hex ()
118+
119+ # position of services byte of first addr in anchors.dat
120+ # network magic, vector length, version, nTime
121+ services_index = 4 + 1 + 4 + 4
122+ data = bytes ()
123+ with open (node_anchors_path , "rb" ) as file_handler :
124+ data = file_handler .read ()
125+ assert_equal (data [services_index ], 0x00 ) # services == NONE
126+ anchors2 = data .hex ()
127+ assert expected_pubkey in anchors2
128+
129+ with open (node_anchors_path , "wb" ) as file_handler :
130+ # Modify service flags for this address even though we never connected to it.
131+ # This is necessary because on restart we will not attempt an anchor connection
132+ # to a host without our required services, even if its address is in the anchors.dat file
133+ new_data = bytearray (data )[:- 32 ]
134+ new_data [services_index ] = P2P_SERVICES
135+ new_data_hash = hash256 (new_data )
136+ file_handler .write (new_data + new_data_hash )
137+
138+ self .log .info ("Restarting node attempts to reconnect to anchors" )
139+ with self .nodes [0 ].assert_debug_log ([f"Trying to make an anchor connection to { ONION_ADDR } " ]):
140+ self .start_node (0 , extra_args = [f"-onion={ onion_conf .addr [0 ]} :{ onion_conf .addr [1 ]} " ])
141+
87142
88143if __name__ == "__main__" :
89144 AnchorsTest ().main ()
0 commit comments