Commit Graph

87 Commits

Author SHA1 Message Date
SomberNight
51b7fc04ef walletdb: fix convert_version_58 for partial local txs
The transaction dict can also contain PSBTs (in addition to complete raw hex txs).
This is the case if the user has saved a partial (e.g. unsigned) tx as local into the history.

fixes https://github.com/spesmilo/electrum/issues/8913
2024-02-26 18:54:21 +00:00
SomberNight
b3a908f647 WalletDB: (trivial) add type hint 2024-02-12 18:26:08 +00:00
ThomasV
061c821128 Merge pull request #8843 from SomberNight/202401_jsondb_set
walletdb: change structure of prevouts_by_scripthash, and db upgrade
2024-01-31 12:56:11 +01:00
SomberNight
cbece71894 walletdb: rm some dead code 2024-01-23 02:20:01 +00:00
SomberNight
79aba5364c walletdb: change structure of prevouts_by_scripthash, and db upgrade
this fixes the test case added in prev
2024-01-23 01:53:06 +00:00
Sander van Grieken
57bd291491 call super().__init__() for WalletFileException descendants,
qt: handle unfinished wallets when opened via File>Open (ref #8809)
2024-01-15 17:06:44 +01:00
SomberNight
f7cb523b9d wallet db: deduplicate "seed_type" field
In the db, the 'seed_type' field could be present both at the top-level and inside keystores.

Note:
- both fields had usages
- the top-level field was added in 2.8 re "initial segwit support" (3a64ec0f2e)
  - there was no db upgrade for it, so older files are missing it
  - if present, valid values can be electrum types but also
    other types supported by the wizard, e.g. "bip39"
- the keystore-level field was added in 4.1 (7b7bba2299)
  - there was a db upgrade when it was introduced, so old files also have it
  - if present, valid values can only be electrum types
- there is not much value in the top-level one having a non-electrum value,
  and those values were never used by other parts of the code
  - note that when creating a standard wallet from a bip39 seed, the seed is discarded.
    Only the derived xprv and the derivation path are kept. If we changed this and also kept the seed,
    e.g. to display it to the user, then it would make sense to save the seed type (e.g. "bip39").
    However storing that seed_type would make more sense at the keystore level (not top-level).

We delete the top-level 'seed_type' field.

```
{
    "keystore": {
        "seed_type": "segwit",
        ...
    },
    "seed_type": "segwit",
    ...
}
```
2023-12-01 18:43:37 +00:00
SomberNight
511674a532 contacts: fix adding new contacts
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
```
2023-11-01 17:28:29 +00:00
ThomasV
98a4d7b60d public channels:
- send node and channel announcements.
 - store channel_flags in constraints
 - store signatures in local and remote configs
2023-10-16 13:54:16 +02:00
Sander van Grieken
7ca9b735d5 daemon: refactor load_wallet to not just return None, but raise specific exceptions.
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)
2023-10-10 17:42:07 +02:00
ThomasV
019be008d6 json_db: do not overload load_data.
instead, pass an upgrader function to the constructor.
2023-09-24 12:10:35 +02:00
ThomasV
30038f4ace follow-up previous commit: write storage only if there was an upgrade 2023-09-23 15:15:17 +02:00
ThomasV
56e80c20d7 wallet_db upgrade: do not use '/' in StoredDict keys 2023-09-23 11:05:36 +02:00
SomberNight
a7128438d4 wallet_db: fix typo in renamed arg "upgrade"
follow-up 8be3c4dadd
2023-09-22 16:36:47 +00:00
ThomasV
68159b3ef6 walletDB: replace 'manual_upgrades' parameter with 'upgrade', with opposite semantics 2023-09-22 15:02:07 +02:00
ThomasV
b5bc5ff9ed Separate WalletDB from storage upgrades.
Make sure that WalletDB.data is always a StoredDict.
Perform db upgrades in a separate class, since they
operate on a dict object.
2023-09-22 15:02:06 +02:00
SomberNight
4e6e6f76ca invoices: also run amount-validator on setter
- @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
2023-08-22 18:10:21 +00:00
ThomasV
b96cc82333 Make storage a field of db
This comes from the jsonpatch_new branch.
I rather have in master now, because it touches a lot of filese.
2023-08-18 08:08:31 +02:00
SomberNight
cee22abcb5 wallet_db: upgrade to version 53, for imported chan backups
follow-up https://github.com/spesmilo/electrum/pull/8536

This replaces 69336befee, which was insufficient.
#8536 added a new field into the struct, which older versions do not ignore but raise:
opening a wallet file with new code updated the struct to include it,
after which old code could no longer open the wallet file.
i.e. #8536 was an invisible wallet upgrade, breaking compat.
This commit simply formalises the wallet upgrade: old code will now show
an understandable error when trying to open new files.
2023-08-17 14:08:27 +00:00
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:
c820423b00
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 64a931f21e,
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