Commit Graph

636 Commits

Author SHA1 Message Date
ThomasV
3adfe9a8de Merge pull request #9598 from f321x/jit-gui-improvements
Handle zeroconf lightning requests in QT gui
2025-03-14 08:34:00 +01:00
SomberNight
3ff794da12 wallet: (trivial) refactor is_frozen_coin 2025-03-14 00:07:26 +00:00
SomberNight
8ccd31fe49 wallet: set_frozen_state_of_coins to handle freeze=None
Internally whether a coin is frozen is tri-state:
- forced-True, set by the user
- forced-False, set by the user
- unset/default: is_frozen_coin() can decide whether the coin should be frozen

This patch lets set_frozen_state_of_coins() undo a previous explicit setting of True/False,
by calling it with a value of None.
Note: there is still no way in the GUI to undo an explicit setting of True/False.
2025-03-13 18:32:58 +00:00
f321x
5134d07b14 add zeroconf handling to qt gui 2025-03-13 11:49:50 +01:00
ThomasV
bdb7a82220 batch payment manager:
The class TxBatcher handles the creation, broadcast and replacement
of replaceable transactions. Callers (LNWatcher, SwapManager) use
methods add_payment_output and add_sweep_info. Transactions
created by TxBatcher may combine sweeps and outgoing payments.

Transactions created by TxBatcher will have their fee bumped
automatically (this was only the case for sweeps before).

TxBatcher manages several TxBatches. TxBatches are created
dynamically when needed.

The GUI does not touch txbatcher transactions:
  - wallet.get_candidates_for_batching excludes txbatcher
    transactions
  - RBF dialogs do not work with txbatcher transactions

wallet:
  - instead of reading config variables, make_unsigned_transaction
    takes new parameters: base_tx, send_change_to_lighting

tests:
  - unit tests in test_txbatcher.py (replaces test_sswaps.py)
  - force all regtests to use MPP, so that we sweep transactions
    with several HTLCs. This forces the payment manager to aggregate
    first-stage HTLC tx inputs. second-stage are not batched for now.
2025-03-13 10:17:10 +01:00
SomberNight
3f327eea07 wallet: fix wallet.make_unsigned_transaction method signature
- "fee_policy" arg is actually mandatory
- and fix test/stdio guis following fee_policy/config split

follow-up 840243e029
2025-03-11 16:15:17 +00:00
ThomasV
764cc78386 Merge pull request #9590 from f321x/jit-update-unfunded-state
Handle unfunded zeroconf channels in update_unfunded_state
2025-03-07 13:55:55 +01:00
f321x
6fd833ccfb add handling of zeroconf channels to update_unfunded_state 2025-03-07 13:53:01 +01:00
ThomasV
d5ee678b7f if a network object is there but fee estimates are not available,
raise NoDynamicFeeEstimates in FeePolicy rather than in wallet.

Also, show an error message in Qt
2025-03-06 13:13:01 +01:00
ThomasV
074ede8f12 make_unsigned_transaction: pass merge_duplicate_outputs as
a parameter, because it must not be used in some contexts
(e.g. tx batcher).

This makes config.MERGE_DUPLICATE_OUTPUTS a GUI option
2025-03-06 09:22:12 +01:00
ThomasV
943f6436c7 make_unsigned_transaction: make some parameters non-optional 2025-03-05 16:10:27 +01:00
ThomasV
ab14c3e138 tx batching in GUI:
- discard config.WALLET_BATCH_RBF
 - allow the user to choose base_tx from a list of batching
   candidates in ConfirmTxDialog
2025-03-05 14:07:02 +01:00
ThomasV
3b369abf16 make_unsigned_transaction:
- use base_tx.remove_signatures(), because it also blanks script_sig
 - do not use config.WALLET_SEND_CHANGE_TO_LIGHTNING, as this is
   passed as a parameter.
2025-03-05 14:05:41 +01:00
ThomasV
840243e029 separate fee policy from config
- Wallet.make_unsigned_transaction takes a FeePolicy parameter
 - fee sliders act on a FeePolicy instead of config
 - different fee policies may be used for different purposes
 - do not detect dust outputs in lnsweep, delegate that to lnwatcher
2025-03-05 10:29:26 +01:00
ThomasV
77a00db52a get_full_history: make sure 'ln_value' and 'bc_value' are in every item 2025-03-03 10:37:44 +01:00
ThomasV
8a96c88615 remove config vars WALLET_BIP21_LIGHTNING and WALLET_BOLT11_FALLBACK (see #9580) 2025-02-26 11:41:59 +01:00
SomberNight
3140c78ab1 qt: follow-up LN/onchain req sep: consistent URI/bolt11 errors
- if we show error for LN request, we should also show error for LN-only bip21 URI
  follow-up af0ac40478
- for LN request, show better error msg if don't have any channels
  closes https://github.com/spesmilo/electrum/issues/9413

note: would be nice if qml GUI could reuse this logic (wallet.get_help_texts_for_receive_request)
2025-02-25 15:03:53 +00:00
ThomasV
3d2531cb93 reintroduce separate request types for lightning and onchain
cmdline: add_request has a --lightning option
2025-02-25 11:27:32 +01:00
SomberNight
19b2536da2 wallet: add method "can_rbf_tx"
from https://github.com/spesmilo/electrum/pull/8821
2025-02-19 16:10:52 +00:00
ThomasV
392c219913 simplify history-related commands:
- reduce number of methods
 - use nametuples instead of dicts
 - only two types: OnchainHistoryItem and LightningHistoryItem
 - channel open/closes are groups
 - move capital gains into separate RPC
2025-02-19 11:40:21 +01:00
ThomasV
18baf003d4 submarine swaps: backport changes from batch_payment_manager
- add 'is_funded' method to SwapData
 - sign claim transactions using the 'make_witness' method
2025-02-15 10:29:19 +01:00
ThomasV
6ddd0b95ca workaround grouping bug with dummy values 2025-02-14 13:46:38 +01:00
ThomasV
c3faadf23f If a transaction uses make_witness, also set script_sig.
Other methods (remove_signatures) may have set script_sig to None
during the lifetime of the tx object.
2025-02-13 11:01:03 +01:00
Sander van Grieken
605b511b43 qt,qml: move get_text_not_enough_funds_mentioning_frozen and get_frozen_balance_str to backend wallet
Note: the qt gui used to include FX in get_frozen_balance_str, but that is not replicated now.
2025-01-31 18:03:21 +01:00
SomberNight
cba073dfd1 lightning: change derivation of funding_pubkey
Ideally, given an on-chain backup, after the remote force-closes, we should be able to spend our anchor output,
to CPFP the remote commitment tx (assuming the channel used OPTION_ANCHORS).
To spend the anchor output, we need to be able to sign with the local funding_privkey.

Previously we derived the funding_key from the channel_seed (which comes from os.urandom).
Prior to anchors, there was no use case for signing with the funding_key given a channel backup.
Now with anchors, we should make its derivation deterministic somehow, in a way so that it can
be derived given just an on-chain backup.
- one way would be to put some more data into the existing OP_RETURN
  - uses block space
  - the OP_RETURNs can be disabled via "use_recoverable_channels"
  - only the initiator can use OP_RETURNs (so what if channel is in incoming dir?)
- instead, new scheme for our funding_key:
  - we derive the funding_privkey from the lnworker root secret (derived from our bip32 seed)
  - for outgoing channels:
    - lnworker_root_secret + remote_node_id + funding_tx_nlocktime
  - for incoming channels:
    - lnworker_root_secret + remote_node_id + remote_funding_pubkey
  - a check is added to avoid reusing the same key between channels:
      not letting to user open more than one channel with the same peer in a single block
  - only the first 16 bytes of the remote_node_id are used, as the onchain backup OP_RETURNs only contain that
- as the funding_privkey cannot be derived from the channel_seed anymore, it is included in the
imported channel backups, which in turn need a new version defined
  - a wallet db upgrade is used to update already stored imported cbs
  - alternatively we could keep the imported cbs as-is, so no new version, no new funding_privkey field, as it is clearly somewhat redundant given on-chain backups can reconstruct it
    - however adding the field seems easier
      - otherwise the existing code would try to derive the funding_privkey from the channel_seed
      - also note: atm there is no field in the imported backups to distinguish anchor channels vs static-remotekey channels
2025-01-14 17:56:48 +00:00
ThomasV
fefd123275 wallet: always include wanted_height (for future tx) 2025-01-10 10:41:54 +01:00
ThomasV
33d0e6dbec Attach labels to outpoints instead of txids.
Move labels logic from lnworker to wallet.

Due to batching, a single transaction may have several labels attached to it.
2025-01-03 10:54:11 +01:00
ThomasV
ac1c9f088d Anchor channels: require deterministic wallet with software keystore.
This ends LN support in hardware and watching-only wallets.
2024-12-20 10:17:51 +01:00
ThomasV
ee42e09387 anchor channels: unlock wallet on startup if the wallet has channels 2024-12-20 10:10:07 +01:00
ThomasV
77ec49ac67 make_unsigned_transaction: ensure coins and inputs do not overlap
(follow-up 8bec974a39)
2024-12-17 10:54:21 +01:00
ThomasV
62af1ee887 fixes for txin.make_witness:
- add witness_sizehint
  - fix make_unsigned_transaction
  - do not remove witness_script in tx.finalize()
2024-12-13 14:44:35 +01:00
ThomasV
3b1dc194e4 Refactor lnsweep:
- txins have an optional make_witness method
 - instead of gen_tx, SweepInfo has a txin and
   an optional txout, for 1st stage HTLCs
 - sweep transactions are created by lnwatcher

The purpose of this change is to allow combining several
inputs in the same sweep transaction.
2024-12-11 17:14:14 +01:00
ThomasV
8bec974a39 wallet: add inputs and base_tx parameters to make_unsigned_transaction 2024-12-08 09:54:10 +01:00
ThomasV
58fee0d1cc Merge pull request #9265 from SomberNight/202410_ln_address_reuse_2
lnworker: reserve wallet addresses also for chan backups
2024-11-13 10:59:03 +01:00
ThomasV
60f13a977e Swaps over Nostr
- Separation between SwapManager and its transport:
   Legacy transpport uses http, Nostr uses websockets
 - The transport uses a context to open/close connections.
   This context is not async, because it needs to be called
   from the GUI
 - Swapserver fees values are initialized to None instead
   of 0, so that any attempt to use them before the swap
   manager is initialized will raise an exception.
 - Remove swapserver fees disk caching (swap_pairs file)
 - Regtests use http transport
 - Android uses http transport (until QML is ready)
2024-11-12 09:32:25 +01:00
SomberNight
b9a81cd03e lnworker: reserve wallet addresses also for chan backups
We were already reserving wallet addresses for full channels.
Now we also do the same for imported channel backups.
(but not for onchain, as we don't have enough info for that)

Without this, if the same seed is used on multiple devices (with each
device having its own set of LN channels), the wallet instances will
reuse keys (specifically the payment_basepoint, which for
static_remotekey chans is used as the to_remote output).
Now with this change, at least if the wallet instances have imported
channel backups of each other, this reuse is avoided.
2024-10-20 13:58:10 +00:00
SomberNight
e84679982e qt tx dlg: fix showing fee warnings
In qt, only the confirm_tx_dialog was showing the fee warnings, the transaction_dialog was not...

regression from bc3946d2f4
2024-10-16 12:42:58 +00:00
ThomasV
3721f04ac8 replace electrum/ecc with electrum_ecc package 2024-10-10 15:46:00 +00:00
SomberNight
16d2f0f9d4 wallet.get_tx_status: fix incorrect feerate for partial txs
The history tab would show an incorrect feerate for partial/unsigned (local) txs,
if they had any p2sh/p2wsh txins. We would just guess the script is p2wpkh, and
use that for the size calc. Now with calling add_info_from_wallet, the correct
size is used to calculate the feerate.

(The gui tx dialogs call add_info_from_wallet independently, so the size/feerate
shown there were already correct.)
2024-08-13 03:20:32 +00:00
SomberNight
3d6198eff0 trustedcoin: Wallet_2fa.make_unsigned_transaction to use **kwargs
We often forget updating the method signature of Wallet_2fa.make_unsigned_transaction
when changing Abstract_Wallet.make_unsigned_transaction.
2024-06-17 16:55:23 +00:00
ThomasV
912e1a3a5b reintroduce 'unlock' command
- the unlock command was replaced by an option to load_wallet,
because some applications (the swapserver plugin) need to be
executed with an unlocked password. Now the swapserver plugin
waits until the wallet is unlocked.
- wallet.unlock now checks password unconditionally, see #8799
2024-06-08 11:10:33 +02:00
SomberNight
e25658d724 fix plot.py
fixes https://github.com/spesmilo/electrum/issues/9058
2024-05-22 15:26:26 +00:00
SomberNight
13d9677e53 transaction: tx.sign API change: rm hex usage 2024-04-29 17:10:30 +00:00
SomberNight
2f1095510c bitcoin.py/transaction.py: API changes: rm most hex usage
Instead of some functions operating with hex strings,
and others using bytes, this consolidates most things to use bytes.

This mainly focuses on bitcoin.py and transaction.py,
and then adapts the API usages in other files.

Notably,
- scripts,
- pubkeys,
- signatures
should be bytes in almost all places now.
2024-04-29 17:10:26 +00:00
SomberNight
05599eeda5 swaps: fix get_swap_by_funding_tx, and types/type-hints
- funding txs having only one output is not true...
- batch_rbf can combine funding txs
2024-03-13 11:37:01 +00:00
SomberNight
8ab3dcce5d keystore: API changes for from_seed/from_bip43_rootseed/bip39_to_seed
- force kwargs
- add type hints
2024-02-21 15:08:19 +00:00
ThomasV
9799603779 Merge pull request #8888 from SomberNight/202402_jsonrpc_errors
cli/rpc: nicer error messages and error-passing
2024-02-21 13:20:28 +01:00
SomberNight
0925f15280 wallet/keystore: add apis for "add_slip_19_ownership_proofs_to_tx"
- implement it specifically for the "singlesig trezor" case
- aimed to be generic enough that support for more complex scripts
  and other keystores could be added later
2024-02-21 11:56:13 +00:00
SomberNight
bd492fbd14 cli/rpc: nicer error messages and error-passing
Previously, generally, in case of any error, commands would raise a generic "Exception()" and the CLI/RPC would convert that and return it as `str(e)`.

With this change, we now distinguish "user-facing exceptions" (e.g. "Password required" or "wallet not loaded") and "internal errors" (e.g. bugs).
- for "user-facing exceptions", the behaviour is unchanged
- for "internal errors", we now pass around the traceback (e.g. from daemon server to rpc client) and show it to the user (previously, assuming there was a daemon running, the user could only retrieve the exception from the log of that daemon). These errors use a new jsonrpc error code int (code 2).

As the logic only changes for "internal errors", I deem this change not to be compatibility-breaking.

----------
Examples follow.
Consider the following two commands:
```
@command('')
async def errorgood(self):
	from electrum.util import UserFacingException
	raise UserFacingException("heyheyhey")

@command('')
async def errorbad(self):
	raise Exception("heyheyhey")
```

----------
(before change)

CLI with daemon:
```
$ ./run_electrum --testnet daemon -d
starting daemon (PID 9221)
$ ./run_electrum --testnet errorgood
heyheyhey
$ ./run_electrum --testnet errorbad
heyheyhey
$ ./run_electrum --testnet stop
Daemon stopped
```

CLI without daemon:
```
$ ./run_electrum --testnet -o errorgood
heyheyhey
$ ./run_electrum --testnet -o errorbad
heyheyhey
```

RPC:
```
$ curl --data-binary '{"id":"curltext","jsonrpc":"2.0","method":"errorgood","params":[]}' http://user:pass@127.0.0.1:7777
{"id": "curltext", "jsonrpc": "2.0", "error": {"code": 1, "message": "heyheyhey"}}
$ curl --data-binary '{"id":"curltext","jsonrpc":"2.0","method":"errorbad","params":[]}' http://user:pass@127.0.0.1:7777
{"id": "curltext", "jsonrpc": "2.0", "error": {"code": 1, "message": "heyheyhey"}}
```

----------
(after change)

CLI with daemon:
```
$ ./run_electrum --testnet daemon -d
starting daemon (PID 9254)
$ ./run_electrum --testnet errorgood
heyheyhey
$ ./run_electrum --testnet errorbad
(inside daemon): Traceback (most recent call last):
  File "/home/user/wspace/electrum/electrum/daemon.py", line 254, in handle
    response['result'] = await f(*params)
  File "/home/user/wspace/electrum/electrum/daemon.py", line 361, in run_cmdline
    result = await func(*args, **kwargs)
  File "/home/user/wspace/electrum/electrum/commands.py", line 163, in func_wrapper
    return await func(*args, **kwargs)
  File "/home/user/wspace/electrum/electrum/commands.py", line 217, in errorbad
    raise Exception("heyheyhey")
Exception: heyheyhey

internal error while executing RPC
$ ./run_electrum --testnet stop
Daemon stopped
```

CLI without daemon:
```
$ ./run_electrum --testnet -o errorgood
heyheyhey
$ ./run_electrum --testnet -o errorbad
  0.78 | E | __main__ | error running command (without daemon)
Traceback (most recent call last):
  File "/home/user/wspace/electrum/./run_electrum", line 534, in handle_cmd
    result = fut.result()
  File "/usr/lib/python3.10/concurrent/futures/_base.py", line 458, in result
    return self.__get_result()
  File "/usr/lib/python3.10/concurrent/futures/_base.py", line 403, in __get_result
    raise self._exception
  File "/home/user/wspace/electrum/./run_electrum", line 255, in run_offline_command
    result = await func(*args, **kwargs)
  File "/home/user/wspace/electrum/electrum/commands.py", line 163, in func_wrapper
    return await func(*args, **kwargs)
  File "/home/user/wspace/electrum/electrum/commands.py", line 217, in errorbad
    raise Exception("heyheyhey")
Exception: heyheyhey
```

RPC:
```
$ curl --data-binary '{"id":"curltext","jsonrpc":"2.0","method":"errorgood","params":[]}' http://user:pass@127.0.0.1:7777
{"id": "curltext", "jsonrpc": "2.0", "error": {"code": 1, "message": "heyheyhey"}}
$ curl --data-binary '{"id":"curltext","jsonrpc":"2.0","method":"errorbad","params":[]}' http://user:pass@127.0.0.1:7777
{"id": "curltext", "jsonrpc": "2.0", "error": {"code": 2, "message": "internal error while executing RPC", "data": {"exception": "Exception('heyheyhey')", "traceback": "Traceback (most recent call last):\n  File \"/home/user/wspace/electrum/electrum/daemon.py\", line 254, in handle\n    response['result'] = await f(*params)\n  File \"/home/user/wspace/electrum/electrum/commands.py\", line 163, in func_wrapper\n    return await func(*args, **kwargs)\n  File \"/home/user/wspace/electrum/electrum/commands.py\", line 217, in errorbad\n    raise Exception(\"heyheyhey\")\nException: heyheyhey\n"}}}
```
2024-02-12 19:02:02 +00:00
SomberNight
c84e55e957 wallet: (trivial) simplify class hierarchy
legacy cruft
2024-02-05 12:47:20 +00:00