swaps: add check for blockchain().is_tip_stale()
What changed, and why it matters
This change adds safety checks to Electrum's submarine swap feature so it refuses to create or accept swaps if the wallet's view of the Bitcoin blockchain is outdated ('stale tip'). If the wallet acted on old blockchain data, swap locktimes could be set dangerously far in the future or too close to the present, which could let an attacker lock up funds unfairly or prevent a refund. The patch is defensive and partial: it stops the risky action but does not by itself fix whatever caused the stale tip.
Review whether is_tip_stale() threshold is appropriate for swap timing; ensure callers handle the exception gracefully; consider adding user-visible messaging; verify the stale-tip detection itself is reliable and not subject to eclipse attacks.
Security signals we found
Defensive check added to prevent acting on stale blockchain tip
Locktime-based swap safety depends on fresh local height
Stale tip could cause MAX_LOCKTIME_DELTA or MIN_LOCKTIME_DELTA checks to be bypassed or misapplied
Submarine swaps involve on-chain HTLC/refund timing, making stale height a safety issue
Evidence from the diff
The commit inserts calls to self.network.blockchain().is_tip_stale() at four points in electrum/submarine_swaps.py: before creating a reverse swap, before creating a forward swap (server side), before adding a normal swap, and before adding a reverse swap. If the local blockchain tip is stale, an exception is raised and the swap operation aborts. The locktime checks already compare against self.network.get_local_height(); a stale height could therefore make those comparisons unreliable. The patch prevents swap creation/acceptance when the local chain height is not fresh.
Changed components
electrum/submarine_swaps.pySwapManager.create_reverse_swapSwapManager.server_create_normal_swapSwapManager.add_normal_swapSwapManager.add_reverse_swapInspect captured patch +8 / −0
diff --git a/electrum/submarine_swaps.py b/electrum/submarine_swaps.py
index fd1abc2..cef15fd 100644
--- a/electrum/submarine_swaps.py
+++ b/electrum/submarine_swaps.py
@@ -595,6 +595,8 @@ class SwapManager(Logger):
if payment_hash.hex() in self._swaps:
raise Exception("payment_hash already in use")
locktime = self.network.get_local_height() + LOCKTIME_DELTA_REFUND
+ if self.network.blockchain().is_tip_stale():
+ raise Exception("our blockchain tip is stale")
our_privkey = os.urandom(32)
our_pubkey = ECPrivkey(our_privkey).get_public_key_bytes(compressed=True)
onchain_amount_sat = self._get_recv_amount(lightning_amount_sat, is_reverse=True) # what the client is going to receive
@@ -696,6 +698,8 @@ class SwapManager(Logger):
""" server method. """
assert lightning_amount_sat is not None
locktime = self.network.get_local_height() + LOCKTIME_DELTA_REFUND
+ if self.network.blockchain().is_tip_stale():
+ raise Exception("our blockchain tip is stale")
privkey = os.urandom(32)
our_pubkey = ECPrivkey(privkey).get_public_key_bytes(compressed=True)
onchain_amount_sat = self._get_send_amount(lightning_amount_sat, is_reverse=False)
@@ -881,6 +885,8 @@ class SwapManager(Logger):
# verify that they are not locking up funds for too long
if locktime - self.network.get_local_height() > MAX_LOCKTIME_DELTA:
raise Exception("fswap check failed: locktime too far in future")
+ if self.network.blockchain().is_tip_stale():
+ raise Exception("our blockchain tip is stale")
swap, invoice, _ = self.add_normal_swap(
redeem_script=redeem_script,
@@ -1065,6 +1071,8 @@ class SwapManager(Logger):
# verify that we will have enough time to get our tx confirmed
if locktime - self.network.get_local_height() <= MIN_LOCKTIME_DELTA:
raise Exception("rswap check failed: locktime too close")
+ if self.network.blockchain().is_tip_stale():
+ raise Exception("our blockchain tip is stale")
# verify invoice payment_hash
lnaddr = self.lnworker._check_bolt11_invoice(invoice)
invoice_amount = int(lnaddr.get_amount_sat())
Why this scored 58/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.