lnutil+lnwire: implement ChannelType
This commit is contained in:
@@ -8,7 +8,6 @@ import json
|
||||
from collections import namedtuple, defaultdict
|
||||
from typing import NamedTuple, List, Tuple, Mapping, Optional, TYPE_CHECKING, Union, Dict, Set, Sequence
|
||||
import re
|
||||
import time
|
||||
import attr
|
||||
from aiorpcx import NetAddress
|
||||
|
||||
@@ -1029,6 +1028,12 @@ class LnFeatures(IntFlag):
|
||||
_ln_feature_contexts[OPTION_SHUTDOWN_ANYSEGWIT_REQ] = (LNFC.INIT | LNFC.NODE_ANN)
|
||||
_ln_feature_contexts[OPTION_SHUTDOWN_ANYSEGWIT_OPT] = (LNFC.INIT | LNFC.NODE_ANN)
|
||||
|
||||
OPTION_CHANNEL_TYPE_REQ = 1 << 44
|
||||
OPTION_CHANNEL_TYPE_OPT = 1 << 45
|
||||
|
||||
_ln_feature_contexts[OPTION_CHANNEL_TYPE_REQ] = (LNFC.INIT | LNFC.NODE_ANN)
|
||||
_ln_feature_contexts[OPTION_CHANNEL_TYPE_OPT] = (LNFC.INIT | LNFC.NODE_ANN)
|
||||
|
||||
# temporary
|
||||
OPTION_TRAMPOLINE_ROUTING_REQ_ECLAIR = 1 << 50
|
||||
OPTION_TRAMPOLINE_ROUTING_OPT_ECLAIR = 1 << 51
|
||||
@@ -1103,6 +1108,52 @@ class LnFeatures(IntFlag):
|
||||
or get_ln_flag_pair_of_bit(flag) in our_flags)
|
||||
|
||||
|
||||
class ChannelType(IntFlag):
|
||||
OPTION_LEGACY_CHANNEL = 0
|
||||
OPTION_STATIC_REMOTEKEY = 1 << 12
|
||||
OPTION_ANCHOR_OUTPUTS = 1 << 20
|
||||
OPTION_ANCHORS_ZERO_FEE_HTLC_TX = 1 << 22
|
||||
|
||||
def discard_unknown_and_check(self):
|
||||
"""Discards unknown flags and checks flag combination."""
|
||||
flags = list_enabled_bits(self)
|
||||
known_channel_types = []
|
||||
for flag in flags:
|
||||
channel_type = ChannelType(1 << flag)
|
||||
if channel_type.name:
|
||||
known_channel_types.append(channel_type)
|
||||
final_channel_type = known_channel_types[0]
|
||||
for channel_type in known_channel_types[1:]:
|
||||
final_channel_type |= channel_type
|
||||
|
||||
final_channel_type.check_combinations()
|
||||
return final_channel_type
|
||||
|
||||
def check_combinations(self):
|
||||
if self == ChannelType.OPTION_STATIC_REMOTEKEY:
|
||||
pass
|
||||
elif self == ChannelType.OPTION_ANCHOR_OUTPUTS | ChannelType.OPTION_STATIC_REMOTEKEY:
|
||||
pass
|
||||
elif self == ChannelType.OPTION_ANCHORS_ZERO_FEE_HTLC_TX | ChannelType.OPTION_STATIC_REMOTEKEY:
|
||||
pass
|
||||
else:
|
||||
raise ValueError("Channel type is not a valid flag combination.")
|
||||
|
||||
def complies_with_features(self, features: LnFeatures) -> bool:
|
||||
flags = list_enabled_bits(self)
|
||||
complies = True
|
||||
for flag in flags:
|
||||
feature = LnFeatures(1 << flag)
|
||||
complies &= features.supports(feature)
|
||||
return complies
|
||||
|
||||
def to_bytes_minimal(self):
|
||||
# MUST use the smallest bitmap possible to represent the channel type.
|
||||
bit_length =self.value.bit_length()
|
||||
byte_length = bit_length // 8 + int(bool(bit_length % 8))
|
||||
return self.to_bytes(byte_length, byteorder='big')
|
||||
|
||||
|
||||
del LNFC # name is ambiguous without context
|
||||
|
||||
# features that are actually implemented and understood in our codebase:
|
||||
|
||||
@@ -53,6 +53,8 @@ msgdata,open_channel,channel_flags,byte,
|
||||
msgdata,open_channel,tlvs,open_channel_tlvs,
|
||||
tlvtype,open_channel_tlvs,upfront_shutdown_script,0
|
||||
tlvdata,open_channel_tlvs,upfront_shutdown_script,shutdown_scriptpubkey,byte,...
|
||||
tlvtype,open_channel_tlvs,channel_type,1
|
||||
tlvdata,open_channel_tlvs,channel_type,type,byte,...
|
||||
msgtype,accept_channel,33
|
||||
msgdata,accept_channel,temporary_channel_id,byte,32
|
||||
msgdata,accept_channel,dust_limit_satoshis,u64,
|
||||
@@ -71,6 +73,8 @@ msgdata,accept_channel,first_per_commitment_point,point,
|
||||
msgdata,accept_channel,tlvs,accept_channel_tlvs,
|
||||
tlvtype,accept_channel_tlvs,upfront_shutdown_script,0
|
||||
tlvdata,accept_channel_tlvs,upfront_shutdown_script,shutdown_scriptpubkey,byte,...
|
||||
tlvtype,accept_channel_tlvs,channel_type,1
|
||||
tlvdata,accept_channel_tlvs,channel_type,type,byte,...
|
||||
msgtype,funding_created,34
|
||||
msgdata,funding_created,temporary_channel_id,byte,32
|
||||
msgdata,funding_created,funding_txid,sha256,
|
||||
|
||||
|
@@ -9,7 +9,7 @@ from electrum.lnutil import (RevocationStore, get_per_commitment_secret_from_see
|
||||
derive_pubkey, make_htlc_tx, extract_ctn_from_tx, UnableToDeriveSecret,
|
||||
get_compressed_pubkey_from_bech32, split_host_port, ConnStringFormatError,
|
||||
ScriptHtlc, extract_nodeid, calc_fees_for_commitment_tx, UpdateAddHtlc, LnFeatures,
|
||||
ln_compare_features, IncompatibleLightningFeatures)
|
||||
ln_compare_features, IncompatibleLightningFeatures, ChannelType)
|
||||
from electrum.util import bh2u, bfh, MyEncoder
|
||||
from electrum.transaction import Transaction, PartialTransaction
|
||||
from electrum.lnworker import LNWallet
|
||||
@@ -890,3 +890,15 @@ class TestLNUtil(ElectrumTestCase):
|
||||
self.assertEqual(
|
||||
None,
|
||||
LNWallet._decode_channel_update_msg(bytes.fromhex("0101") + msg_without_prefix))
|
||||
|
||||
def test_channel_type(self):
|
||||
# test compliance and non compliance with LN features
|
||||
features = LnFeatures(LnFeatures.BASIC_MPP_OPT | LnFeatures.OPTION_STATIC_REMOTEKEY_OPT)
|
||||
self.assertTrue(ChannelType.OPTION_STATIC_REMOTEKEY.complies_with_features(features))
|
||||
|
||||
features = LnFeatures(LnFeatures.BASIC_MPP_OPT | LnFeatures.OPTION_TRAMPOLINE_ROUTING_OPT)
|
||||
self.assertFalse(ChannelType.OPTION_STATIC_REMOTEKEY.complies_with_features(features))
|
||||
|
||||
# ignore unknown channel types
|
||||
channel_type = ChannelType(0b10000000001000000000010).discard_unknown_and_check()
|
||||
self.assertEqual(ChannelType(0b10000000001000000000000), channel_type)
|
||||
Reference in New Issue
Block a user