lnaddr: rename LnAddr -> bolt11
The LnAddr, lndecode and lnencode naming didn't imply that it is bolt 11 specific, making it confusing to work with, now that there are also bolt 12 "lnaddr". Renaming it to *bolt11* creates a clear separation to bolt 12 things and reduces mental load. This commit is pure renaming (using the PyCharm IDE refactor function), except for the removal of the `object` inheritance of LnAddr/BOLT11Addr, this is Python 2 legacy.
This commit is contained in:
+3
-3
@@ -7,7 +7,7 @@ from typing import Optional
|
||||
from . import bitcoin
|
||||
from .util import format_satoshis_plain
|
||||
from .bitcoin import COIN, TOTAL_COIN_SUPPLY_LIMIT_IN_BTC
|
||||
from .lnaddr import lndecode, LnDecodeException
|
||||
from .bolt11 import decode_bolt11_invoice, BOLT11DecodeException
|
||||
|
||||
# note: when checking against these, use .lower() to support case-insensitivity
|
||||
BITCOIN_BIP21_URI_SCHEME = 'bitcoin'
|
||||
@@ -93,8 +93,8 @@ def parse_bip21_URI(uri: str) -> dict:
|
||||
raise InvalidBitcoinURI(f"failed to parse 'sig' field: {repr(e)}") from e
|
||||
if 'lightning' in out:
|
||||
try:
|
||||
lnaddr = lndecode(out['lightning'])
|
||||
except LnDecodeException as e:
|
||||
lnaddr = decode_bolt11_invoice(out['lightning'])
|
||||
except BOLT11DecodeException as e:
|
||||
raise InvalidBitcoinURI(f"Failed to decode 'lightning' field: {e!r}") from e
|
||||
amount_sat = out.get('amount')
|
||||
if amount_sat:
|
||||
|
||||
@@ -23,9 +23,9 @@ if TYPE_CHECKING:
|
||||
from .lnutil import LnFeatures
|
||||
|
||||
|
||||
class LnInvoiceException(Exception): pass
|
||||
class LnDecodeException(LnInvoiceException): pass
|
||||
class LnEncodeException(LnInvoiceException): pass
|
||||
class BOLT11InvoiceException(Exception): pass
|
||||
class BOLT11DecodeException(BOLT11InvoiceException): pass
|
||||
class BOLT11EncodeException(BOLT11InvoiceException): pass
|
||||
|
||||
|
||||
# BOLT #11:
|
||||
@@ -68,7 +68,7 @@ def unshorten_amount(amount) -> Decimal:
|
||||
# A reader SHOULD fail if `amount` contains a non-digit, or is followed by
|
||||
# anything except a `multiplier` in the table above.
|
||||
if not re.fullmatch("\\d+[pnum]?", str(amount)):
|
||||
raise LnDecodeException("Invalid amount '{}'".format(amount))
|
||||
raise BOLT11DecodeException("Invalid amount '{}'".format(amount))
|
||||
|
||||
if unit in units.keys():
|
||||
return Decimal(amount[:-1]) / units[unit]
|
||||
@@ -88,7 +88,7 @@ def encode_fallback_addr(fallback: str, net: Type[AbstractNet]) -> Sequence[int]
|
||||
elif addrtype == net.ADDRTYPE_P2SH:
|
||||
wver = 18
|
||||
else:
|
||||
raise LnEncodeException(f"Unknown address type {addrtype} for {net}")
|
||||
raise BOLT11EncodeException(f"Unknown address type {addrtype} for {net}")
|
||||
wprog = addr
|
||||
data5 = convertbits(wprog, 8, 5)
|
||||
assert data5 is not None
|
||||
@@ -156,7 +156,7 @@ def pull_tagged(data5: bytearray) -> Tuple[str, Sequence[int]]:
|
||||
return ret
|
||||
|
||||
|
||||
def lnencode(addr: 'LnAddr', privkey) -> str:
|
||||
def encode_bolt11_invoice(addr: 'BOLT11Addr', privkey) -> str:
|
||||
if addr.amount:
|
||||
amount = addr.net.BOLT11_HRP + shorten_amount(addr.amount)
|
||||
else:
|
||||
@@ -185,7 +185,7 @@ def lnencode(addr: 'LnAddr', privkey) -> str:
|
||||
# A writer MUST NOT include more than one `d`, `h`, `n` or `x` fields,
|
||||
if k in ('d', 'h', 'n', 'x', 'p', 's', '9'):
|
||||
if k in tags_set:
|
||||
raise LnEncodeException("Duplicate '{}' tag".format(k))
|
||||
raise BOLT11EncodeException("Duplicate '{}' tag".format(k))
|
||||
|
||||
if k == 'r':
|
||||
route = bytearray()
|
||||
@@ -228,7 +228,7 @@ def lnencode(addr: 'LnAddr', privkey) -> str:
|
||||
data5 += tagged5('9', feature_bits)
|
||||
else:
|
||||
# FIXME: Support unknown tags?
|
||||
raise LnEncodeException("Unknown tag {}".format(k))
|
||||
raise BOLT11EncodeException("Unknown tag {}".format(k))
|
||||
|
||||
tags_set.add(k)
|
||||
|
||||
@@ -254,7 +254,7 @@ def lnencode(addr: 'LnAddr', privkey) -> str:
|
||||
return bech32_encode(segwit_addr.Encoding.BECH32, hrp, data5)
|
||||
|
||||
|
||||
class LnAddr(object):
|
||||
class BOLT11Addr:
|
||||
def __init__(self, *, paymenthash: bytes = None, amount=None, net: Type[AbstractNet] = None, tags=None, date=None,
|
||||
payment_secret: bytes = None):
|
||||
self.date = int(time.time()) if not date else int(date)
|
||||
@@ -274,16 +274,16 @@ class LnAddr(object):
|
||||
@amount.setter
|
||||
def amount(self, value):
|
||||
if not (isinstance(value, Decimal) or value is None):
|
||||
raise LnInvoiceException(f"amount must be Decimal or None, not {value!r}")
|
||||
raise BOLT11InvoiceException(f"amount must be Decimal or None, not {value!r}")
|
||||
if value is None:
|
||||
self._amount = None
|
||||
return
|
||||
assert isinstance(value, Decimal)
|
||||
if value.is_nan() or not (0 <= value <= TOTAL_COIN_SUPPLY_LIMIT_IN_BTC):
|
||||
raise LnInvoiceException(f"amount is out-of-bounds: {value!r} BTC")
|
||||
raise BOLT11InvoiceException(f"amount is out-of-bounds: {value!r} BTC")
|
||||
if value * 10**12 % 10:
|
||||
# max resolution is millisatoshi
|
||||
raise LnInvoiceException(f"Cannot encode {value!r}: too many decimal places")
|
||||
raise BOLT11InvoiceException(f"Cannot encode {value!r}: too many decimal places")
|
||||
self._amount = value
|
||||
|
||||
def get_amount_sat(self) -> Optional[Decimal]:
|
||||
@@ -341,7 +341,7 @@ class LnAddr(object):
|
||||
ln_compare_features(myfeatures.for_invoice(), invoice_features)
|
||||
|
||||
def __str__(self):
|
||||
return "LnAddr[{}, amount={}{} tags=[{}]]".format(
|
||||
return "BOLT11Addr[{}, amount={}{} tags=[{}]]".format(
|
||||
hexlify(self.pubkey.serialize()).decode('utf-8') if self.pubkey else None,
|
||||
self.amount, self.net.BOLT11_HRP,
|
||||
", ".join([k + '=' + str(v) for k, v in self.tags])
|
||||
@@ -403,7 +403,7 @@ class SerializableKey:
|
||||
return self.pubkey.get_public_key_bytes(True)
|
||||
|
||||
|
||||
def lndecode(invoice: str, *, verbose=False, net=None) -> LnAddr:
|
||||
def decode_bolt11_invoice(invoice: str, *, verbose=False, net=None) -> BOLT11Addr:
|
||||
"""Parses a string into an LnAddr object.
|
||||
Can raise LnDecodeException or IncompatibleOrInsaneFeatures.
|
||||
"""
|
||||
@@ -413,27 +413,27 @@ def lndecode(invoice: str, *, verbose=False, net=None) -> LnAddr:
|
||||
hrp = decoded_bech32.hrp
|
||||
data5 = decoded_bech32.data # "5" as in list of 5-bit integers
|
||||
if decoded_bech32.encoding is None:
|
||||
raise LnDecodeException("Bad bech32 checksum")
|
||||
raise BOLT11DecodeException("Bad bech32 checksum")
|
||||
if decoded_bech32.encoding != segwit_addr.Encoding.BECH32:
|
||||
raise LnDecodeException("Bad bech32 encoding: must be using vanilla BECH32")
|
||||
raise BOLT11DecodeException("Bad bech32 encoding: must be using vanilla BECH32")
|
||||
|
||||
# BOLT #11:
|
||||
#
|
||||
# A reader MUST fail if it does not understand the `prefix`.
|
||||
if not hrp.startswith('ln'):
|
||||
raise LnDecodeException("Does not start with ln")
|
||||
raise BOLT11DecodeException("Does not start with ln")
|
||||
|
||||
if not hrp[2:].startswith(net.BOLT11_HRP):
|
||||
raise LnDecodeException(f"Wrong Lightning invoice HRP {hrp[2:]}, should be {net.BOLT11_HRP}")
|
||||
raise BOLT11DecodeException(f"Wrong Lightning invoice HRP {hrp[2:]}, should be {net.BOLT11_HRP}")
|
||||
|
||||
# Final signature 65 bytes, split it off.
|
||||
if len(data5) < 65*8//5:
|
||||
raise LnDecodeException("Too short to contain signature")
|
||||
raise BOLT11DecodeException("Too short to contain signature")
|
||||
sigdecoded = bytes(convertbits(data5[-65*8//5:], 5, 8, False))
|
||||
data5 = data5[:-65*8//5]
|
||||
data5_remaining = bytearray(data5) # note: bytearray is faster than list of ints
|
||||
|
||||
addr = LnAddr()
|
||||
addr = BOLT11Addr()
|
||||
addr.pubkey = None
|
||||
addr.net = net
|
||||
|
||||
@@ -580,7 +580,7 @@ def lndecode(invoice: str, *, verbose=False, net=None) -> LnAddr:
|
||||
# A reader MUST use the `n` field to validate the signature instead of
|
||||
# performing signature recovery if a valid `n` field is provided.
|
||||
if not ecc.ECPubkey(addr.pubkey).ecdsa_verify(sigdecoded[:64], hrp_hash):
|
||||
raise LnDecodeException("bad signature")
|
||||
raise BOLT11DecodeException("bad signature")
|
||||
pubkey_copy = addr.pubkey
|
||||
|
||||
class WrappedBytesKey:
|
||||
@@ -10,7 +10,7 @@ from electrum.i18n import _
|
||||
from electrum.util import format_time
|
||||
from electrum.lnutil import format_short_channel_id, LOCAL, REMOTE, UpdateAddHtlc, Direction
|
||||
from electrum.lnchannel import htlcsum, Channel, AbstractChannel, HTLCWithStatus
|
||||
from electrum.lnaddr import LnAddr, lndecode
|
||||
from electrum.bolt11 import BOLT11Addr, decode_bolt11_invoice
|
||||
from electrum.bitcoin import COIN
|
||||
from electrum.wallet import Abstract_Wallet
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ from electrum.exchange_rate import FxThread
|
||||
from electrum.simple_config import SimpleConfig
|
||||
from electrum.logging import Logger
|
||||
from electrum.lntransport import extract_nodeid, ConnStringFormatError
|
||||
from electrum.lnaddr import lndecode, LnAddr
|
||||
from electrum.bolt11 import decode_bolt11_invoice, BOLT11Addr
|
||||
from electrum.submarine_swaps import SwapServerTransport, NostrTransport
|
||||
from electrum.fee_policy import FeePolicy
|
||||
|
||||
@@ -1678,7 +1678,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger, QtEventListener):
|
||||
|
||||
def show_lightning_invoice(self, invoice: Invoice):
|
||||
from electrum.util import format_short_id
|
||||
lnaddr = lndecode(invoice.lightning_invoice)
|
||||
lnaddr = decode_bolt11_invoice(invoice.lightning_invoice)
|
||||
d = WindowModalDialog(self, _("Lightning Invoice"))
|
||||
vbox = QVBoxLayout(d)
|
||||
grid = QGridLayout()
|
||||
@@ -1713,7 +1713,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger, QtEventListener):
|
||||
grid.addWidget(QLabel(_('Text') + ':'), 8, 0)
|
||||
grid.addWidget(invoice_e, 8, 1)
|
||||
r_tags = lnaddr.get_routing_info('r')
|
||||
r_tags = '\n'.join(repr(r) for r in LnAddr.format_bolt11_routing_info_as_human_readable(r_tags))
|
||||
r_tags = '\n'.join(repr(r) for r in BOLT11Addr.format_bolt11_routing_info_as_human_readable(r_tags))
|
||||
routing_e = QTextEdit(str(r_tags))
|
||||
routing_e.setReadOnly(True)
|
||||
grid.addWidget(QLabel(_("Routing Hints") + ':'), 9, 0)
|
||||
|
||||
@@ -50,9 +50,9 @@ def parse_bip21(text):
|
||||
|
||||
|
||||
def parse_bolt11(text):
|
||||
from electrum.lnaddr import lndecode
|
||||
from electrum.bolt11 import decode_bolt11_invoice
|
||||
try:
|
||||
return lndecode(text)
|
||||
return decode_bolt11_invoice(text)
|
||||
except Exception:
|
||||
return
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ from .i18n import _
|
||||
from .util import age, InvoiceError, format_satoshis
|
||||
from .bip21 import create_bip21_uri
|
||||
from .lnutil import hex_to_bytes
|
||||
from .lnaddr import lndecode, LnAddr
|
||||
from .bolt11 import decode_bolt11_invoice, BOLT11Addr
|
||||
from . import constants
|
||||
from .bitcoin import COIN, TOTAL_COIN_SUPPLY_LIMIT_IN_BTC
|
||||
from .bitcoin import address_to_script
|
||||
@@ -213,7 +213,7 @@ class BaseInvoice(StoredObject):
|
||||
Might raise InvoiceError.
|
||||
"""
|
||||
try:
|
||||
lnaddr = lndecode(invoice)
|
||||
lnaddr = decode_bolt11_invoice(invoice)
|
||||
except Exception as e:
|
||||
raise InvoiceError(e) from e
|
||||
amount_msat = lnaddr.get_amount_msat()
|
||||
@@ -275,9 +275,9 @@ class Invoice(BaseInvoice):
|
||||
return address
|
||||
|
||||
@property
|
||||
def _lnaddr(self) -> LnAddr:
|
||||
def _lnaddr(self) -> BOLT11Addr:
|
||||
if self.__lnaddr is None:
|
||||
self.__lnaddr = lndecode(self.lightning_invoice)
|
||||
self.__lnaddr = decode_bolt11_invoice(self.lightning_invoice)
|
||||
return self.__lnaddr
|
||||
|
||||
@property
|
||||
@@ -288,7 +288,7 @@ class Invoice(BaseInvoice):
|
||||
@lightning_invoice.validator
|
||||
def _validate_invoice_str(self, attribute, value):
|
||||
if value is not None:
|
||||
lnaddr = lndecode(value) # this checks the str can be decoded
|
||||
lnaddr = decode_bolt11_invoice(value) # this checks the str can be decoded
|
||||
self.__lnaddr = lnaddr # save it, just to avoid having to recompute later
|
||||
|
||||
def can_be_paid_onchain(self) -> bool:
|
||||
|
||||
+5
-5
@@ -12,7 +12,7 @@ import aiohttp.client_exceptions
|
||||
|
||||
from electrum import segwit_addr, util
|
||||
from electrum.segwit_addr import bech32_decode, Encoding, convertbits, bech32_encode
|
||||
from electrum.lnaddr import LnDecodeException, LnEncodeException
|
||||
from electrum.bolt11 import BOLT11DecodeException, BOLT11EncodeException
|
||||
from electrum.network import Network
|
||||
from electrum.logging import get_logger
|
||||
from electrum.i18n import _
|
||||
@@ -47,11 +47,11 @@ def decode_lnurl(lnurl: str) -> str:
|
||||
hrp = decoded_bech32.hrp
|
||||
data = decoded_bech32.data
|
||||
if decoded_bech32.encoding is None:
|
||||
raise LnDecodeException("Bad bech32 checksum")
|
||||
raise BOLT11DecodeException("Bad bech32 checksum")
|
||||
if decoded_bech32.encoding != Encoding.BECH32:
|
||||
raise LnDecodeException("Bad bech32 encoding: must be using vanilla BECH32")
|
||||
raise BOLT11DecodeException("Bad bech32 encoding: must be using vanilla BECH32")
|
||||
if not hrp.startswith("lnurl"):
|
||||
raise LnDecodeException("Does not start with lnurl")
|
||||
raise BOLT11DecodeException("Does not start with lnurl")
|
||||
data = convertbits(data, 5, 8, False)
|
||||
url = bytes(data).decode("utf-8")
|
||||
return url
|
||||
@@ -62,7 +62,7 @@ def encode_lnurl(url: str) -> str:
|
||||
try:
|
||||
url = url.encode("utf-8")
|
||||
except UnicodeError as e:
|
||||
raise LnEncodeException("invalid url") from e
|
||||
raise BOLT11EncodeException("invalid url") from e
|
||||
bech32_data = convertbits(url, 8, 5, True)
|
||||
assert bech32_data
|
||||
lnurl = bech32_encode(
|
||||
|
||||
+10
-10
@@ -64,7 +64,7 @@ from .lntransport import (
|
||||
ConnStringFormatError
|
||||
)
|
||||
from .lnpeer import Peer, LN_P2P_NETWORK_TIMEOUT
|
||||
from .lnaddr import lnencode, LnAddr, lndecode
|
||||
from .bolt11 import encode_bolt11_invoice, BOLT11Addr, decode_bolt11_invoice
|
||||
from .lnchannel import Channel, AbstractChannel, ChannelState, PeerState, HTLCWithStatus, ChannelBackup
|
||||
from .lnrater import LNRater
|
||||
from .lnutil import (
|
||||
@@ -123,7 +123,7 @@ class PaymentInfo:
|
||||
|
||||
- Historically, we used to store "bolt11, direction, status", but deserializing bolt11 was too slow.
|
||||
(even deserializing just once - all bolt11 during wallet-open - was slow)
|
||||
- note: the deserialization code in lnaddr.py has been significantly sped up since
|
||||
- note: the deserialization code in bolt11.py has been significantly sped up since
|
||||
- For incoming payments, for unpaid requests, ~every time the user displays the unpaid bolt11,
|
||||
we get a chance to display a new bolt11, with same payment_hash/amount, but with updated
|
||||
routing_hints (channels might get closed/opened, or just liquidity changed drastically).
|
||||
@@ -1930,7 +1930,7 @@ class LNWallet(Logger):
|
||||
f"pay_to_node starting session for RHASH={payment_hash.hex()}. "
|
||||
f"using_trampoline={self.uses_trampoline()}. "
|
||||
f"invoice_features={paysession.invoice_features.get_names()}. "
|
||||
f"r_tags={LnAddr.format_bolt11_routing_info_as_human_readable(r_tags)}. "
|
||||
f"r_tags={BOLT11Addr.format_bolt11_routing_info_as_human_readable(r_tags)}. "
|
||||
f"{amount_to_pay=} msat. {budget=}")
|
||||
if not self.uses_trampoline():
|
||||
self.logger.info(
|
||||
@@ -2219,11 +2219,11 @@ class LNWallet(Logger):
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
def _check_bolt11_invoice(self, bolt11_invoice: str, *, amount_msat: int = None) -> LnAddr:
|
||||
def _check_bolt11_invoice(self, bolt11_invoice: str, *, amount_msat: int = None) -> BOLT11Addr:
|
||||
"""Parses and validates a bolt11 invoice str into a LnAddr.
|
||||
Includes pre-payment checks external to the parser.
|
||||
"""
|
||||
addr = lndecode(bolt11_invoice)
|
||||
addr = decode_bolt11_invoice(bolt11_invoice)
|
||||
if addr.is_expired():
|
||||
raise InvoiceError(_("This invoice has expired"))
|
||||
# check amount
|
||||
@@ -2563,7 +2563,7 @@ class LNWallet(Logger):
|
||||
message: str,
|
||||
fallback_address: Optional[str],
|
||||
channels: Optional[Sequence[Channel]] = None,
|
||||
) -> Tuple[LnAddr, str]:
|
||||
) -> Tuple[BOLT11Addr, str]:
|
||||
amount_msat = payment_info.amount_msat
|
||||
pair = self._bolt11_cache.get(payment_info.payment_hash)
|
||||
if pair:
|
||||
@@ -2580,12 +2580,12 @@ class LNWallet(Logger):
|
||||
# TODO: make invoice_features dynamic depending on available trampoline channels
|
||||
only_trampoline=payment_info.invoice_features.supports(LnFeatures.OPTION_TRAMPOLINE_ROUTING_OPT_ELECTRUM),
|
||||
)
|
||||
formatted_r_hints = LnAddr.format_bolt11_routing_info_as_human_readable(routing_hints, has_explicit_r_tagtype=True)
|
||||
formatted_r_hints = BOLT11Addr.format_bolt11_routing_info_as_human_readable(routing_hints, has_explicit_r_tagtype=True)
|
||||
self.logger.info(f"creating bolt11 invoice with routing_hints: {formatted_r_hints}, sat: {(amount_msat or 0) // 1000}")
|
||||
payment_secret = self.get_payment_secret(payment_info.payment_hash)
|
||||
amount_btc = amount_msat/Decimal(COIN*1000) if amount_msat else None
|
||||
min_final_cltv_delta = payment_info.min_final_cltv_delta + MIN_FINAL_CLTV_DELTA_BUFFER_INVOICE
|
||||
lnaddr = LnAddr(
|
||||
lnaddr = BOLT11Addr(
|
||||
paymenthash=payment_info.payment_hash,
|
||||
amount=amount_btc,
|
||||
tags=[
|
||||
@@ -2597,7 +2597,7 @@ class LNWallet(Logger):
|
||||
] + routing_hints,
|
||||
date=timestamp,
|
||||
payment_secret=payment_secret)
|
||||
invoice = lnencode(lnaddr, self.node_keypair.privkey)
|
||||
invoice = encode_bolt11_invoice(lnaddr, self.node_keypair.privkey)
|
||||
pair = lnaddr, invoice
|
||||
self._bolt11_cache[payment_info.payment_hash] = pair
|
||||
return pair
|
||||
@@ -3971,7 +3971,7 @@ class LNWallet(Logger):
|
||||
invoice_features = payload["invoice_features"]["invoice_features"]
|
||||
invoice_routing_info = payload["invoice_routing_info"]["invoice_routing_info"]
|
||||
r_tags = decode_routing_info(invoice_routing_info)
|
||||
self.logger.info(f'r_tags {LnAddr.format_bolt11_routing_info_as_human_readable(r_tags)}')
|
||||
self.logger.info(f'r_tags {BOLT11Addr.format_bolt11_routing_info_as_human_readable(r_tags)}')
|
||||
# TODO legacy mpp payment, use total_msat from trampoline onion
|
||||
else:
|
||||
self.logger.info('forward_trampoline: end-to-end')
|
||||
|
||||
@@ -18,7 +18,7 @@ from .lnurl import (decode_lnurl, request_lnurl, callback_lnurl, LNURLError,
|
||||
lightning_address_to_url, try_resolve_lnurlpay, LNURL6Data,
|
||||
LNURL3Data, LNURLData, SUPPORTED_LNURL_SCHEMES)
|
||||
from .bitcoin import opcodes, construct_script
|
||||
from .lnaddr import LnInvoiceException
|
||||
from .bolt11 import BOLT11InvoiceException
|
||||
from .lnutil import IncompatibleOrInsaneFeatures
|
||||
from .bip21 import parse_bip21_URI, InvalidBitcoinURI, LIGHTNING_URI_SCHEME, BITCOIN_BIP21_URI_SCHEME
|
||||
from .segwit_addr import bech32_decode
|
||||
@@ -520,7 +520,7 @@ class PaymentIdentifier(Logger):
|
||||
error = _("Error parsing Lightning invoice") + f":\n{e!r}"
|
||||
if e.args and len(e.args):
|
||||
arg = e.args[0]
|
||||
if isinstance(arg, LnInvoiceException):
|
||||
if isinstance(arg, BOLT11InvoiceException):
|
||||
error = _("Error parsing Lightning invoice") + f":\n{e}"
|
||||
elif isinstance(arg, IncompatibleOrInsaneFeatures):
|
||||
error = _("Invoice requires unknown or incompatible Lightning feature") + f":\n{e!r}"
|
||||
|
||||
@@ -8,7 +8,7 @@ from aiohttp import web
|
||||
from electrum.util import log_exceptions, ignore_exceptions
|
||||
from electrum.logging import Logger
|
||||
from electrum.util import EventListener
|
||||
from electrum.lnaddr import lndecode
|
||||
from electrum.bolt11 import decode_bolt11_invoice
|
||||
from electrum.daemon import AuthenticatedServer
|
||||
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ from .util import (
|
||||
)
|
||||
from . import lnutil
|
||||
from .lnutil import hex_to_bytes, REDEEM_AFTER_DOUBLE_SPENT_DELAY, Keypair
|
||||
from .lnaddr import lndecode
|
||||
from .bolt11 import decode_bolt11_invoice
|
||||
from .json_db import StoredObject, stored_in
|
||||
from . import constants
|
||||
from .address_synchronizer import (TX_HEIGHT_LOCAL, TX_HEIGHT_FUTURE, TX_HEIGHT_UNCONFIRMED,
|
||||
@@ -997,7 +997,7 @@ class SwapManager(Logger):
|
||||
}
|
||||
await transport.send_request_to_server('addswapinvoice', request_data)
|
||||
# wait for funding tx
|
||||
lnaddr = lndecode(invoice)
|
||||
lnaddr = decode_bolt11_invoice(invoice)
|
||||
while swap.funding_txid is None and not lnaddr.is_expired():
|
||||
await asyncio.sleep(0.1)
|
||||
return swap.funding_txid
|
||||
|
||||
@@ -905,7 +905,7 @@ class WalletDBUpgrader(Logger):
|
||||
self.data['seed_version'] = 44
|
||||
|
||||
def _convert_version_45(self):
|
||||
from .lnaddr import lndecode
|
||||
from .bolt11 import decode_bolt11_invoice
|
||||
if not self._is_upgrade_method_needed(44, 44):
|
||||
return
|
||||
swaps = self.data.get('submarine_swaps', {})
|
||||
@@ -921,7 +921,7 @@ class WalletDBUpgrader(Logger):
|
||||
outputs = item['outputs'] if not is_lightning else None
|
||||
bip70 = item['bip70'] if not is_lightning else None
|
||||
if is_lightning:
|
||||
lnaddr = lndecode(item['invoice'])
|
||||
lnaddr = decode_bolt11_invoice(item['invoice'])
|
||||
amount_msat = lnaddr.get_amount_msat()
|
||||
timestamp = lnaddr.date
|
||||
exp_delay = lnaddr.get_expiry()
|
||||
@@ -974,7 +974,7 @@ class WalletDBUpgrader(Logger):
|
||||
self.data['seed_version'] = 46
|
||||
|
||||
def _convert_version_47(self):
|
||||
from .lnaddr import lndecode
|
||||
from .bolt11 import decode_bolt11_invoice
|
||||
if not self._is_upgrade_method_needed(46, 46):
|
||||
return
|
||||
# recalc keys of requests
|
||||
@@ -982,7 +982,7 @@ class WalletDBUpgrader(Logger):
|
||||
for key, item in list(requests.items()):
|
||||
lnaddr = item.get('lightning_invoice')
|
||||
if lnaddr:
|
||||
lnaddr = lndecode(lnaddr)
|
||||
lnaddr = decode_bolt11_invoice(lnaddr)
|
||||
rhash = lnaddr.paymenthash.hex()
|
||||
if key != rhash:
|
||||
requests[rhash] = item
|
||||
@@ -1023,7 +1023,7 @@ class WalletDBUpgrader(Logger):
|
||||
self.data['seed_version'] = 50
|
||||
|
||||
def _convert_version_51(self):
|
||||
from .lnaddr import lndecode
|
||||
from .bolt11 import decode_bolt11_invoice
|
||||
if not self._is_upgrade_method_needed(50, 50):
|
||||
return
|
||||
requests = self.data.get('payment_requests', {})
|
||||
@@ -1032,7 +1032,7 @@ class WalletDBUpgrader(Logger):
|
||||
if lightning_invoice is None:
|
||||
payment_hash = None
|
||||
else:
|
||||
lnaddr = lndecode(lightning_invoice)
|
||||
lnaddr = decode_bolt11_invoice(lightning_invoice)
|
||||
payment_hash = lnaddr.paymenthash.hex()
|
||||
item['payment_hash'] = payment_hash
|
||||
self.data['seed_version'] = 51
|
||||
|
||||
+37
-37
@@ -4,7 +4,7 @@ from binascii import unhexlify, hexlify
|
||||
import pprint
|
||||
import unittest
|
||||
|
||||
from electrum.lnaddr import shorten_amount, unshorten_amount, LnAddr, lnencode, lndecode
|
||||
from electrum.bolt11 import shorten_amount, unshorten_amount, BOLT11Addr, encode_bolt11_invoice, decode_bolt11_invoice
|
||||
from electrum.segwit_addr import bech32_encode, bech32_decode
|
||||
from electrum import segwit_addr
|
||||
from electrum.lnutil import UnknownEvenFeatureBits, LnFeatures, IncompatibleLightningFeatures
|
||||
@@ -67,106 +67,106 @@ class TestBolt11(ElectrumTestCase):
|
||||
|
||||
timestamp = 1615922274
|
||||
tests = [
|
||||
(LnAddr(date=timestamp, paymenthash=RHASH, payment_secret=PAYMENT_SECRET, tags=[('d', ''), ('9', 33282)]),
|
||||
(BOLT11Addr(date=timestamp, paymenthash=RHASH, payment_secret=PAYMENT_SECRET, tags=[('d', ''), ('9', 33282)]),
|
||||
"lnbc1ps9zprzpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygsdqq9qypqszpyrpe4tym8d3q87d43cgdhhlsrt78epu7u99mkzttmt2wtsx0304rrw50addkryfrd3vn3zy467vxwlmf4uz7yvntuwjr2hqjl9lw5cqwtp2dy"),
|
||||
(LnAddr(date=timestamp, paymenthash=RHASH, payment_secret=PAYMENT_SECRET, amount=Decimal('0.001'), tags=[('d', '1 cup coffee'), ('x', 60), ('9', 0x28200)]),
|
||||
(BOLT11Addr(date=timestamp, paymenthash=RHASH, payment_secret=PAYMENT_SECRET, amount=Decimal('0.001'), tags=[('d', '1 cup coffee'), ('x', 60), ('9', 0x28200)]),
|
||||
"lnbc1m1ps9zprzpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygsdq5xysxxatsyp3k7enxv4jsxqzpu9qy9qsqw8l2pulslacwjt86vle3sgfdmcct5v34gtcpfnujsf6ufqa7v7jzdpddnwgte82wkscdlwfwucrgn8z36rv9hzk5mukltteh0yqephqpk5vegu"),
|
||||
(LnAddr(date=timestamp, paymenthash=RHASH, payment_secret=PAYMENT_SECRET, amount=Decimal('1'), tags=[('h', longdescription), ('9', 0x28200)]),
|
||||
(BOLT11Addr(date=timestamp, paymenthash=RHASH, payment_secret=PAYMENT_SECRET, amount=Decimal('1'), tags=[('h', longdescription), ('9', 0x28200)]),
|
||||
"lnbc11ps9zprzpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygshp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqs9qy9qsq0jnua6dc4p984aeafs6ss7tjjj7553ympvg82qrjq0zgdqgtdvt5wlwkvw4ds5sn96nazp6ct9ts37tcw708kzkk4p8znahpsgp9tnspnycsf7"),
|
||||
(LnAddr(date=timestamp, paymenthash=RHASH, payment_secret=PAYMENT_SECRET, net=constants.BitcoinTestnet, tags=[('f', 'mk2QpYatsKicvFVuTAQLBryyccRXMUaGHP'), ('h', longdescription), ('9', 0x28200)]),
|
||||
(BOLT11Addr(date=timestamp, paymenthash=RHASH, payment_secret=PAYMENT_SECRET, net=constants.BitcoinTestnet, tags=[('f', 'mk2QpYatsKicvFVuTAQLBryyccRXMUaGHP'), ('h', longdescription), ('9', 0x28200)]),
|
||||
"lntb1ps9zprzpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygsfpp3x9et2e20v6pu37c5d9vax37wxq72un98hp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqs9qy9qsqy5826t0z3sn29z396pmr4kv73lcx0v7y6vas6h3pysmqllmzwgm5ps2t468gm4psj52usjy6y4xcry4k84n2zggs6f9agwg95454v6gqrwmh4f"),
|
||||
(LnAddr(date=timestamp, paymenthash=RHASH, payment_secret=PAYMENT_SECRET, amount=24, tags=[
|
||||
(BOLT11Addr(date=timestamp, paymenthash=RHASH, payment_secret=PAYMENT_SECRET, amount=24, tags=[
|
||||
('r', [(unhexlify('029e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255'), unhexlify('0102030405060708'), 1, 20, 3),
|
||||
(unhexlify('039e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255'), unhexlify('030405060708090a'), 2, 30, 4)]),
|
||||
('f', '1RustyRX2oai4EYYDpQGWvEL62BBGqN9T'),
|
||||
('h', longdescription),
|
||||
('9', 0x28200)]),
|
||||
"lnbc241ps9zprzpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygsr9yq20q82gphp2nflc7jtzrcazrra7wwgzxqc8u7754cdlpfrmccae92qgzqvzq2ps8pqqqqqqpqqqqq9qqqvpeuqafqxu92d8lr6fvg0r5gv0heeeqgcrqlnm6jhphu9y00rrhy4grqszsvpcgpy9qqqqqqgqqqqq7qqzqfpp3qjmp7lwpagxun9pygexvgpjdc4jdj85fhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqs9qy9qsqfnk063vsrgjx7l6td6v42skuxql7epn5tmrl4qte2e78nqnsjlgjg3sgkxreqex5fw4c9chnvtc2hykqnyxr84zwfr8f3d9q3h0nfdgqenlzvj"),
|
||||
(LnAddr(date=timestamp, paymenthash=RHASH, payment_secret=PAYMENT_SECRET, amount=24, tags=[('f', '3EktnHQD7RiAE6uzMj2ZifT9YgRrkSgzQX'), ('h', longdescription), ('9', 0x28200)]),
|
||||
(BOLT11Addr(date=timestamp, paymenthash=RHASH, payment_secret=PAYMENT_SECRET, amount=24, tags=[('f', '3EktnHQD7RiAE6uzMj2ZifT9YgRrkSgzQX'), ('h', longdescription), ('9', 0x28200)]),
|
||||
"lnbc241ps9zprzpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygsfppj3a24vwu6r8ejrss3axul8rxldph2q7z9hp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqs9qy9qsqqf6z4r7ruzr5txm5ln4netwa2f4x233tud7jy8gxrynyx07rxt7qm92yk2krlgwr7d8jknglur75sujeyapmda5nf3femrk2mep8a2cp4hlvup"),
|
||||
(LnAddr(date=timestamp, paymenthash=RHASH, payment_secret=PAYMENT_SECRET, amount=24, tags=[('f', 'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4'), ('h', longdescription), ('9', 0x28200)]),
|
||||
(BOLT11Addr(date=timestamp, paymenthash=RHASH, payment_secret=PAYMENT_SECRET, amount=24, tags=[('f', 'bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t4'), ('h', longdescription), ('9', 0x28200)]),
|
||||
"lnbc241ps9zprzpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygsfppqw508d6qejxtdg4y5r3zarvary0c5xw7khp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqs9qy9qsqy4wp73jma5uktd9y7yha56f98n2k0hxgnvp2qdcury00dapps3k3urgfy8tvv8jzwcafpy576msk5xx2hladf06m3s5mgx5msn4elfqqaaqjhk"),
|
||||
(LnAddr(date=timestamp, paymenthash=RHASH, payment_secret=PAYMENT_SECRET, amount=24, tags=[('f', 'bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3'), ('h', longdescription), ('9', 0x28200)]),
|
||||
(BOLT11Addr(date=timestamp, paymenthash=RHASH, payment_secret=PAYMENT_SECRET, amount=24, tags=[('f', 'bc1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qccfmv3'), ('h', longdescription), ('9', 0x28200)]),
|
||||
"lnbc241ps9zprzpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygsfp4qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3qhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqs9qy9qsqgt4gg9uktlpgnnuvczazusp5uwjv78na305ucsw06c8uk58e5stjqj9sz7fgavw0z688alt364js72mc9mg8yumhpes2dsmq5k9nr5qqddykxy"),
|
||||
(LnAddr(date=timestamp, paymenthash=RHASH, payment_secret=PAYMENT_SECRET, amount=24, tags=[('n', PUBKEY), ('h', longdescription), ('9', 0x28200)]),
|
||||
(BOLT11Addr(date=timestamp, paymenthash=RHASH, payment_secret=PAYMENT_SECRET, amount=24, tags=[('n', PUBKEY), ('h', longdescription), ('9', 0x28200)]),
|
||||
"lnbc241ps9zprzpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygsnp4q0n326hr8v9zprg8gsvezcch06gfaqqhde2aj730yg0durunfhv66hp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqs9qy9qsq2y235rxw7v0gkn2t9ehc742tm3p22q2yjjykq4d85ze6g62yk60navxqz0ga96sqrszju8nlfajthem4gngxvyz4hwy39j4nqm8kv0qq9znxs7"),
|
||||
(LnAddr(date=timestamp, paymenthash=RHASH, payment_secret=PAYMENT_SECRET, amount=24, tags=[('h', longdescription), ('9', 2 + (1 << 9) + (1 << 15))]),
|
||||
(BOLT11Addr(date=timestamp, paymenthash=RHASH, payment_secret=PAYMENT_SECRET, amount=24, tags=[('h', longdescription), ('9', 2 + (1 << 9) + (1 << 15))]),
|
||||
"lnbc241ps9zprzpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygshp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqs9qypqszrwfgrl5k3rt4q4mclc8t00p2tcjsf9pmpcq6lu5zhmampyvk43fk30eqpdm8t5qmdpzan25aqxqaqdzmy0smrtduazjcxx975vz78ccpx0qhev"),
|
||||
(LnAddr(date=timestamp, paymenthash=RHASH, payment_secret=PAYMENT_SECRET, amount=24, tags=[('h', longdescription), ('9', 10 + (1 << 8) + (1 << 15))]),
|
||||
(BOLT11Addr(date=timestamp, paymenthash=RHASH, payment_secret=PAYMENT_SECRET, amount=24, tags=[('h', longdescription), ('9', 10 + (1 << 8) + (1 << 15))]),
|
||||
"lnbc241ps9zprzpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygshp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqs9qypqg2wans8f6vkfd3l7zjv547hlc7wd7eqyxfwhtdudnkkgrpk6p9ffykwrvdtwm0aakaxujurdxgd7cllnfypmj22cvy7z333udg6zncgacqzmd2z9"),
|
||||
(LnAddr(date=timestamp, paymenthash=RHASH, payment_secret=PAYMENT_SECRET, amount=24, tags=[('h', longdescription), ('9', 10 + (1 << 9) + (1 << 15))]),
|
||||
(BOLT11Addr(date=timestamp, paymenthash=RHASH, payment_secret=PAYMENT_SECRET, amount=24, tags=[('h', longdescription), ('9', 10 + (1 << 9) + (1 << 15))]),
|
||||
"lnbc241ps9zprzpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygshp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqs9qypqs2dr525u5f4kjxdv0hq5c822qwxrtttjl4u586yl84x0kvvx66gz9ygy76005s5sjwgr7fp55ccsae47vpl4gqvwhc3exps964g743j5gqwtt68t"),
|
||||
(LnAddr(date=timestamp, paymenthash=RHASH, payment_secret=PAYMENT_SECRET, amount=24, tags=[('h', longdescription), ('9', 10 + (1 << 9) + (1 << 14))]),
|
||||
(BOLT11Addr(date=timestamp, paymenthash=RHASH, payment_secret=PAYMENT_SECRET, amount=24, tags=[('h', longdescription), ('9', 10 + (1 << 9) + (1 << 14))]),
|
||||
"lnbc241ps9zprzpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygshp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqs9qrss2f8kr98446xls02yndup2ynwjh46u8kdeuuncexx2hnets0j0064nyq25gkd6jnttldzt5qqtszum5dufvuvryxt204w2p24557udxgcp0nlwtw"),
|
||||
]
|
||||
# Some old tests follow that do not have payment_secret. Note that if the parser raised due to the lack of features/payment_secret,
|
||||
# old wallets that have these invoices saved (as paid/expired), could not be opened (though we could do a db upgrade and delete them).
|
||||
tests.extend([
|
||||
(LnAddr(date=timestamp, paymenthash=RHASH, tags=[('d', '')]),
|
||||
(BOLT11Addr(date=timestamp, paymenthash=RHASH, tags=[('d', '')]),
|
||||
"lnbc1ps9zprzpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdqqd9n3kwjjwglnfne5p4rvkze998m3xcxrc8kunl5khkchlaqhwhlyztuuwkrglv47mqg96mcqjjx70hh9luaj4te0u4ww6aclxwve3fqpkmdxlj"),
|
||||
(LnAddr(date=timestamp, paymenthash=RHASH, amount=Decimal('0.001'), tags=[('d', '1 cup coffee'), ('x', 60)]),
|
||||
(BOLT11Addr(date=timestamp, paymenthash=RHASH, amount=Decimal('0.001'), tags=[('d', '1 cup coffee'), ('x', 60)]),
|
||||
"lnbc1m1ps9zprzpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqdq5xysxxatsyp3k7enxv4jsxqzpu9rflz25dx0qw6kdg05u0c5hdc30yq6ga6ew4pz86n244va45nchns9zrs3wjxznsqnt37hz7pswvc56wvuhxcjyd6k3lqf4ujynyxuspmvr078"),
|
||||
(LnAddr(date=timestamp, paymenthash=RHASH, amount=Decimal('1'), tags=[('h', longdescription)]),
|
||||
(BOLT11Addr(date=timestamp, paymenthash=RHASH, amount=Decimal('1'), tags=[('h', longdescription)]),
|
||||
"lnbc11ps9zprzpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqhp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqs2qjafckq94q3js6lvqz2kmenn9ysjejyj8fm4hlx0xtqhaxfzlxjappkgp0hmm40dnuan4v3jy83lqjup2n0fdzgysg049y9l9uc98qq07kfd3"),
|
||||
(LnAddr(date=timestamp, paymenthash=RHASH, net=constants.BitcoinTestnet, tags=[('f', 'mk2QpYatsKicvFVuTAQLBryyccRXMUaGHP'), ('h', longdescription)]),
|
||||
(BOLT11Addr(date=timestamp, paymenthash=RHASH, net=constants.BitcoinTestnet, tags=[('f', 'mk2QpYatsKicvFVuTAQLBryyccRXMUaGHP'), ('h', longdescription)]),
|
||||
"lntb1ps9zprzpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqfpp3x9et2e20v6pu37c5d9vax37wxq72un98hp58yjmdan79s6qqdhdzgynm4zwqd5d7xmw5fk98klysy043l2ahrqsr9zktgu78k8p9t8555ve37qwfvqn6ga37fnfwhgexmf20nzdpmuhwvuv7zra3xrh8y2ggxxuemqfsgka9x7uzsrcx8rfv85c8pmhq9gq4sampn"),
|
||||
|
||||
])
|
||||
|
||||
# Roundtrip
|
||||
for lnaddr1, invoice_str1 in tests:
|
||||
invoice_str2 = lnencode(lnaddr1, PRIVKEY)
|
||||
invoice_str2 = encode_bolt11_invoice(lnaddr1, PRIVKEY)
|
||||
self.assertEqual(invoice_str1, invoice_str2)
|
||||
lnaddr2 = lndecode(invoice_str2, net=lnaddr1.net)
|
||||
lnaddr2 = decode_bolt11_invoice(invoice_str2, net=lnaddr1.net)
|
||||
self.compare(lnaddr1, lnaddr2)
|
||||
|
||||
def test_n_decoding(self):
|
||||
# We flip the signature recovery bit, which would normally give a different
|
||||
# pubkey.
|
||||
_, hrp, data = bech32_decode(
|
||||
lnencode(LnAddr(paymenthash=RHASH, payment_secret=PAYMENT_SECRET, amount=24, tags=[('d', ''), ('9', 33282)]), PRIVKEY),
|
||||
encode_bolt11_invoice(BOLT11Addr(paymenthash=RHASH, payment_secret=PAYMENT_SECRET, amount=24, tags=[('d', ''), ('9', 33282)]), PRIVKEY),
|
||||
ignore_long_length=True)
|
||||
data[-1] ^= 1
|
||||
lnaddr = lndecode(bech32_encode(segwit_addr.Encoding.BECH32, hrp, data), verbose=True)
|
||||
lnaddr = decode_bolt11_invoice(bech32_encode(segwit_addr.Encoding.BECH32, hrp, data), verbose=True)
|
||||
self.assertNotEqual(lnaddr.pubkey.serialize(), PUBKEY)
|
||||
|
||||
# But not if we supply expliciy `n` specifier!
|
||||
_, hrp, data = bech32_decode(
|
||||
lnencode(LnAddr(paymenthash=RHASH, payment_secret=PAYMENT_SECRET, amount=24, tags=[('d', ''), ('n', PUBKEY), ('9', 33282)]), PRIVKEY),
|
||||
encode_bolt11_invoice(BOLT11Addr(paymenthash=RHASH, payment_secret=PAYMENT_SECRET, amount=24, tags=[('d', ''), ('n', PUBKEY), ('9', 33282)]), PRIVKEY),
|
||||
ignore_long_length=True)
|
||||
data[-1] ^= 1
|
||||
lnaddr = lndecode(bech32_encode(segwit_addr.Encoding.BECH32, hrp, data), verbose=True)
|
||||
lnaddr = decode_bolt11_invoice(bech32_encode(segwit_addr.Encoding.BECH32, hrp, data), verbose=True)
|
||||
self.assertEqual(lnaddr.pubkey.serialize(), PUBKEY)
|
||||
|
||||
def test_min_final_cltv_expiry_decoding(self):
|
||||
lnaddr = lndecode("lnsb500u1pdsgyf3pp5nmrqejdsdgs4n9ukgxcp2kcq265yhrxd4k5dyue58rxtp5y83s3qsp5qyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqsdqqcqzys9qypqsqp2h6a5xeytuc3fad2ed4gxvhd593lwjdna3dxsyeem0qkzjx6guk44jend0xq4zzvp6f3fy07wnmxezazzsxgmvqee8shxjuqu2eu0qpnvc95x",
|
||||
net=constants.BitcoinSimnet)
|
||||
lnaddr = decode_bolt11_invoice("lnsb500u1pdsgyf3pp5nmrqejdsdgs4n9ukgxcp2kcq265yhrxd4k5dyue58rxtp5y83s3qsp5qyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqsdqqcqzys9qypqsqp2h6a5xeytuc3fad2ed4gxvhd593lwjdna3dxsyeem0qkzjx6guk44jend0xq4zzvp6f3fy07wnmxezazzsxgmvqee8shxjuqu2eu0qpnvc95x",
|
||||
net=constants.BitcoinSimnet)
|
||||
self.assertEqual(144, lnaddr.get_min_final_cltv_delta())
|
||||
|
||||
lnaddr = lndecode("lntb15u1p0m6lzupp5zqjthgvaad9mewmdjuehwddyze9d8zyxcc43zhaddeegt37sndgsdq4xysyymr0vd4kzcmrd9hx7cqp7xqrrss9qy9qsqsp5vlhcs24hwm747w8f3uau2tlrdkvjaglffnsstwyamj84cxuhrn2s8tut3jqumepu42azyyjpgqa4w9w03204zp9h4clk499y2umstl6s29hqyj8vv4as6zt5567ux7l3f66m8pjhk65zjaq2esezk7ll2kcpljewkg",
|
||||
net=constants.BitcoinTestnet)
|
||||
lnaddr = decode_bolt11_invoice("lntb15u1p0m6lzupp5zqjthgvaad9mewmdjuehwddyze9d8zyxcc43zhaddeegt37sndgsdq4xysyymr0vd4kzcmrd9hx7cqp7xqrrss9qy9qsqsp5vlhcs24hwm747w8f3uau2tlrdkvjaglffnsstwyamj84cxuhrn2s8tut3jqumepu42azyyjpgqa4w9w03204zp9h4clk499y2umstl6s29hqyj8vv4as6zt5567ux7l3f66m8pjhk65zjaq2esezk7ll2kcpljewkg",
|
||||
net=constants.BitcoinTestnet)
|
||||
self.assertEqual(30, lnaddr.get_min_final_cltv_delta())
|
||||
|
||||
def test_min_final_cltv_expiry_roundtrip(self):
|
||||
for cltv in (1, 15, 16, 31, 32, 33, 150, 511, 512, 513, 1023, 1024, 1025):
|
||||
lnaddr = LnAddr(
|
||||
lnaddr = BOLT11Addr(
|
||||
paymenthash=RHASH, payment_secret=b"\x01"*32, amount=Decimal('0.001'), tags=[('d', '1 cup coffee'), ('x', 60), ('c', cltv), ('9', 33282)])
|
||||
self.assertEqual(cltv, lnaddr.get_min_final_cltv_delta())
|
||||
invoice = lnencode(lnaddr, PRIVKEY)
|
||||
self.assertEqual(cltv, lndecode(invoice).get_min_final_cltv_delta())
|
||||
invoice = encode_bolt11_invoice(lnaddr, PRIVKEY)
|
||||
self.assertEqual(cltv, decode_bolt11_invoice(invoice).get_min_final_cltv_delta())
|
||||
|
||||
def test_features(self):
|
||||
lnaddr = lndecode("lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygsdq5vdhkven9v5sxyetpdees9qypqsztrz5v3jfnxskfv7g8chmyzyrfhf2vupcavuq5rce96kyt6g0zh337h206awccwp335zarqrud4wccgdn39vur44d8um4hmgv06aj0sgpdrv73z")
|
||||
lnaddr = decode_bolt11_invoice("lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygsdq5vdhkven9v5sxyetpdees9qypqsztrz5v3jfnxskfv7g8chmyzyrfhf2vupcavuq5rce96kyt6g0zh337h206awccwp335zarqrud4wccgdn39vur44d8um4hmgv06aj0sgpdrv73z")
|
||||
self.assertEqual(33282, lnaddr.get_tag('9'))
|
||||
self.assertEqual(LnFeatures(33282), lnaddr.get_features())
|
||||
|
||||
def test_payment_secret(self):
|
||||
lnaddr = lndecode("lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygsdq5vdhkven9v5sxyetpdees9q5sqqqqqqqqqqqqqqqpqsqvvh7ut50r00p3pg34ea68k7zfw64f8yx9jcdk35lh5ft8qdr8g4r0xzsdcrmcy9hex8un8d8yraewvhqc9l0sh8l0e0yvmtxde2z0hgpzsje5l")
|
||||
lnaddr = decode_bolt11_invoice("lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygsdq5vdhkven9v5sxyetpdees9q5sqqqqqqqqqqqqqqqpqsqvvh7ut50r00p3pg34ea68k7zfw64f8yx9jcdk35lh5ft8qdr8g4r0xzsdcrmcy9hex8un8d8yraewvhqc9l0sh8l0e0yvmtxde2z0hgpzsje5l")
|
||||
self.assertEqual((1 << 9) + (1 << 15) + (1 << 99), lnaddr.get_tag('9'))
|
||||
self.assertEqual(b"\x11" * 32, lnaddr.payment_secret)
|
||||
|
||||
def test_validate_and_compare_features(self):
|
||||
lnaddr = lndecode("lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygsdq5vdhkven9v5sxyetpdees9q5sqqqqqqqqqqqqqqqpqsqvvh7ut50r00p3pg34ea68k7zfw64f8yx9jcdk35lh5ft8qdr8g4r0xzsdcrmcy9hex8un8d8yraewvhqc9l0sh8l0e0yvmtxde2z0hgpzsje5l")
|
||||
lnaddr = decode_bolt11_invoice("lnbc25m1pvjluezpp5qqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqqqsyqcyq5rqwzqfqypqsp5zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zyg3zygsdq5vdhkven9v5sxyetpdees9q5sqqqqqqqqqqqqqqqpqsqvvh7ut50r00p3pg34ea68k7zfw64f8yx9jcdk35lh5ft8qdr8g4r0xzsdcrmcy9hex8un8d8yraewvhqc9l0sh8l0e0yvmtxde2z0hgpzsje5l")
|
||||
lnaddr.validate_and_compare_features(LnFeatures((1 << 8) + (1 << 14) + (1 << 15)))
|
||||
with self.assertRaises(IncompatibleLightningFeatures):
|
||||
lnaddr.validate_and_compare_features(LnFeatures((1 << 8) + (1 << 14) + (1 << 16)))
|
||||
@@ -188,7 +188,7 @@ class TestBolt11(ElectrumTestCase):
|
||||
'16000000x0x717', 0, 1, 40),]
|
||||
),
|
||||
],
|
||||
LnAddr.format_bolt11_routing_info_as_human_readable(r_tags_expl, has_explicit_r_tagtype=True))
|
||||
BOLT11Addr.format_bolt11_routing_info_as_human_readable(r_tags_expl, has_explicit_r_tagtype=True))
|
||||
|
||||
r_tags_impl = [
|
||||
[(bfh('029e03a901b85534ff1e92c43c74431f7ce72046060fcf7a95c37e148f78c77255'), bfh('0102030405060708'), 1, 20, 3),
|
||||
@@ -204,9 +204,9 @@ class TestBolt11(ElectrumTestCase):
|
||||
[('038863cf8ab91046230f561cd5b386cbff8309fa02e3f0c3ed161a3aeb64a643b9',
|
||||
'16000000x0x717', 0, 1, 40),],
|
||||
],
|
||||
LnAddr.format_bolt11_routing_info_as_human_readable(r_tags_impl, has_explicit_r_tagtype=False))
|
||||
BOLT11Addr.format_bolt11_routing_info_as_human_readable(r_tags_impl, has_explicit_r_tagtype=False))
|
||||
|
||||
for has_explicit_r_tagtype in (False, True):
|
||||
self.assertEqual(
|
||||
[],
|
||||
LnAddr.format_bolt11_routing_info_as_human_readable([], has_explicit_r_tagtype=has_explicit_r_tagtype))
|
||||
BOLT11Addr.format_bolt11_routing_info_as_human_readable([], has_explicit_r_tagtype=has_explicit_r_tagtype))
|
||||
|
||||
@@ -20,7 +20,7 @@ from electrum.submarine_swaps import SwapOffer, SwapFees, NostrTransport
|
||||
from electrum.transaction import Transaction, TxOutput, tx_from_any
|
||||
from electrum.util import UserFacingException, NotEnoughFunds
|
||||
from electrum.crypto import sha256
|
||||
from electrum.lnaddr import lndecode
|
||||
from electrum.bolt11 import decode_bolt11_invoice
|
||||
from electrum.daemon import Daemon
|
||||
from electrum import json_db
|
||||
|
||||
@@ -508,7 +508,7 @@ class TestCommandsTestnet(ElectrumTestCase):
|
||||
expiry=3500,
|
||||
wallet=wallet,
|
||||
)
|
||||
invoice = lndecode(invoice=result['invoice'])
|
||||
invoice = decode_bolt11_invoice(invoice=result['invoice'])
|
||||
assert invoice.paymenthash.hex() == payment_hash
|
||||
assert wallet.lnworker.get_payment_info(bytes.fromhex(payment_hash), direction=RECEIVED)
|
||||
assert payment_hash in wallet.lnworker.dont_expire_htlcs
|
||||
|
||||
@@ -29,7 +29,7 @@ from electrum import constants
|
||||
from electrum import bip32
|
||||
from electrum.network import Network, ProxySettings
|
||||
from electrum import simple_config, lnutil
|
||||
from electrum.lnaddr import lnencode, LnAddr, lndecode
|
||||
from electrum.bolt11 import encode_bolt11_invoice, BOLT11Addr, decode_bolt11_invoice
|
||||
from electrum.bitcoin import COIN, sha256
|
||||
from electrum.transaction import Transaction
|
||||
from electrum.util import NetworkRetryManager, bfh, OldTaskGroup, EventListener, InvoiceError
|
||||
@@ -179,7 +179,7 @@ class MockLNWallet(LNWallet):
|
||||
self.channel_db.stop()
|
||||
await self.channel_db.stopped_event.wait()
|
||||
|
||||
async def create_routes_from_invoice(self, amount_msat: int, decoded_invoice: LnAddr, *, full_path=None):
|
||||
async def create_routes_from_invoice(self, amount_msat: int, decoded_invoice: BOLT11Addr, *, full_path=None):
|
||||
paysession = PaySession(
|
||||
payment_hash=decoded_invoice.paymenthash,
|
||||
payment_secret=decoded_invoice.payment_secret,
|
||||
@@ -419,7 +419,7 @@ class TestPeer(ElectrumTestCase):
|
||||
invoice_features: LnFeatures = None,
|
||||
min_final_cltv_delta: int = None,
|
||||
expiry: int = None,
|
||||
) -> Tuple[LnAddr, Invoice]:
|
||||
) -> Tuple[BOLT11Addr, Invoice]:
|
||||
amount_btc = amount_msat/Decimal(COIN*1000)
|
||||
if payment_preimage is None and not payment_hash:
|
||||
payment_preimage = os.urandom(32)
|
||||
@@ -450,7 +450,7 @@ class TestPeer(ElectrumTestCase):
|
||||
invoice_features=invoice_features,
|
||||
)
|
||||
w2.save_payment_info(info)
|
||||
lnaddr1 = LnAddr(
|
||||
lnaddr1 = BOLT11Addr(
|
||||
paymenthash=payment_hash,
|
||||
amount=amount_btc,
|
||||
tags=[
|
||||
@@ -461,8 +461,8 @@ class TestPeer(ElectrumTestCase):
|
||||
] + routing_hints,
|
||||
payment_secret=payment_secret,
|
||||
)
|
||||
invoice = lnencode(lnaddr1, w2.node_keypair.privkey)
|
||||
lnaddr2 = lndecode(invoice) # unlike lnaddr1, this now has a pubkey set
|
||||
invoice = encode_bolt11_invoice(lnaddr1, w2.node_keypair.privkey)
|
||||
lnaddr2 = decode_bolt11_invoice(invoice) # unlike lnaddr1, this now has a pubkey set
|
||||
return lnaddr2, Invoice.from_bech32(invoice)
|
||||
|
||||
async def _activate_trampoline(self, w: MockLNWallet):
|
||||
@@ -1052,7 +1052,7 @@ class TestPeerDirect(TestPeer):
|
||||
self.assertEqual(PR_UNPAID, w2.get_payment_status(lnaddr.paymenthash, direction=RECEIVED))
|
||||
assert lnaddr.get_min_final_cltv_delta() == 400 # what the receiver expects
|
||||
lnaddr.tags = [tag for tag in lnaddr.tags if tag[0] != 'c'] + [['c', 144]]
|
||||
b11 = lnencode(lnaddr, w2.node_keypair.privkey)
|
||||
b11 = encode_bolt11_invoice(lnaddr, w2.node_keypair.privkey)
|
||||
pay_req = Invoice.from_bech32(b11)
|
||||
assert pay_req._lnaddr.get_min_final_cltv_delta() == 144 # what w1 will use to pay
|
||||
result, log = await w1.pay_invoice(pay_req)
|
||||
@@ -1095,7 +1095,7 @@ class TestPeerDirect(TestPeer):
|
||||
# create lightning invoice in the past, so it is expired
|
||||
with mock.patch('time.time', return_value=int(time.time()) - 10000):
|
||||
lnaddr, _pay_req = self.prepare_invoice(w2, expiry=3600)
|
||||
b11 = lnencode(lnaddr, w2.node_keypair.privkey)
|
||||
b11 = encode_bolt11_invoice(lnaddr, w2.node_keypair.privkey)
|
||||
pay_req = Invoice.from_bech32(b11)
|
||||
|
||||
async def try_pay_expired_invoice(pay_req: Invoice, w1=w1):
|
||||
@@ -2044,7 +2044,7 @@ class TestPeerDirect(TestPeer):
|
||||
}
|
||||
|
||||
# create 10 invoices (10 pending htlc sets with 1 htlc each)
|
||||
invoices = [] # type: list[tuple[LnAddr, Invoice]]
|
||||
invoices = [] # type: list[tuple[BOLT11Addr, Invoice]]
|
||||
for i in range(10):
|
||||
lnaddr, pay_req = self.prepare_invoice(bob_w)
|
||||
# prevent bob from settling so that htlc switch will have to iterate through all pending htlcs
|
||||
|
||||
Reference in New Issue
Block a user