URI: 
       tMerge pull request #2964 from SomberNight/tests_wallet_keystore_bip39 - electrum - Electrum Bitcoin wallet
  HTML git clone https://git.parazyd.org/electrum
   DIR Log
   DIR Files
   DIR Refs
   DIR Submodules
       ---
   DIR commit 73c7fbcc6970e0b56eae6a8277116fb51b8a53a2
   DIR parent 34a786ee433960fc3b33af3e82ca80656a540f21
  HTML Author: ThomasV <thomasv@electrum.org>
       Date:   Thu,  5 Oct 2017 10:10:57 +0200
       
       Merge pull request #2964 from SomberNight/tests_wallet_keystore_bip39
       
       ttests: wallet-keystore integrity (bip39)
       Diffstat:
         M lib/base_wizard.py                  |       5 +----
         M lib/keystore.py                     |       7 +++++++
         M lib/tests/test_wallet_vertical.py   |     120 ++++++++++++++++++++++++-------
       
       3 files changed, 101 insertions(+), 31 deletions(-)
       ---
   DIR diff --git a/lib/base_wizard.py b/lib/base_wizard.py
       t@@ -302,10 +302,7 @@ class BaseWizard(object):
                self.on_keystore(k)
        
            def on_bip43(self, seed, passphrase, derivation):
       -        k = keystore.BIP32_KeyStore({})
       -        bip32_seed = keystore.bip39_to_seed(seed, passphrase)
       -        t = 'segwit_p2sh' if derivation.startswith("m/49'") else 'standard'
       -        k.add_xprv_from_seed(bip32_seed, t, derivation)
       +        k = keystore.from_bip39_seed(seed, passphrase, derivation)
                self.on_keystore(k)
        
            def on_keystore(self, k):
   DIR diff --git a/lib/keystore.py b/lib/keystore.py
       t@@ -577,6 +577,13 @@ def bip39_is_checksum_valid(mnemonic):
            calculated_checksum = hashed >> (256 - checksum_length)
            return checksum == calculated_checksum, True
        
       +def from_bip39_seed(seed, passphrase, derivation):
       +    k = BIP32_KeyStore({})
       +    bip32_seed = bip39_to_seed(seed, passphrase)
       +    t = 'segwit_p2sh' if derivation.startswith("m/49'") else 'standard'  # bip43
       +    k.add_xprv_from_seed(bip32_seed, t, derivation)
       +    return k
       +
        # extended pubkeys
        
        def is_xpubkey(x_pubkey):
   DIR diff --git a/lib/tests/test_wallet_vertical.py b/lib/tests/test_wallet_vertical.py
       t@@ -8,9 +8,10 @@ import lib.wallet as wallet
        
        
        # TODO: 2fa
       -# TODO: bip39 (standard, segwit_p2sh)
        class TestWalletKeystoreAddressIntegrity(unittest.TestCase):
        
       +    gap_limit = 1  # make tests run faster
       +
            def _check_seeded_keystore_sanity(self, ks):
                self.assertTrue (ks.is_deterministic())
                self.assertFalse(ks.is_watching_only())
       t@@ -23,6 +24,25 @@ class TestWalletKeystoreAddressIntegrity(unittest.TestCase):
                self.assertFalse(ks.can_import())
                self.assertFalse(ks.has_seed())
        
       +    def _create_standard_wallet(self, ks):
       +        store = storage.WalletStorage('if_this_exists_mocking_failed_648151893')
       +        store.put('keystore', ks.dump())
       +        store.put('gap_limit', self.gap_limit)
       +        w = wallet.Standard_Wallet(store)
       +        w.synchronize()
       +        return w
       +
       +    def _create_multisig_wallet(self, ks1, ks2):
       +        store = storage.WalletStorage('if_this_exists_mocking_failed_648151893')
       +        multisig_type = "%dof%d" % (2, 2)
       +        store.put('wallet_type', multisig_type)
       +        store.put('x%d/' % 1, ks1.dump())
       +        store.put('x%d/' % 2, ks2.dump())
       +        store.put('gap_limit', self.gap_limit)
       +        w = wallet.Multisig_Wallet(store)
       +        w.synchronize()
       +        return w
       +
            @mock.patch.object(storage.WalletStorage, '_write')
            def test_electrum_seed_standard(self, mock_write):
                seed_words = 'cycle rocket west magnet parrot shuffle foot correct salt library feed song'
       t@@ -35,10 +55,7 @@ class TestWalletKeystoreAddressIntegrity(unittest.TestCase):
        
                self.assertEqual(ks.xpub, 'xpub661MyMwAqRbcFWohJWt7PHsFEJfZAvw9ZxwQoDa4SoMgsDDM1T7WK3u9E4edkC4ugRnZ8E4xDZRpk8Rnts3Nbt97dPwT52CwBdDWroaZf8U')
        
       -        store = storage.WalletStorage('if_this_exists_mocking_failed_648151893')
       -        store.put('keystore', ks.dump())
       -        w = wallet.Standard_Wallet(store)
       -        w.synchronize()
       +        w = self._create_standard_wallet(ks)
        
                self.assertEqual(w.get_receiving_addresses()[0], '1NNkttn1YvVGdqBW4PR6zvc3Zx3H5owKRf')
                self.assertEqual(w.get_change_addresses()[0], '1KSezYMhAJMWqFbVFB2JshYg69UpmEXR4D')
       t@@ -55,10 +72,7 @@ class TestWalletKeystoreAddressIntegrity(unittest.TestCase):
        
                self.assertEqual(ks.xpub, 'zpub6jftahH18ngZyLeqfLBFAm7YaWFVttE9pku5pNMX2qPzTjoq1FVgZMmhjecyB2nqFb31gHE9vNvbaggU6vvWpNZbXEWLLUjYjFqG95LNyT8')
        
       -        store = storage.WalletStorage('if_this_exists_mocking_failed_648151893')
       -        store.put('keystore', ks.dump())
       -        w = wallet.Standard_Wallet(store)
       -        w.synchronize()
       +        w = self._create_standard_wallet(ks)
        
                self.assertEqual(w.get_receiving_addresses()[0], 'bc1qtt5msqvcqyvuu7hq7urwgraqqyq2yhtuzdpwc4')
                self.assertEqual(w.get_change_addresses()[0], 'bc1q9wlrynvj7qz7x4fs29d8dnje0zdevj5vmenter')
       t@@ -75,15 +89,44 @@ class TestWalletKeystoreAddressIntegrity(unittest.TestCase):
        
                self.assertEqual(ks.mpk, 'e9d4b7866dd1e91c862aebf62a49548c7dbf7bcc6e4b7b8c9da820c7737968df9c09d5a3e271dc814a29981f81b3faaf2737b551ef5dcc6189cf0f8252c442b3')
        
       -        store = storage.WalletStorage('if_this_exists_mocking_failed_648151893')
       -        store.put('keystore', ks.dump())
       -        w = wallet.Standard_Wallet(store)
       -        w.synchronize()
       +        w = self._create_standard_wallet(ks)
        
                self.assertEqual(w.get_receiving_addresses()[0], '1FJEEB8ihPMbzs2SkLmr37dHyRFzakqUmo')
                self.assertEqual(w.get_change_addresses()[0], '1KRW8pH6HFHZh889VDq6fEKvmrsmApwNfe')
        
            @mock.patch.object(storage.WalletStorage, '_write')
       +    def test_bip39_seed_bip44_standard(self, mock_write):
       +        seed_words = 'treat dwarf wealth gasp brass outside high rent blood crowd make initial'
       +        self.assertEqual(keystore.bip39_is_checksum_valid(seed_words), (True, True))
       +
       +        ks = keystore.from_bip39_seed(seed_words, '', "m/44'/0'/0'")
       +
       +        self.assertTrue(isinstance(ks, keystore.BIP32_KeyStore))
       +
       +        self.assertEqual(ks.xpub, 'xpub6DFh1smUsyqmYD4obDX6ngaxhd53Zx7aeFjoobebm7vbkT6f9awJWFuGzBT9FQJEWFBL7UyhMXtYzRcwDuVbcxtv9Ce2W9eMm4KXLdvdbjv')
       +
       +        w = self._create_standard_wallet(ks)
       +
       +        self.assertEqual(w.get_receiving_addresses()[0], '16j7Dqk3Z9DdTdBtHcCVLaNQy9MTgywUUo')
       +        self.assertEqual(w.get_change_addresses()[0], '1GG5bVeWgAp5XW7JLCphse14QaC4qiHyWn')
       +
       +    @mock.patch.object(storage.WalletStorage, '_write')
       +    def test_bip39_seed_bip49_p2sh_segwit(self, mock_write):
       +        seed_words = 'treat dwarf wealth gasp brass outside high rent blood crowd make initial'
       +        self.assertEqual(keystore.bip39_is_checksum_valid(seed_words), (True, True))
       +
       +        ks = keystore.from_bip39_seed(seed_words, '', "m/49'/0'/0'")
       +
       +        self.assertTrue(isinstance(ks, keystore.BIP32_KeyStore))
       +
       +        self.assertEqual(ks.xpub, 'ypub6XDth9u8DzXV1tcpDtoDKMf6kVMaVMn1juVWEesTshcX4zUVvfNgjPJLXrD9N7AdTLnbHFL64KmBn3SNaTe69iZYbYCqLCCNPZKbLz9niQ4')
       +
       +        w = self._create_standard_wallet(ks)
       +
       +        self.assertEqual(w.get_receiving_addresses()[0], '35ohQTdNykjkF1Mn9nAVEFjupyAtsPAK1W')
       +        self.assertEqual(w.get_change_addresses()[0], '3KaBTcviBLEJajTEMstsA2GWjYoPzPK7Y7')
       +
       +    @mock.patch.object(storage.WalletStorage, '_write')
            def test_electrum_multisig_seed_standard(self, mock_write):
                seed_words = 'blast uniform dragon fiscal ensure vast young utility dinosaur abandon rookie sure'
                self.assertEqual(bitcoin.seed_type(seed_words), 'standard')
       t@@ -97,13 +140,7 @@ class TestWalletKeystoreAddressIntegrity(unittest.TestCase):
                self._check_xpub_keystore_sanity(ks2)
                self.assertTrue(isinstance(ks2, keystore.BIP32_KeyStore))
        
       -        store = storage.WalletStorage('if_this_exists_mocking_failed_648151893')
       -        multisig_type = "%dof%d" % (2, 2)
       -        store.put('wallet_type', multisig_type)
       -        store.put('x%d/' % 1, ks1.dump())
       -        store.put('x%d/' % 2, ks2.dump())
       -        w = wallet.Multisig_Wallet(store)
       -        w.synchronize()
       +        w = self._create_multisig_wallet(ks1, ks2)
        
                self.assertEqual(w.get_receiving_addresses()[0], '32ji3QkAgXNz6oFoRfakyD3ys1XXiERQYN')
                self.assertEqual(w.get_change_addresses()[0], '36XWwEHrrVCLnhjK5MrVVGmUHghr9oWTN1')
       t@@ -122,14 +159,43 @@ class TestWalletKeystoreAddressIntegrity(unittest.TestCase):
                self._check_xpub_keystore_sanity(ks2)
                self.assertTrue(isinstance(ks2, keystore.BIP32_KeyStore))
        
       -        store = storage.WalletStorage('if_this_exists_mocking_failed_648151893')
       -        multisig_type = "%dof%d" % (2, 2)
       -        store.put('wallet_type', multisig_type)
       -        store.put('x%d/' % 1, ks1.dump())
       -        store.put('x%d/' % 2, ks2.dump())
       -        w = wallet.Multisig_Wallet(store)
       -        w.synchronize()
       +        w = self._create_multisig_wallet(ks1, ks2)
        
                self.assertEqual(w.get_receiving_addresses()[0], 'bc1qnvks7gfdu72de8qv6q6rhkkzu70fqz4wpjzuxjf6aydsx7wxfwcqnlxuv3')
                self.assertEqual(w.get_change_addresses()[0], 'bc1qsvfq6ekp0paugjhfey38pt3nqyvs3tcxu5l00v56j3g6g5la004qw4d33a')
        
       +    @mock.patch.object(storage.WalletStorage, '_write')
       +    def test_bip39_multisig_seed_bip44_standard(self, mock_write):
       +        seed_words = 'treat dwarf wealth gasp brass outside high rent blood crowd make initial'
       +        self.assertEqual(keystore.bip39_is_checksum_valid(seed_words), (True, True))
       +
       +        ks1 = keystore.from_bip39_seed(seed_words, '', "m/44'/0'/0'")
       +        self.assertTrue(isinstance(ks1, keystore.BIP32_KeyStore))
       +        self.assertEqual(ks1.xpub, 'xpub6DFh1smUsyqmYD4obDX6ngaxhd53Zx7aeFjoobebm7vbkT6f9awJWFuGzBT9FQJEWFBL7UyhMXtYzRcwDuVbcxtv9Ce2W9eMm4KXLdvdbjv')
       +
       +        ks2 = keystore.from_xpub('xpub6D9mmC1euHjT6dVrsfwSeNRPF2oi3cTifXwgnhzAay7RiCmZTtzAPCGPcyYP9NwTn5QvoyYsx7DxSQYc82872dk3pWv1P5om1EC1jAr5jGT')
       +        self._check_xpub_keystore_sanity(ks2)
       +        self.assertTrue(isinstance(ks2, keystore.BIP32_KeyStore))
       +
       +        w = self._create_multisig_wallet(ks1, ks2)
       +
       +        self.assertEqual(w.get_receiving_addresses()[0], '35hp2ELdVzs3xF7cFhsuifV9HnyHpNAwbf')
       +        self.assertEqual(w.get_change_addresses()[0], '39LMwwqYwx8XUNCs83FQ82nNBCpu3JDrcW')
       +
       +    @mock.patch.object(storage.WalletStorage, '_write')
       +    def test_bip39_multisig_seed_bip49_p2sh_segwit(self, mock_write):
       +        seed_words = 'treat dwarf wealth gasp brass outside high rent blood crowd make initial'
       +        self.assertEqual(keystore.bip39_is_checksum_valid(seed_words), (True, True))
       +
       +        ks1 = keystore.from_bip39_seed(seed_words, '', "m/49'/0'/0'")
       +        self.assertTrue(isinstance(ks1, keystore.BIP32_KeyStore))
       +        self.assertEqual(ks1.xpub, 'ypub6XDth9u8DzXV1tcpDtoDKMf6kVMaVMn1juVWEesTshcX4zUVvfNgjPJLXrD9N7AdTLnbHFL64KmBn3SNaTe69iZYbYCqLCCNPZKbLz9niQ4')
       +
       +        ks2 = keystore.from_xpub('ypub6WnnkE8TGSfWMb6QUVYoVsDRwpCUR98xUg7JnSoVuK7w41UGNViztuCCd8f4mHi6KkUahrh5CnZex1PJNi3oKcSCZ9Lni4huF5FAGouGkuz')
       +        self._check_xpub_keystore_sanity(ks2)
       +        self.assertTrue(isinstance(ks2, keystore.BIP32_KeyStore))
       +
       +        w = self._create_multisig_wallet(ks1, ks2)
       +
       +        self.assertEqual(w.get_receiving_addresses()[0], '33hvqSEadWahj8WUbAcoLFBEXBRThuUDQd')
       +        self.assertEqual(w.get_change_addresses()[0], '39Soij7BaNmD83d9NXF2283sqjb5Vwhe1m')