Skip to content

Commit 109ad2b

Browse files
committed
add mechanism to block htlcs from settling back
1 parent 4917f7e commit 109ad2b

File tree

3 files changed

+16
-3
lines changed

3 files changed

+16
-3
lines changed

electrum/lnpeer.py

+4
Original file line numberDiff line numberDiff line change
@@ -1943,6 +1943,7 @@ def log_fail_reason(reason: str):
19431943
except BaseException as e:
19441944
log_fail_reason(f"error sending message to next_peer={next_chan.node_id.hex()}")
19451945
raise OnionRoutingFailure(code=OnionFailureCode.TEMPORARY_CHANNEL_FAILURE, data=outgoing_chan_upd_message)
1946+
19461947
htlc_key = serialize_htlc_key(next_chan.get_scid_or_local_alias(), next_htlc.htlc_id)
19471948
return htlc_key
19481949

@@ -2297,6 +2298,9 @@ def log_fail_reason(reason: str):
22972298
else:
22982299
return None, None
22992300

2301+
if payment_hash.hex() in self.lnworker.dont_settle_htlcs:
2302+
return None, None
2303+
23002304
chan.opening_fee = None
23012305
self.logger.info(f"maybe_fulfill_htlc. will FULFILL HTLC: chan {chan.short_channel_id}. htlc={str(htlc)}")
23022306
return preimage, None

electrum/lnworker.py

+11-3
Original file line numberDiff line numberDiff line change
@@ -812,6 +812,7 @@ def __init__(self, wallet: 'Abstract_Wallet', xprv):
812812
self.active_forwardings = self.db.get_dict('active_forwardings') # type: Dict[str, List[str]] # Dict: payment_key -> list of htlc_keys
813813
self.forwarding_failures = self.db.get_dict('forwarding_failures') # type: Dict[str, Tuple[str, str]] # Dict: payment_key -> (error_bytes, error_message)
814814
self.downstream_to_upstream_htlc = {} # type: Dict[str, str] # Dict: htlc_key -> htlc_key (not persisted)
815+
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
815816

816817
# payment_hash -> callback:
817818
self.hold_invoice_callbacks = {} # type: Dict[bytes, Callable[[bytes], Awaitable[None]]]
@@ -1176,6 +1177,9 @@ async def open_channel_just_in_time(
11761177
) -> str:
11771178
# if an exception is raised during negotiation, we raise an OnionRoutingFailure.
11781179
# this will cancel the incoming HTLC
1180+
1181+
# prevent settling the htlc until the channel opening was successfull so we can fail it if needed
1182+
self.dont_settle_htlcs[payment_hash.hex()] = None
11791183
try:
11801184
funding_sat = 2 * (next_amount_msat_htlc // 1000) # try to fully spend htlcs
11811185
password = self.wallet.get_unlocked_password() if self.wallet.has_password() else None
@@ -1210,13 +1214,17 @@ async def wait_for_preimage():
12101214
while self.get_preimage(payment_hash) is None:
12111215
await asyncio.sleep(1)
12121216
await util.wait_for2(wait_for_preimage(), LN_P2P_NETWORK_TIMEOUT)
1217+
1218+
# We have been paid and can broadcast
1219+
# todo: if broadcasting raise an exception, we should try to rebroadcast
1220+
await self.network.broadcast_transaction(funding_tx)
12131221
except OnionRoutingFailure:
12141222
raise
12151223
except Exception:
12161224
raise OnionRoutingFailure(code=OnionFailureCode.TEMPORARY_NODE_FAILURE, data=b'')
1217-
# We have been paid and can broadcast
1218-
# todo: if broadcasting raise an exception, we should try to rebroadcast
1219-
await self.network.broadcast_transaction(funding_tx)
1225+
finally:
1226+
del self.dont_settle_htlcs[payment_hash.hex()]
1227+
12201228
htlc_key = serialize_htlc_key(next_chan.get_scid_or_local_alias(), htlc.htlc_id)
12211229
return htlc_key
12221230

tests/test_lnpeer.py

+1
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ def __init__(self, *, local_keypair: Keypair, chans: Iterable['Channel'], tx_que
197197
self.preimages = {}
198198
self.stopping_soon = False
199199
self.downstream_to_upstream_htlc = {}
200+
self.dont_settle_htlcs = {}
200201
self.hold_invoice_callbacks = {}
201202
self.payment_bundles = [] # lists of hashes. todo:persist
202203
self.config.INITIAL_TRAMPOLINE_FEE_LEVEL = 0

0 commit comments

Comments
 (0)