URI: 
       tcreate_trampoline_route: check that we can pay the amount and the fees, and that the route is sane - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit c9d6d11604b3a90ff1d0e1413da94ff9f96041cd
   DIR parent ab9bf07a792bb2637201eed420158d71a9880c22
  HTML Author: ThomasV <thomasv@electrum.org>
       Date:   Wed, 24 Feb 2021 18:25:49 +0100
       
       create_trampoline_route: check that we can pay the amount and the fees, and that the route is sane
       
       Diffstat:
         M electrum/lnworker.py                |     149 ++++++++++++++++---------------
       
       1 file changed, 78 insertions(+), 71 deletions(-)
       ---
   DIR diff --git a/electrum/lnworker.py b/electrum/lnworker.py
       t@@ -1281,6 +1281,7 @@ class LNWallet(LNWorker):
        
            def create_trampoline_route(
                    self, amount_msat:int,
       +            min_cltv_expiry:int,
                    invoice_pubkey:bytes,
                    invoice_features:int,
                    channels: List[Channel],
       t@@ -1304,86 +1305,92 @@ class LNWallet(LNWorker):
                else:
                    is_legacy = True
        
       -        # Find a trampoline. We assume we have a direct channel to trampoline
       -        for chan in channels:
       -            if not self.is_trampoline_peer(chan.node_id):
       -                continue
       -            if chan.is_active() and chan.can_pay(amount_msat, check_frozen=True):
       -                trampoline_short_channel_id = chan.short_channel_id
       -                trampoline_node_id = chan.node_id
       -                break
       -        else:
       -            raise NoPathFound()
       -        # use attempt number to decide fee and second trampoline
       -        # we need a state with the list of nodes we have not tried
       -        # add optional second trampoline
       -        trampoline2 = None
       -        if is_legacy:
       -            for node_id in self.trampoline2_list:
       -                if node_id != trampoline_node_id:
       -                    trampoline2 = node_id
       -                    break
                # fee level. the same fee is used for all trampolines
                if self.trampoline_fee_level < len(TRAMPOLINE_FEES):
                    params = TRAMPOLINE_FEES[self.trampoline_fee_level]
                else:
                    raise NoPathFound()
       -        self.logger.info(f'create route with trampoline: fee_level={self.trampoline_fee_level}, is legacy: {is_legacy}')
       -        self.logger.info(f'first trampoline: {trampoline_node_id.hex()}')
       -        self.logger.info(f'second trampoline: {trampoline2.hex() if trampoline2 else None}')
       -        self.logger.info(f'params: {params}')
       -        # node_features is only used to determine is_tlv
       -        trampoline_features = LnFeatures.VAR_ONION_OPT
       -        # hop to trampoline
       -        route = [
       -            RouteEdge(
       -                node_id=trampoline_node_id,
       -                short_channel_id=trampoline_short_channel_id,
       -                fee_base_msat=0,
       -                fee_proportional_millionths=0,
       -                cltv_expiry_delta=0,
       -                node_features=trampoline_features)
       -        ]
       -        # trampoline hop
       -        route.append(
       -            TrampolineEdge(
       -                node_id=trampoline_node_id,
       -                fee_base_msat=params['fee_base_msat'],
       -                fee_proportional_millionths=params['fee_proportional_millionths'],
       -                cltv_expiry_delta=params['cltv_expiry_delta'],
       -                node_features=trampoline_features))
       -        if trampoline2:
       +        # Find a trampoline. We assume we have a direct channel to trampoline
       +        for chan in channels:
       +            if not self.is_trampoline_peer(chan.node_id):
       +                continue
       +            trampoline_short_channel_id = chan.short_channel_id
       +            trampoline_node_id = chan.node_id
       +            # use attempt number to decide fee and second trampoline
       +            # we need a state with the list of nodes we have not tried
       +            # add optional second trampoline
       +            trampoline2 = None
       +            if is_legacy:
       +                for node_id in self.trampoline2_list:
       +                    if node_id != trampoline_node_id:
       +                        trampoline2 = node_id
       +                        break
       +            # node_features is only used to determine is_tlv
       +            trampoline_features = LnFeatures.VAR_ONION_OPT
       +            # hop to trampoline
       +            route = [
       +                RouteEdge(
       +                    node_id=trampoline_node_id,
       +                    short_channel_id=trampoline_short_channel_id,
       +                    fee_base_msat=0,
       +                    fee_proportional_millionths=0,
       +                    cltv_expiry_delta=0,
       +                    node_features=trampoline_features)
       +            ]
       +            # trampoline hop
                    route.append(
                        TrampolineEdge(
       -                    node_id=trampoline2,
       +                    node_id=trampoline_node_id,
                            fee_base_msat=params['fee_base_msat'],
                            fee_proportional_millionths=params['fee_proportional_millionths'],
                            cltv_expiry_delta=params['cltv_expiry_delta'],
                            node_features=trampoline_features))
       -        # add routing info
       -        if is_legacy:
       -            invoice_routing_info = self.encode_routing_info(r_tags)
       -            route[-1].invoice_routing_info = invoice_routing_info
       -            route[-1].invoice_features = invoice_features
       +            if trampoline2:
       +                route.append(
       +                    TrampolineEdge(
       +                        node_id=trampoline2,
       +                        fee_base_msat=params['fee_base_msat'],
       +                        fee_proportional_millionths=params['fee_proportional_millionths'],
       +                        cltv_expiry_delta=params['cltv_expiry_delta'],
       +                        node_features=trampoline_features))
       +            # add routing info
       +            if is_legacy:
       +                invoice_routing_info = self.encode_routing_info(r_tags)
       +                route[-1].invoice_routing_info = invoice_routing_info
       +                route[-1].invoice_features = invoice_features
       +            else:
       +                if t_tag:
       +                    pubkey, feebase, feerate, cltv = t_tag
       +                    if route[-1].node_id != pubkey:
       +                        route.append(
       +                            TrampolineEdge(
       +                                node_id=pubkey,
       +                                fee_base_msat=feebase,
       +                                fee_proportional_millionths=feerate,
       +                                cltv_expiry_delta=cltv,
       +                                node_features=trampoline_features))
       +            # Fake edge (not part of actual route, needed by calc_hops_data)
       +            route.append(
       +                TrampolineEdge(
       +                    node_id=invoice_pubkey,
       +                    fee_base_msat=0,
       +                    fee_proportional_millionths=0,
       +                    cltv_expiry_delta=0,
       +                    node_features=trampoline_features))
       +            # check that we can pay amount and fees
       +            for edge in route[::-1]:
       +                amount_msat += edge.fee_for_edge(amount_msat)
       +            if not chan.can_pay(amount_msat, check_frozen=True):
       +                continue
       +            if not is_route_sane_to_use(route, amount_msat, min_cltv_expiry):
       +                continue
       +            break
                else:
       -            if t_tag:
       -                pubkey, feebase, feerate, cltv = t_tag
       -                if route[-1].node_id != pubkey:
       -                    route.append(
       -                        TrampolineEdge(
       -                            node_id=pubkey,
       -                            fee_base_msat=feebase,
       -                            fee_proportional_millionths=feerate,
       -                            cltv_expiry_delta=cltv,
       -                            node_features=trampoline_features))
       -        # Fake edge (not part of actual route, needed by calc_hops_data)
       -        route.append(
       -            TrampolineEdge(
       -                node_id=invoice_pubkey,
       -                fee_base_msat=0,
       -                fee_proportional_millionths=0,
       -                cltv_expiry_delta=0,
       -                node_features=trampoline_features))
       +            raise NoPathFound()
       +        self.logger.info(f'created route with trampoline: fee_level={self.trampoline_fee_level}, is legacy: {is_legacy}')
       +        self.logger.info(f'first trampoline: {trampoline_node_id.hex()}')
       +        self.logger.info(f'second trampoline: {trampoline2.hex() if trampoline2 else None}')
       +        self.logger.info(f'params: {params}')
                return route
        
            @profiler
       t@@ -1422,7 +1429,6 @@ class LNWallet(LNWorker):
                    # preference -funds = (low rating=high preference).
                    split_configurations = suggest_splits(amount_msat, channels_with_funds)
                    for s in split_configurations:
       -                self.logger.info(f"trying split configuration: {s[0]} rating: {s[1]}")
                        routes = []
                        try:
                            for chanid, part_amount_msat in s[0].items():
       t@@ -1441,11 +1447,12 @@ class LNWallet(LNWorker):
                                        channel,
                                        full_path=None)
                                    routes.append((route, amt))
       +                    self.logger.info(f"found acceptable split configuration: {list(s[0].values())} rating: {s[1]}")
                            break
                        except NoPathFound:
                            continue
                    else:
       -                raise NoPathFound
       +                raise NoPathFound()
                return routes
        
            def create_route_for_payment(
       t@@ -1461,7 +1468,7 @@ class LNWallet(LNWorker):
                channels = [outgoing_channel] if outgoing_channel else list(self.channels.values())
                if not self.channel_db:
                    route = self.create_trampoline_route(
       -                amount_msat, invoice_pubkey, invoice_features, channels, r_tags, t_tags)
       +                amount_msat, min_cltv_expiry, invoice_pubkey, invoice_features, channels, r_tags, t_tags)
                    return route, amount_msat
        
                route = None