Commit Graph

68 Commits

Author SHA1 Message Date
ThomasV b8b36c7c30 follow-up prev: fix flake8 test 2023-06-24 12:56:55 +02:00
ThomasV 411098f293 move methods from wallet_db to json_db
the goal of this commit is to call JsonDB.__init__ with data,
not an empty dict
2023-06-24 12:45:07 +02:00
ThomasV 759eaf1cf5 json_db: register extra types outside of constructor 2023-06-23 12:16:14 +02:00
ThomasV 295734fc53 storage: encapsulate type conversions of stored objects using
decorators (instead of overloading JsonDB._convert_dict and
 _convert_value)
 - stored_in for elements of a StoreDict
 - stored_as for singletons
 - extra register methods are defined for key conversions

This commit was adapted from the jsonpatch branch
2023-06-18 13:08:57 +02:00
SomberNight 68fb996d20 wallet_db version 52: break non-homogeneous multisig wallets
- case 1: in version 4.4.1, 4.4.2, the qml GUI wizard allowed creating multisig wallets with an old_mpk as cosigner.
- case 2: in version 4.4.0, 4.4.1, 4.4.2, the qml GUI wizard allowed creating multisig wallets with mixed xpub/Ypub/Zpub.

The corresponding missing input validation was a bug in the wizard, it was unintended behaviour. Validation was added in d2cf21fc2b. Note however that there might be users who created such wallet files.

Re case 1 wallet files: there is no version of Electrum that allows spending from such a wallet. Coins received at addresses are not burned, however it is technically challenging to spend them. (unless the multisig can spend without needing the old_mpk cosigner in the quorum).

Re case 2 wallet files: it is possible to create a corresponding spending wallet for such a multisig, however it is a bit tricky. The script type for the addresses in such a heterogeneous xpub wallet is based on the xpub_type of the first keystore. So e.g. given a wallet file [Yprv1, Zpub2] it will have sh(wsh()) scripts, and the cosigner should create a wallet file [Ypub1, Zprv2] (same order).

Technically case 2 wallet files could be "fixed" automatically by converting the xpub types as part of a wallet_db upgrade. However if the wallet files also contain seeds, those cannot be converted ("standard" vs "segwit" electrum seed).
Case 1 wallet files are not possible to "fix" automatically as the cosigner using the old_mpk is not bip32 based.

It is unclear if there are *any* users out there affected by this. I suspect for case 1 it is very likely there are none (not many people have pre-2.0 electrum seeds which were never supported as part of a multisig who would also now try to create a multisig using them); for case 2 however there might be.

This commit breaks both case 1 and case 2 wallets: these wallet files can no longer be opened in new Electrum, an error message is shown and the crash reporter opens. If any potential users opt to send crash reports, at least we will know they exist and can help them recover.
2023-05-11 14:26:11 +00:00
SomberNight 312f2641e7 don't use bare except
use "except Exception", or if really needed explicitly "except BaseException"
2023-04-24 12:58:01 +00:00
SomberNight 950065a3de Store file creation date and version in db
Store the electrum version used to create a wallet file and a timestamp,
in the file itself. This can be useful for debugging.
2023-03-13 15:15:50 +00:00
ThomasV 719b468eee Refresh bolt11 routing hints when channel liquidity changes:
- wallet_db update: separate Invoices and Requests.
 - do not store bolt11 invoice in Request
2023-02-28 15:33:17 +01:00
ThomasV 015648c4e5 Move get_dict method from wallet_db to json_db.
Define overloaded methods: _convert_dict _convert_values
2022-11-03 12:41:49 +01:00
ThomasV 14e96f4d53 Index request by ID instead of receiving address.
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
2022-09-02 10:58:11 +02:00
SomberNight 7b8e257ebb wallet db upgrade: rm support of "legacy" lightning channels
("legacy" as in pre-static-remote-key channels)
2022-08-16 08:49:17 +02:00
SomberNight ed65f335bd wallet_db upgrade: fix possible corruption of invoice amounts
see https://github.com/spesmilo/electrum/pull/7774
2022-07-15 18:26:13 +02:00
ThomasV 9fe93524b7 Index lightning requests with rhash instead of onchain address.
get_unused_addresses() has been broken since #7730, because
addresses are considered as permanently used if they are in
the list of keys of receive_requests. This is true even if
an address is used as fallback for a lightning payment. This
means that the number of lightning payments we can receive
is constrained by the gap limit.

If a payment succeeds off-chain, we want to be able to reuse
its fallback address in other requests (this does not reduce
privacy, because invoices already share the same public key).

This implies that we should not use the onchain address as key
for lightning-enabled requests in wallet.receive_requests. If
we did, paid invoices would be overwritten when the address is
reused. That is the reason for the wallet_db upgrade.

Related: a3faf85e3c
2022-06-15 18:44:52 +02:00
SomberNight cbc69742b9 wallet_db: clarify hww types in old upgrades
There is no point in adding new hww types to these lists every time support for a new hww is added.
These upgrades got released in 2.7.0 and any hw types added after are unrelated.

reverted to just-after last relevant change:
https://github.com/spesmilo/electrum/commit/c820423b00553913024ff8c2f54ac2fd5e3a9b89
2022-05-11 19:50:57 +02:00
SomberNight cfa6b91f22 wallet_db: rm dependence on PaymentRequest class in convert_version_25
Change convert_version_25 to delete invoices instead of converting them.
convert_version_25 was released ~2 years ago. Wallet files not opened since will have old bip70 invoices deleted upon upgrading.

In general it is ~unsafe for convert_version_* to depend on other modules of the code.
(using e.g. sha256 is fine as its API will never change,
but using e.g. PaymentRequest is dangerous as its API might change over time)
2022-04-23 20:15:10 +02:00
SomberNight adfe542fae wallet_db upgrade: recalc keys of outgoing on-chain invoices
closes https://github.com/spesmilo/electrum/issues/7777
2022-04-22 19:53:55 +02:00
ThomasV e392197ab9 wallet_db upgrade:
- unify lightning and onchain invoices, with optional fields for bip70 and lightning
 - add receive_address fields to submarine swaps
2022-04-20 12:48:22 +02:00
SomberNight 03df14b27a wallet_db: handle legacy channels in convert_version_44
I still have a mainnet wallet with some pre-static-remotekey channels
(though those channels are closed) that I do not want to delete yet.

follow-up https://github.com/spesmilo/electrum/pull/7636

```
E | gui.qt.exception_window.Exception_Hook | exception caught by crash reporter
Traceback (most recent call last):
  File "...\electrum\electrum\gui\qt\__init__.py", line 307, in wrapper
    return func(self, *args, **kwargs)
  File "...\electrum\electrum\gui\qt\__init__.py", line 332, in start_new_window
    wallet = self._start_wizard_to_select_or_create_wallet(path)
  File "...\electrum\electrum\gui\qt\__init__.py", line 377, in _start_wizard_to_select_or_create_wallet
    db = WalletDB(storage.read(), manual_upgrades=False)
  File "...\electrum\electrum\wallet_db.py", line 73, in __init__
    self.load_data(raw)
  File "...\electrum\electrum\wallet_db.py", line 106, in load_data
    self.upgrade()
  File "...\electrum\electrum\util.py", line 439, in <lambda>
    return lambda *args, **kw_args: do_profile(args, kw_args)
  File "...\electrum\electrum\util.py", line 435, in do_profile
    o = func(*args, **kw_args)
  File "...\electrum\electrum\wallet_db.py", line 195, in upgrade
    self._convert_version_44()
  File "...\electrum\electrum\wallet_db.py", line 859, in _convert_version_44
    if item['static_remotekey_enabled']:
KeyError: 'static_remotekey_enabled'
```
2022-02-25 20:44:05 +01:00
bitromortac db86aeb83a wallet: replace static remotekey with channel type 2022-01-20 16:47:49 +01:00
bitromortac 6915e3cb10 lnpeer+wallet: use channel type for channel open
* channel_type is put into storage, serialized as int and
  deserialized as ChannelType
* check for static_remotekey is done via channel type
2022-01-20 16:47:48 +01:00
SomberNight 88a1c1a618 python 3.10: fix some deprecation warnings and compat with 3.10 2021-11-09 01:02:57 +01:00
ThomasV b431d8e9b8 follow-up eadd1bebb2 2021-09-24 17:36:33 +02:00
ThomasV eadd1bebb2 Do not convert StoredDict keys to str.
Instead, convert json keys to int when storage is read.
2021-09-20 14:49:59 +02:00
ThomasV 7a0904c0f4 wallet update: move fields that have string keys out of channel log 2021-09-20 14:47:20 +02:00
SomberNight 1188187431 wallet_db upgrade: in OnchainInvoice['outputs'], convert vals None->0
should fix https://github.com/spesmilo/electrum/issues/7500
2021-09-19 17:35:49 +02:00
SomberNight b7cdf3fe11 wallet_db upgrades: (trivial) make upgrades more standalone
and robust to code changes
2021-09-19 17:32:25 +02:00
SomberNight 34c2cb5220 wallet: fix channels backups in .backup files
This is a regression from https://github.com/spesmilo/electrum/commit/64a931f21e6f6699f192158e54ff8f2883682604,
which introduced "onchain_channel_backups", and renamed
the old "channel_backups" key to "imported_channel_backups".

The `save_backup` method was not changed to use the new "imported_channel_backups" key,
so the channel backups are in the backup file but they are ignored.
2021-06-08 16:21:43 +02:00
SomberNight 7b7bba2299 wallet_db: put 'seed_type' into keystores (incl db upgrade) 2021-03-30 21:16:14 +02:00
Benoit Verret f731c38293 Minor style changes 2021-03-21 00:36:23 -04:00
ThomasV 64a931f21e Deterministic NodeID:
- use_recoverable_channel is a user setting, available
   only in standard wallets with a 'segwit' seed_type
 - if enabled, 'lightning_xprv' is derived from seed
 - otherwise, wallets use the existing 'lightning_privkey2'

Recoverable channels:
 - channel recovery data is added funding tx using an OP_RETURN
 - recovery data = 4 magic bytes + node id[0:16]
 - recovery data is chacha20 encrypted using funding_address as nonce.
   (this will allow to fund multiple channels in the same tx)

GUI:
  - whether channels are recoverable is shown in wallet info dialog.
  - if the wallet can have recoverable channels but has an old node_id,
    users are told to close their channels and restore from seed
    to have that feature.
2021-03-19 10:17:02 +01:00
SomberNight 0aa36ab5ac invoices: validate 'amount' not to be out-of-bounds 2021-02-18 06:11:09 +01:00
SomberNight b080df9cff wallet.bump_fee: (fix) make sure input signatures are removed
bump_fee was returning an invalid tx if its input was a
PartialTransaction that had signatures. It was relying on
line 1441 to remove signatures.

Relatedly, the WalletDB used to store such PartialTransactions as
PartialTransaction objects, but only until the program was restarted.
This is because serialising and de-serialising such a tx results in a
Transaction object.

So, combining these two, to reproduce a bug:
- create a tx, sign it, save as local
- bump fee, sign it, save as local
- bump fee --> tx already signed!? --> has old sigs, so it is invalid
2021-02-15 10:20:30 +01:00
ThomasV e477a43385 PaymentInfo: use msat precision 2021-02-01 15:03:56 +01:00
SomberNight 27cd078001 wallet: auto-freeze small unconfirmed UTXOs
see #6960
2021-01-29 12:37:15 +01:00
ThomasV 3cb68b10b9 remove broken payment requests. fixes #6350 2021-01-12 14:57:31 +01:00
bitromortac e5458bb534 wallet_db: migrate to upfront shutdown scripts 2021-01-11 11:37:14 +01:00
Malcolm Smith 67ae678137 storage/db: use faster JSON encoder settings when wallet is encrypted
The standard json module has an optimized C encoder, but that doesn't
currently support indentation. So if you request indentation, it falls
back on the slower Python encoder.

Readability doesn't matter for encrypted wallets, so this disables
indentation when the wallet is encrypted.

-----

based on https://github.com/Electron-Cash/Electron-Cash/commit/b2399b6a3e3e39ddd82ffc432bb1ca07f2aab454

For a large encrypted wallet, compare:
before change:
JsonDB.dump 1.3153 sec
zlib.compress 1.281 sec
ECPubkey.encrypt_message 0.1744 sec

after change:
JsonDB.dump 0.5059 sec
zlib.compress 1.3120 sec
ECPubkey.encrypt_message 0.1630 sec

Co-authored-by: SomberNight <somber.night@protonmail.com>
2021-01-06 21:14:56 +01:00
ThomasV 89ecc85c64 convert_version_24: loop over list instead of dict items (see #6863 and #6349) 2020-12-18 14:30:47 +01:00
SomberNight 3a7c00634e wallet_db: impl convert_version_33: put 'height' field into invoices
The 'height' field was added in https://github.com/spesmilo/electrum/commit/cdfaaa260942b807f809c2c0414fb242a03e945a
At the time we thought we could just add it with a default value without a db upgrade;
however the issue is that if old code tries to open a new db, it will fail (due to unexpected new field).
Hence it is better to do an explicit conversion where old code *knows* it cannot open the new db.

E | gui.qt.ElectrumGui |
Traceback (most recent call last):
  File "...\electrum\electrum\gui\qt\__init__.py", line 257, in start_new_window
    wallet = self.daemon.load_wallet(path, None)
  File "...\electrum\electrum\daemon.py", line 488, in load_wallet
    db = WalletDB(storage.read(), manual_upgrades=manual_upgrades)
  File "...\electrum\electrum\wallet_db.py", line 72, in __init__
    self.load_data(raw)
  File "...\electrum\electrum\wallet_db.py", line 103, in load_data
    self._after_upgrade_tasks()
  File "...\electrum\electrum\wallet_db.py", line 189, in _after_upgrade_tasks
    self._load_transactions()
  File "...\electrum\electrum\util.py", line 408, in <lambda>
    return lambda *args, **kw_args: do_profile(args, kw_args)
  File "...\electrum\electrum\util.py", line 404, in do_profile
    o = func(*args, **kw_args)
  File "...\electrum\electrum\wallet_db.py", line 1139, in _load_transactions
    self.data = StoredDict(self.data, self, [])
  File "...\electrum\electrum\json_db.py", line 79, in __init__
    self.__setitem__(k, v)
  File "...\electrum\electrum\json_db.py", line 44, in wrapper
    return func(self, *args, **kwargs)
  File "...\electrum\electrum\json_db.py", line 105, in __setitem__
    v = self.db._convert_dict(self.path, key, v)
  File "...\electrum\electrum\wallet_db.py", line 1182, in _convert_dict
    v = dict((k, Invoice.from_json(x)) for k, x in v.items())
  File "...\electrum\electrum\wallet_db.py", line 1182, in <genexpr>
    v = dict((k, Invoice.from_json(x)) for k, x in v.items())
  File "...\electrum\electrum\invoices.py", line 108, in from_json
    return OnchainInvoice(**x)
TypeError: __init__() got an unexpected keyword argument 'height'
2020-12-17 15:17:08 +01:00
SomberNight da6080421e wallet_db: WalletDB.get_txo_addr now returns dict instead of list 2020-10-18 20:37:25 +02:00
SomberNight 4b6c86ecbe wallet: make labels private, and access to need lock
e.g. labels plugin iterated over wallet.labels on asyncio thread while user could trigger an edit from Qt thread
2020-10-13 18:57:55 +02:00
SomberNight a7199696d3 json_db: exempt keystore from StoredDict conversion
The keystore logic would need to be significantly changed to nicely
interoperate with StoredDict/json_db logic.
(just see KeyStore.__init__() and KeyStore.dump())
For now we exempt the keystore from the recursive StoredDict conversion, as
it is a smaller change that is also easier to review for correctness.

fixes #6066
fixes #6401

also reverts 2d3c2eeea9 (which was an even hackier workaround for #6066)
2020-09-04 16:11:01 +02:00
SomberNight 307403a02c invoices: rm old corrupted non-bip70 invoices
fixes #6345
2020-07-08 00:57:23 +02:00
SomberNight 9cd79ec2e5 WalletDB: raise different exc if cannot parse given file
closes #6292
2020-06-27 16:03:03 +02:00
SomberNight dee5d52948 invoices: make sure that OnchainInvoice .exp and .time are not None
related: #6284
2020-06-27 02:27:50 +02:00
SomberNight d5f368c584 LN invoices: support msat precision
fixes #6250
2020-06-22 22:48:13 +02:00
ThomasV 3874f7ec77 swaps: use StoredObject to store data 2020-06-18 14:28:40 +02:00
SomberNight 43892dd61a invoices: fix #6233 2020-06-14 03:39:35 +02:00
ThomasV 6058829870 Use attr.s classes for invoices and requests:
- storage upgrade
 - fixes #6192
 - add can_pay_invoice, can_receive_invoice to lnworker
2020-06-01 21:02:45 +02:00
ThomasV 8f41aeb783 Replace wallet backup with channel backups
- channels can be backed up individually
 - backups are added to lnwatcher
 - AbstractChannel ancestor class
2020-04-10 14:45:23 +02:00