lnworker.pay_to_node: make trampoline fee_level and failed_routes local
multiple instances of pay_to_node might run concurrently, esp for trampoline forwarding
This commit is contained in:
@@ -1294,8 +1294,8 @@ class LNWallet(LNWorker):
|
|||||||
# sometimes need to fall back to a single trampoline forwarder, at the expense
|
# sometimes need to fall back to a single trampoline forwarder, at the expense
|
||||||
# of privacy
|
# of privacy
|
||||||
use_two_trampolines = True
|
use_two_trampolines = True
|
||||||
self.trampoline_fee_level = self.INITIAL_TRAMPOLINE_FEE_LEVEL
|
trampoline_fee_level = self.INITIAL_TRAMPOLINE_FEE_LEVEL
|
||||||
self.failed_trampoline_routes = []
|
failed_trampoline_routes = []
|
||||||
start_time = time.time()
|
start_time = time.time()
|
||||||
amount_inflight = 0 # what we sent in htlcs (that receiver gets, without fees)
|
amount_inflight = 0 # what we sent in htlcs (that receiver gets, without fees)
|
||||||
nhtlcs_inflight = 0
|
nhtlcs_inflight = 0
|
||||||
@@ -1315,7 +1315,8 @@ class LNWallet(LNWorker):
|
|||||||
full_path=full_path,
|
full_path=full_path,
|
||||||
payment_hash=payment_hash,
|
payment_hash=payment_hash,
|
||||||
payment_secret=payment_secret,
|
payment_secret=payment_secret,
|
||||||
trampoline_fee_level=self.trampoline_fee_level,
|
trampoline_fee_level=trampoline_fee_level,
|
||||||
|
failed_trampoline_routes=failed_trampoline_routes,
|
||||||
use_two_trampolines=use_two_trampolines,
|
use_two_trampolines=use_two_trampolines,
|
||||||
fwd_trampoline_onion=fwd_trampoline_onion,
|
fwd_trampoline_onion=fwd_trampoline_onion,
|
||||||
channels=channels,
|
channels=channels,
|
||||||
@@ -1326,7 +1327,7 @@ class LNWallet(LNWorker):
|
|||||||
amount_inflight += sent_htlc_info.amount_receiver_msat
|
amount_inflight += sent_htlc_info.amount_receiver_msat
|
||||||
if amount_inflight > amount_to_pay: # safety belts
|
if amount_inflight > amount_to_pay: # safety belts
|
||||||
raise Exception(f"amount_inflight={amount_inflight} > amount_to_pay={amount_to_pay}")
|
raise Exception(f"amount_inflight={amount_inflight} > amount_to_pay={amount_to_pay}")
|
||||||
sent_htlc_info = sent_htlc_info._replace(trampoline_fee_level=self.trampoline_fee_level)
|
sent_htlc_info = sent_htlc_info._replace(trampoline_fee_level=trampoline_fee_level)
|
||||||
await self.pay_to_route(
|
await self.pay_to_route(
|
||||||
sent_htlc_info=sent_htlc_info,
|
sent_htlc_info=sent_htlc_info,
|
||||||
payment_hash=payment_hash,
|
payment_hash=payment_hash,
|
||||||
@@ -1338,7 +1339,7 @@ class LNWallet(LNWorker):
|
|||||||
# (e.g. attempt counter)
|
# (e.g. attempt counter)
|
||||||
util.trigger_callback('invoice_status', self.wallet, payment_hash.hex(), PR_INFLIGHT)
|
util.trigger_callback('invoice_status', self.wallet, payment_hash.hex(), PR_INFLIGHT)
|
||||||
# 3. await a queue
|
# 3. await a queue
|
||||||
self.logger.info(f"(paysession for RHASH {payment_hash.hex()}) {amount_inflight=}. {nhtlcs_inflight=}")
|
self.logger.info(f"paysession for RHASH {payment_hash.hex()} waiting... {amount_inflight=}. {nhtlcs_inflight=}")
|
||||||
htlc_log = await self.sent_htlcs_q[payment_key].get() # TODO maybe wait a bit, more failures might come
|
htlc_log = await self.sent_htlcs_q[payment_key].get() # TODO maybe wait a bit, more failures might come
|
||||||
amount_inflight -= htlc_log.amount_msat
|
amount_inflight -= htlc_log.amount_msat
|
||||||
nhtlcs_inflight -= 1
|
nhtlcs_inflight -= 1
|
||||||
@@ -1373,12 +1374,14 @@ class LNWallet(LNWorker):
|
|||||||
# trampoline
|
# trampoline
|
||||||
if self.uses_trampoline():
|
if self.uses_trampoline():
|
||||||
def maybe_raise_trampoline_fee(htlc_log):
|
def maybe_raise_trampoline_fee(htlc_log):
|
||||||
if htlc_log.trampoline_fee_level == self.trampoline_fee_level:
|
nonlocal trampoline_fee_level
|
||||||
self.trampoline_fee_level += 1
|
nonlocal failed_trampoline_routes
|
||||||
self.failed_trampoline_routes = []
|
if htlc_log.trampoline_fee_level == trampoline_fee_level:
|
||||||
self.logger.info(f'raising trampoline fee level {self.trampoline_fee_level}')
|
trampoline_fee_level += 1
|
||||||
|
failed_trampoline_routes = []
|
||||||
|
self.logger.info(f'raising trampoline fee level {trampoline_fee_level}')
|
||||||
else:
|
else:
|
||||||
self.logger.info(f'NOT raising trampoline fee level, already at {self.trampoline_fee_level}')
|
self.logger.info(f'NOT raising trampoline fee level, already at {trampoline_fee_level}')
|
||||||
# FIXME The trampoline nodes in the path are chosen randomly.
|
# FIXME The trampoline nodes in the path are chosen randomly.
|
||||||
# Some of the errors might depend on how we have chosen them.
|
# Some of the errors might depend on how we have chosen them.
|
||||||
# Having more attempts is currently useful in part because of the randomness,
|
# Having more attempts is currently useful in part because of the randomness,
|
||||||
@@ -1402,8 +1405,10 @@ class LNWallet(LNWorker):
|
|||||||
trampoline_route = htlc_log.route
|
trampoline_route = htlc_log.route
|
||||||
r = [hop.end_node.hex() for hop in trampoline_route]
|
r = [hop.end_node.hex() for hop in trampoline_route]
|
||||||
self.logger.info(f'failed trampoline route: {r}')
|
self.logger.info(f'failed trampoline route: {r}')
|
||||||
assert r not in self.failed_trampoline_routes
|
if r not in failed_trampoline_routes:
|
||||||
self.failed_trampoline_routes.append(r)
|
failed_trampoline_routes.append(r)
|
||||||
|
else:
|
||||||
|
pass # maybe the route was reused between different MPP parts
|
||||||
continue
|
continue
|
||||||
else:
|
else:
|
||||||
raise PaymentFailure(failure_msg.code_name())
|
raise PaymentFailure(failure_msg.code_name())
|
||||||
@@ -1658,6 +1663,7 @@ class LNWallet(LNWorker):
|
|||||||
payment_hash: bytes,
|
payment_hash: bytes,
|
||||||
payment_secret: bytes,
|
payment_secret: bytes,
|
||||||
trampoline_fee_level: int,
|
trampoline_fee_level: int,
|
||||||
|
failed_trampoline_routes: Iterable[Sequence[str]],
|
||||||
use_two_trampolines: bool,
|
use_two_trampolines: bool,
|
||||||
fwd_trampoline_onion=None,
|
fwd_trampoline_onion=None,
|
||||||
full_path: LNPaymentPath = None,
|
full_path: LNPaymentPath = None,
|
||||||
@@ -1731,7 +1737,7 @@ class LNWallet(LNWorker):
|
|||||||
local_height=local_height,
|
local_height=local_height,
|
||||||
trampoline_fee_level=trampoline_fee_level,
|
trampoline_fee_level=trampoline_fee_level,
|
||||||
use_two_trampolines=use_two_trampolines,
|
use_two_trampolines=use_two_trampolines,
|
||||||
failed_routes=self.failed_trampoline_routes)
|
failed_routes=failed_trampoline_routes)
|
||||||
# node_features is only used to determine is_tlv
|
# node_features is only used to determine is_tlv
|
||||||
per_trampoline_secret = os.urandom(32)
|
per_trampoline_secret = os.urandom(32)
|
||||||
per_trampoline_fees = per_trampoline_amount_with_fees - per_trampoline_amount
|
per_trampoline_fees = per_trampoline_amount_with_fees - per_trampoline_amount
|
||||||
|
|||||||
@@ -240,6 +240,7 @@ class MockLNWallet(Logger, EventListener, NetworkRetryManager[LNPeerAddr]):
|
|||||||
r_tags=decoded_invoice.get_routing_info('r'),
|
r_tags=decoded_invoice.get_routing_info('r'),
|
||||||
invoice_features=decoded_invoice.get_features(),
|
invoice_features=decoded_invoice.get_features(),
|
||||||
trampoline_fee_level=0,
|
trampoline_fee_level=0,
|
||||||
|
failed_trampoline_routes=[],
|
||||||
use_two_trampolines=False,
|
use_two_trampolines=False,
|
||||||
payment_hash=decoded_invoice.paymenthash,
|
payment_hash=decoded_invoice.paymenthash,
|
||||||
payment_secret=decoded_invoice.payment_secret,
|
payment_secret=decoded_invoice.payment_secret,
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import os
|
|||||||
import bitstring
|
import bitstring
|
||||||
import random
|
import random
|
||||||
|
|
||||||
from typing import Mapping, DefaultDict, Tuple, Optional, Dict, List
|
from typing import Mapping, DefaultDict, Tuple, Optional, Dict, List, Iterable, Sequence
|
||||||
|
|
||||||
from .lnutil import LnFeatures
|
from .lnutil import LnFeatures
|
||||||
from .lnonion import calc_hops_data_for_payment, new_onion_packet
|
from .lnonion import calc_hops_data_for_payment, new_onion_packet
|
||||||
@@ -141,7 +141,7 @@ def trampoline_policy(
|
|||||||
raise NoPathFound()
|
raise NoPathFound()
|
||||||
|
|
||||||
|
|
||||||
def extend_trampoline_route(
|
def _extend_trampoline_route(
|
||||||
route: List,
|
route: List,
|
||||||
start_node: bytes,
|
start_node: bytes,
|
||||||
end_node: bytes,
|
end_node: bytes,
|
||||||
@@ -161,7 +161,7 @@ def extend_trampoline_route(
|
|||||||
node_features=trampoline_features))
|
node_features=trampoline_features))
|
||||||
|
|
||||||
|
|
||||||
def choose_second_trampoline(my_trampoline, trampolines, failed_routes):
|
def _choose_second_trampoline(my_trampoline, trampolines, failed_routes: Iterable[Sequence[str]]):
|
||||||
if my_trampoline in trampolines:
|
if my_trampoline in trampolines:
|
||||||
trampolines.remove(my_trampoline)
|
trampolines.remove(my_trampoline)
|
||||||
for r in failed_routes:
|
for r in failed_routes:
|
||||||
@@ -184,7 +184,7 @@ def create_trampoline_route(
|
|||||||
r_tags,
|
r_tags,
|
||||||
trampoline_fee_level: int,
|
trampoline_fee_level: int,
|
||||||
use_two_trampolines: bool,
|
use_two_trampolines: bool,
|
||||||
failed_routes: list,
|
failed_routes: Iterable[Sequence[str]],
|
||||||
) -> LNPaymentRoute:
|
) -> LNPaymentRoute:
|
||||||
# we decide whether to convert to a legacy payment
|
# we decide whether to convert to a legacy payment
|
||||||
is_legacy, invoice_trampolines = is_legacy_relay(invoice_features, r_tags)
|
is_legacy, invoice_trampolines = is_legacy_relay(invoice_features, r_tags)
|
||||||
@@ -194,14 +194,14 @@ def create_trampoline_route(
|
|||||||
second_trampoline = None
|
second_trampoline = None
|
||||||
|
|
||||||
# our first trampoline hop is decided by the channel we use
|
# our first trampoline hop is decided by the channel we use
|
||||||
extend_trampoline_route(route, my_pubkey, my_trampoline, trampoline_fee_level)
|
_extend_trampoline_route(route, my_pubkey, my_trampoline, trampoline_fee_level)
|
||||||
|
|
||||||
if is_legacy:
|
if is_legacy:
|
||||||
# we add another different trampoline hop for privacy
|
# we add another different trampoline hop for privacy
|
||||||
if use_two_trampolines:
|
if use_two_trampolines:
|
||||||
trampolines = trampolines_by_id()
|
trampolines = trampolines_by_id()
|
||||||
second_trampoline = choose_second_trampoline(my_trampoline, list(trampolines.keys()), failed_routes)
|
second_trampoline = _choose_second_trampoline(my_trampoline, list(trampolines.keys()), failed_routes)
|
||||||
extend_trampoline_route(route, my_trampoline, second_trampoline, trampoline_fee_level)
|
_extend_trampoline_route(route, my_trampoline, second_trampoline, trampoline_fee_level)
|
||||||
# the last trampoline onion must contain routing hints for the last trampoline
|
# the last trampoline onion must contain routing hints for the last trampoline
|
||||||
# node to find the recipient
|
# node to find the recipient
|
||||||
invoice_routing_info = encode_routing_info(r_tags)
|
invoice_routing_info = encode_routing_info(r_tags)
|
||||||
@@ -219,11 +219,11 @@ def create_trampoline_route(
|
|||||||
else:
|
else:
|
||||||
add_trampoline = True
|
add_trampoline = True
|
||||||
if add_trampoline:
|
if add_trampoline:
|
||||||
second_trampoline = choose_second_trampoline(my_trampoline, invoice_trampolines, failed_routes)
|
second_trampoline = _choose_second_trampoline(my_trampoline, invoice_trampolines, failed_routes)
|
||||||
extend_trampoline_route(route, my_trampoline, second_trampoline, trampoline_fee_level)
|
_extend_trampoline_route(route, my_trampoline, second_trampoline, trampoline_fee_level)
|
||||||
|
|
||||||
# final edge (not part of the route if payment is legacy, but eclair requires an encrypted blob)
|
# final edge (not part of the route if payment is legacy, but eclair requires an encrypted blob)
|
||||||
extend_trampoline_route(route, route[-1].end_node, invoice_pubkey, trampoline_fee_level, pay_fees=False)
|
_extend_trampoline_route(route, route[-1].end_node, invoice_pubkey, trampoline_fee_level, pay_fees=False)
|
||||||
# check that we can pay amount and fees
|
# check that we can pay amount and fees
|
||||||
for edge in route[::-1]:
|
for edge in route[::-1]:
|
||||||
amount_msat += edge.fee_for_edge(amount_msat)
|
amount_msat += edge.fee_for_edge(amount_msat)
|
||||||
@@ -294,7 +294,7 @@ def create_trampoline_route_and_onion(
|
|||||||
local_height: int,
|
local_height: int,
|
||||||
trampoline_fee_level: int,
|
trampoline_fee_level: int,
|
||||||
use_two_trampolines: bool,
|
use_two_trampolines: bool,
|
||||||
failed_routes: list):
|
failed_routes: Iterable[Sequence[str]]):
|
||||||
# create route for the trampoline_onion
|
# create route for the trampoline_onion
|
||||||
trampoline_route = create_trampoline_route(
|
trampoline_route = create_trampoline_route(
|
||||||
amount_msat=amount_msat,
|
amount_msat=amount_msat,
|
||||||
|
|||||||
Reference in New Issue
Block a user