Browse Source

Merge #8775: RPC refactoring: Access wallet using new GetWalletForJSONRPCRequest

d678771 Wallet: Sanitise -wallet parameter (Luke Dashjr)
9756be3 Wallet/RPC: Use filename rather than CWallet pointer, for lockwallet RPCRunLater job name (Luke Dashjr)
86be48a More tightly couple EnsureWalletIsAvailable with GetWalletForJSONRPCRequest where appropriate (Luke Dashjr)
a435632 Move wallet RPC declarations to rpcwallet.h (Luke Dashjr)
ad15734 RPC: Pass on JSONRPCRequest metadata (URI/user/etc) for "help" method (Luke Dashjr)
bf8a04a Reformat touched lines with C++11 (Luke Dashjr)
2e518e3 Move nWalletUnlockTime to CWallet::nRelockTime, and name timed task unique per CWallet (Luke Dashjr)
d77ad6d RPC: Do all wallet access through new GetWalletForJSONRPCRequest (Luke Dashjr)
eca550f RPC/Wallet: Pass CWallet as pointer to helper functions (Luke Dashjr)

Tree-SHA512: bfd592da841693390e16f83b451503eb5cedb71208089aa32b3fc45e973555584a3ed7696dd239f6409324464d565dacf0f3d0e36e8e13ae6a7843848465f960
0.15
Wladimir J. van der Laan 8 years ago
parent
commit
eb281842b7
No known key found for this signature in database
GPG Key ID: 74810B012346C9A6
  1. 66
      src/rpc/misc.cpp
  2. 16
      src/rpc/rawtransaction.cpp
  3. 11
      src/rpc/server.cpp
  4. 6
      src/rpc/server.h
  5. 3
      src/utilstrencodings.cpp
  6. 3
      src/utilstrencodings.h
  7. 248
      src/wallet/rpcdump.cpp
  8. 638
      src/wallet/rpcwallet.cpp
  9. 13
      src/wallet/rpcwallet.h
  10. 6
      src/wallet/wallet.cpp
  11. 3
      src/wallet/wallet.h

66
src/rpc/misc.cpp

@ -14,6 +14,7 @@
#include "util.h" #include "util.h"
#include "utilstrencodings.h" #include "utilstrencodings.h"
#ifdef ENABLE_WALLET #ifdef ENABLE_WALLET
#include "wallet/rpcwallet.h"
#include "wallet/wallet.h" #include "wallet/wallet.h"
#include "wallet/walletdb.h" #include "wallet/walletdb.h"
#endif #endif
@ -70,7 +71,9 @@ UniValue getinfo(const JSONRPCRequest& request)
); );
#ifdef ENABLE_WALLET #ifdef ENABLE_WALLET
LOCK2(cs_main, pwalletMain ? &pwalletMain->cs_wallet : NULL); CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);
#else #else
LOCK(cs_main); LOCK(cs_main);
#endif #endif
@ -82,9 +85,9 @@ UniValue getinfo(const JSONRPCRequest& request)
obj.push_back(Pair("version", CLIENT_VERSION)); obj.push_back(Pair("version", CLIENT_VERSION));
obj.push_back(Pair("protocolversion", PROTOCOL_VERSION)); obj.push_back(Pair("protocolversion", PROTOCOL_VERSION));
#ifdef ENABLE_WALLET #ifdef ENABLE_WALLET
if (pwalletMain) { if (pwallet) {
obj.push_back(Pair("walletversion", pwalletMain->GetVersion())); obj.push_back(Pair("walletversion", pwallet->GetVersion()));
obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance()))); obj.push_back(Pair("balance", ValueFromAmount(pwallet->GetBalance())));
} }
#endif #endif
obj.push_back(Pair("blocks", (int)chainActive.Height())); obj.push_back(Pair("blocks", (int)chainActive.Height()));
@ -95,12 +98,13 @@ UniValue getinfo(const JSONRPCRequest& request)
obj.push_back(Pair("difficulty", (double)GetDifficulty())); obj.push_back(Pair("difficulty", (double)GetDifficulty()));
obj.push_back(Pair("testnet", Params().NetworkIDString() == CBaseChainParams::TESTNET)); obj.push_back(Pair("testnet", Params().NetworkIDString() == CBaseChainParams::TESTNET));
#ifdef ENABLE_WALLET #ifdef ENABLE_WALLET
if (pwalletMain) { if (pwallet) {
obj.push_back(Pair("keypoololdest", pwalletMain->GetOldestKeyPoolTime())); obj.push_back(Pair("keypoololdest", pwallet->GetOldestKeyPoolTime()));
obj.push_back(Pair("keypoolsize", (int)pwalletMain->GetKeyPoolSize())); obj.push_back(Pair("keypoolsize", (int)pwallet->GetKeyPoolSize()));
}
if (pwallet && pwallet->IsCrypted()) {
obj.push_back(Pair("unlocked_until", pwallet->nRelockTime));
} }
if (pwalletMain && pwalletMain->IsCrypted())
obj.push_back(Pair("unlocked_until", nWalletUnlockTime));
obj.push_back(Pair("paytxfee", ValueFromAmount(payTxFee.GetFeePerK()))); obj.push_back(Pair("paytxfee", ValueFromAmount(payTxFee.GetFeePerK())));
#endif #endif
obj.push_back(Pair("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK()))); obj.push_back(Pair("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK())));
@ -112,13 +116,17 @@ UniValue getinfo(const JSONRPCRequest& request)
class DescribeAddressVisitor : public boost::static_visitor<UniValue> class DescribeAddressVisitor : public boost::static_visitor<UniValue>
{ {
public: public:
CWallet * const pwallet;
DescribeAddressVisitor(CWallet *_pwallet) : pwallet(_pwallet) {}
UniValue operator()(const CNoDestination &dest) const { return UniValue(UniValue::VOBJ); } UniValue operator()(const CNoDestination &dest) const { return UniValue(UniValue::VOBJ); }
UniValue operator()(const CKeyID &keyID) const { UniValue operator()(const CKeyID &keyID) const {
UniValue obj(UniValue::VOBJ); UniValue obj(UniValue::VOBJ);
CPubKey vchPubKey; CPubKey vchPubKey;
obj.push_back(Pair("isscript", false)); obj.push_back(Pair("isscript", false));
if (pwalletMain && pwalletMain->GetPubKey(keyID, vchPubKey)) { if (pwallet && pwallet->GetPubKey(keyID, vchPubKey)) {
obj.push_back(Pair("pubkey", HexStr(vchPubKey))); obj.push_back(Pair("pubkey", HexStr(vchPubKey)));
obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed())); obj.push_back(Pair("iscompressed", vchPubKey.IsCompressed()));
} }
@ -129,7 +137,7 @@ public:
UniValue obj(UniValue::VOBJ); UniValue obj(UniValue::VOBJ);
CScript subscript; CScript subscript;
obj.push_back(Pair("isscript", true)); obj.push_back(Pair("isscript", true));
if (pwalletMain && pwalletMain->GetCScript(scriptID, subscript)) { if (pwallet && pwallet->GetCScript(scriptID, subscript)) {
std::vector<CTxDestination> addresses; std::vector<CTxDestination> addresses;
txnouttype whichType; txnouttype whichType;
int nRequired; int nRequired;
@ -177,7 +185,9 @@ UniValue validateaddress(const JSONRPCRequest& request)
); );
#ifdef ENABLE_WALLET #ifdef ENABLE_WALLET
LOCK2(cs_main, pwalletMain ? &pwalletMain->cs_wallet : NULL); CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);
#else #else
LOCK(cs_main); LOCK(cs_main);
#endif #endif
@ -197,16 +207,17 @@ UniValue validateaddress(const JSONRPCRequest& request)
ret.push_back(Pair("scriptPubKey", HexStr(scriptPubKey.begin(), scriptPubKey.end()))); ret.push_back(Pair("scriptPubKey", HexStr(scriptPubKey.begin(), scriptPubKey.end())));
#ifdef ENABLE_WALLET #ifdef ENABLE_WALLET
isminetype mine = pwalletMain ? IsMine(*pwalletMain, dest) : ISMINE_NO; isminetype mine = pwallet ? IsMine(*pwallet, dest) : ISMINE_NO;
ret.push_back(Pair("ismine", (mine & ISMINE_SPENDABLE) ? true : false)); ret.push_back(Pair("ismine", (mine & ISMINE_SPENDABLE) ? true : false));
ret.push_back(Pair("iswatchonly", (mine & ISMINE_WATCH_ONLY) ? true: false)); ret.push_back(Pair("iswatchonly", (mine & ISMINE_WATCH_ONLY) ? true: false));
UniValue detail = boost::apply_visitor(DescribeAddressVisitor(), dest); UniValue detail = boost::apply_visitor(DescribeAddressVisitor(pwallet), dest);
ret.pushKVs(detail); ret.pushKVs(detail);
if (pwalletMain && pwalletMain->mapAddressBook.count(dest)) if (pwallet && pwallet->mapAddressBook.count(dest)) {
ret.push_back(Pair("account", pwalletMain->mapAddressBook[dest].name)); ret.push_back(Pair("account", pwallet->mapAddressBook[dest].name));
}
CKeyID keyID; CKeyID keyID;
if (pwalletMain) { if (pwallet) {
const auto& meta = pwalletMain->mapKeyMetadata; const auto& meta = pwallet->mapKeyMetadata;
auto it = address.GetKeyID(keyID) ? meta.find(keyID) : meta.end(); auto it = address.GetKeyID(keyID) ? meta.find(keyID) : meta.end();
if (it == meta.end()) { if (it == meta.end()) {
it = meta.find(CScriptID(scriptPubKey)); it = meta.find(CScriptID(scriptPubKey));
@ -224,10 +235,13 @@ UniValue validateaddress(const JSONRPCRequest& request)
return ret; return ret;
} }
// Needed even with !ENABLE_WALLET, to pass (ignored) pointers around
class CWallet;
/** /**
* Used by addmultisigaddress / createmultisig: * Used by addmultisigaddress / createmultisig:
*/ */
CScript _createmultisig_redeemScript(const UniValue& params) CScript _createmultisig_redeemScript(CWallet * const pwallet, const UniValue& params)
{ {
int nRequired = params[0].get_int(); int nRequired = params[0].get_int();
const UniValue& keys = params[1].get_array(); const UniValue& keys = params[1].get_array();
@ -249,16 +263,16 @@ CScript _createmultisig_redeemScript(const UniValue& params)
#ifdef ENABLE_WALLET #ifdef ENABLE_WALLET
// Case 1: Bitcoin address and we have full public key: // Case 1: Bitcoin address and we have full public key:
CBitcoinAddress address(ks); CBitcoinAddress address(ks);
if (pwalletMain && address.IsValid()) if (pwallet && address.IsValid()) {
{
CKeyID keyID; CKeyID keyID;
if (!address.GetKeyID(keyID)) if (!address.GetKeyID(keyID))
throw runtime_error( throw runtime_error(
strprintf("%s does not refer to a key",ks)); strprintf("%s does not refer to a key",ks));
CPubKey vchPubKey; CPubKey vchPubKey;
if (!pwalletMain->GetPubKey(keyID, vchPubKey)) if (!pwallet->GetPubKey(keyID, vchPubKey)) {
throw runtime_error( throw runtime_error(
strprintf("no full public key for address %s",ks)); strprintf("no full public key for address %s",ks));
}
if (!vchPubKey.IsFullyValid()) if (!vchPubKey.IsFullyValid())
throw runtime_error(" Invalid public key: "+ks); throw runtime_error(" Invalid public key: "+ks);
pubkeys[i] = vchPubKey; pubkeys[i] = vchPubKey;
@ -290,6 +304,12 @@ CScript _createmultisig_redeemScript(const UniValue& params)
UniValue createmultisig(const JSONRPCRequest& request) UniValue createmultisig(const JSONRPCRequest& request)
{ {
#ifdef ENABLE_WALLET
CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
#else
CWallet * const pwallet = NULL;
#endif
if (request.fHelp || request.params.size() < 2 || request.params.size() > 2) if (request.fHelp || request.params.size() < 2 || request.params.size() > 2)
{ {
string msg = "createmultisig nrequired [\"key\",...]\n" string msg = "createmultisig nrequired [\"key\",...]\n"
@ -320,7 +340,7 @@ UniValue createmultisig(const JSONRPCRequest& request)
} }
// Construct using pay-to-script-hash: // Construct using pay-to-script-hash:
CScript inner = _createmultisig_redeemScript(request.params); CScript inner = _createmultisig_redeemScript(pwallet, request.params);
CScriptID innerID(inner); CScriptID innerID(inner);
CBitcoinAddress address(innerID); CBitcoinAddress address(innerID);

16
src/rpc/rawtransaction.cpp

@ -24,6 +24,7 @@
#include "uint256.h" #include "uint256.h"
#include "utilstrencodings.h" #include "utilstrencodings.h"
#ifdef ENABLE_WALLET #ifdef ENABLE_WALLET
#include "wallet/rpcwallet.h"
#include "wallet/wallet.h" #include "wallet/wallet.h"
#endif #endif
@ -594,6 +595,10 @@ static void TxInErrorToJSON(const CTxIn& txin, UniValue& vErrorsRet, const std::
UniValue signrawtransaction(const JSONRPCRequest& request) UniValue signrawtransaction(const JSONRPCRequest& request)
{ {
#ifdef ENABLE_WALLET
CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
#endif
if (request.fHelp || request.params.size() < 1 || request.params.size() > 4) if (request.fHelp || request.params.size() < 1 || request.params.size() > 4)
throw runtime_error( throw runtime_error(
"signrawtransaction \"hexstring\" ( [{\"txid\":\"id\",\"vout\":n,\"scriptPubKey\":\"hex\",\"redeemScript\":\"hex\"},...] [\"privatekey1\",...] sighashtype )\n" "signrawtransaction \"hexstring\" ( [{\"txid\":\"id\",\"vout\":n,\"scriptPubKey\":\"hex\",\"redeemScript\":\"hex\"},...] [\"privatekey1\",...] sighashtype )\n"
@ -603,7 +608,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
"The third optional argument (may be null) is an array of base58-encoded private\n" "The third optional argument (may be null) is an array of base58-encoded private\n"
"keys that, if given, will be the only keys used to sign the transaction.\n" "keys that, if given, will be the only keys used to sign the transaction.\n"
#ifdef ENABLE_WALLET #ifdef ENABLE_WALLET
+ HelpRequiringPassphrase() + "\n" + HelpRequiringPassphrase(pwallet) + "\n"
#endif #endif
"\nArguments:\n" "\nArguments:\n"
@ -654,7 +659,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
); );
#ifdef ENABLE_WALLET #ifdef ENABLE_WALLET
LOCK2(cs_main, pwalletMain ? &pwalletMain->cs_wallet : NULL); LOCK2(cs_main, pwallet ? &pwallet->cs_wallet : NULL);
#else #else
LOCK(cs_main); LOCK(cs_main);
#endif #endif
@ -717,8 +722,9 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
} }
} }
#ifdef ENABLE_WALLET #ifdef ENABLE_WALLET
else if (pwalletMain) else if (pwallet) {
EnsureWalletIsUnlocked(); EnsureWalletIsUnlocked(pwallet);
}
#endif #endif
// Add previous txouts given in the RPC call: // Add previous txouts given in the RPC call:
@ -785,7 +791,7 @@ UniValue signrawtransaction(const JSONRPCRequest& request)
} }
#ifdef ENABLE_WALLET #ifdef ENABLE_WALLET
const CKeyStore& keystore = ((fGivenKeys || !pwalletMain) ? tempKeystore : *pwalletMain); const CKeyStore& keystore = ((fGivenKeys || !pwallet) ? tempKeystore : *pwallet);
#else #else
const CKeyStore& keystore = tempKeystore; const CKeyStore& keystore = tempKeystore;
#endif #endif

11
src/rpc/server.cpp

@ -178,7 +178,7 @@ vector<unsigned char> ParseHexO(const UniValue& o, string strKey)
* Note: This interface may still be subject to change. * Note: This interface may still be subject to change.
*/ */
std::string CRPCTable::help(const std::string& strCommand) const std::string CRPCTable::help(const std::string& strCommand, const JSONRPCRequest& helpreq) const
{ {
string strRet; string strRet;
string category; string category;
@ -189,16 +189,19 @@ std::string CRPCTable::help(const std::string& strCommand) const
vCommands.push_back(make_pair(mi->second->category + mi->first, mi->second)); vCommands.push_back(make_pair(mi->second->category + mi->first, mi->second));
sort(vCommands.begin(), vCommands.end()); sort(vCommands.begin(), vCommands.end());
JSONRPCRequest jreq(helpreq);
jreq.fHelp = true;
jreq.params = UniValue();
BOOST_FOREACH(const PAIRTYPE(string, const CRPCCommand*)& command, vCommands) BOOST_FOREACH(const PAIRTYPE(string, const CRPCCommand*)& command, vCommands)
{ {
const CRPCCommand *pcmd = command.second; const CRPCCommand *pcmd = command.second;
string strMethod = pcmd->name; string strMethod = pcmd->name;
if ((strCommand != "" || pcmd->category == "hidden") && strMethod != strCommand) if ((strCommand != "" || pcmd->category == "hidden") && strMethod != strCommand)
continue; continue;
jreq.strMethod = strMethod;
try try
{ {
JSONRPCRequest jreq;
jreq.fHelp = true;
rpcfn_type pfn = pcmd->actor; rpcfn_type pfn = pcmd->actor;
if (setDone.insert(pfn).second) if (setDone.insert(pfn).second)
(*pfn)(jreq); (*pfn)(jreq);
@ -247,7 +250,7 @@ UniValue help(const JSONRPCRequest& jsonRequest)
if (jsonRequest.params.size() > 0) if (jsonRequest.params.size() > 0)
strCommand = jsonRequest.params[0].get_str(); strCommand = jsonRequest.params[0].get_str();
return tableRPC.help(strCommand); return tableRPC.help(strCommand, jsonRequest);
} }

6
src/rpc/server.h

@ -154,7 +154,7 @@ private:
public: public:
CRPCTable(); CRPCTable();
const CRPCCommand* operator[](const std::string& name) const; const CRPCCommand* operator[](const std::string& name) const;
std::string help(const std::string& name) const; std::string help(const std::string& name, const JSONRPCRequest& helpreq) const;
/** /**
* Execute a method. * Execute a method.
@ -190,16 +190,12 @@ extern uint256 ParseHashO(const UniValue& o, std::string strKey);
extern std::vector<unsigned char> ParseHexV(const UniValue& v, std::string strName); extern std::vector<unsigned char> ParseHexV(const UniValue& v, std::string strName);
extern std::vector<unsigned char> ParseHexO(const UniValue& o, std::string strKey); extern std::vector<unsigned char> ParseHexO(const UniValue& o, std::string strKey);
extern int64_t nWalletUnlockTime;
extern CAmount AmountFromValue(const UniValue& value); extern CAmount AmountFromValue(const UniValue& value);
extern UniValue ValueFromAmount(const CAmount& amount); extern UniValue ValueFromAmount(const CAmount& amount);
extern double GetDifficulty(const CBlockIndex* blockindex = NULL); extern double GetDifficulty(const CBlockIndex* blockindex = NULL);
extern std::string HelpRequiringPassphrase();
extern std::string HelpExampleCli(const std::string& methodname, const std::string& args); extern std::string HelpExampleCli(const std::string& methodname, const std::string& args);
extern std::string HelpExampleRpc(const std::string& methodname, const std::string& args); extern std::string HelpExampleRpc(const std::string& methodname, const std::string& args);
extern void EnsureWalletIsUnlocked();
bool StartRPC(); bool StartRPC();
void InterruptRPC(); void InterruptRPC();
void StopRPC(); void StopRPC();

3
src/utilstrencodings.cpp

@ -19,7 +19,8 @@ static const string CHARS_ALPHA_NUM = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNO
static const string SAFE_CHARS[] = static const string SAFE_CHARS[] =
{ {
CHARS_ALPHA_NUM + " .,;-_/:?@()", // SAFE_CHARS_DEFAULT CHARS_ALPHA_NUM + " .,;-_/:?@()", // SAFE_CHARS_DEFAULT
CHARS_ALPHA_NUM + " .,;-_?@" // SAFE_CHARS_UA_COMMENT CHARS_ALPHA_NUM + " .,;-_?@", // SAFE_CHARS_UA_COMMENT
CHARS_ALPHA_NUM + ".-_", // SAFE_CHARS_FILENAME
}; };
string SanitizeString(const string& str, int rule) string SanitizeString(const string& str, int rule)

3
src/utilstrencodings.h

@ -26,7 +26,8 @@
enum SafeChars enum SafeChars
{ {
SAFE_CHARS_DEFAULT, //!< The full set of allowed chars SAFE_CHARS_DEFAULT, //!< The full set of allowed chars
SAFE_CHARS_UA_COMMENT //!< BIP-0014 subset SAFE_CHARS_UA_COMMENT, //!< BIP-0014 subset
SAFE_CHARS_FILENAME, //!< Chars allowed in filenames
}; };
/** /**

248
src/wallet/rpcdump.cpp

@ -16,6 +16,8 @@
#include "merkleblock.h" #include "merkleblock.h"
#include "core_io.h" #include "core_io.h"
#include "rpcwallet.h"
#include <fstream> #include <fstream>
#include <stdint.h> #include <stdint.h>
@ -29,9 +31,6 @@
using namespace std; using namespace std;
void EnsureWalletIsUnlocked();
bool EnsureWalletIsAvailable(bool avoidException);
std::string static EncodeDumpTime(int64_t nTime) { std::string static EncodeDumpTime(int64_t nTime) {
return DateTimeStrFormat("%Y-%m-%dT%H:%M:%SZ", nTime); return DateTimeStrFormat("%Y-%m-%dT%H:%M:%SZ", nTime);
} }
@ -77,8 +76,10 @@ std::string DecodeDumpString(const std::string &str) {
UniValue importprivkey(const JSONRPCRequest& request) UniValue importprivkey(const JSONRPCRequest& request)
{ {
if (!EnsureWalletIsAvailable(request.fHelp)) CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue; return NullUniValue;
}
if (request.fHelp || request.params.size() < 1 || request.params.size() > 3) if (request.fHelp || request.params.size() < 1 || request.params.size() > 3)
throw runtime_error( throw runtime_error(
@ -101,9 +102,9 @@ UniValue importprivkey(const JSONRPCRequest& request)
); );
LOCK2(cs_main, pwalletMain->cs_wallet); LOCK2(cs_main, pwallet->cs_wallet);
EnsureWalletIsUnlocked(); EnsureWalletIsUnlocked(pwallet);
string strSecret = request.params[0].get_str(); string strSecret = request.params[0].get_str();
string strLabel = ""; string strLabel = "";
@ -130,65 +131,72 @@ UniValue importprivkey(const JSONRPCRequest& request)
assert(key.VerifyPubKey(pubkey)); assert(key.VerifyPubKey(pubkey));
CKeyID vchAddress = pubkey.GetID(); CKeyID vchAddress = pubkey.GetID();
{ {
pwalletMain->MarkDirty(); pwallet->MarkDirty();
pwalletMain->SetAddressBook(vchAddress, strLabel, "receive"); pwallet->SetAddressBook(vchAddress, strLabel, "receive");
// Don't throw error in case a key is already there // Don't throw error in case a key is already there
if (pwalletMain->HaveKey(vchAddress)) if (pwallet->HaveKey(vchAddress)) {
return NullUniValue; 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"); throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
}
// whenever a key is imported, we need to scan the whole chain // whenever a key is imported, we need to scan the whole chain
pwalletMain->UpdateTimeFirstKey(1); pwallet->UpdateTimeFirstKey(1);
if (fRescan) { if (fRescan) {
pwalletMain->ScanForWalletTransactions(chainActive.Genesis(), true); pwallet->ScanForWalletTransactions(chainActive.Genesis(), true);
} }
} }
return NullUniValue; return NullUniValue;
} }
void ImportAddress(const CBitcoinAddress& address, const string& strLabel); void ImportAddress(CWallet*, const CBitcoinAddress& address, const string& strLabel);
void ImportScript(const CScript& script, const string& strLabel, bool isRedeemScript) void ImportScript(CWallet * const pwallet, const CScript& script, const string& strLabel, bool isRedeemScript)
{ {
if (!isRedeemScript && ::IsMine(*pwalletMain, script) == ISMINE_SPENDABLE) if (!isRedeemScript && ::IsMine(*pwallet, script) == ISMINE_SPENDABLE) {
throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script"); 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"); throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
}
if (isRedeemScript) { 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"); throw JSONRPCError(RPC_WALLET_ERROR, "Error adding p2sh redeemScript to wallet");
ImportAddress(CBitcoinAddress(CScriptID(script)), strLabel); }
ImportAddress(pwallet, CBitcoinAddress(CScriptID(script)), strLabel);
} else { } else {
CTxDestination destination; CTxDestination destination;
if (ExtractDestination(script, 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 string& strLabel)
{ {
CScript script = GetScriptForDestination(address.Get()); CScript script = GetScriptForDestination(address.Get());
ImportScript(script, strLabel, false); ImportScript(pwallet, script, strLabel, false);
// add to address book or update label // add to address book or update label
if (address.IsValid()) if (address.IsValid())
pwalletMain->SetAddressBook(address.Get(), strLabel, "receive"); pwallet->SetAddressBook(address.Get(), strLabel, "receive");
} }
UniValue importaddress(const JSONRPCRequest& request) UniValue importaddress(const JSONRPCRequest& request)
{ {
if (!EnsureWalletIsAvailable(request.fHelp)) CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue; return NullUniValue;
}
if (request.fHelp || request.params.size() < 1 || request.params.size() > 4) if (request.fHelp || request.params.size() < 1 || request.params.size() > 4)
throw runtime_error( throw runtime_error(
@ -230,24 +238,24 @@ UniValue importaddress(const JSONRPCRequest& request)
if (request.params.size() > 3) if (request.params.size() > 3)
fP2SH = request.params[3].get_bool(); 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()); CBitcoinAddress address(request.params[0].get_str());
if (address.IsValid()) { if (address.IsValid()) {
if (fP2SH) if (fP2SH)
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Cannot use the p2sh flag with an address - use a script instead"); 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())) { } else if (IsHex(request.params[0].get_str())) {
std::vector<unsigned char> data(ParseHex(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 { } else {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address or script"); throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address or script");
} }
if (fRescan) if (fRescan)
{ {
pwalletMain->ScanForWalletTransactions(chainActive.Genesis(), true); pwallet->ScanForWalletTransactions(chainActive.Genesis(), true);
pwalletMain->ReacceptWalletTransactions(); pwallet->ReacceptWalletTransactions();
} }
return NullUniValue; return NullUniValue;
@ -255,8 +263,10 @@ UniValue importaddress(const JSONRPCRequest& request)
UniValue importprunedfunds(const JSONRPCRequest& request) UniValue importprunedfunds(const JSONRPCRequest& request)
{ {
if (!EnsureWalletIsAvailable(request.fHelp)) CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue; return NullUniValue;
}
if (request.fHelp || request.params.size() != 2) if (request.fHelp || request.params.size() != 2)
throw runtime_error( throw runtime_error(
@ -271,7 +281,7 @@ UniValue importprunedfunds(const JSONRPCRequest& request)
if (!DecodeHexTx(tx, request.params[0].get_str())) if (!DecodeHexTx(tx, request.params[0].get_str()))
throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed"); throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
uint256 hashTx = tx.GetHash(); 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); CDataStream ssMB(ParseHexV(request.params[1], "proof"), SER_NETWORK, PROTOCOL_VERSION);
CMerkleBlock merkleBlock; CMerkleBlock merkleBlock;
@ -302,10 +312,10 @@ UniValue importprunedfunds(const JSONRPCRequest& request)
wtx.nIndex = txnIndex; wtx.nIndex = txnIndex;
wtx.hashBlock = merkleBlock.header.GetHash(); wtx.hashBlock = merkleBlock.header.GetHash();
LOCK2(cs_main, pwalletMain->cs_wallet); LOCK2(cs_main, pwallet->cs_wallet);
if (pwalletMain->IsMine(wtx)) { if (pwallet->IsMine(wtx)) {
pwalletMain->AddToWallet(wtx, false); pwallet->AddToWallet(wtx, false);
return NullUniValue; return NullUniValue;
} }
@ -314,8 +324,10 @@ UniValue importprunedfunds(const JSONRPCRequest& request)
UniValue removeprunedfunds(const JSONRPCRequest& request) UniValue removeprunedfunds(const JSONRPCRequest& request)
{ {
if (!EnsureWalletIsAvailable(request.fHelp)) CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue; return NullUniValue;
}
if (request.fHelp || request.params.size() != 1) if (request.fHelp || request.params.size() != 1)
throw runtime_error( throw runtime_error(
@ -329,7 +341,7 @@ UniValue removeprunedfunds(const JSONRPCRequest& request)
+ HelpExampleRpc("removprunedfunds", "\"a8d0c0184dde994a09ec054286f1ce581bebf46446a512166eae7628734ea0a5\"") + HelpExampleRpc("removprunedfunds", "\"a8d0c0184dde994a09ec054286f1ce581bebf46446a512166eae7628734ea0a5\"")
); );
LOCK2(cs_main, pwalletMain->cs_wallet); LOCK2(cs_main, pwallet->cs_wallet);
uint256 hash; uint256 hash;
hash.SetHex(request.params[0].get_str()); hash.SetHex(request.params[0].get_str());
@ -337,7 +349,7 @@ UniValue removeprunedfunds(const JSONRPCRequest& request)
vHash.push_back(hash); vHash.push_back(hash);
vector<uint256> vHashOut; vector<uint256> vHashOut;
if(pwalletMain->ZapSelectTx(vHash, vHashOut) != DB_LOAD_OK) { if (pwallet->ZapSelectTx(vHash, vHashOut) != DB_LOAD_OK) {
throw JSONRPCError(RPC_INTERNAL_ERROR, "Could not properly delete the transaction."); throw JSONRPCError(RPC_INTERNAL_ERROR, "Could not properly delete the transaction.");
} }
@ -350,8 +362,10 @@ UniValue removeprunedfunds(const JSONRPCRequest& request)
UniValue importpubkey(const JSONRPCRequest& request) UniValue importpubkey(const JSONRPCRequest& request)
{ {
if (!EnsureWalletIsAvailable(request.fHelp)) CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue; return NullUniValue;
}
if (request.fHelp || request.params.size() < 1 || request.params.size() > 4) if (request.fHelp || request.params.size() < 1 || request.params.size() > 4)
throw runtime_error( throw runtime_error(
@ -391,15 +405,15 @@ UniValue importpubkey(const JSONRPCRequest& request)
if (!pubKey.IsFullyValid()) if (!pubKey.IsFullyValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey is not a valid public key"); 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); ImportAddress(pwallet, CBitcoinAddress(pubKey.GetID()), strLabel);
ImportScript(GetScriptForRawPubKey(pubKey), strLabel, false); ImportScript(pwallet, GetScriptForRawPubKey(pubKey), strLabel, false);
if (fRescan) if (fRescan)
{ {
pwalletMain->ScanForWalletTransactions(chainActive.Genesis(), true); pwallet->ScanForWalletTransactions(chainActive.Genesis(), true);
pwalletMain->ReacceptWalletTransactions(); pwallet->ReacceptWalletTransactions();
} }
return NullUniValue; return NullUniValue;
@ -408,8 +422,10 @@ UniValue importpubkey(const JSONRPCRequest& request)
UniValue importwallet(const JSONRPCRequest& request) UniValue importwallet(const JSONRPCRequest& request)
{ {
if (!EnsureWalletIsAvailable(request.fHelp)) CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue; return NullUniValue;
}
if (request.fHelp || request.params.size() != 1) if (request.fHelp || request.params.size() != 1)
throw runtime_error( throw runtime_error(
@ -429,9 +445,9 @@ UniValue importwallet(const JSONRPCRequest& request)
if (fPruneMode) if (fPruneMode)
throw JSONRPCError(RPC_WALLET_ERROR, "Importing wallets is disabled in pruned mode"); 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; ifstream file;
file.open(request.params[0].get_str().c_str(), std::ios::in | std::ios::ate); file.open(request.params[0].get_str().c_str(), std::ios::in | std::ios::ate);
@ -445,9 +461,9 @@ UniValue importwallet(const JSONRPCRequest& request)
int64_t nFilesize = std::max((int64_t)1, (int64_t)file.tellg()); int64_t nFilesize = std::max((int64_t)1, (int64_t)file.tellg());
file.seekg(0, file.beg); 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()) { 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::string line;
std::getline(file, line); std::getline(file, line);
if (line.empty() || line[0] == '#') if (line.empty() || line[0] == '#')
@ -464,7 +480,7 @@ UniValue importwallet(const JSONRPCRequest& request)
CPubKey pubkey = key.GetPubKey(); CPubKey pubkey = key.GetPubKey();
assert(key.VerifyPubKey(pubkey)); assert(key.VerifyPubKey(pubkey));
CKeyID keyid = pubkey.GetID(); CKeyID keyid = pubkey.GetID();
if (pwalletMain->HaveKey(keyid)) { if (pwallet->HaveKey(keyid)) {
LogPrintf("Skipping import of %s (key already present)\n", CBitcoinAddress(keyid).ToString()); LogPrintf("Skipping import of %s (key already present)\n", CBitcoinAddress(keyid).ToString());
continue; continue;
} }
@ -484,27 +500,27 @@ UniValue importwallet(const JSONRPCRequest& request)
} }
} }
LogPrintf("Importing %s...\n", CBitcoinAddress(keyid).ToString()); LogPrintf("Importing %s...\n", CBitcoinAddress(keyid).ToString());
if (!pwalletMain->AddKeyPubKey(key, pubkey)) { if (!pwallet->AddKeyPubKey(key, pubkey)) {
fGood = false; fGood = false;
continue; continue;
} }
pwalletMain->mapKeyMetadata[keyid].nCreateTime = nTime; pwallet->mapKeyMetadata[keyid].nCreateTime = nTime;
if (fLabel) if (fLabel)
pwalletMain->SetAddressBook(keyid, strLabel, "receive"); pwallet->SetAddressBook(keyid, strLabel, "receive");
nTimeBegin = std::min(nTimeBegin, nTime); nTimeBegin = std::min(nTimeBegin, nTime);
} }
file.close(); file.close();
pwalletMain->ShowProgress("", 100); // hide progress dialog in GUI pwallet->ShowProgress("", 100); // hide progress dialog in GUI
CBlockIndex *pindex = chainActive.Tip(); CBlockIndex *pindex = chainActive.Tip();
while (pindex && pindex->pprev && pindex->GetBlockTime() > nTimeBegin - 7200) while (pindex && pindex->pprev && pindex->GetBlockTime() > nTimeBegin - 7200)
pindex = pindex->pprev; pindex = pindex->pprev;
pwalletMain->UpdateTimeFirstKey(nTimeBegin); pwallet->UpdateTimeFirstKey(nTimeBegin);
LogPrintf("Rescanning last %i blocks\n", chainActive.Height() - pindex->nHeight + 1); LogPrintf("Rescanning last %i blocks\n", chainActive.Height() - pindex->nHeight + 1);
pwalletMain->ScanForWalletTransactions(pindex); pwallet->ScanForWalletTransactions(pindex);
pwalletMain->MarkDirty(); pwallet->MarkDirty();
if (!fGood) if (!fGood)
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding some keys to wallet"); throw JSONRPCError(RPC_WALLET_ERROR, "Error adding some keys to wallet");
@ -514,8 +530,10 @@ UniValue importwallet(const JSONRPCRequest& request)
UniValue dumpprivkey(const JSONRPCRequest& request) UniValue dumpprivkey(const JSONRPCRequest& request)
{ {
if (!EnsureWalletIsAvailable(request.fHelp)) CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue; return NullUniValue;
}
if (request.fHelp || request.params.size() != 1) if (request.fHelp || request.params.size() != 1)
throw runtime_error( throw runtime_error(
@ -532,9 +550,9 @@ UniValue dumpprivkey(const JSONRPCRequest& request)
+ HelpExampleRpc("dumpprivkey", "\"myaddress\"") + 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(); string strAddress = request.params[0].get_str();
CBitcoinAddress address; CBitcoinAddress address;
@ -544,16 +562,19 @@ UniValue dumpprivkey(const JSONRPCRequest& request)
if (!address.GetKeyID(keyID)) if (!address.GetKeyID(keyID))
throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to a key"); throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to a key");
CKey vchSecret; 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"); throw JSONRPCError(RPC_WALLET_ERROR, "Private key for address " + strAddress + " is not known");
}
return CBitcoinSecret(vchSecret).ToString(); return CBitcoinSecret(vchSecret).ToString();
} }
UniValue dumpwallet(const JSONRPCRequest& request) UniValue dumpwallet(const JSONRPCRequest& request)
{ {
if (!EnsureWalletIsAvailable(request.fHelp)) CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue; return NullUniValue;
}
if (request.fHelp || request.params.size() != 1) if (request.fHelp || request.params.size() != 1)
throw runtime_error( throw runtime_error(
@ -566,9 +587,9 @@ UniValue dumpwallet(const JSONRPCRequest& request)
+ HelpExampleRpc("dumpwallet", "\"test\"") + HelpExampleRpc("dumpwallet", "\"test\"")
); );
LOCK2(cs_main, pwalletMain->cs_wallet); LOCK2(cs_main, pwallet->cs_wallet);
EnsureWalletIsUnlocked(); EnsureWalletIsUnlocked(pwallet);
ofstream file; ofstream file;
file.open(request.params[0].get_str().c_str()); file.open(request.params[0].get_str().c_str());
@ -577,8 +598,8 @@ UniValue dumpwallet(const JSONRPCRequest& request)
std::map<CTxDestination, int64_t> mapKeyBirth; std::map<CTxDestination, int64_t> mapKeyBirth;
std::set<CKeyID> setKeyPool; std::set<CKeyID> setKeyPool;
pwalletMain->GetKeyBirthTimes(mapKeyBirth); pwallet->GetKeyBirthTimes(mapKeyBirth);
pwalletMain->GetAllReserveKeys(setKeyPool); pwallet->GetAllReserveKeys(setKeyPool);
// sort time/key pairs // sort time/key pairs
std::vector<std::pair<int64_t, CKeyID> > vKeyBirth; std::vector<std::pair<int64_t, CKeyID> > vKeyBirth;
@ -598,12 +619,11 @@ UniValue dumpwallet(const JSONRPCRequest& request)
file << "\n"; file << "\n";
// add the base58check encoded extended master if the wallet uses HD // add the base58check encoded extended master if the wallet uses HD
CKeyID masterKeyID = pwalletMain->GetHDChain().masterKeyID; CKeyID masterKeyID = pwallet->GetHDChain().masterKeyID;
if (!masterKeyID.IsNull()) if (!masterKeyID.IsNull())
{ {
CKey key; CKey key;
if (pwalletMain->GetKey(masterKeyID, key)) if (pwallet->GetKey(masterKeyID, key)) {
{
CExtKey masterKey; CExtKey masterKey;
masterKey.SetMaster(key.begin(), key.size()); masterKey.SetMaster(key.begin(), key.size());
@ -618,20 +638,20 @@ UniValue dumpwallet(const JSONRPCRequest& request)
std::string strTime = EncodeDumpTime(it->first); std::string strTime = EncodeDumpTime(it->first);
std::string strAddr = CBitcoinAddress(keyid).ToString(); std::string strAddr = CBitcoinAddress(keyid).ToString();
CKey key; CKey key;
if (pwalletMain->GetKey(keyid, key)) { if (pwallet->GetKey(keyid, key)) {
file << strprintf("%s %s ", CBitcoinSecret(key).ToString(), strTime); file << strprintf("%s %s ", CBitcoinSecret(key).ToString(), strTime);
if (pwalletMain->mapAddressBook.count(keyid)) { if (pwallet->mapAddressBook.count(keyid)) {
file << strprintf("label=%s", EncodeDumpString(pwalletMain->mapAddressBook[keyid].name)); file << strprintf("label=%s", EncodeDumpString(pwallet->mapAddressBook[keyid].name));
} else if (keyid == masterKeyID) { } else if (keyid == masterKeyID) {
file << "hdmaster=1"; file << "hdmaster=1";
} else if (setKeyPool.count(keyid)) { } else if (setKeyPool.count(keyid)) {
file << "reserve=1"; file << "reserve=1";
} else if (pwalletMain->mapKeyMetadata[keyid].hdKeypath == "m") { } else if (pwallet->mapKeyMetadata[keyid].hdKeypath == "m") {
file << "inactivehdmaster=1"; file << "inactivehdmaster=1";
} else { } else {
file << "change=1"; 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"; file << "\n";
@ -641,7 +661,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 { try {
bool success = false; bool success = false;
@ -723,32 +743,32 @@ UniValue ProcessImport(const UniValue& data, const int64_t timestamp)
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid P2SH address / script"); 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->HaveWatchOnly(redeemScript) && !pwallet->AddWatchOnly(redeemScript, timestamp)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet"); 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"); throw JSONRPCError(RPC_WALLET_ERROR, "Error adding p2sh redeemScript to wallet");
} }
CBitcoinAddress redeemAddress = CBitcoinAddress(CScriptID(redeemScript)); CBitcoinAddress redeemAddress = CBitcoinAddress(CScriptID(redeemScript));
CScript redeemDestination = GetScriptForDestination(redeemAddress.Get()); 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"); 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->HaveWatchOnly(redeemDestination) && !pwallet->AddWatchOnly(redeemDestination, timestamp)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet"); throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
} }
// add to address book or update label // add to address book or update label
if (address.IsValid()) { if (address.IsValid()) {
pwalletMain->SetAddressBook(address.Get(), label, "receive"); pwallet->SetAddressBook(address.Get(), label, "receive");
} }
// Import private keys. // Import private keys.
@ -773,20 +793,20 @@ UniValue ProcessImport(const UniValue& data, const int64_t timestamp)
assert(key.VerifyPubKey(pubkey)); assert(key.VerifyPubKey(pubkey));
CKeyID vchAddress = pubkey.GetID(); CKeyID vchAddress = pubkey.GetID();
pwalletMain->MarkDirty(); pwallet->MarkDirty();
pwalletMain->SetAddressBook(vchAddress, label, "receive"); pwallet->SetAddressBook(vchAddress, label, "receive");
if (pwalletMain->HaveKey(vchAddress)) { if (pwallet->HaveKey(vchAddress)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Already have this key"); 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"); throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
} }
pwalletMain->UpdateTimeFirstKey(timestamp); pwallet->UpdateTimeFirstKey(timestamp);
} }
} }
@ -829,31 +849,31 @@ UniValue ProcessImport(const UniValue& data, const int64_t timestamp)
CScript pubKeyScript = GetScriptForDestination(pubKeyAddress.Get()); 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"); 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->HaveWatchOnly(pubKeyScript) && !pwallet->AddWatchOnly(pubKeyScript, timestamp)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet"); throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
} }
// add to address book or update label // add to address book or update label
if (pubKeyAddress.IsValid()) { if (pubKeyAddress.IsValid()) {
pwalletMain->SetAddressBook(pubKeyAddress.Get(), label, "receive"); pwallet->SetAddressBook(pubKeyAddress.Get(), label, "receive");
} }
// TODO Is this necessary? // TODO Is this necessary?
CScript scriptRawPubKey = GetScriptForRawPubKey(pubKey); 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"); 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->HaveWatchOnly(scriptRawPubKey) && !pwallet->AddWatchOnly(scriptRawPubKey, timestamp)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet"); throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
} }
@ -901,40 +921,40 @@ UniValue ProcessImport(const UniValue& data, const int64_t timestamp)
} }
CKeyID vchAddress = pubKey.GetID(); CKeyID vchAddress = pubKey.GetID();
pwalletMain->MarkDirty(); pwallet->MarkDirty();
pwalletMain->SetAddressBook(vchAddress, label, "receive"); pwallet->SetAddressBook(vchAddress, label, "receive");
if (pwalletMain->HaveKey(vchAddress)) { if (pwallet->HaveKey(vchAddress)) {
return false; 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"); throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
} }
pwalletMain->UpdateTimeFirstKey(timestamp); pwallet->UpdateTimeFirstKey(timestamp);
success = true; success = true;
} }
// Import scriptPubKey only. // Import scriptPubKey only.
if (pubKeys.size() == 0 && keys.size() == 0) { 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"); 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->HaveWatchOnly(script) && !pwallet->AddWatchOnly(script, timestamp)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet"); throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
} }
if (scriptPubKey.getType() == UniValue::VOBJ) { if (scriptPubKey.getType() == UniValue::VOBJ) {
// add to address book or update label // add to address book or update label
if (address.IsValid()) { if (address.IsValid()) {
pwalletMain->SetAddressBook(address.Get(), label, "receive"); pwallet->SetAddressBook(address.Get(), label, "receive");
} }
} }
@ -974,6 +994,11 @@ int64_t GetImportTimestamp(const UniValue& data, int64_t now)
UniValue importmulti(const JSONRPCRequest& mainRequest) UniValue importmulti(const JSONRPCRequest& mainRequest)
{ {
CWallet * const pwallet = GetWalletForJSONRPCRequest(mainRequest);
if (!EnsureWalletIsAvailable(pwallet, mainRequest.fHelp)) {
return NullUniValue;
}
// clang-format off // clang-format off
if (mainRequest.fHelp || mainRequest.params.size() < 1 || mainRequest.params.size() > 2) if (mainRequest.fHelp || mainRequest.params.size() < 1 || mainRequest.params.size() > 2)
throw runtime_error( throw runtime_error(
@ -1012,9 +1037,6 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
" [{ \"success\": true } , { \"success\": false, \"error\": { \"code\": -1, \"message\": \"Internal Server Error\"} }, ... ]\n"); " [{ \"success\": true } , { \"success\": false, \"error\": { \"code\": -1, \"message\": \"Internal Server Error\"} }, ... ]\n");
// clang-format on // clang-format on
if (!EnsureWalletIsAvailable(mainRequest.fHelp)) {
return NullUniValue;
}
RPCTypeCheck(mainRequest.params, boost::assign::list_of(UniValue::VARR)(UniValue::VOBJ)); RPCTypeCheck(mainRequest.params, boost::assign::list_of(UniValue::VARR)(UniValue::VOBJ));
@ -1031,8 +1053,8 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
} }
} }
LOCK2(cs_main, pwalletMain->cs_wallet); LOCK2(cs_main, pwallet->cs_wallet);
EnsureWalletIsUnlocked(); EnsureWalletIsUnlocked(pwallet);
// Verify all timestamps are present before importing any keys. // Verify all timestamps are present before importing any keys.
const int64_t now = chainActive.Tip() ? chainActive.Tip()->GetMedianTimePast() : 0; const int64_t now = chainActive.Tip() ? chainActive.Tip()->GetMedianTimePast() : 0;
@ -1054,7 +1076,7 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
BOOST_FOREACH (const UniValue& data, requests.getValues()) { BOOST_FOREACH (const UniValue& data, requests.getValues()) {
const int64_t timestamp = std::max(GetImportTimestamp(data, now), minimumTimestamp); 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); response.push_back(result);
if (!fRescan) { if (!fRescan) {
@ -1076,8 +1098,8 @@ UniValue importmulti(const JSONRPCRequest& mainRequest)
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 - 7200, 0)) : chainActive.Genesis();
CBlockIndex* scannedRange = nullptr; CBlockIndex* scannedRange = nullptr;
if (pindex) { if (pindex) {
scannedRange = pwalletMain->ScanForWalletTransactions(pindex, true); scannedRange = pwallet->ScanForWalletTransactions(pindex, true);
pwalletMain->ReacceptWalletTransactions(); pwallet->ReacceptWalletTransactions();
} }
if (!scannedRange || scannedRange->nHeight > pindex->nHeight) { if (!scannedRange || scannedRange->nHeight > pindex->nHeight) {

638
src/wallet/rpcwallet.cpp

File diff suppressed because it is too large Load Diff

13
src/wallet/rpcwallet.h

@ -6,7 +6,20 @@
#define BITCOIN_WALLET_RPCWALLET_H #define BITCOIN_WALLET_RPCWALLET_H
class CRPCTable; class CRPCTable;
class JSONRPCRequest;
void RegisterWalletRPCCommands(CRPCTable &t); void RegisterWalletRPCCommands(CRPCTable &t);
/**
* Figures out what wallet, if any, to use for a JSONRPCRequest.
*
* @param[in] request JSONRPCRequest that wishes to access a wallet
* @return NULL if no wallet should be used, or a pointer to the CWallet
*/
CWallet *GetWalletForJSONRPCRequest(const JSONRPCRequest&);
std::string HelpRequiringPassphrase(CWallet *);
void EnsureWalletIsUnlocked(CWallet *);
bool EnsureWalletIsAvailable(CWallet *, bool avoidException);
#endif //BITCOIN_WALLET_RPCWALLET_H #endif //BITCOIN_WALLET_RPCWALLET_H

6
src/wallet/wallet.cpp

@ -3770,6 +3770,12 @@ bool CWallet::InitLoadWallet()
std::string walletFile = GetArg("-wallet", DEFAULT_WALLET_DAT); std::string walletFile = GetArg("-wallet", DEFAULT_WALLET_DAT);
if (walletFile.find_first_of("/\\") != std::string::npos) {
return InitError(_("-wallet parameter must only specify a filename (not a path)"));
} else if (SanitizeString(walletFile, SAFE_CHARS_FILENAME) != walletFile) {
return InitError(_("Invalid characters in -wallet filename"));
}
CWallet * const pwallet = CreateWalletFromFile(walletFile); CWallet * const pwallet = CreateWalletFromFile(walletFile);
if (!pwallet) { if (!pwallet) {
return false; return false;

3
src/wallet/wallet.h

@ -768,6 +768,9 @@ public:
//! Adds a watch-only address to the store, without saving it to disk (used by LoadWallet) //! Adds a watch-only address to the store, without saving it to disk (used by LoadWallet)
bool LoadWatchOnly(const CScript &dest); bool LoadWatchOnly(const CScript &dest);
//! Holds a timestamp at which point the wallet is scheduled (externally) to be relocked. Caller must arrange for actual relocking to occur via Lock().
int64_t nRelockTime;
bool Unlock(const SecureString& strWalletPassphrase); bool Unlock(const SecureString& strWalletPassphrase);
bool ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase); bool ChangeWalletPassphrase(const SecureString& strOldWalletPassphrase, const SecureString& strNewWalletPassphrase);
bool EncryptWallet(const SecureString& strWalletPassphrase); bool EncryptWallet(const SecureString& strWalletPassphrase);

Loading…
Cancel
Save