1#!/usr/bin/env python3 2# Copyright (c) 2016 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 6from test_framework.test_framework import BitcoinTestFramework 7from test_framework.util import (start_nodes, start_node, assert_equal, bitcoind_processes) 8 9 10def read_dump(file_name, addrs, hd_master_addr_old): 11 """ 12 Read the given dump, count the addrs that match, count change and reserve. 13 Also check that the old hd_master is inactive 14 """ 15 with open(file_name, encoding='utf8') as inputfile: 16 found_addr = 0 17 found_addr_chg = 0 18 found_addr_rsv = 0 19 hd_master_addr_ret = None 20 for line in inputfile: 21 # only read non comment lines 22 if line[0] != "#" and len(line) > 10: 23 # split out some data 24 key_label, comment = line.split("#") 25 # key = key_label.split(" ")[0] 26 keytype = key_label.split(" ")[2] 27 if len(comment) > 1: 28 addr_keypath = comment.split(" addr=")[1] 29 addr = addr_keypath.split(" ")[0] 30 keypath = None 31 if keytype == "inactivehdmaster=1": 32 # ensure the old master is still available 33 assert(hd_master_addr_old == addr) 34 elif keytype == "hdmaster=1": 35 # ensure we have generated a new hd master key 36 assert(hd_master_addr_old != addr) 37 hd_master_addr_ret = addr 38 else: 39 keypath = addr_keypath.rstrip().split("hdkeypath=")[1] 40 41 # count key types 42 for addrObj in addrs: 43 if addrObj['address'] == addr and addrObj['hdkeypath'] == keypath and keytype == "label=": 44 found_addr += 1 45 break 46 elif keytype == "change=1": 47 found_addr_chg += 1 48 break 49 elif keytype == "reserve=1": 50 found_addr_rsv += 1 51 break 52 return found_addr, found_addr_chg, found_addr_rsv, hd_master_addr_ret 53 54 55class WalletDumpTest(BitcoinTestFramework): 56 57 def __init__(self): 58 super().__init__() 59 self.setup_clean_chain = False 60 self.num_nodes = 1 61 self.extra_args = [["-keypool=90"]] 62 63 def setup_network(self, split=False): 64 # Use 1 minute timeout because the initial getnewaddress RPC can take 65 # longer than the default 30 seconds due to an expensive 66 # CWallet::TopUpKeyPool call, and the encryptwallet RPC made later in 67 # the test often takes even longer. 68 self.nodes = start_nodes(self.num_nodes, self.options.tmpdir, self.extra_args, timewait=60) 69 70 def run_test (self): 71 tmpdir = self.options.tmpdir 72 73 # generate 20 addresses to compare against the dump 74 test_addr_count = 20 75 addrs = [] 76 for i in range(0,test_addr_count): 77 addr = self.nodes[0].getnewaddress() 78 vaddr= self.nodes[0].validateaddress(addr) #required to get hd keypath 79 addrs.append(vaddr) 80 # Should be a no-op: 81 self.nodes[0].keypoolrefill() 82 83 # dump unencrypted wallet 84 self.nodes[0].dumpwallet(tmpdir + "/node0/wallet.unencrypted.dump") 85 86 found_addr, found_addr_chg, found_addr_rsv, hd_master_addr_unenc = \ 87 read_dump(tmpdir + "/node0/wallet.unencrypted.dump", addrs, None) 88 assert_equal(found_addr, test_addr_count) # all keys must be in the dump 89 assert_equal(found_addr_chg, 50) # 50 blocks where mined 90 assert_equal(found_addr_rsv, 90 + 1) # keypool size (TODO: fix off-by-one) 91 92 #encrypt wallet, restart, unlock and dump 93 self.nodes[0].encryptwallet('test') 94 bitcoind_processes[0].wait() 95 self.nodes[0] = start_node(0, self.options.tmpdir, self.extra_args[0]) 96 self.nodes[0].walletpassphrase('test', 10) 97 # Should be a no-op: 98 self.nodes[0].keypoolrefill() 99 self.nodes[0].dumpwallet(tmpdir + "/node0/wallet.encrypted.dump") 100 101 found_addr, found_addr_chg, found_addr_rsv, hd_master_addr_enc = \ 102 read_dump(tmpdir + "/node0/wallet.encrypted.dump", addrs, hd_master_addr_unenc) 103 assert_equal(found_addr, test_addr_count) 104 assert_equal(found_addr_chg, 90 + 1 + 50) # old reserve keys are marked as change now 105 assert_equal(found_addr_rsv, 90 + 1) # keypool size (TODO: fix off-by-one) 106 107if __name__ == '__main__': 108 WalletDumpTest().main () 109