Skip to content

Commit f60cdb0

Browse files
authored
Merge pull request #10614 from f321x/lnaddr_rename
bolt11: rename *lnaddr* -> *bolt11*
2 parents d2700df + b0a5e20 commit f60cdb0

15 files changed

Lines changed: 116 additions & 126 deletions

electrum/bip21.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from . import bitcoin
88
from .util import format_satoshis_plain
99
from .bitcoin import COIN, TOTAL_COIN_SUPPLY_LIMIT_IN_BTC
10-
from .lnaddr import lndecode, LnDecodeException
10+
from .bolt11 import decode_bolt11_invoice, BOLT11DecodeException
1111

1212
# note: when checking against these, use .lower() to support case-insensitivity
1313
BITCOIN_BIP21_URI_SCHEME = 'bitcoin'
@@ -93,8 +93,8 @@ def parse_bip21_URI(uri: str) -> dict:
9393
raise InvalidBitcoinURI(f"failed to parse 'sig' field: {repr(e)}") from e
9494
if 'lightning' in out:
9595
try:
96-
lnaddr = lndecode(out['lightning'])
97-
except LnDecodeException as e:
96+
lnaddr = decode_bolt11_invoice(out['lightning'])
97+
except BOLT11DecodeException as e:
9898
raise InvalidBitcoinURI(f"Failed to decode 'lightning' field: {e!r}") from e
9999
amount_sat = out.get('amount')
100100
if amount_sat:
Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@
2323
from .lnutil import LnFeatures
2424

2525

26-
class LnInvoiceException(Exception): pass
27-
class LnDecodeException(LnInvoiceException): pass
28-
class LnEncodeException(LnInvoiceException): pass
26+
class BOLT11InvoiceException(Exception): pass
27+
class BOLT11DecodeException(BOLT11InvoiceException): pass
28+
class BOLT11EncodeException(BOLT11InvoiceException): pass
2929

3030

3131
# BOLT #11:
@@ -68,7 +68,7 @@ def unshorten_amount(amount) -> Decimal:
6868
# A reader SHOULD fail if `amount` contains a non-digit, or is followed by
6969
# anything except a `multiplier` in the table above.
7070
if not re.fullmatch("\\d+[pnum]?", str(amount)):
71-
raise LnDecodeException("Invalid amount '{}'".format(amount))
71+
raise BOLT11DecodeException("Invalid amount '{}'".format(amount))
7272

7373
if unit in units.keys():
7474
return Decimal(amount[:-1]) / units[unit]
@@ -88,7 +88,7 @@ def encode_fallback_addr(fallback: str, net: Type[AbstractNet]) -> Sequence[int]
8888
elif addrtype == net.ADDRTYPE_P2SH:
8989
wver = 18
9090
else:
91-
raise LnEncodeException(f"Unknown address type {addrtype} for {net}")
91+
raise BOLT11EncodeException(f"Unknown address type {addrtype} for {net}")
9292
wprog = addr
9393
data5 = convertbits(wprog, 8, 5)
9494
assert data5 is not None
@@ -156,7 +156,7 @@ def pull_tagged(data5: bytearray) -> Tuple[str, Sequence[int]]:
156156
return ret
157157

158158

159-
def lnencode(addr: 'LnAddr', privkey) -> str:
159+
def encode_bolt11_invoice(addr: 'BOLT11Addr', privkey) -> str:
160160
if addr.amount:
161161
amount = addr.net.BOLT11_HRP + shorten_amount(addr.amount)
162162
else:
@@ -185,7 +185,7 @@ def lnencode(addr: 'LnAddr', privkey) -> str:
185185
# A writer MUST NOT include more than one `d`, `h`, `n` or `x` fields,
186186
if k in ('d', 'h', 'n', 'x', 'p', 's', '9'):
187187
if k in tags_set:
188-
raise LnEncodeException("Duplicate '{}' tag".format(k))
188+
raise BOLT11EncodeException("Duplicate '{}' tag".format(k))
189189

190190
if k == 'r':
191191
route = bytearray()
@@ -228,7 +228,7 @@ def lnencode(addr: 'LnAddr', privkey) -> str:
228228
data5 += tagged5('9', feature_bits)
229229
else:
230230
# FIXME: Support unknown tags?
231-
raise LnEncodeException("Unknown tag {}".format(k))
231+
raise BOLT11EncodeException("Unknown tag {}".format(k))
232232

233233
tags_set.add(k)
234234

@@ -254,7 +254,7 @@ def lnencode(addr: 'LnAddr', privkey) -> str:
254254
return bech32_encode(segwit_addr.Encoding.BECH32, hrp, data5)
255255

256256

257-
class LnAddr(object):
257+
class BOLT11Addr:
258258
def __init__(self, *, paymenthash: bytes = None, amount=None, net: Type[AbstractNet] = None, tags=None, date=None,
259259
payment_secret: bytes = None):
260260
self.date = int(time.time()) if not date else int(date)
@@ -274,16 +274,16 @@ def amount(self) -> Optional[Decimal]:
274274
@amount.setter
275275
def amount(self, value):
276276
if not (isinstance(value, Decimal) or value is None):
277-
raise LnInvoiceException(f"amount must be Decimal or None, not {value!r}")
277+
raise BOLT11InvoiceException(f"amount must be Decimal or None, not {value!r}")
278278
if value is None:
279279
self._amount = None
280280
return
281281
assert isinstance(value, Decimal)
282282
if value.is_nan() or not (0 <= value <= TOTAL_COIN_SUPPLY_LIMIT_IN_BTC):
283-
raise LnInvoiceException(f"amount is out-of-bounds: {value!r} BTC")
283+
raise BOLT11InvoiceException(f"amount is out-of-bounds: {value!r} BTC")
284284
if value * 10**12 % 10:
285285
# max resolution is millisatoshi
286-
raise LnInvoiceException(f"Cannot encode {value!r}: too many decimal places")
286+
raise BOLT11InvoiceException(f"Cannot encode {value!r}: too many decimal places")
287287
self._amount = value
288288

289289
def get_amount_sat(self) -> Optional[Decimal]:
@@ -332,7 +332,8 @@ def get_features(self) -> 'LnFeatures':
332332
def validate_and_compare_features(self, myfeatures: 'LnFeatures') -> None:
333333
"""Raises IncompatibleOrInsaneFeatures.
334334
335-
note: these checks are not done by the parser (in lndecode), as then when we started requiring a new feature,
335+
note: these checks are not done by the parser (in decode_bolt11_invoice),
336+
as then when we started requiring a new feature,
336337
old saved already paid invoices could no longer be parsed.
337338
"""
338339
from .lnutil import validate_features, ln_compare_features
@@ -341,7 +342,7 @@ def validate_and_compare_features(self, myfeatures: 'LnFeatures') -> None:
341342
ln_compare_features(myfeatures.for_invoice(), invoice_features)
342343

343344
def __str__(self):
344-
return "LnAddr[{}, amount={}{} tags=[{}]]".format(
345+
return "BOLT11Addr[{}, amount={}{} tags=[{}]]".format(
345346
hexlify(self.pubkey.serialize()).decode('utf-8') if self.pubkey else None,
346347
self.amount, self.net.BOLT11_HRP,
347348
", ".join([k + '=' + str(v) for k, v in self.tags])
@@ -403,37 +404,37 @@ def serialize(self):
403404
return self.pubkey.get_public_key_bytes(True)
404405

405406

406-
def lndecode(invoice: str, *, verbose=False, net=None) -> LnAddr:
407-
"""Parses a string into an LnAddr object.
408-
Can raise LnDecodeException or IncompatibleOrInsaneFeatures.
407+
def decode_bolt11_invoice(invoice: str, *, verbose=False, net=None) -> BOLT11Addr:
408+
"""Parses a string into a BOLT11Addr object.
409+
Can raise BOLT11DecodeException or IncompatibleOrInsaneFeatures.
409410
"""
410411
if net is None:
411412
net = constants.net
412413
decoded_bech32 = bech32_decode(invoice, ignore_long_length=True)
413414
hrp = decoded_bech32.hrp
414415
data5 = decoded_bech32.data # "5" as in list of 5-bit integers
415416
if decoded_bech32.encoding is None:
416-
raise LnDecodeException("Bad bech32 checksum")
417+
raise BOLT11DecodeException("Bad bech32 checksum")
417418
if decoded_bech32.encoding != segwit_addr.Encoding.BECH32:
418-
raise LnDecodeException("Bad bech32 encoding: must be using vanilla BECH32")
419+
raise BOLT11DecodeException("Bad bech32 encoding: must be using vanilla BECH32")
419420

420421
# BOLT #11:
421422
#
422423
# A reader MUST fail if it does not understand the `prefix`.
423424
if not hrp.startswith('ln'):
424-
raise LnDecodeException("Does not start with ln")
425+
raise BOLT11DecodeException("Does not start with ln")
425426

426427
if not hrp[2:].startswith(net.BOLT11_HRP):
427-
raise LnDecodeException(f"Wrong Lightning invoice HRP {hrp[2:]}, should be {net.BOLT11_HRP}")
428+
raise BOLT11DecodeException(f"Wrong Lightning invoice HRP {hrp[2:]}, should be {net.BOLT11_HRP}")
428429

429430
# Final signature 65 bytes, split it off.
430431
if len(data5) < 65*8//5:
431-
raise LnDecodeException("Too short to contain signature")
432+
raise BOLT11DecodeException("Too short to contain signature")
432433
sigdecoded = bytes(convertbits(data5[-65*8//5:], 5, 8, False))
433434
data5 = data5[:-65*8//5]
434435
data5_remaining = bytearray(data5) # note: bytearray is faster than list of ints
435436

436-
addr = LnAddr()
437+
addr = BOLT11Addr()
437438
addr.pubkey = None
438439
addr.net = net
439440

@@ -580,7 +581,7 @@ def lndecode(invoice: str, *, verbose=False, net=None) -> LnAddr:
580581
# A reader MUST use the `n` field to validate the signature instead of
581582
# performing signature recovery if a valid `n` field is provided.
582583
if not ecc.ECPubkey(addr.pubkey).ecdsa_verify(sigdecoded[:64], hrp_hash):
583-
raise LnDecodeException("bad signature")
584+
raise BOLT11DecodeException("bad signature")
584585
pubkey_copy = addr.pubkey
585586

586587
class WrappedBytesKey:

electrum/gui/qt/channel_details.py

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,12 @@
33
import PyQt6.QtGui as QtGui
44
import PyQt6.QtWidgets as QtWidgets
55
import PyQt6.QtCore as QtCore
6-
from PyQt6.QtWidgets import QLabel, QLineEdit, QHBoxLayout, QGridLayout
6+
from PyQt6.QtWidgets import QLabel, QHBoxLayout
77

8-
from electrum.util import EventListener, ShortID
8+
from electrum.util import ShortID
99
from electrum.i18n import _
10-
from electrum.util import format_time
11-
from electrum.lnutil import format_short_channel_id, LOCAL, REMOTE, UpdateAddHtlc, Direction
12-
from electrum.lnchannel import htlcsum, Channel, AbstractChannel, HTLCWithStatus
13-
from electrum.lnaddr import LnAddr, lndecode
14-
from electrum.bitcoin import COIN
15-
from electrum.wallet import Abstract_Wallet
10+
from electrum.lnutil import LOCAL, REMOTE, UpdateAddHtlc, Direction
11+
from electrum.lnchannel import Channel, AbstractChannel, HTLCWithStatus
1612

1713
from electrum.gui.common_qt.util import QtEventListener, qt_event_listener
1814
from .util import Buttons, CloseButton, ShowQRLineEdit, MessageBoxMixin, WWLabel, VLine

electrum/gui/qt/main_window.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@
7373
from electrum.simple_config import SimpleConfig
7474
from electrum.logging import Logger
7575
from electrum.lntransport import extract_nodeid, ConnStringFormatError
76-
from electrum.lnaddr import lndecode, LnAddr
76+
from electrum.bolt11 import decode_bolt11_invoice, BOLT11Addr
7777
from electrum.submarine_swaps import SwapServerTransport, NostrTransport
7878
from electrum.fee_policy import FeePolicy
7979

@@ -1678,7 +1678,7 @@ def show_onchain_invoice(self, invoice: Invoice):
16781678

16791679
def show_lightning_invoice(self, invoice: Invoice):
16801680
from electrum.util import format_short_id
1681-
lnaddr = lndecode(invoice.lightning_invoice)
1681+
lnaddr = decode_bolt11_invoice(invoice.lightning_invoice)
16821682
d = WindowModalDialog(self, _("Lightning Invoice"))
16831683
vbox = QVBoxLayout(d)
16841684
grid = QGridLayout()
@@ -1713,7 +1713,7 @@ def show_lightning_invoice(self, invoice: Invoice):
17131713
grid.addWidget(QLabel(_('Text') + ':'), 8, 0)
17141714
grid.addWidget(invoice_e, 8, 1)
17151715
r_tags = lnaddr.get_routing_info('r')
1716-
r_tags = '\n'.join(repr(r) for r in LnAddr.format_bolt11_routing_info_as_human_readable(r_tags))
1716+
r_tags = '\n'.join(repr(r) for r in BOLT11Addr.format_bolt11_routing_info_as_human_readable(r_tags))
17171717
routing_e = QTextEdit(str(r_tags))
17181718
routing_e.setReadOnly(True)
17191719
grid.addWidget(QLabel(_("Routing Hints") + ':'), 9, 0)

electrum/gui/text.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,9 @@ def parse_bip21(text):
5050

5151

5252
def parse_bolt11(text):
53-
from electrum.lnaddr import lndecode
53+
from electrum.bolt11 import decode_bolt11_invoice
5454
try:
55-
return lndecode(text)
55+
return decode_bolt11_invoice(text)
5656
except Exception:
5757
return
5858

electrum/invoices.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from .util import age, InvoiceError, format_satoshis
1010
from .bip21 import create_bip21_uri
1111
from .lnutil import hex_to_bytes
12-
from .lnaddr import lndecode, LnAddr
12+
from .bolt11 import decode_bolt11_invoice, BOLT11Addr
1313
from . import constants
1414
from .bitcoin import COIN, TOTAL_COIN_SUPPLY_LIMIT_IN_BTC
1515
from .bitcoin import address_to_script
@@ -213,7 +213,7 @@ def from_bech32(cls, invoice: str) -> 'Invoice':
213213
Might raise InvoiceError.
214214
"""
215215
try:
216-
lnaddr = lndecode(invoice)
216+
lnaddr = decode_bolt11_invoice(invoice)
217217
except Exception as e:
218218
raise InvoiceError(e) from e
219219
amount_msat = lnaddr.get_amount_msat()
@@ -275,9 +275,9 @@ def get_address(self) -> Optional[str]:
275275
return address
276276

277277
@property
278-
def _lnaddr(self) -> LnAddr:
278+
def _lnaddr(self) -> BOLT11Addr:
279279
if self.__lnaddr is None:
280-
self.__lnaddr = lndecode(self.lightning_invoice)
280+
self.__lnaddr = decode_bolt11_invoice(self.lightning_invoice)
281281
return self.__lnaddr
282282

283283
@property
@@ -288,7 +288,7 @@ def rhash(self) -> str:
288288
@lightning_invoice.validator
289289
def _validate_invoice_str(self, attribute, value):
290290
if value is not None:
291-
lnaddr = lndecode(value) # this checks the str can be decoded
291+
lnaddr = decode_bolt11_invoice(value) # this checks the str can be decoded
292292
self.__lnaddr = lnaddr # save it, just to avoid having to recompute later
293293

294294
def can_be_paid_onchain(self) -> bool:

electrum/lnurl.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
from electrum import segwit_addr, util
1414
from electrum.segwit_addr import bech32_decode, Encoding, convertbits, bech32_encode
15-
from electrum.lnaddr import LnDecodeException, LnEncodeException
15+
from electrum.bolt11 import BOLT11DecodeException, BOLT11EncodeException
1616
from electrum.network import Network
1717
from electrum.logging import get_logger
1818
from electrum.i18n import _
@@ -47,11 +47,11 @@ def decode_lnurl(lnurl: str) -> str:
4747
hrp = decoded_bech32.hrp
4848
data = decoded_bech32.data
4949
if decoded_bech32.encoding is None:
50-
raise LnDecodeException("Bad bech32 checksum")
50+
raise BOLT11DecodeException("Bad bech32 checksum")
5151
if decoded_bech32.encoding != Encoding.BECH32:
52-
raise LnDecodeException("Bad bech32 encoding: must be using vanilla BECH32")
52+
raise BOLT11DecodeException("Bad bech32 encoding: must be using vanilla BECH32")
5353
if not hrp.startswith("lnurl"):
54-
raise LnDecodeException("Does not start with lnurl")
54+
raise BOLT11DecodeException("Does not start with lnurl")
5555
data = convertbits(data, 5, 8, False)
5656
url = bytes(data).decode("utf-8")
5757
return url
@@ -62,7 +62,7 @@ def encode_lnurl(url: str) -> str:
6262
try:
6363
url = url.encode("utf-8")
6464
except UnicodeError as e:
65-
raise LnEncodeException("invalid url") from e
65+
raise BOLT11EncodeException("invalid url") from e
6666
bech32_data = convertbits(url, 8, 5, True)
6767
assert bech32_data
6868
lnurl = bech32_encode(

electrum/lnworker.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464
ConnStringFormatError
6565
)
6666
from .lnpeer import Peer, LN_P2P_NETWORK_TIMEOUT
67-
from .lnaddr import lnencode, LnAddr, lndecode
67+
from .bolt11 import encode_bolt11_invoice, BOLT11Addr, decode_bolt11_invoice
6868
from .lnchannel import Channel, AbstractChannel, ChannelState, PeerState, HTLCWithStatus, ChannelBackup
6969
from .lnrater import LNRater
7070
from .lnutil import (
@@ -123,7 +123,7 @@ class PaymentInfo:
123123
124124
- Historically, we used to store "bolt11, direction, status", but deserializing bolt11 was too slow.
125125
(even deserializing just once - all bolt11 during wallet-open - was slow)
126-
- note: the deserialization code in lnaddr.py has been significantly sped up since
126+
- note: the deserialization code in bolt11.py has been significantly sped up since
127127
- For incoming payments, for unpaid requests, ~every time the user displays the unpaid bolt11,
128128
we get a chance to display a new bolt11, with same payment_hash/amount, but with updated
129129
routing_hints (channels might get closed/opened, or just liquidity changed drastically).
@@ -1930,7 +1930,7 @@ async def pay_to_node(
19301930
f"pay_to_node starting session for RHASH={payment_hash.hex()}. "
19311931
f"using_trampoline={self.uses_trampoline()}. "
19321932
f"invoice_features={paysession.invoice_features.get_names()}. "
1933-
f"r_tags={LnAddr.format_bolt11_routing_info_as_human_readable(r_tags)}. "
1933+
f"r_tags={BOLT11Addr.format_bolt11_routing_info_as_human_readable(r_tags)}. "
19341934
f"{amount_to_pay=} msat. {budget=}")
19351935
if not self.uses_trampoline():
19361936
self.logger.info(
@@ -2219,11 +2219,11 @@ def _decode_channel_update_msg(cls, chan_upd_msg: bytes) -> Optional[Dict[str, A
22192219
except Exception:
22202220
return None
22212221

2222-
def _check_bolt11_invoice(self, bolt11_invoice: str, *, amount_msat: int = None) -> LnAddr:
2223-
"""Parses and validates a bolt11 invoice str into a LnAddr.
2222+
def _check_bolt11_invoice(self, bolt11_invoice: str, *, amount_msat: int = None) -> BOLT11Addr:
2223+
"""Parses and validates a bolt11 invoice str into a BOLT11Addr.
22242224
Includes pre-payment checks external to the parser.
22252225
"""
2226-
addr = lndecode(bolt11_invoice)
2226+
addr = decode_bolt11_invoice(bolt11_invoice)
22272227
if addr.is_expired():
22282228
raise InvoiceError(_("This invoice has expired"))
22292229
# check amount
@@ -2563,7 +2563,7 @@ def get_bolt11_invoice(
25632563
message: str,
25642564
fallback_address: Optional[str],
25652565
channels: Optional[Sequence[Channel]] = None,
2566-
) -> Tuple[LnAddr, str]:
2566+
) -> Tuple[BOLT11Addr, str]:
25672567
amount_msat = payment_info.amount_msat
25682568
pair = self._bolt11_cache.get(payment_info.payment_hash)
25692569
if pair:
@@ -2580,12 +2580,12 @@ def get_bolt11_invoice(
25802580
# TODO: make invoice_features dynamic depending on available trampoline channels
25812581
only_trampoline=payment_info.invoice_features.supports(LnFeatures.OPTION_TRAMPOLINE_ROUTING_OPT_ELECTRUM),
25822582
)
2583-
formatted_r_hints = LnAddr.format_bolt11_routing_info_as_human_readable(routing_hints, has_explicit_r_tagtype=True)
2583+
formatted_r_hints = BOLT11Addr.format_bolt11_routing_info_as_human_readable(routing_hints, has_explicit_r_tagtype=True)
25842584
self.logger.info(f"creating bolt11 invoice with routing_hints: {formatted_r_hints}, sat: {(amount_msat or 0) // 1000}")
25852585
payment_secret = self.get_payment_secret(payment_info.payment_hash)
25862586
amount_btc = amount_msat/Decimal(COIN*1000) if amount_msat else None
25872587
min_final_cltv_delta = payment_info.min_final_cltv_delta + MIN_FINAL_CLTV_DELTA_BUFFER_INVOICE
2588-
lnaddr = LnAddr(
2588+
lnaddr = BOLT11Addr(
25892589
paymenthash=payment_info.payment_hash,
25902590
amount=amount_btc,
25912591
tags=[
@@ -2597,7 +2597,7 @@ def get_bolt11_invoice(
25972597
] + routing_hints,
25982598
date=timestamp,
25992599
payment_secret=payment_secret)
2600-
invoice = lnencode(lnaddr, self.node_keypair.privkey)
2600+
invoice = encode_bolt11_invoice(lnaddr, self.node_keypair.privkey)
26012601
pair = lnaddr, invoice
26022602
self._bolt11_cache[payment_info.payment_hash] = pair
26032603
return pair
@@ -3971,7 +3971,7 @@ async def _maybe_forward_trampoline(
39713971
invoice_features = payload["invoice_features"]["invoice_features"]
39723972
invoice_routing_info = payload["invoice_routing_info"]["invoice_routing_info"]
39733973
r_tags = decode_routing_info(invoice_routing_info)
3974-
self.logger.info(f'r_tags {LnAddr.format_bolt11_routing_info_as_human_readable(r_tags)}')
3974+
self.logger.info(f'r_tags {BOLT11Addr.format_bolt11_routing_info_as_human_readable(r_tags)}')
39753975
# TODO legacy mpp payment, use total_msat from trampoline onion
39763976
else:
39773977
self.logger.info('forward_trampoline: end-to-end')

0 commit comments

Comments
 (0)