Browse Source

lnworker: fix amount_inflight.

(amount with routing fees were used on htlc failures)
patch-4
ThomasV 4 years ago
parent
commit
5663e59863
  1. 51
      electrum/lnworker.py

51
electrum/lnworker.py

@ -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)
@ -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"
@ -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,
@ -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)
@ -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,
@ -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(
@ -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()
@ -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
@ -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,
@ -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,
@ -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:
@ -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:
@ -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()
@ -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:
@ -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)

Loading…
Cancel
Save