Browse Source

create_trampoline_route: check that we can pay the amount and the fees, and that the route is sane

patch-4
ThomasV 4 years ago
parent
commit
c9d6d11604
  1. 39
      electrum/lnworker.py

39
electrum/lnworker.py

@ -1281,6 +1281,7 @@ class LNWallet(LNWorker):
def create_trampoline_route( def create_trampoline_route(
self, amount_msat:int, self, amount_msat:int,
min_cltv_expiry:int,
invoice_pubkey:bytes, invoice_pubkey:bytes,
invoice_features:int, invoice_features:int,
channels: List[Channel], channels: List[Channel],
@ -1304,16 +1305,17 @@ class LNWallet(LNWorker):
else: else:
is_legacy = True is_legacy = True
# 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()
# Find a trampoline. We assume we have a direct channel to trampoline # Find a trampoline. We assume we have a direct channel to trampoline
for chan in channels: for chan in channels:
if not self.is_trampoline_peer(chan.node_id): if not self.is_trampoline_peer(chan.node_id):
continue continue
if chan.is_active() and chan.can_pay(amount_msat, check_frozen=True):
trampoline_short_channel_id = chan.short_channel_id trampoline_short_channel_id = chan.short_channel_id
trampoline_node_id = chan.node_id trampoline_node_id = chan.node_id
break
else:
raise NoPathFound()
# use attempt number to decide fee and second trampoline # use attempt number to decide fee and second trampoline
# we need a state with the list of nodes we have not tried # we need a state with the list of nodes we have not tried
# add optional second trampoline # add optional second trampoline
@ -1323,15 +1325,6 @@ class LNWallet(LNWorker):
if node_id != trampoline_node_id: if node_id != trampoline_node_id:
trampoline2 = node_id trampoline2 = node_id
break 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 # node_features is only used to determine is_tlv
trampoline_features = LnFeatures.VAR_ONION_OPT trampoline_features = LnFeatures.VAR_ONION_OPT
# hop to trampoline # hop to trampoline
@ -1384,6 +1377,20 @@ class LNWallet(LNWorker):
fee_proportional_millionths=0, fee_proportional_millionths=0,
cltv_expiry_delta=0, cltv_expiry_delta=0,
node_features=trampoline_features)) 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:
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 return route
@profiler @profiler
@ -1422,7 +1429,6 @@ class LNWallet(LNWorker):
# preference -funds = (low rating=high preference). # preference -funds = (low rating=high preference).
split_configurations = suggest_splits(amount_msat, channels_with_funds) split_configurations = suggest_splits(amount_msat, channels_with_funds)
for s in split_configurations: for s in split_configurations:
self.logger.info(f"trying split configuration: {s[0]} rating: {s[1]}")
routes = [] routes = []
try: try:
for chanid, part_amount_msat in s[0].items(): for chanid, part_amount_msat in s[0].items():
@ -1441,11 +1447,12 @@ class LNWallet(LNWorker):
channel, channel,
full_path=None) full_path=None)
routes.append((route, amt)) routes.append((route, amt))
self.logger.info(f"found acceptable split configuration: {list(s[0].values())} rating: {s[1]}")
break break
except NoPathFound: except NoPathFound:
continue continue
else: else:
raise NoPathFound raise NoPathFound()
return routes return routes
def create_route_for_payment( def create_route_for_payment(
@ -1461,7 +1468,7 @@ class LNWallet(LNWorker):
channels = [outgoing_channel] if outgoing_channel else list(self.channels.values()) channels = [outgoing_channel] if outgoing_channel else list(self.channels.values())
if not self.channel_db: if not self.channel_db:
route = self.create_trampoline_route( 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 return route, amount_msat
route = None route = None

Loading…
Cancel
Save