Changeset View
Changeset View
Standalone View
Standalone View
test/functional/wallet_createwallet.py
Show All 19 Lines | class CreateWalletTest(BitcoinTestFramework): | ||||
def skip_test_if_missing_module(self): | def skip_test_if_missing_module(self): | ||||
self.skip_if_no_wallet() | self.skip_if_no_wallet() | ||||
def run_test(self): | def run_test(self): | ||||
node = self.nodes[0] | node = self.nodes[0] | ||||
# Leave IBD for sethdseed | # Leave IBD for sethdseed | ||||
self.generate(node, 1) | self.generate(node, 1) | ||||
self.nodes[0].createwallet(wallet_name='w0') | self.nodes[0].createwallet(wallet_name="w0") | ||||
w0 = node.get_wallet_rpc('w0') | w0 = node.get_wallet_rpc("w0") | ||||
address1 = w0.getnewaddress() | address1 = w0.getnewaddress() | ||||
self.log.info("Test disableprivatekeys creation.") | self.log.info("Test disableprivatekeys creation.") | ||||
self.nodes[0].createwallet(wallet_name='w1', disable_private_keys=True) | self.nodes[0].createwallet(wallet_name="w1", disable_private_keys=True) | ||||
w1 = node.get_wallet_rpc('w1') | w1 = node.get_wallet_rpc("w1") | ||||
assert_raises_rpc_error(-4, | assert_raises_rpc_error( | ||||
"Error: This wallet has no available keys", w1.getnewaddress) | -4, "Error: This wallet has no available keys", w1.getnewaddress | ||||
assert_raises_rpc_error(-4, "Error: This wallet has no available keys", | ) | ||||
w1.getrawchangeaddress) | assert_raises_rpc_error( | ||||
w1.importpubkey(w0.getaddressinfo(address1)['pubkey']) | -4, "Error: This wallet has no available keys", w1.getrawchangeaddress | ||||
) | |||||
w1.importpubkey(w0.getaddressinfo(address1)["pubkey"]) | |||||
self.log.info('Test that private keys cannot be imported') | self.log.info("Test that private keys cannot be imported") | ||||
eckey = ECKey() | eckey = ECKey() | ||||
eckey.generate() | eckey.generate() | ||||
privkey = bytes_to_wif(eckey.get_bytes()) | privkey = bytes_to_wif(eckey.get_bytes()) | ||||
assert_raises_rpc_error( | assert_raises_rpc_error( | ||||
-4, 'Cannot import private keys to a wallet with private keys disabled', w1.importprivkey, privkey) | -4, | ||||
"Cannot import private keys to a wallet with private keys disabled", | |||||
w1.importprivkey, | |||||
privkey, | |||||
) | |||||
if self.options.descriptors: | if self.options.descriptors: | ||||
result = w1.importdescriptors( | result = w1.importdescriptors( | ||||
[{'desc': descsum_create(f"pkh({privkey})"), | [{"desc": descsum_create(f"pkh({privkey})"), "timestamp": "now"}] | ||||
'timestamp': 'now'}]) | ) | ||||
else: | else: | ||||
result = w1.importmulti( | result = w1.importmulti( | ||||
[{'scriptPubKey': { | [ | ||||
'address': key_to_p2pkh(eckey.get_pubkey().get_bytes())}, | { | ||||
'timestamp': 'now', 'keys': [privkey]}]) | "scriptPubKey": { | ||||
assert not result[0]['success'] | "address": key_to_p2pkh(eckey.get_pubkey().get_bytes()) | ||||
assert 'warning' not in result[0] | }, | ||||
assert_equal(result[0]['error']['code'], -4) | "timestamp": "now", | ||||
assert_equal(result[0]['error']['message'], | "keys": [privkey], | ||||
'Cannot import private keys to a wallet with private keys disabled') | } | ||||
] | |||||
) | |||||
assert not result[0]["success"] | |||||
assert "warning" not in result[0] | |||||
assert_equal(result[0]["error"]["code"], -4) | |||||
assert_equal( | |||||
result[0]["error"]["message"], | |||||
"Cannot import private keys to a wallet with private keys disabled", | |||||
) | |||||
self.log.info("Test blank creation with private keys disabled.") | self.log.info("Test blank creation with private keys disabled.") | ||||
self.nodes[0].createwallet( | self.nodes[0].createwallet( | ||||
wallet_name='w2', disable_private_keys=True, blank=True) | wallet_name="w2", disable_private_keys=True, blank=True | ||||
w2 = node.get_wallet_rpc('w2') | ) | ||||
assert_raises_rpc_error(-4, | w2 = node.get_wallet_rpc("w2") | ||||
"Error: This wallet has no available keys", w2.getnewaddress) | assert_raises_rpc_error( | ||||
assert_raises_rpc_error(-4, "Error: This wallet has no available keys", | -4, "Error: This wallet has no available keys", w2.getnewaddress | ||||
w2.getrawchangeaddress) | ) | ||||
w2.importpubkey(w0.getaddressinfo(address1)['pubkey']) | assert_raises_rpc_error( | ||||
-4, "Error: This wallet has no available keys", w2.getrawchangeaddress | |||||
) | |||||
w2.importpubkey(w0.getaddressinfo(address1)["pubkey"]) | |||||
self.log.info("Test blank creation with private keys enabled.") | self.log.info("Test blank creation with private keys enabled.") | ||||
self.nodes[0].createwallet( | self.nodes[0].createwallet( | ||||
wallet_name='w3', disable_private_keys=False, blank=True) | wallet_name="w3", disable_private_keys=False, blank=True | ||||
w3 = node.get_wallet_rpc('w3') | ) | ||||
assert_equal(w3.getwalletinfo()['keypoolsize'], 0) | w3 = node.get_wallet_rpc("w3") | ||||
assert_raises_rpc_error(-4, | assert_equal(w3.getwalletinfo()["keypoolsize"], 0) | ||||
"Error: This wallet has no available keys", w3.getnewaddress) | assert_raises_rpc_error( | ||||
assert_raises_rpc_error(-4, "Error: This wallet has no available keys", | -4, "Error: This wallet has no available keys", w3.getnewaddress | ||||
w3.getrawchangeaddress) | ) | ||||
assert_raises_rpc_error( | |||||
-4, "Error: This wallet has no available keys", w3.getrawchangeaddress | |||||
) | |||||
# Import private key | # Import private key | ||||
w3.importprivkey(generate_wif_key()) | w3.importprivkey(generate_wif_key()) | ||||
# Imported private keys are currently ignored by the keypool | # Imported private keys are currently ignored by the keypool | ||||
assert_equal(w3.getwalletinfo()['keypoolsize'], 0) | assert_equal(w3.getwalletinfo()["keypoolsize"], 0) | ||||
assert_raises_rpc_error(-4, | assert_raises_rpc_error( | ||||
"Error: This wallet has no available keys", w3.getnewaddress) | -4, "Error: This wallet has no available keys", w3.getnewaddress | ||||
) | |||||
# Set the seed | # Set the seed | ||||
if self.options.descriptors: | if self.options.descriptors: | ||||
w3.importdescriptors([{ | w3.importdescriptors( | ||||
'desc': descsum_create( | [ | ||||
'pkh(tprv8ZgxMBicQKsPcwuZGKp8TeWppSuLMiLe2d9PupB14QpPeQsqoj3LneJLhGHH13xESfvASyd4EFLJvLrG8b7DrLxEuV7hpF9uUc6XruKA1Wq/0h/*)'), | { | ||||
'timestamp': 'now', | "desc": descsum_create( | ||||
'active': True | "pkh(tprv8ZgxMBicQKsPcwuZGKp8TeWppSuLMiLe2d9PupB14QpPeQsqoj3LneJLhGHH13xESfvASyd4EFLJvLrG8b7DrLxEuV7hpF9uUc6XruKA1Wq/0h/*)" | ||||
), | |||||
"timestamp": "now", | |||||
"active": True, | |||||
}, | }, | ||||
{ | { | ||||
'desc': descsum_create( | "desc": descsum_create( | ||||
'pkh(tprv8ZgxMBicQKsPcwuZGKp8TeWppSuLMiLe2d9PupB14QpPeQsqoj3LneJLhGHH13xESfvASyd4EFLJvLrG8b7DrLxEuV7hpF9uUc6XruKA1Wq/1h/*)'), | "pkh(tprv8ZgxMBicQKsPcwuZGKp8TeWppSuLMiLe2d9PupB14QpPeQsqoj3LneJLhGHH13xESfvASyd4EFLJvLrG8b7DrLxEuV7hpF9uUc6XruKA1Wq/1h/*)" | ||||
'timestamp': 'now', | ), | ||||
'active': True, | "timestamp": "now", | ||||
'internal': True | "active": True, | ||||
}]) | "internal": True, | ||||
}, | |||||
] | |||||
) | |||||
else: | else: | ||||
w3.sethdseed() | w3.sethdseed() | ||||
assert_equal(w3.getwalletinfo()['keypoolsize'], 1) | assert_equal(w3.getwalletinfo()["keypoolsize"], 1) | ||||
w3.getnewaddress() | w3.getnewaddress() | ||||
w3.getrawchangeaddress() | w3.getrawchangeaddress() | ||||
self.log.info( | self.log.info("Test blank creation with privkeys enabled and then encryption") | ||||
"Test blank creation with privkeys enabled and then encryption") | |||||
self.nodes[0].createwallet( | self.nodes[0].createwallet( | ||||
wallet_name='w4', disable_private_keys=False, blank=True) | wallet_name="w4", disable_private_keys=False, blank=True | ||||
w4 = node.get_wallet_rpc('w4') | ) | ||||
assert_equal(w4.getwalletinfo()['keypoolsize'], 0) | w4 = node.get_wallet_rpc("w4") | ||||
assert_raises_rpc_error(-4, | assert_equal(w4.getwalletinfo()["keypoolsize"], 0) | ||||
"Error: This wallet has no available keys", w4.getnewaddress) | assert_raises_rpc_error( | ||||
assert_raises_rpc_error(-4, "Error: This wallet has no available keys", | -4, "Error: This wallet has no available keys", w4.getnewaddress | ||||
w4.getrawchangeaddress) | ) | ||||
assert_raises_rpc_error( | |||||
-4, "Error: This wallet has no available keys", w4.getrawchangeaddress | |||||
) | |||||
# Encrypt the wallet. Nothing should change about the keypool | # Encrypt the wallet. Nothing should change about the keypool | ||||
w4.encryptwallet('pass') | w4.encryptwallet("pass") | ||||
assert_raises_rpc_error(-4, | assert_raises_rpc_error( | ||||
"Error: This wallet has no available keys", w4.getnewaddress) | -4, "Error: This wallet has no available keys", w4.getnewaddress | ||||
assert_raises_rpc_error(-4, "Error: This wallet has no available keys", | ) | ||||
w4.getrawchangeaddress) | assert_raises_rpc_error( | ||||
-4, "Error: This wallet has no available keys", w4.getrawchangeaddress | |||||
) | |||||
# Now set a seed and it should work. Wallet should also be encrypted | # Now set a seed and it should work. Wallet should also be encrypted | ||||
w4.walletpassphrase('pass', 2) | w4.walletpassphrase("pass", 2) | ||||
if self.options.descriptors: | if self.options.descriptors: | ||||
w4.importdescriptors([{ | w4.importdescriptors( | ||||
'desc': descsum_create( | [ | ||||
'pkh(tprv8ZgxMBicQKsPcwuZGKp8TeWppSuLMiLe2d9PupB14QpPeQsqoj3LneJLhGHH13xESfvASyd4EFLJvLrG8b7DrLxEuV7hpF9uUc6XruKA1Wq/0h/*)'), | { | ||||
'timestamp': 'now', | "desc": descsum_create( | ||||
'active': True | "pkh(tprv8ZgxMBicQKsPcwuZGKp8TeWppSuLMiLe2d9PupB14QpPeQsqoj3LneJLhGHH13xESfvASyd4EFLJvLrG8b7DrLxEuV7hpF9uUc6XruKA1Wq/0h/*)" | ||||
), | |||||
"timestamp": "now", | |||||
"active": True, | |||||
}, | }, | ||||
{ | { | ||||
'desc': descsum_create( | "desc": descsum_create( | ||||
'pkh(tprv8ZgxMBicQKsPcwuZGKp8TeWppSuLMiLe2d9PupB14QpPeQsqoj3LneJLhGHH13xESfvASyd4EFLJvLrG8b7DrLxEuV7hpF9uUc6XruKA1Wq/1h/*)'), | "pkh(tprv8ZgxMBicQKsPcwuZGKp8TeWppSuLMiLe2d9PupB14QpPeQsqoj3LneJLhGHH13xESfvASyd4EFLJvLrG8b7DrLxEuV7hpF9uUc6XruKA1Wq/1h/*)" | ||||
'timestamp': 'now', | ), | ||||
'active': True, | "timestamp": "now", | ||||
'internal': True | "active": True, | ||||
}]) | "internal": True, | ||||
}, | |||||
] | |||||
) | |||||
else: | else: | ||||
w4.sethdseed() | w4.sethdseed() | ||||
w4.getnewaddress() | w4.getnewaddress() | ||||
w4.getrawchangeaddress() | w4.getrawchangeaddress() | ||||
self.log.info( | self.log.info("Test blank creation with privkeys disabled and then encryption") | ||||
"Test blank creation with privkeys disabled and then encryption") | |||||
self.nodes[0].createwallet( | self.nodes[0].createwallet( | ||||
wallet_name='w5', disable_private_keys=True, blank=True) | wallet_name="w5", disable_private_keys=True, blank=True | ||||
) | |||||
w5 = node.get_wallet_rpc('w5') | w5 = node.get_wallet_rpc("w5") | ||||
assert_equal(w5.getwalletinfo()['keypoolsize'], 0) | assert_equal(w5.getwalletinfo()["keypoolsize"], 0) | ||||
assert_raises_rpc_error(-4, | assert_raises_rpc_error( | ||||
"Error: This wallet has no available keys", w5.getnewaddress) | -4, "Error: This wallet has no available keys", w5.getnewaddress | ||||
assert_raises_rpc_error(-4, "Error: This wallet has no available keys", | ) | ||||
w5.getrawchangeaddress) | assert_raises_rpc_error( | ||||
-4, "Error: This wallet has no available keys", w5.getrawchangeaddress | |||||
) | |||||
# Encrypt the wallet | # Encrypt the wallet | ||||
assert_raises_rpc_error(-16, | assert_raises_rpc_error( | ||||
-16, | |||||
"Error: wallet does not contain private keys, nothing to encrypt.", | "Error: wallet does not contain private keys, nothing to encrypt.", | ||||
w5.encryptwallet, | w5.encryptwallet, | ||||
'pass') | "pass", | ||||
assert_raises_rpc_error(-4, | ) | ||||
"Error: This wallet has no available keys", w5.getnewaddress) | assert_raises_rpc_error( | ||||
assert_raises_rpc_error(-4, "Error: This wallet has no available keys", | -4, "Error: This wallet has no available keys", w5.getnewaddress | ||||
w5.getrawchangeaddress) | ) | ||||
assert_raises_rpc_error( | |||||
-4, "Error: This wallet has no available keys", w5.getrawchangeaddress | |||||
) | |||||
self.log.info('New blank and encrypted wallets can be created') | self.log.info("New blank and encrypted wallets can be created") | ||||
self.nodes[0].createwallet( | self.nodes[0].createwallet( | ||||
wallet_name='wblank', | wallet_name="wblank", | ||||
disable_private_keys=False, | disable_private_keys=False, | ||||
blank=True, | blank=True, | ||||
passphrase='thisisapassphrase') | passphrase="thisisapassphrase", | ||||
wblank = node.get_wallet_rpc('wblank') | ) | ||||
wblank = node.get_wallet_rpc("wblank") | |||||
assert_raises_rpc_error( | assert_raises_rpc_error( | ||||
-13, | -13, | ||||
"Error: Please enter the wallet passphrase with walletpassphrase first.", | "Error: Please enter the wallet passphrase with walletpassphrase first.", | ||||
wblank.signmessage, | wblank.signmessage, | ||||
"needanargument", | "needanargument", | ||||
"test") | "test", | ||||
wblank.walletpassphrase('thisisapassphrase', 10) | ) | ||||
assert_raises_rpc_error(-4, | wblank.walletpassphrase("thisisapassphrase", 10) | ||||
"Error: This wallet has no available keys", | assert_raises_rpc_error( | ||||
wblank.getnewaddress) | -4, "Error: This wallet has no available keys", wblank.getnewaddress | ||||
assert_raises_rpc_error(-4, | ) | ||||
"Error: This wallet has no available keys", | assert_raises_rpc_error( | ||||
wblank.getrawchangeaddress) | -4, "Error: This wallet has no available keys", wblank.getrawchangeaddress | ||||
) | |||||
self.log.info('Test creating a new encrypted wallet.') | self.log.info("Test creating a new encrypted wallet.") | ||||
# Born encrypted wallet is created (has keys) | # Born encrypted wallet is created (has keys) | ||||
self.nodes[0].createwallet( | self.nodes[0].createwallet( | ||||
wallet_name='w6', | wallet_name="w6", | ||||
disable_private_keys=False, | disable_private_keys=False, | ||||
blank=False, | blank=False, | ||||
passphrase='thisisapassphrase') | passphrase="thisisapassphrase", | ||||
w6 = node.get_wallet_rpc('w6') | ) | ||||
w6 = node.get_wallet_rpc("w6") | |||||
assert_raises_rpc_error( | assert_raises_rpc_error( | ||||
-13, | -13, | ||||
"Error: Please enter the wallet passphrase with walletpassphrase first.", | "Error: Please enter the wallet passphrase with walletpassphrase first.", | ||||
w6.signmessage, | w6.signmessage, | ||||
"needanargument", | "needanargument", | ||||
"test") | "test", | ||||
w6.walletpassphrase('thisisapassphrase', 10) | ) | ||||
w6.signmessage(w6.getnewaddress('', 'legacy'), "test") | w6.walletpassphrase("thisisapassphrase", 10) | ||||
w6.signmessage(w6.getnewaddress("", "legacy"), "test") | |||||
w6.keypoolrefill(1) | w6.keypoolrefill(1) | ||||
# There should only be 1 key for legacy and for descriptors | # There should only be 1 key for legacy and for descriptors | ||||
walletinfo = w6.getwalletinfo() | walletinfo = w6.getwalletinfo() | ||||
assert_equal(walletinfo['keypoolsize'], 1) | assert_equal(walletinfo["keypoolsize"], 1) | ||||
assert_equal(walletinfo['keypoolsize_hd_internal'], 1) | assert_equal(walletinfo["keypoolsize_hd_internal"], 1) | ||||
# Allow empty passphrase, but there should be a warning | # Allow empty passphrase, but there should be a warning | ||||
resp = self.nodes[0].createwallet( | resp = self.nodes[0].createwallet( | ||||
wallet_name='w7', | wallet_name="w7", disable_private_keys=False, blank=False, passphrase="" | ||||
disable_private_keys=False, | ) | ||||
blank=False, | |||||
passphrase='') | |||||
assert ( | assert ( | ||||
'Empty string given as passphrase, wallet will not be encrypted.' | "Empty string given as passphrase, wallet will not be encrypted." | ||||
in resp['warning']) | in resp["warning"] | ||||
w7 = node.get_wallet_rpc('w7') | ) | ||||
w7 = node.get_wallet_rpc("w7") | |||||
assert_raises_rpc_error( | assert_raises_rpc_error( | ||||
-15, | -15, | ||||
'Error: running with an unencrypted wallet, but walletpassphrase was called.', | ( | ||||
"Error: running with an unencrypted wallet, but walletpassphrase was" | |||||
" called." | |||||
), | |||||
w7.walletpassphrase, | w7.walletpassphrase, | ||||
'', | "", | ||||
10) | 10, | ||||
) | |||||
self.log.info('Test making a wallet with avoid reuse flag') | self.log.info("Test making a wallet with avoid reuse flag") | ||||
# Use positional arguments to check for bug where avoid_reuse could not | # Use positional arguments to check for bug where avoid_reuse could not | ||||
# be set for wallets without needing them to be encrypted | # be set for wallets without needing them to be encrypted | ||||
self.nodes[0].createwallet('w8', False, False, '', True) | self.nodes[0].createwallet("w8", False, False, "", True) | ||||
w8 = node.get_wallet_rpc('w8') | w8 = node.get_wallet_rpc("w8") | ||||
assert_raises_rpc_error( | assert_raises_rpc_error( | ||||
-15, | -15, | ||||
'Error: running with an unencrypted wallet, but walletpassphrase was called.', | ( | ||||
"Error: running with an unencrypted wallet, but walletpassphrase was" | |||||
" called." | |||||
), | |||||
w7.walletpassphrase, | w7.walletpassphrase, | ||||
'', | "", | ||||
10) | 10, | ||||
) | |||||
assert_equal(w8.getwalletinfo()["avoid_reuse"], True) | assert_equal(w8.getwalletinfo()["avoid_reuse"], True) | ||||
self.log.info( | self.log.info("Using a passphrase with private keys disabled returns error") | ||||
'Using a passphrase with private keys disabled returns error') | |||||
assert_raises_rpc_error( | assert_raises_rpc_error( | ||||
-4, | -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.', | ( | ||||
"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, | self.nodes[0].createwallet, | ||||
wallet_name='w9', | wallet_name="w9", | ||||
disable_private_keys=True, | disable_private_keys=True, | ||||
passphrase='thisisapassphrase') | passphrase="thisisapassphrase", | ||||
) | |||||
if __name__ == '__main__': | if __name__ == "__main__": | ||||
CreateWalletTest().main() | CreateWalletTest().main() |