Commit Graph

503 Commits

Author SHA1 Message Date
ThomasV
503776c0de move fiat columns show/hide settings from settings_dialog to tab toolbars 2023-03-12 13:30:11 +01:00
SomberNight
d83863cc52 qt tx dialog: add checkbox "Download input data"
If checked, we download prev (parent) txs from the network, asynchronously.
This allows calculating the fee and showing "input addresses".

We could also SPV-verify the tx, to fill in missing tx_mined_status
(block height, blockhash, timestamp, short ids), but this is not done currently.
Note that there is no clean way to do this with electrum protocol 1.4:
`blockchain.transaction.get_merkle(tx_hash, height)` requires knowledge of the block height.

Loosely based on 6112fe0e51
2023-03-12 00:24:31 +00:00
SomberNight
81772faf6c wallet: add_input_info to no longer do network requests
- wallet.add_input_info() previously had a fallback to download parent
  prev txs from the network (after a lookup in wallet.db failed).
  wallet.add_input_info() is not async, so the network request cannot
  be done cleanly there and was really just a hack.
- tx.add_info_from_wallet() calls wallet.add_input_info() on each txin,
  in which case these network requests were done sequentially, not concurrently
- the network part of wallet.add_input_info() is now split out into new method:
  txin.add_info_from_network()
- in addition to tx.add_info_from_wallet(), there is now also tx.add_info_from_network()
  - callers of old tx.add_info_from_wallet() should now called either
    - tx.add_info_from_wallet(), then tx.add_info_from_network(), preferably in that order
    - tx.add_info_from_wallet() alone is sufficient if the tx is complete,
      or typically when not in a signing context
- callers of wallet.bump_fee and wallet.dscancel are now expected to have already
  called tx.add_info_from_network(), as it cannot be done in a non-async context
  (but for the common case of all-inputs-are-ismine, bump_fee/dscancel should work regardless)
- PartialTxInput.utxo was moved to the baseclass, TxInput.utxo
2023-03-12 00:21:57 +00:00
SomberNight
7746cc8e60 bip32: (trivial) rename method strpath_to_intpath, for symmetry
Required a much higher mental load to parse the name "convert_bip32_path_to_list_of_uint32"
than to parse "convert_bip32_strpath_to_intpath".
And we already have the ~inverse: "convert_bip32_intpath_to_strpath".
2023-03-10 14:23:17 +00:00
SomberNight
7584ba00ce wallet: kill negative conf numbers for TxMinedInfo
fixes https://github.com/spesmilo/electrum/issues/8240

#8240 was triggering an AssertionError in wallet.get_invoice_status,
as code there was assuming conf >= 0. To trigger, force-close
a LN channel, and while the sweep is waiting on the CSV, try to
make a payment in the Send tab to the ismine change address used
for the sweep in the future_tx. (order of events can also be reversed)
2023-03-09 14:59:08 +00:00
ThomasV
364510906f Fix edge case of batch_rbf, where we need to spend outputs from the base tx 2023-03-08 15:03:05 +01:00
ThomasV
3253e4904b Add rbf_merge_txid to PartialTransaction, instead of calling
get_unconfirmed_base_tx_for_batching a second time from GUI.
2023-03-08 12:38:41 +01:00
ThomasV
a5c7cc65ee make_unsigned_transaction: call get_unconfirmed_base_tx_for_batching lazily 2023-03-07 18:13:27 +01:00
ThomasV
74718e9085 confirm_tx_dialog: separate messages from warnings. add warnings about tx batching and spending unconfirmed coins 2023-03-06 19:25:46 +01:00
ThomasV
2f6d60c715 Move transaction related settings into transaction editor.
That way, users can see the effects settings directly on their transaction.
This changes the API of make_tx:
 - get_coins is called inside make_tx, so that inputs can be changed dynamically
 - make_tx takes an optional parameter: unconfirmed_only, passed to get_coins
 - ConfirmTxDialog detects if we can pay by disabling confirmed_only or lowering fee
2023-03-05 10:17:03 +01:00
ThomasV
2ed71579c3 privacy analysis: detect address reuse
add tx position to get_addr_io
2023-03-04 08:53:49 +01:00
ThomasV
798cd607b5 Merge pull request #8230 from SomberNight/202302_osd_tx
output script descriptors, part 1: change API of transaction.py
2023-03-04 08:48:56 +01:00
SomberNight
a80bef8421 follow-up descriptor.py: small clean-up 2023-03-03 16:40:45 +00:00
SomberNight
31f457c242 wallet.get_script_desc_for_addr: use xpub instead of derived pubkey
also put key origin info into descriptor, if available
2023-03-03 16:40:38 +00:00
SomberNight
36986a9881 transaction.py: set txio.{witness,redeem}|script based on descriptor 2023-03-03 16:40:15 +00:00
SomberNight
0647a2cf9f transaction.py: rm PartialTxInput.{num_sig, script_type} 2023-03-03 16:40:12 +00:00
SomberNight
ec889b8c3f wallet: fix import_requests, and mention quirk re preimages 2023-03-03 16:35:34 +00:00
SomberNight
81bd6f7d1b follow-up invoice changes: fix "Add lightning invoice to bitcoin URIs"
follow-up 719b468eee
2023-03-03 16:14:35 +00:00
SomberNight
a1a1fae4cc invoices.py: small clean-up 2023-03-03 16:02:19 +00:00
SomberNight
5673f08750 follow-up invoice changes: fix wallet.get_bolt11_inv if amt is None
follow-up 719b468eee

Traceback (most recent call last):
  File "...\electrum\electrum\gui\qt\request_list.py", line 111, in item_changed
    self.receive_tab.update_current_request()
  File "...\electrum\electrum\gui\qt\receive_tab.py", line 227, in update_current_request
    lnaddr = self.wallet.get_bolt11_invoice(req) if not help_texts.ln_is_error else ''
  File "...\electrum\electrum\wallet.py", line 2515, in get_bolt11_invoice
    amount_msat = req.amount_msat if req.amount_msat > 0 else None
TypeError: '>' not supported between instances of 'NoneType' and 'int'
2023-03-03 16:02:12 +00:00
ThomasV
e24c4004fa change invoice type hints following 719b468eee 2023-03-03 10:08:34 +01:00
ThomasV
9f5c5f92b3 follow-up 719b468eee 2023-03-03 10:04:37 +01:00
SomberNight
f1f39f0e82 descriptors: wallet/transaction: construct intermediate osd 2023-03-01 17:53:52 +00:00
SomberNight
d11237d6a1 lnworker: start watching already redeemed chans if txs are missing
This fixes a bug where if one runs `wallet.clear_history()` they would see exceptions later:
```
Traceback (most recent call last):
  File "/home/user/wspace/electrum/electrum/gui/qt/main_window.py", line 866, in timer_actions
	self.update_wallet()
  File "/home/user/wspace/electrum/electrum/gui/qt/main_window.py", line 1021, in update_wallet
	self.update_tabs()
  File "/home/user/wspace/electrum/electrum/gui/qt/main_window.py", line 1033, in update_tabs
	self.utxo_list.update()
  File "/home/user/wspace/electrum/electrum/gui/qt/utxo_list.py", line 103, in update
	self.refresh_row(name, idx)
  File "/home/user/wspace/electrum/electrum/gui/qt/utxo_list.py", line 124, in refresh_row
	parents = self.wallet.get_tx_parents(txid)
  File "/home/user/wspace/electrum/electrum/wallet.py", line 885, in get_tx_parents
	result.update(self.get_tx_parents(_txid))
  File "/home/user/wspace/electrum/electrum/wallet.py", line 881, in get_tx_parents
	for i, txin in enumerate(tx.inputs()):
AttributeError: 'NoneType' object has no attribute 'inputs'
```
This is related to the privacy analysis, which assumes that for each tx item in the history list
we should have the raw tx in the db. This is no longer true after wallet.clear_history(), if
the wallet has certain LN channels. E.g. an already redeemed channel that was local-force-closed,
as that closing tx is not related to the wallet directly.

In commit 3541ecb576, we decided not to watch already redeemed channels.
This is potentially good for e.g. privacy, as the server would otherwise see us subscribe to that chan.
However it means that after running wallet.clear_history() txs related to the channel but not to the
wallet won't be re-downloaded.

Instead, now if there are missing txs for a redeemed channel, we start watching it, hence the
synchronizer will re-downloaded the txs.
2023-03-01 16:20:42 +00:00
ThomasV
4ad9caddab Merge pull request #8231 from spesmilo/fix_8213
Refresh bolt11 routing hints when channel liquidity changes:
2023-03-01 11:35:34 +01:00
ThomasV
33c7ecbaf8 utxo details: show list of parents as a tree 2023-03-01 11:07:12 +01: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
e4273e5ab9 utxo privacy analysis:
- add a new event, 'adb_removed_tx'
 - new wallet method: get_tx_parents
 - number of parents is shown in coins tab
 - detailed list of parents is shown in dialog
2023-02-25 11:46:47 +01:00
SomberNight
d4338fb503 tests: clean-up use of asyncio 2023-02-20 16:53:44 +00:00
SomberNight
373db76ac9 util: kill bh2u
no longer useful, and the name is so confusing...
2023-02-17 11:43:11 +00:00
ThomasV
f617887509 RBF dialog: do not decrease payment for swap funding transactions. 2023-02-10 16:30:08 +01:00
ThomasV
bf16919a74 Merge pull request #8197 from spesmilo/new_tx_flow
Qt: new onchain tx creation flow:
2023-02-10 10:26:44 +01:00
SomberNight
8a53a3201c wallet.try_detecting_internal_addresses_corruption: check more addrs
related https://github.com/spesmilo/electrum/issues/8202

For a HD wallet, instead of checking the first 10 addrs + 10 additional random ones,
we now check the first 10 addrs + 10 random used addrs + 10 random unused addrs.
Checking unused addresses is useful to prevent getting money sent there,
and checking used addresses is useful to inform people of already lost money.
2023-02-08 23:32:32 +00:00
ThomasV
bc3946d2f4 Qt: new onchain tx creation flow:
- transaction_dialog is read-only
 - ConfirmTxDialog and RBF dialogs inherit from TxEditor
 - TxEditors are configurable
2023-02-07 16:42:20 +01:00
ThomasV
d6febb5c12 Display mined tx outputs as ShortIDs instead of full transaction outpoints.
ShortIDs were originally designed for lightning channels, and are now
understood by some block explorers.

This allows to remove one column in the UTXO tab (height is redundant).

In the transaction dialog, the space saving ensures that all inputs fit
into one line (it was not the case previously with p2wsh addresses).
For clarity and consistency, the ShortID is displayed for both inputs
and outputs in the transaction dialog.
2023-01-26 10:48:28 +01:00
ThomasV
062051b530 lnworker: store onchain default labels in a cache 2023-01-23 10:48:25 +01:00
Sander van Grieken
aac0e4f693 add explicit is_lightning check before potentially calling lnworker.get_invoice_status in wallet.export_request 2023-01-17 11:34:23 +01:00
ThomasV
7bfcf4f4d8 Merge pull request #8143 from MrNaif2018/tx-hashes-unpaid-invoices
Return list of tx hashes for partially paid invoices too
2023-01-13 18:29:58 +01:00
ThomasV
7d52021d6b Merge pull request #8139 from SomberNight/202301_locale_decimal_point
locale amounts: consistently use "." as dec point, and " " as thou sep
2023-01-13 16:00:47 +01:00
MrNaif2018
c785eb9ccd Return list of tx hashes for partially paid invoices too 2023-01-13 01:04:49 +03:00
SomberNight
9a0fff2571 wallet.get_request_by_addr: make deterministic
This makes test_invoices/test_wallet_get_request_by_addr pass without flakyness.

closes https://github.com/spesmilo/electrum/issues/8113
2023-01-12 18:19:11 +00:00
SomberNight
7dcaa4b204 tests: add tests for wallet/invoices functionality
only for payment requests ("incoming invoices") for now
2023-01-12 18:19:08 +00:00
SomberNight
8829b7cd63 wallet: fix deadlock in on_event_adb_added_verified_tx
wallet.lock -> wallet.transaction_lock order must be respected.

deadlock example:
```
# ThreadID: 19100
File: ...\Python\Python310\lib\threading.py", line 966, in _bootstrap
  self._bootstrap_inner()
File: ...\Python\Python310\lib\threading.py", line 1009, in _bootstrap_inner
  self.run()
File: ...\Python\Python310\lib\threading.py", line 946, in run
  self._target(*self._args, **self._kwargs)
File: "...\electrum\electrum\util.py", line 1552, in run_event_loop
  loop.run_until_complete(stopping_fut)
File: ...\Python\Python310\lib\asyncio\base_events.py", line 633, in run_until_complete
  self.run_forever()
File: ...\Python\Python310\lib\asyncio\windows_events.py", line 321, in run_forever
  super().run_forever()
File: ...\Python\Python310\lib\asyncio\base_events.py", line 600, in run_forever
  self._run_once()
File: ...\Python\Python310\lib\asyncio\base_events.py", line 1896, in _run_once
  handle._run()
File: ...\Python\Python310\lib\asyncio\events.py", line 80, in _run
  self._context.run(self._callback, *self._args)
File: "...\electrum\electrum\wallet.py", line 494, in on_event_adb_added_verified_tx
  self._update_invoices_and_reqs_touched_by_tx(tx_hash)
File: "...\electrum\electrum\wallet.py", line 2454, in _update_invoices_and_reqs_touched_by_tx
  status = self.get_invoice_status(request)
File: "...\electrum\electrum\wallet.py", line 2333, in get_invoice_status
  paid, conf = self.is_onchain_invoice_paid(invoice)
File: "...\electrum\electrum\wallet.py", line 1120, in is_onchain_invoice_paid
  is_paid, conf_needed, relevant_txs = self._is_onchain_invoice_paid(invoice)
File: "...\electrum\electrum\wallet.py", line 1095, in _is_onchain_invoice_paid
  with self.lock, self.transaction_lock:
File: "...\electrum\electrum\address_synchronizer.py", line 70, in acquire
  return self._lock.acquire(*args, **kwargs)

# ThreadID: 20040
File: "C:\Program Files\JetBrains\PyCharm Community Edition 2021.3.3\plugins\python-ce\helpers\pycharm\_jb_pytest_runner.py", line 51, in <module>
  sys.exit(pytest.main(args, plugins_to_load + [Plugin]))
File: "...\Python\Python310\site-packages\_pytest\config\__init__.py", line 164, in main
  ret: Union[ExitCode, int] = config.hook.pytest_cmdline_main(
File: ...\Python\Python310\lib\site-packages\pluggy\_hooks.py", line 265, in __call__
  return self._hookexec(self.name, self.get_hookimpls(), kwargs, firstresult)
File: ...\Python\Python310\lib\site-packages\pluggy\_manager.py", line 80, in _hookexec
  return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
File: ...\Python\Python310\lib\site-packages\pluggy\_callers.py", line 39, in _multicall
  res = hook_impl.function(*args)
File: "...\Python\Python310\site-packages\_pytest\main.py", line 315, in pytest_cmdline_main
  return wrap_session(config, _main)
File: "...\Python\Python310\site-packages\_pytest\main.py", line 268, in wrap_session
  session.exitstatus = doit(config, session) or 0
File: "...\Python\Python310\site-packages\_pytest\main.py", line 322, in _main
  config.hook.pytest_runtestloop(session=session)
File: ...\Python\Python310\lib\site-packages\pluggy\_hooks.py", line 265, in __call__
  return self._hookexec(self.name, self.get_hookimpls(), kwargs, firstresult)
File: ...\Python\Python310\lib\site-packages\pluggy\_manager.py", line 80, in _hookexec
  return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
File: ...\Python\Python310\lib\site-packages\pluggy\_callers.py", line 39, in _multicall
  res = hook_impl.function(*args)
File: "...\Python\Python310\site-packages\_pytest\main.py", line 347, in pytest_runtestloop
  item.config.hook.pytest_runtest_protocol(item=item, nextitem=nextitem)
File: ...\Python\Python310\lib\site-packages\pluggy\_hooks.py", line 265, in __call__
  return self._hookexec(self.name, self.get_hookimpls(), kwargs, firstresult)
File: ...\Python\Python310\lib\site-packages\pluggy\_manager.py", line 80, in _hookexec
  return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
File: ...\Python\Python310\lib\site-packages\pluggy\_callers.py", line 39, in _multicall
  res = hook_impl.function(*args)
File: "...\Python\Python310\site-packages\_pytest\runner.py", line 111, in pytest_runtest_protocol
  runtestprotocol(item, nextitem=nextitem)
File: "...\Python\Python310\site-packages\_pytest\runner.py", line 130, in runtestprotocol
  reports.append(call_and_report(item, "call", log))
File: "...\Python\Python310\site-packages\_pytest\runner.py", line 219, in call_and_report
  call = call_runtest_hook(item, when, **kwds)
File: "...\Python\Python310\site-packages\_pytest\runner.py", line 258, in call_runtest_hook
  return CallInfo.from_call(
File: "...\Python\Python310\site-packages\_pytest\runner.py", line 338, in from_call
  result: Optional[TResult] = func()
File: "...\Python\Python310\site-packages\_pytest\runner.py", line 259, in <lambda>
  lambda: ihook(item=item, **kwds), when=when, reraise=reraise
File: ...\Python\Python310\lib\site-packages\pluggy\_hooks.py", line 265, in __call__
  return self._hookexec(self.name, self.get_hookimpls(), kwargs, firstresult)
File: ...\Python\Python310\lib\site-packages\pluggy\_manager.py", line 80, in _hookexec
  return self._inner_hookexec(hook_name, methods, kwargs, firstresult)
File: ...\Python\Python310\lib\site-packages\pluggy\_callers.py", line 39, in _multicall
  res = hook_impl.function(*args)
File: "...\Python\Python310\site-packages\_pytest\runner.py", line 166, in pytest_runtest_call
  item.runtest()
File: "...\Python\Python310\site-packages\_pytest\unittest.py", line 327, in runtest
  self._testcase(result=self)  # type: ignore[arg-type]
File: ...\Python\Python310\lib\unittest\case.py", line 650, in __call__
  return self.run(*args, **kwds)
File: ...\Python\Python310\lib\unittest\case.py", line 591, in run
  self._callTestMethod(testMethod)
File: ...\Python\Python310\lib\unittest\case.py", line 549, in _callTestMethod
  method()
File: "...\electrum\electrum\tests\test_invoices.py", line 120, in test_wallet_without_ln_creates_payreq_and_gets_paid_onchain
  self.assertEqual(PR_PAID, wallet1.get_invoice_status(pr))
File: "...\electrum\electrum\wallet.py", line 2333, in get_invoice_status
  paid, conf = self.is_onchain_invoice_paid(invoice)
File: "...\electrum\electrum\wallet.py", line 1120, in is_onchain_invoice_paid
  is_paid, conf_needed, relevant_txs = self._is_onchain_invoice_paid(invoice)
File: "...\electrum\electrum\wallet.py", line 1095, in _is_onchain_invoice_paid
  with self.lock, self.transaction_lock:
File: "...\electrum\electrum\address_synchronizer.py", line 70, in acquire
  return self._lock.acquire(*args, **kwargs)
```
2023-01-12 18:19:04 +00:00
SomberNight
2a9909c252 locale amounts: consistently use "." as dec point, and " " as thou sep
Always use "." as decimal point, and " " as thousands separator.

Previously,
- for decimal point, we were using
  - "." in some places (e.g. AmountEdit, most fiat amounts), and
  - `locale.localeconv()['decimal_point']` in others.
- for thousands separator, we were using
  - "," in some places (most fiat amounts), and
  - " " in others (format_satoshis)

I think it is better to be consistent even if whatever we pick differs from the locale.
Using whitespace for thousands separator (vs comma) is probably less confusing for people
whose locale would user "." for ts and "," for dp (as in e.g. German).

The alternative option would be to always use the locale. Even if we decide to do that later,
this refactoring should be useful.

closes https://github.com/spesmilo/electrum/issues/2629
2023-01-10 14:45:35 +00:00
SomberNight
61f2654f31 wallet: fire fewer 'status' and 'wallet_updated' triggers
Especially during initial history sync, there are a lot of False->False up_to_date transitions
(e.g. adb.add_address generates one), and the GUI does some work for each, which adds up to a lot
of CPU usage for the full sync.
2022-12-23 09:35:29 +00:00
ThomasV
a383f56909 Simplify RBF user experience:
- replace complex strategies with a simpler choice,
   between preserving or decreasing the payment.
 - Always expose that choice to the user.
 - Show the resulting fees to the user before they click OK
2022-12-13 11:26:44 +01:00
ThomasV
e1dc7d1e6f Set the RBF flat to all transactions, and remove the 'use_rbf'
preference from the GUI, because the mempoolfullrbf option in
Bitcoin 0.24 makes RBF signaling pretty meaningless. Fixes #8088.

Note: RBF remains disabled for channel funding transactions.
In that case, the flag is actually only used as a semaphore
between different instances of the same wallet.
2022-12-10 18:58:15 +01:00
SomberNight
30f3d27baa wallet: change _requests_addr_to_key map to multi-map
I find this easier to reason about than occasionally overwriting the items.
get_request_by_addr still only returns a single invoice for simplicity,
but now all logic regarding how to handle collisions is inside that method.
2022-11-18 18:10:43 +00:00
SomberNight
1a8cc68f53 wallet: _requests_addr_to_key map to prefer unexpired reqs if collision 2022-11-18 16:59:47 +00:00
MrNaif2018
b357391c48 Add tx_hashes to exported payment requests (#7936)
* Add `tx_hashes` to payment requests

* Apply patch

* Fix for missing lnworker
2022-11-10 17:48:00 +00:00