URI: 
       tMerge pull request #6070 from spesmilo/channel_save_seed2 - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 4512f9d6d87fc8778d574b4c5cf901fe946d4ea0
   DIR parent 1dc3100ba3b179d395ce12a3a2cd07654f00716a
  HTML Author: ThomasV <thomasv@electrum.org>
       Date:   Mon,  6 Apr 2020 16:56:34 +0200
       
       Merge pull request #6070 from spesmilo/channel_save_seed2
       
       Save channel seed in localconfig
       Diffstat:
         M electrum/lnpeer.py                  |      31 +++++++++----------------------
         M electrum/lnutil.py                  |      32 +++++++++++++++++++++++--------
         M electrum/tests/test_lnchannel.py    |       1 +
         M electrum/wallet_db.py               |      11 ++++++++++-
       
       4 files changed, 44 insertions(+), 31 deletions(-)
       ---
   DIR diff --git a/electrum/lnpeer.py b/electrum/lnpeer.py
       t@@ -20,7 +20,6 @@ import aiorpcx
        
        from .crypto import sha256, sha256d
        from . import bitcoin
       -from .bip32 import BIP32Node
        from . import ecc
        from .ecc import sig_string_from_r_and_s, get_r_and_s_from_sig_string, der_sig_from_sig_string
        from . import constants
       t@@ -484,38 +483,26 @@ class Peer(Logger):
                return bool(self.features & LnFeatures.OPTION_STATIC_REMOTEKEY_OPT)
        
            def make_local_config(self, funding_sat: int, push_msat: int, initiator: HTLCOwner) -> LocalConfig:
       -        # key derivation
       -        seed = os.urandom(32)
       -        node = BIP32Node.from_rootseed(seed, xtype='standard')
       -        keypair_generator = lambda family: generate_keypair(node, family)
       -
       -        if initiator == LOCAL:
       -            initial_msat = funding_sat * 1000 - push_msat
       -        else:
       -            initial_msat = push_msat
       -
       +        channel_seed = os.urandom(32)
       +        initial_msat = funding_sat * 1000 - push_msat if initiator == LOCAL else push_msat
                if self.is_static_remotekey():
       +            # Note: in the future, if a CSV delay is added,
       +            # we will want to derive that key
                    wallet = self.lnworker.wallet
                    assert wallet.txin_type == 'p2wpkh'
                    addr = wallet.get_unused_address()
       -            static_key = wallet.get_public_key(addr) # just a pubkey
       -            payment_basepoint = OnlyPubkeyKeypair(bfh(static_key))
       +            static_remotekey = bfh(wallet.get_public_key(addr))
                else:
       -            payment_basepoint = keypair_generator(LnKeyFamily.PAYMENT_BASE)
       -
       -        local_config=LocalConfig(
       -            payment_basepoint=payment_basepoint,
       -            multisig_key=keypair_generator(LnKeyFamily.MULTISIG),
       -            htlc_basepoint=keypair_generator(LnKeyFamily.HTLC_BASE),
       -            delayed_basepoint=keypair_generator(LnKeyFamily.DELAY_BASE),
       -            revocation_basepoint=keypair_generator(LnKeyFamily.REVOCATION_BASE),
       +            static_remotekey = None
       +        local_config = LocalConfig.from_seed(
       +            channel_seed=channel_seed,
       +            static_remotekey=static_remotekey,
                    to_self_delay=DEFAULT_TO_SELF_DELAY,
                    dust_limit_sat=546,
                    max_htlc_value_in_flight_msat=funding_sat * 1000,
                    max_accepted_htlcs=5,
                    initial_msat=initial_msat,
                    reserve_sat=546,
       -            per_commitment_secret_seed=keypair_generator(LnKeyFamily.REVOCATION_ROOT).privkey,
                    funding_locked_received=False,
                    was_announced=False,
                    current_commitment_signature=None,
   DIR diff --git a/electrum/lnutil.py b/electrum/lnutil.py
       t@@ -23,7 +23,7 @@ from .bitcoin import push_script, redeem_script_to_address, address_to_script
        from . import segwit_addr
        from .i18n import _
        from .lnaddr import lndecode
       -from .bip32 import BIP32Node
       +from .bip32 import BIP32Node, BIP32_PRIME
        
        if TYPE_CHECKING:
            from .lnchannel import Channel
       t@@ -77,11 +77,27 @@ class Config(StoredObject):
        
        @attr.s
        class LocalConfig(Config):
       -    per_commitment_secret_seed = attr.ib(type=bytes, converter=hex_to_bytes)
       +    channel_seed = attr.ib(type=bytes, converter=hex_to_bytes)  # type: Optional[bytes]
            funding_locked_received = attr.ib(type=bool)
            was_announced = attr.ib(type=bool)
            current_commitment_signature = attr.ib(type=bytes, converter=hex_to_bytes)
            current_htlc_signatures = attr.ib(type=bytes, converter=hex_to_bytes)
       +    per_commitment_secret_seed = attr.ib(type=bytes, converter=hex_to_bytes)
       +
       +    @classmethod
       +    def from_seed(self, **kwargs):
       +        channel_seed = kwargs['channel_seed']
       +        static_remotekey = kwargs.pop('static_remotekey')
       +        node = BIP32Node.from_rootseed(channel_seed, xtype='standard')
       +        keypair_generator = lambda family: generate_keypair(node, family)
       +        kwargs['per_commitment_secret_seed'] = keypair_generator(LnKeyFamily.REVOCATION_ROOT).privkey
       +        kwargs['multisig_key'] = keypair_generator(LnKeyFamily.MULTISIG)
       +        kwargs['htlc_basepoint'] = keypair_generator(LnKeyFamily.HTLC_BASE)
       +        kwargs['delayed_basepoint'] = keypair_generator(LnKeyFamily.DELAY_BASE)
       +        kwargs['revocation_basepoint'] = keypair_generator(LnKeyFamily.REVOCATION_BASE)
       +        kwargs['payment_basepoint'] = OnlyPubkeyKeypair(static_remotekey) if static_remotekey else keypair_generator(LnKeyFamily.PAYMENT_BASE)
       +        return LocalConfig(**kwargs)
       +
        
        @attr.s
        class RemoteConfig(Config):
       t@@ -1024,12 +1040,12 @@ def extract_nodeid(connect_contents: str) -> Tuple[bytes, str]:
        # key derivation
        # see lnd/keychain/derivation.go
        class LnKeyFamily(IntEnum):
       -    MULTISIG = 0
       -    REVOCATION_BASE = 1
       -    HTLC_BASE = 2
       -    PAYMENT_BASE = 3
       -    DELAY_BASE = 4
       -    REVOCATION_ROOT = 5
       +    MULTISIG = 0 | BIP32_PRIME
       +    REVOCATION_BASE = 1 | BIP32_PRIME
       +    HTLC_BASE = 2 | BIP32_PRIME
       +    PAYMENT_BASE = 3 | BIP32_PRIME
       +    DELAY_BASE = 4 | BIP32_PRIME
       +    REVOCATION_ROOT = 5 | BIP32_PRIME
            NODE_KEY = 6
        
        
   DIR diff --git a/electrum/tests/test_lnchannel.py b/electrum/tests/test_lnchannel.py
       t@@ -70,6 +70,7 @@ def create_channel_state(funding_txid, funding_index, funding_sat, is_initiator,
                        current_per_commitment_point=cur,
                    ),
                    "local_config":lnpeer.LocalConfig(
       +                channel_seed = None,
                        payment_basepoint=privkeys[0],
                        multisig_key=privkeys[1],
                        htlc_basepoint=privkeys[2],
   DIR diff --git a/electrum/wallet_db.py b/electrum/wallet_db.py
       t@@ -50,7 +50,7 @@ if TYPE_CHECKING:
        
        OLD_SEED_VERSION = 4        # electrum versions < 2.0
        NEW_SEED_VERSION = 11       # electrum versions >= 2.0
       -FINAL_SEED_VERSION = 27     # electrum >= 2.7 will set this to prevent
       +FINAL_SEED_VERSION = 28     # electrum >= 2.7 will set this to prevent
                                    # old versions from overwriting new format
        
        
       t@@ -173,6 +173,7 @@ class WalletDB(JsonDB):
                self._convert_version_25()
                self._convert_version_26()
                self._convert_version_27()
       +        self._convert_version_28()
                self.put('seed_version', FINAL_SEED_VERSION)  # just to be sure
        
                self._after_upgrade_tasks()
       t@@ -596,6 +597,14 @@ class WalletDB(JsonDB):
                    c['local_config']['htlc_minimum_msat'] = 1
                self.data['seed_version'] = 27
        
       +    def _convert_version_28(self):
       +        if not self._is_upgrade_method_needed(27, 27):
       +            return
       +        channels = self.data.get('channels', {})
       +        for channel_id, c in channels.items():
       +            c['local_config']['channel_seed'] = None
       +        self.data['seed_version'] = 28
       +
            def _convert_imported(self):
                if not self._is_upgrade_method_needed(0, 13):
                    return