1
0

Merge pull request #10126 from SomberNight/202508_tests_wizard

tests: more WalletWizardTestCases
This commit is contained in:
accumulator
2025-08-13 10:08:21 +02:00
committed by GitHub
3 changed files with 334 additions and 85 deletions

View File

@@ -679,6 +679,11 @@ class NewWalletWizard(KeystoreWizard):
addresses[addr] = {'type': txin_type, 'pubkey': pubkey}
elif 'address_list' in data:
for addr in data['address_list'].split():
assert isinstance(addr, str)
assert bitcoin.is_address(addr), f"expected bitcoin addr. got {addr[:5] + '..' + addr[-2:]}"
# note: we do not normalize addresses. :/
# In particular, bech32 addresses can be either all-lowercase or all-uppercase.
# TODO we should normalize them, but it only makes sense if we also do a walletDB-upgrade.
addresses[addr] = {}
elif data['keystore_type'] in ['createseed', 'haveseed']:
seed_extension = data['seed_extra_words'] if data['seed_extend'] else ''

View File

@@ -481,6 +481,8 @@ class Test_bitcoin(ElectrumTestCase):
# test vectors from BIP-0173
# note: the ones that are commented out have been invalidated by BIP-0350
self.assertEqual(address_to_script('BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4').hex(), '0014751e76e8199196d454941c45d1b3a323f1433bd6')
self.assertEqual(address_to_script('tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7', net=constants.BitcoinTestnet).hex(), '00201863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262')
self.assertEqual(address_to_script('tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy', net=constants.BitcoinTestnet).hex(), '0020000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433')
# self.assertEqual(address_to_script('bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7k7grplx'), '5128751e76e8199196d454941c45d1b3a323f1433bd6751e76e8199196d454941c45d1b3a323f1433bd6')
# self.assertEqual(address_to_script('BC1SW50QA3JX3S'), '6002751e')
# self.assertEqual(address_to_script('bc1zw508d6qejxtdg4y5r3zarvaryvg6kdaj'), '5210751e76e8199196d454941c45d1b3a323')
@@ -491,43 +493,57 @@ class Test_bitcoin(ElectrumTestCase):
self.assertEqual(address_to_script('BC1SW50QGDZ25J').hex(), '6002751e')
self.assertEqual(address_to_script('bc1zw508d6qejxtdg4y5r3zarvaryvaxxpcs').hex(), '5210751e76e8199196d454941c45d1b3a323')
self.assertEqual(address_to_script('bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqzk5jj0').hex(), '512079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798')
self.assertEqual(address_to_script('tb1pqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesf3hn0c', net=constants.BitcoinTestnet).hex(), '5120000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433')
# invalid addresses (from BIP-0173)
self.assertFalse(is_address('tc1qw508d6qejxtdg4y5r3zarvary0c5xw7kg3g4ty'))
self.assertFalse(is_address('bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5'))
self.assertFalse(is_address('BC13W508D6QEJXTDG4Y5R3ZARVARY0C5XW7KN40WF2'))
self.assertFalse(is_address('bc1rw5uspcuh'))
self.assertFalse(is_address('bc10w508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kw5rljs90'))
self.assertFalse(is_address('BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P'))
self.assertFalse(is_address('tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sL5k7'))
self.assertFalse(is_address('bc1zw508d6qejxtdg4y5r3zarvaryvqyzf3du'))
self.assertFalse(is_address('tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3pjxtptv'))
self.assertFalse(is_address('bc1gmk9yu'))
for net in [constants.BitcoinMainnet, constants.BitcoinTestnet]:
self.assertFalse(is_address('tc1qw508d6qejxtdg4y5r3zarvary0c5xw7kg3g4ty', net=net))
self.assertFalse(is_address('bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5', net=net))
self.assertFalse(is_address('BC13W508D6QEJXTDG4Y5R3ZARVARY0C5XW7KN40WF2', net=net))
self.assertFalse(is_address('bc1rw5uspcuh', net=net))
self.assertFalse(is_address('bc10w508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kw5rljs90', net=net))
self.assertFalse(is_address('BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P', net=net))
self.assertFalse(is_address('tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sL5k7', net=net))
self.assertFalse(is_address('bc1zw508d6qejxtdg4y5r3zarvaryvqyzf3du', net=net))
self.assertFalse(is_address('tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3pjxtptv', net=net))
self.assertFalse(is_address('bc1gmk9yu', net=net))
# invalid addresses (from BIP-0350)
self.assertFalse(is_address('tc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vq5zuyut'))
self.assertFalse(is_address('bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqh2y7hd'))
self.assertFalse(is_address('tb1z0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqglt7rf'))
self.assertFalse(is_address('BC1S0XLXVLHEMJA6C4DQV22UAPCTQUPFHLXM9H8Z3K2E72Q4K9HCZ7VQ54WELL'))
self.assertFalse(is_address('bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kemeawh'))
self.assertFalse(is_address('tb1q0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vq24jc47'))
self.assertFalse(is_address('bc1p38j9r5y49hruaue7wxjce0updqjuyyx0kh56v8s25huc6995vvpql3jow4'))
self.assertFalse(is_address('BC130XLXVLHEMJA6C4DQV22UAPCTQUPFHLXM9H8Z3K2E72Q4K9HCZ7VQ7ZWS8R'))
self.assertFalse(is_address('bc1pw5dgrnzv'))
self.assertFalse(is_address('bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7v8n0nx0muaewav253zgeav'))
self.assertFalse(is_address('BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P'))
self.assertFalse(is_address('tb1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vq47Zagq'))
self.assertFalse(is_address('bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7v07qwwzcrf'))
self.assertFalse(is_address('tb1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vpggkg4j'))
self.assertFalse(is_address('bc1gmk9yu'))
for net in [constants.BitcoinMainnet, constants.BitcoinTestnet]:
self.assertFalse(is_address('tc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vq5zuyut', net=net))
self.assertFalse(is_address('bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqh2y7hd', net=net))
self.assertFalse(is_address('tb1z0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqglt7rf', net=net))
self.assertFalse(is_address('BC1S0XLXVLHEMJA6C4DQV22UAPCTQUPFHLXM9H8Z3K2E72Q4K9HCZ7VQ54WELL', net=net))
self.assertFalse(is_address('bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kemeawh', net=net))
self.assertFalse(is_address('tb1q0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vq24jc47', net=net))
self.assertFalse(is_address('bc1p38j9r5y49hruaue7wxjce0updqjuyyx0kh56v8s25huc6995vvpql3jow4', net=net))
self.assertFalse(is_address('BC130XLXVLHEMJA6C4DQV22UAPCTQUPFHLXM9H8Z3K2E72Q4K9HCZ7VQ7ZWS8R', net=net))
self.assertFalse(is_address('bc1pw5dgrnzv', net=net))
self.assertFalse(is_address('bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7v8n0nx0muaewav253zgeav', net=net))
self.assertFalse(is_address('BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P', net=net))
self.assertFalse(is_address('tb1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vq47Zagq', net=net))
self.assertFalse(is_address('bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7v07qwwzcrf', net=net))
self.assertFalse(is_address('tb1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vpggkg4j', net=net))
self.assertFalse(is_address('bc1gmk9yu', net=net))
# bech32(m) mixed case:
bech32_mixed_case1 = 'BC1QW508D6QEJXTDG4Y5R3zarvary0c5xw7kv8f3t4'
self.assertFalse(is_address(bech32_mixed_case1))
self.assertTrue(is_address(bech32_mixed_case1.lower()))
self.assertTrue(is_address(bech32_mixed_case1.upper()))
# base58 P2PKH
self.assertEqual(address_to_script('14gcRovpkCoGkCNBivQBvw7eso7eiNAbxG').hex(), '76a91428662c67561b95c79d2257d2a93d9d151c977e9188ac')
self.assertEqual(address_to_script('1BEqfzh4Y3zzLosfGhw1AsqbEKVW6e1qHv').hex(), '76a914704f4b81cadb7bf7e68c08cd3657220f680f863c88ac')
self.assertEqual(address_to_script('mutXcGt1CJdkRvXuN2xoz2quAAQYQ59bRX', net=constants.BitcoinTestnet).hex(), '76a9149da64e300c5e4eb4aaffc9c2fd465348d5618ad488ac')
self.assertEqual(address_to_script('miqtaRTkU3U8rzwKbEHx3g8FSz8GJtPS3K', net=constants.BitcoinTestnet).hex(), '76a914247d2d5b6334bdfa2038e85b20fc15264f8e5d2788ac')
# base58 P2SH
self.assertEqual(address_to_script('35ZqQJcBQMZ1rsv8aSuJ2wkC7ohUCQMJbT').hex(), 'a9142a84cf00d47f699ee7bbc1dea5ec1bdecb4ac15487')
self.assertEqual(address_to_script('3PyjzJ3im7f7bcV724GR57edKDqoZvH7Ji').hex(), 'a914f47c8954e421031ad04ecd8e7752c9479206b9d387')
self.assertEqual(address_to_script('2N3LSvr3hv5EVdfcrxg2Yzecf3SRvqyBE4p', net=constants.BitcoinTestnet).hex(), 'a9146eae23d8c4a941316017946fc761a7a6c85561fb87')
self.assertEqual(address_to_script('2NE4ZdmxFmUgwu5wtfoN2gVniyMgRDYq1kk', net=constants.BitcoinTestnet).hex(), 'a914e4567743d378957cd2ee7072da74b1203c1a7a0b87')
def test_address_to_payload(self):
# bech32 P2WPKH
@@ -644,59 +660,6 @@ class Test_bitcoin(ElectrumTestCase):
segwit_addr.bech32_decode('1p2gdwpf'))
class Test_bitcoin_testnet(ElectrumTestCase):
TESTNET = True
def test_address_to_script(self):
# bech32/bech32m native segwit
# test vectors from BIP-0173
self.assertEqual(address_to_script('tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7').hex(), '00201863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262')
self.assertEqual(address_to_script('tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy').hex(), '0020000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433')
# bech32/bech32m native segwit
# test vectors from BIP-0350
self.assertEqual(address_to_script('tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sl5k7').hex(), '00201863143c14c5166804bd19203356da136c985678cd4d27a1b8c6329604903262')
self.assertEqual(address_to_script('tb1qqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesrxh6hy').hex(), '0020000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433')
self.assertEqual(address_to_script('tb1pqqqqp399et2xygdj5xreqhjjvcmzhxw4aywxecjdzew6hylgvsesf3hn0c').hex(), '5120000000c4a5cad46221b2a187905e5266362b99d5e91c6ce24d165dab93e86433')
# invalid addresses (from BIP-0173)
self.assertFalse(is_address('tc1qw508d6qejxtdg4y5r3zarvary0c5xw7kg3g4ty'))
self.assertFalse(is_address('bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kv8f3t5'))
self.assertFalse(is_address('BC13W508D6QEJXTDG4Y5R3ZARVARY0C5XW7KN40WF2'))
self.assertFalse(is_address('bc1rw5uspcuh'))
self.assertFalse(is_address('bc10w508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kw5rljs90'))
self.assertFalse(is_address('BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P'))
self.assertFalse(is_address('tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3q0sL5k7'))
self.assertFalse(is_address('bc1zw508d6qejxtdg4y5r3zarvaryvqyzf3du'))
self.assertFalse(is_address('tb1qrp33g0q5c5txsp9arysrx4k6zdkfs4nce4xj0gdcccefvpysxf3pjxtptv'))
self.assertFalse(is_address('bc1gmk9yu'))
# invalid addresses (from BIP-0350)
self.assertFalse(is_address('tc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vq5zuyut'))
self.assertFalse(is_address('bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqh2y7hd'))
self.assertFalse(is_address('tb1z0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vqglt7rf'))
self.assertFalse(is_address('BC1S0XLXVLHEMJA6C4DQV22UAPCTQUPFHLXM9H8Z3K2E72Q4K9HCZ7VQ54WELL'))
self.assertFalse(is_address('bc1qw508d6qejxtdg4y5r3zarvary0c5xw7kemeawh'))
self.assertFalse(is_address('tb1q0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vq24jc47'))
self.assertFalse(is_address('bc1p38j9r5y49hruaue7wxjce0updqjuyyx0kh56v8s25huc6995vvpql3jow4'))
self.assertFalse(is_address('BC130XLXVLHEMJA6C4DQV22UAPCTQUPFHLXM9H8Z3K2E72Q4K9HCZ7VQ7ZWS8R'))
self.assertFalse(is_address('bc1pw5dgrnzv'))
self.assertFalse(is_address('bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7v8n0nx0muaewav253zgeav'))
self.assertFalse(is_address('BC1QR508D6QEJXTDG4Y5R3ZARVARYV98GJ9P'))
self.assertFalse(is_address('tb1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vq47Zagq'))
self.assertFalse(is_address('bc1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7v07qwwzcrf'))
self.assertFalse(is_address('tb1p0xlxvlhemja6c4dqv22uapctqupfhlxm9h8z3k2e72q4k9hcz7vpggkg4j'))
self.assertFalse(is_address('bc1gmk9yu'))
# base58 P2PKH
self.assertEqual(address_to_script('mutXcGt1CJdkRvXuN2xoz2quAAQYQ59bRX').hex(), '76a9149da64e300c5e4eb4aaffc9c2fd465348d5618ad488ac')
self.assertEqual(address_to_script('miqtaRTkU3U8rzwKbEHx3g8FSz8GJtPS3K').hex(), '76a914247d2d5b6334bdfa2038e85b20fc15264f8e5d2788ac')
# base58 P2SH
self.assertEqual(address_to_script('2N3LSvr3hv5EVdfcrxg2Yzecf3SRvqyBE4p').hex(), 'a9146eae23d8c4a941316017946fc761a7a6c85561fb87')
self.assertEqual(address_to_script('2NE4ZdmxFmUgwu5wtfoN2gVniyMgRDYq1kk').hex(), 'a914e4567743d378957cd2ee7072da74b1203c1a7a0b87')
class Test_xprv_xpub(ElectrumTestCase):
xprv_xpub = (

View File

@@ -8,6 +8,7 @@ from electrum.wizard import ServerConnectWizard, NewWalletWizard, WizardViewStat
from electrum.daemon import Daemon
from electrum.wallet import Abstract_Wallet
from electrum import util
from electrum import slip39
from . import ElectrumTestCase
from .test_wallet_vertical import UNICODE_HORROR
@@ -124,11 +125,6 @@ class ServerConnectWizardTestCase(WizardTestCase):
class WalletWizardTestCase(WizardTestCase):
# TODO imported addresses
# TODO imported WIF keys
# TODO multisig
# TODO slip39
def _wizard_for(
self,
*,
@@ -155,7 +151,7 @@ class WalletWizardTestCase(WizardTestCase):
*,
v: WizardViewState,
w: NewWalletWizard,
recv_addr: str,
recv_addr: str | None, # "first addr" only makes sense for HD wallets
password: str | None = None,
encrypt_file: bool = False,
) -> Abstract_Wallet:
@@ -171,7 +167,8 @@ class WalletWizardTestCase(WizardTestCase):
self.assertTrue(os.path.exists(wallet_path))
wallet = Daemon._load_wallet(wallet_path, password=password, config=self.config)
self.assertEqual(recv_addr, wallet.get_receiving_addresses()[0])
if recv_addr is not None:
self.assertEqual(recv_addr, wallet.get_receiving_addresses()[0])
self.assertEqual(bool(password), wallet.has_password())
self.assertEqual(encrypt_file, wallet.has_storage_encryption())
return wallet
@@ -337,6 +334,22 @@ class WalletWizardTestCase(WizardTestCase):
v = w.resolve_next(v.view, d)
self._set_password_and_check_address(v=v, w=w, recv_addr="bc1qgvx24uzdv4mapfmtlu8azty5fxdcw9ghxu4pr4")
async def test_create_standard_wallet_have_master_key(self):
w = self._wizard_for(wallet_type='standard')
v = w._current
d = v.wizard_data
self.assertEqual('keystore_type', v.view)
d.update({'keystore_type': 'masterkey'})
v = w.resolve_next(v.view, d)
self.assertEqual('have_master_key', v.view)
d.update({
'master_key': 'zpub6nAZodjgiMNf9zzX1pTqd6ZVX61ax8azhUDnWRumKVUr1VYATVoqAuqv3qKsb8WJXjxei4wei2p4vnMG9RnpKnen2kmgdhvZUmug2NnHNsr',
'multisig_master_pubkey': 'zpub6nAZodjgiMNf9zzX1pTqd6ZVX61ax8azhUDnWRumKVUr1VYATVoqAuqv3qKsb8WJXjxei4wei2p4vnMG9RnpKnen2kmgdhvZUmug2NnHNsr'})
v = w.resolve_next(v.view, d)
self._set_password_and_check_address(v=v, w=w, recv_addr="bc1qq2tmmcngng78nllq2pvrkchcdukemtj56uyue0")
async def test_create_standard_wallet_haveseed_bip39(self):
w = self._wizard_for(wallet_type='standard')
v = w._current
@@ -377,6 +390,68 @@ class WalletWizardTestCase(WizardTestCase):
v = w.resolve_next(v.view, d)
self._set_password_and_check_address(v=v, w=w, recv_addr="bc1qjexrunguxz8rlfuul8h4apafyh3sq5yp9kg98j")
async def test_create_standard_wallet_haveseed_slip39(self):
w = self._wizard_for(wallet_type='standard')
v = w._current
d = v.wizard_data
self.assertEqual('keystore_type', v.view)
d.update({'keystore_type': 'haveseed'})
v = w.resolve_next(v.view, d)
self.assertEqual('have_seed', v.view)
# SLIP39 shares (128 bits, 2 groups from 1 of 1, 1 of 1, 3 of 5, 2 of 6)
mnemonics = [
"fact else acrobat romp analysis usher havoc vitamins analysis garden prevent romantic silent dramatic adjust priority mailman plains vintage else",
"fact else ceramic round craft lips snake faint adorn square bucket deadline violence guitar greatest academic stadium snake frequent memory",
"fact else ceramic scatter counter remove club forbid busy cause taxi forecast prayer uncover living type training forward software pumps",
"fact else ceramic shaft clock crowd detect cleanup wildlife depict include trip profile isolate express category wealthy advance garden mixture",
]
encrypted_seed = slip39.recover_ems(mnemonics)
d.update({'seed': encrypted_seed, 'seed_variant': 'slip39', 'seed_type': 'slip39', 'seed_extend': False})
v = w.resolve_next(v.view, d)
self.assertEqual('script_and_derivation', v.view)
d.update({
'script_type': 'p2wpkh', 'derivation_path': 'm/84h/0h/0h',
'multisig_master_pubkey': 'zpub6riQosasrLdM1rmmohyUHtseLYeCBKP55Xe1LTT7jyKFM6dMMZPYVx5ug6zH2gZ6XFGcUYubjbm43vXHecTzNmoMS3yfp6oeZT3GetsGFt4'})
v = w.resolve_next(v.view, d)
self._set_password_and_check_address(v=v, w=w, recv_addr="bc1q40ksvkl7wvc2l999ppl48swgt3rsl45ykyyrjn")
async def test_create_standard_wallet_haveseed_slip39_passphrase(self):
w = self._wizard_for(wallet_type='standard')
v = w._current
d = v.wizard_data
self.assertEqual('keystore_type', v.view)
d.update({'keystore_type': 'haveseed'})
v = w.resolve_next(v.view, d)
self.assertEqual('have_seed', v.view)
# SLIP39 shares (128 bits, 2 groups from 1 of 1, 1 of 1, 3 of 5, 2 of 6)
mnemonics = [
"fact else acrobat romp analysis usher havoc vitamins analysis garden prevent romantic silent dramatic adjust priority mailman plains vintage else",
"fact else ceramic round craft lips snake faint adorn square bucket deadline violence guitar greatest academic stadium snake frequent memory",
"fact else ceramic scatter counter remove club forbid busy cause taxi forecast prayer uncover living type training forward software pumps",
"fact else ceramic shaft clock crowd detect cleanup wildlife depict include trip profile isolate express category wealthy advance garden mixture",
]
encrypted_seed = slip39.recover_ems(mnemonics)
d.update({'seed': encrypted_seed, 'seed_variant': 'slip39', 'seed_type': 'slip39', 'seed_extend': True})
v = w.resolve_next(v.view, d)
self.assertEqual('have_ext', v.view)
d.update({'seed_extra_words': 'TREZOR'})
v = w.resolve_next(v.view, d)
self.assertEqual('script_and_derivation', v.view)
d.update({
'script_type': 'p2wpkh', 'derivation_path': 'm/84h/0h/0h',
'multisig_master_pubkey': 'zpub6s6A9ynh7TT1sPXmQyu8S6g7kxMF6iSZkM3NmgF4w7CtpsGgg56aouYSWHgAoMy186a8FRT8zkmhcwV5SWKFFQfMpvV8C9Ft4woWSzD5sXz'})
v = w.resolve_next(v.view, d)
self._set_password_and_check_address(v=v, w=w, recv_addr="bc1qs2svwhfz47qv9qju2waa6prxzv5f522fc4p06t")
async def test_2fa_createseed(self):
self.assertTrue(self.config.get('enable_plugin_trustedcoin'))
w = self._wizard_for(wallet_type='2fa')
@@ -546,3 +621,209 @@ class WalletWizardTestCase(WizardTestCase):
d.update({'password': '03a580deb85ef85654ed177fc049867ce915a8b392a34a524123870925e48a5b9e'})
self.assertTrue(w.is_last_view(v.view, d))
v = w.resolve_next(v.view, d)
async def test_create_multisig_wallet_2of2_createseed_cosigner2hasmasterkey(self):
w = self._wizard_for(wallet_type='multisig')
v = w._current
d = v.wizard_data
self.assertEqual('multisig', v.view)
d.update({'multisig_participants': 2, 'multisig_signatures': 2, 'multisig_cosigner_data': {}})
v = w.resolve_next(v.view, d)
self.assertEqual('keystore_type', v.view)
d.update({'keystore_type': 'createseed'})
v = w.resolve_next(v.view, d)
self.assertEqual('create_seed', v.view)
d.update({
'seed': 'eager divert pigeon dentist punch festival manage smart globe regular adult cash',
'seed_type': 'segwit', 'seed_extend': False, 'seed_variant': 'electrum'})
v = w.resolve_next(v.view, d)
self.assertEqual('confirm_seed', v.view)
d.update({'multisig_master_pubkey': 'Zpub6y7YR1dmZZV4f5rRm6dJCKSqqxZhKUxc8PkssXm84k2bzbGYkL22ugC4aZxVxC1qz4yo53Zwz1c1kiSHmybB4JjCsjCPjzygSsN1UcdCcvB'})
v = w.resolve_next(v.view, d)
self.assertEqual('multisig_cosigner_keystore', v.view)
# 2nd cosigner uses Zpub from "9dk" seed
d['multisig_cosigner_data']['2'] = {'keystore_type': 'masterkey'}
d.update({
'multisig_current_cosigner': 2, 'cosigner_keystore_type': 'masterkey'})
v = w.resolve_next(v.view, d)
self.assertEqual('multisig_cosigner_key', v.view)
d['multisig_cosigner_data']['2'].update({'master_key': 'Zpub6y4evsU8HJw2d7ZH8QNyC6UKWHyxinAuQKkD6btsEZMbamy96UnefnM4sZp2K38rdiUssEhNq9TBpJ8Bh1GZCGTFpnYz8jM9pAdS6vk5VQs'})
v = w.resolve_next(v.view, d)
self._set_password_and_check_address(v=v, w=w, recv_addr="bc1qg39tkymxwq4tn2ly6c3lmnyvsy94jyw52rdvfqkzdv2slvlj9xcsfy63vc")
async def test_create_multisig_wallet_3of6_haveseed_passphrase__cs2hasbip39__cs3zpub__cs4trezor__cs5seedandpassphrase__cs6zprv(self):
w = self._wizard_for(wallet_type='multisig')
v = w._current
d = v.wizard_data
self.assertEqual('multisig', v.view)
d.update({'multisig_participants': 6, 'multisig_signatures': 3, 'multisig_cosigner_data': {}})
v = w.resolve_next(v.view, d)
self.assertEqual('keystore_type', v.view)
d.update({'keystore_type': 'haveseed'})
v = w.resolve_next(v.view, d)
self.assertEqual('have_seed', v.view)
d.update({
'seed': '9dk',
'seed_variant': 'electrum', 'seed_type': 'segwit', 'seed_extend': True})
v = w.resolve_next(v.view, d)
self.assertEqual('have_ext', v.view)
d.update({
'seed_extra_words': UNICODE_HORROR,
'multisig_master_pubkey': 'Zpub6zAYrXzLbLwWFCkahiB3fQz4KMUm68RsoGVHkM5aBjzHBGnQ9orvy7PKuFvMj4gyJXhFW5uFzHBgDDYFEPS75b3ADq3yvtuEJF86ZgLLyeL'})
v = w.resolve_next(v.view, d)
self.assertEqual('multisig_cosigner_keystore', v.view)
# 2nd cosigner
d['multisig_cosigner_data']['2'] = {'keystore_type': 'haveseed'}
d.update({
'multisig_current_cosigner': 2, 'cosigner_keystore_type': 'haveseed'})
v = w.resolve_next(v.view, d)
self.assertEqual('multisig_cosigner_seed', v.view)
d['multisig_cosigner_data']['2'].update({
'seed': 'abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about',
'seed_variant': 'bip39', 'seed_type': 'bip39', 'seed_extend': False})
v = w.resolve_next(v.view, d)
self.assertEqual('multisig_cosigner_script_and_derivation', v.view)
d['multisig_cosigner_data']['2'].update({
'script_type': 'p2wsh', 'derivation_path': 'm/48h/0h/0h/2h'})
v = w.resolve_next(v.view, d)
self.assertEqual('multisig_cosigner_keystore', v.view)
# 3rd cosigner uses Zpub from "9dk" seed
d['multisig_cosigner_data']['3'] = {'keystore_type': 'masterkey'}
d.update({
'multisig_current_cosigner': 3, 'cosigner_keystore_type': 'masterkey'})
v = w.resolve_next(v.view, d)
self.assertEqual('multisig_cosigner_key', v.view)
d['multisig_cosigner_data']['3'].update({
'master_key': 'Zpub6y4evsU8HJw2d7ZH8QNyC6UKWHyxinAuQKkD6btsEZMbamy96UnefnM4sZp2K38rdiUssEhNq9TBpJ8Bh1GZCGTFpnYz8jM9pAdS6vk5VQs'})
v = w.resolve_next(v.view, d)
self.assertEqual('multisig_cosigner_keystore', v.view)
# 4th cosigner
d['multisig_cosigner_data']['4'] = {'keystore_type': 'hardware'}
d.update({
'multisig_current_cosigner': 4, 'cosigner_keystore_type': 'hardware'})
v = w.resolve_next(v.view, d)
self.assertEqual('multisig_cosigner_hardware', v.view)
d['multisig_cosigner_data']['4'].update({
'hardware_device': (
'trezor',
DeviceInfo(
device=Device(path='webusb:002:1', interface_number=-1, id_='webusb:002:1', product_key='Trezor', usage_page=0, transport_ui_string='webusb:002:1'),
label='trezor_unittests', initialized=True, exception=None, plugin_name='trezor', soft_device_id='088C3F260B66F60E15DE0FA5', model_name='Trezor T'))})
v = w.resolve_next(v.view, d)
self.assertEqual('trezor_start', v.view)
d['multisig_cosigner_data']['4'].update({
'script_type': 'p2wsh', 'derivation_path': 'm/48h/0h/0h/2h'})
v = w.resolve_next(v.view, d)
self.assertEqual('trezor_xpub', v.view)
d['multisig_cosigner_data']['4'].update({
'hw_type': 'trezor', 'master_key': 'Zpub75t8XsK4GVa2EyQtjvT9auayKwonGaQJ149qB9r11o5iikugxJ99hYgbcaTdCGjd4DUdz4z2bqAtmDv2s8UihG1AnbzBufSG82GxjMDfVUn',
'root_fingerprint': '6306ee35', 'label': 'trezor_unittests', 'soft_device_id': '088C3F260B66F60E15DE0FA5'})
v = w.resolve_next(v.view, d)
self.assertEqual('multisig_cosigner_keystore', v.view)
# 5th cosigner
d['multisig_cosigner_data']['5'] = {'keystore_type': 'haveseed'}
d.update({
'multisig_current_cosigner': 5, 'cosigner_keystore_type': 'haveseed'})
v = w.resolve_next(v.view, d)
self.assertEqual('multisig_cosigner_seed', v.view)
d['multisig_cosigner_data']['5'].update({
'seed': 'abandon bike',
'seed_variant': 'electrum', 'seed_type': 'segwit', 'seed_extend': True})
v = w.resolve_next(v.view, d)
self.assertEqual('multisig_cosigner_have_ext', v.view)
d['multisig_cosigner_data']['5'].update({
'seed_extra_words': UNICODE_HORROR})
v = w.resolve_next(v.view, d)
self.assertEqual('multisig_cosigner_keystore', v.view)
# 6th cosigner uses Zprv from "abandon bike" seed
d['multisig_cosigner_data']['6'] = {'keystore_type': 'masterkey'}
d.update({
'multisig_current_cosigner': 6, 'cosigner_keystore_type': 'masterkey'})
v = w.resolve_next(v.view, d)
self.assertEqual('multisig_cosigner_key', v.view)
d['multisig_cosigner_data']['6'].update({
'master_key': 'ZprvAjWENdvYc1Ctvppxm4Z67U4EoiDy5VXKNvWmVAZshy7UjgKggu1UcAH7MqRqTaHVunuEPZ7o51wCrsZnJXPJtzHnAoxNmMLWFMHC7uvUN5P'})
v = w.resolve_next(v.view, d)
self._set_password_and_check_address(v=v, w=w, recv_addr="bc1qtuzp7rectyjquax5c3p80eletswhp6cxslye749l47h4m9x92hzs6cmymy")
async def test_create_imported_wallet_from_addresses(self):
w = self._wizard_for(wallet_type='imported')
v = w._current
d = v.wizard_data
self.assertEqual('imported', v.view)
d.update({
'address_list':
'14gcRovpkCoGkCNBivQBvw7eso7eiNAbxG\n'
'35ZqQJcBQMZ1rsv8aSuJ2wkC7ohUCQMJbT\n'
'BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4\n'
'bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kt5nd6y\n'})
v = w.resolve_next(v.view, d)
wallet = self._set_password_and_check_address(v=v, w=w, recv_addr=None)
self.assertEqual(
set(wallet.get_receiving_addresses()),
{
"14gcRovpkCoGkCNBivQBvw7eso7eiNAbxG",
"35ZqQJcBQMZ1rsv8aSuJ2wkC7ohUCQMJbT",
"BC1QW508D6QEJXTDG4Y5R3ZARVARY0C5XW7KV8F3T4", # TODO normalize to lowercase?
"bc1pw508d6qejxtdg4y5r3zarvary0c5xw7kw508d6qejxtdg4y5r3zarvary0c5xw7kt5nd6y",
},
)
async def test_create_imported_wallet_from_addresses__invalid_input(self):
w = self._wizard_for(wallet_type='imported')
v = w._current
d = v.wizard_data
self.assertEqual('imported', v.view)
d.update({
'address_list':
'garbagegarbage\n'
'35ZqQJcBQMZ1rsv8aSuJ2wkC7ohUCQMJbT\n'
})
v = w.resolve_next(v.view, d)
with self.assertRaises(AssertionError) as ctx:
wallet = self._set_password_and_check_address(v=v, w=w, recv_addr=None)
self.assertTrue("expected bitcoin addr" in ctx.exception.args[0])
async def test_create_imported_wallet_from_wif_keys(self):
w = self._wizard_for(wallet_type='imported')
v = w._current
d = v.wizard_data
self.assertEqual('imported', v.view)
d.update({
'private_key_list':
'p2wpkh:L1cgMEnShp73r9iCukoPE3MogLeueNYRD9JVsfT1zVHyPBR3KqBY\n'
'p2pkh:KyQ2voUQj71P6E9KyDFqQoYMMm3yKKAPMKbfqZccib6xWxbWHCex\n'
'p2pkh:5JuecQZ1nH4VCQRQJTQjB4yu93BU6NmnAkDoGRdHX2PyH2E8QVX\n'})
v = w.resolve_next(v.view, d)
wallet = self._set_password_and_check_address(v=v, w=w, recv_addr=None)
self.assertEqual(
set(wallet.get_receiving_addresses()),
{"bc1qq2tmmcngng78nllq2pvrkchcdukemtj56uyue0", "1LNvv5h6QHoYv1nJcqrp13T2TBkD2sUGn1", "1FJEEB8ihPMbzs2SkLmr37dHyRFzakqUmo"},
)