URI: 
       tlnworker: fix amount_inflight. (amount with routing fees were used on htlc failures) - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 5663e598637d5cf8aba6b2be8c2b3ccc609fd692
   DIR parent d3d476f44c57cc9c545f9dabddf32897b84c784c
  HTML Author: ThomasV <thomasv@electrum.org>
       Date:   Sat,  6 Mar 2021 10:45:52 +0100
       
       lnworker: fix amount_inflight.
       (amount with routing fees were used on htlc failures)
       
       Diffstat:
         M electrum/lnworker.py                |      51 ++++++++++++++++---------------
       
       1 file changed, 27 insertions(+), 24 deletions(-)
       ---
   DIR diff --git a/electrum/lnworker.py b/electrum/lnworker.py
       t@@ -601,7 +601,7 @@ class LNWallet(LNWorker):
        
                self.sent_htlcs = defaultdict(asyncio.Queue)  # type: Dict[bytes, asyncio.Queue[HtlcLog]]
                self.sent_htlcs_routes = dict()               # (RHASH, scid, htlc_id) -> route, payment_secret, amount_msat, bucket_msat
       -        self.sent_buckets = defaultdict(set)
       +        self.sent_buckets = dict()
                self.received_htlcs = dict()                  # RHASH -> mpp_status, htlc_set
        
                self.swap_manager = SwapManager(wallet=self.wallet, lnworker=self)
       t@@ -1074,19 +1074,21 @@ class LNWallet(LNWorker):
                            use_two_trampolines=use_two_trampolines,
                            fwd_trampoline_onion=fwd_trampoline_onion))
                        # 2. send htlcs
       -                for route, amount_msat, total_msat, cltv_delta, bucket_payment_secret, trampoline_onion in routes:
       +                for route, amount_msat, total_msat, amount_receiver_msat, cltv_delta, bucket_payment_secret, trampoline_onion in routes:
                            await self.pay_to_route(
                                route=route,
                                amount_msat=amount_msat,
                                total_msat=total_msat,
       +                        amount_receiver_msat=amount_receiver_msat,
                                payment_hash=payment_hash,
                                payment_secret=bucket_payment_secret,
                                min_cltv_expiry=cltv_delta,
                                trampoline_onion=trampoline_onion)
       -                    amount_inflight += amount_msat
       +                    amount_inflight += amount_receiver_msat
                            assert amount_inflight <= amount_to_pay, f"amount_inflight {amount_inflight} > amount_to_pay {amount_to_pay}"
                        util.trigger_callback('invoice_status', self.wallet, payment_hash.hex())
                    # 3. await a queue
       +            self.logger.info(f"amount inflight {amount_inflight}")
                    htlc_log = await self.sent_htlcs[payment_hash].get()
                    amount_inflight -= htlc_log.amount_msat
                    assert amount_inflight >= 0, f"amount_inflight={amount_inflight} < 0"
       t@@ -1124,6 +1126,7 @@ class LNWallet(LNWorker):
                    route: LNPaymentRoute,
                    amount_msat: int,
                    total_msat: int,
       +            amount_receiver_msat:int,
                    payment_hash: bytes,
                    payment_secret: Optional[bytes],
                    min_cltv_expiry: int,
       t@@ -1147,11 +1150,12 @@ class LNWallet(LNWorker):
                    trampoline_onion=trampoline_onion)
        
                key = (payment_hash, short_channel_id, htlc.htlc_id)
       -        self.sent_htlcs_routes[key] = route, payment_secret, amount_msat, total_msat
       +        self.sent_htlcs_routes[key] = route, payment_secret, amount_msat, total_msat, amount_receiver_msat
                # if we sent MPP to a trampoline, add item to sent_buckets
                if not self.channel_db and amount_msat != total_msat:
                    if payment_secret not in self.sent_buckets:
       -                self.sent_buckets[payment_secret] = total_msat
       +                self.sent_buckets[payment_secret] = 0
       +            self.sent_buckets[payment_secret] += amount_receiver_msat
                util.trigger_callback('htlc_added', chan, htlc, SENT)
        
        
       t@@ -1309,7 +1313,7 @@ class LNWallet(LNWorker):
                                continue
                            if chan.is_frozen_for_sending():
                                continue
       -                    trampoline_onion, trampoline_fee, amount_with_fees, cltv_delta = create_trampoline_route_and_onion(
       +                    trampoline_onion, amount_with_fees, cltv_delta = create_trampoline_route_and_onion(
                                amount_msat=amount_msat,
                                total_msat=final_total_msat,
                                min_cltv_expiry=min_cltv_expiry,
       t@@ -1325,8 +1329,7 @@ class LNWallet(LNWorker):
                                trampoline_fee_level=trampoline_fee_level,
                                use_two_trampolines=use_two_trampolines)
                            trampoline_payment_secret = os.urandom(32)
       -                    amount_to_send = amount_with_fees + trampoline_fee
       -                    if chan.available_to_spend(LOCAL, strict=True) < amount_to_send:
       +                    if chan.available_to_spend(LOCAL, strict=True) < amount_with_fees:
                                continue
                            route = [
                                RouteEdge(
       t@@ -1338,7 +1341,7 @@ class LNWallet(LNWorker):
                                    cltv_expiry_delta=0,
                                    node_features=trampoline_features)
                            ]
       -                    routes = [(route, amount_to_send, amount_to_send, cltv_delta, trampoline_payment_secret, trampoline_onion)]
       +                    routes = [(route, amount_with_fees, amount_with_fees, amount_msat, cltv_delta, trampoline_payment_secret, trampoline_onion)]
                            break
                        else:
                            raise NoPathFound()
       t@@ -1350,7 +1353,7 @@ class LNWallet(LNWorker):
                            r_tags=r_tags, t_tags=t_tags,
                            invoice_features=invoice_features,
                            outgoing_channel=None, full_path=full_path)
       -                routes = [(route, amount_msat, final_total_msat, min_cltv_expiry, payment_secret, fwd_trampoline_onion)]
       +                routes = [(route, amount_msat, final_total_msat, amount_msat, min_cltv_expiry, payment_secret, fwd_trampoline_onion)]
                except NoPathFound:
                    if not invoice_features.supports(LnFeatures.BASIC_MPP_OPT):
                        raise
       t@@ -1374,7 +1377,7 @@ class LNWallet(LNWorker):
                                        buckets[chan.node_id].append((chan_id, part_amount_msat))
                                for node_id, bucket in buckets.items():
                                    bucket_amount_msat = sum([x[1] for x in bucket])
       -                            trampoline_onion, trampoline_fee, bucket_amount_with_fees, bucket_cltv_delta = create_trampoline_route_and_onion(
       +                            trampoline_onion, bucket_amount_with_fees, bucket_cltv_delta = create_trampoline_route_and_onion(
                                        amount_msat=bucket_amount_msat,
                                        total_msat=final_total_msat,
                                        min_cltv_expiry=min_cltv_expiry,
       t@@ -1389,15 +1392,16 @@ class LNWallet(LNWorker):
                                        local_height=local_height,
                                        trampoline_fee_level=trampoline_fee_level,
                                        use_two_trampolines=use_two_trampolines)
       -                            self.logger.info(f'trampoline fee {trampoline_fee}')
                                    # node_features is only used to determine is_tlv
                                    bucket_payment_secret = os.urandom(32)
       +                            bucket_fees = bucket_amount_with_fees - bucket_amount_msat
       +                            self.logger.info(f'bucket_fees {bucket_fees}')
                                    for chan_id, part_amount_msat in bucket:
                                        chan = self.channels[chan_id]
                                        margin = chan.available_to_spend(LOCAL, strict=True) - part_amount_msat
       -                                delta_fee = min(trampoline_fee, margin)
       +                                delta_fee = min(bucket_fees, margin) # fixme: we have to pay all trampolines
                                        part_amount_msat_with_fees = part_amount_msat + delta_fee
       -                                trampoline_fee -= delta_fee
       +                                bucket_fees -= delta_fee
                                        route = [
                                            RouteEdge(
                                                start_node=self.node_keypair.pubkey,
       t@@ -1409,8 +1413,8 @@ class LNWallet(LNWorker):
                                                node_features=trampoline_features)
                                        ]
                                        self.logger.info(f'adding route {part_amount_msat} {delta_fee} {margin}')
       -                                routes.append((route, part_amount_msat_with_fees, bucket_amount_with_fees, bucket_cltv_delta, bucket_payment_secret, trampoline_onion))
       -                            if trampoline_fee > 0:
       +                                routes.append((route, part_amount_msat_with_fees, bucket_amount_with_fees, part_amount_msat, bucket_cltv_delta, bucket_payment_secret, trampoline_onion))
       +                            if bucket_fees != 0:
                                        self.logger.info('not enough margin to pay trampoline fee')
                                        raise NoPathFound()
                            else:
       t@@ -1424,7 +1428,7 @@ class LNWallet(LNWorker):
                                            r_tags=r_tags, t_tags=t_tags,
                                            invoice_features=invoice_features,
                                            outgoing_channel=channel, full_path=None)
       -                                routes.append((route, part_amount_msat, final_total_msat, min_cltv_expiry, payment_secret, fwd_trampoline_onion))
       +                                routes.append((route, part_amount_msat, final_total_msat, part_amount_msat, min_cltv_expiry, payment_secret, fwd_trampoline_onion))
                            self.logger.info(f"found acceptable split configuration: {list(s[0].values())} rating: {s[1]}")
                            break
                        except NoPathFound:
       t@@ -1660,11 +1664,11 @@ class LNWallet(LNWorker):
                util.trigger_callback('htlc_fulfilled', payment_hash, chan.channel_id)
                q = self.sent_htlcs.get(payment_hash)
                if q:
       -            route, payment_secret, amount_msat, bucket_msat = self.sent_htlcs_routes[(payment_hash, chan.short_channel_id, htlc_id)]
       +            route, payment_secret, amount_msat, bucket_msat, amount_receiver_msat = self.sent_htlcs_routes[(payment_hash, chan.short_channel_id, htlc_id)]
                    htlc_log = HtlcLog(
                        success=True,
                        route=route,
       -                amount_msat=amount_msat)
       +                amount_msat=amount_receiver_msat)
                    q.put_nowait(htlc_log)
                else:
                    key = payment_hash.hex()
       t@@ -1685,7 +1689,7 @@ class LNWallet(LNWorker):
                    # detect if it is part of a bucket
                    # if yes, wait until the bucket completely failed
                    key = (payment_hash, chan.short_channel_id, htlc_id)
       -            route, payment_secret, amount_msat, bucket_msat = self.sent_htlcs_routes[key]
       +            route, payment_secret, amount_msat, bucket_msat, amount_receiver_msat = self.sent_htlcs_routes[key]
                    if error_bytes:
                        # TODO "decode_onion_error" might raise, catch and maybe blacklist/penalise someone?
                        try:
       t@@ -1701,16 +1705,15 @@ class LNWallet(LNWorker):
        
                    # check sent_buckets if we use trampoline
                    if self.channel_db is None and payment_secret in self.sent_buckets:
       -                self.sent_buckets[payment_secret] -= amount_msat
       +                self.sent_buckets[payment_secret] -= amount_receiver_msat
                        if self.sent_buckets[payment_secret] > 0:
                            return
       -                else:
       -                    amount_msat = bucket_msat
       +                assert self.sent_buckets[payment_secret] == 0
        
                    htlc_log = HtlcLog(
                        success=False,
                        route=route,
       -                amount_msat=amount_msat,
       +                amount_msat=amount_receiver_msat,
                        error_bytes=error_bytes,
                        failure_msg=failure_message,
                        sender_idx=sender_idx)