@ -1225,6 +1225,7 @@ class LNWallet(LNWorker):
# of privacy
use_two_trampolines = True
self . trampoline_fee_level = self . INITIAL_TRAMPOLINE_FEE_LEVEL
self . failed_trampoline_routes = [ ]
start_time = time . time ( )
amount_inflight = 0 # what we sent in htlcs (that receiver gets, without fees)
while True :
@ -1249,7 +1250,7 @@ class LNWallet(LNWorker):
channels = channels ,
)
# 2. send htlcs
async for route , amount_msat , total_msat , amount_receiver_msat , cltv_delta , bucket_payment_secret , trampoline_onion in routes :
async for route , amount_msat , total_msat , amount_receiver_msat , cltv_delta , bucket_payment_secret , trampoline_onion , trampoline_route in routes :
amount_inflight + = amount_receiver_msat
if amount_inflight > amount_to_pay : # safety belts
raise Exception ( f " amount_inflight= { amount_inflight } > amount_to_pay= { amount_to_pay } " )
@ -1262,7 +1263,8 @@ class LNWallet(LNWorker):
payment_secret = bucket_payment_secret ,
min_cltv_expiry = cltv_delta ,
trampoline_onion = trampoline_onion ,
trampoline_fee_level = self . trampoline_fee_level )
trampoline_fee_level = self . trampoline_fee_level ,
trampoline_route = trampoline_route )
util . trigger_callback ( ' invoice_status ' , self . wallet , payment_hash . hex ( ) )
# 3. await a queue
self . logger . info ( f " amount inflight { amount_inflight } " )
@ -1301,6 +1303,7 @@ class LNWallet(LNWorker):
def maybe_raise_trampoline_fee ( htlc_log ) :
if htlc_log . trampoline_fee_level == self . trampoline_fee_level :
self . trampoline_fee_level + = 1
self . failed_trampoline_routes = [ ]
self . logger . info ( f ' raising trampoline fee level { self . trampoline_fee_level } ' )
else :
self . logger . info ( f ' NOT raising trampoline fee level, already at { self . trampoline_fee_level } ' )
@ -1322,7 +1325,11 @@ class LNWallet(LNWorker):
OnionFailureCode . UNKNOWN_NEXT_PEER ,
OnionFailureCode . TEMPORARY_NODE_FAILURE ,
OnionFailureCode . TEMPORARY_CHANNEL_FAILURE ) :
maybe_raise_trampoline_fee ( htlc_log )
trampoline_route = htlc_log . route
r = [ hop . end_node . hex ( ) for hop in trampoline_route ]
self . logger . info ( f ' failed trampoline route: { r } ' )
assert r not in self . failed_trampoline_routes
self . failed_trampoline_routes . append ( r )
continue
else :
raise PaymentFailure ( failure_msg . code_name ( ) )
@ -1340,7 +1347,8 @@ class LNWallet(LNWorker):
payment_secret : Optional [ bytes ] ,
min_cltv_expiry : int ,
trampoline_onion : bytes = None ,
trampoline_fee_level : int ) - > None :
trampoline_fee_level : int ,
trampoline_route : Optional [ List ] ) - > None :
# send a single htlc
short_channel_id = route [ 0 ] . short_channel_id
@ -1360,7 +1368,7 @@ class LNWallet(LNWorker):
trampoline_onion = trampoline_onion )
key = ( payment_hash , short_channel_id , htlc . htlc_id )
self . sent_htlcs_info [ key ] = route , payment_secret , amount_msat , total_msat , amount_receiver_msat , trampoline_fee_level
self . sent_htlcs_info [ key ] = route , payment_secret , amount_msat , total_msat , amount_receiver_msat , trampoline_fee_level , trampoline_route
# 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 :
@ -1588,7 +1596,8 @@ class LNWallet(LNWorker):
payment_secret = payment_secret ,
local_height = local_height ,
trampoline_fee_level = trampoline_fee_level ,
use_two_trampolines = use_two_trampolines )
use_two_trampolines = use_two_trampolines ,
failed_routes = self . failed_trampoline_routes )
trampoline_payment_secret = os . urandom ( 32 )
trampoline_total_msat = amount_with_fees
if chan . available_to_spend ( LOCAL , strict = True ) < amount_with_fees :
@ -1605,7 +1614,7 @@ class LNWallet(LNWorker):
cltv_expiry_delta = 0 ,
node_features = trampoline_features )
]
yield route , amount_with_fees , trampoline_total_msat , amount_msat , cltv_delta , trampoline_payment_secret , trampoline_onion
yield route , amount_with_fees , trampoline_total_msat , amount_msat , cltv_delta , trampoline_payment_secret , trampoline_onion , trampoline_route
break
else :
raise NoPathFound ( )
@ -1622,7 +1631,7 @@ class LNWallet(LNWorker):
full_path = full_path
)
)
yield route , amount_msat , final_total_msat , amount_msat , min_cltv_expiry , payment_secret , fwd_trampoline_onion
yield route , amount_msat , final_total_msat , amount_msat , min_cltv_expiry , payment_secret , fwd_trampoline_onion , None
except NoPathFound : # fall back to payment splitting
self . logger . info ( " no path found, trying multi-part payment " )
if not invoice_features . supports ( LnFeatures . BASIC_MPP_OPT ) :
@ -1672,7 +1681,8 @@ class LNWallet(LNWorker):
payment_secret = payment_secret ,
local_height = local_height ,
trampoline_fee_level = trampoline_fee_level ,
use_two_trampolines = use_two_trampolines )
use_two_trampolines = use_two_trampolines ,
failed_routes = self . failed_trampoline_routes )
# node_features is only used to determine is_tlv
per_trampoline_secret = os . urandom ( 32 )
per_trampoline_fees = per_trampoline_amount_with_fees - per_trampoline_amount
@ -1697,7 +1707,7 @@ 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 , per_trampoline_amount_with_fees , part_amount_msat , per_trampoline_cltv_delta , per_trampoline_secret , trampoline_onion ) )
routes . append ( ( route , part_amount_msat_with_fees , per_trampoline_amount_with_fees , part_amount_msat , per_trampoline_cltv_delta , per_trampoline_secret , trampoline_onion , trampoline_route ) )
if per_trampoline_fees != 0 :
self . logger . info ( ' not enough margin to pay trampoline fee ' )
raise NoPathFound ( )
@ -1735,7 +1745,7 @@ class LNWallet(LNWorker):
full_path = None
)
)
yield route , part_amount_msat , final_total_msat , part_amount_msat , min_cltv_expiry , payment_secret , fwd_trampoline_onion
yield route , part_amount_msat , final_total_msat , part_amount_msat , min_cltv_expiry , payment_secret , fwd_trampoline_onion , None
yielded_from_split_configuration = True
except NoPathFound :
continue
@ -1991,7 +2001,7 @@ class LNWallet(LNWorker):
self . _on_maybe_forwarded_htlc_resolved ( chan = chan , htlc_id = htlc_id )
q = self . sent_htlcs . get ( payment_hash )
if q :
route , payment_secret , amount_msat , bucket_msat , amount_receiver_msat , trampoline_fee_level = self . sent_htlcs_info [ ( payment_hash , chan . short_channel_id , htlc_id ) ]
route , payment_secret , amount_msat , bucket_msat , amount_receiver_msat , trampoline_fee_level , trampoline_route = self . sent_htlcs_info [ ( payment_hash , chan . short_channel_id , htlc_id ) ]
htlc_log = HtlcLog (
success = True ,
route = route ,
@ -2018,7 +2028,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 , amount_receiver_msat , trampoline_fee_level = self . sent_htlcs_info [ key ]
route , payment_secret , amount_msat , bucket_msat , amount_receiver_msat , trampoline_fee_level , trampoline_route = self . sent_htlcs_info [ key ]
if error_bytes :
# TODO "decode_onion_error" might raise, catch and maybe blacklist/penalise someone?
try :
@ -2043,6 +2053,8 @@ class LNWallet(LNWorker):
self . logger . info ( ' bucket failed ' )
amount_receiver_msat = amount_sent
if trampoline_route :
route = trampoline_route
htlc_log = HtlcLog (
success = False ,
route = route ,