Browse Source

Use different trampoline bits than Eclair. Fixes #8141

master
ThomasV 3 years ago
parent
commit
d95f3e5622
  1. 19
      electrum/lnutil.py
  2. 9
      electrum/lnworker.py
  3. 6
      electrum/tests/test_lnpeer.py
  4. 4
      electrum/tests/test_lnutil.py
  5. 3
      electrum/trampoline.py

19
electrum/lnutil.py

@ -1090,12 +1090,19 @@ class LnFeatures(IntFlag):
_ln_feature_contexts[OPTION_SUPPORT_LARGE_CHANNEL_OPT] = (LNFC.INIT | LNFC.NODE_ANN)
_ln_feature_contexts[OPTION_SUPPORT_LARGE_CHANNEL_REQ] = (LNFC.INIT | LNFC.NODE_ANN)
# This is still a temporary number. Also used by Eclair.
OPTION_TRAMPOLINE_ROUTING_REQ = 1 << 148
OPTION_TRAMPOLINE_ROUTING_OPT = 1 << 149
# Temporary number.
OPTION_TRAMPOLINE_ROUTING_REQ_ECLAIR = 1 << 148
OPTION_TRAMPOLINE_ROUTING_OPT_ECLAIR = 1 << 149
_ln_feature_contexts[OPTION_TRAMPOLINE_ROUTING_REQ] = (LNFC.INIT | LNFC.NODE_ANN | LNFC.INVOICE)
_ln_feature_contexts[OPTION_TRAMPOLINE_ROUTING_OPT] = (LNFC.INIT | LNFC.NODE_ANN | LNFC.INVOICE)
_ln_feature_contexts[OPTION_TRAMPOLINE_ROUTING_REQ_ECLAIR] = (LNFC.INIT | LNFC.NODE_ANN | LNFC.INVOICE)
_ln_feature_contexts[OPTION_TRAMPOLINE_ROUTING_OPT_ECLAIR] = (LNFC.INIT | LNFC.NODE_ANN | LNFC.INVOICE)
# We use a different bit because Phoenix cannot do end-to-end multi-trampoline routes
OPTION_TRAMPOLINE_ROUTING_REQ_ELECTRUM = 1 << 150
OPTION_TRAMPOLINE_ROUTING_OPT_ELECTRUM = 1 << 151
_ln_feature_contexts[OPTION_TRAMPOLINE_ROUTING_REQ_ELECTRUM] = (LNFC.INIT | LNFC.NODE_ANN | LNFC.INVOICE)
_ln_feature_contexts[OPTION_TRAMPOLINE_ROUTING_OPT_ELECTRUM] = (LNFC.INIT | LNFC.NODE_ANN | LNFC.INVOICE)
OPTION_SHUTDOWN_ANYSEGWIT_REQ = 1 << 26
OPTION_SHUTDOWN_ANYSEGWIT_OPT = 1 << 27
@ -1249,7 +1256,7 @@ LN_FEATURES_IMPLEMENTED = (
| LnFeatures.VAR_ONION_OPT | LnFeatures.VAR_ONION_REQ
| LnFeatures.PAYMENT_SECRET_OPT | LnFeatures.PAYMENT_SECRET_REQ
| LnFeatures.BASIC_MPP_OPT | LnFeatures.BASIC_MPP_REQ
| LnFeatures.OPTION_TRAMPOLINE_ROUTING_OPT | LnFeatures.OPTION_TRAMPOLINE_ROUTING_REQ
| LnFeatures.OPTION_TRAMPOLINE_ROUTING_OPT_ELECTRUM | LnFeatures.OPTION_TRAMPOLINE_ROUTING_REQ_ELECTRUM
| LnFeatures.OPTION_SHUTDOWN_ANYSEGWIT_OPT | LnFeatures.OPTION_SHUTDOWN_ANYSEGWIT_REQ
| LnFeatures.OPTION_CHANNEL_TYPE_OPT | LnFeatures.OPTION_CHANNEL_TYPE_REQ
)

9
electrum/lnworker.py

@ -184,7 +184,7 @@ LNWALLET_FEATURES = BASE_FEATURES\
| LnFeatures.OPTION_STATIC_REMOTEKEY_REQ\
| LnFeatures.GOSSIP_QUERIES_REQ\
| LnFeatures.BASIC_MPP_OPT\
| LnFeatures.OPTION_TRAMPOLINE_ROUTING_OPT\
| LnFeatures.OPTION_TRAMPOLINE_ROUTING_OPT_ELECTRUM\
| LnFeatures.OPTION_SHUTDOWN_ANYSEGWIT_OPT\
| LnFeatures.OPTION_CHANNEL_TYPE_OPT\
@ -1531,9 +1531,10 @@ class LNWallet(LNWorker):
if is_hardcoded_trampoline(node_id):
return True
peer = self._peers.get(node_id)
if peer and peer.their_features.supports(LnFeatures.OPTION_TRAMPOLINE_ROUTING_OPT):
return True
return False
if not peer:
return False
return (peer.their_features.supports(LnFeatures.OPTION_TRAMPOLINE_ROUTING_OPT_ECLAIR)\
or peer.their_features.supports(LnFeatures.OPTION_TRAMPOLINE_ROUTING_OPT_ELECTRUM))
def suggest_peer(self) -> Optional[bytes]:
if not self.uses_trampoline():

6
electrum/tests/test_lnpeer.py

@ -150,7 +150,7 @@ class MockLNWallet(Logger, EventListener, NetworkRetryManager[LNPeerAddr]):
self.features |= LnFeatures.OPTION_UPFRONT_SHUTDOWN_SCRIPT_OPT
self.features |= LnFeatures.VAR_ONION_OPT
self.features |= LnFeatures.PAYMENT_SECRET_OPT
self.features |= LnFeatures.OPTION_TRAMPOLINE_ROUTING_OPT
self.features |= LnFeatures.OPTION_TRAMPOLINE_ROUTING_OPT_ELECTRUM
self.features |= LnFeatures.OPTION_CHANNEL_TYPE_OPT
self.pending_payments = defaultdict(asyncio.Future)
for chan in chans:
@ -1071,7 +1071,7 @@ class TestPeer(TestCaseForTestnet):
if mpp_invoice:
graph.workers['dave'].features |= LnFeatures.BASIC_MPP_OPT
if disable_trampoline_receiving:
graph.workers['dave'].features &= ~LnFeatures.OPTION_TRAMPOLINE_ROUTING_OPT
graph.workers['dave'].features &= ~LnFeatures.OPTION_TRAMPOLINE_ROUTING_OPT_ELECTRUM
if not bob_forwarding:
graph.workers['bob'].enable_htlc_forwarding = False
if alice_uses_trampoline:
@ -1165,7 +1165,7 @@ class TestPeer(TestCaseForTestnet):
peers = graph.peers.values()
if is_legacy:
# turn off trampoline features in invoice
graph.workers['dave'].features = graph.workers['dave'].features ^ LnFeatures.OPTION_TRAMPOLINE_ROUTING_OPT
graph.workers['dave'].features = graph.workers['dave'].features ^ LnFeatures.OPTION_TRAMPOLINE_ROUTING_OPT_ELECTRUM
# declare routing nodes as trampoline nodes
electrum.trampoline._TRAMPOLINE_NODES_UNITTESTS = {

4
electrum/tests/test_lnutil.py

@ -869,7 +869,7 @@ class TestLNUtil(ElectrumTestCase):
self.assertTrue(f1.supports(LnFeatures.PAYMENT_SECRET_OPT))
self.assertTrue(f1.supports(LnFeatures.BASIC_MPP_REQ))
self.assertFalse(f1.supports(LnFeatures.OPTION_STATIC_REMOTEKEY_OPT))
self.assertFalse(f1.supports(LnFeatures.OPTION_TRAMPOLINE_ROUTING_REQ))
self.assertFalse(f1.supports(LnFeatures.OPTION_TRAMPOLINE_ROUTING_REQ_ELECTRUM))
def test_lnworker_decode_channel_update_msg(self):
msg_without_prefix = bytes.fromhex("439b71c8ddeff63004e4ff1f9764a57dcf20232b79d9d669aef0e31c42be8e44208f7d868d0133acb334047f30e9399dece226ccd98e5df5330adf7f356290516fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d619000000000008762700054a00005ef2cf9c0101009000000000000003e80000000000000001000000002367b880")
@ -896,7 +896,7 @@ class TestLNUtil(ElectrumTestCase):
features = LnFeatures(LnFeatures.BASIC_MPP_OPT | LnFeatures.OPTION_STATIC_REMOTEKEY_OPT)
self.assertTrue(ChannelType.OPTION_STATIC_REMOTEKEY.complies_with_features(features))
features = LnFeatures(LnFeatures.BASIC_MPP_OPT | LnFeatures.OPTION_TRAMPOLINE_ROUTING_OPT)
features = LnFeatures(LnFeatures.BASIC_MPP_OPT | LnFeatures.OPTION_TRAMPOLINE_ROUTING_OPT_ELECTRUM)
self.assertFalse(ChannelType.OPTION_STATIC_REMOTEKEY.complies_with_features(features))
# ignore unknown channel types

3
electrum/trampoline.py

@ -102,7 +102,8 @@ def is_legacy_relay(invoice_features, r_tags) -> Tuple[bool, List[bytes]]:
"""
invoice_features = LnFeatures(invoice_features)
# trampoline-supporting wallets:
if invoice_features.supports(LnFeatures.OPTION_TRAMPOLINE_ROUTING_OPT):
if invoice_features.supports(LnFeatures.OPTION_TRAMPOLINE_ROUTING_OPT_ECLAIR)\
or invoice_features.supports(LnFeatures.OPTION_TRAMPOLINE_ROUTING_OPT_ELECTRUM):
# If there are no r_tags (routing hints) included, the wallet doesn't have
# private channels and is probably directly connected to a trampoline node.
# Any trampoline node should be able to figure out a path to the receiver and

Loading…
Cancel
Save