1
0

trampoline: improve payment success

- better error handling: previously we stopped all attempts on any of
  TRAMPOLINE_EXPIRY_TOO_SOON, UNKNOWN_NEXT_PEER, TEMPORARY_NODE_FAILURE.
  Instead we should retry (but see code comments).
- previously payments failed if ALL of the following criteria applied:
  - sender is paying via trampoline, but not via the ACINQ node (which is
    special cased)
  - receiver only has private channels and has put r_tags into invoice, along
    with setting the trampoline feature bit in the invoice, however the receiver
    is not connected to any trampoline forwarders directly
  The sender would then assume that the private routing hints in the invoice
  correspond to trampoline forwarders.
- also, previously if both the sender and the recipient used trampoline and
  they shared a trampoline forwarder (that they were both connected to), the
  private channels the recipient had (with nodes other than the shared TF)
  would never be attempted.
This commit is contained in:
SomberNight
2021-07-02 18:44:39 +02:00
parent 3bc8ef6651
commit 3a7f5373ac
6 changed files with 77 additions and 36 deletions

View File

@@ -151,7 +151,7 @@ def create_test_channels(*, feerate=6000, local_msat=None, remote_msat=None,
bob_first, other_node_id=bob_pubkey, l_dust=200, r_dust=1300,
l_csv=5, r_csv=4
),
name=bob_name,
name=f"{alice_name}->{bob_name}",
initial_feerate=feerate),
lnchannel.Channel(
create_channel_state(
@@ -160,7 +160,7 @@ def create_test_channels(*, feerate=6000, local_msat=None, remote_msat=None,
alice_first, other_node_id=alice_pubkey, l_dust=1300, r_dust=200,
l_csv=4, r_csv=5
),
name=alice_name,
name=f"{bob_name}->{alice_name}",
initial_feerate=feerate)
)

View File

@@ -12,6 +12,8 @@ from typing import Iterable, NamedTuple, Tuple, List, Dict
from aiorpcx import TaskGroup, timeout_after, TaskTimeout
import electrum
import electrum.trampoline
from electrum import bitcoin
from electrum import constants
from electrum.network import Network
@@ -152,6 +154,8 @@ class MockLNWallet(Logger, NetworkRetryManager[LNPeerAddr]):
self.preimages = {}
self.stopping_soon = False
self.logger.info(f"created LNWallet[{name}] with nodeID={local_keypair.pubkey.hex()}")
def get_invoice_status(self, key):
pass
@@ -272,8 +276,8 @@ class PutIntoOthersQueueTransport(MockTransport):
self.other_mock_transport.queue.put_nowait(data)
def transport_pair(k1, k2, name1, name2):
t1 = PutIntoOthersQueueTransport(k1, name2)
t2 = PutIntoOthersQueueTransport(k2, name1)
t1 = PutIntoOthersQueueTransport(k1, name1)
t2 = PutIntoOthersQueueTransport(k2, name2)
t1.other_mock_transport = t2
t2.other_mock_transport = t1
return t1, t2
@@ -341,7 +345,7 @@ class TestPeer(TestCaseForTestnet):
self._loop_thread.join(timeout=1)
super().tearDown()
def prepare_peers(self, alice_channel, bob_channel):
def prepare_peers(self, alice_channel: Channel, bob_channel: Channel):
k1, k2 = keypair(), keypair()
alice_channel.node_id = k2.pubkey
bob_channel.node_id = k1.pubkey
@@ -424,6 +428,8 @@ class TestPeer(TestCaseForTestnet):
w_b.network.config.set_key('lightning_forward_payments', True)
w_c.network.config.set_key('lightning_forward_payments', True)
w_b.network.config.set_key('lightning_forward_trampoline_payments', True)
w_c.network.config.set_key('lightning_forward_trampoline_payments', True)
# forwarding fees, etc
chan_ab.forwarding_fee_proportional_millionths *= 500
@@ -448,7 +454,7 @@ class TestPeer(TestCaseForTestnet):
peer_cd.mark_open(chan_cd)
peer_db.mark_open(chan_db)
peer_dc.mark_open(chan_dc)
return SquareGraph(
graph = SquareGraph(
w_a=w_a,
w_b=w_b,
w_c=w_c,
@@ -470,6 +476,7 @@ class TestPeer(TestCaseForTestnet):
chan_db=chan_db,
chan_dc=chan_dc,
)
return graph
@staticmethod
async def prepare_invoice(
@@ -935,7 +942,14 @@ class TestPeer(TestCaseForTestnet):
def test_multipart_payment_with_trampoline(self):
# single attempt will fail with insufficient trampoline fee
graph = self.prepare_chans_and_peers_in_square()
self._run_mpp(graph, {'alice_uses_trampoline':True, 'attempts':1}, {'alice_uses_trampoline':True, 'attempts':3})
electrum.trampoline._TRAMPOLINE_NODES_UNITTESTS = {
graph.w_b.name: LNPeerAddr(host="127.0.0.1", port=9735, pubkey=graph.w_b.node_keypair.pubkey),
graph.w_c.name: LNPeerAddr(host="127.0.0.1", port=9735, pubkey=graph.w_c.node_keypair.pubkey),
}
try:
self._run_mpp(graph, {'alice_uses_trampoline':True, 'attempts':1}, {'alice_uses_trampoline':True, 'attempts':30})
finally:
electrum.trampoline._TRAMPOLINE_NODES_UNITTESTS = {}
@needs_test_with_all_chacha20_implementations
def test_fail_pending_htlcs_on_shutdown(self):