Commit Graph

297 Commits

Author SHA1 Message Date
f321x
76f69676d3 config/regtest: add config to disable automatic fee updates
Some regtest tests depend on manual fee injection to simulate certain
mempool conditions (e.g. lnwatcher_waits_until_fees_go_down). This is
done by manually injecting fee estimates into the `Network` object using
the `test_inject_fee_etas` cli command. However it can still happen that
the Network automatically updates its fee estimates from the connected
electrum server in the time between injecting the fee and the actual
tested logic making decisions based on the fee. This causes the test to
fail sometimes.
By setting the `test_disable_automatic_fee_eta_update` true the Network
will stop automatically updating the fee estimates and the test will
behave as expected.
2025-10-31 14:50:26 +01:00
f321x
f2aa4404ad qt: fix ServerWidget
The ServerWidget was not working properly, when switching from "Manual
Mode" to "Auto Connect" the change wouldn't get saved as it depended on
having a correct server string entered (which isn't neccessary for Auto
Connect).
Also makes the widget behave more sane by cleaning the server input if
Auto Connect is enabled and switching to Manual Mode if the user
manually selects a server.

Update the ServerWidget every time it is shown (on initialization and
also when the user opens it again or switches between network dialog
tabs).
This will clean it up if the user has entered some invalid server and
closes it, otherwise this server would stay in the input field until the
application is restarted.

The list of servers in the ServerWidget allows the user to right click
and 'Use as server' on the servers in the list, however internally it
was handled differently than what the user would expect when clicking on
'Use as server'. E.g. if the user selects a server in autoconnect mode
it would still stay in autoconnect mode so the server could switch again
to another server any time? Now it will also change the mode to manual
(or stay in single server mode if that was selected before), making it
clear that this server will stay selected.

If the user clicks on "Follow this branch" the connect mode will get changed to
autoconnect as internally we connect to a random interface on this
branch.
2025-10-27 18:46:36 +01:00
ThomasV
5c2c9ac941 network.py: do not require MyEncoder for serializing recent servers
This class is overkill. I am trying to restrict its usage to wallet_db
2025-09-18 12:04:17 +02:00
SomberNight
6d99717d5b txbatcher: add comment to _to_pay_after 2025-08-21 15:15:08 +00:00
SomberNight
8b99c218b4 network: move broadcast_transaction move network to interface.py 2025-08-07 16:29:49 +00:00
ghost43
dfd480d5dd Merge pull request #10033 from SomberNight/202507_interface_fast_forward
interface: parallel header-chunks download
2025-07-31 15:47:11 +00:00
SomberNight
eef562389c qml: qenetwork: fix type confusion for "server"
exc triggered when switching from same server to same server:
```
  9.43 | D | gui.qml.qenetwork | server_status updated: Connecting
  9.43 | E | network | Exception in _run_new_interface: Exception('diagnostic name not yet available?')
Traceback (most recent call last):
  File "/home/user/wspace/electrum/electrum/logging.py", line 241, in __get_logger_for_obj
    diag_name = self.diagnostic_name()
  File "/home/user/wspace/electrum/electrum/interface.py", line 555, in diagnostic_name
    return self.server.net_addr_str()
AttributeError: 'str' object has no attribute 'net_addr_str'

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/home/user/wspace/electrum/electrum/util.py", line 1218, in wrapper
    return await func(*args, **kwargs)
  File "/home/user/wspace/electrum/electrum/network.py", line 986, in _run_new_interface
    interface = Interface(network=self, server=server)
  File "/home/user/wspace/electrum/electrum/interface.py", line 502, in __init__
    Logger.__init__(self)
  File "/home/user/wspace/electrum/electrum/logging.py", line 232, in __init__
    self.logger = self.__get_logger_for_obj()
  File "/home/user/wspace/electrum/electrum/logging.py", line 243, in __get_logger_for_obj
    raise Exception("diagnostic name not yet available?") from e
Exception: diagnostic name not yet available?
```
2025-07-18 14:16:30 +00:00
SomberNight
6a56fd756b interface: split request_chunk, based on "can_return_early" param 2025-07-15 22:53:35 +00:00
SomberNight
27599ac537 interface: small clean-up. intro ChainResolutionMode.
- type hints
- minor API changes
- no functional changes
2025-06-06 16:42:15 +00:00
ThomasV
853b793bef rm verbosity_shortcuts option (unused, redundant) 2025-05-29 16:20:41 +02:00
Sander van Grieken
82e3932aaf network: add oneserver/auto_connect both enabled checks, avoid connecting to random/multiple servers
if oneserver is enabled.
2025-05-19 18:07:29 +02:00
SomberNight
1c41bd23b7 network: broadcast_transaction: log full raw tx on errors 2025-05-16 15:49:54 +00:00
SomberNight
68ac2d8079 network: sanitize_tx_broadcast_response: add new error messages 2025-05-16 15:48:12 +00:00
Sander van Grieken
64a160027a imports, whitespace, type hints 2025-04-23 16:09:31 +02:00
SomberNight
0b3a283586 asyncio: hold our own strong refs for tasks and futures
see https://docs.python.org/3.13/library/asyncio-task.html#asyncio.create_task :

> Important
>
> Save a reference to the result of this function, to avoid a task
> disappearing mid-execution. The event loop only keeps weak references
> to tasks. A task that isn’t referenced elsewhere may get garbage
> collected at any time, even before it’s done. For reliable
> “fire-and-forget” background tasks, gather them in a collection

ref https://github.com/python/cpython/issues/91887
ref https://github.com/beeware/toga/pull/2814
2025-03-05 17:06:04 +00:00
SomberNight
b88d9f9d06 network: follow-up ProxySettings. make sure probe_tor cleans-up.
follow-up 2aa427b4bf
2025-03-05 17:04:49 +00:00
SomberNight
2aa427b4bf Merge branch 'pr/9507': qt: refactor NetworkChoiceLayout to ProxyWidget+ServerWidget
ref https://github.com/spesmilo/electrum/pull/9507
2025-03-05 15:01:05 +00:00
SomberNight
5dc2ae243e util: refactor Tor-detection to be async
- on my PC, with Tor Browser running (socks proxy on port 9150), detect_tor_socks_proxy took ~4.01 seconds
- this was because we probed port 9050, 2 sec timeout, 9051, 2 sec timeout, 9150, ~few ms to succeed
- instead we now probe all ports concurrently
2025-03-05 14:46:47 +00:00
Sander van Grieken
f1e9abf04e qt,qml: review rework, refactor spinner, add tor probe active indicator 2025-03-05 10:52:25 +01:00
ThomasV
840243e029 separate fee policy from config
- Wallet.make_unsigned_transaction takes a FeePolicy parameter
 - fee sliders act on a FeePolicy instead of config
 - different fee policies may be used for different purposes
 - do not detect dust outputs in lnsweep, delegate that to lnwatcher
2025-03-05 10:29:26 +01:00
Sander van Grieken
fea598cfbe network: create ProxySettings class replacing dict and encapsulating proxy related funcs,
allow enable/disable proxy without nuking proxy mode, host and port (explicit enable_proxy config setting),
move tor probe from frontend to backend code, add probe buttons for Qt and QML
2025-03-04 14:23:33 +01:00
SomberNight
be2cd02e54 some clean-ups now that we require python 3.10 2025-01-10 18:52:53 +00:00
ThomasV
29a8c41025 move watchtower to a plugin.
remove watchtower dialog in qt
2024-12-20 15:34:26 +01:00
Sander van Grieken
f4520b9e0d network: use TOR stream isolation
also refactor, for proxy instantiation, use Network instance, not a proxy dict.
2024-10-25 01:10:58 +02:00
SomberNight
7a0bffc3e3 swaps: broadcast_transaction error-handling 2024-06-05 19:00:51 +00:00
SomberNight
bc57926498 network: (trivial) simplify send_http_on_proxy 2024-06-04 13:48:37 +00:00
SomberNight
b9a2b0d19b network: re-detect is_proxy_tor every time we connect to a server
This avoids some false negatives for is_proxy_tor.
(previously we only set is_proxy_tor when the proxy settings were changed)
In particular, consider scenario:
- Tor browser not running
- user sets "localhost:9150" as proxy
- detection sets network.is_proxy_tor to False
- user starts Tor browser
- network, due to retries, finds proxy working and connects to some servers
- network.is_proxy_tor remains False
2024-04-25 22:48:56 +00:00
SomberNight
e5d28563cc network: implement basic "add server as bookmark" functionality
implement backend and expose it to qt gui
2024-02-03 12:33:34 +00:00
Sander van Grieken
831be3b680 network: fix issue starting tor probe when proxy disabled 2023-12-12 13:27:42 +01:00
Sander van Grieken
15592d4987 followup 0d476f73df 2023-12-05 11:08:20 +01:00
accumulator
134fd6c656 Merge pull request #8714 from accumulator/tor_probe
network: async tor probe
2023-12-04 16:45:03 +01:00
Sander van Grieken
0d476f73df network: rename network.tor_proxy to network.is_proxy_tor and keep it at None until TOR probe is done. 2023-12-04 10:42:32 +01:00
SomberNight
64f82cd260 qt wizard bip39 recovery: better handle --offline mode
```
 32.40 | E | gui.qt.exception_window.Exception_Hook | exception caught by crash reporter
Traceback (most recent call last):
  File "/home/user/wspace/electrum/electrum/gui/qt/wizard/wallet.py", line 709, in <lambda>
    button.clicked.connect(lambda: Bip39RecoveryDialog(self, get_account_xpub, on_account_select))
  File "/home/user/wspace/electrum/electrum/gui/qt/bip39_recovery_dialog.py", line 40, in __init__
    fut = asyncio.run_coroutine_threadsafe(coro, network.asyncio_loop)
AttributeError: 'NoneType' object has no attribute 'asyncio_loop'
```
2023-12-01 17:37:58 +00:00
Sander van Grieken
90d1d587e8 network: async tor probe 2023-11-30 14:32:19 +01:00
Sander van Grieken
70da74166c network: no assert for port number range check 2023-11-30 14:27:32 +01:00
Sander van Grieken
297568a148 network: remove resolver monkey-patch as no local hostname lookups are performed when
enabling SOCKS5 proxy.
2023-11-30 14:27:31 +01:00
Sander van Grieken
667485b17e network: split off proxy_user and proxy_pass from serialized proxy string and add separate cmdline params and config keys for them.
support parsing both old style mode:host:port:user:pass and new mode:host:port, where new form also accepts IPv6 addresses
2023-11-30 14:27:31 +01:00
ThomasV
7447cf9dcc lnworker: always initialize self.config in constructor 2023-11-13 14:54:40 +01:00
SomberNight
4c63d8729b add sanity checks we don't sign tx including dummy addr
Somewhat a follow-up to 649ce979ab.

This adds some safety belts so we don't accidentally sign a tx that
contains a dummy address.
Specifically we check that tx does not contain output for dummy addr:
- in wallet.sign_transaction
- in network.broadcast_transaction

The second one is perhaps redundant, but I think it does not hurt.
2023-09-16 04:36:08 +00:00
SomberNight
f28a2824d5 qt: do not show UntrustedServerReturnedError when sweeping
We should not show the untrusted text in the GUI...
With this change, we still log the text, but otherwise it should avoid
unintentionally showing it anywhere, as the original exception is
masked away.

related: https://github.com/spesmilo/electrum/issues/8599#issuecomment-1706775508

Example traceback (and the exc is then shown in main_window.on_error):
```
 10.77 | D | n/network | got error from server for Network.listunspent_for_scripthash: <UntrustedServerReturnedError [DO NOT TRUST THIS MESSAGE] original_exception: "RPCError(0, 'heyheyhey')">
 10.78 | E | gui.qt.main_window.[test_segwit_2] | on_error
Traceback (most recent call last):
  File "...\electrum\electrum\network.py", line 898, in wrapper
    return await func(self, *args, **kwargs)
  File "...\electrum\electrum\network.py", line 1149, in listunspent_for_scripthash
    return await self.interface.listunspent_for_scripthash(sh)
  File "...\electrum\electrum\interface.py", line 1027, in listunspent_for_scripthash
    raise aiorpcx.jsonrpc.RPCError(0, "heyheyhey")
aiorpcx.jsonrpc.RPCError: (0, 'heyheyhey')

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "...\electrum\electrum\gui\qt\util.py", line 925, in run
    result = task.task()
  File "...\electrum\electrum\gui\qt\main_window.py", line 2505, in <lambda>
    task = lambda: self.network.run_from_another_thread(
  File "...\electrum\electrum\network.py", line 383, in run_from_another_thread
    return fut.result(timeout)
  File "...\Python310\lib\concurrent\futures\_base.py", line 458, in result
    return self.__get_result()
  File "...\Python310\lib\concurrent\futures\_base.py", line 403, in __get_result
    raise self._exception
  File "...\electrum\electrum\wallet.py", line 151, in sweep_preparations
    async with OldTaskGroup() as group:
  File "...\aiorpcX\aiorpcx\curio.py", line 304, in __aexit__
    await self.join()
  File "...\electrum\electrum\util.py", line 1316, in join
    task.result()
  File "...\electrum\electrum\wallet.py", line 142, in find_utxos_for_privkey
    await _append_utxos_to_inputs(
  File "...\electrum\electrum\wallet.py", line 129, in _append_utxos_to_inputs
    u = await network.listunspent_for_scripthash(scripthash)
  File "...\electrum\electrum\network.py", line 872, in make_reliable_wrapper
    async with OldTaskGroup(wait=any) as group:
  File "...\aiorpcX\aiorpcx\curio.py", line 304, in __aexit__
    await self.join()
  File "...\electrum\electrum\util.py", line 1327, in join
    self.completed.result()
  File "...\electrum\electrum\network.py", line 903, in wrapper
    raise wrapped_exc from e
electrum.network.UntrustedServerReturnedError: The server returned an error.
```
2023-09-05 15:47:33 +00:00
ThomasV
5f3a1f0b71 do not spam log with fee_histogram 2023-08-14 09:58:17 +02:00
SomberNight
d51f00e2a3 asyncio.wait_for() is too buggy. use util.wait_for2() instead
wasted some time because asyncio.wait_for() was suppressing cancellations. [0][1][2]
deja vu... [3]

Looks like this is finally getting fixed in cpython 3.12 [4]
So far away...
In attempt to avoid encountering this again, let's try using
asyncio.timeout in 3.11, which is how upstream reimplemented wait_for in 3.12 [4], and
aiorpcx.timeout_after in 3.8-3.10.

[0] https://github.com/python/cpython/issues/86296
[1] https://bugs.python.org/issue42130
[2] https://bugs.python.org/issue45098
[3] https://github.com/kyuupichan/aiorpcX/issues/44
[4] https://github.com/python/cpython/pull/98518
2023-08-04 18:18:21 +00:00
Sander van Grieken
1e725b6baa break the cyclic dependency 2023-06-28 16:49:28 +02:00
SomberNight
24980feab7 config: introduce ConfigVars
A new config API is introduced, and ~all of the codebase is adapted to it.
The old API is kept but mainly only for dynamic usage where its extra flexibility is needed.

Using examples, the old config API looked this:
```
>>> config.get("request_expiry", 86400)
604800
>>> config.set_key("request_expiry", 86400)
>>>
```

The new config API instead:
```
>>> config.WALLET_PAYREQ_EXPIRY_SECONDS
604800
>>> config.WALLET_PAYREQ_EXPIRY_SECONDS = 86400
>>>
```

The old API operated on arbitrary string keys, the new one uses
a static ~enum-like list of variables.

With the new API:
- there is a single centralised list of config variables, as opposed to
  these being scattered all over
- no more duplication of default values (in the getters)
- there is now some (minimal for now) type-validation/conversion for
  the config values

closes https://github.com/spesmilo/electrum/pull/5640
closes https://github.com/spesmilo/electrum/pull/5649

Note: there is yet a third API added here, for certain niche/abstract use-cases,
where we need a reference to the config variable itself.
It should only be used when needed:
```
>>> var = config.cv.WALLET_PAYREQ_EXPIRY_SECONDS
>>> var
<ConfigVarWithConfig key='request_expiry'>
>>> var.get()
604800
>>> var.set(3600)
>>> var.get_default_value()
86400
>>> var.is_set()
True
>>> var.is_modifiable()
True
```
2023-05-25 17:39:48 +00:00
SomberNight
03ab33f4b2 SimpleConfig: change API of set_key(): "save" is now kwarg-only 2023-05-25 17:37:16 +00:00
SomberNight
fd41308c6b network: log original error text in catch_server_exceptions
related: https://github.com/spesmilo/electrum/issues/8439
2023-05-16 15:10:12 +00:00
SomberNight
53d61c011a qml network: restrict cases where server is shown "lagging" 2023-05-03 13:49:44 +00:00
SomberNight
e2406f21b4 fix flake8-bugbear B011
B011 Do not call assert False since python -O removes these calls. Instead callers should raise AssertionError().
2023-04-24 12:58:19 +00:00
SomberNight
312f2641e7 don't use bare except
use "except Exception", or if really needed explicitly "except BaseException"
2023-04-24 12:58:01 +00:00
SomberNight
a6c36b8588 regtests: test_watchtower started failing due to newly exposed bug
local_watchtower.adb.start_network was getting called twice.

follow-up 6ac3f84095

```
20230418T014725.636141Z |    ERROR | __main__ |
Traceback (most recent call last):
  File "/home/user/wspace/electrum/./run_electrum", line 435, in main
    handle_cmd(
  File "/home/user/wspace/electrum/./run_electrum", line 469, in handle_cmd
    d = daemon.Daemon(config, fd)
  File "/home/user/wspace/electrum/electrum/util.py", line 462, in <lambda>
    return lambda *args, **kw_args: do_profile(args, kw_args)
  File "/home/user/wspace/electrum/electrum/util.py", line 458, in do_profile
    o = func(*args, **kw_args)
  File "/home/user/wspace/electrum/electrum/daemon.py", line 404, in __init__
    self.network = Network(config, daemon=self)
  File "/home/user/wspace/electrum/electrum/network.py", line 348, in __init__
    self.local_watchtower.adb.start_network(self)
  File "/home/user/wspace/electrum/electrum/address_synchronizer.py", line 185, in start_network
    assert self.network is None, "already started"
AssertionError: already started
```
2023-04-18 02:02:07 +00:00