What changed, and why it matters
This is a small code cleanup change. A function that reads routing hints from Lightning invoices no longer takes a tag argument because only one type of routing hint ('r') is now supported. All callers are updated accordingly. There is no security issue visible in the change.
No security action required. Treat as routine refactoring.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The commit refactors BOLT11Addr.get_routing_info(tag) to get_routing_info(), hardcoding the ‘r’ tag filter. It updates all call sites in bolt11.py, lnworker.py, the Qt and QML GUIs, and test files. The change is purely an API simplification after the removal of t-type routing info tags. No logic changes that would affect parsing, validation, or payment security are present.
Changed components
electrum/bolt11.pyelectrum/lnworker.pyelectrum/gui/qt/main_window.pyelectrum/gui/qml/qeinvoice.pytests/test_bolt11.pytests/test_lnwallet.pytests/lnhelpers.pyInspect captured patch +12 / −12
### electrum/bolt11.py
@@ -328,8 +328,8 @@ def get_amount_sat(self) -> Optional[Decimal]:
return None
return self.amount * COIN
- def get_routing_info(self, tag):
- r_tags = list(filter(lambda x: x[0] == tag, self.tags))
+ def get_routing_info(self):
+ r_tags = list(filter(lambda x: x[0] == 'r', self.tags))
# strip the tag type, it's implicitly 'r' now
r_tags = list(map(lambda x: x[1], r_tags))
# if there are multiple hints, we will use the first one that works,
@@ -427,7 +427,7 @@ def to_debug_json(self) -> Dict[str, Any]:
'tags': self.tags,
'unknown_tags': self.unknown_tags,
}
- if ln_routing_info := self.get_routing_info('r'):
+ if ln_routing_info := self.get_routing_info():
d['r_tags'] = self.format_bolt11_routing_info_as_human_readable(ln_routing_info)
return d
### electrum/gui/qml/qeinvoice.py
@@ -275,7 +275,7 @@ def set_lnprops(self):
return
lnaddr = self._effectiveInvoice._lnaddr
- ln_routing_info = lnaddr.get_routing_info('r')
+ ln_routing_info = lnaddr.get_routing_info()
self._logger.debug(str(ln_routing_info))
self._lnprops = {
### electrum/gui/qt/main_window.py
@@ -1718,7 +1718,7 @@ def show_lightning_invoice(self, invoice: Invoice):
invoice_e.setText(invoice.lightning_invoice)
grid.addWidget(QLabel(_('Text') + ':'), 8, 0)
grid.addWidget(invoice_e, 8, 1)
- r_tags = lnaddr.get_routing_info('r')
+ r_tags = lnaddr.get_routing_info()
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)
### electrum/lnworker.py
@@ -1969,7 +1969,7 @@ async def pay_invoice(
payment_secret = lnaddr.payment_secret
invoice_pubkey = lnaddr.pubkey.serialize()
invoice_features = lnaddr.get_features()
- r_tags = lnaddr.get_routing_info('r')
+ r_tags = lnaddr.get_routing_info()
amount_to_pay = lnaddr.get_amount_msat()
status = self.get_invoice_status(invoice)
if status == PR_PAID:
### tests/lnhelpers.py
@@ -285,7 +285,7 @@ async def create_routes_from_invoice(self, amount_msat: int, decoded_invoice: BO
payment_secret=decoded_invoice.payment_secret,
initial_trampoline_fee_level=0,
invoice_features=decoded_invoice.get_features(),
- r_tags=decoded_invoice.get_routing_info('r'),
+ r_tags=decoded_invoice.get_routing_info(),
min_final_cltv_delta=decoded_invoice.get_min_final_cltv_delta(),
amount_to_pay=amount_msat,
invoice_pubkey=decoded_invoice.pubkey.serialize(),
### tests/test_bolt11.py
@@ -277,7 +277,7 @@ def test_tag_padding_errors(self):
# control: a well-formed hop is parsed
r_hop = bytes(33) + bytes(8) + (1).to_bytes(4, 'big') + (2).to_bytes(4, 'big') + (3).to_bytes(2, 'big')
invoice = self._encode_invoice_with_raw_tag('r', list(convertbits(r_hop, 8, 5)))
- self.assertEqual(1, len(decode_bolt11_invoice(invoice).get_routing_info('r')))
+ self.assertEqual(1, len(decode_bolt11_invoice(invoice).get_routing_info()))
def test_invalid_signature(self):
# The trailing 65 bytes of an invoice are attacker-controlled: every way the ecc lib
### tests/test_lnwallet.py
@@ -160,7 +160,7 @@ async def test_trampoline_invoice_features_and_routing_hints(self):
)
lnaddr, _ = wallet.get_bolt11_invoice(payment_info=pi, message='test', fallback_address=None)
- hint_node_ids = {route[0][0] for route in lnaddr.get_routing_info('r')}
+ hint_node_ids = {route[0][0] for route in lnaddr.get_routing_info()}
self.assertEqual(hint_node_ids, {trampoline_pubkey, regular_pubkey})
# trampoline feature should not be set if we use trampoline but one peer is not a trampoline
@@ -176,7 +176,7 @@ async def test_trampoline_invoice_features_and_routing_hints(self):
wallet.clear_invoices_cache()
lnaddr, _ = wallet.get_bolt11_invoice(payment_info=pi, message='test', fallback_address=None)
- hint_node_ids = {route[0][0] for route in lnaddr.get_routing_info('r')}
+ hint_node_ids = {route[0][0] for route in lnaddr.get_routing_info()}
self.assertEqual(hint_node_ids, {trampoline_pubkey, regular_pubkey})
wallet.uses_trampoline = old_check
@@ -198,14 +198,14 @@ async def test_trampoline_invoice_features_and_routing_hints(self):
wallet.clear_invoices_cache()
lnaddr2, _ = wallet.get_bolt11_invoice(payment_info=pi2, message='test', fallback_address=None)
- hint_node_ids2 = {route[0][0] for route in lnaddr2.get_routing_info('r')}
+ hint_node_ids2 = {route[0][0] for route in lnaddr2.get_routing_info()}
self.assertEqual(hint_node_ids2, {trampoline_pubkey, regular_pubkey})
# assert only trampoline peers are included in r_tags if the invoice_features signal trampoline
del electrum.trampoline._TRAMPOLINE_NODES_UNITTESTS['regular_peer']
wallet.clear_invoices_cache()
lnaddr3, _ = wallet.get_bolt11_invoice(payment_info=pi2, message='test', fallback_address=None)
- hint_node_ids3 = {route[0][0] for route in lnaddr3.get_routing_info('r')}
+ hint_node_ids3 = {route[0][0] for route in lnaddr3.get_routing_info()}
self.assertEqual(hint_node_ids3, {trampoline_pubkey})
async def test_open_channel_just_in_time_success(self):Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.