1
0
Commit Graph

375 Commits

Author SHA1 Message Date
f321x
1c5408cccb ServerConnectWizard: don't set autoconnect on user cancel
Don't set the NETWORK_AUTO_CONNECT config if the user checked the custom
server config checkbox and then cancels the wizard, so the next time the
user starts the wizard they again will have the choice instead of
silently being forced into a random server.
Currently if the user cancels the wizard during the network config the
welcome component will already have set the NETWORK_AUTO_CONNECT config
to False (as the user selected the custom server checkbox), preventing
the wizard from starting again on the next startup.
2026-01-26 15:28:54 +01:00
SomberNight
87540dbe3e util.EventListener: store WeakMethods in CallbackManager to avoid leaks
This patch changes the CallbackManager to use WeakMethods (weakrefs) to
break the ref cycle and allow the GC to clean up the wallet objects.
unregister_callbacks() will also get called automatically, from
EventListener.__del__, to clean up the CallbackManager.

I also added a few unit tests for this.

fixes https://github.com/spesmilo/electrum/issues/10427

-----

original problem:

In many subclasses of `EventListener`, such as `Abstract_Wallet`, `LNWatcher`,
`LNPeerManager`, we call `register_callbacks()` in `__init__`.
`unregister_callbacks()` is usually called in the `stop()` method.

Example - consider the wallet object:
- `Abstract_Wallet.__init__()` calls `register_callbacks()`
- there is a `start_network()` method
- there is a `stop()` method, which calls `unregister_callbacks()`
- typically the wallet API user only calls `stop()` if they also called
  `start_network()`.

This means the callbacks are often left registered, leading to the wallet
objects not getting GC-ed. The GC won't clean them up as
`util.callback_mgr.callbacks` stores strong refs to instance methods
of `Abstract_Wallet`, hence strong refs to the `Abstract_Wallet` objects.

An annoying example is `daemon.check_password_for_directory`, which
potentially creates wallet objects for all wallet files in the datadir.
It simply constructs the wallets, does not call `start_network()` and
neither does it call `stop()`.
2026-01-21 17:49:41 +00:00
SomberNight
50b10284ac util.CallbackManager: use sets instead of lists
- to gracefully take duplicate calls of register_callbacks(): should be idempotent now
- as a side-effect, the order of the callbacks is changed and not guaranteed
  - not like anyone should have been relying on it before though
2026-01-20 22:33:21 +00:00
SomberNight
57b26ba473 tests: add basic tests for util.CallbackManager and EventListener 2026-01-20 22:33:18 +00:00
ThomasV
fa575ab1fc fix test_onion_message (follow-up previous commit) 2026-01-13 17:36:06 +01:00
ghost43
5778fa401d Merge pull request #10363 from f321x/unittest_lnwallet
tests: add test_lnwallet to test lnwallet utils
2026-01-12 15:20:52 +00:00
f321x
dee2371738 test_lnpeer: use PeerInTests instead if Peer
ec65c53 replaces the usage of `PeerInTest` with `Peer` in
test_lnpeer.py.
PeerInTests sets `Peer.DELAY_INC_MSG_PROCESSING_SLEEP` to 0 so all
incoming messages get processed immediately. Because `Peer` instead of
`TestInPeer` was used the delay caused `test_reestablish_with_old_state`
to fail regularly because bob receives the old channel state and kills
the OldTaskGroup of the unittest with GracefulDisconnect before Alice
processed the answer of Bob and is still in ChannelState.REESTABLISHING.

```
FAILED tests/test_lnpeer.py::TestPeerDirect::test_reestablish_with_old_state - AssertionError: <PeerState.REESTABLISHING: 1> != <PeerState.BAD: 3>
```
2026-01-08 14:57:13 +01:00
f321x
562839c540 tests: add TestLNWallet to test lnwallet utils
Adds new unittest file test_lnwallet.py to allow unittesting
utility functions of LNWallet.
2026-01-08 13:16:34 +01:00
SomberNight
927724145a tests: rm some more dead code 2026-01-05 15:56:13 +00:00
SomberNight
0afd433c42 tests: properly clean-up MockLNWallets after tests finish 2026-01-05 15:56:10 +00:00
SomberNight
dfeb9918d8 tests: lnchannel: rewrite create_test_channels to use LNWallet 2026-01-05 15:56:04 +00:00
SomberNight
17f41044d5 tests: lnpeer: fix cyclic lnworker.wallet.lnworker inconsistency
These better hold, lol:
wallet.lnworker.wallet == wallet
lnworker.wallet.lnworker == lnworker
2026-01-05 15:56:01 +00:00
SomberNight
ea42b02ceb tests: simplify MockLNWallet, add fixme for cyclic inconsistency 2026-01-05 15:55:58 +00:00
SomberNight
91b98240dc tests: lnpeer: follow-up prev: rm horrible ugly hack 2026-01-05 15:55:54 +00:00
SomberNight
ec65c53de3 tests: lnpeer: mostly unify prepare_peers and prepare_graph 2026-01-05 15:55:51 +00:00
SomberNight
024f9b988d tests: lnpeer: (move-only) towards unifying prepare_{peers,graph} 2026-01-05 15:55:48 +00:00
SomberNight
17b7974800 tests: lnpeer: simplify tx_queue 2026-01-05 15:55:45 +00:00
SomberNight
1006e8092f lnworker: split LNWallet and LNWorker: LNWallet "has an" LNWorker
- LNWallet no longer "is-an" LNWorker, instead LNWallet "has-an" LNWorker
- the motivation is to make the unit tests nicer, and allow writing unit tests for more things
  - I hope this makes it possible to e.g. test lnsweep in the unit tests
  - some stuff we would previously have to write a regtest for, maybe we can write a unit test for, now
- in unit tests, MockLNWallet now
  - inherits LNWallet
  - the Wallet is no longer being mocked
2026-01-05 15:55:31 +00:00
ghost43
bdcd3f9c7c Merge pull request #10364 from f321x/test_dont_settle_htlcs_forwarding
lnpeer/lnworker: check dont_settle_htlcs when forwarding
2025-12-30 16:13:16 +00:00
f321x
dd1d98e37c pi: allow emaillike pi with 'lightning:' prefix
Lightning addresses with 'lightning:' do occur in the wild and make
sense (how else would e.g. the smartphone know to open a lightning
wallet instead of the e-mail client). So we should allow this.
2025-12-22 18:06:26 +01:00
f321x
2cd1de4f21 pi: fix incorrectly parsing emaillike with 'ln' prefix
Fixes a bug where we incorrectly parsed emaillike payment identifiers as
bech32 lightning payment identifier if they start with a 'ln' prefix.
2025-12-22 18:06:17 +01:00
SomberNight
08f101a7e5 tests: lnpeer/onion_msg: rm dead code 2025-12-19 14:53:28 +00:00
f321x
3b028b06a0 qml: enforce use of existing password for wallet creation
When creating a new wallet in a Electrum instance with existing wallets
this change forces the user to reuse a password of any existing wallet
if `SimpleConfig.WALLET_USE_SINGLE_PASSWORD` is True.
This prevents the amount of different passwords from increasing and
guides the user towards a single wallet password (the intended default).
2025-12-17 14:01:41 +01:00
SomberNight
5e53f82bc6 tests: lnpeer: simplify MockNetwork: rm dead code
not needed since 9224404108
2025-12-15 15:38:16 +00:00
f321x
e0b835eee6 tests: rm TestPeerDirect::test_dont_settle_htlcs
The new test
TestPeerForwarding::test_dont_settle_htlcs_receiver_and_forwarder covers
the receiver as well as the forwarder. So this unittest becomes obsolete
as it only tests the receiver.
2025-12-15 10:36:14 +01:00
f321x
cd1157ec14 tests: lnpeer: test_dont_settle_htlc_receiver_and_forwarder 2025-12-15 10:36:12 +01:00
ThomasV
bd735c645d Merge pull request #10359 from f321x/lnpeer_remove_zlib_compression
lnpeer: remove zlib encoding support from gossip
2025-12-13 11:18:22 +01:00
SomberNight
37db6ea7e8 transaction: tx_from_any: rm all whitespaces from str, none from bytes
- whitespaces are safe to remove from strings, and is convenient if we do this for users
- bytes-like inputs should be left alone: individual bytes that look like whitespaces can appear in them anywhere
  - even stripping the leading/trailing whitespaces is not safe to do: the first byte of the nVersion or the last byte of the nLocktime might look like whitespace too!
- instead, leading/trailing whitespaces can be stripped closer to where they are input, e.g. in the GUI
  - e.g. ".txn" files that we ourselves create contain a complete tx as a hex string, with a trailing final newline in the file
    - instead of reading that as bytes, we can read it as text
  - ".psbt" files OTOH are binary
2025-12-11 16:48:50 +00:00
SomberNight
16363cc3d9 transaction: tx_from_any: follow-up: only rm whitespaces from strings 2025-12-11 16:24:31 +00:00
f321x
b4fc39ca5f test: lnpeer: add test_decode_short_ids 2025-12-11 15:53:30 +01:00
f321x
7d307048a0 tx: replace whitespace chars in raw tx string
Removes all whitespace characters from a raw transaction string.
This is useful for example when loading raw transactions from text input
as it happens that there are some newline characters in the text.
I noticed this when copying-pasting from a timelock recovery pdf.
2025-12-11 10:34:49 +01:00
ghost43
6ceb4ad71f Merge pull request #10351 from f321x/jit_htlc_switch_fixes
lnpeer/lnutil: fail mpp if we didn't signal mpp in invoice
2025-12-10 15:56:23 +00:00
f321x
c34efce984 lnchannel: allow deleting unfunded incoming channels
We tried to delete incoming channels that didn't get funded after
lnutil.CHANNEL_OPENING_TIMEOUT, however an assert prevented this:

```
  3.63 | E | lnwatcher.LNWatcher.[default_wallet-LNW] | Exception in check_onchain_situation: AssertionError()
Traceback (most recent call last):
  File "/home/user/code/electrum-fork/electrum/util.py", line 1233, in wrapper
    return await func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/user/code/electrum-fork/electrum/lnwatcher.py", line 117, in check_onchain_situation
    await self.update_channel_state(
    ...<5 lines>...
        keep_watching=keep_watching)
  File "/home/user/code/electrum-fork/electrum/lnwatcher.py", line 135, in update_channel_state
    chan.update_onchain_state(
    ~~~~~~~~~~~~~~~~~~~~~~~~~^
        funding_txid=funding_txid,
        ^^^^^^^^^^^^^^^^^^^^^^^^^^
    ...<2 lines>...
        closing_height=closing_height,
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
        keep_watching=keep_watching)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/user/code/electrum-fork/electrum/lnchannel.py", line 341, in update_onchain_state
    self.update_unfunded_state()
    ~~~~~~~~~~~~~~~~~~~~~~~~~~^^
  File "/home/user/code/electrum-fork/electrum/lnchannel.py", line 382, in update_unfunded_state
    self.lnworker.remove_channel(self.channel_id)
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^
  File "/home/user/code/electrum-fork/electrum/lnworker.py", line 3244, in remove_channel
    assert chan.can_be_deleted()
           ~~~~~~~~~~~~~~~~~~~^^
AssertionError
```
2025-12-10 13:20:32 +01:00
f321x
7c01d9db75 tests: lnpeer: add test_reject_mpp_for_non_mpp_invoice 2025-12-10 10:36:41 +01:00
f321x
183d426e93 lnpeer: fail htlcs if we get unwanted mpp
Fail incoming htlcs if we receive a payment consisting of multiple parts
if we signaled to not want mpp in the invoice.
2025-12-10 10:36:39 +01:00
f321x
125a921cc4 lnworker: add invoice features to PaymentInfo class
Adds the invoice features to the `PaymentInfo` class so we can check if
the sender respects our requested features (e.g. if they tried to send
mpp if we requested no mpp).
2025-12-10 10:36:31 +01:00
ghost43
f8fc2b63e3 Merge pull request #10271 from f321x/fix_save_payment_info
lightning: fix self payments (e.g. rebalance)
2025-12-05 17:19:39 +00:00
ThomasV
55cc27d27e Test JIT channels: check that lnpay success is true.
This test fails since 0f314d1dd9
2025-12-05 12:05:37 +01:00
ThomasV
40729aa0e5 test accounting_addresses: stop alice before requesting, because we need a new session.
(follow-up 9b72dc297b)
2025-12-05 11:31:27 +01:00
ThomasV
9b72dc297b lnwatcher: remove rearly return that breaks accounting_addresses
This reverts 6ffaa55.
Also, in regtests, add a check that fails if accounting_addresses are broken.
2025-12-04 10:26:01 +01:00
SomberNight
14fd85f935 json_db: fix StoredDict.__delitem__() to work similarly to .pop()
follow-up https://github.com/spesmilo/electrum/pull/10233 ("jsondb pointers")
2025-12-01 19:42:47 +00:00
SomberNight
afc87fea9a tests: json_db: add more asserts for clarity 2025-12-01 19:33:14 +00:00
f321x
923d48f9db lnworker: differentiate PaymentInfo by direction
Allows storing two different payment info of the same payment hash by
including the direction into the db key.
We create and store PaymentInfo for sending attempts and for requests (receiving),
if we try to pay ourself (e.g. through a channel rebalance) the checks
in `save_payment_info` would prevent this and throw an exception.
By storing the PaymentInfos of outgoing and incoming payments separately in
the db this collision is avoided and it makes it easier to reason about
which PaymentInfo belongs where.
2025-12-01 18:39:56 +01:00
f321x
af4dc24d87 lnworker: use config lightning fee for estimate
I was unable to do a "Max" amount submarine swap because the
`fee_estimate` method used by `LNWallet.num_sats_can_send()` uses a
hardcoded `fee_proportional_millionths` to estimate the fee for the
lightning payment.
When the actual fee determined later is higher
than the estimated fee the payment fails as the channel is unable to add
the htlc sum including the real fees as the amount exceeds the balance of
the channel.
Using the fees the maximum fees user has configured and estimate the
potential fee as inverse of PaymentFeeBudget is more
reliable/conservative as we definitely aren't going to pay more fees
than this amount.
2025-11-28 16:25:34 +01:00
f321x
59586d6f94 tests: lnpeer: add test_payment_with_malformed_onion
Adds a simple forwarding test where the receiver fails a malformed onion with
`update_fail_malformed_htlc`.
2025-11-27 17:58:51 +01:00
f321x
1fd5458b0e tests: lnpeer: test_dont_expire_htlcs
Adds unittest to test the dont_expire_htlcs logic
2025-11-27 17:58:47 +01:00
f321x
4f2e1b65f0 tests: test_lnpeer: add test_dont_settle_htlcs
Adds test for the dont_settle_htlcs functionality of lnworker used by
Just-In-Time channels.
2025-11-27 17:58:46 +01:00
f321x
abc469c846 lnworker: split dont_settle_htlcs
Splits `LNWallet.dont_settle_htlcs` into `LNWallet.dont_settle_htlcs`
and `LNWallet.dont_expire_htlcs`.

Registering a payment hash in dont_settle_htlcs will prevent it from
getting fulfilled if we have the preimage stored. The preimage will not
be released before the the payment hash gets removed from
dont_settle_htlcs. Htlcs can still get expired as usual or failed if no
preimage is known.
This is only used by Just-in-time channel openings.

Registering a payment hash in dont_expire_htlcs allows to overwrite the
minimum final cltv delta value after which htlcs would usually get
expired. This allows to delay expiry of htlcs or, if the value in the
dont_settle_htlcs dict is None, completely prevent expiry and let the
htlc get expired onchain.

Splitting this up in two different dicts makes it more explicit and
easier to reason about what they are actually doing.

 Please enter the commit message for your changes. Lines starting
2025-11-27 17:58:44 +01:00
f321x
b1e58450bd tests: test_lnpeer: add test_payment_bundle_with_hold_invoice
Adds test_payment_bundle_with_hold_invoice to simulate the use of a
payment bundle in which one invoice of the bundle needs to trigger a hold invoice
callback (similar to submarine swaps).
Also modifies the test helper _test_simple_payment() to compare the
results of all payment attempts instead of just returning after the
first (of multiple) payments raises its result causing the test to miss
if all payments were successful or not.
2025-11-27 17:58:43 +01:00
f321x
042557da9b tests: test_lnpeer: test_htlc_switch_iteration_benchmark
Benchmark how long a call to _run_htlc_switch_iteration takes with 10
trampoline mpp sets of 1 htlc each.
2025-11-27 17:58:40 +01:00