lnworker: stop setting static jit alias for jit channel
What changed, and why it matters
This change fixes a bug in Electrum's Lightning 'just-in-time' (JIT) channel feature. Previously, every JIT channel opened with the same Lightning service provider (LSP) was being assigned the same internal identifier derived from the LSP's public key. That made it impossible to tell multiple JIT channels apart, which could confuse routing and prevent a user from having more than one usable JIT channel with the same LSP. The patch stops setting that duplicate identifier and instead relies on a remote alias already received when the channel becomes ready. A test is added to verify that two JIT channels can be opened successfully.
Reviewers should confirm that removing the static alias does not leave any code path expecting that alias, and that on_channel_ready's saved alias is always present before HTLC forwarding. Users running Lightning JIT channels should update to avoid routing/channel-lookup issues with the same LSP.
Security signals we found
Lightning channel alias collision removed
JIT channel identifier now uses remote-provided scid alias
Functional test added for multiple JIT channels with same LSP
Evidence from the diff
In electrum/lnworker.py, the JIT channel opening flow no longer calls next_chan.save_remote_scid_alias(self._scid_alias_of_node(next_peer.pubkey)). The static alias based on the peer’s node ID was redundant because on_channel_ready already stores a remote scid alias after the zero-confirmation channel reaches open state. Reusing the same static alias across multiple JIT channels with one LSP caused alias collisions and broke channel differentiation. The regtest ‘just_in_time’ is extended to open a second JIT channel and assert that Alice ends up with two channels.
Changed components
electrum/lnworker.pytests/regtest/regtest.shInspect captured patch +19 / −6
diff --git a/electrum/lnworker.py b/electrum/lnworker.py
index 8e39e78..5bc933a 100644
--- a/electrum/lnworker.py
+++ b/electrum/lnworker.py
@@ -1511,8 +1511,7 @@ class LNWallet(Logger):
while not next_chan.is_open():
await asyncio.sleep(1)
await util.wait_for2(wait_for_channel(), LN_P2P_NETWORK_TIMEOUT)
- next_chan.save_remote_scid_alias(self._scid_alias_of_node(next_peer.pubkey))
- self.logger.info(f'JIT channel is open')
+ self.logger.info(f'JIT channel is open (will forward htlc and await preimage now)')
next_amount_msat_htlc -= channel_opening_fee
# fixme: some checks are missing
htlc = next_peer.send_htlc(
diff --git a/tests/regtest/regtest.sh b/tests/regtest/regtest.sh
index e51af80..f9f1975 100755
--- a/tests/regtest/regtest.sh
+++ b/tests/regtest/regtest.sh
@@ -779,10 +779,24 @@ if [[ $1 == "just_in_time" ]]; then
echo "carol pays alice"
# note: set amount to 0.001 to test failure: 'payment too low'
invoice=$($alice add_request 0.01 --lightning --memo "invoice" | jq -r ".lightning_invoice")
- success=$($carol lnpay $invoice| jq '.success')
- if [[ $success != "true" ]]; then
- echo "JIT payment failed"
- exit 1
+ success=$($carol lnpay $invoice | jq -r ".success")
+ if [[ "$success" != "true" ]]; then
+ echo "jit payment failed"
+ exit 1
+ fi
+ # try again, multiple jit openings should work without issues
+ new_blocks 3
+ echo "carol pays alice again"
+ invoice=$($alice add_request 0.04 --lightning --memo "invoice2" | jq -r ".lightning_invoice")
+ success=$($carol lnpay $invoice | jq -r ".success")
+ if [[ "$success" != "true" ]]; then
+ echo "jit payment failed"
+ exit 1
+ fi
+ alice_chan_count=$($alice list_channels | jq '. | length')
+ if [[ "$alice_chan_count" != "2" ]]; then
+ echo "alice should have two jit channels"
+ exit 1
fi
fi
Why this scored 26/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.