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:
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):