URI: 
       tmake xpub/xprv version information user-visible - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 63a1db117282eb5526f5ef55b4bc720ae820fdde
   DIR parent bd16e20a4d5705b8b957a9af8aa9ec83286b20af
  HTML Author: ThomasV <thomasv@electrum.org>
       Date:   Mon,  4 Sep 2017 11:04:59 +0200
       
       make xpub/xprv version information user-visible
       
       Diffstat:
         M lib/bitcoin.py                      |      36 +++++++++++++++++++++----------
         M lib/keystore.py                     |       7 +------
         M lib/wallet.py                       |      25 ++++++++++++++++++-------
         M plugins/ledger/ledger.py            |      11 +++--------
         M plugins/trezor/clientbase.py        |       3 ++-
       
       5 files changed, 49 insertions(+), 33 deletions(-)
       ---
   DIR diff --git a/lib/bitcoin.py b/lib/bitcoin.py
       t@@ -47,14 +47,30 @@ def read_json_dict(filename):
            return r
        
        
       +# Version numbers for BIP32 extended keys
       +# standard: xprv, xpub
       +# segwit in p2sh: yprv, ypub
       +# native segwit: zprv, zpub
       +XPRV_HEADERS = {
       +    'standard': 0x0488ade4,
       +    'segwit_p2sh': 0x049d7878,
       +    'segwit': 0x4b2430c
       +}
       +XPUB_HEADERS = {
       +    'standard': 0x0488b21e,
       +    'segwit_p2sh': 0x049d7cb2,
       +    'segwit': 0x4b24746
       +}
       +
       +
        # Bitcoin network constants
        TESTNET = False
        NOLNET = False
        ADDRTYPE_P2PKH = 0
        ADDRTYPE_P2SH = 5
        SEGWIT_HRP = "bc"
       -XPRV_HEADER = 0x0488ade4
       -XPUB_HEADER = 0x0488b21e
       +
       +
        HEADERS_URL = "https://headers.electrum.org/blockchain_headers"
        GENESIS = "000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"
        SERVERLIST = 'servers.json'
       t@@ -63,7 +79,6 @@ DEFAULT_SERVERS = read_json_dict('servers.json')
        
        def set_testnet():
            global ADDRTYPE_P2PKH, ADDRTYPE_P2SH
       -    global XPRV_HEADER, XPUB_HEADER
            global TESTNET, HEADERS_URL
            global GENESIS
            global SEGWIT_HRP
       t@@ -72,8 +87,6 @@ def set_testnet():
            ADDRTYPE_P2PKH = 111
            ADDRTYPE_P2SH = 196
            SEGWIT_HRP = "tb"
       -    XPRV_HEADER = 0x04358394
       -    XPUB_HEADER = 0x043587cf
            HEADERS_URL = "https://headers.electrum.org/testnet_headers"
            GENESIS = "000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943"
            SERVERLIST = 'servers_testnet.json'
       t@@ -816,11 +829,11 @@ def _CKD_pub(cK, c, s):
        
        
        def xprv_header(xtype):
       -    return bfh("%08x" % (XPRV_HEADER + xtype))
       +    return bfh("%08x" % XPRV_HEADERS[xtype])
        
        
        def xpub_header(xtype):
       -    return bfh("%08x" % (XPUB_HEADER + xtype))
       +    return bfh("%08x" % XPUB_HEADERS[xtype])
        
        
        def serialize_xprv(xtype, c, k, depth=0, fingerprint=b'\x00'*4, child_number=b'\x00'*4):
       t@@ -841,10 +854,11 @@ def deserialize_xkey(xkey, prv):
            fingerprint = xkey[5:9]
            child_number = xkey[9:13]
            c = xkey[13:13+32]
       -    header = XPRV_HEADER if prv else XPUB_HEADER
       -    xtype = int('0x' + bh2u(xkey[0:4]), 16) - header
       -    if xtype not in [0, 1]:
       -        raise BaseException('Invalid header')
       +    header = int('0x' + bh2u(xkey[0:4]), 16)
       +    headers = XPRV_HEADERS if prv else XPUB_HEADERS
       +    if header not in headers.values():
       +        raise BaseException('Invalid xpub format', hex(header))
       +    xtype = list(headers.keys())[list(headers.values()).index(header)]
            n = 33 if prv else 32
            K_or_k = xkey[13+n:]
            return xtype, depth, fingerprint, child_number, c, K_or_k
   DIR diff --git a/lib/keystore.py b/lib/keystore.py
       t@@ -76,8 +76,6 @@ class KeyStore(PrintError):
                    return False
                return bool(self.get_tx_derivations(tx))
        
       -    def is_segwit(self):
       -        return False
        
        
        class Software_KeyStore(KeyStore):
       t@@ -335,8 +333,6 @@ class BIP32_KeyStore(Deterministic_KeyStore, Xpub):
                pk = bip32_private_key(sequence, k, c)
                return pk
        
       -    def is_segwit(self):
       -        return bool(deserialize_xpub(self.xpub)[0])
        
        
        class Old_KeyStore(Deterministic_KeyStore):
       t@@ -699,8 +695,7 @@ def from_seed(seed, passphrase):
                keystore.add_seed(seed)
                keystore.passphrase = passphrase
                bip32_seed = Mnemonic.mnemonic_to_seed(seed, passphrase)
       -        xtype = 0 if t == 'standard' else 1
       -        keystore.add_xprv_from_seed(bip32_seed, xtype, "m/")
       +        keystore.add_xprv_from_seed(bip32_seed, t, "m/")
            else:
                raise BaseException(t)
            return keystore
   DIR diff --git a/lib/wallet.py b/lib/wallet.py
       t@@ -1544,8 +1544,15 @@ class Simple_Wallet(Abstract_Wallet):
        
            def load_keystore(self):
                self.keystore = load_keystore(self.storage, 'keystore')
       -        self.is_segwit = self.keystore.is_segwit()
       -        self.txin_type = 'p2wpkh' if self.is_segwit else 'p2pkh'
       +        xtype = deserialize_xpub(self.keystore.xpub)[0]
       +        if xtype == 'standard':
       +            self.txin_type = 'p2pkh'
       +        elif xtype == 'segwit':
       +            self.txin_type = 'p2wpkh'
       +        elif xtype == 'segwit_p2sh':
       +            self.txin_type = 'p2wpkh-p2sh'
       +        else:
       +            raise BaseException('unknown txin_type', xtype)
        
            def get_pubkey(self, c, i):
                return self.derive_pubkeys(c, i)
       t@@ -1640,8 +1647,7 @@ class Standard_Wallet(Simple_Deterministic_Wallet):
            wallet_type = 'standard'
        
            def pubkeys_to_redeem_script(self, pubkey):
       -        if self.is_segwit:
       -            return transaction.segwit_script(pubkey)
       +        return transaction.segwit_script(pubkey)
        
            def pubkeys_to_address(self, pubkey):
                if self.txin_type == 'p2pkh':
       t@@ -1652,7 +1658,7 @@ class Standard_Wallet(Simple_Deterministic_Wallet):
                    redeem_script = self.pubkeys_to_redeem_script(pubkey)
                    return bitcoin.hash160_to_p2sh(hash_160(bfh(redeem_script)))
                else:
       -            raise NotImplementedError()
       +            raise NotImplementedError(self.txin_type)
        
        
        class Multisig_Wallet(Deterministic_Wallet):
       t@@ -1693,8 +1699,13 @@ class Multisig_Wallet(Deterministic_Wallet):
                    name = 'x%d/'%(i+1)
                    self.keystores[name] = load_keystore(self.storage, name)
                self.keystore = self.keystores['x1/']
       -        self.is_segwit = self.keystore.is_segwit()
       -        self.txin_type = 'p2wsh' if self.is_segwit else 'p2sh'
       +        xtype = deserialize_xpub(self.keystore.xpub)[0]
       +        if xtype == 'standard':
       +            self.txin_type = 'p2sh'
       +        elif xtype == 'segwit':
       +            self.txin_type = 'p2wsh'
       +        elif xtype == 'segwit_p2sh':
       +            self.txin_type = 'p2wsh-p2sh'
        
            def save_keystore(self):
                for name, k in self.keystores.items():
   DIR diff --git a/plugins/ledger/ledger.py b/plugins/ledger/ledger.py
       t@@ -59,6 +59,7 @@ class Ledger_Client():
                #self.get_client() # prompt for the PIN before displaying the dialog if necessary
                #self.handler.show_message("Computing master public key")
                try:
       +            xtype = 'segwit_p2sh' if bip32_path.startswith("m/49'/") else 'standard'
                    splitPath = bip32_path.split('/')
                    if splitPath[0] == 'm':
                        splitPath = splitPath[1:]
       t@@ -75,11 +76,8 @@ class Ledger_Client():
                    publicKey = compress_public_key(nodeData['publicKey'])
                    depth = len(splitPath)
                    lastChild = splitPath[len(splitPath) - 1].split('\'')
       -            if len(lastChild) == 1:
       -                childnum = int(lastChild[0])
       -            else:
       -                childnum = 0x80000000 | int(lastChild[0])
       -            xpub = bitcoin.serialize_xpub(0, nodeData['chainCode'], publicKey, depth, self.i4b(fingerprint), self.i4b(childnum))
       +            childnum = int(lastChild[0]) if len(lastChild) == 1 else 0x80000000 | int(lastChild[0])
       +            xpub = bitcoin.serialize_xpub(xtype, nodeData['chainCode'], publicKey, depth, self.i4b(fingerprint), self.i4b(childnum))
                    return xpub
                except Exception as e:
                    traceback.print_exc(file=sys.stdout)
       t@@ -173,9 +171,6 @@ class Ledger_KeyStore(Hardware_KeyStore):
                self.signing = False
                self.cfg = d.get('cfg', {'mode':0,'pair':''})
        
       -    def is_segwit(self):
       -        return self.derivation.startswith("m/49'/")
       -
            def dump(self):
                obj = Hardware_KeyStore.dump(self)
                obj['cfg'] = self.cfg
   DIR diff --git a/plugins/trezor/clientbase.py b/plugins/trezor/clientbase.py
       t@@ -151,7 +151,8 @@ class TrezorClientBase(GuiMixin, PrintError):
                address_n = self.expand_path(bip32_path)
                creating = False #self.next_account_number() == 0
                node = self.get_public_node(address_n, creating).node
       -        return serialize_xpub(0, node.chain_code, node.public_key, node.depth, self.i4b(node.fingerprint), self.i4b(node.child_num))
       +        xtype = 'segwit_p2sh' if bip32_path.startswith("m/49'/") else 'standard'
       +        return serialize_xpub(xtype, node.chain_code, node.public_key, node.depth, self.i4b(node.fingerprint), self.i4b(node.child_num))
        
            #def address_from_derivation(self, derivation):
            #    return self.get_address('Bitcoin', self.expand_path(derivation))