1
0
Commit Graph

160 Commits

Author SHA1 Message Date
ThomasV
d1917b2951 Merge pull request #9837 from spesmilo/htlc_slots_left
pass number of htlc_slots_left to suggest_splits
2025-05-20 12:55:45 +02:00
ThomasV
b432a1406a lnchannel: apply stricter max_htlc_value_in_flight rules for receiving
Otherwise we create invoices that eclair cannot route to us
2025-05-20 12:44:14 +02:00
f321x
e433b8d5bf explicitly test the htlc slot limit in TestMppSplit 2025-05-20 12:26:21 +02:00
ThomasV
a66439eea5 CLI: add preimage to get_invoice
This should make regtest extract_preimage more reliable
2025-05-18 15:25:06 +02:00
ThomasV
4a17d5a316 pass number of htlc_slots_left to suggest_splits 2025-05-17 15:50:03 +02:00
Sander van Grieken
c3f0993e53 test_lnchannel: add single_payment testcase for TestAvailableToSpend 2025-05-16 12:29:00 +02:00
SomberNight
6320597f2c regtests: rm sleep from "swapserver_forceclose" test
less reliance on timing
(OTOH it hardcodes the output index of the commitment tx... meh)
2025-05-15 19:50:16 +00:00
SomberNight
f3551f3c25 commands: add cmd wait_for_sync 2025-05-15 19:42:34 +00:00
SomberNight
61283fe18b adb: (trivial) receive_tx_callback: make tx_height param kw-only 2025-05-15 19:09:37 +00:00
ThomasV
6500788328 Merge pull request #9710 from f321x/dont_delete_config_on_syntax_error
config: Raise instead of overwriting the config file on syntax error
2025-05-15 17:24:35 +02:00
f321x
8870838834 raise instead of overwriting the config file on syntax error 2025-05-15 17:21:16 +02:00
ghost43
79a54c1578 Merge pull request #9826 from f321x/fix_fee_disagreement_ln
fix: reduce update_fee target for anchor channels
2025-05-15 13:30:11 +00:00
ThomasV
93e7de20e9 Merge pull request #9753 from f321x/debug_ln_payment_failure
ln: don't exclude single part configs for too small payments
2025-05-15 13:25:00 +02:00
f321x
e8171ca7c6 suggest_splits: don't exclude single part configs for too small multi
part configs

I noticed certain ln payments become very unreliable. These payments are ~21k sat, from gossip to gossip sender, with direct, unannounced channel.

Due to the recent fix https://github.com/spesmilo/electrum/pull/9723 `LNPathFinder.get_shortest_path_hops()` will not use channels for the last hop of a route anymore that aren't also passed to it in `my_sending_channels`:

```python
if edge_startnode == nodeA and my_sending_channels:  # payment outgoing, on our channel
    if edge_channel_id not in my_sending_channels:
        continue
```

Conceptually this makes sense as we only want to send through `my_sending_channels`, however if the only channel between us and the receiver is a direct channel that we got from the r_tag and it's not passed in `my_sending_channel` it's not able to construct a route now.

Previously this type of payment worked as `get_shortest_path_hops()` knew of the direct channel between us and `nodeB` from the invoices r_tag and then just used this channel as the route, even though it was (often) not contained in `my_sending_channels`.

`my_sending_channels`, passed in `LNWallet.create_routes_for_payment()` is either a single channel or all our channels, depending on `is_multichan_mpp`:

```python
for sc in split_configurations:
	  is_multichan_mpp = len(sc.config.items()) > 1
```

This causes the unreliable, random behavior as `LNWallet.suggest_splits()` is supposed to `exclude_single_part_payments` if the amount is > `MPP_SPLIT_PART_MINAMT_SAT` (5000 sat).
As `mpp_split.py suggest_splits()` is selecting channels randomly, and then removes single part configs, it sometimes doesn't return a single configuration, as it removes single part splits, and also removes multi part splits if a part is below 10 000 sat:

```python
if target_parts > 1 and config.is_any_amount_smaller_than_min_part_size():
    continue
```

This will result in a fallback to allow single part payments:

```python
split_configurations = get_splits()
if not split_configurations and exclude_single_part_payments:
    exclude_single_part_payments = False
    split_configurations = get_splits()
```

Then the payment works as all our channels are passed as `my_sending_channels` to  `LNWallet.create_routes_for_payment()`.

However sometimes this fallback doesn't happen, because a few mpp configurations found in the first iteration of `suggest_splits` have been kept, e.g. [10500, 10500], but at the same time most others have been removed as they crossed the limit, e.g. [11001, 9999], (which happens sometimes with payments ~20k sat), this makes `suggest_splits` return very few usable channels/configurations (sometimes just one or two, even with way more available channels).
This makes payments in this range unreliable as we do not retry to generate new split configurations if the following path finding fails with `NoPathFound()`, and there is no single part configuration that allows the path finding to access all channels. Also this does not only affect direct channel payments, but all gossip payments in this amount range.

There seem to be multiple ways to fix this, i think one simple approach is to just disable `exclude_single_part_payments` if the splitting loop already begins to sort out configs on the second iteration (the first split), as this indicates that the amount may be too small to split within the given limits, and prevents the issue of having only few valid splits returned and not going into the fallback. However this also results in increased usage of single part payments.
2025-05-15 10:26:33 +02:00
f321x
61874e9fe7 fix: reduce update_fee target for anchor channels
the update_fee logic for lightning channels was not adapted to anchor
channels causing us to send update_fee with a eta target of 2 blocks.
This causes force closes when there are mempool spikes as the fees we
try to update to are a lot higher than e.g. eclair uses. Eclair will
force close if our fee is 10x > than their fee.
2025-05-14 18:01:44 +02:00
SomberNight
44f3444795 lnworker: make "preimages" dict private
I want to hook into lnworker.save_preimage (not done yet).
Other modules should not put preimages into the dict directly.
2025-05-14 13:23:02 +00:00
ThomasV
660ffa2b8f fix test_txbatcher (follow-up 6e3f173a71) 2025-05-13 09:09:35 +02:00
ThomasV
6e3f173a71 SweepInfo: define csv_delay as property 2025-05-13 08:50:33 +02:00
ThomasV
0607a406ce Qt: add closing warning if we have an unconfirmed local commitment tx with htlcs
add htlc direction (offered, received) to the htlc sweep_info name
regtest: add test_reedeem_received_htlcs
2025-05-12 15:48:20 +02:00
Oren
2fb0dd066f Timelock Recovery Extension (#9589)
* Timelock Recovery Extension

* Timelock Recovery Extension tests

* Use fee_policy instead of fee_est

Following 3f327eea07

* making tx with base_tx

Following ab14c3e138

* move plugin metadata from __init__.py to manifest.json

* removing json large indentation

* timelock recovery icon

* timelock recovery plugin: fix typos

* timelock recovery plugin: use menu instead of status bar.

The status bar should be used for displaying status. For example,
hardware wallet plugins use it because their connection status is
changing and needs to be displayed.

* timelock recovery plugin: ask for password only once

* timelock recovery plugin: ask whether to create cancellation tx in the initial window

* remove unnecessary code.

(calling run_hook from a plugin does not make sense)

* show alert and cancellation address at the end.

skip unnecessary dialog

* timelock recovery plugin: do not show transactions one by one.

Set the fee policy in the first dialog, and use the same fee
policy for all tx. We could add 3 sliders to this dialog, if
different fees are needed, but I think this really isn't
really necessary.

* simplify default_wallet for tests

All the lightning-related stuff is irrelevant for
this plugin.

Also use a different destination address
for the test recovery-plan (an address
that does not belong to the same wallet).

* Fee selection should be above fee calculation

also show fee calculation result with "fee: " label.

* hide Sign and Broadcast buttons during view

* recalculate cancellation transaction

The checkbox could be clicked after the fee rate
has been set. Calling update_transactions() may seem
inefficient, but it's the simplest way to avoid such edge-cases.

Also set the context's cancellation transaction to None when the
checkbox is unset.

* use context.cancellation_tx instead of checkbox value

context.cancellation_tx will be None iff the checkbox was unset

* hide cancellation address if not used

* init monospace font correctly

* timelock recovery plugin: add input info at signing time.

Fixes trezor exception: 'Missing previous tx'

* timelock recovery: remove unused parameters

* avoid saving the tx in a separate var

fixing the assertions

* avoid caching recovery & cancellation inputs

* timelock recovery: separate help window from agreement.

move agreement at the end of the flow, rephrase it

* do not cache alert_tx_outputs

* do not crash when not enough funds

not enough funds can happen
when multiple addresses are specified
in payto_e, with an amount larger
than the wallet has - so we set
the payto_e color to red.

It can also happen when the user
selects a really high fee, but this
is not common in a "recovery"
wallet with significant funds.

* If files not saved - ask before closing

* move the checkbox above the save buttons

people read the text from top to
bottom and may not understand
why the buttons are disabled

---------

Co-authored-by: f321x <f321x@tutamail.com>
Co-authored-by: ThomasV <thomasv@electrum.org>
2025-04-22 10:02:01 +02:00
f321x
8d79c58c5e Stop including all invoice r_tags in legacy trampoline onion
This change modifies create_trampoline_onion to only include as many
available r_tags as there is space left in the trampoline onion payload.

Previously we tried to include all passed invoice r_tags of legacy
trampoline payments into the payload which caused an user facing
exception and payment failure as the onion can only store a max of 400
bytes.
A single, single hop r_tag is around 52 bytes and the payload
without r_tags is already at ~280 bytes. So usually there is enough
space for 2 r_tags.
The implementation shuffles the r_tags on each call
so the payment will try different route hints on the attempts (fee level
increase or user retry).

I have logged the following byte sizes of the trampoline onion with a 2
trampoline onion hop and changing amounts of r_tags:

3 rtags:
payload size [0]: 113 (hop size: 81)
payload size [1]: 440 (hop size: 295) ( 52 bytes/rtag )
payload size [2]: 550 (hop size: 78)

2 rtags:
payload size [0]: 113 (hop size: 81)
payload size [1]: 386 (hop size: 241) ( 52 bytes/rtag )
payload size [2]: 496 (hop size: 78)

1 rtag:
payload size [0]: 113 (hop size: 81)
payload size [1]: 334 (hop size: 189) ( 52 bytes/rtag )
payload size [2]: 444 (hop size: 78)

0 rtags:
payload size [0]: 113 (hop size: 81)
payload size [1]: 282 (hop size: 137)
payload size [2]: 392 (hop size: 78)

As can be seen in the data, using 2 trampoline hops there is not enough
space for even a single r_tag which is why this option is being removed
too.
2025-04-14 19:20:11 +02:00
ThomasV
bcb6df72a7 Merge pull request #9729 from spesmilo/recursive_config
recursive config file
2025-04-11 20:02:25 +02:00
SomberNight
bd0085e680 tests: commands: add test_setconfig_none 2025-04-11 17:17:53 +00:00
ThomasV
8f3490c87e recursive config file
move plugin variables into sub dictionaries of user config
2025-04-11 19:06:48 +02:00
SomberNight
5c17f452b1 tests: util.custom_task_factory: fix res warn "coro was never awaited"
follow-up 70d1e1170e

```
=============================== warnings summary ===============================
tests/test_util.py::TestUtil::test_custom_task_factory
  /tmp/cirrus-ci-build/tests/test_util.py:504: RuntimeWarning: coroutine 'TestUtil.test_custom_task_factory.<locals>.foo' was never awaited
    self.assertEqual(foo().__qualname__, task.get_coro().__qualname__)
  Enable tracemalloc to get traceback where the object was allocated.
  See https://docs.pytest.org/en/stable/how-to/capture-warnings.html#resource-warnings for more info.

```
2025-04-10 13:10:58 +00:00
ThomasV
1494cca486 Merge pull request #9681 from f321x/txbatcherror
wallet: make txbatcher wait for network connection
2025-04-09 12:44:57 +02:00
SomberNight
70d1e1170e asyncio: clarify strong refs for run_coroutine_threadsafe
We added some code in 0b3a283586
to explicitly hold strong refs for all tasks/futures. At the time I was uncertain if that also solves
GC issues with asyncio.run_coroutine_threadsafe.
ref https://github.com/spesmilo/electrum/pull/9608#issuecomment-2703681663

Looks like it does. run_coroutine_threadsafe *is* going through the custom task factory.
See the unit test.
The somewhat confusing thing is that we need a few event loop iterations for the task factory to run,
due to how run_coroutine_threadsafe is implemented. And also, the task that we will hold as strong ref
in the global set is not the concurrent.futures.Future that run_coroutine_threadsafe returns.

So this commit simply "fixes" the unit test so that it showcases this, and removes related, older, plumbing
from util.py that we now know is no longer needed because of this.
2025-04-08 18:54:58 +00:00
f321x
42bd334f5b add coinchooser test with zero fee estimation 2025-04-07 17:14:25 +02:00
f321x
03018fa218 make txbatcher wait for network connection 2025-04-04 11:43:24 +02:00
ThomasV
001a1152fd add unit tests for ln_utxo_reserve 2025-04-03 14:39:05 +02:00
SomberNight
5c233ac325 ci: enable more flake8 stuff
```
$ export ELECTRUM_LINTERS=E9,E101,E129,E273,E274,E703,E71,E722,F5,F6,F7,F8,W191,W29,B
$ export ELECTRUM_LINTERS_IGNORE=B007,B009,B010,B019,B036,F541,F841
$ flake8 . --count --select="$ELECTRUM_LINTERS" --ignore="$ELECTRUM_LINTERS_IGNORE" --show-source --statistics --exclude "*_pb2.py,electrum/_vendor/"
./electrum/commands.py:98:1: F811 redefinition of unused 'format_satoshis' from line 48
def format_satoshis(x):
^
./electrum/commands.py:437:9: F811 redefinition of unused 'Mnemonic' from line 62
        from .mnemonic import Mnemonic
        ^
./electrum/gui/qt/wizard/wallet.py:37:5: F811 redefinition of unused 'Daemon' from line 14
    from electrum.daemon import Daemon
    ^
./electrum/lntransport.py:14:1: F811 redefinition of unused 'Optional' from line 12
from typing import NamedTuple, List, Tuple, Mapping, Optional, TYPE_CHECKING, Union, Dict, Set, Sequence
^
./electrum/lntransport.py:14:1: F811 redefinition of unused 'TYPE_CHECKING' from line 12
from typing import NamedTuple, List, Tuple, Mapping, Optional, TYPE_CHECKING, Union, Dict, Set, Sequence
^
./electrum/plugin.py:966:13: F811 redefinition of unused 'hid' from line 593
            import hid
            ^
./electrum/plugin.py:1040:13: F811 redefinition of unused 'hid' from line 593
            import hid
            ^
./electrum/util.py:44:1: F811 redefinition of unused 'json' from line 26
import json
^
./electrum/util.py:46:1: F811 redefinition of unused 'NamedTuple' from line 29
from typing import NamedTuple, Optional
^
./electrum/util.py:46:1: F811 redefinition of unused 'Optional' from line 29
from typing import NamedTuple, Optional
^
./electrum/util.py:1456:56: F811 redefinition of unused 'traceback' from line 34
        async def __aexit__(self, exc_type, exc_value, traceback):
                                                       ^
./electrum/wallet_db.py:536:9: F811 redefinition of unused 'LOCAL' from line 46
        LOCAL = 1
        ^
./electrum/wallet_db.py:537:9: F811 redefinition of unused 'REMOTE' from line 46
        REMOTE = -1
        ^
./tests/test_bitcoin.py:28:1: F811 redefinition of unused 'bitcoin' from line 9
from electrum import crypto, constants, bitcoin
^
./tests/test_txbatcher.py:11:1: F811 redefinition of unused 'Transaction' from line 7
from electrum.transaction import Transaction, PartialTxInput, PartialTxOutput, TxOutpoint
^
./tests/test_wallet_vertical.py:20:1: F811 redefinition of unused 'Transaction' from line 10
from electrum.transaction import Transaction, PartialTxOutput, tx_from_any, Sighash
^
16    F811 redefinition of unused 'format_satoshis' from line 48
16

```
2025-04-02 16:21:59 +00:00
SomberNight
5f551183ae tests/test_txbatcher.py: fix race in network.next_tx()
With `txbatcher.SLEEP_INTERVAL = 0.01`, on my laptop, the batcher called try_broadcasting() even before next_tx() effectively awaited _tx_event.
This resulted in the test failing due to timeout.

Basically, if the txbatcher.SLEEP_INTERVAL was too low, the 2-4 event loop iterations needed to await _tx_event.wait() took too long.
(note that the exact number of event loop iterations needed depends on the python version and the OS)
2025-04-01 15:54:05 +00:00
SomberNight
2807be08c8 tests/test_txbatcher.py: de-duplicate "create wallet" logic 2025-04-01 15:00:23 +00:00
f321x
0b19b660c5 don't use fallback feerates in lightning by default 2025-04-01 14:12:02 +02:00
ThomasV
e67cb560f6 Commands: add option documentation in docstring.
This allows plugins to document the commands they add.

The docstring is parsed as a regular expression:

    arg:<type>:<name>:<description>\n

Types are defined in commands.arg_types.

Note that this commit removes support for single letter
shortcuts in command options.

If a command is not properly documented, a warning is issued
with print(), because no logger is available at this point.
2025-03-19 13:03:38 +01:00
ThomasV
d8964a00e7 config vars for plugins 2025-03-19 11:59:05 +01:00
ThomasV
26910ef81d Merge pull request #9620 from accumulator/lightning_pass_invoice_not_bolt11
refactor lnworker.pay_invoice to accept Invoice object instead of bolt11 string
2025-03-18 20:09:01 +01:00
f321x
246f03fe20 allow all plugins to be either zip or directory based 2025-03-17 16:27:33 +01:00
ThomasV
81d4e90f66 Merge branch 'master' into 140325-force-close-exception 2025-03-14 19:38:13 +01:00
SomberNight
977d8b1dd6 wallet: kill create_transaction 2025-03-14 17:19:41 +00:00
f321x
5edbf923cd fix sweeping anchor outputs with multiple change addresses option enabled, don't consider tx inputs sufficient value if there are no outputs so change outpu gets added 2025-03-14 18:15:04 +01:00
SomberNight
3c3778db9c wallet: towards killing create_transaction: rm "sign" arg 2025-03-14 16:44:46 +00:00
ThomasV
fbebe7de1a Make lnwatcher not async
This fixes offline history not having the proper labels
2025-03-14 11:09:11 +01:00
SomberNight
8ccd31fe49 wallet: set_frozen_state_of_coins to handle freeze=None
Internally whether a coin is frozen is tri-state:
- forced-True, set by the user
- forced-False, set by the user
- unset/default: is_frozen_coin() can decide whether the coin should be frozen

This patch lets set_frozen_state_of_coins() undo a previous explicit setting of True/False,
by calling it with a value of None.
Note: there is still no way in the GUI to undo an explicit setting of True/False.
2025-03-13 18:32:58 +00:00
ThomasV
bdb7a82220 batch payment manager:
The class TxBatcher handles the creation, broadcast and replacement
of replaceable transactions. Callers (LNWatcher, SwapManager) use
methods add_payment_output and add_sweep_info. Transactions
created by TxBatcher may combine sweeps and outgoing payments.

Transactions created by TxBatcher will have their fee bumped
automatically (this was only the case for sweeps before).

TxBatcher manages several TxBatches. TxBatches are created
dynamically when needed.

The GUI does not touch txbatcher transactions:
  - wallet.get_candidates_for_batching excludes txbatcher
    transactions
  - RBF dialogs do not work with txbatcher transactions

wallet:
  - instead of reading config variables, make_unsigned_transaction
    takes new parameters: base_tx, send_change_to_lighting

tests:
  - unit tests in test_txbatcher.py (replaces test_sswaps.py)
  - force all regtests to use MPP, so that we sweep transactions
    with several HTLCs. This forces the payment manager to aggregate
    first-stage HTLC tx inputs. second-stage are not batched for now.
2025-03-13 10:17:10 +01:00
ThomasV
798df671ea If we have proposed htlcs in a channel that was force-closed,
call lnworker.htlc_failed once the htlc_tx is deeply mined.

In the case of a forwarding, this will fail incoming htlcs.
(fixes #8547)
2025-03-12 20:11:11 +01:00
SomberNight
0d120145d5 tests/regtest.py: trivial clean-up
from dde7fd09ac
2025-03-10 14:54:50 +00:00
ThomasV
707d87a0d4 Revert "regtests: in py ctx, refer to configvars directly, not as str literals"
This reverts commit dde7fd09ac.
2025-03-10 12:01:41 +01:00
Sander van Grieken
6fdb6c93f7 refactor lnworker.pay_invoice to accept Invoice object instead of bolt11 string
rename lnworker._check_invoice to lnworker._check_bolt11_invoice
2025-03-09 14:47:34 +01:00
Sander van Grieken
6331ac0f85 lnutil: imports, whitespace, remove unused code 2025-03-09 12:30:02 +01:00