1
0

ln: require LnFeatures.OPTION_CHANNEL_TYPE as bolts now mandate it

This simplifies some code.

following 9d456b1c4a
This commit is contained in:
SomberNight
2025-12-18 16:43:19 +00:00
parent 85a45f9b1f
commit aab22a237b
3 changed files with 24 additions and 29 deletions

View File

@@ -894,9 +894,6 @@ class Peer(Logger, EventListener):
def is_shutdown_anysegwit(self): def is_shutdown_anysegwit(self):
return self.features.supports(LnFeatures.OPTION_SHUTDOWN_ANYSEGWIT_OPT) return self.features.supports(LnFeatures.OPTION_SHUTDOWN_ANYSEGWIT_OPT)
def is_channel_type(self):
return self.features.supports(LnFeatures.OPTION_CHANNEL_TYPE_OPT)
def accepts_zeroconf(self): def accepts_zeroconf(self):
return self.features.supports(LnFeatures.OPTION_ZEROCONF_OPT) return self.features.supports(LnFeatures.OPTION_ZEROCONF_OPT)
@@ -936,10 +933,11 @@ class Peer(Logger, EventListener):
# flexibility to decide an address at closing time # flexibility to decide an address at closing time
upfront_shutdown_script = b'' upfront_shutdown_script = b''
if self.use_anchors(): assert channel_type is not None
if channel_type & ChannelType.OPTION_ANCHORS_ZERO_FEE_HTLC_TX: # anchors
static_payment_key = self.lnworker.static_payment_key static_payment_key = self.lnworker.static_payment_key
static_remotekey = None static_remotekey = None
else: else: # static_remotekey
assert channel_type & channel_type.OPTION_STATIC_REMOTEKEY assert channel_type & channel_type.OPTION_STATIC_REMOTEKEY
wallet = self.lnworker.wallet wallet = self.lnworker.wallet
assert wallet.txin_type == 'p2wpkh' assert wallet.txin_type == 'p2wpkh'
@@ -1055,13 +1053,12 @@ class Peer(Logger, EventListener):
# Eclair accepts channel_type with that bit, but does not require it. # Eclair accepts channel_type with that bit, but does not require it.
# if option_channel_type is negotiated: MUST set channel_type # if option_channel_type is negotiated: MUST set channel_type
if self.is_channel_type(): # if it includes channel_type: MUST set it to a defined type representing the type it wants.
# if it includes channel_type: MUST set it to a defined type representing the type it wants. open_channel_tlvs['channel_type'] = {
open_channel_tlvs['channel_type'] = { 'type': our_channel_type.to_bytes_minimal()
'type': our_channel_type.to_bytes_minimal() }
}
if self.use_anchors(): if our_channel_type & ChannelType.OPTION_ANCHORS_ZERO_FEE_HTLC_TX:
multisig_funding_keypair = lnutil.derive_multisig_funding_key_if_we_opened( multisig_funding_keypair = lnutil.derive_multisig_funding_key_if_we_opened(
funding_root_secret=self.lnworker.funding_root_keypair.privkey, funding_root_secret=self.lnworker.funding_root_keypair.privkey,
remote_node_id_or_prefix=self.pubkey, remote_node_id_or_prefix=self.pubkey,
@@ -1168,7 +1165,7 @@ class Peer(Logger, EventListener):
initial_feerate_per_kw=feerate, initial_feerate_per_kw=feerate,
config=self.network.config, config=self.network.config,
peer_features=self.features, peer_features=self.features,
has_anchors=self.use_anchors(), channel_type=our_channel_type,
) )
# -> funding created # -> funding created
@@ -1285,21 +1282,19 @@ class Peer(Logger, EventListener):
channel_type = open_channel_tlvs.get('channel_type') if open_channel_tlvs else None channel_type = open_channel_tlvs.get('channel_type') if open_channel_tlvs else None
# The receiving node MAY fail the channel if: # The receiving node MAY fail the channel if:
# option_channel_type was negotiated but the message doesn't include a channel_type # option_channel_type was negotiated but the message doesn't include a channel_type
if self.is_channel_type() and channel_type is None: if channel_type is None:
raise Exception("sender has advertised option_channel_type, but hasn't sent the channel type") raise Exception("sender has advertised option_channel_type, but hasn't sent the channel type")
# MUST fail the channel if it supports channel_type, # MUST fail the channel if it supports channel_type,
# channel_type was set, and the type is not suitable. # channel_type was set, and the type is not suitable.
elif self.is_channel_type() and channel_type is not None: else:
channel_type = ChannelType.from_bytes(channel_type['type'], byteorder='big').discard_unknown_and_check() channel_type = ChannelType.from_bytes(channel_type['type'], byteorder='big').discard_unknown_and_check()
if not channel_type.complies_with_features(self.features): if not channel_type.complies_with_features(self.features):
raise Exception("sender has sent a channel type we don't support") raise Exception("sender has sent a channel type we don't support")
assert isinstance(channel_type, ChannelType)
if self.is_channel_type(): is_zeroconf = bool(channel_type & ChannelType.OPTION_ZEROCONF)
is_zeroconf = bool(channel_type & ChannelType.OPTION_ZEROCONF) if is_zeroconf and not self.network.config.ZEROCONF_TRUSTED_NODE.startswith(self.pubkey.hex()):
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}")
raise Exception(f"not accepting zeroconf from node {self.pubkey}")
else:
is_zeroconf = False
if self.lnworker.has_recoverable_channels() and not is_zeroconf: if self.lnworker.has_recoverable_channels() and not is_zeroconf:
# FIXME: we might want to keep the connection open # FIXME: we might want to keep the connection open
@@ -1324,7 +1319,7 @@ class Peer(Logger, EventListener):
self.logger.info(f"just-in-time opening fee: {channel_opening_fee} msat") self.logger.info(f"just-in-time opening fee: {channel_opening_fee} msat")
pass pass
if self.use_anchors(): if channel_type & ChannelType.OPTION_ANCHORS_ZERO_FEE_HTLC_TX:
multisig_funding_keypair = lnutil.derive_multisig_funding_key_if_they_opened( multisig_funding_keypair = lnutil.derive_multisig_funding_key_if_they_opened(
funding_root_secret=self.lnworker.funding_root_keypair.privkey, funding_root_secret=self.lnworker.funding_root_keypair.privkey,
remote_node_id_or_prefix=self.pubkey, remote_node_id_or_prefix=self.pubkey,
@@ -1370,7 +1365,7 @@ class Peer(Logger, EventListener):
initial_feerate_per_kw=feerate, initial_feerate_per_kw=feerate,
config=self.network.config, config=self.network.config,
peer_features=self.features, peer_features=self.features,
has_anchors=self.use_anchors(), channel_type=channel_type,
) )
channel_flags = ord(payload['channel_flags']) channel_flags = ord(payload['channel_flags'])
@@ -1390,12 +1385,10 @@ class Peer(Logger, EventListener):
'upfront_shutdown_script': { 'upfront_shutdown_script': {
'shutdown_scriptpubkey': local_config.upfront_shutdown_script 'shutdown_scriptpubkey': local_config.upfront_shutdown_script
}, },
'channel_type': {
'type': channel_type.to_bytes_minimal(),
},
} }
# The sender: if it sets channel_type: MUST set it to the channel_type from open_channel
if self.is_channel_type():
accept_channel_tlvs['channel_type'] = {
'type': channel_type.to_bytes_minimal()
}
self.send_message( self.send_message(
'accept_channel', 'accept_channel',

View File

@@ -170,8 +170,9 @@ class ChannelConfig(StoredObject):
initial_feerate_per_kw: int, initial_feerate_per_kw: int,
config: 'SimpleConfig', config: 'SimpleConfig',
peer_features: 'LnFeatures', peer_features: 'LnFeatures',
has_anchors: bool, channel_type: 'ChannelType',
) -> None: ) -> None:
has_anchors = bool(channel_type & ChannelType.OPTION_ANCHORS_ZERO_FEE_HTLC_TX)
# first we validate the configs separately # first we validate the configs separately
local_config.validate_params(funding_sat=funding_sat, config=config, peer_features=peer_features) local_config.validate_params(funding_sat=funding_sat, config=config, peer_features=peer_features)
remote_config.validate_params(funding_sat=funding_sat, config=config, peer_features=peer_features) remote_config.validate_params(funding_sat=funding_sat, config=config, peer_features=peer_features)
@@ -1621,7 +1622,7 @@ class ChannelType(IntFlag):
OPTION_SCID_ALIAS = 1 << 46 OPTION_SCID_ALIAS = 1 << 46
OPTION_ZEROCONF = 1 << 50 OPTION_ZEROCONF = 1 << 50
def discard_unknown_and_check(self): def discard_unknown_and_check(self) -> 'ChannelType':
"""Discards unknown flags and checks flag combination.""" """Discards unknown flags and checks flag combination."""
flags = list_enabled_bits(self) flags = list_enabled_bits(self)
known_channel_types = [] known_channel_types = []

View File

@@ -203,6 +203,7 @@ LNWALLET_FEATURES = (
| LnFeatures.OPTION_SHUTDOWN_ANYSEGWIT_OPT | LnFeatures.OPTION_SHUTDOWN_ANYSEGWIT_OPT
| LnFeatures.OPTION_SCID_ALIAS_OPT | LnFeatures.OPTION_SCID_ALIAS_OPT
| LnFeatures.OPTION_SUPPORT_LARGE_CHANNEL_OPT | LnFeatures.OPTION_SUPPORT_LARGE_CHANNEL_OPT
| LnFeatures.OPTION_CHANNEL_TYPE_REQ
) )
LNGOSSIP_FEATURES = ( LNGOSSIP_FEATURES = (