Changeset View
Changeset View
Standalone View
Standalone View
test/functional/wallet_hd.py
Show First 20 Lines • Show All 147 Lines • ▼ Show 20 Lines | def run_test(self): | ||||
orig_masterkeyid = self.nodes[1].getwalletinfo()['hdseedid'] | orig_masterkeyid = self.nodes[1].getwalletinfo()['hdseedid'] | ||||
self.nodes[1].sethdseed() | self.nodes[1].sethdseed() | ||||
new_masterkeyid = self.nodes[1].getwalletinfo()['hdseedid'] | new_masterkeyid = self.nodes[1].getwalletinfo()['hdseedid'] | ||||
assert orig_masterkeyid != new_masterkeyid | assert orig_masterkeyid != new_masterkeyid | ||||
addr = self.nodes[1].getnewaddress() | addr = self.nodes[1].getnewaddress() | ||||
# Make sure the new address is the first from the keypool | # Make sure the new address is the first from the keypool | ||||
assert_equal(self.nodes[1].getaddressinfo( | assert_equal(self.nodes[1].getaddressinfo( | ||||
addr)['hdkeypath'], 'm/0\'/0\'/0\'') | addr)['hdkeypath'], 'm/0\'/0\'/0\'') | ||||
self.nodes[1].keypoolrefill(1) # Fill keypool with 1 key | # Fill keypool with 1 key | ||||
self.nodes[1].keypoolrefill(1) | |||||
# Set a new HD seed on node 1 without flushing the keypool | # Set a new HD seed on node 1 without flushing the keypool | ||||
new_seed = self.nodes[0].dumpprivkey(self.nodes[0].getnewaddress()) | new_seed = self.nodes[0].dumpprivkey(self.nodes[0].getnewaddress()) | ||||
orig_masterkeyid = new_masterkeyid | orig_masterkeyid = new_masterkeyid | ||||
self.nodes[1].sethdseed(False, new_seed) | self.nodes[1].sethdseed(False, new_seed) | ||||
new_masterkeyid = self.nodes[1].getwalletinfo()['hdseedid'] | new_masterkeyid = self.nodes[1].getwalletinfo()['hdseedid'] | ||||
assert orig_masterkeyid != new_masterkeyid | assert orig_masterkeyid != new_masterkeyid | ||||
addr = self.nodes[1].getnewaddress() | addr = self.nodes[1].getnewaddress() | ||||
Show All 22 Lines | def run_test(self): | ||||
self.nodes[1].sethdseed, "Not_bool") | self.nodes[1].sethdseed, "Not_bool") | ||||
assert_raises_rpc_error(-1, "JSON value is not a string as expected", | assert_raises_rpc_error(-1, "JSON value is not a string as expected", | ||||
self.nodes[1].sethdseed, False, True) | self.nodes[1].sethdseed, False, True) | ||||
assert_raises_rpc_error(-5, "Already have this key", | assert_raises_rpc_error(-5, "Already have this key", | ||||
self.nodes[1].sethdseed, False, new_seed) | self.nodes[1].sethdseed, False, new_seed) | ||||
assert_raises_rpc_error(-5, "Already have this key", | assert_raises_rpc_error(-5, "Already have this key", | ||||
self.nodes[1].sethdseed, False, self.nodes[1].dumpprivkey(self.nodes[1].getnewaddress())) | self.nodes[1].sethdseed, False, self.nodes[1].dumpprivkey(self.nodes[1].getnewaddress())) | ||||
self.log.info( | |||||
'Test sethdseed restoring with keys outside of the initial keypool') | |||||
self.nodes[0].generate(10) | |||||
# Restart node 1 with keypool of 3 and a different wallet | |||||
self.nodes[1].createwallet(wallet_name='origin', blank=True) | |||||
self.stop_node(1) | |||||
self.start_node(1, extra_args=['-keypool=3', '-wallet=origin']) | |||||
connect_nodes(self.nodes[0], self.nodes[1]) | |||||
# sethdseed restoring and seeing txs to addresses out of the | |||||
# keypool | |||||
origin_rpc = self.nodes[1].get_wallet_rpc('origin') | |||||
seed = self.nodes[0].dumpprivkey(self.nodes[0].getnewaddress()) | |||||
origin_rpc.sethdseed(True, seed) | |||||
self.nodes[1].createwallet(wallet_name='restore', blank=True) | |||||
restore_rpc = self.nodes[1].get_wallet_rpc('restore') | |||||
# Set to be the same seed as origin_rpc | |||||
restore_rpc.sethdseed(True, seed) | |||||
# Rotate to a new seed, making original `seed` inactive | |||||
restore_rpc.sethdseed(True) | |||||
self.nodes[1].createwallet(wallet_name='restore2', blank=True) | |||||
restore2_rpc = self.nodes[1].get_wallet_rpc('restore2') | |||||
# Set to be the same seed as origin_rpc | |||||
restore2_rpc.sethdseed(True, seed) | |||||
# Rotate to a new seed, making original `seed` inactive | |||||
restore2_rpc.sethdseed(True) | |||||
# Check persistence of inactive seed by reloading restore. restore2 | |||||
# is still loaded to test the case where the wallet is not reloaded | |||||
restore_rpc.unloadwallet() | |||||
self.nodes[1].loadwallet('restore') | |||||
restore_rpc = self.nodes[1].get_wallet_rpc('restore') | |||||
# Empty origin keypool and get an address that is beyond the | |||||
# initial keypool | |||||
origin_rpc.getnewaddress() | |||||
origin_rpc.getnewaddress() | |||||
# Last address of initial keypool | |||||
last_addr = origin_rpc.getnewaddress() | |||||
# First address beyond initial keypool | |||||
addr = origin_rpc.getnewaddress() | |||||
# Check that the restored seed has last_addr but does not have addr | |||||
info = restore_rpc.getaddressinfo(last_addr) | |||||
assert_equal(info['ismine'], True) | |||||
info = restore_rpc.getaddressinfo(addr) | |||||
assert_equal(info['ismine'], False) | |||||
info = restore2_rpc.getaddressinfo(last_addr) | |||||
assert_equal(info['ismine'], True) | |||||
info = restore2_rpc.getaddressinfo(addr) | |||||
assert_equal(info['ismine'], False) | |||||
# Check that the origin seed has addr | |||||
info = origin_rpc.getaddressinfo(addr) | |||||
assert_equal(info['ismine'], True) | |||||
# Send a transaction to addr, which is out of the initial keypool. | |||||
# The wallet that has set a new seed (restore_rpc) should not | |||||
# detect this transaction. | |||||
txid = self.nodes[0].sendtoaddress(addr, 1) | |||||
origin_rpc.sendrawtransaction( | |||||
self.nodes[0].gettransaction(txid)['hex']) | |||||
self.nodes[0].generate(1) | |||||
origin_rpc.gettransaction(txid) | |||||
assert_raises_rpc_error(-5, | |||||
'Invalid or non-wallet transaction id', | |||||
restore_rpc.gettransaction, | |||||
txid) | |||||
out_of_kp_txid = txid | |||||
# Send a transaction to last_addr, which is in the initial keypool. | |||||
# The wallet that has set a new seed (restore_rpc) should detect this | |||||
# transaction and generate 3 new keys from the initial seed. | |||||
# The previous transaction (out_of_kp_txid) should still not be | |||||
# detected as a rescan is required. | |||||
txid = self.nodes[0].sendtoaddress(last_addr, 1) | |||||
origin_rpc.sendrawtransaction( | |||||
self.nodes[0].gettransaction(txid)['hex']) | |||||
self.nodes[0].generate(1) | |||||
origin_rpc.gettransaction(txid) | |||||
restore_rpc.gettransaction(txid) | |||||
assert_raises_rpc_error(-5, | |||||
'Invalid or non-wallet transaction id', | |||||
restore_rpc.gettransaction, | |||||
out_of_kp_txid) | |||||
restore2_rpc.gettransaction(txid) | |||||
assert_raises_rpc_error(-5, | |||||
'Invalid or non-wallet transaction id', | |||||
restore2_rpc.gettransaction, | |||||
out_of_kp_txid) | |||||
# After rescanning, restore_rpc should now see out_of_kp_txid and generate an additional key. | |||||
# addr should now be part of restore_rpc and be ismine | |||||
restore_rpc.rescanblockchain() | |||||
restore_rpc.gettransaction(out_of_kp_txid) | |||||
info = restore_rpc.getaddressinfo(addr) | |||||
assert_equal(info['ismine'], True) | |||||
restore2_rpc.rescanblockchain() | |||||
restore2_rpc.gettransaction(out_of_kp_txid) | |||||
info = restore2_rpc.getaddressinfo(addr) | |||||
assert_equal(info['ismine'], True) | |||||
# Check again that 3 keys were derived. | |||||
# Empty keypool and get an address that is beyond the initial | |||||
# keypool | |||||
origin_rpc.getnewaddress() | |||||
origin_rpc.getnewaddress() | |||||
last_addr = origin_rpc.getnewaddress() | |||||
addr = origin_rpc.getnewaddress() | |||||
# Check that the restored seed has last_addr but does not have addr | |||||
info = restore_rpc.getaddressinfo(last_addr) | |||||
assert_equal(info['ismine'], True) | |||||
info = restore_rpc.getaddressinfo(addr) | |||||
assert_equal(info['ismine'], False) | |||||
info = restore2_rpc.getaddressinfo(last_addr) | |||||
assert_equal(info['ismine'], True) | |||||
info = restore2_rpc.getaddressinfo(addr) | |||||
assert_equal(info['ismine'], False) | |||||
if __name__ == '__main__': | if __name__ == '__main__': | ||||
WalletHDTest().main() | WalletHDTest().main() |