(invoices for which we do not have the preimage)
Callbacks and timeouts are registered with lnworker. If the
preimage is not known after the timeout has expired, the payment
is failed with MPP_TIMEOUT.
- qt chan details dlg: show both local and remote aliases
- lnchannel: more descriptive names, add clarification in doctstrings,
and also save the "local_scid_alias" in the wallet file (to remember if
we sent it)
- lnpeer:
- resend channel_ready msg after reestablish, to upgrade old existing channels
to having local_scid_alias
- forwarding bugfix, to follow BOLT-04:
> - if it returns a `channel_update`:
> - MUST set `short_channel_id` to the `short_channel_id` used by the incoming onion.
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
```
On mobile, it can take a while before channelDB is loaded. If payment is attempted before the DB
is fully loaded, this would result in a payment failure, but also leaves the payment attempt in IN_PROGRESS
state. This patch adds a more specific ChannelDBNotLoaded exception class, so we can handle this case more
gracefully, since we know the payment didn't succeed.
fixes https://github.com/spesmilo/electrum/issues/8402
To reproduce,
- create wallet from a zpub
- LN is disabled there by default
- create a receive request, which won't have a lightning part
- enable config var "bip21_lightning"
- enable LN
- existing request is now ~breaking receive tab
This fixes a bug where if one runs `wallet.clear_history()` they would see exceptions later:
```
Traceback (most recent call last):
File "/home/user/wspace/electrum/electrum/gui/qt/main_window.py", line 866, in timer_actions
self.update_wallet()
File "/home/user/wspace/electrum/electrum/gui/qt/main_window.py", line 1021, in update_wallet
self.update_tabs()
File "/home/user/wspace/electrum/electrum/gui/qt/main_window.py", line 1033, in update_tabs
self.utxo_list.update()
File "/home/user/wspace/electrum/electrum/gui/qt/utxo_list.py", line 103, in update
self.refresh_row(name, idx)
File "/home/user/wspace/electrum/electrum/gui/qt/utxo_list.py", line 124, in refresh_row
parents = self.wallet.get_tx_parents(txid)
File "/home/user/wspace/electrum/electrum/wallet.py", line 885, in get_tx_parents
result.update(self.get_tx_parents(_txid))
File "/home/user/wspace/electrum/electrum/wallet.py", line 881, in get_tx_parents
for i, txin in enumerate(tx.inputs()):
AttributeError: 'NoneType' object has no attribute 'inputs'
```
This is related to the privacy analysis, which assumes that for each tx item in the history list
we should have the raw tx in the db. This is no longer true after wallet.clear_history(), if
the wallet has certain LN channels. E.g. an already redeemed channel that was local-force-closed,
as that closing tx is not related to the wallet directly.
In commit 3541ecb576, we decided not to watch already redeemed channels.
This is potentially good for e.g. privacy, as the server would otherwise see us subscribe to that chan.
However it means that after running wallet.clear_history() txs related to the channel but not to the
wallet won't be re-downloaded.
Instead, now if there are missing txs for a redeemed channel, we start watching it, hence the
synchronizer will re-downloaded the txs.
- save remote alias for use in invoices
- derive local alias from wallet xpub
- send channel_type without the option_scid_alias bit
(apparently LND does not like it)
Sometimes the trampoline node fails to send a payment and returns
TEMPORARY_CHANNEL_FAILURE, while it succeeds with a higher trampoline
fee. My guess is that the initial fee was not sufficient to try
all routes, and that a higher fee allows to use extra routes. I
suppose it would make more sense if the trampoline node returned
TRAMPOLINE_FEE_INSUFFICIENT in that case.
* add invoice status to invoice_status callback
* debug statement fails tests
* removed commented lines, added progress/attempt counter comment in lnworker.pay_to_node,
and update the invoice_status event handler in qeinvoicelistmodel.py
If the short_channel_id of a channel update received
with update_fail_htlc does not match the channel in
our route, blacklist the channel in our route.
Before this commit, partial results were yielded before we had
examined the whole split configuration.
I think the correct behaviour is to create all the routes for the
current configuration, then to yield them. If there is an exception,
we should try the next one.
Upon receiving UNKNOWN_NEXT_PEER, TEMPORARY_NODE_FAILURE
or TEMPORARY_CHANNEL_FAILURE, remember the trampoline route
that was used, and try other routes before raising the
trampoline fee.
Before this commit, we used to raise the trampoline fee
upon receiving any error message, in order to ensure
termination of the payment loop.
Note that we will still retry failing routes after we have
raised the trampoline fee. This choice is questionable, it
is unclear if doing so significantly increases the probability
of success.
Tests: add a test for trampoline handling of UNKNOWN_NEXT_PEER
Replace get_key_for_outgoing_invoice, get_key_for_incoming_request
with Invoice.get_id()
When a new request is created, reuse addresses of expired requests (fixes#7927)
The API is changed for the following commands:
get_request, get_invoice,
list_requests, list_invoices,
delete_request, delete_invoice
`wallet.make_unsigned_transaction` can raise NotEnoughFunds or NoDynamicFeeEstimates.
These are "expected" exceptions that need to be handled or worked around. Added a note
of this in the docstring now.
We now handle NoDynamicFeeEstimates by allowing a static fallback fee in
`wallet.can_pay_onchain` and `lnworker.suggest_funding_amount`. It should be
fine to have a static fallback in these cases, as the user still has a chance
to set their own fee later in the flow.
(though ofc the static fallback might be too high in some mempool conditions,
in which case e.g. can_pay_onchain might return a false-negative, but this
is still an improvement over raising I believe)
fixes https://github.com/spesmilo/electrum/issues/5784
Previously lnworker called LNWatcher.add_channel() on these, and then LNWatcher itself decided to unwatch them.
-----
note: motivation related to https://github.com/spesmilo/electrum/pull/7932#discussion_r945755584 ,
where I have legacy (pre-staticremotekey) redeemed channels in a wallet.
Tracebacks:
```
E/W | lnwatcher.LNWalletWatcher.[default_wallet-LNW] | Exception in do_breach_remedy: AssertionError()
Traceback (most recent call last):
File "...\electrum\electrum\util.py", line 1235, in wrapper
return await func(*args, **kwargs)
File "...\electrum\electrum\lnwatcher.py", line 443, in do_breach_remedy
sweep_info_dict = chan.sweep_ctx(closing_tx)
File "...\electrum\electrum\lnchannel.py", line 264, in sweep_ctx
our_sweep_info = self.create_sweeptxs_for_our_ctx(ctx)
File "...\electrum\electrum\lnchannel.py", line 253, in create_sweeptxs_for_our_ctx
return create_sweeptxs_for_our_ctx(chan=self, ctx=ctx, sweep_address=self.sweep_address)
File "...\electrum\electrum\lnchannel.py", line 757, in sweep_address
assert self.is_static_remotekey_enabled()
AssertionError
```
```
E/W | lnwatcher.LNWalletWatcher.[default_wallet-LNW] | Exception in trigger_callbacks: AssertionError()
Traceback (most recent call last):
File "...\electrum\electrum\util.py", line 1235, in wrapper
return await func(*args, **kwargs)
File "...\electrum\electrum\lnwatcher.py", line 208, in trigger_callbacks
await callback()
File "...\electrum\electrum\lnwatcher.py", line 225, in check_onchain_situation
keep_watching = await self.do_breach_remedy(funding_outpoint, closing_tx, spenders)
File "...\electrum\electrum\util.py", line 1235, in wrapper
return await func(*args, **kwargs)
File "...\electrum\electrum\lnwatcher.py", line 443, in do_breach_remedy
sweep_info_dict = chan.sweep_ctx(closing_tx)
File "...\electrum\electrum\lnchannel.py", line 264, in sweep_ctx
our_sweep_info = self.create_sweeptxs_for_our_ctx(ctx)
File "...\electrum\electrum\lnchannel.py", line 253, in create_sweeptxs_for_our_ctx
return create_sweeptxs_for_our_ctx(chan=self, ctx=ctx, sweep_address=self.sweep_address)
File "...\electrum\electrum\lnchannel.py", line 757, in sweep_address
assert self.is_static_remotekey_enabled()
AssertionError
```