ttest_wallet_vertical.py - electrum - Electrum Bitcoin wallet
HTML git clone https://git.parazyd.org/electrum
DIR Log
DIR Files
DIR Refs
DIR Submodules
---
ttest_wallet_vertical.py (357049B)
---
1 import unittest
2 from unittest import mock
3 import shutil
4 import tempfile
5 from typing import Sequence
6 import asyncio
7 import copy
8
9 from electrum import storage, bitcoin, keystore, bip32, wallet
10 from electrum import Transaction
11 from electrum import SimpleConfig
12 from electrum.address_synchronizer import TX_HEIGHT_UNCONFIRMED, TX_HEIGHT_UNCONF_PARENT
13 from electrum.wallet import (sweep, Multisig_Wallet, Standard_Wallet, Imported_Wallet,
14 restore_wallet_from_text, Abstract_Wallet, BumpFeeStrategy)
15 from electrum.util import bfh, bh2u, create_and_start_event_loop
16 from electrum.transaction import (TxOutput, Transaction, PartialTransaction, PartialTxOutput,
17 PartialTxInput, tx_from_any, TxOutpoint)
18 from electrum.mnemonic import seed_type
19
20 from electrum.plugins.trustedcoin import trustedcoin
21
22 from . import TestCaseForTestnet
23 from . import ElectrumTestCase
24
25
26 UNICODE_HORROR_HEX = 'e282bf20f09f988020f09f98882020202020e3818620e38191e3819fe381be20e3828fe3828b2077cda2cda2cd9d68cda16fcda2cda120ccb8cda26bccb5cd9f6eccb4cd98c7ab77ccb8cc9b73cd9820cc80cc8177cd98cda2e1b8a9ccb561d289cca1cda27420cca7cc9568cc816fccb572cd8fccb5726f7273cca120ccb6cda1cda06cc4afccb665cd9fcd9f20ccb6cd9d696ecda220cd8f74cc9568ccb7cca1cd9f6520cd9fcd9f64cc9b61cd9c72cc95cda16bcca2cca820cda168ccb465cd8f61ccb7cca2cca17274cc81cd8f20ccb4ccb7cda0c3b2ccb5ccb666ccb82075cca7cd986ec3adcc9bcd9c63cda2cd8f6fccb7cd8f64ccb8cda265cca1cd9d3fcd9e'
27 UNICODE_HORROR = bfh(UNICODE_HORROR_HEX).decode('utf-8')
28 assert UNICODE_HORROR == '₿ 😀 😈 う けたま わる w͢͢͝h͡o͢͡ ̸͢k̵͟n̴͘ǫw̸̛s͘ ̀́w͘͢ḩ̵a҉̡͢t ̧̕h́o̵r͏̵rors̡ ̶͡͠lį̶e͟͟ ̶͝in͢ ͏t̕h̷̡͟e ͟͟d̛a͜r̕͡k̢̨ ͡h̴e͏a̷̢̡rt́͏ ̴̷͠ò̵̶f̸ u̧͘ní̛͜c͢͏o̷͏d̸͢e̡͝?͞'
29
30
31 class WalletIntegrityHelper:
32
33 gap_limit = 1 # make tests run faster
34
35 @classmethod
36 def check_seeded_keystore_sanity(cls, test_obj, ks):
37 test_obj.assertTrue(ks.is_deterministic())
38 test_obj.assertFalse(ks.is_watching_only())
39 test_obj.assertFalse(ks.can_import())
40 test_obj.assertTrue(ks.has_seed())
41
42 @classmethod
43 def check_xpub_keystore_sanity(cls, test_obj, ks):
44 test_obj.assertTrue(ks.is_deterministic())
45 test_obj.assertTrue(ks.is_watching_only())
46 test_obj.assertFalse(ks.can_import())
47 test_obj.assertFalse(ks.has_seed())
48
49 @classmethod
50 def create_standard_wallet(cls, ks, *, config: SimpleConfig, gap_limit=None):
51 db = storage.WalletDB('', manual_upgrades=False)
52 db.put('keystore', ks.dump())
53 db.put('gap_limit', gap_limit or cls.gap_limit)
54 w = Standard_Wallet(db, None, config=config)
55 w.synchronize()
56 return w
57
58 @classmethod
59 def create_imported_wallet(cls, *, config: SimpleConfig, privkeys: bool):
60 db = storage.WalletDB('', manual_upgrades=False)
61 if privkeys:
62 k = keystore.Imported_KeyStore({})
63 db.put('keystore', k.dump())
64 w = Imported_Wallet(db, None, config=config)
65 return w
66
67 @classmethod
68 def create_multisig_wallet(cls, keystores: Sequence, multisig_type: str, *,
69 config: SimpleConfig, gap_limit=None):
70 """Creates a multisig wallet."""
71 db = storage.WalletDB('', manual_upgrades=True)
72 for i, ks in enumerate(keystores):
73 cosigner_index = i + 1
74 db.put('x%d/' % cosigner_index, ks.dump())
75 db.put('wallet_type', multisig_type)
76 db.put('gap_limit', gap_limit or cls.gap_limit)
77 w = Multisig_Wallet(db, None, config=config)
78 w.synchronize()
79 return w
80
81
82 class TestWalletKeystoreAddressIntegrityForMainnet(ElectrumTestCase):
83
84 def setUp(self):
85 super().setUp()
86 self.config = SimpleConfig({'electrum_path': self.electrum_path})
87
88 @mock.patch.object(wallet.Abstract_Wallet, 'save_db')
89 def test_electrum_seed_standard(self, mock_save_db):
90 seed_words = 'cycle rocket west magnet parrot shuffle foot correct salt library feed song'
91 self.assertEqual(seed_type(seed_words), 'standard')
92
93 ks = keystore.from_seed(seed_words, '', False)
94
95 WalletIntegrityHelper.check_seeded_keystore_sanity(self, ks)
96 self.assertTrue(isinstance(ks, keystore.BIP32_KeyStore))
97
98 self.assertEqual(ks.xprv, 'xprv9s21ZrQH143K32jECVM729vWgGq4mUDJCk1ozqAStTphzQtCTuoFmFafNoG1g55iCnBTXUzz3zWnDb5CVLGiFvmaZjuazHDL8a81cPQ8KL6')
99 self.assertEqual(ks.xpub, 'xpub661MyMwAqRbcFWohJWt7PHsFEJfZAvw9ZxwQoDa4SoMgsDDM1T7WK3u9E4edkC4ugRnZ8E4xDZRpk8Rnts3Nbt97dPwT52CwBdDWroaZf8U')
100
101 w = WalletIntegrityHelper.create_standard_wallet(ks, config=self.config)
102 self.assertEqual(w.txin_type, 'p2pkh')
103
104 self.assertEqual(w.get_receiving_addresses()[0], '1NNkttn1YvVGdqBW4PR6zvc3Zx3H5owKRf')
105 self.assertEqual(w.get_change_addresses()[0], '1KSezYMhAJMWqFbVFB2JshYg69UpmEXR4D')
106
107 @mock.patch.object(wallet.Abstract_Wallet, 'save_db')
108 def test_electrum_seed_segwit(self, mock_save_db):
109 seed_words = 'bitter grass shiver impose acquire brush forget axis eager alone wine silver'
110 self.assertEqual(seed_type(seed_words), 'segwit')
111
112 ks = keystore.from_seed(seed_words, '', False)
113
114 WalletIntegrityHelper.check_seeded_keystore_sanity(self, ks)
115 self.assertTrue(isinstance(ks, keystore.BIP32_KeyStore))
116
117 self.assertEqual(ks.xprv, 'zprvAZswDvNeJeha8qZ8g7efN3FXYVJLaEUsE9TW6qXDEbVe74AZ75c2sZFZXPNFzxnhChDQ89oC8C5AjWwHmH1HeRKE1c4kKBQAmjUDdKDUZw2')
118 self.assertEqual(ks.xpub, 'zpub6nsHdRuY92FsMKdbn9BfjBCG6X8pyhCibNP6uDvpnw2cyrVhecvHRMa3Ne8kdJZxjxgwnpbHLkcR4bfnhHy6auHPJyDTQ3kianeuVLdkCYQ')
119
120 w = WalletIntegrityHelper.create_standard_wallet(ks, config=self.config)
121 self.assertEqual(w.txin_type, 'p2wpkh')
122
123 self.assertEqual(w.get_receiving_addresses()[0], 'bc1q3g5tmkmlvxryhh843v4dz026avatc0zzr6h3af')
124 self.assertEqual(w.get_change_addresses()[0], 'bc1qdy94n2q5qcp0kg7v9yzwe6wvfkhnvyzje7nx2p')
125
126 @mock.patch.object(wallet.Abstract_Wallet, 'save_db')
127 def test_electrum_seed_segwit_passphrase(self, mock_save_db):
128 seed_words = 'bitter grass shiver impose acquire brush forget axis eager alone wine silver'
129 self.assertEqual(seed_type(seed_words), 'segwit')
130
131 ks = keystore.from_seed(seed_words, UNICODE_HORROR, False)
132
133 WalletIntegrityHelper.check_seeded_keystore_sanity(self, ks)
134 self.assertTrue(isinstance(ks, keystore.BIP32_KeyStore))
135
136 self.assertEqual(ks.xprv, 'zprvAZDmEQiCLUcZXPfrBXoksCD2R6RMAzAre7SUyBotibisy9c7vGhLYvHaP3d9rYU12DKAWdZfscPNA7qEPgTkCDqX5sE93ryAJAQvkDbfLxU')
137 self.assertEqual(ks.xpub, 'zpub6nD7dvF6ArArjskKHZLmEL9ky8FqaSti1LN5maDWGwFrqwwGTp1b6ic4EHwciFNaYDmCXcQYxXSiF9BjcLCMPcaYkVN2nQD6QjYQ8vpSR3Z')
138
139 w = WalletIntegrityHelper.create_standard_wallet(ks, config=self.config)
140 self.assertEqual(w.txin_type, 'p2wpkh')
141
142 self.assertEqual(w.get_receiving_addresses()[0], 'bc1qx94dutas7ysn2my645cyttujrms5d9p57f6aam')
143 self.assertEqual(w.get_change_addresses()[0], 'bc1qcywwsy87sdp8vz5rfjh3sxdv6rt95kujdqq38g')
144
145 @mock.patch.object(wallet.Abstract_Wallet, 'save_db')
146 def test_electrum_seed_old(self, mock_save_db):
147 seed_words = 'powerful random nobody notice nothing important anyway look away hidden message over'
148 self.assertEqual(seed_type(seed_words), 'old')
149
150 ks = keystore.from_seed(seed_words, '', False)
151
152 WalletIntegrityHelper.check_seeded_keystore_sanity(self, ks)
153 self.assertTrue(isinstance(ks, keystore.Old_KeyStore))
154
155 self.assertEqual(ks.mpk, 'e9d4b7866dd1e91c862aebf62a49548c7dbf7bcc6e4b7b8c9da820c7737968df9c09d5a3e271dc814a29981f81b3faaf2737b551ef5dcc6189cf0f8252c442b3')
156
157 w = WalletIntegrityHelper.create_standard_wallet(ks, config=self.config)
158 self.assertEqual(w.txin_type, 'p2pkh')
159
160 self.assertEqual(w.get_receiving_addresses()[0], '1FJEEB8ihPMbzs2SkLmr37dHyRFzakqUmo')
161 self.assertEqual(w.get_change_addresses()[0], '1KRW8pH6HFHZh889VDq6fEKvmrsmApwNfe')
162
163 @mock.patch.object(wallet.Abstract_Wallet, 'save_db')
164 def test_electrum_seed_2fa_legacy_pre27(self, mock_save_db):
165 # pre-version-2.7 2fa seed
166 seed_words = 'bind clever room kidney crucial sausage spy edit canvas soul liquid ribbon slam open alpha suffer gate relax voice carpet law hill woman tonight abstract'
167 self.assertEqual(seed_type(seed_words), '2fa')
168
169 xprv1, xpub1, xprv2, xpub2 = trustedcoin.TrustedCoinPlugin.xkeys_from_seed(seed_words, '')
170
171 ks1 = keystore.from_xprv(xprv1)
172 self.assertTrue(isinstance(ks1, keystore.BIP32_KeyStore))
173 self.assertEqual(ks1.xprv, 'xprv9s21ZrQH143K2TsDemiaPqaTuBkW3gns4sGi9f65pWtg27nmmmAut6fErgaHFxj3d4rHgyFKjhvtAUafqF3wwU8Bkou8LefQgBtRWjUKN3V')
174 self.assertEqual(ks1.xpub, 'xpub661MyMwAqRbcEwwgkoFakyXCTDazT9WiS6CJx3VhNrRetv7vKJVARtyihwCVatSsUtVsEYcvdxhvDtkSk8qKV3VVtcL3csz6sQTbGzmEckd')
175 self.assertEqual(ks1.xpub, xpub1)
176
177 ks2 = keystore.from_xprv(xprv2)
178 self.assertTrue(isinstance(ks2, keystore.BIP32_KeyStore))
179 self.assertEqual(ks2.xprv, 'xprv9s21ZrQH143K3r6H1h91TqRECE7tmDB5PYGZDKPuSjefTzNbDMauUMUnjsUSv8X8nuzQsrtGmtCuA51CNz7XimRj2HPYxUxXGGf4KB7M74y')
180 self.assertEqual(ks2.xpub, 'xpub661MyMwAqRbcGLAk7ig1pyMxkFxPAftvkmCA1hoX15BeLnhjktuA29oGb7bh9opQgNERu6iWhwcY6b5bZX57dYsGo7zYjwXTNCryfKuPfek')
181 self.assertEqual(ks2.xpub, xpub2)
182
183 long_user_id, short_id = trustedcoin.get_user_id(
184 {'x1/': {'xpub': xpub1},
185 'x2/': {'xpub': xpub2}})
186 xtype = bip32.xpub_type(xpub1)
187 xpub3 = trustedcoin.make_xpub(trustedcoin.get_signing_xpub(xtype), long_user_id)
188 ks3 = keystore.from_xpub(xpub3)
189 WalletIntegrityHelper.check_xpub_keystore_sanity(self, ks3)
190 self.assertTrue(isinstance(ks3, keystore.BIP32_KeyStore))
191
192 w = WalletIntegrityHelper.create_multisig_wallet([ks1, ks2, ks3], '2of3', config=self.config)
193 self.assertEqual(w.txin_type, 'p2sh')
194
195 self.assertEqual(w.get_receiving_addresses()[0], '3Bw5jczNModhFAbvfwvUHbdGrC2Lh2qRQp')
196 self.assertEqual(w.get_change_addresses()[0], '3Ke6pKrmtSyyQaMob1ES4pk8siAAkRmst9')
197
198 @mock.patch.object(wallet.Abstract_Wallet, 'save_db')
199 def test_electrum_seed_2fa_legacy_post27(self, mock_save_db):
200 # post-version-2.7 2fa seed
201 seed_words = 'kiss live scene rude gate step hip quarter bunker oxygen motor glove'
202 self.assertEqual(seed_type(seed_words), '2fa')
203
204 xprv1, xpub1, xprv2, xpub2 = trustedcoin.TrustedCoinPlugin.xkeys_from_seed(seed_words, '')
205
206 ks1 = keystore.from_xprv(xprv1)
207 self.assertTrue(isinstance(ks1, keystore.BIP32_KeyStore))
208 self.assertEqual(ks1.xprv, 'xprv9uraXy9F3HP7i8QDqwNTBiD8Jf4bPD4Epif8cS8qbUbgeidUesyZpKmzfcSeHutsGfFnjgih7kzwTB5UQVRNB5LoXaNc8pFusKYx3KVVvYR')
209 self.assertEqual(ks1.xpub, 'xpub68qvwUg8sewQvcUgwxuTYr9rrgu5nfn6BwajQpYT9p8fXWxdCRHpN86UWruWJAD1ede8Sv8ERrTa22Gyc4SBfm7zFpcyoVWVBKCVwnw6s1J')
210 self.assertEqual(ks1.xpub, xpub1)
211
212 ks2 = keystore.from_xprv(xprv2)
213 self.assertTrue(isinstance(ks2, keystore.BIP32_KeyStore))
214 self.assertEqual(ks2.xprv, 'xprv9uraXy9F3HP7kKSiRAvLV7Nrjj7YzspDys7dvGLLu4tLZT49CEBxPWp88dHhVxvZ69SHrPQMUCWjj4Ka2z9kNvs1HAeEf3extGGeSWqEVqf')
215 self.assertEqual(ks2.xpub, 'xpub68qvwUg8sewQxoXBXCTLrFKbHkx3QLY5M63EiejxTQRKSFPHjmWCwK8byvZMM2wZNYA3SmxXoma3M1zxhGESHZwtB7SwrxRgKXAG8dCD2eS')
216 self.assertEqual(ks2.xpub, xpub2)
217
218 long_user_id, short_id = trustedcoin.get_user_id(
219 {'x1/': {'xpub': xpub1},
220 'x2/': {'xpub': xpub2}})
221 xtype = bip32.xpub_type(xpub1)
222 xpub3 = trustedcoin.make_xpub(trustedcoin.get_signing_xpub(xtype), long_user_id)
223 ks3 = keystore.from_xpub(xpub3)
224 WalletIntegrityHelper.check_xpub_keystore_sanity(self, ks3)
225 self.assertTrue(isinstance(ks3, keystore.BIP32_KeyStore))
226
227 w = WalletIntegrityHelper.create_multisig_wallet([ks1, ks2, ks3], '2of3', config=self.config)
228 self.assertEqual(w.txin_type, 'p2sh')
229
230 self.assertEqual(w.get_receiving_addresses()[0], '35L8XmCDoEBKeaWRjvmZvoZvhp8BXMMMPV')
231 self.assertEqual(w.get_change_addresses()[0], '3PeZEcumRqHSPNN43hd4yskGEBdzXgY8Cy')
232
233 @mock.patch.object(wallet.Abstract_Wallet, 'save_db')
234 def test_electrum_seed_2fa_segwit(self, mock_save_db):
235 seed_words = 'universe topic remind silver february ranch shine worth innocent cattle enhance wise'
236 self.assertEqual(seed_type(seed_words), '2fa_segwit')
237
238 xprv1, xpub1, xprv2, xpub2 = trustedcoin.TrustedCoinPlugin.xkeys_from_seed(seed_words, '')
239
240 ks1 = keystore.from_xprv(xprv1)
241 self.assertTrue(isinstance(ks1, keystore.BIP32_KeyStore))
242 self.assertEqual(ks1.xprv, 'ZprvAm1R3RZMrkSLYKZer8QECGoc8oA1RQuKfsztHkBTmi2yF8RhmN1JRb7Ag69mMrL88sP67WiaegaSSDnKndorWEpFr7a5B2QgrD7TkERSYX6')
243 self.assertEqual(ks1.xpub, 'Zpub6yzmSw6Fh7zdkoe7x9wEZQkLgpzVpsdB36vV68b5L3Zx7vkrJuKYyPReXMSjBegmtUjFBxP2uZEdL87cYvtTtGaVuwtRRCTSFUsoAdKZMge')
244 self.assertEqual(ks1.xpub, xpub1)
245
246 ks2 = keystore.from_xprv(xprv2)
247 self.assertTrue(isinstance(ks2, keystore.BIP32_KeyStore))
248 self.assertEqual(ks2.xprv, 'ZprvAm1R3RZMrkSLab4jVKTwuroBgKEfnsmK9CQa1ErkuRzpsPauYuv9z2UzhDNn9YgbLHcmXpmxbNq4MdDRAUM5B2N9Wr3Uq9yp2c4AtTJDFdi')
249 self.assertEqual(ks2.xpub, 'Zpub6yzmSw6Fh7zdo59CbLzxGzjvEM5ACLVAWRLAodGNTmXokBv46TEQXpoUYUaoxPCeynysxg7APfScikCQ2jhCfM3NcNEk46BCVfSSrdrSkbR')
250 self.assertEqual(ks2.xpub, xpub2)
251
252 long_user_id, short_id = trustedcoin.get_user_id(
253 {'x1/': {'xpub': xpub1},
254 'x2/': {'xpub': xpub2}})
255 xtype = bip32.xpub_type(xpub1)
256 xpub3 = trustedcoin.make_xpub(trustedcoin.get_signing_xpub(xtype), long_user_id)
257 ks3 = keystore.from_xpub(xpub3)
258 WalletIntegrityHelper.check_xpub_keystore_sanity(self, ks3)
259 self.assertTrue(isinstance(ks3, keystore.BIP32_KeyStore))
260
261 w = WalletIntegrityHelper.create_multisig_wallet([ks1, ks2, ks3], '2of3', config=self.config)
262 self.assertEqual(w.txin_type, 'p2wsh')
263
264 self.assertEqual(w.get_receiving_addresses()[0], 'bc1qpmufh0zjp5prfsrk2yskcy82sa26srqkd97j0457andc6m0gh5asw7kqd2')
265 self.assertEqual(w.get_change_addresses()[0], 'bc1qd4q50nft7kxm9yglfnpup9ed2ukj3tkxp793y0zya8dc9m39jcwq308dxz')
266
267 @mock.patch.object(wallet.Abstract_Wallet, 'save_db')
268 def test_bip39_seed_bip44_standard(self, mock_save_db):
269 seed_words = 'treat dwarf wealth gasp brass outside high rent blood crowd make initial'
270 self.assertEqual(keystore.bip39_is_checksum_valid(seed_words), (True, True))
271
272 ks = keystore.from_bip39_seed(seed_words, '', "m/44'/0'/0'")
273
274 self.assertTrue(isinstance(ks, keystore.BIP32_KeyStore))
275
276 self.assertEqual(ks.xprv, 'xprv9zGLcNEb3cHUKizLVBz6RYeE9bEZAVPjH2pD1DEzCnPcsemWc3d3xTao8sfhfUmDLMq6e3RcEMEvJG1Et8dvfL8DV4h7mwm9J6AJsW9WXQD')
277 self.assertEqual(ks.xpub, 'xpub6DFh1smUsyqmYD4obDX6ngaxhd53Zx7aeFjoobebm7vbkT6f9awJWFuGzBT9FQJEWFBL7UyhMXtYzRcwDuVbcxtv9Ce2W9eMm4KXLdvdbjv')
278
279 w = WalletIntegrityHelper.create_standard_wallet(ks, config=self.config)
280 self.assertEqual(w.txin_type, 'p2pkh')
281
282 self.assertEqual(w.get_receiving_addresses()[0], '16j7Dqk3Z9DdTdBtHcCVLaNQy9MTgywUUo')
283 self.assertEqual(w.get_change_addresses()[0], '1GG5bVeWgAp5XW7JLCphse14QaC4qiHyWn')
284
285 @mock.patch.object(wallet.Abstract_Wallet, 'save_db')
286 def test_bip39_seed_bip44_standard_passphrase(self, mock_save_db):
287 seed_words = 'treat dwarf wealth gasp brass outside high rent blood crowd make initial'
288 self.assertEqual(keystore.bip39_is_checksum_valid(seed_words), (True, True))
289
290 ks = keystore.from_bip39_seed(seed_words, UNICODE_HORROR, "m/44'/0'/0'")
291
292 self.assertTrue(isinstance(ks, keystore.BIP32_KeyStore))
293
294 self.assertEqual(ks.xprv, 'xprv9z8izheguGnLopSqkY7GcGFrP2Gu6rzBvvHo6uB9B8DWJhsows6WDZAsbBTaP3ncP2AVbTQphyEQkahrB9s1L7ihZtfz5WGQPMbXwsUtSik')
295 self.assertEqual(ks.xpub, 'xpub6D85QDBajeLe2JXJrZeGyQCaw47PWKi3J9DPuHakjTkVBWCxVQQkmMVMSSfnw39tj9FntbozpRtb1AJ8ubjeVSBhyK4M5mzdvsXZzKPwodT')
296
297 w = WalletIntegrityHelper.create_standard_wallet(ks, config=self.config)
298 self.assertEqual(w.txin_type, 'p2pkh')
299
300 self.assertEqual(w.get_receiving_addresses()[0], '1F88g2naBMhDB7pYFttPWGQgryba3hPevM')
301 self.assertEqual(w.get_change_addresses()[0], '1H4QD1rg2zQJ4UjuAVJr5eW1fEM8WMqyxh')
302
303 @mock.patch.object(wallet.Abstract_Wallet, 'save_db')
304 def test_bip39_seed_bip49_p2sh_segwit(self, mock_save_db):
305 seed_words = 'treat dwarf wealth gasp brass outside high rent blood crowd make initial'
306 self.assertEqual(keystore.bip39_is_checksum_valid(seed_words), (True, True))
307
308 ks = keystore.from_bip39_seed(seed_words, '', "m/49'/0'/0'")
309
310 self.assertTrue(isinstance(ks, keystore.BIP32_KeyStore))
311
312 self.assertEqual(ks.xprv, 'yprvAJEYHeNEPcyBoQYM7sGCxDiNCTX65u4ANgZuSGTrKN5YCC9MP84SBayrgaMyZV7zvkHrr3HVPTK853s2SPk4EttPazBZBmz6QfDkXeE8Zr7')
313 self.assertEqual(ks.xpub, 'ypub6XDth9u8DzXV1tcpDtoDKMf6kVMaVMn1juVWEesTshcX4zUVvfNgjPJLXrD9N7AdTLnbHFL64KmBn3SNaTe69iZYbYCqLCCNPZKbLz9niQ4')
314
315 w = WalletIntegrityHelper.create_standard_wallet(ks, config=self.config)
316 self.assertEqual(w.txin_type, 'p2wpkh-p2sh')
317
318 self.assertEqual(w.get_receiving_addresses()[0], '35ohQTdNykjkF1Mn9nAVEFjupyAtsPAK1W')
319 self.assertEqual(w.get_change_addresses()[0], '3KaBTcviBLEJajTEMstsA2GWjYoPzPK7Y7')
320
321 @mock.patch.object(wallet.Abstract_Wallet, 'save_db')
322 def test_bip39_seed_bip84_native_segwit(self, mock_save_db):
323 # test case from bip84
324 seed_words = 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about'
325 self.assertEqual(keystore.bip39_is_checksum_valid(seed_words), (True, True))
326
327 ks = keystore.from_bip39_seed(seed_words, '', "m/84'/0'/0'")
328
329 self.assertTrue(isinstance(ks, keystore.BIP32_KeyStore))
330
331 self.assertEqual(ks.xprv, 'zprvAdG4iTXWBoARxkkzNpNh8r6Qag3irQB8PzEMkAFeTRXxHpbF9z4QgEvBRmfvqWvGp42t42nvgGpNgYSJA9iefm1yYNZKEm7z6qUWCroSQnE')
332 self.assertEqual(ks.xpub, 'zpub6rFR7y4Q2AijBEqTUquhVz398htDFrtymD9xYYfG1m4wAcvPhXNfE3EfH1r1ADqtfSdVCToUG868RvUUkgDKf31mGDtKsAYz2oz2AGutZYs')
333
334 w = WalletIntegrityHelper.create_standard_wallet(ks, config=self.config)
335 self.assertEqual(w.txin_type, 'p2wpkh')
336
337 self.assertEqual(w.get_receiving_addresses()[0], 'bc1qcr8te4kr609gcawutmrza0j4xv80jy8z306fyu')
338 self.assertEqual(w.get_change_addresses()[0], 'bc1q8c6fshw2dlwun7ekn9qwf37cu2rn755upcp6el')
339
340 @mock.patch.object(wallet.Abstract_Wallet, 'save_db')
341 def test_electrum_multisig_seed_standard(self, mock_save_db):
342 seed_words = 'blast uniform dragon fiscal ensure vast young utility dinosaur abandon rookie sure'
343 self.assertEqual(seed_type(seed_words), 'standard')
344
345 ks1 = keystore.from_seed(seed_words, '', True)
346 WalletIntegrityHelper.check_seeded_keystore_sanity(self, ks1)
347 self.assertTrue(isinstance(ks1, keystore.BIP32_KeyStore))
348 self.assertEqual(ks1.xprv, 'xprv9s21ZrQH143K3t9vo23J3hajRbzvkRLJ6Y1zFrUFAfU3t8oooMPfb7f87cn5KntgqZs5nipZkCiBFo5ZtaSD2eDo7j7CMuFV8Zu6GYLTpY6')
349 self.assertEqual(ks1.xpub, 'xpub661MyMwAqRbcGNEPu3aJQqXTydqR9t49Tkwb4Esrj112kw8xLthv8uybxvaki4Ygt9xiwZUQGeFTG7T2TUzR3eA4Zp3aq5RXsABHFBUrq4c')
350
351 # electrum seed: ghost into match ivory badge robot record tackle radar elbow traffic loud
352 ks2 = keystore.from_xpub('xpub661MyMwAqRbcGfCPEkkyo5WmcrhTq8mi3xuBS7VEZ3LYvsgY1cCFDbenT33bdD12axvrmXhuX3xkAbKci3yZY9ZEk8vhLic7KNhLjqdh5ec')
353 WalletIntegrityHelper.check_xpub_keystore_sanity(self, ks2)
354 self.assertTrue(isinstance(ks2, keystore.BIP32_KeyStore))
355
356 w = WalletIntegrityHelper.create_multisig_wallet([ks1, ks2], '2of2', config=self.config)
357 self.assertEqual(w.txin_type, 'p2sh')
358
359 self.assertEqual(w.get_receiving_addresses()[0], '32ji3QkAgXNz6oFoRfakyD3ys1XXiERQYN')
360 self.assertEqual(w.get_change_addresses()[0], '36XWwEHrrVCLnhjK5MrVVGmUHghr9oWTN1')
361
362 @mock.patch.object(wallet.Abstract_Wallet, 'save_db')
363 def test_electrum_multisig_seed_segwit(self, mock_save_db):
364 seed_words = 'snow nest raise royal more walk demise rotate smooth spirit canyon gun'
365 self.assertEqual(seed_type(seed_words), 'segwit')
366
367 ks1 = keystore.from_seed(seed_words, '', True)
368 WalletIntegrityHelper.check_seeded_keystore_sanity(self, ks1)
369 self.assertTrue(isinstance(ks1, keystore.BIP32_KeyStore))
370 self.assertEqual(ks1.xprv, 'ZprvAjxLRqPiDfPDxXrm8JvcoCGRAW6xUtktucG6AMtdzaEbTEJN8qcECvujfhtDU3jLJ9g3Dr3Gz5m1ypfMs8iSUh62gWyHZ73bYLRWyeHf6y4')
371 self.assertEqual(ks1.xpub, 'Zpub6xwgqLvc42wXB1wEELTdALD9iXwStMUkGqBgxkJFYumaL2dWgNvUkjEDWyDFZD3fZuDWDzd1KQJ4NwVHS7hs6H6QkpNYSShfNiUZsgMdtNg')
372
373 # electrum seed: hedgehog sunset update estate number jungle amount piano friend donate upper wool
374 ks2 = keystore.from_xpub('Zpub6y4oYeETXAbzLNg45wcFDGwEG3vpgsyMJybiAfi2pJtNF3i3fJVxK2BeZJaw7VeKZm192QHvXP3uHDNpNmNDbQft9FiMzkKUhNXQafUMYUY')
375 WalletIntegrityHelper.check_xpub_keystore_sanity(self, ks2)
376 self.assertTrue(isinstance(ks2, keystore.BIP32_KeyStore))
377
378 w = WalletIntegrityHelper.create_multisig_wallet([ks1, ks2], '2of2', config=self.config)
379 self.assertEqual(w.txin_type, 'p2wsh')
380
381 self.assertEqual(w.get_receiving_addresses()[0], 'bc1qvzezdcv6vs5h45ugkavp896e0nde5c5lg5h0fwe2xyfhnpkxq6gq7pnwlc')
382 self.assertEqual(w.get_change_addresses()[0], 'bc1qxqf840dqswcmu7a8v82fj6ej0msx08flvuy6kngr7axstjcaq6us9hrehd')
383
384 @mock.patch.object(wallet.Abstract_Wallet, 'save_db')
385 def test_bip39_multisig_seed_bip45_standard(self, mock_save_db):
386 seed_words = 'treat dwarf wealth gasp brass outside high rent blood crowd make initial'
387 self.assertEqual(keystore.bip39_is_checksum_valid(seed_words), (True, True))
388
389 ks1 = keystore.from_bip39_seed(seed_words, '', "m/45'/0")
390 self.assertTrue(isinstance(ks1, keystore.BIP32_KeyStore))
391 self.assertEqual(ks1.xprv, 'xprv9vyEFyXf7pYVv4eDU3hhuCEAHPHNGuxX73nwtYdpbLcqwJCPwFKknAK8pHWuHHBirCzAPDZ7UJHrYdhLfn1NkGp9rk3rVz2aEqrT93qKRD9')
392 self.assertEqual(ks1.xpub, 'xpub69xafV4YxC6o8Yiga5EiGLAtqR7rgNgNUGiYgw3S9g9pp6XYUne1KxdcfYtxwmA3eBrzMFuYcNQKfqsXCygCo4GxQFHfywxpUbKNfYvGJka')
393
394 # bip39 seed: tray machine cook badge night page project uncover ritual toward person enact
395 # der: m/45'/0
396 ks2 = keystore.from_xpub('xpub6B26nSWddbWv7J3qQn9FbwPPQktSBdPQfLfHhRK4375QoZq8fvM8rQey1koGSTxC5xVoMzNMaBETMUmCqmXzjc8HyAbN7LqrvE4ovGRwNGg')
397 WalletIntegrityHelper.check_xpub_keystore_sanity(self, ks2)
398 self.assertTrue(isinstance(ks2, keystore.BIP32_KeyStore))
399
400 w = WalletIntegrityHelper.create_multisig_wallet([ks1, ks2], '2of2', config=self.config)
401 self.assertEqual(w.txin_type, 'p2sh')
402
403 self.assertEqual(w.get_receiving_addresses()[0], '3JPTQ2nitVxXBJ1yhMeDwH6q417UifE3bN')
404 self.assertEqual(w.get_change_addresses()[0], '3FGyDuxgUDn2pSZe5xAJH1yUwSdhzDMyEE')
405
406 @mock.patch.object(wallet.Abstract_Wallet, 'save_db')
407 def test_bip39_multisig_seed_p2sh_segwit(self, mock_save_db):
408 # bip39 seed: pulse mixture jazz invite dune enrich minor weapon mosquito flight fly vapor
409 # der: m/49'/0'/0'
410 # NOTE: there is currently no bip43 standard derivation path for p2wsh-p2sh
411 ks1 = keystore.from_xprv('YprvAUXFReVvDjrPerocC3FxVH748sJUTvYjkAhtKop5VnnzVzMEHr1CHrYQKZwfJn1As3X4LYMav6upxd5nDiLb6SCjRZrBH76EFvyQAG4cn79')
412 self.assertTrue(isinstance(ks1, keystore.BIP32_KeyStore))
413 self.assertEqual(ks1.xpub, 'Ypub6hWbqA2p47QgsLt5J4nxrR3ngu8xsPGb7PdV8CDh48KyNngNqPKSqertAqYhQ4umELu1UsZUCYfj9XPA6AdSMZWDZQobwF7EJ8uNrECaZg1')
414
415 # bip39 seed: slab mixture skin evoke harsh tattoo rare crew sphere extend balcony frost
416 # der: m/49'/0'/0'
417 ks2 = keystore.from_xpub('Ypub6iNDhL4WWq5kFZcdFqHHwX4YTH4rYGp8xbndpRrY7WNZFFRfogSrL7wRTajmVHgR46AT1cqUG1mrcRd7h1WXwBsgX2QvT3zFbBCDiSDLkau')
418 WalletIntegrityHelper.check_xpub_keystore_sanity(self, ks2)
419 self.assertTrue(isinstance(ks2, keystore.BIP32_KeyStore))
420
421 w = WalletIntegrityHelper.create_multisig_wallet([ks1, ks2], '2of2', config=self.config)
422 self.assertEqual(w.txin_type, 'p2wsh-p2sh')
423
424 self.assertEqual(w.get_receiving_addresses()[0], '35LeC45QgCVeRor1tJD6LiDgPbybBXisns')
425 self.assertEqual(w.get_change_addresses()[0], '39RhtDchc6igmx5tyoimhojFL1ZbQBrXa6')
426
427 @mock.patch.object(wallet.Abstract_Wallet, 'save_db')
428 def test_bip32_extended_version_bytes(self, mock_save_db):
429 seed_words = 'crouch dumb relax small truck age shine pink invite spatial object tenant'
430 self.assertEqual(keystore.bip39_is_checksum_valid(seed_words), (True, True))
431 bip32_seed = keystore.bip39_to_seed(seed_words, '')
432 self.assertEqual('0df68c16e522eea9c1d8e090cfb2139c3b3a2abed78cbcb3e20be2c29185d3b8df4e8ce4e52a1206a688aeb88bfee249585b41a7444673d1f16c0d45755fa8b9',
433 bh2u(bip32_seed))
434
435 def create_keystore_from_bip32seed(xtype):
436 ks = keystore.BIP32_KeyStore({})
437 ks.add_xprv_from_seed(bip32_seed, xtype=xtype, derivation='m/')
438 return ks
439
440 ks = create_keystore_from_bip32seed(xtype='standard')
441 self.assertEqual('033a05ec7ae9a9833b0696eb285a762f17379fa208b3dc28df1c501cf84fe415d0', ks.derive_pubkey(0, 0).hex())
442 self.assertEqual('02bf27f41683d84183e4e930e66d64fc8af5508b4b5bf3c473c505e4dbddaeed80', ks.derive_pubkey(1, 0).hex())
443
444 ks = create_keystore_from_bip32seed(xtype='standard') # p2pkh
445 w = WalletIntegrityHelper.create_standard_wallet(ks, config=self.config)
446 self.assertEqual(ks.xprv, 'xprv9s21ZrQH143K3nyWMZVjzGL4KKAE1zahmhTHuV5pdw4eK3o3igC5QywgQG7UTRe6TGBniPDpPFWzXMeMUFbBj8uYsfXGjyMmF54wdNt8QBm')
447 self.assertEqual(ks.xpub, 'xpub661MyMwAqRbcGH3yTb2kMQGnsLziRTJZ8vNthsVSCGbdBr8CGDWKxnGAFYgyKTzBtwvPPmfVAWJuFmxRXjSbUTg87wDkWQ5GmzpfUcN9t8Z')
448 self.assertEqual(w.get_receiving_addresses()[0], '19fWEVaXqgJFFn7JYNr6ouxyjZy3uK7CdK')
449 self.assertEqual(w.get_change_addresses()[0], '1EEX7da31qndYyeKdbM665w1ze5gbkkAZZ')
450
451 ks = create_keystore_from_bip32seed(xtype='p2wpkh-p2sh')
452 w = WalletIntegrityHelper.create_standard_wallet(ks, config=self.config)
453 self.assertEqual(ks.xprv, 'yprvABrGsX5C9janu6AdBvHNCMRZVHJfxcaCgoyWgsyi1wSXN9cGyLMe33bpRU54TLJ1ruJbTrpNqusYQeFvBx1CXNb9k1DhKtBFWo8b1sLbXhN')
454 self.assertEqual(ks.xpub, 'ypub6QqdH2c5z7967aF6HwpNZVNJ3K9AN5J442u7VGPKaGyWEwwRWsftaqvJGkeZKNe7Jb3C9FG3dAfT94ZzFRrcGhMizGvB6Jtm3itJsEFhxMC')
455 self.assertEqual(w.get_receiving_addresses()[0], '34SAT5gGF5UaBhhSZ8qEuuxYvZ2cm7Zi23')
456 self.assertEqual(w.get_change_addresses()[0], '38unULZaetSGSKvDx7Krukh8zm8NQnxGiA')
457
458 ks = create_keystore_from_bip32seed(xtype='p2wpkh')
459 w = WalletIntegrityHelper.create_standard_wallet(ks, config=self.config)
460 self.assertEqual(ks.xprv, 'zprvAWgYBBk7JR8GkPMk2H4zQSX4fFT7uEZhbvVjUGsbPwpQRFRWDzXCf7FxSg2eTEwwGYRQDLQwJaE6HvsUueRDKcGkcLv7unzjnXCEQVWhrF9')
461 self.assertEqual(ks.xpub, 'zpub6jftahH18ngZxsSD8JbzmaToDHHcJhHYy9RLGfHCxHMPJ3kemXqTCuaSHxc9KHJ2iE9ztirc5q212MBYy8Gd4w3KrccbgDiFKSwxFpYKEH6')
462 self.assertEqual(w.get_receiving_addresses()[0], 'bc1qtuynwzd0d6wptvyqmc6ehkm70zcamxpshyzu5e')
463 self.assertEqual(w.get_change_addresses()[0], 'bc1qjy5zunxh6hjysele86qqywfa437z4xwmleq8wk')
464
465 ks = create_keystore_from_bip32seed(xtype='standard') # p2sh
466 w = WalletIntegrityHelper.create_multisig_wallet([ks], '1of1', config=self.config)
467 self.assertEqual(ks.xprv, 'xprv9s21ZrQH143K3nyWMZVjzGL4KKAE1zahmhTHuV5pdw4eK3o3igC5QywgQG7UTRe6TGBniPDpPFWzXMeMUFbBj8uYsfXGjyMmF54wdNt8QBm')
468 self.assertEqual(ks.xpub, 'xpub661MyMwAqRbcGH3yTb2kMQGnsLziRTJZ8vNthsVSCGbdBr8CGDWKxnGAFYgyKTzBtwvPPmfVAWJuFmxRXjSbUTg87wDkWQ5GmzpfUcN9t8Z')
469 self.assertEqual(w.get_receiving_addresses()[0], '3F4nm8Vunb7mxVvqhUP238PYge2hpU5qYv')
470 self.assertEqual(w.get_change_addresses()[0], '3N8jvKGmxzVHENn6B4zTdZt3N9bmRKjj96')
471
472 ks = create_keystore_from_bip32seed(xtype='p2wsh-p2sh')
473 w = WalletIntegrityHelper.create_multisig_wallet([ks], '1of1', config=self.config)
474 self.assertEqual(ks.xprv, 'YprvANkMzkodih9AKfL18akM2RmND5LwAyFo15dBc9FFPiGvzLBBjjjv8ATkEB2Y1mWv6NNaLSpVj8G3XosgVBA9frhpaUL6jHeFQXQTbqVPcv2')
475 self.assertEqual(ks.xpub, 'Ypub6bjiQGLXZ4hTY9QUEcHMPZi6m7BRaRyeNJYnQXerx3ous8WLHH4AfxnE5Tc2sos1Y47B1qGAWP3xGEBkYf1ZRBUPpk2aViMkwTABT6qoiBb')
476 self.assertEqual(w.get_receiving_addresses()[0], '3L1BxLLASGKE3DR1ruraWm3hZshGCKqcJx')
477 self.assertEqual(w.get_change_addresses()[0], '3NDGcbZVXTpaQWRhiuVPpXsNt4g2JiCX4E')
478
479 ks = create_keystore_from_bip32seed(xtype='p2wsh')
480 w = WalletIntegrityHelper.create_multisig_wallet([ks], '1of1', config=self.config)
481 self.assertEqual(ks.xprv, 'ZprvAhadJRUYsNgeAxX7xwXyEWrsP3VP7bFHvC9QPY98miep3RzQzPuUkE7tFNz81gAqW1VP5vR4BncbR6VFCsaAU6PRSp2XKCTjgFU6zRpk6Xp')
482 self.assertEqual(ks.xpub, 'Zpub6vZyhw1ShkEwPSbb4y4ybeobw5KsX3y9HR51BvYkL4BnvEKZXwDjJ2SN6fZcsiWvwhDymJriy3QW9WoKGMRaDR9zh5j15dBFDBDpqjK1ekQ')
483 self.assertEqual(w.get_receiving_addresses()[0], 'bc1q84x0yrztvcjg88qef4d6978zccxulcmc9y88xcg4ghjdau999x7q7zv2qe')
484 self.assertEqual(w.get_change_addresses()[0], 'bc1q0fj5mra96hhnum80kllklc52zqn6kppt3hyzr49yhr3ecr42z3tsrkg3gs')
485
486
487 class TestWalletKeystoreAddressIntegrityForTestnet(TestCaseForTestnet):
488
489 def setUp(self):
490 super().setUp()
491 self.config = SimpleConfig({'electrum_path': self.electrum_path})
492
493 @mock.patch.object(wallet.Abstract_Wallet, 'save_db')
494 def test_bip39_multisig_seed_p2sh_segwit_testnet(self, mock_save_db):
495 # bip39 seed: finish seminar arrange erosion sunny coil insane together pretty lunch lunch rose
496 # der: m/49'/1'/0'
497 # NOTE: there is currently no bip43 standard derivation path for p2wsh-p2sh
498 ks1 = keystore.from_xprv('Uprv9BEixD3As2LK5h6G2SNT3cTqbZpsWYPceKTSuVAm1yuSybxSvQz2MV1o8cHTtctQmj4HAenb3eh5YJv4YRZjv35i8fofVnNbs4Dd2B4i5je')
499 self.assertTrue(isinstance(ks1, keystore.BIP32_KeyStore))
500 self.assertEqual(ks1.xpub, 'Upub5QE5Mia4hPtcJBAj8TuTQkQa9bfMv17U1YP3hsaNaKSRrQHbTxJGuHLGyv3MbKZixuPyjfXGUdbTjE4KwyFcX8YD7PX5ybTDbP11UT8UpZR')
501
502 # bip39 seed: square page wood spy oil story rebel give milk screen slide shuffle
503 # der: m/49'/1'/0'
504 ks2 = keystore.from_xpub('Upub5QRzUGRJuWJe5MxGzwgQAeyJjzcdGTXkkq77w6EfBkCyf5iWppSaZ4caY2MgWcU9LP4a4uE5apUFN4wLoENoe9tpu26mrUxeGsH84dN3JFh')
505 WalletIntegrityHelper.check_xpub_keystore_sanity(self, ks2)
506 self.assertTrue(isinstance(ks2, keystore.BIP32_KeyStore))
507
508 w = WalletIntegrityHelper.create_multisig_wallet([ks1, ks2], '2of2', config=self.config)
509 self.assertEqual(w.txin_type, 'p2wsh-p2sh')
510
511 self.assertEqual(w.get_receiving_addresses()[0], '2MzsfTfTGomPRne6TkctMmoDj6LwmVkDrMt')
512 self.assertEqual(w.get_change_addresses()[0], '2NFp9w8tbYYP9Ze2xQpeYBJQjx3gbXymHX7')
513
514 @mock.patch.object(wallet.Abstract_Wallet, 'save_db')
515 def test_bip32_extended_version_bytes(self, mock_save_db):
516 seed_words = 'crouch dumb relax small truck age shine pink invite spatial object tenant'
517 self.assertEqual(keystore.bip39_is_checksum_valid(seed_words), (True, True))
518 bip32_seed = keystore.bip39_to_seed(seed_words, '')
519 self.assertEqual('0df68c16e522eea9c1d8e090cfb2139c3b3a2abed78cbcb3e20be2c29185d3b8df4e8ce4e52a1206a688aeb88bfee249585b41a7444673d1f16c0d45755fa8b9',
520 bh2u(bip32_seed))
521
522 def create_keystore_from_bip32seed(xtype):
523 ks = keystore.BIP32_KeyStore({})
524 ks.add_xprv_from_seed(bip32_seed, xtype=xtype, derivation='m/')
525 return ks
526
527 ks = create_keystore_from_bip32seed(xtype='standard')
528 self.assertEqual('033a05ec7ae9a9833b0696eb285a762f17379fa208b3dc28df1c501cf84fe415d0', ks.derive_pubkey(0, 0).hex())
529 self.assertEqual('02bf27f41683d84183e4e930e66d64fc8af5508b4b5bf3c473c505e4dbddaeed80', ks.derive_pubkey(1, 0).hex())
530
531 ks = create_keystore_from_bip32seed(xtype='standard') # p2pkh
532 w = WalletIntegrityHelper.create_standard_wallet(ks, config=self.config)
533 self.assertEqual(ks.xprv, 'tprv8ZgxMBicQKsPecD328MF9ux3dSaSFWci7FNQmuWH7uZ86eY8i3XpvjK8KSH8To2QphiZiUqaYc6nzDC6bTw8YCB9QJjaQL5pAApN4z7vh2B')
534 self.assertEqual(ks.xpub, 'tpubD6NzVbkrYhZ4Y5Epun1qZKcACU6NQqocgYyC4RYaYBMWw8nuLSMR7DvzVamkqxwRgrTJ1MBMhc8wwxT2vbHqMu8RBXy4BvjWMxR5EdZroxE')
535 self.assertEqual(w.get_receiving_addresses()[0], 'mpBTXYfWehjW2tavFwpUdqBJbZZkup13k2')
536 self.assertEqual(w.get_change_addresses()[0], 'mtkUQgf1psDtL67wMAKTv19LrdgPWy6GDQ')
537
538 ks = create_keystore_from_bip32seed(xtype='p2wpkh-p2sh')
539 w = WalletIntegrityHelper.create_standard_wallet(ks, config=self.config)
540 self.assertEqual(ks.xprv, 'uprv8tXDerPXZ1QsVuQ9rV8sN13YoQitC8cD2MtdZJQAVuw19kMMxhhPYnyGLeEiThgLELqNTxS91GTLsVofKAM9LRrkGeRzzEuJRtt1Tcostr7')
541 self.assertEqual(ks.xpub, 'upub57Wa4MvRPNyAiPUcxWfsj8zHMSZNbbL4PapEMgon4FTz2YgWWF1e6bHkBvpDKk2Rg2Zy9LsonXFFbv7jNeCZ5kdKWv8UkfcoxpdjJrZuBX6')
542 self.assertEqual(w.get_receiving_addresses()[0], '2MuzNWpcHrXyvPVKzEGT7Xrwp8uEnXXjWnK')
543 self.assertEqual(w.get_change_addresses()[0], '2MzTzY5VcGLwce7YmdEwjXhgQD7LYEKLJTm')
544
545 ks = create_keystore_from_bip32seed(xtype='p2wpkh')
546 w = WalletIntegrityHelper.create_standard_wallet(ks, config=self.config)
547 self.assertEqual(ks.xprv, 'vprv9DMUxX4ShgxMMCbGgqvVa693yNsL8kbhwUQrLhJ3svJtCrAbDMrxArdQMrCJTcLFdyxBDS2hTvotknRE2rmA8fYM8z8Ra9inhcwerEsG6Ev')
548 self.assertEqual(ks.xpub, 'vpub5SLqN2bLY4WeZgfjnsTVwE5nXQhpYDKZJhLT95hfSFqs5eVjkuBCiewtD8moKegM5fgmtpUNFBboVCjJ6LcZszJvPFpuLaSJEYhNhUAnrCS')
549 self.assertEqual(w.get_receiving_addresses()[0], 'tb1qtuynwzd0d6wptvyqmc6ehkm70zcamxpsaze002')
550 self.assertEqual(w.get_change_addresses()[0], 'tb1qjy5zunxh6hjysele86qqywfa437z4xwm4lm549')
551
552 ks = create_keystore_from_bip32seed(xtype='standard') # p2sh
553 w = WalletIntegrityHelper.create_multisig_wallet([ks], '1of1', config=self.config)
554 self.assertEqual(ks.xprv, 'tprv8ZgxMBicQKsPecD328MF9ux3dSaSFWci7FNQmuWH7uZ86eY8i3XpvjK8KSH8To2QphiZiUqaYc6nzDC6bTw8YCB9QJjaQL5pAApN4z7vh2B')
555 self.assertEqual(ks.xpub, 'tpubD6NzVbkrYhZ4Y5Epun1qZKcACU6NQqocgYyC4RYaYBMWw8nuLSMR7DvzVamkqxwRgrTJ1MBMhc8wwxT2vbHqMu8RBXy4BvjWMxR5EdZroxE')
556 self.assertEqual(w.get_receiving_addresses()[0], '2N6czpsRwQ3d8AHZPNbztf5NotzEsaZmVQ8')
557 self.assertEqual(w.get_change_addresses()[0], '2NDgwz4CoaSzdSAQdrCcLFWsJaVowCNgiPA')
558
559 ks = create_keystore_from_bip32seed(xtype='p2wsh-p2sh')
560 w = WalletIntegrityHelper.create_multisig_wallet([ks], '1of1', config=self.config)
561 self.assertEqual(ks.xprv, 'Uprv95RJn67y7xyEvUZXo9brC5PMXCm9QVHoLdYJUZfhsgmQmvvGj75fduqC9MCC28uETouMLYSFtUqqzfRRcPW6UuyR77YQPeNJKd9t3XutF8b')
562 self.assertEqual(ks.xpub, 'Upub5JQfBberxLXY8xdzuB8rZDL65Ebdox1ehrTuGx5KS2JPejFRGePvBi9fzdmgtBFKuVdx1vsvfjdkj5jVfsMWEEjzMPEtA55orYubtrCZmRr')
563 self.assertEqual(w.get_receiving_addresses()[0], '2NBZQ25GC3ipaF13ZY3UT8i2xnDuS17pJqx')
564 self.assertEqual(w.get_change_addresses()[0], '2NDmUgLVX8vKvcJ4FQ37GSUre6QtBzKkb6k')
565
566 ks = create_keystore_from_bip32seed(xtype='p2wsh')
567 w = WalletIntegrityHelper.create_multisig_wallet([ks], '1of1', config=self.config)
568 self.assertEqual(ks.xprv, 'Vprv16YtLrHXxePM6noKqtFtMtmUgBE9bEpF3fPLmpvuPksssLostujtdHBwqhEeVuzESz22UY8hyPx9ed684SQpCmUKSVhpxPFbvVNY7qnviNR')
569 self.assertEqual(ks.xpub, 'Vpub5dEvVGKn7251zFq7jXvUmJRbFCk5ka19cxz84LyCp2gGhq4eXJZUomop1qjGt5uFK8kkmQUV8PzJcNM4PZmX2URbDiwJjyuJ8GyFHRrEmmG')
570 self.assertEqual(w.get_receiving_addresses()[0], 'tb1q84x0yrztvcjg88qef4d6978zccxulcmc9y88xcg4ghjdau999x7qf2696k')
571 self.assertEqual(w.get_change_addresses()[0], 'tb1q0fj5mra96hhnum80kllklc52zqn6kppt3hyzr49yhr3ecr42z3ts5777jl')
572
573
574 class TestWalletSending(TestCaseForTestnet):
575
576 def setUp(self):
577 super().setUp()
578 self.config = SimpleConfig({'electrum_path': self.electrum_path})
579
580 def create_standard_wallet_from_seed(self, seed_words, *, config=None, gap_limit=2):
581 if config is None:
582 config = self.config
583 ks = keystore.from_seed(seed_words, '', False)
584 return WalletIntegrityHelper.create_standard_wallet(ks, gap_limit=gap_limit, config=config)
585
586 @mock.patch.object(wallet.Abstract_Wallet, 'save_db')
587 def test_sending_between_p2wpkh_and_compressed_p2pkh(self, mock_save_db):
588 wallet1 = self.create_standard_wallet_from_seed('bitter grass shiver impose acquire brush forget axis eager alone wine silver')
589 wallet2 = self.create_standard_wallet_from_seed('cycle rocket west magnet parrot shuffle foot correct salt library feed song')
590
591 # bootstrap wallet1
592 funding_tx = Transaction('01000000014576dacce264c24d81887642b726f5d64aa7825b21b350c7b75a57f337da6845010000006b483045022100a3f8b6155c71a98ad9986edd6161b20d24fad99b6463c23b463856c0ee54826d02200f606017fd987696ebbe5200daedde922eee264325a184d5bbda965ba5160821012102e5c473c051dae31043c335266d0ef89c1daab2f34d885cc7706b267f3269c609ffffffff0240420f00000000001600148a28bddb7f61864bdcf58b2ad13d5aeb3abc3c42a2ddb90e000000001976a914c384950342cb6f8df55175b48586838b03130fad88ac00000000')
593 funding_txid = funding_tx.txid()
594 funding_output_value = 1000000
595 self.assertEqual('add2535aedcbb5ba79cc2260868bb9e57f328738ca192937f2c92e0e94c19203', funding_txid)
596 wallet1.receive_tx_callback(funding_txid, funding_tx, TX_HEIGHT_UNCONFIRMED)
597
598 # wallet1 -> wallet2
599 outputs = [PartialTxOutput.from_address_and_value(wallet2.get_receiving_address(), 250000)]
600 tx = wallet1.mktx(outputs=outputs, password=None, fee=5000, tx_version=1)
601
602 self.assertTrue(tx.is_complete())
603 self.assertTrue(tx.is_segwit())
604 self.assertEqual(1, len(tx.inputs()))
605 self.assertEqual(wallet1.txin_type, tx.inputs()[0].script_type)
606 tx_copy = tx_from_any(tx.serialize())
607 self.assertTrue(wallet1.is_mine(wallet1.get_txin_address(tx_copy.inputs()[0])))
608
609 self.assertEqual('010000000001010392c1940e2ec9f2372919ca3887327fe5b98b866022cc79bab5cbed5a53d2ad0000000000feffffff0290d00300000000001976a914ea7804a2c266063572cc009a63dc25dcc0e9d9b588ac285e0b0000000000160014690b59a8140602fb23cc2904ece9cc4daf361052024730440220608a5339ca894592da82119e1e4a1d09335d70a552c683687223b8ed724465e902201b3f0feccf391b1b6257e4b18970ae57d7ca060af2dae519b3690baad2b2a34e0121030faee9b4a25b7db82023ca989192712cdd4cb53d3d9338591c7909e581ae1c0c00000000',
610 str(tx_copy))
611 self.assertEqual('3c06ae4d9be8226a472b3e7f7c127c7e3016f525d658d26106b80b4c7e3228e2', tx_copy.txid())
612 self.assertEqual('d8d930ae91dce73118c3fffabbdfcfb87f5d91673fb4c7dfd0fbe7cf03bf426b', tx_copy.wtxid())
613 self.assertEqual(tx.wtxid(), tx_copy.wtxid())
614
615 wallet1.receive_tx_callback(tx.txid(), tx, TX_HEIGHT_UNCONFIRMED) # TX_HEIGHT_UNCONF_PARENT but nvm
616 wallet2.receive_tx_callback(tx.txid(), tx, TX_HEIGHT_UNCONFIRMED)
617
618 # wallet2 -> wallet1
619 outputs = [PartialTxOutput.from_address_and_value(wallet1.get_receiving_address(), 100000)]
620 tx = wallet2.mktx(outputs=outputs, password=None, fee=5000, tx_version=1)
621
622 self.assertTrue(tx.is_complete())
623 self.assertFalse(tx.is_segwit())
624 self.assertEqual(1, len(tx.inputs()))
625 self.assertEqual(wallet2.txin_type, tx.inputs()[0].script_type)
626 tx_copy = tx_from_any(tx.serialize())
627 self.assertTrue(wallet2.is_mine(wallet2.get_txin_address(tx_copy.inputs()[0])))
628
629 self.assertEqual('0100000001e228327e4c0bb80661d258d625f516307e7c127c7f3e2b476a22e89b4dae063c000000006a47304402200c7b06ff882db5ffe9d6e2a3cc2cabf5cd1b4224f1453d1e3dadd13b3d391e2c02201d23fde8482b05837f27d43021d17a1be2ee619dfc889ee80d4c2761e7c7ffb20121030b482838721a38d94847699fed8818b5c5f56500ef72f13489e365b65e5749cffeffffff02a086010000000000160014284520c815980d426264766d8d930013dd20aa6068360200000000001976a914ca4c60999c46c2108326590b125aefd476dcb11888ac00000000',
630 str(tx_copy))
631 self.assertEqual('4ff22c31dd884dedbb905fae275508d1f7bb4948c1c979d2567132848fdff24a', tx_copy.txid())
632 self.assertEqual('4ff22c31dd884dedbb905fae275508d1f7bb4948c1c979d2567132848fdff24a', tx_copy.wtxid())
633 self.assertEqual(tx.wtxid(), tx_copy.wtxid())
634
635 wallet1.receive_tx_callback(tx.txid(), tx, TX_HEIGHT_UNCONFIRMED)
636 wallet2.receive_tx_callback(tx.txid(), tx, TX_HEIGHT_UNCONFIRMED)
637
638 # wallet level checks
639 self.assertEqual((0, funding_output_value - 250000 - 5000 + 100000, 0), wallet1.get_balance())
640 self.assertEqual((0, 250000 - 5000 - 100000, 0), wallet2.get_balance())
641
642 @mock.patch.object(wallet.Abstract_Wallet, 'save_db')
643 def test_sending_between_p2sh_2of3_and_uncompressed_p2pkh(self, mock_save_db):
644 wallet1a = WalletIntegrityHelper.create_multisig_wallet(
645 [
646 keystore.from_seed('blast uniform dragon fiscal ensure vast young utility dinosaur abandon rookie sure', '', True),
647 keystore.from_xpub('tpubD6NzVbkrYhZ4YTPEgwk4zzr8wyo7pXGmbbVUnfYNtx6SgAMF5q3LN3Kch58P9hxGNsTmP7Dn49nnrmpE6upoRb1Xojg12FGLuLHkVpVtS44'),
648 keystore.from_xpub('tpubD6NzVbkrYhZ4XJzYkhsCbDCcZRmDAKSD7bXi9mdCni7acVt45fxbTVZyU6jRGh29ULKTjoapkfFsSJvQHitcVKbQgzgkkYsAmaovcro7Mhf')
649 ],
650 '2of3', gap_limit=2,
651 config=self.config
652 )
653 wallet1b = WalletIntegrityHelper.create_multisig_wallet(
654 [
655 keystore.from_seed('cycle rocket west magnet parrot shuffle foot correct salt library feed song', '', True),
656 keystore.from_xpub('tpubD6NzVbkrYhZ4YTPEgwk4zzr8wyo7pXGmbbVUnfYNtx6SgAMF5q3LN3Kch58P9hxGNsTmP7Dn49nnrmpE6upoRb1Xojg12FGLuLHkVpVtS44'),
657 keystore.from_xpub('tpubD6NzVbkrYhZ4YARFMEZPckrqJkw59GZD1PXtQnw14ukvWDofR7Z1HMeSCxfYEZVvg4VdZ8zGok5VxHwdrLqew5cMdQntWc5mT7mh1CSgrnX')
658 ],
659 '2of3', gap_limit=2,
660 config=self.config
661 )
662 # ^ third seed: ghost into match ivory badge robot record tackle radar elbow traffic loud
663 wallet2 = self.create_standard_wallet_from_seed('powerful random nobody notice nothing important anyway look away hidden message over')
664
665 # bootstrap wallet1
666 funding_tx = Transaction('010000000001014121f99dc02f0364d2dab3d08905ff4c36fc76c55437fd90b769c35cc18618280100000000fdffffff02d4c22d00000000001600143fd1bc5d32245850c8cb5be5b09c73ccbb9a0f75001bb7000000000017a91480c2353f6a7bc3c71e99e062655b19adb3dd2e4887024830450221008781c78df0c9d4b5ea057333195d5d76bc29494d773f14fa80e27d2f288b2c360220762531614799b6f0fb8d539b18cb5232ab4253dd4385435157b28a44ff63810d0121033de77d21926e09efd04047ae2d39dbd3fb9db446e8b7ed53e0f70f9c9478f735dac11300')
667 funding_txid = funding_tx.txid()
668 funding_output_value = 12000000
669 self.assertEqual('b25cd55687c9e528c2cfd546054f35fb6741f7cf32d600f07dfecdf2e1d42071', funding_txid)
670 wallet1a.receive_tx_callback(funding_txid, funding_tx, TX_HEIGHT_UNCONFIRMED)
671
672 # wallet1 -> wallet2
673 outputs = [PartialTxOutput.from_address_and_value(wallet2.get_receiving_address(), 370000)]
674 tx = wallet1a.mktx(outputs=outputs, password=None, fee=5000, tx_version=1)
675 partial_tx = tx.serialize_as_bytes().hex()
parazyd.org:70 /git/electrum/file/electrum/tests/test_wallet_vertical.py.gph:685: line too long