- is_trampoline was True iff we are the final recipient of a trampoline payment
- in that case, we were only comparing htlc.cltv_expiry against the outer onion cltv
- we should and do now also compare against the inner onion cltv
- the checks are changed from "!=" to "<", to adapt to bolts PR 1032
- see b38156b951
- note that the leniency is needed for the cltv off-by-one
added in eca10eb04d to work
propageate back to the sender.
lnworker: in htlc_fulfilled and htlc_failed, return early if the
htlc was forwarded, so that we do not trigger invoice callbacks
lnworker.pay_to_node(min_cltv_expiry=) expects a relative cltv, and
we were passing an absolute one.
It is not so clear what precisely should be passed here, and that is
because pay_to_node's API was not written with forwarding in mind.
The value chosen here is just some guess that typically should work.
catch OSError for proxy-related issues (and probably other low level networking)
```
19.52 | E | exchange_rate.CoinGecko | failed fx quotes: ProxyConnectionError(22, 'Can not connect to proxy localhost:9050 [The remote computer refused the network connection]')
Traceback (most recent call last):
File "...\Python310\site-packages\python_socks\async_\asyncio\ext\_proxy.py", line 59, in _connect
await self._stream.open_connection(
File "...\Python310\site-packages\python_socks\async_\asyncio\ext\_stream.py", line 61, in open_connection
self._reader, self._writer = await asyncio.open_connection(
File "...\Python310\lib\asyncio\streams.py", line 48, in open_connection
transport, _ = await loop.create_connection(
File "...\Python310\lib\asyncio\base_events.py", line 1076, in create_connection
raise exceptions[0]
File "...\Python310\lib\asyncio\base_events.py", line 1060, in create_connection
sock = await self._connect_sock(
File "...\Python310\lib\asyncio\base_events.py", line 969, in _connect_sock
await self.sock_connect(sock, address)
File "...\Python310\lib\asyncio\proactor_events.py", line 709, in sock_connect
return await self._proactor.connect(sock, address)
File "...\Python310\lib\asyncio\windows_events.py", line 826, in _poll
value = callback(transferred, key, ov)
File "...\Python310\lib\asyncio\windows_events.py", line 613, in finish_connect
ov.getresult()
ConnectionRefusedError: [WinError 1225] The remote computer refused the network connection
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "...\electrum\exchange_rate.py", line 85, in update_safe
self._quotes = await self.get_rates(ccy)
File "...\electrum\exchange_rate.py", line 345, in get_rates
json = await self.get_json('api.coingecko.com', '/api/v3/exchange_rates')
File "...\electrum\exchange_rate.py", line 69, in get_json
async with session.get(url) as response:
File "...\Python310\site-packages\aiohttp\client.py", line 1140, in __aenter__
self._resp = await self._coro
File "...\Python310\site-packages\aiohttp\client.py", line 535, in _request
conn = await self._connector.connect(
File "...\Python310\site-packages\aiohttp\connector.py", line 543, in connect
proto = await self._create_connection(req, traces, timeout)
File "...\Python310\site-packages\aiohttp\connector.py", line 906, in _create_connection
_, proto = await self._create_direct_connection(req, traces, timeout)
File "...\Python310\site-packages\aiohttp\connector.py", line 1174, in _create_direct_connection
transp, proto = await self._wrap_create_connection(
File "...\Python310\site-packages\aiohttp_socks\connector.py", line 58, in _wrap_create_connection
stream = await proxy.connect(
File "...\Python310\site-packages\python_socks\async_\asyncio\ext\_proxy.py", line 47, in connect
await self._connect()
File "...\Python310\site-packages\python_socks\async_\asyncio\ext\_proxy.py", line 73, in _connect
raise ProxyConnectionError(e.errno, msg) from e
python_socks._errors.ProxyConnectionError: [Errno 22] Can not connect to proxy localhost:9050 [The remote computer refused the network connection]
```
- construct_channel_announcement: return also whether
node ids are in reverse order
- maybe_send_channel_announcement:
return early if signatures have not been received
- see comment in lnaddr.py
- Previously we used feature bit 50/51 for trampoline.
The spec subsequently defined fbit 50/51 as option_zeroconf, which
requires fbit 46/47 (option_scid_alias) to also be set.
We moved the non-standard trampoline fbit to a different int.
However, old wallets might have old invoices saved that set fbit 50/51
for trampoline, and those would not have the dependent bit set.
Invoices are parsed at wallet-open, so if the parser ran these checks,
those wallets could not be opened.
- note: we could potentially also run lnaddr.validate_and_compare_features
when saving new invoices into the wallet but this is not done here
The following exceptions should be expected:
FileNotFoundError: given wallet path does not exist
StorageReadWriteError: given file is not readable/writable or containing folder is not writable
InvalidPassword: wallet requires a password but no password or an invalid password was given
WalletFileException: any internal wallet data issue. specific subclasses can be caught separately:
- WalletRequiresSplit: wallet needs splitting (split_data passed in Exception)
- WalletRequiresUpgrade: wallet needs upgrade, and no upgrade=True was passed to load_wallet
- WalletUnfinished: wallet file contains an action and needs additional information to finalize. (WalletDB passed in exception)
Removed qml/qewalletdb.py
This patch also fixes load_wallet calls in electrum/scripts and adds a qml workaround for dialogs opening and closing so
fast that the dialog opened==true property change is missed (which we need to manage the dialog/page stack)
The return value of f.write and f.seek cannot be compared when using open() in text mode:
```
>>> import os
>>> s = "aá"
>>>
>>> with open("a1", "w", encoding='utf-8') as f:
... a = f.write(s)
... pos = f.seek(0, os.SEEK_END)
... print(a, pos)
...
2 3
>>>
>>> with open("a2", "wb") as f:
... a = f.write(s.encode('utf-8'))
... pos = f.seek(0, os.SEEK_END)
... print(a, pos)
...
3 3
```
Was getting errors on Windows, probably due to `\r\n` vs `\n`?
```
20231010T121334.522573Z | ERROR | util.CallbackManager | cb errored. event='adb_set_up_to_date'. exc=AssertionError((2471475, 2522998))
Traceback (most recent call last):
File "...\electrum\electrum\wallet.py", line 497, in on_event_adb_set_up_to_date
self.save_db()
File "...\electrum\electrum\wallet.py", line 403, in save_db
self.db.write()
File "...\electrum\electrum\json_db.py", line 48, in wrapper
return func(self, *args, **kwargs)
File "...\electrum\electrum\json_db.py", line 389, in write
self._append_pending_changes()
File "...\electrum\electrum\json_db.py", line 48, in wrapper
return func(self, *args, **kwargs)
File "...\electrum\electrum\json_db.py", line 400, in _append_pending_changes
self.storage.append(s)
File "...\electrum\electrum\storage.py", line 110, in append
assert pos == self.pos, (self.pos, pos)
AssertionError: (2471475, 2522998)
```
Python 3.12 does not work with current aiohttp, see
https://github.com/aio-libs/aiohttp/issues/7229
It is currently possible to build a wheel using aiohttp==3.9.0b0.
However, unit tests fail in that case, because TestLNTransport::test_loop stalls.