diff options
Diffstat (limited to 'src/wallet/rpcdump.cpp')
-rw-r--r-- | src/wallet/rpcdump.cpp | 351 |
1 files changed, 199 insertions, 152 deletions
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index 20a3cbda1e..82708dab26 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -16,6 +16,8 @@ #include "merkleblock.h" #include "core_io.h" +#include "rpcwallet.h" + #include <fstream> #include <stdint.h> @@ -27,11 +29,6 @@ #include <boost/assign/list_of.hpp> #include <boost/foreach.hpp> -using namespace std; - -void EnsureWalletIsUnlocked(); -bool EnsureWalletIsAvailable(bool avoidException); - std::string static EncodeDumpTime(int64_t nTime) { return DateTimeStrFormat("%Y-%m-%dT%H:%M:%SZ", nTime); } @@ -77,11 +74,13 @@ std::string DecodeDumpString(const std::string &str) { UniValue importprivkey(const JSONRPCRequest& request) { - if (!EnsureWalletIsAvailable(request.fHelp)) + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; - + } + if (request.fHelp || request.params.size() < 1 || request.params.size() > 3) - throw runtime_error( + throw std::runtime_error( "importprivkey \"bitcoinprivkey\" ( \"label\" ) ( rescan )\n" "\nAdds a private key (as returned by dumpprivkey) to your wallet.\n" "\nArguments:\n" @@ -96,17 +95,19 @@ UniValue importprivkey(const JSONRPCRequest& request) + HelpExampleCli("importprivkey", "\"mykey\"") + "\nImport using a label and without rescan\n" + HelpExampleCli("importprivkey", "\"mykey\" \"testing\" false") + + "\nImport using default blank label and without rescan\n" + + HelpExampleCli("importprivkey", "\"mykey\" \"\" false") + "\nAs a JSON-RPC call\n" + HelpExampleRpc("importprivkey", "\"mykey\", \"testing\", false") ); - LOCK2(cs_main, pwalletMain->cs_wallet); + LOCK2(cs_main, pwallet->cs_wallet); - EnsureWalletIsUnlocked(); + EnsureWalletIsUnlocked(pwallet); - string strSecret = request.params[0].get_str(); - string strLabel = ""; + std::string strSecret = request.params[0].get_str(); + std::string strLabel = ""; if (request.params.size() > 1) strLabel = request.params[1].get_str(); @@ -130,68 +131,100 @@ UniValue importprivkey(const JSONRPCRequest& request) assert(key.VerifyPubKey(pubkey)); CKeyID vchAddress = pubkey.GetID(); { - pwalletMain->MarkDirty(); - pwalletMain->SetAddressBook(vchAddress, strLabel, "receive"); + pwallet->MarkDirty(); + pwallet->SetAddressBook(vchAddress, strLabel, "receive"); // Don't throw error in case a key is already there - if (pwalletMain->HaveKey(vchAddress)) + if (pwallet->HaveKey(vchAddress)) { return NullUniValue; + } - pwalletMain->mapKeyMetadata[vchAddress].nCreateTime = 1; + pwallet->mapKeyMetadata[vchAddress].nCreateTime = 1; - if (!pwalletMain->AddKeyPubKey(key, pubkey)) + if (!pwallet->AddKeyPubKey(key, pubkey)) { throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet"); + } // whenever a key is imported, we need to scan the whole chain - pwalletMain->UpdateTimeFirstKey(1); + pwallet->UpdateTimeFirstKey(1); if (fRescan) { - pwalletMain->ScanForWalletTransactions(chainActive.Genesis(), true); + pwallet->ScanForWalletTransactions(chainActive.Genesis(), true); } } return NullUniValue; } -void ImportAddress(const CBitcoinAddress& address, const string& strLabel); -void ImportScript(const CScript& script, const string& strLabel, bool isRedeemScript) +UniValue abortrescan(const JSONRPCRequest& request) { - if (!isRedeemScript && ::IsMine(*pwalletMain, script) == ISMINE_SPENDABLE) + CWallet* const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { + return NullUniValue; + } + + if (request.fHelp || request.params.size() > 0) + throw std::runtime_error( + "abortrescan\n" + "\nStops current wallet rescan triggered e.g. by an importprivkey call.\n" + "\nExamples:\n" + "\nImport a private key\n" + + HelpExampleCli("importprivkey", "\"mykey\"") + + "\nAbort the running wallet rescan\n" + + HelpExampleCli("abortrescan", "") + + "\nAs a JSON-RPC call\n" + + HelpExampleRpc("abortrescan", "") + ); + + if (!pwallet->IsScanning() || pwallet->IsAbortingRescan()) return false; + pwallet->AbortRescan(); + return true; +} + +void ImportAddress(CWallet*, const CBitcoinAddress& address, const std::string& strLabel); +void ImportScript(CWallet* const pwallet, const CScript& script, const std::string& strLabel, bool isRedeemScript) +{ + if (!isRedeemScript && ::IsMine(*pwallet, script) == ISMINE_SPENDABLE) { throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script"); + } - pwalletMain->MarkDirty(); + pwallet->MarkDirty(); - if (!pwalletMain->HaveWatchOnly(script) && !pwalletMain->AddWatchOnly(script, 0 /* nCreateTime */)) + if (!pwallet->HaveWatchOnly(script) && !pwallet->AddWatchOnly(script, 0 /* nCreateTime */)) { throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet"); + } if (isRedeemScript) { - if (!pwalletMain->HaveCScript(script) && !pwalletMain->AddCScript(script)) + if (!pwallet->HaveCScript(script) && !pwallet->AddCScript(script)) { throw JSONRPCError(RPC_WALLET_ERROR, "Error adding p2sh redeemScript to wallet"); - ImportAddress(CBitcoinAddress(CScriptID(script)), strLabel); + } + ImportAddress(pwallet, CBitcoinAddress(CScriptID(script)), strLabel); } else { CTxDestination destination; if (ExtractDestination(script, destination)) { - pwalletMain->SetAddressBook(destination, strLabel, "receive"); + pwallet->SetAddressBook(destination, strLabel, "receive"); } } } -void ImportAddress(const CBitcoinAddress& address, const string& strLabel) +void ImportAddress(CWallet* const pwallet, const CBitcoinAddress& address, const std::string& strLabel) { CScript script = GetScriptForDestination(address.Get()); - ImportScript(script, strLabel, false); + ImportScript(pwallet, script, strLabel, false); // add to address book or update label if (address.IsValid()) - pwalletMain->SetAddressBook(address.Get(), strLabel, "receive"); + pwallet->SetAddressBook(address.Get(), strLabel, "receive"); } UniValue importaddress(const JSONRPCRequest& request) { - if (!EnsureWalletIsAvailable(request.fHelp)) + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; - + } + if (request.fHelp || request.params.size() < 1 || request.params.size() > 4) - throw runtime_error( + throw std::runtime_error( "importaddress \"address\" ( \"label\" rescan p2sh )\n" "\nAdds a script (in hex) or address that can be watched as if it were in your wallet but cannot be used to spend.\n" "\nArguments:\n" @@ -213,7 +246,7 @@ UniValue importaddress(const JSONRPCRequest& request) ); - string strLabel = ""; + std::string strLabel = ""; if (request.params.size() > 1) strLabel = request.params[1].get_str(); @@ -230,24 +263,24 @@ UniValue importaddress(const JSONRPCRequest& request) if (request.params.size() > 3) fP2SH = request.params[3].get_bool(); - LOCK2(cs_main, pwalletMain->cs_wallet); + LOCK2(cs_main, pwallet->cs_wallet); CBitcoinAddress address(request.params[0].get_str()); if (address.IsValid()) { if (fP2SH) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Cannot use the p2sh flag with an address - use a script instead"); - ImportAddress(address, strLabel); + ImportAddress(pwallet, address, strLabel); } else if (IsHex(request.params[0].get_str())) { std::vector<unsigned char> data(ParseHex(request.params[0].get_str())); - ImportScript(CScript(data.begin(), data.end()), strLabel, fP2SH); + ImportScript(pwallet, CScript(data.begin(), data.end()), strLabel, fP2SH); } else { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address or script"); } if (fRescan) { - pwalletMain->ScanForWalletTransactions(chainActive.Genesis(), true); - pwalletMain->ReacceptWalletTransactions(); + pwallet->ScanForWalletTransactions(chainActive.Genesis(), true); + pwallet->ReacceptWalletTransactions(); } return NullUniValue; @@ -255,11 +288,13 @@ UniValue importaddress(const JSONRPCRequest& request) UniValue importprunedfunds(const JSONRPCRequest& request) { - if (!EnsureWalletIsAvailable(request.fHelp)) + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; + } if (request.fHelp || request.params.size() != 2) - throw runtime_error( + throw std::runtime_error( "importprunedfunds\n" "\nImports funds without rescan. Corresponding address or script must previously be included in wallet. Aimed towards pruned wallets. The end-user is responsible to import additional transactions that subsequently spend the imported outputs or rescan after the point in the blockchain the transaction is included.\n" "\nArguments:\n" @@ -271,15 +306,15 @@ UniValue importprunedfunds(const JSONRPCRequest& request) if (!DecodeHexTx(tx, request.params[0].get_str())) throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); uint256 hashTx = tx.GetHash(); - CWalletTx wtx(pwalletMain, MakeTransactionRef(std::move(tx))); + CWalletTx wtx(pwallet, MakeTransactionRef(std::move(tx))); CDataStream ssMB(ParseHexV(request.params[1], "proof"), SER_NETWORK, PROTOCOL_VERSION); CMerkleBlock merkleBlock; ssMB >> merkleBlock; //Search partial merkle tree in proof for our transaction and index in valid block - vector<uint256> vMatch; - vector<unsigned int> vIndex; + std::vector<uint256> vMatch; + std::vector<unsigned int> vIndex; unsigned int txnIndex = 0; if (merkleBlock.txn.ExtractMatches(vMatch, vIndex) == merkleBlock.header.hashMerkleRoot) { @@ -288,7 +323,7 @@ UniValue importprunedfunds(const JSONRPCRequest& request) if (!mapBlockIndex.count(merkleBlock.header.GetHash()) || !chainActive.Contains(mapBlockIndex[merkleBlock.header.GetHash()])) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found in chain"); - vector<uint256>::const_iterator it; + std::vector<uint256>::const_iterator it; if ((it = std::find(vMatch.begin(), vMatch.end(), hashTx))==vMatch.end()) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction given doesn't exist in proof"); } @@ -302,10 +337,10 @@ UniValue importprunedfunds(const JSONRPCRequest& request) wtx.nIndex = txnIndex; wtx.hashBlock = merkleBlock.header.GetHash(); - LOCK2(cs_main, pwalletMain->cs_wallet); + LOCK2(cs_main, pwallet->cs_wallet); - if (pwalletMain->IsMine(wtx)) { - pwalletMain->AddToWallet(wtx, false); + if (pwallet->IsMine(wtx)) { + pwallet->AddToWallet(wtx, false); return NullUniValue; } @@ -314,11 +349,13 @@ UniValue importprunedfunds(const JSONRPCRequest& request) UniValue removeprunedfunds(const JSONRPCRequest& request) { - if (!EnsureWalletIsAvailable(request.fHelp)) + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; + } if (request.fHelp || request.params.size() != 1) - throw runtime_error( + 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" "\nArguments:\n" @@ -329,20 +366,20 @@ UniValue removeprunedfunds(const JSONRPCRequest& request) + HelpExampleRpc("removprunedfunds", "\"a8d0c0184dde994a09ec054286f1ce581bebf46446a512166eae7628734ea0a5\"") ); - LOCK2(cs_main, pwalletMain->cs_wallet); + LOCK2(cs_main, pwallet->cs_wallet); uint256 hash; hash.SetHex(request.params[0].get_str()); - vector<uint256> vHash; + std::vector<uint256> vHash; vHash.push_back(hash); - vector<uint256> vHashOut; + std::vector<uint256> vHashOut; - if(pwalletMain->ZapSelectTx(vHash, vHashOut) != DB_LOAD_OK) { - throw JSONRPCError(RPC_INTERNAL_ERROR, "Could not properly delete the transaction."); + if (pwallet->ZapSelectTx(vHash, vHashOut) != DB_LOAD_OK) { + throw JSONRPCError(RPC_WALLET_ERROR, "Could not properly delete the transaction."); } if(vHashOut.empty()) { - throw JSONRPCError(RPC_INTERNAL_ERROR, "Transaction does not exist in wallet."); + throw JSONRPCError(RPC_INVALID_PARAMETER, "Transaction does not exist in wallet."); } return NullUniValue; @@ -350,11 +387,13 @@ UniValue removeprunedfunds(const JSONRPCRequest& request) UniValue importpubkey(const JSONRPCRequest& request) { - if (!EnsureWalletIsAvailable(request.fHelp)) + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; + } if (request.fHelp || request.params.size() < 1 || request.params.size() > 4) - throw runtime_error( + throw std::runtime_error( "importpubkey \"pubkey\" ( \"label\" rescan )\n" "\nAdds a public key (in hex) that can be watched as if it were in your wallet but cannot be used to spend.\n" "\nArguments:\n" @@ -372,7 +411,7 @@ UniValue importpubkey(const JSONRPCRequest& request) ); - string strLabel = ""; + std::string strLabel = ""; if (request.params.size() > 1) strLabel = request.params[1].get_str(); @@ -391,15 +430,15 @@ UniValue importpubkey(const JSONRPCRequest& request) if (!pubKey.IsFullyValid()) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey is not a valid public key"); - LOCK2(cs_main, pwalletMain->cs_wallet); + LOCK2(cs_main, pwallet->cs_wallet); - ImportAddress(CBitcoinAddress(pubKey.GetID()), strLabel); - ImportScript(GetScriptForRawPubKey(pubKey), strLabel, false); + ImportAddress(pwallet, CBitcoinAddress(pubKey.GetID()), strLabel); + ImportScript(pwallet, GetScriptForRawPubKey(pubKey), strLabel, false); if (fRescan) { - pwalletMain->ScanForWalletTransactions(chainActive.Genesis(), true); - pwalletMain->ReacceptWalletTransactions(); + pwallet->ScanForWalletTransactions(chainActive.Genesis(), true); + pwallet->ReacceptWalletTransactions(); } return NullUniValue; @@ -408,11 +447,13 @@ UniValue importpubkey(const JSONRPCRequest& request) UniValue importwallet(const JSONRPCRequest& request) { - if (!EnsureWalletIsAvailable(request.fHelp)) + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; - + } + if (request.fHelp || request.params.size() != 1) - throw runtime_error( + throw std::runtime_error( "importwallet \"filename\"\n" "\nImports keys from a wallet dump file (see dumpwallet).\n" "\nArguments:\n" @@ -429,11 +470,11 @@ UniValue importwallet(const JSONRPCRequest& request) if (fPruneMode) throw JSONRPCError(RPC_WALLET_ERROR, "Importing wallets is disabled in pruned mode"); - LOCK2(cs_main, pwalletMain->cs_wallet); + LOCK2(cs_main, pwallet->cs_wallet); - EnsureWalletIsUnlocked(); + EnsureWalletIsUnlocked(pwallet); - ifstream file; + std::ifstream file; file.open(request.params[0].get_str().c_str(), std::ios::in | std::ios::ate); if (!file.is_open()) throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file"); @@ -445,9 +486,9 @@ UniValue importwallet(const JSONRPCRequest& request) int64_t nFilesize = std::max((int64_t)1, (int64_t)file.tellg()); file.seekg(0, file.beg); - pwalletMain->ShowProgress(_("Importing..."), 0); // show progress dialog in GUI + pwallet->ShowProgress(_("Importing..."), 0); // show progress dialog in GUI while (file.good()) { - pwalletMain->ShowProgress("", std::max(1, std::min(99, (int)(((double)file.tellg() / (double)nFilesize) * 100)))); + pwallet->ShowProgress("", std::max(1, std::min(99, (int)(((double)file.tellg() / (double)nFilesize) * 100)))); std::string line; std::getline(file, line); if (line.empty() || line[0] == '#') @@ -464,7 +505,7 @@ UniValue importwallet(const JSONRPCRequest& request) CPubKey pubkey = key.GetPubKey(); assert(key.VerifyPubKey(pubkey)); CKeyID keyid = pubkey.GetID(); - if (pwalletMain->HaveKey(keyid)) { + if (pwallet->HaveKey(keyid)) { LogPrintf("Skipping import of %s (key already present)\n", CBitcoinAddress(keyid).ToString()); continue; } @@ -484,27 +525,27 @@ UniValue importwallet(const JSONRPCRequest& request) } } LogPrintf("Importing %s...\n", CBitcoinAddress(keyid).ToString()); - if (!pwalletMain->AddKeyPubKey(key, pubkey)) { + if (!pwallet->AddKeyPubKey(key, pubkey)) { fGood = false; continue; } - pwalletMain->mapKeyMetadata[keyid].nCreateTime = nTime; + pwallet->mapKeyMetadata[keyid].nCreateTime = nTime; if (fLabel) - pwalletMain->SetAddressBook(keyid, strLabel, "receive"); + pwallet->SetAddressBook(keyid, strLabel, "receive"); nTimeBegin = std::min(nTimeBegin, nTime); } file.close(); - pwalletMain->ShowProgress("", 100); // hide progress dialog in GUI + pwallet->ShowProgress("", 100); // hide progress dialog in GUI CBlockIndex *pindex = chainActive.Tip(); - while (pindex && pindex->pprev && pindex->GetBlockTime() > nTimeBegin - 7200) + while (pindex && pindex->pprev && pindex->GetBlockTime() > nTimeBegin - TIMESTAMP_WINDOW) pindex = pindex->pprev; - pwalletMain->UpdateTimeFirstKey(nTimeBegin); + pwallet->UpdateTimeFirstKey(nTimeBegin); LogPrintf("Rescanning last %i blocks\n", chainActive.Height() - pindex->nHeight + 1); - pwalletMain->ScanForWalletTransactions(pindex); - pwalletMain->MarkDirty(); + pwallet->ScanForWalletTransactions(pindex); + pwallet->MarkDirty(); if (!fGood) throw JSONRPCError(RPC_WALLET_ERROR, "Error adding some keys to wallet"); @@ -514,11 +555,13 @@ UniValue importwallet(const JSONRPCRequest& request) UniValue dumpprivkey(const JSONRPCRequest& request) { - if (!EnsureWalletIsAvailable(request.fHelp)) + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; - + } + if (request.fHelp || request.params.size() != 1) - throw runtime_error( + throw std::runtime_error( "dumpprivkey \"address\"\n" "\nReveals the private key corresponding to 'address'.\n" "Then the importprivkey can be used with this output\n" @@ -532,11 +575,11 @@ UniValue dumpprivkey(const JSONRPCRequest& request) + HelpExampleRpc("dumpprivkey", "\"myaddress\"") ); - LOCK2(cs_main, pwalletMain->cs_wallet); + LOCK2(cs_main, pwallet->cs_wallet); - EnsureWalletIsUnlocked(); + EnsureWalletIsUnlocked(pwallet); - string strAddress = request.params[0].get_str(); + std::string strAddress = request.params[0].get_str(); CBitcoinAddress address; if (!address.SetString(strAddress)) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address"); @@ -544,19 +587,22 @@ UniValue dumpprivkey(const JSONRPCRequest& request) if (!address.GetKeyID(keyID)) throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to a key"); CKey vchSecret; - if (!pwalletMain->GetKey(keyID, vchSecret)) + if (!pwallet->GetKey(keyID, vchSecret)) { throw JSONRPCError(RPC_WALLET_ERROR, "Private key for address " + strAddress + " is not known"); + } return CBitcoinSecret(vchSecret).ToString(); } UniValue dumpwallet(const JSONRPCRequest& request) { - if (!EnsureWalletIsAvailable(request.fHelp)) + CWallet * const pwallet = GetWalletForJSONRPCRequest(request); + if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) { return NullUniValue; - + } + if (request.fHelp || request.params.size() != 1) - throw runtime_error( + throw std::runtime_error( "dumpwallet \"filename\"\n" "\nDumps all wallet keys in a human-readable format.\n" "\nArguments:\n" @@ -566,19 +612,19 @@ UniValue dumpwallet(const JSONRPCRequest& request) + HelpExampleRpc("dumpwallet", "\"test\"") ); - LOCK2(cs_main, pwalletMain->cs_wallet); + LOCK2(cs_main, pwallet->cs_wallet); - EnsureWalletIsUnlocked(); + EnsureWalletIsUnlocked(pwallet); - ofstream file; + std::ofstream file; file.open(request.params[0].get_str().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; - pwalletMain->GetKeyBirthTimes(mapKeyBirth); - pwalletMain->GetAllReserveKeys(setKeyPool); + pwallet->GetKeyBirthTimes(mapKeyBirth); + pwallet->GetAllReserveKeys(setKeyPool); // sort time/key pairs std::vector<std::pair<int64_t, CKeyID> > vKeyBirth; @@ -598,12 +644,11 @@ UniValue dumpwallet(const JSONRPCRequest& request) file << "\n"; // add the base58check encoded extended master if the wallet uses HD - CKeyID masterKeyID = pwalletMain->GetHDChain().masterKeyID; + CKeyID masterKeyID = pwallet->GetHDChain().masterKeyID; if (!masterKeyID.IsNull()) { CKey key; - if (pwalletMain->GetKey(masterKeyID, key)) - { + if (pwallet->GetKey(masterKeyID, key)) { CExtKey masterKey; masterKey.SetMaster(key.begin(), key.size()); @@ -618,20 +663,20 @@ UniValue dumpwallet(const JSONRPCRequest& request) std::string strTime = EncodeDumpTime(it->first); std::string strAddr = CBitcoinAddress(keyid).ToString(); CKey key; - if (pwalletMain->GetKey(keyid, key)) { + if (pwallet->GetKey(keyid, key)) { file << strprintf("%s %s ", CBitcoinSecret(key).ToString(), strTime); - if (pwalletMain->mapAddressBook.count(keyid)) { - file << strprintf("label=%s", EncodeDumpString(pwalletMain->mapAddressBook[keyid].name)); + if (pwallet->mapAddressBook.count(keyid)) { + file << strprintf("label=%s", EncodeDumpString(pwallet->mapAddressBook[keyid].name)); } else if (keyid == masterKeyID) { file << "hdmaster=1"; } else if (setKeyPool.count(keyid)) { file << "reserve=1"; - } else if (pwalletMain->mapKeyMetadata[keyid].hdKeypath == "m") { + } else if (pwallet->mapKeyMetadata[keyid].hdKeypath == "m") { file << "inactivehdmaster=1"; } else { file << "change=1"; } - file << strprintf(" # addr=%s%s\n", strAddr, (pwalletMain->mapKeyMetadata[keyid].hdKeypath.size() > 0 ? " hdkeypath="+pwalletMain->mapKeyMetadata[keyid].hdKeypath : "")); + file << strprintf(" # addr=%s%s\n", strAddr, (pwallet->mapKeyMetadata[keyid].hdKeypath.size() > 0 ? " hdkeypath="+pwallet->mapKeyMetadata[keyid].hdKeypath : "")); } } file << "\n"; @@ -641,7 +686,7 @@ UniValue dumpwallet(const JSONRPCRequest& request) } -UniValue ProcessImport(const UniValue& data, const int64_t timestamp) +UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int64_t timestamp) { try { bool success = false; @@ -655,16 +700,16 @@ UniValue ProcessImport(const UniValue& data, const int64_t timestamp) } // Optional fields. - const string& strRedeemScript = data.exists("redeemscript") ? data["redeemscript"].get_str() : ""; + const std::string& strRedeemScript = data.exists("redeemscript") ? data["redeemscript"].get_str() : ""; const UniValue& pubKeys = data.exists("pubkeys") ? data["pubkeys"].get_array() : UniValue(); const UniValue& keys = data.exists("keys") ? data["keys"].get_array() : UniValue(); const bool& internal = data.exists("internal") ? data["internal"].get_bool() : false; const bool& watchOnly = data.exists("watchonly") ? data["watchonly"].get_bool() : false; - const string& label = data.exists("label") && !internal ? data["label"].get_str() : ""; + const std::string& label = data.exists("label") && !internal ? data["label"].get_str() : ""; bool isScript = scriptPubKey.getType() == UniValue::VSTR; bool isP2SH = strRedeemScript.length() > 0; - const string& output = isScript ? scriptPubKey.get_str() : scriptPubKey["address"].get_str(); + const std::string& output = isScript ? scriptPubKey.get_str() : scriptPubKey["address"].get_str(); // Parse the output. CScript script; @@ -723,38 +768,38 @@ UniValue ProcessImport(const UniValue& data, const int64_t timestamp) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid P2SH address / script"); } - pwalletMain->MarkDirty(); + pwallet->MarkDirty(); - if (!pwalletMain->HaveWatchOnly(redeemScript) && !pwalletMain->AddWatchOnly(redeemScript, timestamp)) { + if (!pwallet->AddWatchOnly(redeemScript, timestamp)) { throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet"); } - if (!pwalletMain->HaveCScript(redeemScript) && !pwalletMain->AddCScript(redeemScript)) { + if (!pwallet->HaveCScript(redeemScript) && !pwallet->AddCScript(redeemScript)) { throw JSONRPCError(RPC_WALLET_ERROR, "Error adding p2sh redeemScript to wallet"); } CBitcoinAddress redeemAddress = CBitcoinAddress(CScriptID(redeemScript)); CScript redeemDestination = GetScriptForDestination(redeemAddress.Get()); - if (::IsMine(*pwalletMain, redeemDestination) == ISMINE_SPENDABLE) { + if (::IsMine(*pwallet, redeemDestination) == ISMINE_SPENDABLE) { throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script"); } - pwalletMain->MarkDirty(); + pwallet->MarkDirty(); - if (!pwalletMain->HaveWatchOnly(redeemDestination) && !pwalletMain->AddWatchOnly(redeemDestination, timestamp)) { + if (!pwallet->AddWatchOnly(redeemDestination, timestamp)) { throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet"); } // add to address book or update label if (address.IsValid()) { - pwalletMain->SetAddressBook(address.Get(), label, "receive"); + pwallet->SetAddressBook(address.Get(), label, "receive"); } // Import private keys. if (keys.size()) { for (size_t i = 0; i < keys.size(); i++) { - const string& privkey = keys[i].get_str(); + const std::string& privkey = keys[i].get_str(); CBitcoinSecret vchSecret; bool fGood = vchSecret.SetString(privkey); @@ -773,20 +818,20 @@ UniValue ProcessImport(const UniValue& data, const int64_t timestamp) assert(key.VerifyPubKey(pubkey)); CKeyID vchAddress = pubkey.GetID(); - pwalletMain->MarkDirty(); - pwalletMain->SetAddressBook(vchAddress, label, "receive"); + pwallet->MarkDirty(); + pwallet->SetAddressBook(vchAddress, label, "receive"); - if (pwalletMain->HaveKey(vchAddress)) { + if (pwallet->HaveKey(vchAddress)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Already have this key"); } - pwalletMain->mapKeyMetadata[vchAddress].nCreateTime = timestamp; + pwallet->mapKeyMetadata[vchAddress].nCreateTime = timestamp; - if (!pwalletMain->AddKeyPubKey(key, pubkey)) { + if (!pwallet->AddKeyPubKey(key, pubkey)) { throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet"); } - pwalletMain->UpdateTimeFirstKey(timestamp); + pwallet->UpdateTimeFirstKey(timestamp); } } @@ -794,7 +839,7 @@ UniValue ProcessImport(const UniValue& data, const int64_t timestamp) } else { // Import public keys. if (pubKeys.size() && keys.size() == 0) { - const string& strPubKey = pubKeys[0].get_str(); + const std::string& strPubKey = pubKeys[0].get_str(); if (!IsHex(strPubKey)) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey must be a hex string"); @@ -829,31 +874,31 @@ UniValue ProcessImport(const UniValue& data, const int64_t timestamp) CScript pubKeyScript = GetScriptForDestination(pubKeyAddress.Get()); - if (::IsMine(*pwalletMain, pubKeyScript) == ISMINE_SPENDABLE) { + if (::IsMine(*pwallet, pubKeyScript) == ISMINE_SPENDABLE) { throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script"); } - pwalletMain->MarkDirty(); + pwallet->MarkDirty(); - if (!pwalletMain->HaveWatchOnly(pubKeyScript) && !pwalletMain->AddWatchOnly(pubKeyScript, timestamp)) { + if (!pwallet->AddWatchOnly(pubKeyScript, timestamp)) { throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet"); } // add to address book or update label if (pubKeyAddress.IsValid()) { - pwalletMain->SetAddressBook(pubKeyAddress.Get(), label, "receive"); + pwallet->SetAddressBook(pubKeyAddress.Get(), label, "receive"); } // TODO Is this necessary? CScript scriptRawPubKey = GetScriptForRawPubKey(pubKey); - if (::IsMine(*pwalletMain, scriptRawPubKey) == ISMINE_SPENDABLE) { + if (::IsMine(*pwallet, scriptRawPubKey) == ISMINE_SPENDABLE) { throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script"); } - pwalletMain->MarkDirty(); + pwallet->MarkDirty(); - if (!pwalletMain->HaveWatchOnly(scriptRawPubKey) && !pwalletMain->AddWatchOnly(scriptRawPubKey, timestamp)) { + if (!pwallet->AddWatchOnly(scriptRawPubKey, timestamp)) { throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet"); } @@ -862,7 +907,7 @@ UniValue ProcessImport(const UniValue& data, const int64_t timestamp) // Import private keys. if (keys.size()) { - const string& strPrivkey = keys[0].get_str(); + const std::string& strPrivkey = keys[0].get_str(); // Checks. CBitcoinSecret vchSecret; @@ -901,40 +946,40 @@ UniValue ProcessImport(const UniValue& data, const int64_t timestamp) } CKeyID vchAddress = pubKey.GetID(); - pwalletMain->MarkDirty(); - pwalletMain->SetAddressBook(vchAddress, label, "receive"); + pwallet->MarkDirty(); + pwallet->SetAddressBook(vchAddress, label, "receive"); - if (pwalletMain->HaveKey(vchAddress)) { + if (pwallet->HaveKey(vchAddress)) { return false; } - pwalletMain->mapKeyMetadata[vchAddress].nCreateTime = timestamp; + pwallet->mapKeyMetadata[vchAddress].nCreateTime = timestamp; - if (!pwalletMain->AddKeyPubKey(key, pubKey)) { + if (!pwallet->AddKeyPubKey(key, pubKey)) { throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet"); } - pwalletMain->UpdateTimeFirstKey(timestamp); + pwallet->UpdateTimeFirstKey(timestamp); success = true; } // Import scriptPubKey only. if (pubKeys.size() == 0 && keys.size() == 0) { - if (::IsMine(*pwalletMain, script) == ISMINE_SPENDABLE) { + if (::IsMine(*pwallet, script) == ISMINE_SPENDABLE) { throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script"); } - pwalletMain->MarkDirty(); + pwallet->MarkDirty(); - if (!pwalletMain->HaveWatchOnly(script) && !pwalletMain->AddWatchOnly(script, timestamp)) { + if (!pwallet->AddWatchOnly(script, timestamp)) { throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet"); } if (scriptPubKey.getType() == UniValue::VOBJ) { // add to address book or update label if (address.IsValid()) { - pwalletMain->SetAddressBook(address.Get(), label, "receive"); + pwallet->SetAddressBook(address.Get(), label, "receive"); } } @@ -974,9 +1019,14 @@ int64_t GetImportTimestamp(const UniValue& data, int64_t now) UniValue importmulti(const JSONRPCRequest& mainRequest) { + CWallet * const pwallet = GetWalletForJSONRPCRequest(mainRequest); + if (!EnsureWalletIsAvailable(pwallet, mainRequest.fHelp)) { + return NullUniValue; + } + // clang-format off if (mainRequest.fHelp || mainRequest.params.size() < 1 || mainRequest.params.size() > 2) - throw runtime_error( + throw std::runtime_error( "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" @@ -1012,9 +1062,6 @@ UniValue importmulti(const JSONRPCRequest& mainRequest) " [{ \"success\": true } , { \"success\": false, \"error\": { \"code\": -1, \"message\": \"Internal Server Error\"} }, ... ]\n"); // clang-format on - if (!EnsureWalletIsAvailable(mainRequest.fHelp)) { - return NullUniValue; - } RPCTypeCheck(mainRequest.params, boost::assign::list_of(UniValue::VARR)(UniValue::VOBJ)); @@ -1031,8 +1078,8 @@ UniValue importmulti(const JSONRPCRequest& mainRequest) } } - LOCK2(cs_main, pwalletMain->cs_wallet); - EnsureWalletIsUnlocked(); + LOCK2(cs_main, pwallet->cs_wallet); + EnsureWalletIsUnlocked(pwallet); // Verify all timestamps are present before importing any keys. const int64_t now = chainActive.Tip() ? chainActive.Tip()->GetMedianTimePast() : 0; @@ -1054,7 +1101,7 @@ UniValue importmulti(const JSONRPCRequest& mainRequest) BOOST_FOREACH (const UniValue& data, requests.getValues()) { const int64_t timestamp = std::max(GetImportTimestamp(data, now), minimumTimestamp); - const UniValue result = ProcessImport(data, timestamp); + const UniValue result = ProcessImport(pwallet, data, timestamp); response.push_back(result); if (!fRescan) { @@ -1073,11 +1120,11 @@ UniValue importmulti(const JSONRPCRequest& mainRequest) } if (fRescan && fRunScan && requests.size()) { - CBlockIndex* pindex = nLowestTimestamp > minimumTimestamp ? chainActive.FindEarliestAtLeast(std::max<int64_t>(nLowestTimestamp - 7200, 0)) : chainActive.Genesis(); + CBlockIndex* pindex = nLowestTimestamp > minimumTimestamp ? chainActive.FindEarliestAtLeast(std::max<int64_t>(nLowestTimestamp - TIMESTAMP_WINDOW, 0)) : chainActive.Genesis(); CBlockIndex* scannedRange = nullptr; if (pindex) { - scannedRange = pwalletMain->ScanForWalletTransactions(pindex, true); - pwalletMain->ReacceptWalletTransactions(); + scannedRange = pwallet->ScanForWalletTransactions(pindex, true); + pwallet->ReacceptWalletTransactions(); } if (!scannedRange || scannedRange->nHeight > pindex->nHeight) { @@ -1090,7 +1137,7 @@ 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) - 7200 >= scannedRange->GetBlockTimeMax() || results.at(i).exists("error")) { + if (GetImportTimestamp(request, now) - TIMESTAMP_WINDOW >= scannedRange->GetBlockTimeMax() || results.at(i).exists("error")) { response.push_back(results.at(i)); } else { UniValue result = UniValue(UniValue::VOBJ); |