Skip to content

Commit b1810a1

Browse files
committed
Test that keys from inactive seeds are generated
1 parent c93082e commit b1810a1

File tree

1 file changed

+96
-0
lines changed

1 file changed

+96
-0
lines changed

test/functional/wallet_hd.py

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,5 +170,101 @@ def run_test(self):
170170
assert_raises_rpc_error(-5, "Already have this key", self.nodes[1].sethdseed, False, new_seed)
171171
assert_raises_rpc_error(-5, "Already have this key", self.nodes[1].sethdseed, False, self.nodes[1].dumpprivkey(self.nodes[1].getnewaddress()))
172172

173+
self.log.info('Test sethdseed restoring with keys outside of the initial keypool')
174+
self.nodes[0].generate(10)
175+
# Restart node 1 with keypool of 3 and a different wallet
176+
self.nodes[1].createwallet(wallet_name='origin', blank=True)
177+
self.stop_node(1)
178+
self.start_node(1, extra_args=['-keypool=3', '-wallet=origin'])
179+
connect_nodes(self.nodes[0], 1)
180+
181+
# sethdseed restoring and seeing txs to addresses out of the keypool
182+
origin_rpc = self.nodes[1].get_wallet_rpc('origin')
183+
seed = self.nodes[0].dumpprivkey(self.nodes[0].getnewaddress())
184+
origin_rpc.sethdseed(True, seed)
185+
186+
self.nodes[1].createwallet(wallet_name='restore', blank=True)
187+
restore_rpc = self.nodes[1].get_wallet_rpc('restore')
188+
restore_rpc.sethdseed(True, seed) # Set to be the same seed as origin_rpc
189+
restore_rpc.sethdseed(True) # Rotate to a new seed, making original `seed` inactive
190+
191+
self.nodes[1].createwallet(wallet_name='restore2', blank=True)
192+
restore2_rpc = self.nodes[1].get_wallet_rpc('restore2')
193+
restore2_rpc.sethdseed(True, seed) # Set to be the same seed as origin_rpc
194+
restore2_rpc.sethdseed(True) # Rotate to a new seed, making original `seed` inactive
195+
196+
# Check persistence of inactive seed by reloading restore. restore2 is still loaded to test the case where the wallet is not reloaded
197+
restore_rpc.unloadwallet()
198+
self.nodes[1].loadwallet('restore')
199+
restore_rpc = self.nodes[1].get_wallet_rpc('restore')
200+
201+
# Empty origin keypool and get an address that is beyond the initial keypool
202+
origin_rpc.getnewaddress()
203+
origin_rpc.getnewaddress()
204+
last_addr = origin_rpc.getnewaddress() # Last address of initial keypool
205+
addr = origin_rpc.getnewaddress() # First address beyond initial keypool
206+
207+
# Check that the restored seed has last_addr but does not have addr
208+
info = restore_rpc.getaddressinfo(last_addr)
209+
assert_equal(info['ismine'], True)
210+
info = restore_rpc.getaddressinfo(addr)
211+
assert_equal(info['ismine'], False)
212+
info = restore2_rpc.getaddressinfo(last_addr)
213+
assert_equal(info['ismine'], True)
214+
info = restore2_rpc.getaddressinfo(addr)
215+
assert_equal(info['ismine'], False)
216+
# Check that the origin seed has addr
217+
info = origin_rpc.getaddressinfo(addr)
218+
assert_equal(info['ismine'], True)
219+
220+
# Send a transaction to addr, which is out of the initial keypool.
221+
# The wallet that has set a new seed (restore_rpc) should not detect this transaction.
222+
txid = self.nodes[0].sendtoaddress(addr, 1)
223+
origin_rpc.sendrawtransaction(self.nodes[0].gettransaction(txid)['hex'])
224+
self.nodes[0].generate(1)
225+
origin_rpc.gettransaction(txid)
226+
assert_raises_rpc_error(-5, 'Invalid or non-wallet transaction id', restore_rpc.gettransaction, txid)
227+
out_of_kp_txid = txid
228+
229+
# Send a transaction to last_addr, which is in the initial keypool.
230+
# The wallet that has set a new seed (restore_rpc) should detect this transaction and generate 3 new keys from the initial seed.
231+
# The previous transaction (out_of_kp_txid) should still not be detected as a rescan is required.
232+
txid = self.nodes[0].sendtoaddress(last_addr, 1)
233+
origin_rpc.sendrawtransaction(self.nodes[0].gettransaction(txid)['hex'])
234+
self.nodes[0].generate(1)
235+
origin_rpc.gettransaction(txid)
236+
restore_rpc.gettransaction(txid)
237+
assert_raises_rpc_error(-5, 'Invalid or non-wallet transaction id', restore_rpc.gettransaction, out_of_kp_txid)
238+
restore2_rpc.gettransaction(txid)
239+
assert_raises_rpc_error(-5, 'Invalid or non-wallet transaction id', restore2_rpc.gettransaction, out_of_kp_txid)
240+
241+
# After rescanning, restore_rpc should now see out_of_kp_txid and generate an additional key.
242+
# addr should now be part of restore_rpc and be ismine
243+
restore_rpc.rescanblockchain()
244+
restore_rpc.gettransaction(out_of_kp_txid)
245+
info = restore_rpc.getaddressinfo(addr)
246+
assert_equal(info['ismine'], True)
247+
restore2_rpc.rescanblockchain()
248+
restore2_rpc.gettransaction(out_of_kp_txid)
249+
info = restore2_rpc.getaddressinfo(addr)
250+
assert_equal(info['ismine'], True)
251+
252+
# Check again that 3 keys were derived.
253+
# Empty keypool and get an address that is beyond the initial keypool
254+
origin_rpc.getnewaddress()
255+
origin_rpc.getnewaddress()
256+
last_addr = origin_rpc.getnewaddress()
257+
addr = origin_rpc.getnewaddress()
258+
259+
# Check that the restored seed has last_addr but does not have addr
260+
info = restore_rpc.getaddressinfo(last_addr)
261+
assert_equal(info['ismine'], True)
262+
info = restore_rpc.getaddressinfo(addr)
263+
assert_equal(info['ismine'], False)
264+
info = restore2_rpc.getaddressinfo(last_addr)
265+
assert_equal(info['ismine'], True)
266+
info = restore2_rpc.getaddressinfo(addr)
267+
assert_equal(info['ismine'], False)
268+
173269
if __name__ == '__main__':
174270
WalletHDTest().main ()

0 commit comments

Comments
 (0)