p2p_private_broadcast.py
1 #!/usr/bin/env python3 2 # Copyright (c) 2017-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 how locally submitted transactions are sent to the network when private broadcast is used. 7 """ 8 9 import re 10 import time 11 import threading 12 13 from test_framework.p2p import ( 14 P2PDataStore, 15 P2PInterface, 16 P2P_SERVICES, 17 P2P_VERSION, 18 ) 19 from test_framework.messages import ( 20 CAddress, 21 CInv, 22 MSG_WTX, 23 malleate_tx_to_invalid_witness, 24 msg_inv, 25 msg_tx, 26 ) 27 from test_framework.netutil import ( 28 format_addr_port 29 ) 30 from test_framework.script_util import build_malleated_tx_package 31 from test_framework.socks5 import ( 32 Socks5Configuration, 33 Socks5Server, 34 ) 35 from test_framework.test_framework import ( 36 BitcoinTestFramework, 37 ) 38 from test_framework.util import ( 39 assert_equal, 40 assert_greater_than_or_equal, 41 assert_not_equal, 42 assert_raises_rpc_error, 43 p2p_port, 44 tor_port, 45 ) 46 from test_framework.wallet import ( 47 MiniWallet, 48 ) 49 50 NUM_PRIVATE_BROADCAST_PER_TX = 3 51 52 # Fill addrman with these addresses. Must have enough Tor addresses, so that even 53 # if all 10 default connections are opened to a Tor address (!?) there must be more 54 # for private broadcast. 55 ADDRMAN_ADDRESSES = [ 56 "20.0.0.1", 57 "30.0.0.1", 58 "40.0.0.1", 59 "50.0.0.1", 60 "60.0.0.1", 61 "70.0.0.1", 62 "80.0.0.1", 63 "90.0.0.1", 64 "100.0.0.1", 65 "110.0.0.1", 66 "120.0.0.1", 67 "130.0.0.1", 68 "140.0.0.1", 69 "150.0.0.1", 70 "160.0.0.1", 71 "170.0.0.1", 72 "180.0.0.1", 73 "190.0.0.1", 74 "200.0.0.1", 75 "210.0.0.1", 76 77 "[20::1]", 78 "[30::1]", 79 "[40::1]", 80 "[50::1]", 81 "[60::1]", 82 "[70::1]", 83 "[80::1]", 84 "[90::1]", 85 "[100::1]", 86 "[110::1]", 87 "[120::1]", 88 "[130::1]", 89 "[140::1]", 90 "[150::1]", 91 "[160::1]", 92 "[170::1]", 93 "[180::1]", 94 "[190::1]", 95 "[200::1]", 96 "[210::1]", 97 98 "testonlyad777777777777777777777777777777777777777775b6qd.onion", 99 "testonlyah77777777777777777777777777777777777777777z7ayd.onion", 100 "testonlyal77777777777777777777777777777777777777777vp6qd.onion", 101 "testonlyap77777777777777777777777777777777777777777r5qad.onion", 102 "testonlyat77777777777777777777777777777777777777777udsid.onion", 103 "testonlyax77777777777777777777777777777777777777777yciid.onion", 104 "testonlya777777777777777777777777777777777777777777rhgyd.onion", 105 "testonlybd77777777777777777777777777777777777777777rs4ad.onion", 106 "testonlybp77777777777777777777777777777777777777777zs2ad.onion", 107 "testonlybt777777777777777777777777777777777777777777x6id.onion", 108 "testonlybx777777777777777777777777777777777777777775styd.onion", 109 "testonlyb3777777777777777777777777777777777777777774ckid.onion", 110 "testonlycd77777777777777777777777777777777777777777733id.onion", 111 "testonlych77777777777777777777777777777777777777777t6kid.onion", 112 "testonlycl77777777777777777777777777777777777777777tt3ad.onion", 113 "testonlyct77777777777777777777777777777777777777777wvhyd.onion", 114 "testonlycx7777777777777777777777777777777777777777774bad.onion", 115 "testonlyc377777777777777777777777777777777777777777u6aid.onion", 116 "testonlydd777777777777777777777777777777777777777777u5ad.onion", 117 "testonlydh77777777777777777777777777777777777777777wgnyd.onion", 118 119 "testonlyad77777777777777777777777777777777777777777q.b32.i2p", 120 "testonlyah77777777777777777777777777777777777777777q.b32.i2p", 121 "testonlyap77777777777777777777777777777777777777777q.b32.i2p", 122 "testonlyat77777777777777777777777777777777777777777q.b32.i2p", 123 "testonlyax77777777777777777777777777777777777777777q.b32.i2p", 124 "testonlya377777777777777777777777777777777777777777q.b32.i2p", 125 "testonlya777777777777777777777777777777777777777777q.b32.i2p", 126 "testonlybd77777777777777777777777777777777777777777q.b32.i2p", 127 "testonlybh77777777777777777777777777777777777777777q.b32.i2p", 128 "testonlybl77777777777777777777777777777777777777777q.b32.i2p", 129 "testonlybp77777777777777777777777777777777777777777q.b32.i2p", 130 "testonlybt77777777777777777777777777777777777777777q.b32.i2p", 131 "testonlybx77777777777777777777777777777777777777777q.b32.i2p", 132 "testonlyb777777777777777777777777777777777777777777q.b32.i2p", 133 "testonlych77777777777777777777777777777777777777777q.b32.i2p", 134 "testonlycp77777777777777777777777777777777777777777q.b32.i2p", 135 "testonlyct77777777777777777777777777777777777777777q.b32.i2p", 136 "testonlycx77777777777777777777777777777777777777777q.b32.i2p", 137 "testonlyc377777777777777777777777777777777777777777q.b32.i2p", 138 "testonlyc777777777777777777777777777777777777777777q.b32.i2p", 139 140 "[fc00::1]", 141 "[fc00::2]", 142 "[fc00::3]", 143 "[fc00::5]", 144 "[fc00::6]", 145 "[fc00::7]", 146 "[fc00::8]", 147 "[fc00::9]", 148 "[fc00::10]", 149 "[fc00::11]", 150 "[fc00::12]", 151 "[fc00::13]", 152 "[fc00::15]", 153 "[fc00::16]", 154 "[fc00::17]", 155 "[fc00::18]", 156 "[fc00::19]", 157 "[fc00::20]", 158 "[fc00::22]", 159 "[fc00::23]", 160 ] 161 162 163 class P2PPrivateBroadcast(BitcoinTestFramework): 164 def set_test_params(self): 165 self.disable_autoconnect = False 166 self.num_nodes = 2 167 168 def setup_nodes(self): 169 # Start a SOCKS5 proxy server. 170 socks5_server_config = Socks5Configuration() 171 # self.nodes[0] listens on p2p_port(0), 172 # self.nodes[1] listens on p2p_port(1), 173 # thus we tell the SOCKS5 server to listen on p2p_port(self.num_nodes) (self.num_nodes is 2) 174 socks5_server_config.addr = ("127.0.0.1", p2p_port(self.num_nodes)) 175 socks5_server_config.unauth = True 176 socks5_server_config.auth = True 177 178 self.socks5_server = Socks5Server(socks5_server_config) 179 self.socks5_server.start() 180 181 self.destinations = [] 182 183 self.destinations_lock = threading.Lock() 184 185 def find_connection_type_in_debug_log(to_addr, to_port): 186 """ 187 Scan the debug log of tx_originator for a connection attempt to to_addr:to_port. 188 Return the connection type (outbound-full-relay, private-broadcast, etc) or 189 None if there is no connection attempt to to_addr:to_port. 190 """ 191 with open(self.tx_originator_debug_log_path, mode="r", encoding="utf-8") as debug_log: 192 for line in debug_log.readlines(): 193 match = re.match(f".*trying v. connection \\((.+)\\) to \\[?{to_addr}]?:{to_port},.*", line) 194 if match: 195 return match.group(1) 196 return None 197 198 def destinations_factory(requested_to_addr, requested_to_port): 199 """ 200 Instruct the SOCKS5 proxy to redirect connections: 201 * The first automatic outbound connection -> P2PDataStore 202 * The first private broadcast connection -> nodes[1] 203 * Anything else -> P2PInterface 204 """ 205 conn_type = None 206 def found_connection_in_debug_log(): 207 nonlocal conn_type 208 conn_type = find_connection_type_in_debug_log(requested_to_addr, requested_to_port) 209 return conn_type is not None 210 211 self.wait_until(found_connection_in_debug_log) 212 213 with self.destinations_lock: 214 i = len(self.destinations) 215 actual_to_addr = "" 216 actual_to_port = 0 217 listener = None 218 target_name = "" 219 if conn_type == "private-broadcast" and not any(dest["conn_type"] == "private-broadcast" for dest in self.destinations): 220 # Instruct the SOCKS5 server to redirect the first private 221 # broadcast connection from nodes[0] to nodes[1] 222 actual_to_addr = "127.0.0.1" # nodes[1] listen address 223 actual_to_port = tor_port(1) # nodes[1] listen port for Tor 224 target_name = "nodes[1]" 225 else: 226 # Create a Python P2P listening node and instruct the SOCKS5 proxy to 227 # redirect the connection to it. The first outbound connection is used 228 # later to serve GETDATA, thus make it P2PDataStore(). 229 if conn_type == "outbound-full-relay" and not any(dest["conn_type"] == "outbound-full-relay" for dest in self.destinations): 230 listener = P2PDataStore() 231 target_name = "Python P2PDataStore" 232 else: 233 listener = P2PInterface() 234 target_name = "Python P2PInterface" 235 listener.peer_connect_helper(dstaddr="0.0.0.0", dstport=0, net=self.chain, timeout_factor=self.options.timeout_factor) 236 listener.peer_connect_send_version(services=P2P_SERVICES) 237 238 def on_listen_done(addr, port): 239 nonlocal actual_to_addr 240 nonlocal actual_to_port 241 actual_to_addr = addr 242 actual_to_port = port 243 244 # Use port=0 to let the OS assign an available port. This 245 # avoids "address already in use" errors when tests run 246 # concurrently or ports are still in TIME_WAIT state. 247 self.network_thread.listen( 248 addr="127.0.0.1", 249 port=0, 250 p2p=listener, 251 callback=on_listen_done) 252 # Wait until the callback has been called. 253 self.wait_until(lambda: actual_to_port != 0) 254 255 self.log.debug(f"Instructing the SOCKS5 proxy to redirect connection i={i} ({conn_type}) for " 256 f"{format_addr_port(requested_to_addr, requested_to_port)} to " 257 f"{format_addr_port(actual_to_addr, actual_to_port)} ({target_name})") 258 259 self.destinations.append({ 260 "requested_to": format_addr_port(requested_to_addr, requested_to_port), 261 "conn_type": conn_type, 262 "node": listener, 263 }) 264 assert_equal(len(self.destinations), i + 1) 265 266 return { 267 "actual_to_addr": actual_to_addr, 268 "actual_to_port": actual_to_port, 269 } 270 271 self.socks5_server.conf.destinations_factory = destinations_factory 272 273 self.extra_args = [ 274 [ 275 # Needed to be able to add CJDNS addresses to addrman (otherwise they are unroutable). 276 "-cjdnsreachable", 277 # Connecting, sending garbage, being disconnected messes up with this test's 278 # check_broadcasts() which waits for a particular Python node to receive a connection. 279 "-v2transport=0", 280 "-test=addrman", 281 "-privatebroadcast", 282 f"-proxy={socks5_server_config.addr[0]}:{socks5_server_config.addr[1]}", 283 # To increase coverage, make it think that the I2P network is reachable so that it 284 # selects such addresses as well. Pick a proxy address where nobody is listening 285 # and connection attempts fail quickly. 286 "-i2psam=127.0.0.1:1", 287 ], 288 [ 289 "-connect=0", 290 f"-bind=127.0.0.1:{tor_port(1)}=onion", 291 ], 292 ] 293 super().setup_nodes() 294 295 def setup_network(self): 296 self.setup_nodes() 297 298 def check_broadcasts(self, label, tx, broadcasts_to_expect, skip_destinations): 299 def wait_and_get_destination(n): 300 """Wait for self.destinations[] to have at least n elements and return the 'n'th.""" 301 def get_destinations_len(): 302 with self.destinations_lock: 303 return len(self.destinations) 304 self.wait_until(lambda: get_destinations_len() > n) 305 with self.destinations_lock: 306 return self.destinations[n] 307 308 broadcasts_done = 0 309 i = skip_destinations - 1 310 while broadcasts_done < broadcasts_to_expect: 311 i += 1 312 self.log.debug(f"{label}: waiting for outbound connection i={i}") 313 # At this point the connection may not yet have been established (A), 314 # may be active (B), or may have already been closed (C). 315 dest = wait_and_get_destination(i) 316 peer = dest["node"] 317 if peer is None: 318 continue # That is the first private broadcast connection, redirected to nodes[1] 319 peer.wait_until(lambda: peer.message_count["version"] == 1, check_connected=False) 320 # Now it is either (B) or (C). 321 if peer.last_message["version"].nServices != 0: 322 self.log.debug(f"{label}: outbound connection i={i} to {dest['requested_to']} not a private broadcast, ignoring it (maybe feeler or extra block only)") 323 continue 324 self.log.debug(f"{label}: outbound connection i={i} to {dest['requested_to']} must be a private broadcast, checking it") 325 peer.wait_for_disconnect() 326 # Now it is (C). 327 assert_equal(peer.message_count, { 328 "version": 1, 329 "verack": 1, 330 "inv": 1, 331 "tx": 1, 332 "ping": 1 333 }) 334 dummy_address = CAddress() 335 dummy_address.nServices = 0 336 assert_equal(peer.last_message["version"].nVersion, P2P_VERSION) 337 assert_equal(peer.last_message["version"].nServices, 0) 338 assert_equal(peer.last_message["version"].nTime, 0) 339 assert_equal(peer.last_message["version"].addrTo, dummy_address) 340 assert_equal(peer.last_message["version"].addrFrom, dummy_address) 341 assert_equal(peer.last_message["version"].strSubVer, "/pynode:0.0.1/") 342 assert_equal(peer.last_message["version"].nStartingHeight, 0) 343 assert_equal(peer.last_message["version"].relay, 0) 344 assert_equal(peer.last_message["tx"].tx.txid_hex, tx["txid"]) 345 self.log.info(f"{label}: ok: outbound connection i={i} is private broadcast of txid={tx['txid']}") 346 broadcasts_done += 1 347 348 # Verify the tx we just observed is tracked in getprivatebroadcastinfo. 349 pbinfo = self.nodes[0].getprivatebroadcastinfo() 350 pending = [t for t in pbinfo["transactions"] if t["txid"] == tx["txid"] and t["wtxid"] == tx["wtxid"]] 351 assert_equal(len(pending), 1) 352 assert_equal(pending[0]["hex"].lower(), tx["hex"].lower()) 353 peers = pending[0]["peers"] 354 assert len(peers) >= NUM_PRIVATE_BROADCAST_PER_TX 355 assert all("address" in p and "sent" in p for p in peers) 356 assert_greater_than_or_equal(sum(1 for p in peers if "received" in p), broadcasts_to_expect) 357 358 def run_test(self): 359 tx_originator = self.nodes[0] 360 self.tx_originator_debug_log_path = tx_originator.debug_log_path 361 tx_receiver = self.nodes[1] 362 far_observer = tx_receiver.add_p2p_connection(P2PInterface()) 363 364 wallet = MiniWallet(tx_originator) 365 366 # Fill tx_originator's addrman. 367 for addr in ADDRMAN_ADDRESSES: 368 res = tx_originator.addpeeraddress(address=addr, port=0 if addr.endswith(".i2p") else 8333, tried=False) 369 if not res["success"]: 370 self.log.debug(f"Could not add {addr} to tx_originator's addrman (collision?)") 371 372 txs = wallet.create_self_transfer_chain(chain_length=3) 373 self.log.info(f"Created txid={txs[0]['txid']}: for basic test") 374 self.log.info(f"Created txid={txs[1]['txid']}: for broadcast with dependency in mempool + rebroadcast") 375 self.log.info(f"Created txid={txs[2]['txid']}: for broadcast with dependency not in mempool") 376 tx_originator.sendrawtransaction(hexstring=txs[0]["hex"], maxfeerate=0.1) 377 378 self.log.info("First private broadcast: waiting for the transaction to reach the recipient") 379 self.wait_until(lambda: len(tx_receiver.getrawmempool()) > 0) 380 self.log.info("First private broadcast: the recipient received the transaction") 381 far_observer.wait_for_tx(txs[0]["txid"]) 382 self.log.info("First private broadcast: the recipient further relayed the transaction") 383 384 # One already checked above, check the other NUM_PRIVATE_BROADCAST_PER_TX - 1 broadcasts. 385 self.check_broadcasts("Basic", txs[0], NUM_PRIVATE_BROADCAST_PER_TX - 1, 0) 386 387 self.log.info("Resending the same transaction via RPC again (it is not in the mempool yet)") 388 ignoring_msg = f"Ignoring unnecessary request to schedule an already scheduled transaction: txid={txs[0]['txid']}, wtxid={txs[0]['wtxid']}" 389 with tx_originator.busy_wait_for_debug_log(expected_msgs=[ignoring_msg.encode()]): 390 tx_originator.sendrawtransaction(hexstring=txs[0]["hex"], maxfeerate=0) 391 392 self.log.info("Sending a malleated transaction with an invalid witness via RPC") 393 malleated_invalid = malleate_tx_to_invalid_witness(txs[0]) 394 assert_raises_rpc_error(-26, "mempool-script-verify-flag-failed", 395 tx_originator.sendrawtransaction, 396 hexstring=malleated_invalid.serialize_with_witness().hex(), 397 maxfeerate=0.1) 398 399 self.log.info("Checking that the transaction is not in the originator node's mempool") 400 assert_equal(len(tx_originator.getrawmempool()), 0) 401 402 wtxid_int = int(txs[0]["wtxid"], 16) 403 inv = CInv(MSG_WTX, wtxid_int) 404 405 tx_returner = None # First outbound-full-relay, will be P2PDataStore. 406 other_peer = None # Any other outbound-full-relay, we use the second one. 407 408 def set_tx_returner_and_other(): 409 nonlocal tx_returner 410 nonlocal other_peer 411 tx_returner = None 412 other_peer = None 413 with self.destinations_lock: 414 for dest in self.destinations: 415 if dest["conn_type"] == "outbound-full-relay" and dest["node"] is not None: 416 if tx_returner is None: 417 assert(type(dest["node"]) is P2PDataStore) 418 tx_returner = dest["node"] 419 else: 420 assert(type(dest["node"]) is P2PInterface) 421 other_peer = dest["node"] 422 return True 423 return False 424 425 self.wait_until(set_tx_returner_and_other) 426 427 tx_returner.wait_for_connect() 428 other_peer.wait_for_connect() 429 430 self.log.info("Sending INV and waiting for GETDATA from node") 431 tx_returner.tx_store[wtxid_int] = txs[0]["tx"] 432 assert "getdata" not in tx_returner.last_message 433 received_back_msg = f"Received our privately broadcast transaction (txid={txs[0]['txid']}) from the network" 434 with tx_originator.assert_debug_log(expected_msgs=[received_back_msg]): 435 tx_returner.send_without_ping(msg_inv([inv])) 436 tx_returner.wait_until(lambda: "getdata" in tx_returner.last_message) 437 self.wait_until(lambda: len(tx_originator.getrawmempool()) > 0) 438 439 self.log.info("Waiting for normal broadcast to another peer") 440 other_peer.wait_for_inv([inv]) 441 442 self.log.info("Checking getprivatebroadcastinfo no longer reports the transaction after it is received back") 443 pbinfo = tx_originator.getprivatebroadcastinfo() 444 pending = [t for t in pbinfo["transactions"] if t["txid"] == txs[0]["txid"] and t["wtxid"] == txs[0]["wtxid"]] 445 assert_equal(len(pending), 0) 446 447 self.log.info("Sending a transaction that is already in the mempool") 448 skip_destinations = len(self.destinations) 449 tx_originator.sendrawtransaction(hexstring=txs[0]["hex"], maxfeerate=0) 450 self.check_broadcasts("Broadcast of mempool transaction", txs[0], NUM_PRIVATE_BROADCAST_PER_TX, skip_destinations) 451 452 self.log.info("Sending a transaction with a dependency in the mempool") 453 skip_destinations = len(self.destinations) 454 tx_originator.sendrawtransaction(hexstring=txs[1]["hex"], maxfeerate=0.1) 455 self.check_broadcasts("Dependency in mempool", txs[1], NUM_PRIVATE_BROADCAST_PER_TX, skip_destinations) 456 457 self.log.info("Sending a transaction with a dependency not in the mempool (should be rejected)") 458 assert_equal(len(tx_originator.getrawmempool()), 1) 459 assert_raises_rpc_error(-25, "bad-txns-inputs-missingorspent", 460 tx_originator.sendrawtransaction, hexstring=txs[2]["hex"], maxfeerate=0.1) 461 assert_raises_rpc_error(-25, "bad-txns-inputs-missingorspent", 462 tx_originator.sendrawtransaction, hexstring=txs[2]["hex"], maxfeerate=0) 463 464 # Since txs[1] has not been received back by tx_originator, 465 # it should be re-broadcast after a while. Advance tx_originator's clock 466 # to trigger a re-broadcast. Should be more than the maximum returned by 467 # NextTxBroadcast() in net_processing.cpp. 468 self.log.info("Checking that rebroadcast works") 469 delta = 20 * 60 # 20min 470 skip_destinations = len(self.destinations) 471 rebroadcast_msg = f"Reattempting broadcast of stale txid={txs[1]['txid']}" 472 with tx_originator.busy_wait_for_debug_log(expected_msgs=[rebroadcast_msg.encode()]): 473 tx_originator.setmocktime(int(time.time()) + delta) 474 tx_originator.mockscheduler(delta) 475 self.check_broadcasts("Rebroadcast", txs[1], 1, skip_destinations) 476 tx_originator.setmocktime(0) # Let the clock tick again (it will go backwards due to this). 477 478 self.log.info("Sending a pair of transactions with the same txid but different valid wtxids via RPC") 479 parent = wallet.create_self_transfer()["tx"] 480 parent_amount = parent.vout[0].nValue - 10000 481 child_amount = parent_amount - 10000 482 siblings_parent, sibling1, sibling2 = build_malleated_tx_package( 483 parent=parent, 484 rebalance_parent_output_amount=parent_amount, 485 child_amount=child_amount) 486 self.log.info(f" - sibling1: txid={sibling1.txid_hex}, wtxid={sibling1.wtxid_hex}") 487 self.log.info(f" - sibling2: txid={sibling2.txid_hex}, wtxid={sibling2.wtxid_hex}") 488 assert_equal(sibling1.txid_hex, sibling2.txid_hex) 489 assert_not_equal(sibling1.wtxid_hex, sibling2.wtxid_hex) 490 assert_equal(len(tx_originator.getrawmempool()), 1) 491 tx_returner.send_without_ping(msg_tx(siblings_parent)) 492 self.wait_until(lambda: len(tx_originator.getrawmempool()) > 1) 493 self.log.info(" - siblings' parent added to the mempool") 494 tx_originator.sendrawtransaction(hexstring=sibling1.serialize_with_witness().hex(), maxfeerate=0.1) 495 self.log.info(" - sent sibling1: ok") 496 tx_originator.sendrawtransaction(hexstring=sibling2.serialize_with_witness().hex(), maxfeerate=0.1) 497 self.log.info(" - sent sibling2: ok") 498 499 self.log.info("Checking abortprivatebroadcast removes a pending private-broadcast transaction") 500 tx_abort = wallet.create_self_transfer() 501 tx_originator.sendrawtransaction(hexstring=tx_abort["hex"], maxfeerate=0.1) 502 assert tx_abort["wtxid"] in [t["wtxid"] for t in tx_originator.getprivatebroadcastinfo()["transactions"]] 503 abort_res = tx_originator.abortprivatebroadcast(tx_abort["txid"]) 504 assert_equal(len(abort_res["removed_transactions"]), 1) 505 assert_equal(abort_res["removed_transactions"][0]["txid"], tx_abort["txid"]) 506 assert_equal(abort_res["removed_transactions"][0]["wtxid"], tx_abort["wtxid"]) 507 assert_equal(abort_res["removed_transactions"][0]["hex"].lower(), tx_abort["hex"].lower()) 508 assert all(t["wtxid"] != tx_abort["wtxid"] for t in tx_originator.getprivatebroadcastinfo()["transactions"]) 509 510 self.log.info("Checking abortprivatebroadcast fails for non-existent transaction") 511 assert_raises_rpc_error( 512 -5, 513 "Transaction not in private broadcast queue", 514 tx_originator.abortprivatebroadcast, 515 "0" * 64, 516 ) 517 518 # Stop the SOCKS5 proxy server to avoid it being upset by the bitcoin 519 # node disconnecting in the middle of the SOCKS5 handshake when we 520 # restart below. 521 self.socks5_server.stop() 522 523 self.log.info("Trying to send a transaction when none of Tor or I2P is reachable") 524 self.restart_node(0, extra_args=[ 525 "-privatebroadcast", 526 "-v2transport=0", 527 # A location where definitely a Tor control is not listening. This would allow 528 # Bitcoin Core to start, hoping/assuming that the location of the Tor proxy 529 # may be retrieved after startup from the Tor control, but it will not be, so 530 # the RPC should throw. 531 "-torcontrol=127.0.0.1:1", 532 "-listenonion", 533 ]) 534 assert_raises_rpc_error(-1, "none of the Tor or I2P networks is reachable", 535 tx_originator.sendrawtransaction, hexstring=txs[0]["hex"], maxfeerate=0.1) 536 537 538 if __name__ == "__main__": 539 P2PPrivateBroadcast(__file__).main()