Dash Core  0.12.2.1
P2P Digital Currency
wallet-hd.py
Go to the documentation of this file.
1 #!/usr/bin/env python2
2 # coding=utf-8
3 # ^^^^^^^^^^^^ TODO remove when supporting only Python3
4 # Copyright (c) 2016 The Bitcoin Core developers
5 # Distributed under the MIT software license, see the accompanying
6 # file COPYING or http://www.opensource.org/licenses/mit-license.php.
7 """Test Hierarchical Deterministic wallet function."""
8 
9 from test_framework.test_framework import BitcoinTestFramework
10 from test_framework.util import *
11 
13 
14  def setup_chain(self):
15  print("Initializing test directory "+self.options.tmpdir)
16  initialize_chain_clean(self.options.tmpdir, 2)
17 
18  def setup_network(self):
19  self.nodes = start_nodes(2, self.options.tmpdir, [['-usehd=0'], ['-usehd=1', '-keypool=0']])
20  self.is_network_split = False
21  connect_nodes_bi(self.nodes, 0, 1)
22  self.is_network_split=False
23  self.sync_all()
24 
25  def run_test (self):
26  tmpdir = self.options.tmpdir
27 
28  # Make sure can't switch off usehd after wallet creation
29  stop_node(self.nodes[1],1)
30  try:
31  start_node(1, self.options.tmpdir, ['-usehd=0'])
32  raise AssertionError("Must not allow to turn off HD on an already existing HD wallet")
33  except Exception as e:
34  assert("dashd exited with status 1 during initialization" in str(e))
35  # assert_start_raises_init_error(1, self.options.tmpdir, ['-usehd=0'], 'already existing HD wallet')
36  # self.nodes[1] = start_node(1, self.options.tmpdir, self.node_args[1])
37  self.nodes[1] = start_node(1, self.options.tmpdir, ['-usehd=1', '-keypool=0'])
38  connect_nodes_bi(self.nodes, 0, 1)
39 
40  # Make sure we use hd, keep chainid
41  chainid = self.nodes[1].getwalletinfo()['hdchainid']
42  assert_equal(len(chainid), 64)
43 
44  # create an internal key
45  change_addr = self.nodes[1].getrawchangeaddress()
46  change_addrV= self.nodes[1].validateaddress(change_addr);
47  assert_equal(change_addrV["hdkeypath"], "m/44'/1'/0'/1/0") #first internal child key
48 
49  # Import a non-HD private key in the HD wallet
50  non_hd_add = self.nodes[0].getnewaddress()
51  self.nodes[1].importprivkey(self.nodes[0].dumpprivkey(non_hd_add))
52 
53  # This should be enough to keep the master key and the non-HD key
54  self.nodes[1].backupwallet(tmpdir + "/hd.bak")
55  #self.nodes[1].dumpwallet(tmpdir + "/hd.dump")
56 
57  # Derive some HD addresses and remember the last
58  # Also send funds to each add
59  self.nodes[0].generate(101)
60  hd_add = None
61  num_hd_adds = 300
62  for i in range(num_hd_adds):
63  hd_add = self.nodes[1].getnewaddress()
64  hd_info = self.nodes[1].validateaddress(hd_add)
65  assert_equal(hd_info["hdkeypath"], "m/44'/1'/0'/0/"+str(i+1))
66  assert_equal(hd_info["hdchainid"], chainid)
67  self.nodes[0].sendtoaddress(hd_add, 1)
68  self.nodes[0].generate(1)
69  self.nodes[0].sendtoaddress(non_hd_add, 1)
70  self.nodes[0].generate(1)
71 
72  # create an internal key (again)
73  change_addr = self.nodes[1].getrawchangeaddress()
74  change_addrV= self.nodes[1].validateaddress(change_addr);
75  assert_equal(change_addrV["hdkeypath"], "m/44'/1'/0'/1/1") #second internal child key
76 
77  self.sync_all()
78  assert_equal(self.nodes[1].getbalance(), num_hd_adds + 1)
79 
80  print("Restore backup ...")
81  stop_node(self.nodes[1],1)
82  os.remove(self.options.tmpdir + "/node1/regtest/wallet.dat")
83  shutil.copyfile(tmpdir + "/hd.bak", tmpdir + "/node1/regtest/wallet.dat")
84  self.nodes[1] = start_node(1, self.options.tmpdir, ['-usehd=1', '-keypool=0'])
85  #connect_nodes_bi(self.nodes, 0, 1)
86 
87  # Assert that derivation is deterministic
88  hd_add_2 = None
89  for _ in range(num_hd_adds):
90  hd_add_2 = self.nodes[1].getnewaddress()
91  hd_info_2 = self.nodes[1].validateaddress(hd_add_2)
92  assert_equal(hd_info_2["hdkeypath"], "m/44'/1'/0'/0/"+str(_+1))
93  assert_equal(hd_info_2["hdchainid"], chainid)
94  assert_equal(hd_add, hd_add_2)
95 
96  # Needs rescan
97  stop_node(self.nodes[1],1)
98  self.nodes[1] = start_node(1, self.options.tmpdir, ['-usehd=1', '-keypool=0', '-rescan'])
99  #connect_nodes_bi(self.nodes, 0, 1)
100  assert_equal(self.nodes[1].getbalance(), num_hd_adds + 1)
101 
102  # send a tx and make sure its using the internal chain for the changeoutput
103  txid = self.nodes[1].sendtoaddress(self.nodes[0].getnewaddress(), 1)
104  outs = self.nodes[1].decoderawtransaction(self.nodes[1].gettransaction(txid)['hex'])['vout'];
105  keypath = ""
106  for out in outs:
107  if out['value'] != 1:
108  keypath = self.nodes[1].validateaddress(out['scriptPubKey']['addresses'][0])['hdkeypath']
109 
110  assert_equal(keypath[0:13], "m/44'/1'/0'/1")
111 
112 if __name__ == '__main__':
113  WalletHDTest().main ()
UniValue importprivkey(const UniValue &params, bool fHelp)
Definition: rpcdump.cpp:76
UniValue getrawchangeaddress(const UniValue &params, bool fHelp)
Definition: rpcwallet.cpp:224
def setup_network(self)
Definition: wallet-hd.py:18
UniValue validateaddress(const UniValue &params, bool fHelp)
Definition: misc.cpp:270
UniValue dumpprivkey(const UniValue &params, bool fHelp)
Definition: rpcdump.cpp:546
UniValue getbalance(const UniValue &params, bool fHelp)
Definition: rpcwallet.cpp:792
def start_nodes(num_nodes, dirname, extra_args=None, rpchost=None, binary=None)
Definition: util.py:305
UniValue backupwallet(const UniValue &params, bool fHelp)
Definition: rpcwallet.cpp:1937
UniValue sendtoaddress(const UniValue &params, bool fHelp)
Definition: rpcwallet.cpp:409
UniValue getnewaddress(const UniValue &params, bool fHelp)
Definition: rpcwallet.cpp:113
def initialize_chain_clean(test_dir, num_nodes)
Definition: util.py:252
UniValue getwalletinfo(const UniValue &params, bool fHelp)
Definition: rpcwallet.cpp:2376
UniValue decoderawtransaction(const UniValue &params, bool fHelp)
def start_node(i, dirname, extra_args=None, rpchost=None, timewait=None, binary=None)
Definition: util.py:281
def stop_node(node, i)
Definition: util.py:323
UniValue generate(const UniValue &params, bool fHelp)
Definition: mining.cpp:122
def setup_chain(self)
Definition: wallet-hd.py:14
def assert_equal(thing1, thing2)
Definition: util.py:461
def connect_nodes_bi(nodes, a, b)
Definition: util.py:351
UniValue gettransaction(const UniValue &params, bool fHelp)
Definition: rpcwallet.cpp:1821