* Timelock Recovery Extension
* Timelock Recovery Extension tests
* Use fee_policy instead of fee_est
Following 3f327eea07
* making tx with base_tx
Following ab14c3e138
* move plugin metadata from __init__.py to manifest.json
* removing json large indentation
* timelock recovery icon
* timelock recovery plugin: fix typos
* timelock recovery plugin: use menu instead of status bar.
The status bar should be used for displaying status. For example,
hardware wallet plugins use it because their connection status is
changing and needs to be displayed.
* timelock recovery plugin: ask for password only once
* timelock recovery plugin: ask whether to create cancellation tx in the initial window
* remove unnecessary code.
(calling run_hook from a plugin does not make sense)
* show alert and cancellation address at the end.
skip unnecessary dialog
* timelock recovery plugin: do not show transactions one by one.
Set the fee policy in the first dialog, and use the same fee
policy for all tx. We could add 3 sliders to this dialog, if
different fees are needed, but I think this really isn't
really necessary.
* simplify default_wallet for tests
All the lightning-related stuff is irrelevant for
this plugin.
Also use a different destination address
for the test recovery-plan (an address
that does not belong to the same wallet).
* Fee selection should be above fee calculation
also show fee calculation result with "fee: " label.
* hide Sign and Broadcast buttons during view
* recalculate cancellation transaction
The checkbox could be clicked after the fee rate
has been set. Calling update_transactions() may seem
inefficient, but it's the simplest way to avoid such edge-cases.
Also set the context's cancellation transaction to None when the
checkbox is unset.
* use context.cancellation_tx instead of checkbox value
context.cancellation_tx will be None iff the checkbox was unset
* hide cancellation address if not used
* init monospace font correctly
* timelock recovery plugin: add input info at signing time.
Fixes trezor exception: 'Missing previous tx'
* timelock recovery: remove unused parameters
* avoid saving the tx in a separate var
fixing the assertions
* avoid caching recovery & cancellation inputs
* timelock recovery: separate help window from agreement.
move agreement at the end of the flow, rephrase it
* do not cache alert_tx_outputs
* do not crash when not enough funds
not enough funds can happen
when multiple addresses are specified
in payto_e, with an amount larger
than the wallet has - so we set
the payto_e color to red.
It can also happen when the user
selects a really high fee, but this
is not common in a "recovery"
wallet with significant funds.
* If files not saved - ask before closing
* move the checkbox above the save buttons
people read the text from top to
bottom and may not understand
why the buttons are disabled
---------
Co-authored-by: f321x <f321x@tutamail.com>
Co-authored-by: ThomasV <thomasv@electrum.org>
Accepting a PSBT opens the Tx dialog and pauses receiving additional PSBTs until the Tx dialog is closed.
Rejecting a PSBT will start a cooldown and accept all pending PSBTs into the history for later inspection.
- 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
- 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
and use default sizing when displaying PSBTs.
Prior to this, when displaying a large PSBT (that should still fit within a QR),
the default window size was too small, and the user had to manually resize the window.
e.g. if you consolidate own utxos, the "amount sent" in the dialog is zero,
but for high fee warnings that's not the amount we should be comparing against
RunCoroutineDialog has a run() method that blocks the thread
without blocking the GUI (using exec), and a Cancel button
that cancels the coroutine.
main_window.run_coroutine_dialog() is a wrapper that returns
the coroutine result and may raise exceptions.
BlockingWaitingDialog was removed is transaction_dialog,
where it was not particularly useful.
- rename globals
- also rm hardcoded strings from qml
- use consistent unit names in qml
(previously mixed sat/vB and sat/byte (latter coming from core lib))
- risk_of_burning_coins_as_fees is turned into a private (helper) method, only called by check_sighash.
UIs should only care about check_sighash.
- check_sighash returns instance of new class "TxSighashDanger" instead of tuple
- made warning levels more fine-grained (FEE_WARNING_SKIPCONFIRM vs FEE_WARNING_NEEDCONFIRM)
- this became more complicated than I had hoped for but I think it is worth it to ~merge
check_sighash and risk_of_burning_coins_as_fees into one.
related https://github.com/spesmilo/electrum/pull/8699
qml: use backend sighash check and add user confirmation path
qt: use backend sighash check and add user confirmation path
qml: include get_warning_for_risk_of_burning_coins_as_fees test in txdetails
qt: add warning icon to sighash warning
add sighash and fee checks to wallet.sign_transaction, making all warnings fatal unless ignore_warnings is set to True
tests: test sign_transaction on both code paths with ignore_warnings True and False,
raise specific exceptions TransactionPotentiallyDangerousException and TransactionDangerousException
Somewhat a follow-up to 649ce979ab.
This adds some safety belts so we don't accidentally sign a tx that
contains a dummy address.
Specifically we check that tx does not contain output for dummy addr:
- in wallet.sign_transaction
- in network.broadcast_transaction
The second one is perhaps redundant, but I think it does not hurt.
lnworker is None if lightning is disabled.
follow-up 649ce979ab
```
15.14 | E | gui.qt.exception_window.Exception_Hook | exception caught by crash reporter
Traceback (most recent call last):
File "...\electrum\electrum\gui\qt\rate_limiter.py", line 231, in wrapper
return RateLimiter.invoke(rate, ts_after, func, args, kwargs)
File "...\electrum\electrum\gui\qt\rate_limiter.py", line 79, in invoke
return rl._invoke(args, kwargs)
File "...\electrum\electrum\gui\qt\rate_limiter.py", line 91, in _invoke
return self._doIt()
File "...\electrum\electrum\gui\qt\rate_limiter.py", line 120, in _doIt
retval = self.func(*args, **kwargs) # and.. call the function. use latest invocation's args
File "...\electrum\electrum\gui\qt\transaction_dialog.py", line 745, in _throttled_update
self.update()
File "...\electrum\electrum\gui\qt\transaction_dialog.py", line 750, in update
self.io_widget.update(self.tx)
File "...\electrum\electrum\gui\qt\transaction_dialog.py", line 243, in update
insert_tx_io(
File "...\electrum\electrum\gui\qt\transaction_dialog.py", line 205, in insert_tx_io
tcf_addr = addr_text_format(addr)
File "...\electrum\electrum\gui\qt\transaction_dialog.py", line 173, in addr_text_format
sm = self.wallet.lnworker.swap_manager
AttributeError: 'NoneType' object has no attribute 'swap_manager'
```
```
229.18 | E | gui.qt.main_window.[test_segwit_2] | on_error
Traceback (most recent call last):
File "...\electrum\gui\qt\util.py", line 917, in run
result = task.task()
File "...\electrum\gui\qt\send_tab.py", line 681, in broadcast_thread
if self.payto_e.payment_identifier.has_expired():
AttributeError: 'NoneType' object has no attribute 'has_expired'
```
In SendTab.broadcast_transaction.broadcast_thread, self.payto_e.payment_identifier was referenced -
but do_clear() has already cleared it by then.
E.g. consider SendTab.pay_onchain_dialog: it calls save_pending_invoice(), which calls do_clear(),
and later (in sign_done), it calls window.broadcast_or_show, which will call SendTab.broadcast_transaction().
As there might be multiple independent transaction dialogs open simultaneously, the single shared state
send_tab.payto_e.payment_identifier approach was problematic -- I think it is conceptually nicer to
pass around the payment_identifiers as needed, as done with this change.
However, this change is not a full proper fix, as it still somewhat relies on
send_tab.payto_e.payment_identifier (e.g. in pay_onchain_dialog). Hence, e.g. when using
the invoice_list context menu "Pay..." item, as payto_e.payment_identifier is not set,
payment_identifier will be None in broadcast_transaction.
but at least we handle PI being None gracefully -- before this change, broadcast_transaction
expected PI to be set, and it was never set to the correct thing (as do_clear() already ran by then):
depending on timing it was either None or a new empty PI. In the former case, producing the above
traceback and hard failing (not only for bip70 stuff!), and in the latter, silently ignoring the logic bug.
A new config API is introduced, and ~all of the codebase is adapted to it.
The old API is kept but mainly only for dynamic usage where its extra flexibility is needed.
Using examples, the old config API looked this:
```
>>> config.get("request_expiry", 86400)
604800
>>> config.set_key("request_expiry", 86400)
>>>
```
The new config API instead:
```
>>> config.WALLET_PAYREQ_EXPIRY_SECONDS
604800
>>> config.WALLET_PAYREQ_EXPIRY_SECONDS = 86400
>>>
```
The old API operated on arbitrary string keys, the new one uses
a static ~enum-like list of variables.
With the new API:
- there is a single centralised list of config variables, as opposed to
these being scattered all over
- no more duplication of default values (in the getters)
- there is now some (minimal for now) type-validation/conversion for
the config values
closes https://github.com/spesmilo/electrum/pull/5640
closes https://github.com/spesmilo/electrum/pull/5649
Note: there is yet a third API added here, for certain niche/abstract use-cases,
where we need a reference to the config variable itself.
It should only be used when needed:
```
>>> var = config.cv.WALLET_PAYREQ_EXPIRY_SECONDS
>>> var
<ConfigVarWithConfig key='request_expiry'>
>>> var.get()
604800
>>> var.set(3600)
>>> var.get_default_value()
86400
>>> var.is_set()
True
>>> var.is_modifiable()
True
```
When exporting a tx as qr code, the prev txs are omitted to save space.
This causes problems with offline signers: software electrum signers will
just warn and then proceed, but hw devices will typically error.
This allows users to edit labels from the utxo_dialog,
without having to search for the transaction in history.
Also, remove block hash from tx dialog: not very useful, and
available through block explorers. (the situation where this
could be useful is case of a chain fork, but in that case the
tx might be mined in both branches of the fork, and we would
want to know that).
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
- 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
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