diff --git a/src/rpc/misc.cpp b/src/rpc/misc.cpp --- a/src/rpc/misc.cpp +++ b/src/rpc/misc.cpp @@ -18,6 +18,7 @@ #include "utilstrencodings.h" #include "validation.h" #ifdef ENABLE_WALLET +#include "wallet/rpcwallet.h" #include "wallet/wallet.h" #include "wallet/walletdb.h" #endif @@ -119,8 +120,9 @@ obj.push_back(Pair("keypoololdest", pwallet->GetOldestKeyPoolTime())); obj.push_back(Pair("keypoolsize", (int)pwallet->GetKeyPoolSize())); } - if (pwallet && pwallet->IsCrypted()) - obj.push_back(Pair("unlocked_until", nWalletUnlockTime)); + if (pwallet && pwallet->IsCrypted()) { + obj.push_back(Pair("unlocked_until", pwallet->nRelockTime)); + } obj.push_back(Pair("paytxfee", ValueFromAmount(payTxFee.GetFeePerK()))); #endif obj.push_back( @@ -274,6 +276,9 @@ return ret; } +// Needed even with !ENABLE_WALLET, to pass (ignored) pointers around +class CWallet; + /** * Used by addmultisigaddress / createmultisig: */ diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -27,6 +27,7 @@ #include "utilstrencodings.h" #include "validation.h" #ifdef ENABLE_WALLET +#include "wallet/rpcwallet.h" #include "wallet/wallet.h" #endif diff --git a/src/rpc/server.h b/src/rpc/server.h --- a/src/rpc/server.h +++ b/src/rpc/server.h @@ -180,7 +180,8 @@ public: CRPCTable(); const CRPCCommand *operator[](const std::string &name) const; - std::string help(Config &config, const std::string &name) const; + std::string help(Config &config, const std::string &name, + const JSONRPCRequest &helpreq) const; /** * Execute a method. @@ -216,7 +217,6 @@ extern std::vector ParseHexV(const UniValue &v, std::string strName); extern std::vector ParseHexO(const UniValue &o, std::string strKey); -extern int64_t nWalletUnlockTime; extern Amount AmountFromValue(const UniValue &value); extern UniValue ValueFromAmount(const Amount &amount); extern std::string HelpExampleCli(const std::string &methodname, @@ -224,17 +224,6 @@ extern std::string HelpExampleRpc(const std::string &methodname, const std::string &args); -// Needed even with !ENABLE_WALLET, to pass (ignored) pointers around -class CWallet; - -#ifdef ENABLE_WALLET -// New code accessing the wallet should be under the ../wallet/ directory -CWallet *GetWalletForJSONRPCRequest(const JSONRPCRequest &); -std::string HelpRequiringPassphrase(CWallet *); -void EnsureWalletIsUnlocked(CWallet *); -bool EnsureWalletIsAvailable(CWallet *, bool avoidException); -#endif - bool StartRPC(); void InterruptRPC(); void StopRPC(); diff --git a/src/rpc/server.cpp b/src/rpc/server.cpp --- a/src/rpc/server.cpp +++ b/src/rpc/server.cpp @@ -168,8 +168,8 @@ /** * Note: This interface may still be subject to change. */ -std::string CRPCTable::help(Config &config, - const std::string &strCommand) const { +std::string CRPCTable::help(Config &config, const std::string &strCommand, + const JSONRPCRequest &helpreq) const { std::string strRet; std::string category; std::set setDone; @@ -182,16 +182,25 @@ std::make_pair(mi->second->category + mi->first, mi->second)); sort(vCommands.begin(), vCommands.end()); + JSONRPCRequest jreq(helpreq); + jreq.fHelp = true; + jreq.params = UniValue(); + for (const std::pair &command : vCommands) { const CRPCCommand *pcmd = command.second; std::string strMethod = pcmd->name; // We already filter duplicates, but these deprecated screw up the sort // order - if (strMethod.find("label") != std::string::npos) continue; + if (strMethod.find("label") != std::string::npos) { + continue; + } if ((strCommand != "" || pcmd->category == "hidden") && - strMethod != strCommand) + strMethod != strCommand) { continue; + } + + jreq.strMethod = strMethod; try { JSONRPCRequest jreq; jreq.fHelp = true; @@ -233,10 +242,11 @@ "\"text\" (string) The help text\n"); std::string strCommand; - if (jsonRequest.params.size() > 0) + if (jsonRequest.params.size() > 0) { strCommand = jsonRequest.params[0].get_str(); + } - return tableRPC.help(config, strCommand); + return tableRPC.help(config, strCommand, jsonRequest); } static UniValue stop(const Config &config, const JSONRPCRequest &jsonRequest) { diff --git a/src/utilstrencodings.h b/src/utilstrencodings.h --- a/src/utilstrencodings.h +++ b/src/utilstrencodings.h @@ -25,6 +25,8 @@ SAFE_CHARS_DEFAULT, //!< BIP-0014 subset SAFE_CHARS_UA_COMMENT, + //!< Chars allowed in filenames + SAFE_CHARS_FILENAME, }; /** diff --git a/src/utilstrencodings.cpp b/src/utilstrencodings.cpp --- a/src/utilstrencodings.cpp +++ b/src/utilstrencodings.cpp @@ -20,6 +20,8 @@ CHARS_ALPHA_NUM + " .,;-_/:?@()", // SAFE_CHARS_UA_COMMENT CHARS_ALPHA_NUM + " .,;-_?@", + // SAFE_CHARS_FILENAME + CHARS_ALPHA_NUM + ".-_", }; std::string SanitizeString(const std::string &str, int rule) { diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -9,6 +9,7 @@ #include "init.h" #include "merkleblock.h" #include "rpc/server.h" +#include "rpcwallet.h" #include "script/script.h" #include "script/standard.h" #include "sync.h" diff --git a/src/wallet/rpcwallet.h b/src/wallet/rpcwallet.h --- a/src/wallet/rpcwallet.h +++ b/src/wallet/rpcwallet.h @@ -6,7 +6,20 @@ #define BITCOIN_WALLET_RPCWALLET_H class CRPCTable; +class JSONRPCRequest; 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 diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -25,9 +25,6 @@ #include -int64_t nWalletUnlockTime; -static CCriticalSection cs_nWalletUnlockTime; - CWallet *GetWalletForJSONRPCRequest(const JSONRPCRequest &request) { return pwalletMain; } @@ -713,9 +710,8 @@ // Tally Amount nAmount(0); - for (std::map::iterator it = pwallet->mapWallet.begin(); - it != pwallet->mapWallet.end(); ++it) { - const CWalletTx &wtx = (*it).second; + for (const std::pair &pairWtx : pwallet->mapWallet) { + const CWalletTx &wtx = pairWtx.second; CValidationState state; if (wtx.IsCoinBase() || @@ -785,9 +781,8 @@ // Tally Amount nAmount(0); - for (std::map::iterator it = pwallet->mapWallet.begin(); - it != pwallet->mapWallet.end(); ++it) { - const CWalletTx &wtx = (*it).second; + for (const std::pair &pairWtx : pwallet->mapWallet) { + const CWalletTx &wtx = pairWtx.second; CValidationState state; if (wtx.IsCoinBase() || !ContextualCheckTransactionForCurrentBlock(config, *wtx.tx, @@ -889,10 +884,9 @@ // TxIns spending from the wallet. This also has fewer restrictions on // which unconfirmed transactions are considered trusted. Amount nBalance(0); - for (std::map::iterator it = - pwallet->mapWallet.begin(); - it != pwallet->mapWallet.end(); ++it) { - const CWalletTx &wtx = (*it).second; + for (const std::pair &pairWtx : + pwallet->mapWallet) { + const CWalletTx &wtx = pairWtx.second; CValidationState state; if (!ContextualCheckTransactionForCurrentBlock(config, wtx, state) || @@ -1004,6 +998,7 @@ if (request.params.size() > 4) { strComment = request.params[4].get_str(); } + if (!pwallet->AccountMove(strFrom, strTo, nAmount, strComment)) { throw JSONRPCError(RPC_DATABASE_ERROR, "database error"); } @@ -1389,9 +1384,8 @@ // Tally std::map mapTally; - for (std::map::iterator it = pwallet->mapWallet.begin(); - it != pwallet->mapWallet.end(); ++it) { - const CWalletTx &wtx = (*it).second; + for (const std::pair &pairWtx : pwallet->mapWallet) { + const CWalletTx &wtx = pairWtx.second; CValidationState state; if (wtx.IsCoinBase() || @@ -1948,9 +1942,8 @@ } } - for (std::map::iterator it = pwallet->mapWallet.begin(); - it != pwallet->mapWallet.end(); ++it) { - const CWalletTx &wtx = (*it).second; + for (const std::pair &pairWtx : pwallet->mapWallet) { + const CWalletTx &wtx = pairWtx.second; Amount nFee; std::string strSentAccount; std::list listReceived; @@ -2117,9 +2110,8 @@ UniValue transactions(UniValue::VARR); - for (std::map::iterator it = pwallet->mapWallet.begin(); - it != pwallet->mapWallet.end(); it++) { - CWalletTx tx = (*it).second; + for (const std::pair &pairWtx : pwallet->mapWallet) { + CWalletTx tx = pairWtx.second; if (depth == -1 || tx.GetDepthInMainChain() < depth) { ListTransactions(pwallet, tx, "*", 0, true, transactions, filter); @@ -2393,8 +2385,8 @@ } static void LockWallet(CWallet *pWallet) { - LOCK(cs_nWalletUnlockTime); - nWalletUnlockTime = 0; + LOCK(pWallet->cs_wallet); + pWallet->nRelockTime = 0; pWallet->Lock(); } @@ -2466,9 +2458,9 @@ pwallet->TopUpKeyPool(); int64_t nSleepTime = request.params[1].get_int64(); - LOCK(cs_nWalletUnlockTime); - nWalletUnlockTime = GetTime() + nSleepTime; - RPCRunLater("lockwallet", boost::bind(LockWallet, pwallet), nSleepTime); + pwallet->nRelockTime = GetTime() + nSleepTime; + RPCRunLater(strprintf("lockwallet(%s)", pwallet->strWalletFile), + boost::bind(LockWallet, pwallet), nSleepTime); return NullUniValue; } @@ -2573,11 +2565,8 @@ "walletlock was called."); } - { - LOCK(cs_nWalletUnlockTime); - pwallet->Lock(); - nWalletUnlockTime = 0; - } + pwallet->Lock(); + pwallet->nRelockTime = 0; return NullUniValue; } @@ -2933,7 +2922,7 @@ obj.push_back(Pair("keypoololdest", pwallet->GetOldestKeyPoolTime())); obj.push_back(Pair("keypoolsize", (int)pwallet->GetKeyPoolSize())); if (pwallet->IsCrypted()) { - obj.push_back(Pair("unlocked_until", nWalletUnlockTime)); + obj.push_back(Pair("unlocked_until", pwallet->nRelockTime)); } obj.push_back(Pair("paytxfee", ValueFromAmount(payTxFee.GetFeePerK()))); CKeyID masterKeyID = pwallet->GetHDChain().masterKeyID; diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -782,6 +782,11 @@ //! by LoadWallet) 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 ChangeWalletPassphrase(const SecureString &strOldWalletPassphrase, const SecureString &strNewWalletPassphrase); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -4191,6 +4191,13 @@ 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); if (!pwallet) { return false;