Skip to content

Refactor on_channel_open to accept incoming channels if the source is a trusted zeroconf node #9588

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Mar 4, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 24 additions & 18 deletions electrum/lnpeer.py
Original file line number Diff line number Diff line change
Expand Up @@ -1023,27 +1023,13 @@ async def on_open_channel(self, payload):

Channel configurations are initialized in this method.
"""
if self.lnworker.has_recoverable_channels():
# FIXME: we might want to keep the connection open
raise Exception('not accepting channels')

# <- open_channel
if payload['chain_hash'] != constants.net.rev_genesis_bytes():
raise Exception('wrong chain_hash')
funding_sat = payload['funding_satoshis']
push_msat = payload['push_msat']
feerate = payload['feerate_per_kw'] # note: we are not validating this
temp_chan_id = payload['temporary_channel_id']
# store the temp id now, so that it is recognized for e.g. 'error' messages
# TODO: this is never cleaned up; the dict grows unbounded until disconnect
self.temp_id_to_id[temp_chan_id] = None

open_channel_tlvs = payload.get('open_channel_tlvs')
channel_type = open_channel_tlvs.get('channel_type') if open_channel_tlvs else None

channel_opening_fee = open_channel_tlvs.get('channel_opening_fee') if open_channel_tlvs else None
if channel_opening_fee:
# todo check that the fee is reasonable
pass
# The receiving node MAY fail the channel if:
# option_channel_type was negotiated but the message doesn't include a channel_type
if self.is_channel_type() and channel_type is None:
Expand All @@ -1055,6 +1041,29 @@ async def on_open_channel(self, payload):
if not channel_type.complies_with_features(self.features):
raise Exception("sender has sent a channel type we don't support")

if self.is_channel_type():
is_zeroconf = bool(channel_type & ChannelType.OPTION_ZEROCONF)
if is_zeroconf and not self.network.config.ZEROCONF_TRUSTED_NODE.startswith(self.pubkey.hex()):
raise Exception(f"not accepting zeroconf from node {self.pubkey}")
else:
is_zeroconf = False

if self.lnworker.has_recoverable_channels() and not is_zeroconf:
# FIXME: we might want to keep the connection open
raise Exception('not accepting channels')

funding_sat = payload['funding_satoshis']
push_msat = payload['push_msat']
feerate = payload['feerate_per_kw'] # note: we are not validating this
temp_chan_id = payload['temporary_channel_id']
# store the temp id now, so that it is recognized for e.g. 'error' messages
# TODO: this is never cleaned up; the dict grows unbounded until disconnect
self.temp_id_to_id[temp_chan_id] = None
channel_opening_fee = open_channel_tlvs.get('channel_opening_fee') if open_channel_tlvs else None
if channel_opening_fee:
# todo check that the fee is reasonable
pass

if self.use_anchors():
multisig_funding_keypair = lnutil.derive_multisig_funding_key_if_they_opened(
funding_root_secret=self.lnworker.funding_root_keypair.privkey,
Expand Down Expand Up @@ -1115,9 +1124,6 @@ async def on_open_channel(self, payload):
per_commitment_point_first = secret_to_pubkey(
int.from_bytes(per_commitment_secret_first, 'big'))

is_zeroconf = channel_type & channel_type.OPTION_ZEROCONF
if is_zeroconf and not self.network.config.ZEROCONF_TRUSTED_NODE.startswith(self.pubkey.hex()):
raise Exception(f"not accepting zeroconf from node {self.pubkey}")
min_depth = 0 if is_zeroconf else 3

accept_channel_tlvs = {
Expand Down