Browse Source

payment identifier types as enum

master
Sander van Grieken 3 years ago
parent
commit
74a1f38a8b
  1. 15
      electrum/gui/qml/qeinvoice.py
  2. 10
      electrum/gui/qt/send_tab.py
  3. 47
      electrum/payment_identifier.py
  4. 3
      electrum/x509.py

15
electrum/gui/qml/qeinvoice.py

@ -17,7 +17,7 @@ from electrum.lnurl import decode_lnurl, request_lnurl, callback_lnurl
from electrum.bitcoin import COIN from electrum.bitcoin import COIN
from electrum.paymentrequest import PaymentRequest from electrum.paymentrequest import PaymentRequest
from electrum.payment_identifier import (parse_bip21_URI, InvalidBitcoinURI, maybe_extract_lightning_payment_identifier, from electrum.payment_identifier import (parse_bip21_URI, InvalidBitcoinURI, maybe_extract_lightning_payment_identifier,
PaymentIdentifier, PaymentIdentifierState) PaymentIdentifier, PaymentIdentifierState, PaymentIdentifierType)
from .qetypes import QEAmount from .qetypes import QEAmount
from .qewallet import QEWallet from .qewallet import QEWallet
@ -491,7 +491,8 @@ class QEInvoiceParser(QEInvoice):
return return
self._pi = PaymentIdentifier(self._wallet.wallet, recipient) self._pi = PaymentIdentifier(self._wallet.wallet, recipient)
if not self._pi.is_valid() or self._pi.type not in ['spk', 'bip21', 'bip70', 'bolt11', 'lnurl']: if not self._pi.is_valid() or self._pi.type not in [PaymentIdentifierType.SPK, PaymentIdentifierType.BIP21,
PaymentIdentifierType.BIP70, PaymentIdentifierType.BOLT11, PaymentIdentifierType.LNURLP]:
self.validationError.emit('unknown', _('Unknown invoice')) self.validationError.emit('unknown', _('Unknown invoice'))
return return
@ -502,23 +503,23 @@ class QEInvoiceParser(QEInvoice):
self.resolve_pi() self.resolve_pi()
return return
if self._pi.type == 'lnurl': if self._pi.type == PaymentIdentifierType.LNURLP:
self.on_lnurl(self._pi.lnurl_data) self.on_lnurl(self._pi.lnurl_data)
return return
if self._pi.type == 'bip70': if self._pi.type == PaymentIdentifierType.BIP70:
self._bip70_payment_request_resolved(self._pi.bip70_data) self._bip70_payment_request_resolved(self._pi.bip70_data)
return return
if self._pi.is_available(): if self._pi.is_available():
if self._pi.type == 'spk': if self._pi.type == PaymentIdentifierType.SPK:
outputs = [PartialTxOutput(scriptpubkey=self._pi.spk, value=0)] outputs = [PartialTxOutput(scriptpubkey=self._pi.spk, value=0)]
invoice = self.create_onchain_invoice(outputs, None, None, None) invoice = self.create_onchain_invoice(outputs, None, None, None)
self._logger.debug(repr(invoice)) self._logger.debug(repr(invoice))
self.setValidOnchainInvoice(invoice) self.setValidOnchainInvoice(invoice)
self.validationSuccess.emit() self.validationSuccess.emit()
return return
elif self._pi.type == 'bolt11': elif self._pi.type == PaymentIdentifierType.BOLT11:
lninvoice = Invoice.from_bech32(self._pi.bolt11) lninvoice = Invoice.from_bech32(self._pi.bolt11)
if not self._wallet.wallet.has_lightning() and not lninvoice.get_address(): if not self._wallet.wallet.has_lightning() and not lninvoice.get_address():
self.validationError.emit('no_lightning', self.validationError.emit('no_lightning',
@ -530,7 +531,7 @@ class QEInvoiceParser(QEInvoice):
self.setValidLightningInvoice(lninvoice) self.setValidLightningInvoice(lninvoice)
self.validationSuccess.emit() self.validationSuccess.emit()
elif self._pi.type == 'bip21': elif self._pi.type == PaymentIdentifierType.BIP21:
if self._wallet.wallet.has_lightning() and self._wallet.wallet.lnworker.channels and self._pi.bolt11: if self._wallet.wallet.has_lightning() and self._wallet.wallet.lnworker.channels and self._pi.bolt11:
lninvoice = Invoice.from_bech32(self._pi.bolt11) lninvoice = Invoice.from_bech32(self._pi.bolt11)
self.setValidLightningInvoice(lninvoice) self.setValidLightningInvoice(lninvoice)

10
electrum/gui/qt/send_tab.py

@ -16,7 +16,7 @@ from electrum.util import NotEnoughFunds, NoDynamicFeeEstimates, parse_max_spend
from electrum.invoices import PR_PAID, Invoice, PR_BROADCASTING, PR_BROADCAST from electrum.invoices import PR_PAID, Invoice, PR_BROADCASTING, PR_BROADCAST
from electrum.transaction import Transaction, PartialTxInput, PartialTxOutput from electrum.transaction import Transaction, PartialTxInput, PartialTxOutput
from electrum.network import TxBroadcastError, BestEffortRequestFailed from electrum.network import TxBroadcastError, BestEffortRequestFailed
from electrum.payment_identifier import PaymentIdentifierState from electrum.payment_identifier import PaymentIdentifierState, PaymentIdentifierType
from .amountedit import AmountEdit, BTCAmountEdit, SizedFreezableLineEdit from .amountedit import AmountEdit, BTCAmountEdit, SizedFreezableLineEdit
from .paytoedit import InvalidPaymentIdentifier from .paytoedit import InvalidPaymentIdentifier
@ -206,7 +206,7 @@ class SendTab(QWidget, MessageBoxMixin, Logger):
def spend_max(self): def spend_max(self):
assert self.payto_e.payment_identifier is not None assert self.payto_e.payment_identifier is not None
assert self.payto_e.payment_identifier.type in ['spk', 'multiline'] assert self.payto_e.payment_identifier.type in [PaymentIdentifierType.SPK, PaymentIdentifierType.MULTILINE]
if run_hook('abort_send', self): if run_hook('abort_send', self):
return return
outputs = self.payto_e.payment_identifier.get_onchain_outputs('!') outputs = self.payto_e.payment_identifier.get_onchain_outputs('!')
@ -383,10 +383,10 @@ class SendTab(QWidget, MessageBoxMixin, Logger):
self.send_button.setEnabled(False) self.send_button.setEnabled(False)
return return
lock_recipient = pi.type != 'spk' \ lock_recipient = pi.type != PaymentIdentifierType.SPK \
and not (pi.type == 'emaillike' and pi.is_state(PaymentIdentifierState.NOT_FOUND)) and not (pi.type == PaymentIdentifierType.EMAILLIKE and pi.is_state(PaymentIdentifierState.NOT_FOUND))
lock_max = pi.is_amount_locked() \ lock_max = pi.is_amount_locked() \
or pi.type in ['bolt11', 'lnurl', 'lightningaddress'] or pi.type in [PaymentIdentifierType.BOLT11, PaymentIdentifierType.LNURLP, PaymentIdentifierType.LNADDR]
self.lock_fields(lock_recipient=lock_recipient, self.lock_fields(lock_recipient=lock_recipient,
lock_amount=pi.is_amount_locked(), lock_amount=pi.is_amount_locked(),
lock_max=lock_max, lock_max=lock_max,

47
electrum/payment_identifier.py

@ -182,6 +182,17 @@ class PaymentIdentifierState(IntEnum):
MERCHANT_ERROR = 52 # PI failed notifying the merchant after broadcasting onchain TX MERCHANT_ERROR = 52 # PI failed notifying the merchant after broadcasting onchain TX
INVALID_AMOUNT = 53 # Specified amount not accepted INVALID_AMOUNT = 53 # Specified amount not accepted
class PaymentIdentifierType(IntEnum):
UNKNOWN = 0
SPK = 1
BIP21 = 2
BIP70 = 3
MULTILINE = 4
BOLT11 = 5
LNURLP = 6
EMAILLIKE = 7
OPENALIAS = 8
LNADDR = 9
class PaymentIdentifier(Logger): class PaymentIdentifier(Logger):
""" """
@ -203,7 +214,7 @@ class PaymentIdentifier(Logger):
self.contacts = wallet.contacts if wallet is not None else None self.contacts = wallet.contacts if wallet is not None else None
self.config = wallet.config if wallet is not None else None self.config = wallet.config if wallet is not None else None
self.text = text.strip() self.text = text.strip()
self._type = None self._type = PaymentIdentifierType.UNKNOWN
self.error = None # if set, GUI should show error and stop self.error = None # if set, GUI should show error and stop
self.warning = None # if set, GUI should ask user if they want to proceed self.warning = None # if set, GUI should ask user if they want to proceed
# more than one of those may be set # more than one of those may be set
@ -262,16 +273,16 @@ class PaymentIdentifier(Logger):
return self.is_multiline() and self._is_max return self.is_multiline() and self._is_max
def is_amount_locked(self): def is_amount_locked(self):
if self._type == 'spk': if self._type == PaymentIdentifierType.SPK:
return False return False
elif self._type == 'bip21': elif self._type == PaymentIdentifierType.BIP21:
return bool(self.bip21.get('amount')) return bool(self.bip21.get('amount'))
elif self._type == 'bip70': elif self._type == PaymentIdentifierType.BIP70:
return True # TODO always given? return True # TODO always given?
elif self._type == 'bolt11': elif self._type == PaymentIdentifierType.BOLT11:
lnaddr = lndecode(self.bolt11) lnaddr = lndecode(self.bolt11)
return bool(lnaddr.amount) return bool(lnaddr.amount)
elif self._type == 'lnurl' or self._type == 'lightningaddress': elif self._type in [PaymentIdentifierType.LNURLP, PaymentIdentifierType.LNADDR]:
# amount limits known after resolve, might be specific amount or locked to range # amount limits known after resolve, might be specific amount or locked to range
if self.need_resolve(): if self.need_resolve():
return True return True
@ -279,11 +290,11 @@ class PaymentIdentifier(Logger):
self.logger.debug(f'lnurl f {self.lnurl_data.min_sendable_sat}-{self.lnurl_data.max_sendable_sat}') self.logger.debug(f'lnurl f {self.lnurl_data.min_sendable_sat}-{self.lnurl_data.max_sendable_sat}')
return not (self.lnurl_data.min_sendable_sat < self.lnurl_data.max_sendable_sat) return not (self.lnurl_data.min_sendable_sat < self.lnurl_data.max_sendable_sat)
return True return True
elif self._type == 'multiline': elif self._type == PaymentIdentifierType.MULTILINE:
return True return True
elif self._type == 'emaillike': elif self._type == PaymentIdentifierType.EMAILLIKE:
return False return False
elif self._type == 'openalias': elif self._type == PaymentIdentifierType.OPENALIAS:
return False return False
def is_error(self) -> bool: def is_error(self) -> bool:
@ -298,7 +309,7 @@ class PaymentIdentifier(Logger):
if not text: if not text:
return return
if outputs := self._parse_as_multiline(text): if outputs := self._parse_as_multiline(text):
self._type = 'multiline' self._type = PaymentIdentifierType.MULTILINE
self.multiline_outputs = outputs self.multiline_outputs = outputs
if self.error: if self.error:
self.set_state(PaymentIdentifierState.INVALID) self.set_state(PaymentIdentifierState.INVALID)
@ -306,7 +317,7 @@ class PaymentIdentifier(Logger):
self.set_state(PaymentIdentifierState.AVAILABLE) self.set_state(PaymentIdentifierState.AVAILABLE)
elif invoice_or_lnurl := maybe_extract_lightning_payment_identifier(text): elif invoice_or_lnurl := maybe_extract_lightning_payment_identifier(text):
if invoice_or_lnurl.startswith('lnurl'): if invoice_or_lnurl.startswith('lnurl'):
self._type = 'lnurl' self._type = PaymentIdentifierType.LNURLP
try: try:
self.lnurl = decode_lnurl(invoice_or_lnurl) self.lnurl = decode_lnurl(invoice_or_lnurl)
self.set_state(PaymentIdentifierState.NEED_RESOLVE) self.set_state(PaymentIdentifierState.NEED_RESOLVE)
@ -315,7 +326,7 @@ class PaymentIdentifier(Logger):
self.set_state(PaymentIdentifierState.INVALID) self.set_state(PaymentIdentifierState.INVALID)
return return
else: else:
self._type = 'bolt11' self._type = PaymentIdentifierType.BOLT11
try: try:
lndecode(invoice_or_lnurl) lndecode(invoice_or_lnurl)
except LnInvoiceException as e: except LnInvoiceException as e:
@ -338,10 +349,10 @@ class PaymentIdentifier(Logger):
self.bip21 = out self.bip21 = out
self.bip70 = out.get('r') self.bip70 = out.get('r')
if self.bip70: if self.bip70:
self._type = 'bip70' self._type = PaymentIdentifierType.BIP70
self.set_state(PaymentIdentifierState.NEED_RESOLVE) self.set_state(PaymentIdentifierState.NEED_RESOLVE)
else: else:
self._type = 'bip21' self._type = PaymentIdentifierType.BIP21
# check optional lightning in bip21, set self.bolt11 if valid # check optional lightning in bip21, set self.bolt11 if valid
bolt11 = out.get('lightning') bolt11 = out.get('lightning')
if bolt11: if bolt11:
@ -355,11 +366,11 @@ class PaymentIdentifier(Logger):
self.logger.debug(_("Invoice requires unknown or incompatible Lightning feature") + f":\n{e!r}") self.logger.debug(_("Invoice requires unknown or incompatible Lightning feature") + f":\n{e!r}")
self.set_state(PaymentIdentifierState.AVAILABLE) self.set_state(PaymentIdentifierState.AVAILABLE)
elif scriptpubkey := self.parse_output(text): elif scriptpubkey := self.parse_output(text):
self._type = 'spk' self._type = PaymentIdentifierType.SPK
self.spk = scriptpubkey self.spk = scriptpubkey
self.set_state(PaymentIdentifierState.AVAILABLE) self.set_state(PaymentIdentifierState.AVAILABLE)
elif re.match(RE_EMAIL, text): elif re.match(RE_EMAIL, text):
self._type = 'emaillike' self._type = PaymentIdentifierType.EMAILLIKE
self.emaillike = text self.emaillike = text
self.set_state(PaymentIdentifierState.NEED_RESOLVE) self.set_state(PaymentIdentifierState.NEED_RESOLVE)
elif self.error is None: elif self.error is None:
@ -390,7 +401,7 @@ class PaymentIdentifier(Logger):
'security check, DNSSEC, and thus may not be correct.').format(self.emaillike) 'security check, DNSSEC, and thus may not be correct.').format(self.emaillike)
try: try:
scriptpubkey = self.parse_output(address) scriptpubkey = self.parse_output(address)
self._type = 'openalias' self._type = PaymentIdentifierType.OPENALIAS
self.spk = scriptpubkey self.spk = scriptpubkey
self.set_state(PaymentIdentifierState.AVAILABLE) self.set_state(PaymentIdentifierState.AVAILABLE)
except Exception as e: except Exception as e:
@ -400,7 +411,7 @@ class PaymentIdentifier(Logger):
lnurl = lightning_address_to_url(self.emaillike) lnurl = lightning_address_to_url(self.emaillike)
try: try:
data = await request_lnurl(lnurl) data = await request_lnurl(lnurl)
self._type = 'lightningaddress' self._type = PaymentIdentifierType.LNADDR
self.lnurl = lnurl self.lnurl = lnurl
self.lnurl_data = data self.lnurl_data = data
self.set_state(PaymentIdentifierState.LNURLP_FINALIZE) self.set_state(PaymentIdentifierState.LNURLP_FINALIZE)

3
electrum/x509.py

@ -308,8 +308,7 @@ class X509(object):
raise CertificateError('Certificate has not entered its valid date range. (%s)' % self.get_common_name()) raise CertificateError('Certificate has not entered its valid date range. (%s)' % self.get_common_name())
if self.notAfter <= now: if self.notAfter <= now:
dt = datetime.utcfromtimestamp(time.mktime(self.notAfter)) dt = datetime.utcfromtimestamp(time.mktime(self.notAfter))
# for testnet raise CertificateError(f'Certificate ({self.get_common_name()}) has expired (at {dt} UTC).')
#raise CertificateError(f'Certificate ({self.get_common_name()}) has expired (at {dt} UTC).')
def getFingerprint(self): def getFingerprint(self):
return hashlib.sha1(self.bytes).digest() return hashlib.sha1(self.bytes).digest()

Loading…
Cancel
Save