Browse Source

[Wallet] add rescanblockchain <start_height> <stop_height> RPC command

0.16
Jonas Schnelli 9 years ago
parent
commit
c77170fbdb
No known key found for this signature in database
GPG Key ID: 1EB776BB03C7922D
  1. 2
      src/qt/test/wallettests.cpp
  2. 2
      src/rpc/client.cpp
  3. 77
      src/wallet/rpcwallet.cpp
  4. 6
      src/wallet/test/wallet_tests.cpp
  5. 16
      src/wallet/wallet.cpp
  6. 2
      src/wallet/wallet.h

2
src/qt/test/wallettests.cpp

@ -157,7 +157,7 @@ void TestSendCoins()
wallet.SetAddressBook(test.coinbaseKey.GetPubKey().GetID(), "", "receive"); wallet.SetAddressBook(test.coinbaseKey.GetPubKey().GetID(), "", "receive");
wallet.AddKeyPubKey(test.coinbaseKey, test.coinbaseKey.GetPubKey()); wallet.AddKeyPubKey(test.coinbaseKey, test.coinbaseKey.GetPubKey());
} }
wallet.ScanForWalletTransactions(chainActive.Genesis(), true); wallet.ScanForWalletTransactions(chainActive.Genesis(), nullptr, true);
wallet.SetBroadcastTransactions(true); wallet.SetBroadcastTransactions(true);
// Create widgets for sending coins and listing transactions. // Create widgets for sending coins and listing transactions.

2
src/rpc/client.cpp

@ -140,6 +140,8 @@ static const CRPCConvertParam vRPCConvertParams[] =
{ "echojson", 7, "arg7" }, { "echojson", 7, "arg7" },
{ "echojson", 8, "arg8" }, { "echojson", 8, "arg8" },
{ "echojson", 9, "arg9" }, { "echojson", 9, "arg9" },
{ "rescanblockchain", 0, "start_height"},
{ "rescanblockchain", 1, "stop_height"},
}; };
class CRPCConvertTable class CRPCConvertTable

77
src/wallet/rpcwallet.cpp

@ -3169,6 +3169,81 @@ UniValue generate(const JSONRPCRequest& request)
return generateBlocks(coinbase_script, num_generate, max_tries, true); return generateBlocks(coinbase_script, num_generate, max_tries, true);
} }
UniValue rescanblockchain(const JSONRPCRequest& request)
{
CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}
if (request.fHelp || request.params.size() > 2) {
throw std::runtime_error(
"rescanblockchain (\"start_height\") (\"stop_height\")\n"
"\nRescan the local blockchain for wallet related transactions.\n"
"\nArguments:\n"
"1. \"start_height\" (numeric, optional) block height where the rescan should start\n"
"2. \"stop_height\" (numeric, optional) the last block height that should be scanned\n"
"\nResult:\n"
"{\n"
" \"start_height\" (numeric) The block height where the rescan has started. If omitted, rescan started from the genesis block.\n"
" \"stop_height\" (numeric) The height of the last rescanned block. If omitted, rescan stopped at the chain tip.\n"
"}\n"
"\nExamples:\n"
+ HelpExampleCli("rescanblockchain", "100000 120000")
+ HelpExampleRpc("rescanblockchain", "100000 120000")
);
}
LOCK2(cs_main, pwallet->cs_wallet);
CBlockIndex *pindexStart = chainActive.Genesis();
CBlockIndex *pindexStop = nullptr;
if (!request.params[0].isNull()) {
pindexStart = chainActive[request.params[0].get_int()];
if (!pindexStart) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid start_height");
}
}
if (!request.params[1].isNull()) {
pindexStop = chainActive[request.params[1].get_int()];
if (!pindexStop) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid stop_height");
}
else if (pindexStop->nHeight < pindexStart->nHeight) {
throw JSONRPCError(RPC_INVALID_PARAMETER, "stop_height must be greater then start_height");
}
}
// We can't rescan beyond non-pruned blocks, stop and throw an error
if (fPruneMode) {
CBlockIndex *block = pindexStop ? pindexStop : chainActive.Tip();
while (block && block->nHeight >= pindexStart->nHeight) {
if (!(block->nStatus & BLOCK_HAVE_DATA)) {
throw JSONRPCError(RPC_MISC_ERROR, "Can't rescan beyond pruned data. Use RPC call getblockchaininfo to determine your pruned height.");
}
block = block->pprev;
}
}
CBlockIndex *stopBlock = pwallet->ScanForWalletTransactions(pindexStart, pindexStop, true);
if (!stopBlock) {
if (pwallet->IsAbortingRescan()) {
throw JSONRPCError(RPC_MISC_ERROR, "Rescan aborted.");
}
// if we got a nullptr returned, ScanForWalletTransactions did rescan up to the requested stopindex
stopBlock = pindexStop ? pindexStop : chainActive.Tip();
}
else {
throw JSONRPCError(RPC_MISC_ERROR, "Rescan failed. Potentially corrupted data files.");
}
UniValue response(UniValue::VOBJ);
response.pushKV("start_height", pindexStart->nHeight);
response.pushKV("stop_height", stopBlock->nHeight);
return response;
}
extern UniValue abortrescan(const JSONRPCRequest& request); // in rpcdump.cpp extern UniValue abortrescan(const JSONRPCRequest& request); // in rpcdump.cpp
extern UniValue dumpprivkey(const JSONRPCRequest& request); // in rpcdump.cpp extern UniValue dumpprivkey(const JSONRPCRequest& request); // in rpcdump.cpp
extern UniValue importprivkey(const JSONRPCRequest& request); extern UniValue importprivkey(const JSONRPCRequest& request);
@ -3179,6 +3254,7 @@ extern UniValue importwallet(const JSONRPCRequest& request);
extern UniValue importprunedfunds(const JSONRPCRequest& request); extern UniValue importprunedfunds(const JSONRPCRequest& request);
extern UniValue removeprunedfunds(const JSONRPCRequest& request); extern UniValue removeprunedfunds(const JSONRPCRequest& request);
extern UniValue importmulti(const JSONRPCRequest& request); extern UniValue importmulti(const JSONRPCRequest& request);
extern UniValue rescanblockchain(const JSONRPCRequest& request);
static const CRPCCommand commands[] = static const CRPCCommand commands[] =
{ // category name actor (function) argNames { // category name actor (function) argNames
@ -3233,6 +3309,7 @@ static const CRPCCommand commands[] =
{ "wallet", "walletpassphrasechange", &walletpassphrasechange, {"oldpassphrase","newpassphrase"} }, { "wallet", "walletpassphrasechange", &walletpassphrasechange, {"oldpassphrase","newpassphrase"} },
{ "wallet", "walletpassphrase", &walletpassphrase, {"passphrase","timeout"} }, { "wallet", "walletpassphrase", &walletpassphrase, {"passphrase","timeout"} },
{ "wallet", "removeprunedfunds", &removeprunedfunds, {"txid"} }, { "wallet", "removeprunedfunds", &removeprunedfunds, {"txid"} },
{ "wallet", "rescanblockchain", &rescanblockchain, {"start_height", "stop_height"} },
{ "generating", "generate", &generate, {"nblocks","maxtries"} }, { "generating", "generate", &generate, {"nblocks","maxtries"} },
}; };

6
src/wallet/test/wallet_tests.cpp

@ -386,7 +386,7 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
{ {
CWallet wallet; CWallet wallet;
AddKey(wallet, coinbaseKey); AddKey(wallet, coinbaseKey);
BOOST_CHECK_EQUAL(nullBlock, wallet.ScanForWalletTransactions(oldTip)); BOOST_CHECK_EQUAL(nullBlock, wallet.ScanForWalletTransactions(oldTip, nullptr));
BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 100 * COIN); BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 100 * COIN);
} }
@ -399,7 +399,7 @@ BOOST_FIXTURE_TEST_CASE(rescan, TestChain100Setup)
{ {
CWallet wallet; CWallet wallet;
AddKey(wallet, coinbaseKey); AddKey(wallet, coinbaseKey);
BOOST_CHECK_EQUAL(oldTip, wallet.ScanForWalletTransactions(oldTip)); BOOST_CHECK_EQUAL(oldTip, wallet.ScanForWalletTransactions(oldTip, nullptr));
BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 50 * COIN); BOOST_CHECK_EQUAL(wallet.GetImmatureBalance(), 50 * COIN);
} }
@ -604,7 +604,7 @@ public:
bool firstRun; bool firstRun;
wallet->LoadWallet(firstRun); wallet->LoadWallet(firstRun);
AddKey(*wallet, coinbaseKey); AddKey(*wallet, coinbaseKey);
wallet->ScanForWalletTransactions(chainActive.Genesis()); wallet->ScanForWalletTransactions(chainActive.Genesis(), nullptr);
} }
~ListCoinsTestingSetup() ~ListCoinsTestingSetup()

16
src/wallet/wallet.cpp

@ -1539,7 +1539,7 @@ int64_t CWallet::RescanFromTime(int64_t startTime, bool update)
LogPrintf("%s: Rescanning last %i blocks\n", __func__, startBlock ? chainActive.Height() - startBlock->nHeight + 1 : 0); LogPrintf("%s: Rescanning last %i blocks\n", __func__, startBlock ? chainActive.Height() - startBlock->nHeight + 1 : 0);
if (startBlock) { if (startBlock) {
const CBlockIndex* const failedBlock = ScanForWalletTransactions(startBlock, update); const CBlockIndex* const failedBlock = ScanForWalletTransactions(startBlock, nullptr, update);
if (failedBlock) { if (failedBlock) {
return failedBlock->GetBlockTimeMax() + TIMESTAMP_WINDOW + 1; return failedBlock->GetBlockTimeMax() + TIMESTAMP_WINDOW + 1;
} }
@ -1555,12 +1555,19 @@ int64_t CWallet::RescanFromTime(int64_t startTime, bool update)
* Returns null if scan was successful. Otherwise, if a complete rescan was not * Returns null if scan was successful. Otherwise, if a complete rescan was not
* possible (due to pruning or corruption), returns pointer to the most recent * possible (due to pruning or corruption), returns pointer to the most recent
* block that could not be scanned. * block that could not be scanned.
*
* If pindexStop is not a nullptr, the scan will stop at the block-index
* defined by pindexStop
*/ */
CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate) CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, CBlockIndex* pindexStop, bool fUpdate)
{ {
int64_t nNow = GetTime(); int64_t nNow = GetTime();
const CChainParams& chainParams = Params(); const CChainParams& chainParams = Params();
if (pindexStop) {
assert(pindexStop->nHeight >= pindexStart->nHeight);
}
CBlockIndex* pindex = pindexStart; CBlockIndex* pindex = pindexStart;
CBlockIndex* ret = nullptr; CBlockIndex* ret = nullptr;
{ {
@ -1588,6 +1595,9 @@ CBlockIndex* CWallet::ScanForWalletTransactions(CBlockIndex* pindexStart, bool f
} else { } else {
ret = pindex; ret = pindex;
} }
if (pindex == pindexStop) {
break;
}
pindex = chainActive.Next(pindex); pindex = chainActive.Next(pindex);
} }
if (pindex && fAbortRescan) { if (pindex && fAbortRescan) {
@ -3903,7 +3913,7 @@ CWallet* CWallet::CreateWalletFromFile(const std::string walletFile)
} }
nStart = GetTimeMillis(); nStart = GetTimeMillis();
walletInstance->ScanForWalletTransactions(pindexRescan, true); walletInstance->ScanForWalletTransactions(pindexRescan, nullptr, true);
LogPrintf(" rescan %15dms\n", GetTimeMillis() - nStart); LogPrintf(" rescan %15dms\n", GetTimeMillis() - nStart);
walletInstance->SetBestChain(chainActive.GetLocator()); walletInstance->SetBestChain(chainActive.GetLocator());
walletInstance->dbw->IncrementUpdateCounter(); walletInstance->dbw->IncrementUpdateCounter();

2
src/wallet/wallet.h

@ -919,7 +919,7 @@ public:
void BlockDisconnected(const std::shared_ptr<const CBlock>& pblock) override; void BlockDisconnected(const std::shared_ptr<const CBlock>& pblock) override;
bool AddToWalletIfInvolvingMe(const CTransactionRef& tx, const CBlockIndex* pIndex, int posInBlock, bool fUpdate); bool AddToWalletIfInvolvingMe(const CTransactionRef& tx, const CBlockIndex* pIndex, int posInBlock, bool fUpdate);
int64_t RescanFromTime(int64_t startTime, bool update); int64_t RescanFromTime(int64_t startTime, bool update);
CBlockIndex* ScanForWalletTransactions(CBlockIndex* pindexStart, bool fUpdate = false); CBlockIndex* ScanForWalletTransactions(CBlockIndex* pindexStart, CBlockIndex* pindexStop, bool fUpdate = false);
void ReacceptWalletTransactions(); void ReacceptWalletTransactions();
void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) override; void ResendWalletTransactions(int64_t nBestBlockTime, CConnman* connman) override;
// ResendWalletTransactionsBefore may only be called if fBroadcastTransactions! // ResendWalletTransactionsBefore may only be called if fBroadcastTransactions!

Loading…
Cancel
Save