76
76
create_trampoline_route_and_onion , is_legacy_relay , trampolines_by_id , hardcoded_trampoline_nodes ,
77
77
is_hardcoded_trampoline
78
78
)
79
+ from .network import TxBroadcastServerReturnedError
79
80
80
81
if TYPE_CHECKING :
81
82
from .network import Network
@@ -1129,7 +1130,7 @@ def get_lightning_history(self) -> Dict[str, LightningHistoryItem]:
1129
1130
balance_msat = sum ([x .amount_msat for x in out .values ()])
1130
1131
lb = sum (chan .balance (LOCAL ) if not chan .is_closed_or_closing () else 0
1131
1132
for chan in self .channels .values ())
1132
- assert balance_msat == lb
1133
+ assert balance_msat == lb , f"balance_msat: { balance_msat } != lb: { lb } "
1133
1134
return out
1134
1135
1135
1136
def get_groups_for_onchain_history (self ) -> Dict [str , str ]:
@@ -1250,6 +1251,7 @@ async def open_channel_just_in_time(
1250
1251
1251
1252
# prevent settling the htlc until the channel opening was successfull so we can fail it if needed
1252
1253
self .dont_settle_htlcs [payment_hash .hex ()] = None
1254
+ funding_tx = None
1253
1255
try :
1254
1256
funding_sat = 2 * (next_amount_msat_htlc // 1000 ) # try to fully spend htlcs
1255
1257
password = self .wallet .get_unlocked_password () if self .wallet .has_password () else None
@@ -1268,10 +1270,9 @@ async def open_channel_just_in_time(
1268
1270
)
1269
1271
async def wait_for_channel ():
1270
1272
while not next_chan .is_open ():
1271
- await asyncio .sleep (1 )
1273
+ await asyncio .sleep (0. 1 )
1272
1274
await util .wait_for2 (wait_for_channel (), LN_P2P_NETWORK_TIMEOUT )
1273
- next_chan .save_remote_scid_alias (self ._scid_alias_of_node (next_peer .pubkey ))
1274
- self .logger .info (f'JIT channel is open' )
1275
+ self .logger .info (f'JIT channel is open (funding not broadcasted yet)' )
1275
1276
next_amount_msat_htlc -= channel_opening_fee
1276
1277
# fixme: some checks are missing
1277
1278
htlc = next_peer .send_htlc (
@@ -1282,30 +1283,82 @@ async def wait_for_channel():
1282
1283
onion = next_onion )
1283
1284
async def wait_for_preimage ():
1284
1285
while self .get_preimage (payment_hash ) is None :
1285
- await asyncio .sleep (1 )
1286
- await util .wait_for2 (wait_for_preimage (), LN_P2P_NETWORK_TIMEOUT )
1287
-
1288
- # We have been paid and can broadcast
1289
- # todo: if broadcasting raise an exception, we should try to rebroadcast
1290
- await self .network .broadcast_transaction (funding_tx )
1286
+ await asyncio .sleep (0.1 )
1287
+ try :
1288
+ await util .wait_for2 (wait_for_preimage (), LN_P2P_NETWORK_TIMEOUT )
1289
+ except asyncio .TimeoutError :
1290
+ self .logger .info (
1291
+ f"jit opening didn't get preimage, removing chan { next_chan .get_id_for_log ()} again" )
1292
+ await self .cleanup_failed_jit_channel (next_chan )
1293
+ raise
1291
1294
except OnionRoutingFailure :
1292
1295
raise
1293
1296
except Exception :
1294
1297
raise OnionRoutingFailure (code = OnionFailureCode .TEMPORARY_NODE_FAILURE , data = b'' )
1298
+
1299
+ disable_zeroconf = True
1300
+ try :
1301
+ # after 10 mins `update_unfunded_state` will remove the channel on client side so we can fail here too
1302
+ await util .wait_for2 (self .broadcast_jit_channel_and_wait_for_mempool (next_chan , funding_tx ), 60 * 10 - 30 )
1303
+ disable_zeroconf = False
1304
+ except Exception :
1305
+ # the risk of the funding tx getting mined later is low as we weren't able to get it into the mempool
1306
+ self .preimages .pop (payment_hash .hex (), None )
1307
+ await self .cleanup_failed_jit_channel (next_chan )
1308
+ raise OnionRoutingFailure (code = OnionFailureCode .TEMPORARY_NODE_FAILURE , data = b'' )
1295
1309
finally :
1310
+ if disable_zeroconf :
1311
+ self .logger .warning (f"disabling zeroconf channels to prevent further issues. Check your wallet for consistency." )
1312
+ self .config .ACCEPT_ZEROCONF_CHANNELS = False
1313
+ self .features &= ~ LnFeatures .OPTION_ZEROCONF_OPT
1296
1314
del self .dont_settle_htlcs [payment_hash .hex ()]
1297
1315
1298
1316
htlc_key = serialize_htlc_key (next_chan .get_scid_or_local_alias (), htlc .htlc_id )
1299
1317
return htlc_key
1300
1318
1319
+ async def cleanup_failed_jit_channel (self , chan : Channel ):
1320
+ """Closes a channel that has no published funding tx (e.g. in case of a failed jit open)"""
1321
+ try :
1322
+ # try to send shutdown to signal peer that channel is dead
1323
+ await util .wait_for2 (self .close_channel (chan .channel_id ), LN_P2P_NETWORK_TIMEOUT )
1324
+ except Exception :
1325
+ self .logger .debug (f"chan shutdown to failed zeroconf peer failed " , exc_info = True )
1326
+ chan .set_state (ChannelState .REDEEMED , force = True )
1327
+ self .lnwatcher .adb .remove_transaction (chan .funding_outpoint .txid )
1328
+ self .lnwatcher .unwatch_channel (chan .get_funding_address (), chan .funding_outpoint .to_str ())
1329
+ self .remove_channel (chan .channel_id )
1330
+
1331
+ async def broadcast_jit_channel_and_wait_for_mempool (self , channel : Channel , funding_tx : Transaction ) -> None :
1332
+ last_broadcast_attempt = 0
1333
+ while True :
1334
+ if time .time () - last_broadcast_attempt > 60 :
1335
+ try :
1336
+ await self .network .broadcast_transaction (funding_tx )
1337
+ self .logger .info (f"broadcasted jit channel open txid: { funding_tx .txid ()} " )
1338
+ except TxBroadcastServerReturnedError :
1339
+ self .logger .error (f"we constructed a weird JIT funding tx. Reverting channel again." , exc_info = True )
1340
+ raise
1341
+ except Exception :
1342
+ self .logger .warning (f"Broadcasting jit channel open tx { funding_tx .txid ()} failed." , exc_info = True )
1343
+ last_broadcast_attempt = time .time ()
1344
+
1345
+ # check if the funding tx is at least in the mempool by now
1346
+ funding_info = channel .get_funding_height ()
1347
+ if funding_info is not None :
1348
+ _ , height , _ = funding_info
1349
+ if height > TX_HEIGHT_LOCAL :
1350
+ return
1351
+
1352
+ await asyncio .sleep (1 )
1353
+
1301
1354
@log_exceptions
1302
1355
async def open_channel_with_peer (
1303
1356
self , peer , funding_sat , * ,
1304
1357
push_sat : int = 0 ,
1305
1358
public : bool = False ,
1306
1359
zeroconf : bool = False ,
1307
1360
opening_fee : int = None ,
1308
- password = None ):
1361
+ password = None ) -> Tuple [ Channel , PartialTransaction ] :
1309
1362
if self .config .ENABLE_ANCHOR_CHANNELS :
1310
1363
self .wallet .unlock (password )
1311
1364
coins = self .wallet .get_spendable_coins (None )
0 commit comments