URI: 
       tlnrouter: add comments about path-finding blocking the asyncio loop - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit c95c0dcb8090e7e99a5706c3232077de7051db9b
   DIR parent 05a191cc6a544adf625c70454540c8b79ea5ed7c
  HTML Author: SomberNight <somber.night@protonmail.com>
       Date:   Mon,  9 Mar 2020 20:39:13 +0100
       
       lnrouter: add comments about path-finding blocking the asyncio loop
       
       Diffstat:
         M electrum/lnrouter.py                |       7 ++++++-
         M electrum/lnworker.py                |       7 +++++--
         M electrum/tests/test_lnpeer.py       |       6 +++---
       
       3 files changed, 14 insertions(+), 6 deletions(-)
       ---
   DIR diff --git a/electrum/lnrouter.py b/electrum/lnrouter.py
       t@@ -146,7 +146,6 @@ class LNPathFinder(Logger):
                    return float('inf'), 0
                if channel_policy.is_disabled():
                    return float('inf'), 0
       -        route_edge = RouteEdge.from_channel_policy(channel_policy, short_channel_id, end_node)
                if payment_amt_msat < channel_policy.htlc_minimum_msat:
                    return float('inf'), 0  # payment amount too little
                if channel_info.capacity_sat is not None and \
       t@@ -155,6 +154,7 @@ class LNPathFinder(Logger):
                if channel_policy.htlc_maximum_msat is not None and \
                        payment_amt_msat > channel_policy.htlc_maximum_msat:
                    return float('inf'), 0  # payment amount too large
       +        route_edge = RouteEdge.from_channel_policy(channel_policy, short_channel_id, end_node)
                if not route_edge.is_sane_to_use(payment_amt_msat):
                    return float('inf'), 0  # thanks but no thanks
        
       t@@ -187,6 +187,11 @@ class LNPathFinder(Logger):
                assert type(nodeB) is bytes
                assert type(invoice_amount_msat) is int
                if my_channels is None: my_channels = {}
       +        # note: we don't lock self.channel_db, so while the path finding runs,
       +        #       the underlying graph could potentially change... (not good but maybe ~OK?)
       +        #       (but at the time of writing, we are called on the asyncio event loop,
       +        #        and the graph is also only updated from the event loop, so it will
       +        #        not change)
        
                # FIXME paths cannot be longer than 20 edges (onion packet)...
        
   DIR diff --git a/electrum/lnworker.py b/electrum/lnworker.py
       t@@ -922,7 +922,10 @@ class LNWallet(LNWorker):
                success = False
                for i in range(attempts):
                    try:
       -                route = await self._create_route_from_invoice(decoded_invoice=lnaddr)
       +                # note: this call does path-finding which takes ~1 second
       +                #       -> we will BLOCK the asyncio loop... (could just run in a thread and await,
       +                #       but then the graph could change while the path-finding runs on it)
       +                route = self._create_route_from_invoice(decoded_invoice=lnaddr)
                        self.set_payment_status(payment_hash, PR_INFLIGHT)
                        self.network.trigger_callback('invoice_status', key)
                        payment_attempt_log = await self._pay_to_route(route, lnaddr)
       t@@ -1035,7 +1038,7 @@ class LNWallet(LNWorker):
                        f"min_final_cltv_expiry: {addr.get_min_final_cltv_expiry()}"))
                return addr
        
       -    async def _create_route_from_invoice(self, decoded_invoice) -> LNPaymentRoute:
       +    def _create_route_from_invoice(self, decoded_invoice) -> LNPaymentRoute:
                amount_msat = int(decoded_invoice.amount * COIN * 1000)
                invoice_pubkey = decoded_invoice.pubkey.serialize()
                # use 'r' field from invoice
   DIR diff --git a/electrum/tests/test_lnpeer.py b/electrum/tests/test_lnpeer.py
       t@@ -350,7 +350,7 @@ class TestPeer(ElectrumTestCase):
                    await asyncio.wait_for(p1.initialized, 1)
                    await asyncio.wait_for(p2.initialized, 1)
                    # alice sends htlc
       -            route = await w1._create_route_from_invoice(decoded_invoice=lnaddr)
       +            route = w1._create_route_from_invoice(decoded_invoice=lnaddr)
                    htlc = p1.pay(route, alice_channel, int(lnaddr.amount * COIN * 1000), lnaddr.paymenthash, lnaddr.get_min_final_cltv_expiry())
                    # alice closes
                    await p1.close_channel(alice_channel.channel_id)
       t@@ -370,14 +370,14 @@ class TestPeer(ElectrumTestCase):
                pay_req = self.prepare_invoice(w2)
        
                addr = w1._check_invoice(pay_req)
       -        route = run(w1._create_route_from_invoice(decoded_invoice=addr))
       +        route = w1._create_route_from_invoice(decoded_invoice=addr)
        
                run(w1.force_close_channel(alice_channel.channel_id))
                # check if a tx (commitment transaction) was broadcasted:
                assert q1.qsize() == 1
        
                with self.assertRaises(NoPathFound) as e:
       -            run(w1._create_route_from_invoice(decoded_invoice=addr))
       +            w1._create_route_from_invoice(decoded_invoice=addr)
        
                peer = w1.peers[route[0].node_id]
                # AssertionError is ok since we shouldn't use old routes, and the