wallet_createwallet.py
1 #!/usr/bin/env python3 2 # Copyright (c) 2018-2022 The Bitcoin Core developers 3 # Distributed under the MIT software license, see the accompanying 4 # file COPYING or http://www.opensource.org/licenses/mit-license.php. 5 """Test createwallet arguments. 6 """ 7 8 from test_framework.address import key_to_p2wpkh 9 from test_framework.descriptors import descsum_create 10 from test_framework.test_framework import BitcoinTestFramework 11 from test_framework.util import ( 12 assert_equal, 13 assert_raises_rpc_error, 14 ) 15 from test_framework.wallet_util import generate_keypair, WalletUnlock 16 17 18 EMPTY_PASSPHRASE_MSG = "Empty string given as passphrase, wallet will not be encrypted." 19 LEGACY_WALLET_MSG = "Wallet created successfully. The legacy wallet type is being deprecated and support for creating and opening legacy wallets will be removed in the future." 20 21 22 class CreateWalletTest(BitcoinTestFramework): 23 def add_options(self, parser): 24 self.add_wallet_options(parser) 25 26 def set_test_params(self): 27 self.num_nodes = 1 28 29 def skip_test_if_missing_module(self): 30 self.skip_if_no_wallet() 31 32 def run_test(self): 33 node = self.nodes[0] 34 self.generate(node, 1) # Leave IBD for sethdseed 35 36 self.log.info("Run createwallet with invalid parameters.") 37 # Run createwallet with invalid parameters. This must not prevent a new wallet with the same name from being created with the correct parameters. 38 assert_raises_rpc_error(-4, "Passphrase provided but private keys are disabled. A passphrase is only used to encrypt private keys, so cannot be used for wallets with private keys disabled.", 39 self.nodes[0].createwallet, wallet_name='w0', disable_private_keys=True, passphrase="passphrase") 40 41 self.nodes[0].createwallet(wallet_name='w0') 42 w0 = node.get_wallet_rpc('w0') 43 address1 = w0.getnewaddress() 44 45 self.log.info("Test disableprivatekeys creation.") 46 self.nodes[0].createwallet(wallet_name='w1', disable_private_keys=True) 47 w1 = node.get_wallet_rpc('w1') 48 assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w1.getnewaddress) 49 assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w1.getrawchangeaddress) 50 w1.importpubkey(w0.getaddressinfo(address1)['pubkey']) 51 52 self.log.info('Test that private keys cannot be imported') 53 privkey, pubkey = generate_keypair(wif=True) 54 assert_raises_rpc_error(-4, 'Cannot import private keys to a wallet with private keys disabled', w1.importprivkey, privkey) 55 if self.options.descriptors: 56 result = w1.importdescriptors([{'desc': descsum_create('wpkh(' + privkey + ')'), 'timestamp': 'now'}]) 57 else: 58 result = w1.importmulti([{'scriptPubKey': {'address': key_to_p2wpkh(pubkey)}, 'timestamp': 'now', 'keys': [privkey]}]) 59 assert not result[0]['success'] 60 assert 'warnings' not in result[0] 61 assert_equal(result[0]['error']['code'], -4) 62 assert_equal(result[0]['error']['message'], 'Cannot import private keys to a wallet with private keys disabled') 63 64 self.log.info("Test blank creation with private keys disabled.") 65 self.nodes[0].createwallet(wallet_name='w2', disable_private_keys=True, blank=True) 66 w2 = node.get_wallet_rpc('w2') 67 assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w2.getnewaddress) 68 assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w2.getrawchangeaddress) 69 w2.importpubkey(w0.getaddressinfo(address1)['pubkey']) 70 71 self.log.info("Test blank creation with private keys enabled.") 72 self.nodes[0].createwallet(wallet_name='w3', disable_private_keys=False, blank=True) 73 w3 = node.get_wallet_rpc('w3') 74 assert_equal(w3.getwalletinfo()['keypoolsize'], 0) 75 assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w3.getnewaddress) 76 assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w3.getrawchangeaddress) 77 # Import private key 78 w3.importprivkey(generate_keypair(wif=True)[0]) 79 # Imported private keys are currently ignored by the keypool 80 assert_equal(w3.getwalletinfo()['keypoolsize'], 0) 81 assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w3.getnewaddress) 82 # Set the seed 83 if self.options.descriptors: 84 w3.importdescriptors([{ 85 'desc': descsum_create('wpkh(tprv8ZgxMBicQKsPcwuZGKp8TeWppSuLMiLe2d9PupB14QpPeQsqoj3LneJLhGHH13xESfvASyd4EFLJvLrG8b7DrLxEuV7hpF9uUc6XruKA1Wq/0h/*)'), 86 'timestamp': 'now', 87 'active': True 88 }, 89 { 90 'desc': descsum_create('wpkh(tprv8ZgxMBicQKsPcwuZGKp8TeWppSuLMiLe2d9PupB14QpPeQsqoj3LneJLhGHH13xESfvASyd4EFLJvLrG8b7DrLxEuV7hpF9uUc6XruKA1Wq/1h/*)'), 91 'timestamp': 'now', 92 'active': True, 93 'internal': True 94 }]) 95 else: 96 w3.sethdseed() 97 assert_equal(w3.getwalletinfo()['keypoolsize'], 1) 98 w3.getnewaddress() 99 w3.getrawchangeaddress() 100 101 self.log.info("Test blank creation with privkeys enabled and then encryption") 102 self.nodes[0].createwallet(wallet_name='w4', disable_private_keys=False, blank=True) 103 w4 = node.get_wallet_rpc('w4') 104 assert_equal(w4.getwalletinfo()['keypoolsize'], 0) 105 assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w4.getnewaddress) 106 assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w4.getrawchangeaddress) 107 # Encrypt the wallet. Nothing should change about the keypool 108 w4.encryptwallet('pass') 109 assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w4.getnewaddress) 110 assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w4.getrawchangeaddress) 111 with WalletUnlock(w4, "pass"): 112 # Now set a seed and it should work. Wallet should also be encrypted 113 if self.options.descriptors: 114 w4.importdescriptors([{ 115 'desc': descsum_create('wpkh(tprv8ZgxMBicQKsPcwuZGKp8TeWppSuLMiLe2d9PupB14QpPeQsqoj3LneJLhGHH13xESfvASyd4EFLJvLrG8b7DrLxEuV7hpF9uUc6XruKA1Wq/0h/*)'), 116 'timestamp': 'now', 117 'active': True 118 }, 119 { 120 'desc': descsum_create('wpkh(tprv8ZgxMBicQKsPcwuZGKp8TeWppSuLMiLe2d9PupB14QpPeQsqoj3LneJLhGHH13xESfvASyd4EFLJvLrG8b7DrLxEuV7hpF9uUc6XruKA1Wq/1h/*)'), 121 'timestamp': 'now', 122 'active': True, 123 'internal': True 124 }]) 125 else: 126 w4.sethdseed() 127 w4.getnewaddress() 128 w4.getrawchangeaddress() 129 130 self.log.info("Test blank creation with privkeys disabled and then encryption") 131 self.nodes[0].createwallet(wallet_name='w5', disable_private_keys=True, blank=True) 132 w5 = node.get_wallet_rpc('w5') 133 assert_equal(w5.getwalletinfo()['keypoolsize'], 0) 134 assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w5.getnewaddress) 135 assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w5.getrawchangeaddress) 136 # Encrypt the wallet 137 assert_raises_rpc_error(-16, "Error: wallet does not contain private keys, nothing to encrypt.", w5.encryptwallet, 'pass') 138 assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w5.getnewaddress) 139 assert_raises_rpc_error(-4, "Error: This wallet has no available keys", w5.getrawchangeaddress) 140 141 self.log.info('New blank and encrypted wallets can be created') 142 self.nodes[0].createwallet(wallet_name='wblank', disable_private_keys=False, blank=True, passphrase='thisisapassphrase') 143 wblank = node.get_wallet_rpc('wblank') 144 assert_raises_rpc_error(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.", wblank.signmessage, "needanargument", "test") 145 with WalletUnlock(wblank, "thisisapassphrase"): 146 assert_raises_rpc_error(-4, "Error: This wallet has no available keys", wblank.getnewaddress) 147 assert_raises_rpc_error(-4, "Error: This wallet has no available keys", wblank.getrawchangeaddress) 148 149 self.log.info('Test creating a new encrypted wallet.') 150 # Born encrypted wallet is created (has keys) 151 self.nodes[0].createwallet(wallet_name='w6', disable_private_keys=False, blank=False, passphrase='thisisapassphrase') 152 w6 = node.get_wallet_rpc('w6') 153 assert_raises_rpc_error(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.", w6.signmessage, "needanargument", "test") 154 with WalletUnlock(w6, "thisisapassphrase"): 155 w6.signmessage(w6.getnewaddress('', 'legacy'), "test") 156 w6.keypoolrefill(1) 157 # There should only be 1 key for legacy, 3 for descriptors 158 walletinfo = w6.getwalletinfo() 159 keys = 4 if self.options.descriptors else 1 160 assert_equal(walletinfo['keypoolsize'], keys) 161 assert_equal(walletinfo['keypoolsize_hd_internal'], keys) 162 # Allow empty passphrase, but there should be a warning 163 resp = self.nodes[0].createwallet(wallet_name='w7', disable_private_keys=False, blank=False, passphrase='') 164 assert_equal(resp["warnings"], [EMPTY_PASSPHRASE_MSG] if self.options.descriptors else [EMPTY_PASSPHRASE_MSG, LEGACY_WALLET_MSG]) 165 166 w7 = node.get_wallet_rpc('w7') 167 assert_raises_rpc_error(-15, 'Error: running with an unencrypted wallet, but walletpassphrase was called.', w7.walletpassphrase, '', 60) 168 169 self.log.info('Test making a wallet with avoid reuse flag') 170 self.nodes[0].createwallet('w8', False, False, '', True) # Use positional arguments to check for bug where avoid_reuse could not be set for wallets without needing them to be encrypted 171 w8 = node.get_wallet_rpc('w8') 172 assert_raises_rpc_error(-15, 'Error: running with an unencrypted wallet, but walletpassphrase was called.', w7.walletpassphrase, '', 60) 173 assert_equal(w8.getwalletinfo()["avoid_reuse"], True) 174 175 self.log.info('Using a passphrase with private keys disabled returns error') 176 assert_raises_rpc_error(-4, 'Passphrase provided but private keys are disabled. A passphrase is only used to encrypt private keys, so cannot be used for wallets with private keys disabled.', self.nodes[0].createwallet, wallet_name='w9', disable_private_keys=True, passphrase='thisisapassphrase') 177 178 if self.is_bdb_compiled(): 179 self.log.info("Test legacy wallet deprecation") 180 result = self.nodes[0].createwallet(wallet_name="legacy_w0", descriptors=False, passphrase=None) 181 assert_equal(result, { 182 "name": "legacy_w0", 183 "warnings": [LEGACY_WALLET_MSG], 184 }) 185 result = self.nodes[0].createwallet(wallet_name="legacy_w1", descriptors=False, passphrase="") 186 assert_equal(result, { 187 "name": "legacy_w1", 188 "warnings": [EMPTY_PASSPHRASE_MSG, LEGACY_WALLET_MSG], 189 }) 190 191 192 if __name__ == '__main__': 193 CreateWalletTest().main()