mirror of
https://github.com/dashpay/dash.git
synced 2024-12-26 20:42:59 +01:00
212 lines
9.6 KiB
Python
Executable File
212 lines
9.6 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
# Copyright (c) 2016 The Bitcoin Core developers
|
|
# Distributed under the MIT software license, see the accompanying
|
|
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
"""
|
|
wallet_upgradetohd.py
|
|
|
|
Test upgrade to a Hierarchical Deterministic wallet via upgradetohd rpc
|
|
"""
|
|
|
|
import shutil
|
|
import os
|
|
|
|
from test_framework.test_framework import BitcoinTestFramework
|
|
from test_framework.util import (
|
|
assert_equal,
|
|
assert_raises_rpc_error,
|
|
)
|
|
|
|
|
|
class WalletUpgradeToHDTest(BitcoinTestFramework):
|
|
def set_test_params(self):
|
|
self.num_nodes = 1
|
|
self.extra_args = [['-usehd=0']]
|
|
|
|
def skip_test_if_missing_module(self):
|
|
self.skip_if_no_wallet()
|
|
|
|
def setup_network(self):
|
|
self.add_nodes(self.num_nodes, self.extra_args)
|
|
self.start_nodes()
|
|
self.import_deterministic_coinbase_privkeys()
|
|
|
|
def recover_non_hd(self):
|
|
self.log.info("Recover non-HD wallet to check different upgrade paths")
|
|
node = self.nodes[0]
|
|
self.stop_node(0)
|
|
shutil.copyfile(os.path.join(node.datadir, "non_hd.bak"), os.path.join(node.datadir, self.chain, self.default_wallet_name, self.wallet_data_filename))
|
|
self.start_node(0)
|
|
assert 'hdchainid' not in node.getwalletinfo()
|
|
|
|
def run_test(self):
|
|
node = self.nodes[0]
|
|
node.backupwallet(os.path.join(node.datadir, "non_hd.bak"))
|
|
|
|
self.log.info("No mnemonic, no mnemonic passphrase, no wallet passphrase")
|
|
assert 'hdchainid' not in node.getwalletinfo()
|
|
balance_before = node.getbalance()
|
|
assert node.upgradetohd()
|
|
mnemonic = node.dumphdinfo()['mnemonic']
|
|
chainid = node.getwalletinfo()['hdchainid']
|
|
assert_equal(len(chainid), 64)
|
|
assert_equal(balance_before, node.getbalance())
|
|
|
|
self.log.info("Should be spendable and should use correct paths")
|
|
for i in range(5):
|
|
txid = node.sendtoaddress(node.getnewaddress(), 1)
|
|
outs = node.decoderawtransaction(node.gettransaction(txid)['hex'])['vout']
|
|
for out in outs:
|
|
if out['value'] == 1:
|
|
keypath = node.getaddressinfo(out['scriptPubKey']['address'])['hdkeypath']
|
|
assert_equal(keypath, "m/44'/1'/0'/0/%d" % i)
|
|
else:
|
|
keypath = node.getaddressinfo(out['scriptPubKey']['address'])['hdkeypath']
|
|
assert_equal(keypath, "m/44'/1'/0'/1/%d" % i)
|
|
|
|
self.bump_mocktime(1)
|
|
self.generate(node, 1, sync_fun=self.no_op)
|
|
|
|
self.log.info("Should no longer be able to start it with HD disabled")
|
|
self.stop_node(0)
|
|
node.assert_start_raises_init_error(['-usehd=0'], "Error: Error loading %s: You can't disable HD on an already existing HD wallet" % self.default_wallet_name)
|
|
self.extra_args = []
|
|
self.start_node(0, [])
|
|
balance_after = node.getbalance()
|
|
|
|
self.recover_non_hd()
|
|
|
|
# We spent some coins from non-HD keys to HD ones earlier
|
|
balance_non_HD = node.getbalance()
|
|
assert balance_before != balance_non_HD
|
|
|
|
self.log.info("No mnemonic, no mnemonic passphrase, no wallet passphrase, should result in completely different keys")
|
|
assert node.upgradetohd()
|
|
assert mnemonic != node.dumphdinfo()['mnemonic']
|
|
assert chainid != node.getwalletinfo()['hdchainid']
|
|
assert_equal(balance_non_HD, node.getbalance())
|
|
node.keypoolrefill(5)
|
|
node.rescanblockchain()
|
|
# Completely different keys, no HD coins should be recovered
|
|
assert_equal(balance_non_HD, node.getbalance())
|
|
|
|
self.recover_non_hd()
|
|
|
|
self.log.info("No mnemonic, no mnemonic passphrase, no wallet passphrase, should result in completely different keys")
|
|
self.restart_node(0, extra_args=['-keypool=10'])
|
|
assert node.upgradetohd("", "", "", True)
|
|
# Completely different keys, no HD coins should be recovered
|
|
assert mnemonic != node.dumphdinfo()['mnemonic']
|
|
assert chainid != node.getwalletinfo()['hdchainid']
|
|
assert_equal(balance_non_HD, node.getbalance())
|
|
|
|
self.recover_non_hd()
|
|
|
|
self.log.info("Same mnemonic, another mnemonic passphrase, no wallet passphrase, should result in a different set of keys")
|
|
new_mnemonic_passphrase = "somewords"
|
|
assert node.upgradetohd(mnemonic, new_mnemonic_passphrase)
|
|
assert_equal(mnemonic, node.dumphdinfo()['mnemonic'])
|
|
new_chainid = node.getwalletinfo()['hdchainid']
|
|
assert chainid != new_chainid
|
|
assert_equal(balance_non_HD, node.getbalance())
|
|
node.keypoolrefill(5)
|
|
node.rescanblockchain()
|
|
# A different set of keys, no HD coins should be recovered
|
|
new_addresses = (node.getnewaddress(), node.getrawchangeaddress())
|
|
assert_equal(balance_non_HD, node.getbalance())
|
|
|
|
self.recover_non_hd()
|
|
|
|
self.log.info("Same mnemonic, another mnemonic passphrase, no wallet passphrase, should result in a different set of keys (again)")
|
|
assert node.upgradetohd(mnemonic, new_mnemonic_passphrase)
|
|
assert_equal(mnemonic, node.dumphdinfo()['mnemonic'])
|
|
assert_equal(new_chainid, node.getwalletinfo()['hdchainid'])
|
|
assert_equal(balance_non_HD, node.getbalance())
|
|
node.keypoolrefill(5)
|
|
node.rescanblockchain()
|
|
# A different set of keys, no HD coins should be recovered, keys should be the same as they were the previous time
|
|
assert_equal(new_addresses, (node.getnewaddress(), node.getrawchangeaddress()))
|
|
assert_equal(balance_non_HD, node.getbalance())
|
|
|
|
self.recover_non_hd()
|
|
|
|
self.log.info("Same mnemonic, no mnemonic passphrase, no wallet passphrase, should recover all coins after rescan")
|
|
assert node.upgradetohd(mnemonic)
|
|
assert_equal(mnemonic, node.dumphdinfo()['mnemonic'])
|
|
assert_equal(chainid, node.getwalletinfo()['hdchainid'])
|
|
node.keypoolrefill(5)
|
|
assert balance_after != node.getbalance()
|
|
node.rescanblockchain()
|
|
assert_equal(balance_after, node.getbalance())
|
|
|
|
self.recover_non_hd()
|
|
|
|
self.log.info("Same mnemonic, no mnemonic passphrase, no wallet passphrase, large enough keepool, should recover all coins with no extra rescan")
|
|
self.restart_node(0, extra_args=['-keypool=10'])
|
|
assert node.upgradetohd(mnemonic)
|
|
assert_equal(mnemonic, node.dumphdinfo()['mnemonic'])
|
|
assert_equal(chainid, node.getwalletinfo()['hdchainid'])
|
|
# All coins should be recovered
|
|
assert_equal(balance_after, node.getbalance())
|
|
|
|
self.recover_non_hd()
|
|
|
|
self.log.info("Same mnemonic, no mnemonic passphrase, no wallet passphrase, large enough keepool, rescan is skipped initially, should recover all coins after rescanblockchain")
|
|
self.restart_node(0, extra_args=['-keypool=10'])
|
|
assert node.upgradetohd(mnemonic, "", "", False)
|
|
assert_equal(mnemonic, node.dumphdinfo()['mnemonic'])
|
|
assert_equal(chainid, node.getwalletinfo()['hdchainid'])
|
|
assert balance_after != node.getbalance()
|
|
node.rescanblockchain()
|
|
# All coins should be recovered
|
|
assert_equal(balance_after, node.getbalance())
|
|
|
|
self.recover_non_hd()
|
|
|
|
self.log.info("Same mnemonic, same mnemonic passphrase, encrypt wallet on upgrade, should recover all coins after rescan")
|
|
walletpass = "111pass222"
|
|
assert node.upgradetohd(mnemonic, "", walletpass)
|
|
node.stop()
|
|
node.wait_until_stopped()
|
|
self.start_node(0, extra_args=['-rescan'])
|
|
assert_raises_rpc_error(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.", node.dumphdinfo)
|
|
node.walletpassphrase(walletpass, 100)
|
|
assert_equal(mnemonic, node.dumphdinfo()['mnemonic'])
|
|
assert_equal(chainid, node.getwalletinfo()['hdchainid'])
|
|
# Note: wallet encryption results in additional keypool topup,
|
|
# so we can't compare new balance to balance_non_HD here,
|
|
# assert_equal(balance_non_HD, node.getbalance()) # won't work
|
|
assert balance_non_HD != node.getbalance()
|
|
node.keypoolrefill(4)
|
|
node.rescanblockchain()
|
|
# All coins should be recovered
|
|
assert_equal(balance_after, node.getbalance())
|
|
|
|
self.recover_non_hd()
|
|
|
|
self.log.info("Same mnemonic, same mnemonic passphrase, encrypt wallet first, should recover all coins on upgrade after rescan")
|
|
walletpass = "111pass222"
|
|
node.encryptwallet(walletpass)
|
|
node.stop()
|
|
node.wait_until_stopped()
|
|
self.start_node(0, extra_args=['-rescan'])
|
|
assert_raises_rpc_error(-13, "Error: Wallet encrypted but passphrase not supplied to RPC.", node.upgradetohd, mnemonic)
|
|
assert_raises_rpc_error(-1, "Error: The wallet passphrase entered was incorrect", node.upgradetohd, mnemonic, "", "wrongpass")
|
|
assert node.upgradetohd(mnemonic, "", walletpass)
|
|
assert_raises_rpc_error(-13, "Error: Please enter the wallet passphrase with walletpassphrase first.", node.dumphdinfo)
|
|
node.walletpassphrase(walletpass, 100)
|
|
assert_equal(mnemonic, node.dumphdinfo()['mnemonic'])
|
|
assert_equal(chainid, node.getwalletinfo()['hdchainid'])
|
|
# Note: wallet encryption results in additional keypool topup,
|
|
# so we can't compare new balance to balance_non_HD here,
|
|
# assert_equal(balance_non_HD, node.getbalance()) # won't work
|
|
assert balance_non_HD != node.getbalance()
|
|
node.keypoolrefill(4)
|
|
node.rescanblockchain()
|
|
# All coins should be recovered
|
|
assert_equal(balance_after, node.getbalance())
|
|
|
|
|
|
if __name__ == '__main__':
|
|
WalletUpgradeToHDTest().main ()
|