|
19 | 19 | #include <univalue.h>
|
20 | 20 |
|
21 | 21 | extern UniValue importmulti(const JSONRPCRequest& request);
|
| 22 | +extern UniValue dumpwallet(const JSONRPCRequest& request); |
| 23 | +extern UniValue importwallet(const JSONRPCRequest& request); |
22 | 24 |
|
23 | 25 | // how many times to run all the tests to have a chance to catch errors that only show up with particular random shuffles
|
24 | 26 | #define RUN_TESTS 100
|
@@ -437,6 +439,66 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
|
437 | 439 | }
|
438 | 440 | }
|
439 | 441 |
|
| 442 | +// Verify importwallet RPC starts rescan at earliest block with timestamp |
| 443 | +// greater or equal than key birthday. Previously there was a bug where |
| 444 | +// importwallet RPC would start the scan at the latest block with timestamp less |
| 445 | +// than or equal to key birthday. |
| 446 | +BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup) |
| 447 | +{ |
| 448 | + CWallet *pwalletMainBackup = ::pwalletMain; |
| 449 | + LOCK(cs_main); |
| 450 | + |
| 451 | + // Create two blocks with same timestamp to verify that importwallet rescan |
| 452 | + // will pick up both blocks, not just the first. |
| 453 | + const int64_t BLOCK_TIME = chainActive.Tip()->GetBlockTimeMax() + 5; |
| 454 | + SetMockTime(BLOCK_TIME); |
| 455 | + coinbaseTxns.emplace_back(*CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]); |
| 456 | + coinbaseTxns.emplace_back(*CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]); |
| 457 | + |
| 458 | + // Set key birthday to block time increased by the timestamp window, so |
| 459 | + // rescan will start at the block time. |
| 460 | + const int64_t KEY_TIME = BLOCK_TIME + TIMESTAMP_WINDOW; |
| 461 | + SetMockTime(KEY_TIME); |
| 462 | + coinbaseTxns.emplace_back(*CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]); |
| 463 | + |
| 464 | + // Import key into wallet and call dumpwallet to create backup file. |
| 465 | + { |
| 466 | + CWallet wallet; |
| 467 | + LOCK(wallet.cs_wallet); |
| 468 | + wallet.mapKeyMetadata[coinbaseKey.GetPubKey().GetID()].nCreateTime = KEY_TIME; |
| 469 | + wallet.AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey()); |
| 470 | + |
| 471 | + JSONRPCRequest request; |
| 472 | + request.params.setArray(); |
| 473 | + request.params.push_back("wallet.backup"); |
| 474 | + ::pwalletMain = &wallet; |
| 475 | + ::dumpwallet(request); |
| 476 | + } |
| 477 | + |
| 478 | + // Call importwallet RPC and verify all blocks with timestamps >= BLOCK_TIME |
| 479 | + // were scanned, and no prior blocks were scanned. |
| 480 | + { |
| 481 | + CWallet wallet; |
| 482 | + |
| 483 | + JSONRPCRequest request; |
| 484 | + request.params.setArray(); |
| 485 | + request.params.push_back("wallet.backup"); |
| 486 | + ::pwalletMain = &wallet; |
| 487 | + ::importwallet(request); |
| 488 | + |
| 489 | + BOOST_CHECK_EQUAL(wallet.mapWallet.size(), 3); |
| 490 | + BOOST_CHECK_EQUAL(coinbaseTxns.size(), 103); |
| 491 | + for (size_t i = 0; i < coinbaseTxns.size(); ++i) { |
| 492 | + bool found = wallet.GetWalletTx(coinbaseTxns[i].GetHash()); |
| 493 | + bool expected = i >= 100; |
| 494 | + BOOST_CHECK_EQUAL(found, expected); |
| 495 | + } |
| 496 | + } |
| 497 | + |
| 498 | + SetMockTime(0); |
| 499 | + ::pwalletMain = pwalletMainBackup; |
| 500 | +} |
| 501 | + |
440 | 502 | // Check that GetImmatureCredit() returns a newly calculated value instead of
|
441 | 503 | // the cached value after a MarkDirty() call.
|
442 | 504 | //
|
|
0 commit comments