Commit Graph

9335 Commits

Author SHA1 Message Date
SomberNight 91f286b422 wallet: minor clean-up and sanity checks for unlock/lock
- unlock() did not handle password=="" well
    instead of the caller converting the arg, as in
    https://github.com/spesmilo/electrum/commit/7113cec4c724c2a443031c71cc8d08fee5e2f385,
    it is more robust for the function itself to do it
- get_unlocked_password() should never return an invalid password
- add is_unlocked()
2026-01-19 17:07:35 +00:00
SomberNight 5b915fbff8 qml: fix: allow opening passwordless wallets
This must be an old regression.
The GUI was not allowing to open a wallet that did not have a password set:
it prompted for a password and did not accept any string (should at least accept empty "").

Without this, it was only possible to open a passwordless wallet if that was the first wallet the user opened
(as otherwise we would overwrite the empty pw with the pw of the current wallet).
2026-01-19 16:41:57 +00:00
SomberNight 0ae10b2a7b lnpeer: log name of wallet file in each line
- if multiple LN-enabled wallets are open, need to know which peer is for which wallet
- note: LNGossip is a singleton
  - if a wallet is named LNGossip, can't distinguish. I think that's ok.

compare log lines:
before:
```
84.82 | I | lnpeer.Peer.[LNWallet, 034cc6216f-f8dcaa6e] | Disconnecting: GracefulDisconnect('Failed to initialize: TimeoutError()')
17.97 | D | lnpeer.Peer.[LNGossip, 0259d4116d-1618547b] | Sending INIT
```
after:
```
 5.80 | D | lnpeer.Peer.[test_segwit_2, 038863cf8a-fd53ef9c] | Sending CHANNEL_READY
 5.92 | D | lnpeer.Peer.[LNGossip, 038863cf8a-6286ffd4] | Received INIT
```
2026-01-19 16:03:42 +00:00
ghost43 ece52b0a4e Merge pull request #10340 from f321x/fingerprint
android: implement biometric authentication (fingerprint)
2026-01-19 15:22:17 +00:00
user 47efb8b108 qml: remove pin code authentication
Completely removes the pin code authentication from qml. The config
option in the wallet preferences has been renamed to "Payment
authentication" and now either asks for the Android system
authentication (Biometric or system pin/password) if enabled or will ask
for the wallet password as fallback.
2026-01-19 14:07:25 +01:00
SomberNight 21248817c9 config: allow setting "forgetconfig" option in file, not just on CLI
- by specifying "default=<VALUE>" in commands.py, <VALUE> would always overwrite what is in the config file
- note `$ ./run_electrum -o setconfig forget_config true` still does not work,
  as that first sets forget_config in memory, and then - by virtue of the setting -
  it refuses to write changes to the config file
  - hence this option would have to be set manually by editing the json
    (or as a CLI flag, as before)

ref https://github.com/spesmilo/electrum/pull/10421#issuecomment-3765862081
2026-01-19 11:30:53 +00:00
user e81ac4b7cd lnpeer: followup #10413
Save the updated htlc set in `Peer._fulfill_htlc_set` and
`Peer._fail_htlc_set()` only after the loop iterated through all htlcs.
This potentially improves performance, especially considering that
writing the db can take >100 ms for larger wallets without partial
writes.
2026-01-16 12:16:23 +01:00
SomberNight a27e2cc6b5 addr_sync: update "stored_height" db field immediately on wallet-open
Repro steps:
- in qt gui, with network enabled, open wallet1
- open wizard, create wallet2 (restore from seed something that has mined history)
- close both wallets, stop electrum
- start electrum with "-o" offline flag, open wallet2
- observe all txs in history tab show up as "unconfirmed"

The cause is that "stored_height" only gets updated ~on new blocks.
So if you created a wallet and closed it soon, its db would not contain "stored_height."
2026-01-15 16:43:22 +00:00
SomberNight c37b844f66 lnutil: change ReceivedMPPStatus.htlcs to frozenset, i.e. immutable
As ThomasV says:

> ReceivedMPPStatus is a Namedtuple, which is immutable, but it contains
> a mutable field. Since ReceivedMPPStatus is not a StoredObject,
> no patch will be created when the htlcs list is modified, and we may
> end up not saving the change to disk if partial writes are enabled.

patch taken from https://github.com/spesmilo/electrum/pull/10395#pullrequestreview-3634244541
closes https://github.com/spesmilo/electrum/pull/10395

Co-authored-by: f321x <f@f321x.com>
2026-01-15 15:59:14 +00:00
ghost43 5266b3d61e Merge pull request #10371 from accumulator/qml_manual_fee_feerate_edit
qml: allow manual editing of fee/feerate
2026-01-15 14:43:08 +00:00
SomberNight 8a3d9fd758 qml: FeePicker: restrict abs/rate editing to mimic wallet.bump_fee/cpfp 2026-01-14 16:53:30 +00:00
SomberNight ca597942fd qml: (trivial) qeinvoice: add type hint 2026-01-14 16:13:00 +00:00
ghost43 5db4a16ace Merge pull request #10410 from f321x/fix_10406
qml: fix invalid QEInvoiceParser state
2026-01-14 15:55:18 +00:00
f321x b599ae7d4a qml: fix invalid QEInvoiceParser state
Fixes the issue described in #10406.
When scanning a lightning invoice we would pass it to
`QEInvoiceParser.fromResolvedPaymentIdentifier()`, however
`fromResolvedPaymentIdentifier()` doesn't reset the state of
`QEInvoiceParser._lnurlData` which is used in QML to evaluate
`payImmediately: invoiceParser.isLnurlPay` in the `onValidationSuccess`
connection.

This change calls `clear()` in `fromResolvedPaymentIdentifier()` to
ensure that `QEInvoiceParser` state gets reset when loading a new invoice.
However when retrieving a bolt11 from a lnurl-pay callback we don't
wan't to reset `QEInvoiceParser._lnurlData` so that `payImmediately` is
true when confirming the lnurl pay dialog, for that I skip calling
`fromResolvedPaymentIdentifier()` and instead call `validateRecipient()`
directly so the `QEInvoiceParser` state doesn't get reset in this case.
2026-01-14 11:42:55 +01:00
f321x 6450187902 qeqrscanner: check requestCode on activity result 2026-01-13 18:10:07 +01:00
user 5dd3dda238 android: implement biometric authentication
Allows to unlock the android app with the android biometric api (e.g.
fingerprint). Can be enabled in the settings.
2026-01-13 18:10:00 +01:00
ThomasV 1845143786 lnpeer: wait_for_received_pending_htlcs_to_get_removed: wait only if peer has been initialized 2026-01-13 17:16:10 +01:00
ThomasV 69af2f77ed Merge pull request #10404 from f321x/fix_10403
ExchangeRate: return NaN if rate is 0
2026-01-13 14:55:20 +01:00
f321x 5199c6c742 ExchangeRate: return NaN if rate is 0
Prevent DivisionByZero exceptions by returning `Decimal('NaN')
instead of `Decimal(0)` if the exchange rate is 0.

Fixes https://github.com/spesmilo/electrum/issues/10403

```
>>> bool(Decimal(0))
False
```
2026-01-13 13:57:14 +01:00
ThomasV 0c29c5006e Merge pull request #10394 from f321x/cosigner_wallet_event_listener
bugfixes: set psbt_nostr event on aio loop and use correct cb in TxEditor
2026-01-13 13:45:06 +01:00
SomberNight 65f245f475 qml: FeePicker: hide "Target" line in "Manual" mode
instead use font colors to hint which textedit is being used for target
2026-01-12 18:42:14 +00:00
SomberNight f387300ab2 qml: FeePicker: use UI_UNIT_NAME constants, instead of hardcoding 2026-01-12 18:41:52 +00:00
ghost43 331ed0fe02 Merge pull request #10400 from f321x/fix_qml_type_error
qml: add close no-op to QEQRScanner to fix type error
2026-01-11 06:06:02 +00:00
f321x 04b7b683ed qml: add close no-op to QEQRScanner to fix type error
Adds close() no-op method to QEQRScanner to prevent type errors like
this:
```
01-02 17:28:09.645 10543 10565 I python  : 162.27 | W | gui.qml.qeapp | file:///data/data/org.electrum.electrum/files/app/electrum/gui/qml/components/SweepDialog.qml:123: TypeError: Property 'close' of object QEQRScanner(0xdd32f66fb600)
is not a function
```
2026-01-08 11:14:06 +01:00
f321x fb96ba41cd qt: WalletInfoDialog: sort keystores by root fingerprint
Sort the keystore tabs of the WalletInfoDialog by their root
fingerprints. This makes it less confusing when looking at different
wallet instances of the same multisig setup as the tabs will always have
the same order.
2026-01-08 09:53:41 +01:00
f321x 663fcddc0c AddressSynchronizer: invalidate balance cache on spv
There was a race incorrectly counting transactions with one
confirmations to the unconfirmed balance instead of the confirmed
balance.
This happened because the balance cache of AddressSynchronizer got
invalidated after `on_event_blockchain_updated` and then again after
`receive_history_callback`->`add_transaction`, however when calling
`AddressSynchronizer.get_balance()` before the tx got spv verified the
height would still be counted as 0 (unconfirmed), populating the balance
cache again with the unconfirmed balance.
I noticed this only on QML due to timing differences to Qt.
Invalidating the cache in `AddressSynchronizer.add_verified_tx()` after
the tx got verified causes the balance to get recalculated and shown
correctly.
2026-01-07 18:15:08 +01:00
f321x 72f083d2d0 AddressSynchronizer: remove unneccessary loop
This loop seems like a leftover that is not useful anymore, clearing the
cache once has the same effect.
2026-01-07 16:36:07 +01:00
SomberNight 2172dadf62 hw plugins: coldcard: fix compat with ckcc-protocol v1.5.0
fixes https://github.com/spesmilo/electrum/issues/10386
2026-01-05 16:28:23 +00:00
SomberNight f1f4fc0939 hw plugins: coldcard: log error when I forget to set udev rules
so that next time I check that before changing cables, usb hubs, and VMs o.O
2026-01-05 16:06:24 +00:00
SomberNight c3e373a3b2 lnchannel: chan.lnworker must now always be set, even in unit tests 2026-01-05 15:56:07 +00:00
SomberNight dfeb9918d8 tests: lnchannel: rewrite create_test_channels to use LNWallet 2026-01-05 15:56:04 +00:00
SomberNight 17f41044d5 tests: lnpeer: fix cyclic lnworker.wallet.lnworker inconsistency
These better hold, lol:
wallet.lnworker.wallet == wallet
lnworker.wallet.lnworker == lnworker
2026-01-05 15:56:01 +00:00
SomberNight ea42b02ceb tests: simplify MockLNWallet, add fixme for cyclic inconsistency 2026-01-05 15:55:58 +00:00
SomberNight b292c027c3 lnpeer: move make_local_config to LNWallet
no functional changes
2026-01-05 15:55:41 +00:00
SomberNight 1006e8092f lnworker: split LNWallet and LNWorker: LNWallet "has an" LNWorker
- LNWallet no longer "is-an" LNWorker, instead LNWallet "has-an" LNWorker
- the motivation is to make the unit tests nicer, and allow writing unit tests for more things
  - I hope this makes it possible to e.g. test lnsweep in the unit tests
  - some stuff we would previously have to write a regtest for, maybe we can write a unit test for, now
- in unit tests, MockLNWallet now
  - inherits LNWallet
  - the Wallet is no longer being mocked
2026-01-05 15:55:31 +00:00
f321x 31ac44dddd TxEditor: register correct callback
on_event_channels_updated doesn't get fired if channels change their
state to OPEN. TxEditor needs to use on_event_channel to notice channels
coming online.
2026-01-05 16:36:10 +01:00
f321x e033a5e67b psbt_nostr: add EventListener comment to CosignerWallet
I got confused how on_event_proxy_set can even work if CosignerWallet
doesn't inherit from EventListener until i figured out its children use
the EventListener too. To avoid this confusion i added two comments.
2026-01-05 16:36:05 +01:00
f321x 0d380218a6 bug: psbt_nostr: set CosignerWallet.pending on aio loop
Fixes:
```
Traceback (most recent call last):
  File "/home/user/code/electrum-fork/electrum/plugins/psbt_nostr/qt.py", line 149, in on_receive
    self.mark_pending_event_rcvd(event_id)
    ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^
  File "/home/user/code/electrum-fork/electrum/plugins/psbt_nostr/psbt_nostr.py", line 254, in mark_pending_event_rcvd
    self.pending.set()
    ~~~~~~~~~~~~~~~~^^
  File "/usr/lib64/python3.14/asyncio/locks.py", line 192, in set
    fut.set_result(True)
    ~~~~~~~~~~~~~~^^^^^^
  File "/usr/lib64/python3.14/asyncio/base_events.py", line 829, in call_soon
    self._check_thread()
    ~~~~~~~~~~~~~~~~~~^^
  File "/usr/lib64/python3.14/asyncio/base_events.py", line 866, in _check_thread
    raise RuntimeError(
        "Non-thread-safe operation invoked on an event loop other "
        "than the current one")
RuntimeError: Non-thread-safe operation invoked on an event loop other than the current one
```
2026-01-05 16:02:14 +01:00
ghost43 bdcd3f9c7c Merge pull request #10364 from f321x/test_dont_settle_htlcs_forwarding
lnpeer/lnworker: check dont_settle_htlcs when forwarding
2025-12-30 16:13:16 +00:00
ghost43 ca410beae1 Merge pull request #10385 from f321x/bump_zxingcpp
android: bump barcodescannerview, allow tap to focus, rm 16kb patch
2025-12-22 18:27:44 +00:00
ghost43 a50f963a61 Merge pull request #10373 from accumulator/qml_helpdialog_styling
qml: improve HelpDialog styling
2025-12-22 17:29:57 +00:00
ghost43 261561ad0b Merge pull request #10384 from f321x/pi_handling_lightning_prefix
pi: fix incorrectly parsing emaillike with 'ln' prefix as bech32 ln pi
2025-12-22 17:13:12 +00:00
f321x dd1d98e37c pi: allow emaillike pi with 'lightning:' prefix
Lightning addresses with 'lightning:' do occur in the wild and make
sense (how else would e.g. the smartphone know to open a lightning
wallet instead of the e-mail client). So we should allow this.
2025-12-22 18:06:26 +01:00
f321x 2cd1de4f21 pi: fix incorrectly parsing emaillike with 'ln' prefix
Fixes a bug where we incorrectly parsed emaillike payment identifiers as
bech32 lightning payment identifier if they start with a 'ln' prefix.
2025-12-22 18:06:17 +01:00
f321x d1368db313 android: qr scanner: allow tap to focus
Allow tap to focus in the android qr scanner as some devices don't
support autofocus. This should allow them to focus on some qr code.
2025-12-22 15:02:01 +01:00
f321x 82c006e0e4 qt: Submarine Payments: update tab on_channels_updated
Updates the submarine payments tab if the channels get updated so the
user isn't stuck with a liquidity warning if they open the tab before
the channels are initialized (e.g. on wallet startup).
2025-12-22 14:08:08 +01:00
f321x d233e4ffa8 qt: Add help button to submarine payments tab
Adds a help button with explanation to the submarine payments tab.
2025-12-22 14:08:01 +01:00
f321x 4c44620d4d qt: ConfirmTxDialog: also show Tools text
Also show the `Tools` text besides the preferences icon so it looks
equal to the main window.
Originally this was a followup part of #10300 which got closed
due to other reasons.
2025-12-22 11:02:17 +01:00
f321x db45606288 qt: disable ln configs in ConfirmTxDialog if no ln
Disables the lightning related config options in the ConfirmTxDialog
tools and shows an according tooltip if lightning is not available in
the wallet. This should prevent confusion of users.
2025-12-22 11:02:15 +01:00
f321x 93d85a0b0e qt: disable Submarine Payment tab if not swap_manager
Disable the `Submarine Payments` tab if the swap_manager is None (the
wallet has no lightning support).
2025-12-22 11:02:13 +01:00