This is a regression from 7ca89f56ee, which introduced StoredList.
The newly added test was failing without the change.
```
Traceback (most recent call last):
File "/home/user/wspace/electrum/electrum/gui/qt/main_window.py", line 1786, in new_contact_dialog
self.set_contact(line2.text(), line1.text())
File "/home/user/wspace/electrum/electrum/gui/qt/main_window.py", line 1435, in set_contact
self.contacts[address] = ('address', label)
File "/home/user/wspace/electrum/electrum/contacts.py", line 75, in __setitem__
self.save()
File "/home/user/wspace/electrum/electrum/contacts.py", line 62, in save
self.db.put('contacts', dict(self))
File "/home/user/wspace/electrum/electrum/json_db.py", line 42, in wrapper
return func(self, *args, **kwargs)
File "/home/user/wspace/electrum/electrum/json_db.py", line 318, in put
self.data[key] = copy.deepcopy(value)
File "/usr/lib/python3.10/copy.py", line 146, in deepcopy
y = copier(x, memo)
File "/usr/lib/python3.10/copy.py", line 231, in _deepcopy_dict
y[deepcopy(key, memo)] = deepcopy(value, memo)
File "/usr/lib/python3.10/copy.py", line 172, in deepcopy
y = _reconstruct(x, memo, *rv)
File "/usr/lib/python3.10/copy.py", line 271, in _reconstruct
state = deepcopy(state, memo)
File "/usr/lib/python3.10/copy.py", line 146, in deepcopy
y = copier(x, memo)
File "/usr/lib/python3.10/copy.py", line 231, in _deepcopy_dict
y[deepcopy(key, memo)] = deepcopy(value, memo)
File "/usr/lib/python3.10/copy.py", line 172, in deepcopy
y = _reconstruct(x, memo, *rv)
File "/usr/lib/python3.10/copy.py", line 271, in _reconstruct
state = deepcopy(state, memo)
File "/usr/lib/python3.10/copy.py", line 146, in deepcopy
y = copier(x, memo)
File "/usr/lib/python3.10/copy.py", line 231, in _deepcopy_dict
y[deepcopy(key, memo)] = deepcopy(value, memo)
File "/usr/lib/python3.10/copy.py", line 161, in deepcopy
rv = reductor(4)
TypeError: cannot pickle '_thread.RLock' object
```
The wizard should technically disallows this at creation time,
but this second layer sanity check could not hurt.
Also, looks like the wizard check is not working properly atm
(regression from qt wizard refactor).
- introduce PaymentFeeBudget, which contains limits for fee budget and cltv budget
- when splitting a payment,
- the fee budget is linearly distributed between the parts
- this resolves a FIXME in lnrouter ("FIXME in case of MPP")
- the cltv budget is simply copied
- we could also add other kinds of budgets later, e.g. for the num in-flight htlcs
- resolves TODO in lnworker ("todo: compare to the fee of the actual route we found")
- Refactor _run_mpp so that it takes only one set of arguments.
Success and failure conditions are now tested by calling
_run_mpp multiple times.
- In test_payment_multipart with_timeout, check that the received
failure message actually is MPP_TIMEOUT, and not a generic
failure. Since the onion is obfuscated by the forwarding node,
this tests that obfuscate_onion_packet and decode_onion_packet
work as expected.
- 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
- do not use needs_test_with_all_chacha20_implementation,
this is slow and not really useful here.
- split TestPeer class in two classes, depending on the type
of graph we use.
Somewhat a follow-up to 649ce979ab.
This adds some safety belts so we don't accidentally sign a tx that
contains a dummy address.
Specifically we check that tx does not contain output for dummy addr:
- in wallet.sign_transaction
- in network.broadcast_transaction
The second one is perhaps redundant, but I think it does not hurt.
Besides a literal value, the default can now also be a callable,
which gets called with the config and evaluated as needed, lazily.
This potentially allows e.g. the default value of one configvar to
depend on the current value of another configvar.
```
electrum/tests/test_network.py::TestNetwork::test_can_connect_during_backward
electrum/tests/test_network.py::TestNetwork::test_chain_false_during_binary
electrum/tests/test_network.py::TestNetwork::test_fork_conflict
electrum/tests/test_network.py::TestNetwork::test_fork_noconflict
/tmp/cirrus-ci-build/electrum/interface.py:410: RuntimeWarning: coroutine 'Interface.run' was never awaited
task = await self.network.taskgroup.spawn(self.run())
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.
```
closes https://github.com/spesmilo/electrum/pull/7817
Manage global event loop so that it is accessible to threads
other than the asyncio thread. In particular, the Plugins
thread needs to reference it in its on_stop().
In python 3.8 and 3.9, asyncio.Event/Lock/etc cannot be created before the
event loop itself is created. Hence, to have Plugins.__init__ create an
Event, we need to postpone creating Plugins() from setUpClass to setUp.
follow-up 90f39bce88
- @amount_msat.validator prevents the creation of invoices with e.g. too large amounts
- however the qml gui is mutating invoices by directly setting the `amount_msat` field,
and it looks like attrs validators only run during init.
We can use `on_setattr` (introduced in attrs==20.1.0).
- a wallet db upgrade is added to rm existing insane invoices
- btw the qml gui was already doing its own input validation on the textedit
(see qeconfig.btcAmountRegex). however that only limits the input to not have more
chars than what is needed to represent 21M BTC (e.g. you can still enter 99M BTC,
which the invoice logic does not tolerate later on - but is normally caught).
fixes https://github.com/spesmilo/electrum/issues/8582
Note: We should probably require the password in load_wallet,
and store it in memory as long as the wallet is loaded. In that
case, commands that currently require a password would no longer
require it if the wallet is loaded.
- rename trampoline_forwardings -> final_onion_forwardings,
because this dict is used for both trampoline and hold invoices
- remove timeout from hold_invoice_callbacks (redundant with invoice)
- add test_failure boolean parameter to TestPeer._test_simple_payment,
in order to test correct propagation of OnionRoutingFailures.
- maybe_fulfill_htlc: raise an OnionRoutingFailure if we do not have
the preimage for a payment that does not have a hold invoice callback.
Without this, the above unit tests stall when we use test_failure=True
- introduce SentHtlcInfo named tuple
- some previously unnamed tuples are now much shorter:
create_routes_for_payment no longer returns an 8-tuple!
- sent_htlcs_q (renamed from sent_htlcs), is now keyed on payment_hash+payment_secret
(needed for proper trampoline forwarding)
- add RecvMPPResolution enum for possible states of a pending incoming MPP,
and use it in check_mpp_status
- new state: "FAILED", to allow nicely failing back the whole MPP set
- key more things with payment_hash+payment_secret, for consistency
(just payment_hash is insufficient for trampoline forwarding)