Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions electrum/lnpeer.py
Original file line number Diff line number Diff line change
Expand Up @@ -1943,6 +1943,7 @@ def log_fail_reason(reason: str):
except BaseException as e:
log_fail_reason(f"error sending message to next_peer={next_chan.node_id.hex()}")
raise OnionRoutingFailure(code=OnionFailureCode.TEMPORARY_CHANNEL_FAILURE, data=outgoing_chan_upd_message)

htlc_key = serialize_htlc_key(next_chan.get_scid_or_local_alias(), next_htlc.htlc_id)
return htlc_key

Expand Down Expand Up @@ -2297,6 +2298,9 @@ def log_fail_reason(reason: str):
else:
return None, None

if payment_hash.hex() in self.lnworker.dont_settle_htlcs:
return None, None

chan.opening_fee = None
self.logger.info(f"maybe_fulfill_htlc. will FULFILL HTLC: chan {chan.short_channel_id}. htlc={str(htlc)}")
return preimage, None
Expand Down
14 changes: 11 additions & 3 deletions electrum/lnworker.py
Original file line number Diff line number Diff line change
Expand Up @@ -812,6 +812,7 @@ def __init__(self, wallet: 'Abstract_Wallet', xprv):
self.active_forwardings = self.db.get_dict('active_forwardings') # type: Dict[str, List[str]] # Dict: payment_key -> list of htlc_keys
self.forwarding_failures = self.db.get_dict('forwarding_failures') # type: Dict[str, Tuple[str, str]] # Dict: payment_key -> (error_bytes, error_message)
self.downstream_to_upstream_htlc = {} # type: Dict[str, str] # Dict: htlc_key -> htlc_key (not persisted)
self.dont_settle_htlcs = self.db.get_dict('dont_settle_htlcs') # type: Dict[str, None] # payment_hashes of htlcs that we should not settle back yet even if we have the preimage

# payment_hash -> callback:
self.hold_invoice_callbacks = {} # type: Dict[bytes, Callable[[bytes], Awaitable[None]]]
Expand Down Expand Up @@ -1176,6 +1177,9 @@ async def open_channel_just_in_time(
) -> str:
# if an exception is raised during negotiation, we raise an OnionRoutingFailure.
# this will cancel the incoming HTLC

# prevent settling the htlc until the channel opening was successfull so we can fail it if needed
self.dont_settle_htlcs[payment_hash.hex()] = None
try:
funding_sat = 2 * (next_amount_msat_htlc // 1000) # try to fully spend htlcs
password = self.wallet.get_unlocked_password() if self.wallet.has_password() else None
Expand Down Expand Up @@ -1210,13 +1214,17 @@ async def wait_for_preimage():
while self.get_preimage(payment_hash) is None:
await asyncio.sleep(1)
await util.wait_for2(wait_for_preimage(), LN_P2P_NETWORK_TIMEOUT)

# We have been paid and can broadcast
# todo: if broadcasting raise an exception, we should try to rebroadcast
await self.network.broadcast_transaction(funding_tx)
except OnionRoutingFailure:
raise
except Exception:
raise OnionRoutingFailure(code=OnionFailureCode.TEMPORARY_NODE_FAILURE, data=b'')
# We have been paid and can broadcast
# todo: if broadcasting raise an exception, we should try to rebroadcast
await self.network.broadcast_transaction(funding_tx)
finally:
del self.dont_settle_htlcs[payment_hash.hex()]

htlc_key = serialize_htlc_key(next_chan.get_scid_or_local_alias(), htlc.htlc_id)
return htlc_key

Expand Down
1 change: 1 addition & 0 deletions tests/test_lnpeer.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@ def __init__(self, *, local_keypair: Keypair, chans: Iterable['Channel'], tx_que
self.preimages = {}
self.stopping_soon = False
self.downstream_to_upstream_htlc = {}
self.dont_settle_htlcs = {}
self.hold_invoice_callbacks = {}
self.payment_bundles = [] # lists of hashes. todo:persist
self.config.INITIAL_TRAMPOLINE_FEE_LEVEL = 0
Expand Down