electrum

Electrum Bitcoin wallet
git clone https://git.parazyd.org/electrum
Log | Files | Refs | Submodules

commit eced61123dc49db80366d4988c8594683e100be8
parent 4d32478f301bf732b88c0a4be9200d9f26792ca7
Author: SomberNight <somber.night@protonmail.com>
Date:   Tue,  9 Oct 2018 20:10:26 +0200

clean up local/global features

Diffstat:
Melectrum/lnbase.py | 23+++++++++++++++++++----
Melectrum/lnrouter.py | 6+++---
Melectrum/lnutil.py | 43++++++++++++++++++++++++++++++-------------
3 files changed, 52 insertions(+), 20 deletions(-)

diff --git a/electrum/lnbase.py b/electrum/lnbase.py @@ -17,6 +17,7 @@ from typing import List import cryptography.hazmat.primitives.ciphers.aead as AEAD import aiorpcx +from .util import list_enabled_bits from . import bitcoin from . import ecc from .ecc import sig_string_from_r_and_s, get_r_and_s_from_sig_string @@ -30,8 +31,9 @@ from .lnhtlc import HTLCStateMachine, RevokeAndAck from .lnutil import (Outpoint, ChannelConfig, LocalState, RemoteState, OnlyPubkeyKeypair, ChannelConstraints, RevocationStore, funding_output_script, get_ecdh, get_per_commitment_secret_from_seed, - secret_to_pubkey, LNPeerAddr, PaymentFailure, - LOCAL, REMOTE, HTLCOwner, generate_keypair, LnKeyFamily) + secret_to_pubkey, LNPeerAddr, PaymentFailure, LnLocalFeatures, + LOCAL, REMOTE, HTLCOwner, generate_keypair, LnKeyFamily, + get_ln_flag_pair_of_bit) from .lnrouter import NotFoundChanAnnouncementForUpdate, RouteEdge @@ -290,7 +292,10 @@ class Peer(PrintError): self.announcement_signatures = defaultdict(asyncio.Queue) self.closing_signed = defaultdict(asyncio.Queue) self.payment_preimages = defaultdict(asyncio.Queue) - self.localfeatures = (0x08 if request_initial_sync else 0) + self.localfeatures = LnLocalFeatures(0) + if request_initial_sync: + self.localfeatures |= LnLocalFeatures.INITIAL_ROUTING_SYNC + self.localfeatures |= LnLocalFeatures.OPTION_DATA_LOSS_PROTECT_OPT self.invoices = lnworker.invoices self.attempted_route = {} @@ -442,7 +447,17 @@ class Peer(PrintError): self.network.trigger_callback('ln_status') def on_init(self, payload): - pass + # if they required some even flag we don't have, they will close themselves + # but if we require an even flag they don't have, we close + our_flags = set(list_enabled_bits(self.localfeatures)) + their_flags = set(list_enabled_bits(int.from_bytes(payload['localfeatures'], byteorder="big"))) + for flag in our_flags: + if flag not in their_flags and get_ln_flag_pair_of_bit(flag) not in their_flags: + # they don't have this feature we wanted :( + if flag % 2 == 0: # even flags are compulsory + raise LightningPeerConnectionClosed("remote does not have even flag {}" + .format(str(LnLocalFeatures(1 << flag)))) + self.localfeatures ^= 1 << flag # disable flag def on_channel_update(self, payload): try: diff --git a/electrum/lnrouter.py b/electrum/lnrouter.py @@ -39,7 +39,7 @@ from .storage import JsonDB from .lnchannelverifier import LNChannelVerifier, verify_sig_for_channel_update from .crypto import Hash from . import ecc -from .lnutil import LN_GLOBAL_FEATURE_BITS, LNPeerAddr +from .lnutil import LN_GLOBAL_FEATURES_KNOWN_SET, LNPeerAddr class UnknownEvenFeatureBits(Exception): pass @@ -55,7 +55,7 @@ class ChannelInfo(PrintError): self.features = channel_announcement_payload['features'] enabled_features = list_enabled_bits(int.from_bytes(self.features, "big")) for fbit in enabled_features: - if fbit not in LN_GLOBAL_FEATURE_BITS and fbit % 2 == 0: + if (1 << fbit) not in LN_GLOBAL_FEATURES_KNOWN_SET and fbit % 2 == 0: raise UnknownEvenFeatureBits() self.channel_id = channel_announcement_payload['short_channel_id'] @@ -191,7 +191,7 @@ class NodeInfo(PrintError): self.features = node_announcement_payload['features'] enabled_features = list_enabled_bits(int.from_bytes(self.features, "big")) for fbit in enabled_features: - if fbit not in LN_GLOBAL_FEATURE_BITS and fbit % 2 == 0: + if (1 << fbit) not in LN_GLOBAL_FEATURES_KNOWN_SET and fbit % 2 == 0: raise UnknownEvenFeatureBits() if not addresses_already_parsed: self.addresses = self.parse_addresses_field(node_announcement_payload['addresses']) diff --git a/electrum/lnutil.py b/electrum/lnutil.py @@ -426,19 +426,36 @@ def get_ecdh(priv: bytes, pub: bytes) -> bytes: return sha256(pt.get_public_key_bytes()) -LN_LOCAL_FEATURE_BITS = { - 0: 'option_data_loss_protect_req', - 1: 'option_data_loss_protect_opt', - 3: 'initial_routing_sync', - 4: 'option_upfront_shutdown_script_req', - 5: 'option_upfront_shutdown_script_opt', - 6: 'gossip_queries_req', - 7: 'gossip_queries_opt', -} -LN_LOCAL_FEATURE_BITS_INV = inv_dict(LN_LOCAL_FEATURE_BITS) - -LN_GLOBAL_FEATURE_BITS = {} -LN_GLOBAL_FEATURE_BITS_INV = inv_dict(LN_GLOBAL_FEATURE_BITS) +class LnLocalFeatures(IntFlag): + OPTION_DATA_LOSS_PROTECT_REQ = 1 << 0 + OPTION_DATA_LOSS_PROTECT_OPT = 1 << 1 + INITIAL_ROUTING_SYNC = 1 << 3 + OPTION_UPFRONT_SHUTDOWN_SCRIPT_REQ = 1 << 4 + OPTION_UPFRONT_SHUTDOWN_SCRIPT_OPT = 1 << 5 + GOSSIP_QUERIES_REQ = 1 << 6 + GOSSIP_QUERIES_OPT = 1 << 7 + +# note that these are powers of two, not the bits themselves +LN_LOCAL_FEATURES_KNOWN_SET = set(LnLocalFeatures) + + +def get_ln_flag_pair_of_bit(flag_bit: int): + """Ln Feature flags are assigned in pairs, one even, one odd. See BOLT-09. + Return the other flag from the pair. + e.g. 6 -> 7 + e.g. 7 -> 6 + """ + if flag_bit % 2 == 0: + return flag_bit + 1 + else: + return flag_bit - 1 + + +class LnGlobalFeatures(IntFlag): + pass + +# note that these are powers of two, not the bits themselves +LN_GLOBAL_FEATURES_KNOWN_SET = set(LnGlobalFeatures) class LNPeerAddr(namedtuple('LNPeerAddr', ['host', 'port', 'pubkey'])):