aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWladimir J. van der Laan <laanwj@gmail.com>2017-05-23 16:38:19 +0200
committerWladimir J. van der Laan <laanwj@gmail.com>2017-05-23 16:39:19 +0200
commite76a3927c3b0a6d6a0fc84ef9144540ebecd1bf2 (patch)
tree792a075ff2e64ed0d8fca628cb305ef3c289be1e
parente4775167cb4b15e6a37290d27009386efb1e5e97 (diff)
parent2a8e35a11d4bd4828631654fc7b8b8fe8f0a2460 (diff)
downloadbitcoin-e76a3927c3b0a6d6a0fc84ef9144540ebecd1bf2.tar.xz
Merge #10410: Fix importwallet edge case rescan bug
2a8e35a Fix importwallet edge case rescan bug (Russell Yanofsky) Tree-SHA512: 59522c962290f9ef64436349d11183dd1fd829e515d1f5ec802b63dd813d04303e28d4f3ba38df77a6c151ee4c14f3ca5d3d82204c57456ac94054de62ae4bc7
-rw-r--r--src/wallet/rpcdump.cpp9
-rw-r--r--src/wallet/test/wallet_tests.cpp62
2 files changed, 65 insertions, 6 deletions
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index 82708dab26..d46cf69efb 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -536,14 +536,11 @@ UniValue importwallet(const JSONRPCRequest& request)
}
file.close();
pwallet->ShowProgress("", 100); // hide progress dialog in GUI
-
- CBlockIndex *pindex = chainActive.Tip();
- while (pindex && pindex->pprev && pindex->GetBlockTime() > nTimeBegin - TIMESTAMP_WINDOW)
- pindex = pindex->pprev;
-
pwallet->UpdateTimeFirstKey(nTimeBegin);
- LogPrintf("Rescanning last %i blocks\n", chainActive.Height() - pindex->nHeight + 1);
+ CBlockIndex *pindex = chainActive.FindEarliestAtLeast(nTimeBegin - TIMESTAMP_WINDOW);
+
+ LogPrintf("Rescanning last %i blocks\n", pindex ? chainActive.Height() - pindex->nHeight + 1 : 0);
pwallet->ScanForWalletTransactions(pindex);
pwallet->MarkDirty();
diff --git a/src/wallet/test/wallet_tests.cpp b/src/wallet/test/wallet_tests.cpp
index 8eeba72a06..b077d152d9 100644
--- a/src/wallet/test/wallet_tests.cpp
+++ b/src/wallet/test/wallet_tests.cpp
@@ -19,6 +19,8 @@
#include <univalue.h>
extern UniValue importmulti(const JSONRPCRequest& request);
+extern UniValue dumpwallet(const JSONRPCRequest& request);
+extern UniValue importwallet(const JSONRPCRequest& request);
// how many times to run all the tests to have a chance to catch errors that only show up with particular random shuffles
#define RUN_TESTS 100
@@ -437,6 +439,66 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
}
}
+// Verify importwallet RPC starts rescan at earliest block with timestamp
+// greater or equal than key birthday. Previously there was a bug where
+// importwallet RPC would start the scan at the latest block with timestamp less
+// than or equal to key birthday.
+BOOST_FIXTURE_TEST_CASE(importwallet_rescan, TestChain100Setup)
+{
+ CWallet *pwalletMainBackup = ::pwalletMain;
+ LOCK(cs_main);
+
+ // Create two blocks with same timestamp to verify that importwallet rescan
+ // will pick up both blocks, not just the first.
+ const int64_t BLOCK_TIME = chainActive.Tip()->GetBlockTimeMax() + 5;
+ SetMockTime(BLOCK_TIME);
+ coinbaseTxns.emplace_back(*CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]);
+ coinbaseTxns.emplace_back(*CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]);
+
+ // Set key birthday to block time increased by the timestamp window, so
+ // rescan will start at the block time.
+ const int64_t KEY_TIME = BLOCK_TIME + TIMESTAMP_WINDOW;
+ SetMockTime(KEY_TIME);
+ coinbaseTxns.emplace_back(*CreateAndProcessBlock({}, GetScriptForRawPubKey(coinbaseKey.GetPubKey())).vtx[0]);
+
+ // Import key into wallet and call dumpwallet to create backup file.
+ {
+ CWallet wallet;
+ LOCK(wallet.cs_wallet);
+ wallet.mapKeyMetadata[coinbaseKey.GetPubKey().GetID()].nCreateTime = KEY_TIME;
+ wallet.AddKeyPubKey(coinbaseKey, coinbaseKey.GetPubKey());
+
+ JSONRPCRequest request;
+ request.params.setArray();
+ request.params.push_back("wallet.backup");
+ ::pwalletMain = &wallet;
+ ::dumpwallet(request);
+ }
+
+ // Call importwallet RPC and verify all blocks with timestamps >= BLOCK_TIME
+ // were scanned, and no prior blocks were scanned.
+ {
+ CWallet wallet;
+
+ JSONRPCRequest request;
+ request.params.setArray();
+ request.params.push_back("wallet.backup");
+ ::pwalletMain = &wallet;
+ ::importwallet(request);
+
+ BOOST_CHECK_EQUAL(wallet.mapWallet.size(), 3);
+ BOOST_CHECK_EQUAL(coinbaseTxns.size(), 103);
+ for (size_t i = 0; i < coinbaseTxns.size(); ++i) {
+ bool found = wallet.GetWalletTx(coinbaseTxns[i].GetHash());
+ bool expected = i >= 100;
+ BOOST_CHECK_EQUAL(found, expected);
+ }
+ }
+
+ SetMockTime(0);
+ ::pwalletMain = pwalletMainBackup;
+}
+
// Check that GetImmatureCredit() returns a newly calculated value instead of
// the cached value after a MarkDirty() call.
//