LNWallet: make get_invoice_features base feature independent
What changed, and why it matters
This commit is a small internal code cleanup in Electrum's Lightning wallet. It renames a method and changes it to accept feature flags as an input rather than generating them itself. The actual logic for deciding which feature flags are included in an invoice remains unchanged. There is no indication this fixes a security bug or introduces a vulnerability.
No security action required. Treat as normal refactoring.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch refactors LNWallet._get_invoice_features into _prepare_invoice_features. Previously the method called self.features.for_bolt11_invoice() internally; now callers pass in the base features. The same bit-mask operations (clearing trampoline routing and MPP options under the same conditions) are preserved. The two call sites are updated to pass self.features.for_bolt11_invoice(). This is a pure refactor to allow reuse for BOLT12 offers; no security behavior changes.
Changed components
electrum/lnworker.pyLNWallet invoice feature preparationInspect captured patch +6 / −7
diff --git a/electrum/lnworker.py b/electrum/lnworker.py
index 8481a52..92ae704 100644
--- a/electrum/lnworker.py
+++ b/electrum/lnworker.py
@@ -2631,16 +2631,15 @@ class LNWallet(Logger):
route[-1].node_features |= invoice_features
return route
- def _get_invoice_features(self, amount_msat: Optional[int]) -> LnFeatures:
- invoice_features = self.features.for_bolt11_invoice()
+ def _prepare_invoice_features(self, base_features: LnFeatures, *, amount_msat: Optional[int]) -> LnFeatures:
if not all((not c.is_open() or c.is_frozen_for_receiving()) or self.is_trampoline_peer(c.node_id) \
for c in self.channels.values()):
- invoice_features &= ~ LnFeatures.OPTION_TRAMPOLINE_ROUTING_OPT_ELECTRUM
+ base_features &= ~ LnFeatures.OPTION_TRAMPOLINE_ROUTING_OPT_ELECTRUM
needs_jit: bool = self.receive_requires_jit_channel(amount_msat)
if needs_jit:
# jit only works with single htlcs, mpp will cause LSP to open channels for each htlc
- invoice_features &= ~ LnFeatures.BASIC_MPP_OPT & ~ LnFeatures.BASIC_MPP_REQ
- return invoice_features
+ base_features &= ~ LnFeatures.BASIC_MPP_OPT & ~ LnFeatures.BASIC_MPP_REQ
+ return base_features
def clear_invoices_cache(self):
self._bolt11_cache.clear()
@@ -2713,7 +2712,7 @@ class LNWallet(Logger):
payment_preimage = os.urandom(32)
payment_hash = sha256(payment_preimage)
min_final_cltv_delta = min_final_cltv_delta or MIN_FINAL_CLTV_DELTA_ACCEPTED
- invoice_features = self._get_invoice_features(amount_msat)
+ invoice_features = self._prepare_invoice_features(self.features.for_bolt11_invoice(), amount_msat=amount_msat)
info = PaymentInfo(
payment_hash=payment_hash,
amount_msat=amount_msat,
@@ -2882,7 +2881,7 @@ class LNWallet(Logger):
status=PR_UNPAID,
min_final_cltv_delta=min_final_cltv_delta,
expiry_delay=exp_delay,
- invoice_features=self._get_invoice_features(amount_msat),
+ invoice_features=self._prepare_invoice_features(self.features.for_bolt11_invoice(), amount_msat=amount_msat),
)
self.save_payment_info(info, write_to_disk=False)
Why this scored 12/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.