1
0
Commit Graph

19391 Commits

Author SHA1 Message Date
SomberNight
1b600b49e9 lnmsg/lnonion: follow-up prev: "hide" MappingProxyType usage 2025-11-18 14:54:33 +00:00
f321x
936e7fd1c2 lnonion: immutable OnionPacket and OnionHopsDataSingle
Make OnionHopsDataSingle and OnionPacket immutable for safer caching and
handling.

# Conflicts:
#	electrum/onion_message.py
2025-11-11 14:37:37 +01:00
Sander van Grieken
1ad6607405 onion_message: fix handling of ONION_MESSAGE_LARGE_SIZE payload sizes for onion messages,
process dummy hops regardless of EXPERIMENTAL_LN_FORWARD_PAYMENTS config option.
2025-11-10 16:20:15 +01:00
Sander van Grieken
3cb639f9b4 onion_message: ensure blinded path is list 2025-11-10 15:02:37 +01:00
Sander van Grieken
9481f4f636 followup prev 2025-11-10 13:50:38 +01:00
Sander van Grieken
130af59760 update field naming for BOLT04 structures
see also: 3fffab3b88
2025-11-10 13:47:20 +01:00
ghost43
d87f9e9a44 Merge pull request #10295 from SomberNight/202510_proto16
electrum protocol: add support for 1.6, but keep supporting 1.4
2025-11-07 16:42:11 +00:00
ghost43
7cb5621625 Merge pull request #10274 from f321x/lnpay_collect_failed_htlcs
lnworker: collect failed htlcs during payment attempt, fix todo
2025-11-07 16:17:19 +00:00
SomberNight
e53666ac86 lnworker: follow-up prev: split pay_to_node 2025-11-07 15:37:49 +00:00
ThomasV
359af667d3 Merge pull request #10233 from spesmilo/jsondb_pointers
Jsondb pointers
2025-11-07 10:21:27 +01:00
ThomasV
077bcf515d StoredDict: use pointers instead of path
Instead of storing its own path, each StoredDict element stores
its own key and a pointer to its parent. If a dict is removed
from the db, its parent pointer is set to None. This makes
self.path return None for all branches that have been pruned.

This passes tests/tests_json_db.py and fixes issue #10000
2025-11-07 10:00:10 +01:00
ThomasV
53c1817956 tests/test_jsondb.py: add tests that replace a StoredDict element
after its parent has been removed.

Related: #10000
2025-11-07 10:00:10 +01:00
ThomasV
7aeef92060 json_db: move json to python conversion logic from
StoredDict to json_db.

convert_key, convert_value are used to convert json objects
to python classes, do not call them in StoredDict.__setitem__

This makes StoredDict agnostic about the type of database we use.
2025-11-07 10:00:10 +01:00
SomberNight
2cac527c08 interface: get_history: enforce order of mempool txs
Intentionally surface servers that don't correctly implement this.
2025-11-05 14:47:39 +00:00
Sander van Grieken
7bfe2dd5f6 commands: print warnings to stderr so output is still valid json 2025-11-05 14:37:34 +01:00
ThomasV
9c4c7f01ac daemon: pass cmdname to register_method
This allows plugins to use already existing names without Electrum complaining about collisions
2025-11-04 12:42:54 +01:00
ThomasV
e02cfbfb60 Merge pull request #10277 from f321x/utilities
qt: add text to toolbar button
2025-11-04 10:05:13 +01:00
f321x
c2068a4e4b qt: add text to toolbar button
The toolbar button is very small and some users probably don't even
notice it. As we have lots of space in the toolbar anyways i think it
makes sense to add some text to it to make it more visible and easier to
click. Maybe this is also useful for screen readers.
2025-11-04 09:54:29 +01:00
ThomasV
8a53da93d5 Merge pull request #10296 from f321x/fix_watchtower_exception
plugin: watchtower: call start_watching() threadsafe
2025-11-04 08:39:54 +01:00
SomberNight
e57087daf7 interface: implement support for protocol 1.6
ref https://github.com/spesmilo/electrum-protocol/pull/6
2025-11-03 18:32:48 +00:00
f321x
f402cb3cd1 plugin: watchtower: call start_watching() threadsafe
Launch `WatchtowerPlugin.watchtower.start_watching()` through
asyncio.run_coroutine_threadsafe instead of ensure_future to prevent the
following exception from happening when running python with
`PYTHONASYNCIODEBUG=1`.

```

20251103T165007.087746Z |    ERROR | plugin.Plugins | cannot initialize plugin watchtower: Error loading watchtower plugin: RuntimeError('Non-thread-safe operation invoked on an event loop other than the current one')
Traceback (most recent call last):
  File "/home/user/code/electrum-fork/electrum/plugin.py", line 629, in load_plugin_by_name
    plugin = module.Plugin(self, self.config, name)
  File "/home/user/code/electrum-fork/electrum/plugins/watchtower/watchtower.py", line 59, in __init__
    asyncio.ensure_future(self.watchtower.start_watching())
    ~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.14/asyncio/tasks.py", line 732, in ensure_future
    return loop.create_task(coro_or_future)
           ~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^
  File "/usr/lib64/python3.14/asyncio/base_events.py", line 468, in create_task
    return self._task_factory(self, coro, **kwargs)
           ~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^
  File "/home/user/code/electrum-fork/electrum/util.py", line 1773, in factory
    task = asyncio.Task(coro, loop=loop_, **kwargs)
  File "/usr/lib64/python3.14/asyncio/base_events.py", line 829, in call_soon
    self._check_thread()
    ~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib64/python3.14/asyncio/base_events.py", line 866, in _check_thread
    raise RuntimeError(
        "Non-thread-safe operation invoked on an event loop other "
        "than the current one")
RuntimeError: Non-thread-safe operation invoked on an event loop other than the current one

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

Traceback (most recent call last):
  File "/home/user/code/electrum-fork/electrum/plugin.py", line 184, in load_plugins
    self.load_plugin_by_name(name)
    ~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^
  File "/home/user/code/electrum-fork/electrum/plugin.py", line 631, in load_plugin_by_name
    raise Exception(f"Error loading {name} plugin: {repr(e)}") from e
Exception: Error loading watchtower plugin: RuntimeError('Non-thread-safe operation invoked on an event loop other than the current one')

```
2025-11-03 17:54:48 +01:00
SomberNight
cd3173a289 interface: extend client to be able to support a range of protocols 2025-11-03 16:50:38 +00:00
SomberNight
b1fc5b2461 tests: interface: fix estimatefee response (wrong unit) 2025-11-03 16:45:56 +00:00
SomberNight
325b83b30a tests: interface: add timeout to avoid hangs
instead of an infinite hang, the unit test should just fail
2025-11-03 16:44:47 +00:00
ghost43
0a414ad0f0 Merge pull request #10290 from SomberNight/202510_synchronizer_guess_status1
synchronizer: rm redundant get_history call if new block mined unconf
2025-11-03 15:45:26 +00:00
SomberNight
6d016d70ee synchronizer: rm redundant get_history call if new block mined unconf
This is an optimisation and possible hardening against traffic analysis.

After a new block is mined, we sometimes receive "blockchain.scripthash.subscribe" notifications. If so, this is often due to the just mined block including mempool txs we already knew about.

Normally we would call the "blockchain.scripthash.get_history" RPC, to get full history of the affected scripthash.
Instead now we first optimistically guess that all mempool txs touching this scripthash just got mined and see if by assuming that we can reproduce the announced sh status.
- if yes, we saved a network RTT by not having to call "blockchain.scripthash.get_history"
- if no, we request the history from the server using the RPC
2025-11-03 15:44:02 +00:00
ghost43
f3420aa723 Merge pull request #10288 from f321x/debug_failing_regtest
ci/regtest: fix flaky regtest test lnwatcher_waits_until_fees_go_down
2025-11-03 14:32:32 +00:00
ThomasV
f756e46ecb Merge pull request #10294 from spesmilo/dust_override
add dust_override to SweepInfo
2025-11-03 14:34:03 +01:00
ThomasV
879dcb3224 add dust_override to SweepInfo
We might want to set this value independently from is_anchor.
2025-11-03 14:07:58 +01:00
f321x
ce7774efa8 regtest: add timeout to wait_ functions
Add 30s timeouts to the "wait_" functions in regtest.sh as it
happens from time to time that they get stuck on the CI and waste compute.
2025-10-31 14:50:28 +01:00
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
19e32d6054 lnwatcher/txbatcher: more logging
log more clearly if an input is considered dust, this makes the logs
more helpful when debugging sweeping of lightning utxos.
2025-10-31 14:50:25 +01:00
f321x
80ea7becdc CI: regtest: stop on failed test, expose datadirs
Stops the running regtest if one test fails (using the --failfast
option) and makes the wallet data directories of alice, bob and carol
available for debugging. This seems helpful to fix issues only happening
on the CI.
2025-10-31 14:50:19 +01:00
ghost43
41378e1c91 Merge pull request #10287 from f321x/fix_cake_diagram
qt: allow opening BalanceDialog if warning is set and balance is 0
2025-10-31 13:45:08 +00:00
ghost43
838a23fdcc Merge pull request #10289 from f321x/red_amount_warning
qt: remove outdated help string in SendTab
2025-10-31 13:36:14 +00:00
SomberNight
5212d20f29 synchronizer: small refactor _on_address_status 2025-10-29 19:05:10 +00:00
f321x
fb4b744142 qt: remove outdated help string in SendTab
The amount edit box is not turning red anymore if the amount is higher
than the wallet balance, so this string can be removed.
Alternatively it could be made red again but seems like nobody missed
it.
2025-10-29 18:17:06 +01:00
f321x
6484947485 qt: allow opening BalanceDialog if warning
Allow to open the BalanceDialog, by clicking on the Pie Diagram in the
bottom left corner of the main window, if there is an active warning,
even if the wallets balance is 0. Right now the user can see the
warning icon for the lighting channel reserve, but cannot click on the
icon to read the actual warning if there is no balance in the wallet.
2025-10-29 10:50:56 +01:00
ghost43
bf0ebc8d2b Merge pull request #10283 from f321x/fix_add_peer
cli: fix add_peer command
2025-10-28 16:15:18 +00:00
f321x
fca879d493 test_commands: add unittest for add_peer cli 2025-10-28 17:08:06 +01:00
f321x
95ba7e7547 cli: add_peer: make add_peer wait for connection
peer initialization was never awaited in the `add_peer` method.
This awaits the initialization of the peer so that the caller
actually knows if connection succeeded or timed out.
2025-10-28 17:07:57 +01:00
ghost43
5e8f43e903 Merge pull request #10285 from f321x/lnpeer_dont_send_gossip_before_init
lnpeer: await init in main_loop
2025-10-28 15:33:41 +00:00
f321x
a5cf5f75fc lnpeer: await init in main_loop
Because `LNPeer.initialized` was awaited in
`LNPeer._query_gossip()` instead of the main loop the other tasks got
spawned concurrently and each task on its own has to wait for the
initialization. In `LNPeer._send_own_gossip()` this was missing, instead
there is a fixed 10 sec sleep. If the connection was not initialized but
the 10 sec are exceeded `_send_own_gossip()` tries to send gossip and
causes this exception as the `LNTransport` is not ready:

```
  2.13 | E | lnpeer.Peer.[LNWallet, 0288fa27c0-bc1900c8] | Exception in main_loop: AttributeError("'LNTransport' object has no attribute 'sk'")
Traceback (most recent call last):
  File "/home/user/code/electrum-fork/electrum/util.py", line 1232, in wrapper
    return await func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/user/code/electrum-fork/electrum/lnpeer.py", line 511, in wrapper_func
    return await func(self, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/user/code/electrum-fork/electrum/lnpeer.py", line 525, in main_loop
    async with self.taskgroup as group:
               ^^^^^^^^^^^^^^
  File "/home/user/code/electrum-fork/env/lib/python3.14/site-packages/aiorpcx/curio.py", line 304, in __aexit__
    await self.join()
  File "/home/user/code/electrum-fork/electrum/util.py", line 1420, in join
    task.result()
    ~~~~~~~~~~~^^
  File "/home/user/code/electrum-fork/electrum/lnpeer.py", line 573, in _send_own_gossip
    self.send_node_announcement(alias, color)
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^
  File "/home/user/code/electrum-fork/electrum/lnpeer.py", line 1830, in send_node_announcement
    self.transport.send_bytes(raw_msg)
    ~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^
  File "/home/user/code/electrum-fork/electrum/lntransport.py", line 225, in send_bytes
    lc = aead_encrypt(self.sk, self.sn(), b'', l)
                      ^^^^^^^
AttributeError: 'LNTransport' object has no attribute 'sk'. Did you mean: 'sn'?
```

By awaiting the initialization directly in the `main_loop` it is more
clear that the task getting spawned subsequently depend on the transport
being available and separates the initialization more clearly these
other functions.
2025-10-28 15:42:16 +01:00
ghost43
d379a66a8f Merge pull request #10282 from f321x/cleanup_event_loop
util: cleanup asyncio event loop after stopping
2025-10-28 14:15:03 +00:00
ghost43
36606efdb2 Merge pull request #10284 from f321x/xml_clipboard
android: qr scanner: add emoji to clipboard string
2025-10-28 13:56:38 +00:00
f321x
08673d3534 util: cleanup asyncio event loop after stopping
I noticed many ResourceWarning when running regtests with
PYTHONASYNCIODEBUG=1 and PYTHONDEVMODE=1, each time a daemon
gets stopped the asyncio loop wouldn't get properly cleaned up:

```
(env) user@hp:~/code/electrum-fork$ python3 -m unittest tests.regtest.TestLightningAB.test_lnwatcher_waits_until_fees_go_down
***** test_lnwatcher_waits_until_fees_go_down ******
initializing alice
  0.67 | W | asyncio | Executing <Task finished name='Task-1' coro=<run_offline_command() done, defined at /home/user/code/electrum-fork/./run_electrum:229> result={'msg': 'Please keep ... your wallet.', 'path': '/tmp/alice/r...efault_wallet', 'seed': 'fiction sadd...it radar desk'} created at /home/user/code/electrum-fork/electrum/util.py:1760> took 0.280 seconds
/usr/lib64/python3.14/asyncio/base_events.py:758: ResourceWarning: unclosed event loop <_UnixSelectorEventLoop running=False closed=False debug=True>
/usr/lib64/python3.14/asyncio/base_events.py:758: ResourceWarning: unclosed event loop <_UnixSelectorEventLoop running=False closed=False debug=True>
/usr/lib64/python3.14/asyncio/base_events.py:758: ResourceWarning: unclosed event loop <_UnixSelectorEventLoop running=False closed=False debug=True>
/usr/lib64/python3.14/asyncio/base_events.py:758: ResourceWarning: unclosed event loop <_UnixSelectorEventLoop running=False closed=False debug=True>
/usr/lib64/python3.14/asyncio/base_events.py:758: ResourceWarning: unclosed event loop <_UnixSelectorEventLoop running=False closed=False debug=True>
/usr/lib64/python3.14/asyncio/base_events.py:758: ResourceWarning: unclosed event loop <_UnixSelectorEventLoop running=False closed=False debug=True>
funding alice
/usr/lib64/python3.14/asyncio/base_events.py:758: ResourceWarning: unclosed event loop <_UnixSelectorEventLoop running=False closed=False debug=True>
f84277454a04243e500cf84c67aad16e04dd7a88ffa849ffcf20ce3f9af277df
/usr/lib64/python3.14/asyncio/base_events.py:758: ResourceWarning: unclosed event loop <_UnixSelectorEventLoop running=False closed=False debug=True>
/usr/lib64/python3.14/asyncio/base_events.py:758: ResourceWarning: unclosed event loop <_UnixSelectorEventLoop running=False closed=False debug=True>
initializing bob
  0.54 | W | asyncio | Executing <Task finished name='Task-1' coro=<run_offline_command() done, defined at /home/user/code/electrum-fork/./run_electrum:229> result={'msg': 'Please keep ... your wallet.', 'path': '/tmp/bob/reg...efault_wallet', 'seed': 'wink loud so...ory myth case'} created at /home/user/code/electrum-fork/electrum/util.py:1760> took 0.195 seconds
/usr/lib64/python3.14/asyncio/base_events.py:758: ResourceWarning: unclosed event loop <_UnixSelectorEventLoop running=False closed=False debug=True>
/usr/lib64/python3.14/asyncio/base_events.py:758: ResourceWarning: unclosed event loop <_UnixSelectorEventLoop running=False closed=False debug=True>
/usr/lib64/python3.14/asyncio/base_events.py:758: ResourceWarning: unclosed event loop <_UnixSelectorEventLoop running=False closed=False debug=True>
/usr/lib64/python3.14/asyncio/base_events.py:758: ResourceWarning: unclosed event loop <_UnixSelectorEventLoop running=False closed=False debug=True>
/usr/lib64/python3.14/asyncio/base_events.py:758: ResourceWarning: unclosed event loop <_UnixSelectorEventLoop running=False closed=False debug=True>
/usr/lib64/python3.14/asyncio/base_events.py:758: ResourceWarning: unclosed event loop <_UnixSelectorEventLoop running=False closed=False debug=True>
funding bob
/usr/lib64/python3.14/asyncio/base_events.py:758: ResourceWarning: unclosed event loop <_UnixSelectorEventLoop running=False closed=False debug=True>
f68b651e84dc8547f54dd09129018a2d0d256dedc8ccc48595ae172de895371a
/usr/lib64/python3.14/asyncio/base_events.py:758: ResourceWarning: unclosed event loop <_UnixSelectorEventLoop running=False closed=False debug=True>
mining 1 blocks
starting daemon (PID 38153)
/usr/lib64/python3.14/asyncio/base_events.py:758: ResourceWarning: unclosed event loop <_UnixSelectorEventLoop running=False closed=False debug=True>
/tmp/alice/regtest/wallets/default_wallet
/usr/lib64/python3.14/asyncio/base_events.py:758: ResourceWarning: unclosed event loop <_UnixSelectorEventLoop running=False closed=False debug=True>
```

This commits adds some cleanup to `util.create_and_start_event_loop()`
to
1. cancel remaining tasks
2. shut down asyncgens
3. shutdown the default executor
4. call loop.close() to free the resources allocated to the loop
See https://stackoverflow.com/questions/30765606/whats-the-correct-way-to-clean-up-after-an-interrupted-event-loop

This seems to reliably solve the mentioned `ResourceWarning`.
2025-10-28 14:53:35 +01:00
f321x
c816987164 android: qr scanner: add emoji to clipboard string
The string is not translated and might not be accessible for non-english
speakers, even though its relatively self-explanatory i think adding
this emoji makes it more accessible.
2025-10-28 14:32:04 +01:00
SomberNight
6423323037 interface: PaddedRSTransport: keep in sync with e-x: flush on close
ref f62f986b33

note: ReplyAndDisconnect is specific to electrumx, however I think the name is descriptive enough to keep it here.
2025-10-27 18:09:33 +00:00
ghost43
356f50beae Merge pull request #10280 from f321x/fix_network_tab_selection
qt: fix ServerWidget (Network Tab)
2025-10-27 17:58:33 +00:00
ghost43
d21fd59815 Merge pull request #10281 from f321x/dont_connect_to_other_networks
interface: check genesis hash on connection
2025-10-27 17:55:09 +00:00