lnworker: fix amount_inflight.
(amount with routing fees were used on htlc failures)
This commit is contained in:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user