From db6b6a16f8a380de135480c8d2c10183de6bf846 Mon Sep 17 00:00:00 2001 From: f321x Date: Tue, 27 Jan 2026 12:49:19 +0100 Subject: [PATCH] lnpeermgr: add_peer: fix check if proxy enabled LNPeerManager.add_peer would only check if self.network.proxy is set, which it is always as Network is initialized with self.proxy = ProxySettings(). Instead it should check if proxy is set and enabled. --- electrum/lnworker.py | 2 +- tests/test_lnpeer.py | 3 ++- tests/test_lnpeermgr.py | 60 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 2 deletions(-) create mode 100644 tests/test_lnpeermgr.py diff --git a/electrum/lnworker.py b/electrum/lnworker.py index 4270dad72..f6b503538 100644 --- a/electrum/lnworker.py +++ b/electrum/lnworker.py @@ -588,7 +588,7 @@ class LNPeerManager(Logger, EventListener, NetworkRetryManager[LNPeerAddr]): host, port, timestamp = self.choose_preferred_address(list(addrs)) port = int(port) - if not self.network.proxy: + if not self.network.proxy or not self.network.proxy.enabled: # Try DNS-resolving the host (if needed). This is simply so that # the caller gets a nice exception if it cannot be resolved. # (we don't do the DNS lookup if a proxy is set, to avoid a DNS-leak) diff --git a/tests/test_lnpeer.py b/tests/test_lnpeer.py index 6107a8b49..be4ca3d75 100644 --- a/tests/test_lnpeer.py +++ b/tests/test_lnpeer.py @@ -26,7 +26,7 @@ from electrum import bitcoin from electrum import util from electrum import constants from electrum import bip32 -from electrum.network import Network +from electrum.network import Network, ProxySettings from electrum import simple_config, lnutil from electrum.lnaddr import lnencode, LnAddr, lndecode from electrum.bitcoin import COIN, sha256 @@ -71,6 +71,7 @@ class MockNetwork: self.path_finder = LNPathFinder(self.channel_db) self.lngossip = MockLNGossip() self.tx_queue = asyncio.Queue() + self.proxy = ProxySettings() self._blockchain = MockBlockchain() def get_local_height(self): diff --git a/tests/test_lnpeermgr.py b/tests/test_lnpeermgr.py new file mode 100644 index 000000000..169f7ddc1 --- /dev/null +++ b/tests/test_lnpeermgr.py @@ -0,0 +1,60 @@ +import logging +import os +import socket +import asyncio +from unittest import mock + +from . import ElectrumTestCase + +from electrum.lntransport import ConnStringFormatError +from electrum.logging import console_stderr_handler + + +class TestLNPeerManager(ElectrumTestCase): + TESTNET = True + + @classmethod + def setUpClass(cls): + super().setUpClass() + console_stderr_handler.setLevel(logging.DEBUG) + + async def asyncSetUp(self): + lnwallet = self.create_mock_lnwallet(name='mock_lnwallet_anchors', has_anchors=True) + self.lnpeermgr = lnwallet.lnpeermgr + await super().asyncSetUp() + + async def test_add_peer_conn_string_errors(self): + unknown_node_id = os.urandom(33) + peermgr = self.lnpeermgr + peermgr._add_peer = mock.Mock(side_effect=NotImplementedError) + + # Trampoline enabled, unknown node (no address in trampolines) + channel_db = peermgr.network.channel_db + peermgr.network.channel_db = None + try: + with self.assertRaises(ConnStringFormatError) as cm: + await peermgr.add_peer(unknown_node_id.hex()) + self.assertIn("Address unknown for node", str(cm.exception)) + finally: + peermgr.network.channel_db = channel_db # re-set channel db + + # Trampoline disabled, unknown node (no address in channel_db) + with mock.patch.object(peermgr.network.channel_db, 'get_node_addresses', return_value=[]): + with self.assertRaises(ConnStringFormatError) as cm: + await peermgr.add_peer(unknown_node_id.hex()) + self.assertIn("Don't know any addresses for node", str(cm.exception)) + + # .onion address, but no proxy configured + onion_conn_str = unknown_node_id.hex() + "@somewhere.onion:9735" + self.assertFalse(peermgr.network.proxy.enabled) + with self.assertRaises(ConnStringFormatError) as cm: + await peermgr.add_peer(onion_conn_str) + self.assertIn(".onion address, but no proxy configured", str(cm.exception)) + + # Hostname does not resolve (getaddrinfo failed) + bad_host_conn_str = unknown_node_id.hex() + "@badhost:9735" + loop = asyncio.get_running_loop() + with mock.patch.object(loop, 'getaddrinfo', side_effect=socket.gaierror): + with self.assertRaises(ConnStringFormatError) as cm: + await peermgr.add_peer(bad_host_conn_str) + self.assertIn("Hostname does not resolve", str(cm.exception))