electrum

Electrum Bitcoin wallet
git clone https://git.parazyd.org/electrum
Log | Files | Refs | Submodules

commit 90abfda12bf78ce13332ab0474dcade418a211b1
parent d50a8d1b843d9f155e58e846ed5fa4ff8d28c929
Author: ThomasV <thomasv@electrum.org>
Date:   Tue, 12 Jan 2021 10:49:46 +0100

add unconfirmed state for onchain invoices and requests

Diffstat:
Melectrum/gui/qt/util.py | 3++-
Melectrum/invoices.py | 3+++
Melectrum/wallet.py | 30+++++++++++++++++++++---------
3 files changed, 26 insertions(+), 10 deletions(-)

diff --git a/electrum/gui/qt/util.py b/electrum/gui/qt/util.py @@ -26,7 +26,7 @@ from PyQt5.QtWidgets import (QPushButton, QLabel, QMessageBox, QHBoxLayout, from electrum.i18n import _, languages from electrum.util import FileImportFailed, FileExportFailed, make_aiohttp_session, resource_path -from electrum.invoices import PR_UNPAID, PR_PAID, PR_EXPIRED, PR_INFLIGHT, PR_UNKNOWN, PR_FAILED, PR_ROUTING +from electrum.invoices import PR_UNPAID, PR_PAID, PR_EXPIRED, PR_INFLIGHT, PR_UNKNOWN, PR_FAILED, PR_ROUTING, PR_UNCONFIRMED if TYPE_CHECKING: from .main_window import ElectrumWindow @@ -52,6 +52,7 @@ pr_icons = { PR_INFLIGHT:"unconfirmed.png", PR_FAILED:"warning.png", PR_ROUTING:"unconfirmed.png", + PR_UNCONFIRMED:"unconfirmed.png", } diff --git a/electrum/invoices.py b/electrum/invoices.py @@ -29,6 +29,7 @@ PR_PAID = 3 # send and propagated PR_INFLIGHT = 4 # unconfirmed PR_FAILED = 5 PR_ROUTING = 6 +PR_UNCONFIRMED = 7 pr_color = { PR_UNPAID: (.7, .7, .7, 1), @@ -38,6 +39,7 @@ pr_color = { PR_INFLIGHT: (.9, .6, .3, 1), PR_FAILED: (.9, .2, .2, 1), PR_ROUTING: (.9, .6, .3, 1), + PR_UNCONFIRMED: (.9, .6, .3, 1), } pr_tooltips = { @@ -48,6 +50,7 @@ pr_tooltips = { PR_INFLIGHT:_('In progress'), PR_FAILED:_('Failed'), PR_ROUTING: _('Computing route...'), + PR_UNCONFIRMED: _('Unconfirmed'), } PR_DEFAULT_EXPIRATION_WHEN_CREATING = 24*60*60 # 1 day diff --git a/electrum/wallet.py b/electrum/wallet.py @@ -73,7 +73,7 @@ from .plugin import run_hook from .address_synchronizer import (AddressSynchronizer, TX_HEIGHT_LOCAL, TX_HEIGHT_UNCONF_PARENT, TX_HEIGHT_UNCONFIRMED, TX_HEIGHT_FUTURE) from .invoices import Invoice, OnchainInvoice, LNInvoice -from .invoices import PR_PAID, PR_UNPAID, PR_UNKNOWN, PR_EXPIRED, PR_INFLIGHT, PR_TYPE_ONCHAIN, PR_TYPE_LN +from .invoices import PR_PAID, PR_UNPAID, PR_UNKNOWN, PR_EXPIRED, PR_UNCONFIRMED, PR_TYPE_ONCHAIN, PR_TYPE_LN from .contacts import Contacts from .interface import NetworkException from .mnemonic import Mnemonic @@ -741,7 +741,7 @@ class Abstract_Wallet(AddressSynchronizer, ABC): elif invoice_type == PR_TYPE_ONCHAIN: assert isinstance(invoice, OnchainInvoice) key = invoice.id - if self.is_onchain_invoice_paid(invoice): + if self.is_onchain_invoice_paid(invoice, 0): self.logger.info("saving invoice... but it is already paid!") with self.transaction_lock: for txout in invoice.outputs: @@ -813,7 +813,7 @@ class Abstract_Wallet(AddressSynchronizer, ABC): for txout in invoice.outputs: self._invoices_from_scriptpubkey_map[txout.scriptpubkey].add(invoice_key) - def _is_onchain_invoice_paid(self, invoice: Invoice) -> Tuple[bool, Sequence[str]]: + def _is_onchain_invoice_paid(self, invoice: Invoice, conf: int) -> Tuple[bool, Sequence[str]]: """Returns whether on-chain invoice is satisfied, and list of relevant TXIDs.""" assert invoice.type == PR_TYPE_ONCHAIN assert isinstance(invoice, OnchainInvoice) @@ -827,8 +827,10 @@ class Abstract_Wallet(AddressSynchronizer, ABC): prevouts_and_values = self.db.get_prevouts_by_scripthash(scripthash) total_received = 0 for prevout, v in prevouts_and_values: - height = self.get_tx_height(prevout.txid.hex()).height - if height > 0 and height <= invoice.height: + tx_height = self.get_tx_height(prevout.txid.hex()) + if tx_height.height > 0 and tx_height.height <= invoice.height: + continue + if tx_height.conf < conf: continue total_received += v relevant_txs.append(prevout.txid.hex()) @@ -840,8 +842,8 @@ class Abstract_Wallet(AddressSynchronizer, ABC): return False, [] return True, relevant_txs - def is_onchain_invoice_paid(self, invoice: Invoice) -> bool: - return self._is_onchain_invoice_paid(invoice)[0] + def is_onchain_invoice_paid(self, invoice: Invoice, conf: int) -> bool: + return self._is_onchain_invoice_paid(invoice, conf)[0] def _maybe_set_tx_label_based_on_invoices(self, tx: Transaction) -> bool: # note: this is not done in 'get_default_label' as that would require deserializing each tx @@ -1839,7 +1841,12 @@ class Abstract_Wallet(AddressSynchronizer, ABC): if invoice.is_lightning(): status = self.lnworker.get_invoice_status(invoice) if self.lnworker else PR_UNKNOWN else: - status = PR_PAID if self.is_onchain_invoice_paid(invoice) else PR_UNPAID + if self.is_onchain_invoice_paid(invoice, 1): + status =PR_PAID + elif self.is_onchain_invoice_paid(invoice, 0): + status = PR_UNCONFIRMED + else: + status = PR_UNPAID return self.check_expired_status(invoice, status) def get_request_status(self, key): @@ -1852,7 +1859,12 @@ class Abstract_Wallet(AddressSynchronizer, ABC): else: assert isinstance(r, OnchainInvoice) paid, conf = self.get_onchain_request_status(r) - status = PR_PAID if paid else PR_UNPAID + if not paid: + status = PR_UNPAID + elif conf == 0: + status = PR_UNCONFIRMED + else: + status = PR_PAID return self.check_expired_status(r, status) def get_request(self, key):