What changed, and why it matters
This commit is a minor code cleanup following a previous change. It renames a parameter, adds type hints, switches some function calls to use keyword arguments, and adds a couple of safety assertions. There is no indication it fixes a security bug or introduces a vulnerability.
No security action required. Treat as ordinary maintenance/refactoring commit.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch is a follow-up refactor in Electrum’s Lightning code. Key changes: (1) Channel.__init__ now accepts StoredDict | dict and asserts self.db_lock is set; (2) Peer.create_channel_storage is converted to keyword-only parameters with type annotations and returns dict; (3) call sites are updated to use keyword arguments; (4) LNWallet.add_new_channel is renamed from chan to temp_chan for clarity and an assertion is added that the persisted storage becomes a StoredDict. No functional security behavior is altered.
Changed components
electrum/lnchannel.pyelectrum/lnpeer.pyelectrum/lnworker.pyInspect captured patch +37 / −12
diff --git a/electrum/lnchannel.py b/electrum/lnchannel.py
index 10789af..56595ee 100644
--- a/electrum/lnchannel.py
+++ b/electrum/lnchannel.py
@@ -778,7 +778,7 @@ class Channel(AbstractChannel):
def __init__(
self,
- state: 'StoredDict', *,
+ state: 'StoredDict | dict', *,
name=None,
lnworker: 'LNWallet',
initial_feerate=None,
@@ -792,6 +792,7 @@ class Channel(AbstractChannel):
self.lnworker = lnworker
self.storage = state
self.db_lock = threading.RLock() if type(self.storage) is dict else self.storage.lock
+ assert self.db_lock
self.config = {}
self.config[LOCAL] = state["local_config"]
self.config[REMOTE] = state["remote_config"]
diff --git a/electrum/lnpeer.py b/electrum/lnpeer.py
index a85d3a2..4b88f87 100644
--- a/electrum/lnpeer.py
+++ b/electrum/lnpeer.py
@@ -1178,7 +1178,13 @@ class Peer(Logger, EventListener):
funding_txn_minimum_depth=funding_txn_minimum_depth
)
storage = self.create_channel_storage(
- channel_id, outpoint, local_config, remote_config, constraints, our_channel_type)
+ channel_id=channel_id,
+ outpoint=outpoint,
+ local_config=local_config,
+ remote_config=remote_config,
+ constraints=constraints,
+ channel_type=our_channel_type,
+ )
# temporary channel object, not stored (storage is a dict)
temp_chan = Channel(
storage,
@@ -1217,7 +1223,15 @@ class Peer(Logger, EventListener):
self.send_channel_ready(chan)
return chan, funding_tx
- def create_channel_storage(self, channel_id, outpoint, local_config, remote_config, constraints, channel_type):
+ def create_channel_storage(
+ self, *,
+ channel_id: bytes,
+ outpoint: Outpoint,
+ local_config: LocalConfig,
+ remote_config: RemoteConfig,
+ constraints: ChannelConstraints,
+ channel_type: ChannelType,
+ ) -> dict:
chan_dict = {
"node_id": self.pubkey.hex(),
"channel_id": channel_id.hex(),
@@ -1406,7 +1420,13 @@ class Peer(Logger, EventListener):
)
outpoint = Outpoint(funding_txid, funding_idx)
chan_dict = self.create_channel_storage(
- channel_id, outpoint, local_config, remote_config, constraints, channel_type)
+ channel_id=channel_id,
+ outpoint=outpoint,
+ local_config=local_config,
+ remote_config=remote_config,
+ constraints=constraints,
+ channel_type=channel_type,
+ )
# temporary channel object, not stored (storage is a dict)
temp_chan = Channel(
chan_dict,
diff --git a/electrum/lnworker.py b/electrum/lnworker.py
index d9d0429..1a705d5 100644
--- a/electrum/lnworker.py
+++ b/electrum/lnworker.py
@@ -91,6 +91,7 @@ from .trampoline import (
create_trampoline_route_and_onion, is_legacy_relay, trampolines_by_id, hardcoded_trampoline_nodes,
is_hardcoded_trampoline, decode_routing_info, encode_next_trampolines, decode_next_trampolines
)
+from .stored_dict import StoredDict
if TYPE_CHECKING:
from .network import Network
@@ -1661,21 +1662,24 @@ class LNWallet(Logger):
self._channels[chan.channel_id] = chan
self.lnwatcher.add_channel(chan)
- def add_new_channel(self, chan: Channel):
- # delete the old channel object, becauses it uses a dict
- assert type(chan.storage) is dict
- channel_id = chan.channel_id.hex()
+ def add_new_channel(self, temp_chan: Channel) -> Channel:
+ """Add a new channel into the persisted DB.
+ Deletes the given temporary channel object, because it uses a simple dict.
+ """
+ assert type(temp_chan.storage) is dict
+ channel_id = temp_chan.channel_id.hex()
channels_db = self.db.get_dict('channels')
- channels_db[channel_id] = chan.storage
- jit_opening_fee = chan.jit_opening_fee
- peer_state = chan.peer_state
- del chan
+ channels_db[channel_id] = temp_chan.storage
+ jit_opening_fee = temp_chan.jit_opening_fee
+ peer_state = temp_chan.peer_state
+ del temp_chan
storage = channels_db[channel_id] # StoredDict
chan = Channel(
storage,
lnworker=self,
jit_opening_fee=jit_opening_fee,
)
+ assert type(chan.storage) is StoredDict, type(chan.storage)
chan.peer_state = peer_state
self.add_channel(chan)
self.wallet.set_reserved_addresses_for_chan(chan, reserved=True)
Why this scored 15/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.