URI: 
       tsupport option_static_remotekey - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 2255b0715704bf9e32a4e5b9d1fda511be7b5938
   DIR parent 47d14c579b0e49cd1c29c416a6b3f69f5bd9fd9e
  HTML Author: ThomasV <thomasv@electrum.org>
       Date:   Fri, 13 Dec 2019 14:07:11 +0100
       
       support option_static_remotekey
       
       Diffstat:
         M electrum/lnchannel.py               |       9 ++++++++-
         M electrum/lnpeer.py                  |      24 +++++++++++++++++++++---
         M electrum/lnsweep.py                 |      41 +++++++++++++++++--------------
         M electrum/lnutil.py                  |       2 ++
         M electrum/lnworker.py                |       1 +
       
       5 files changed, 54 insertions(+), 23 deletions(-)
       ---
   DIR diff --git a/electrum/lnchannel.py b/electrum/lnchannel.py
       t@@ -230,6 +230,9 @@ class Channel(Logger):
                self._chan_ann_without_sigs = chan_ann
                return chan_ann
        
       +    def is_static_remotekey_enabled(self):
       +        return self.storage.get('static_remotekey_enabled')
       +
            def set_short_channel_id(self, short_id):
                self.short_channel_id = short_id
                self.storage["short_channel_id"] = short_id
       t@@ -766,7 +769,11 @@ class Channel(Logger):
                    feerate,
                    self.constraints.is_initiator == (subject == LOCAL),
                )
       -        payment_pubkey = derive_pubkey(other_config.payment_basepoint.pubkey, this_point)
       +        if self.is_static_remotekey_enabled():
       +            payment_pubkey = other_config.payment_basepoint.pubkey
       +        else:
       +            payment_pubkey = derive_pubkey(other_config.payment_basepoint.pubkey, this_point)
       +
                return make_commitment(
                    ctn,
                    this_config.multisig_key.pubkey,
   DIR diff --git a/electrum/lnpeer.py b/electrum/lnpeer.py
       t@@ -119,7 +119,7 @@ class Peer(Logger):
            async def initialize(self):
                if isinstance(self.transport, LNTransport):
                    await self.transport.handshake()
       -        self.send_message("init", gflen=0, lflen=1, localfeatures=self.localfeatures)
       +        self.send_message("init", gflen=0, lflen=2, localfeatures=self.localfeatures)
                self._sent_init = True
        
            @property
       t@@ -461,6 +461,9 @@ class Peer(Logger):
                    pass
                self.lnworker.peer_closed(self)
        
       +    def is_static_remotekey(self):
       +        return bool(self.localfeatures & LnLocalFeatures.OPTION_STATIC_REMOTEKEY_OPT)
       +
            def make_local_config(self, funding_sat: int, push_msat: int, initiator: HTLCOwner) -> LocalConfig:
                # key derivation
                channel_counter = self.lnworker.get_and_inc_counter_for_channel_keys()
       t@@ -469,8 +472,16 @@ class Peer(Logger):
                    initial_msat = funding_sat * 1000 - push_msat
                else:
                    initial_msat = push_msat
       +
       +        if self.is_static_remotekey():
       +            addr = self.lnworker.wallet.get_unused_address()
       +            static_key = self.lnworker.wallet.get_public_key(addr) # just a pubkey
       +            payment_basepoint = OnlyPubkeyKeypair(bfh(static_key))
       +        else:
       +            payment_basepoint = keypair_generator(LnKeyFamily.PAYMENT_BASE)
       +
                local_config=LocalConfig(
       -            payment_basepoint=keypair_generator(LnKeyFamily.PAYMENT_BASE),
       +            payment_basepoint=payment_basepoint,
                    multisig_key=keypair_generator(LnKeyFamily.MULTISIG),
                    htlc_basepoint=keypair_generator(LnKeyFamily.HTLC_BASE),
                    delayed_basepoint=keypair_generator(LnKeyFamily.DELAY_BASE),
       t@@ -615,6 +626,7 @@ class Peer(Logger):
                    'data_loss_protect_remote_pcp': {},
                    "log": {},
                    "revocation_store": {},
       +            "static_remotekey_enabled": self.is_static_remotekey(), # stored because it cannot be "downgraded", per BOLT2
                }
                channel_id = chan_dict.get('channel_id')
                channels = self.lnworker.db.get_dict('channels')
       t@@ -729,12 +741,16 @@ class Peer(Logger):
                next_remote_ctn = chan.get_next_ctn(REMOTE)
                assert self.localfeatures & LnLocalFeatures.OPTION_DATA_LOSS_PROTECT_OPT
                # send message
       +        srk_enabled = chan.is_static_remotekey_enabled()
       +        if srk_enabled:
       +            latest_secret, latest_point = chan.get_secret_and_point(LOCAL, 0)
       +        else:
       +            latest_secret, latest_point = chan.get_secret_and_point(LOCAL, latest_local_ctn)
                if oldest_unrevoked_remote_ctn == 0:
                    last_rev_secret = 0
                else:
                    last_rev_index = oldest_unrevoked_remote_ctn - 1
                    last_rev_secret = chan.revocation_store.retrieve_secret(RevocationStore.START_INDEX - last_rev_index)
       -        latest_secret, latest_point = chan.get_secret_and_point(LOCAL, latest_local_ctn)
                self.send_message(
                    "channel_reestablish",
                    channel_id=chan_id,
       t@@ -824,6 +840,8 @@ class Peer(Logger):
                    if our_pcs != their_claim_of_our_last_per_commitment_secret:
                        self.logger.error(f"channel_reestablish: (DLP) local PCS mismatch: {bh2u(our_pcs)} != {bh2u(their_claim_of_our_last_per_commitment_secret)}")
                        return False
       +            if chan.is_static_remotekey_enabled():
       +                return True
                    try:
                        __, our_remote_pcp = chan.get_secret_and_point(REMOTE, their_next_local_ctn - 1)
                    except RemoteCtnTooFarInFuture:
   DIR diff --git a/electrum/lnsweep.py b/electrum/lnsweep.py
       t@@ -324,7 +324,9 @@ def create_sweeptxs_for_their_ctx(*, chan: 'Channel', ctx: Transaction,
            witness_script = bh2u(make_commitment_output_to_local_witness_script(
                our_revocation_pubkey, our_conf.to_self_delay, their_delayed_pubkey))
            to_local_address = redeem_script_to_address('p2wsh', witness_script)
       -    our_payment_pubkey = derive_pubkey(our_conf.payment_basepoint.pubkey, their_pcp)
       +    # to remote address
       +    bpk = our_conf.payment_basepoint.pubkey
       +    our_payment_pubkey = bpk if chan.is_static_remotekey_enabled() else derive_pubkey(bpk, their_pcp)
            to_remote_address = make_commitment_output_to_remote_address(our_payment_pubkey)
            # test if this is their ctx
            _logger.debug(f'testing their ctx: {to_local_address} {to_remote_address}')
       t@@ -345,26 +347,27 @@ def create_sweeptxs_for_their_ctx(*, chan: 'Channel', ctx: Transaction,
            our_htlc_privkey = derive_privkey(secret=int.from_bytes(our_conf.htlc_basepoint.privkey, 'big'), per_commitment_point=their_pcp)
            our_htlc_privkey = ecc.ECPrivkey.from_secret_scalar(our_htlc_privkey)
            their_htlc_pubkey = derive_pubkey(their_conf.htlc_basepoint.pubkey, their_pcp)
       -    our_payment_bp_privkey = ecc.ECPrivkey(our_conf.payment_basepoint.privkey)
       -    our_payment_privkey = derive_privkey(our_payment_bp_privkey.secret_scalar, their_pcp)
       -    our_payment_privkey = ecc.ECPrivkey.from_secret_scalar(our_payment_privkey)
       -    assert our_payment_pubkey == our_payment_privkey.get_public_key_bytes(compressed=True)
            # to_local is handled by lnwatcher
            # to_remote
       -    output_idxs = ctx.get_output_idxs_from_address(to_remote_address)
       -    if output_idxs:
       -        output_idx = output_idxs.pop()
       -        prevout = ctx.txid() + ':%d'%output_idx
       -        sweep_tx = lambda: create_sweeptx_their_ctx_to_remote(
       -            sweep_address=sweep_address,
       -            ctx=ctx,
       -            output_idx=output_idx,
       -            our_payment_privkey=our_payment_privkey,
       -            config=chan.lnworker.config)
       -        txs[prevout] = SweepInfo(name='their_ctx_to_remote',
       -                                 csv_delay=0,
       -                                 cltv_expiry=0,
       -                                 gen_tx=sweep_tx)
       +    if not chan.is_static_remotekey_enabled():
       +        our_payment_bp_privkey = ecc.ECPrivkey(our_conf.payment_basepoint.privkey)
       +        our_payment_privkey = derive_privkey(our_payment_bp_privkey.secret_scalar, their_pcp)
       +        our_payment_privkey = ecc.ECPrivkey.from_secret_scalar(our_payment_privkey)
       +        assert our_payment_pubkey == our_payment_privkey.get_public_key_bytes(compressed=True)
       +        output_idxs = ctx.get_output_idxs_from_address(to_remote_address)
       +        if output_idxs:
       +            output_idx = output_idxs.pop()
       +            prevout = ctx.txid() + ':%d'%output_idx
       +            sweep_tx = lambda: create_sweeptx_their_ctx_to_remote(
       +                sweep_address=sweep_address,
       +                ctx=ctx,
       +                output_idx=output_idx,
       +                our_payment_privkey=our_payment_privkey,
       +                config=chan.lnworker.config)
       +            txs[prevout] = SweepInfo(name='their_ctx_to_remote',
       +                                     csv_delay=0,
       +                                     cltv_expiry=0,
       +                                     gen_tx=sweep_tx)
            # HTLCs
            def create_sweeptx_for_htlc(htlc: 'UpdateAddHtlc', is_received_htlc: bool,
                                        ctx_output_idx: int) -> None:
   DIR diff --git a/electrum/lnutil.py b/electrum/lnutil.py
       t@@ -630,6 +630,8 @@ class LnLocalFeatures(IntFlag):
            OPTION_UPFRONT_SHUTDOWN_SCRIPT_OPT = 1 << 5
            GOSSIP_QUERIES_REQ = 1 << 6
            GOSSIP_QUERIES_OPT = 1 << 7
       +    OPTION_STATIC_REMOTEKEY_REQ = 1 << 12
       +    OPTION_STATIC_REMOTEKEY_OPT = 1 << 13
        
        # note that these are powers of two, not the bits themselves
        LN_LOCAL_FEATURES_KNOWN_SET = set(LnLocalFeatures)
   DIR diff --git a/electrum/lnworker.py b/electrum/lnworker.py
       t@@ -130,6 +130,7 @@ class LNWorker(Logger):
                # note that e.g. DATA_LOSS_PROTECT is needed for LNGossip as many peers require it
                self.localfeatures = LnLocalFeatures(0)
                self.localfeatures |= LnLocalFeatures.OPTION_DATA_LOSS_PROTECT_OPT
       +        self.localfeatures |= LnLocalFeatures.OPTION_STATIC_REMOTEKEY_OPT
        
            def channels_for_peer(self, node_id):
                return {}