@@ -170,5 +170,101 @@ def run_test(self):
170
170
assert_raises_rpc_error (- 5 , "Already have this key" , self .nodes [1 ].sethdseed , False , new_seed )
171
171
assert_raises_rpc_error (- 5 , "Already have this key" , self .nodes [1 ].sethdseed , False , self .nodes [1 ].dumpprivkey (self .nodes [1 ].getnewaddress ()))
172
172
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
+
173
269
if __name__ == '__main__' :
174
270
WalletHDTest ().main ()
0 commit comments