diff options
Diffstat (limited to 'src/wallet/rpcdump.cpp')
-rw-r--r-- | src/wallet/rpcdump.cpp | 90 |
1 files changed, 50 insertions, 40 deletions
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index d46cf69efb..67c6d9ec64 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -26,8 +26,6 @@ #include <univalue.h> -#include <boost/assign/list_of.hpp> -#include <boost/foreach.hpp> std::string static EncodeDumpTime(int64_t nTime) { return DateTimeStrFormat("%Y-%m-%dT%H:%M:%SZ", nTime); @@ -48,7 +46,7 @@ int64_t static DecodeDumpTime(const std::string &str) { std::string static EncodeDumpString(const std::string &str) { std::stringstream ret; - BOOST_FOREACH(unsigned char c, str) { + for (unsigned char c : str) { if (c <= 32 || c >= 128 || c == '%') { ret << '%' << HexStr(&c, &c + 1); } else { @@ -108,12 +106,12 @@ UniValue importprivkey(const JSONRPCRequest& request) std::string strSecret = request.params[0].get_str(); std::string strLabel = ""; - if (request.params.size() > 1) + if (!request.params[1].isNull()) strLabel = request.params[1].get_str(); // Whether to perform rescan after import bool fRescan = true; - if (request.params.size() > 2) + if (!request.params[2].isNull()) fRescan = request.params[2].get_bool(); if (fRescan && fPruneMode) @@ -149,7 +147,7 @@ UniValue importprivkey(const JSONRPCRequest& request) pwallet->UpdateTimeFirstKey(1); if (fRescan) { - pwallet->ScanForWalletTransactions(chainActive.Genesis(), true); + pwallet->RescanFromTime(TIMESTAMP_MIN, true /* update */); } } @@ -247,12 +245,12 @@ UniValue importaddress(const JSONRPCRequest& request) std::string strLabel = ""; - if (request.params.size() > 1) + if (!request.params[1].isNull()) strLabel = request.params[1].get_str(); // Whether to perform rescan after import bool fRescan = true; - if (request.params.size() > 2) + if (!request.params[2].isNull()) fRescan = request.params[2].get_bool(); if (fRescan && fPruneMode) @@ -260,7 +258,7 @@ UniValue importaddress(const JSONRPCRequest& request) // Whether to import a p2sh version, too bool fP2SH = false; - if (request.params.size() > 3) + if (!request.params[3].isNull()) fP2SH = request.params[3].get_bool(); LOCK2(cs_main, pwallet->cs_wallet); @@ -279,7 +277,7 @@ UniValue importaddress(const JSONRPCRequest& request) if (fRescan) { - pwallet->ScanForWalletTransactions(chainActive.Genesis(), true); + pwallet->RescanFromTime(TIMESTAMP_MIN, true /* update */); pwallet->ReacceptWalletTransactions(); } @@ -357,13 +355,13 @@ UniValue removeprunedfunds(const JSONRPCRequest& request) if (request.fHelp || request.params.size() != 1) throw std::runtime_error( "removeprunedfunds \"txid\"\n" - "\nDeletes the specified transaction from the wallet. Meant for use with pruned wallets and as a companion to importprunedfunds. This will effect wallet balances.\n" + "\nDeletes the specified transaction from the wallet. Meant for use with pruned wallets and as a companion to importprunedfunds. This will affect wallet balances.\n" "\nArguments:\n" "1. \"txid\" (string, required) The hex-encoded id of the transaction you are deleting\n" "\nExamples:\n" + HelpExampleCli("removeprunedfunds", "\"a8d0c0184dde994a09ec054286f1ce581bebf46446a512166eae7628734ea0a5\"") + "\nAs a JSON-RPC call\n" - + HelpExampleRpc("removprunedfunds", "\"a8d0c0184dde994a09ec054286f1ce581bebf46446a512166eae7628734ea0a5\"") + + HelpExampleRpc("removeprunedfunds", "\"a8d0c0184dde994a09ec054286f1ce581bebf46446a512166eae7628734ea0a5\"") ); LOCK2(cs_main, pwallet->cs_wallet); @@ -412,12 +410,12 @@ UniValue importpubkey(const JSONRPCRequest& request) std::string strLabel = ""; - if (request.params.size() > 1) + if (!request.params[1].isNull()) strLabel = request.params[1].get_str(); // Whether to perform rescan after import bool fRescan = true; - if (request.params.size() > 2) + if (!request.params[2].isNull()) fRescan = request.params[2].get_bool(); if (fRescan && fPruneMode) @@ -437,7 +435,7 @@ UniValue importpubkey(const JSONRPCRequest& request) if (fRescan) { - pwallet->ScanForWalletTransactions(chainActive.Genesis(), true); + pwallet->RescanFromTime(TIMESTAMP_MIN, true /* update */); pwallet->ReacceptWalletTransactions(); } @@ -537,11 +535,7 @@ UniValue importwallet(const JSONRPCRequest& request) file.close(); pwallet->ShowProgress("", 100); // hide progress dialog in GUI pwallet->UpdateTimeFirstKey(nTimeBegin); - - CBlockIndex *pindex = chainActive.FindEarliestAtLeast(nTimeBegin - TIMESTAMP_WINDOW); - - LogPrintf("Rescanning last %i blocks\n", pindex ? chainActive.Height() - pindex->nHeight + 1 : 0); - pwallet->ScanForWalletTransactions(pindex); + pwallet->RescanFromTime(nTimeBegin, false /* update */); pwallet->MarkDirty(); if (!fGood) @@ -603,7 +597,11 @@ UniValue dumpwallet(const JSONRPCRequest& request) "dumpwallet \"filename\"\n" "\nDumps all wallet keys in a human-readable format.\n" "\nArguments:\n" - "1. \"filename\" (string, required) The filename\n" + "1. \"filename\" (string, required) The filename with path (either absolute or relative to bitcoind)\n" + "\nResult:\n" + "{ (json object)\n" + " \"filename\" : { (string) The filename with full absolute path\n" + "}\n" "\nExamples:\n" + HelpExampleCli("dumpwallet", "\"test\"") + HelpExampleRpc("dumpwallet", "\"test\"") @@ -614,14 +612,15 @@ UniValue dumpwallet(const JSONRPCRequest& request) EnsureWalletIsUnlocked(pwallet); std::ofstream file; - file.open(request.params[0].get_str().c_str()); + boost::filesystem::path filepath = request.params[0].get_str(); + filepath = boost::filesystem::absolute(filepath); + file.open(filepath.string().c_str()); if (!file.is_open()) throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file"); std::map<CTxDestination, int64_t> mapKeyBirth; - std::set<CKeyID> setKeyPool; + const std::map<CKeyID, int64_t>& mapKeyPool = pwallet->GetAllReserveKeys(); pwallet->GetKeyBirthTimes(mapKeyBirth); - pwallet->GetAllReserveKeys(setKeyPool); // sort time/key pairs std::vector<std::pair<int64_t, CKeyID> > vKeyBirth; @@ -666,7 +665,7 @@ UniValue dumpwallet(const JSONRPCRequest& request) file << strprintf("label=%s", EncodeDumpString(pwallet->mapAddressBook[keyid].name)); } else if (keyid == masterKeyID) { file << "hdmaster=1"; - } else if (setKeyPool.count(keyid)) { + } else if (mapKeyPool.count(keyid)) { file << "reserve=1"; } else if (pwallet->mapKeyMetadata[keyid].hdKeypath == "m") { file << "inactivehdmaster=1"; @@ -679,7 +678,11 @@ UniValue dumpwallet(const JSONRPCRequest& request) file << "\n"; file << "# End of dump\n"; file.close(); - return NullUniValue; + + UniValue reply(UniValue::VOBJ); + reply.push_back(Pair("filename", filepath.string())); + + return reply; } @@ -1024,7 +1027,7 @@ UniValue importmulti(const JSONRPCRequest& mainRequest) // clang-format off if (mainRequest.fHelp || mainRequest.params.size() < 1 || mainRequest.params.size() > 2) throw std::runtime_error( - "importmulti \"requests\" \"options\"\n\n" + "importmulti \"requests\" ( \"options\" )\n\n" "Import addresses/scripts (with private or public keys, redeem script (P2SH)), rescanning all addresses in one-shot-only (rescan can be disabled via options).\n\n" "Arguments:\n" "1. requests (array, required) Data to be imported\n" @@ -1040,7 +1043,7 @@ UniValue importmulti(const JSONRPCRequest& mainRequest) " \"redeemscript\": \"<script>\" , (string, optional) Allowed only if the scriptPubKey is a P2SH address or a P2SH scriptPubKey\n" " \"pubkeys\": [\"<pubKey>\", ... ] , (array, optional) Array of strings giving pubkeys that must occur in the output or redeemscript\n" " \"keys\": [\"<key>\", ... ] , (array, optional) Array of strings giving private keys whose corresponding public keys must occur in the output or redeemscript\n" - " \"internal\": <true> , (boolean, optional, default: false) Stating whether matching outputs should be be treated as not incoming payments\n" + " \"internal\": <true> , (boolean, optional, default: false) Stating whether matching outputs should be treated as not incoming payments\n" " \"watchonly\": <true> , (boolean, optional, default: false) Stating whether matching outputs should be considered watched even when they're not spendable, only allowed if keys are empty\n" " \"label\": <label> , (string, optional, default: '') Label to assign to the address (aka account name, for now), only allowed with internal=false\n" " }\n" @@ -1060,14 +1063,14 @@ UniValue importmulti(const JSONRPCRequest& mainRequest) // clang-format on - RPCTypeCheck(mainRequest.params, boost::assign::list_of(UniValue::VARR)(UniValue::VOBJ)); + RPCTypeCheck(mainRequest.params, {UniValue::VARR, UniValue::VOBJ}); const UniValue& requests = mainRequest.params[0]; //Default options bool fRescan = true; - if (mainRequest.params.size() > 1) { + if (!mainRequest.params[1].isNull()) { const UniValue& options = mainRequest.params[1]; if (options.exists("rescan")) { @@ -1096,7 +1099,7 @@ UniValue importmulti(const JSONRPCRequest& mainRequest) UniValue response(UniValue::VARR); - BOOST_FOREACH (const UniValue& data, requests.getValues()) { + for (const UniValue& data : requests.getValues()) { const int64_t timestamp = std::max(GetImportTimestamp(data, now), minimumTimestamp); const UniValue result = ProcessImport(pwallet, data, timestamp); response.push_back(result); @@ -1117,14 +1120,10 @@ UniValue importmulti(const JSONRPCRequest& mainRequest) } if (fRescan && fRunScan && requests.size()) { - CBlockIndex* pindex = nLowestTimestamp > minimumTimestamp ? chainActive.FindEarliestAtLeast(std::max<int64_t>(nLowestTimestamp - TIMESTAMP_WINDOW, 0)) : chainActive.Genesis(); - CBlockIndex* scannedRange = nullptr; - if (pindex) { - scannedRange = pwallet->ScanForWalletTransactions(pindex, true); - pwallet->ReacceptWalletTransactions(); - } + int64_t scannedTime = pwallet->RescanFromTime(nLowestTimestamp, true /* update */); + pwallet->ReacceptWalletTransactions(); - if (!scannedRange || scannedRange->nHeight > pindex->nHeight) { + if (scannedTime > nLowestTimestamp) { std::vector<UniValue> results = response.getValues(); response.clear(); response.setArray(); @@ -1134,12 +1133,23 @@ UniValue importmulti(const JSONRPCRequest& mainRequest) // range, or if the import result already has an error set, let // the result stand unmodified. Otherwise replace the result // with an error message. - if (GetImportTimestamp(request, now) - TIMESTAMP_WINDOW >= scannedRange->GetBlockTimeMax() || results.at(i).exists("error")) { + if (scannedTime <= GetImportTimestamp(request, now) || results.at(i).exists("error")) { response.push_back(results.at(i)); } else { UniValue result = UniValue(UniValue::VOBJ); result.pushKV("success", UniValue(false)); - result.pushKV("error", JSONRPCError(RPC_MISC_ERROR, strprintf("Failed to rescan before time %d, transactions may be missing.", scannedRange->GetBlockTimeMax()))); + result.pushKV( + "error", + JSONRPCError( + RPC_MISC_ERROR, + strprintf("Rescan failed for key with creation timestamp %d. There was an error reading a " + "block from time %d, which is after or within %d seconds of key creation, and " + "could contain transactions pertaining to the key. As a result, transactions " + "and coins using this key may not appear in the wallet. This error could be " + "caused by pruning or data corruption (see bitcoind log for details) and could " + "be dealt with by downloading and rescanning the relevant blocks (see -reindex " + "and -rescan options).", + GetImportTimestamp(request, now), scannedTime - TIMESTAMP_WINDOW - 1, TIMESTAMP_WINDOW))); response.push_back(std::move(result)); } ++i; |