aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/init.cpp22
-rw-r--r--src/rpcblockchain.cpp19
-rw-r--r--src/rpcdump.cpp10
-rw-r--r--src/rpcmining.cpp11
-rw-r--r--src/rpcmisc.cpp16
-rw-r--r--src/rpcnet.cpp10
-rw-r--r--src/rpcrawtransaction.cpp14
-rw-r--r--src/rpcserver.cpp240
-rw-r--r--src/rpcserver.h11
-rw-r--r--src/rpcwallet.cpp69
-rw-r--r--src/sync.h11
11 files changed, 308 insertions, 125 deletions
diff --git a/src/init.cpp b/src/init.cpp
index c2af23139c..c8f32d8bfd 100644
--- a/src/init.cpp
+++ b/src/init.cpp
@@ -234,6 +234,26 @@ bool static Bind(const CService &addr, unsigned int flags) {
return true;
}
+void OnRPCStopped()
+{
+ cvBlockChange.notify_all();
+ LogPrint("rpc", "RPC stopped.\n");
+}
+
+void OnRPCPreCommand(const CRPCCommand& cmd)
+{
+#ifdef ENABLE_WALLET
+ if (cmd.reqWallet && !pwalletMain)
+ throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)");
+#endif
+
+ // Observe safe mode
+ string strWarning = GetWarnings("rpc");
+ if (strWarning != "" && !GetBoolArg("-disablesafemode", false) &&
+ !cmd.okSafeMode)
+ throw JSONRPCError(RPC_FORBIDDEN_BY_SAFE_MODE, string("Safe mode: ") + strWarning);
+}
+
std::string HelpMessage(HelpMessageMode mode)
{
// When adding new options to the categories, please keep and ensure alphabetical ordering.
@@ -802,6 +822,8 @@ bool AppInit2(boost::thread_group& threadGroup)
if (fServer)
{
uiInterface.InitMessage.connect(SetRPCWarmupStatus);
+ RPCServer::OnStopped(&OnRPCStopped);
+ RPCServer::OnPreCommand(&OnRPCPreCommand);
StartRPCThreads();
}
diff --git a/src/rpcblockchain.cpp b/src/rpcblockchain.cpp
index cfc559d198..293d6d5619 100644
--- a/src/rpcblockchain.cpp
+++ b/src/rpcblockchain.cpp
@@ -105,6 +105,7 @@ Value getblockcount(const Array& params, bool fHelp)
+ HelpExampleRpc("getblockcount", "")
);
+ LOCK(cs_main);
return chainActive.Height();
}
@@ -121,6 +122,7 @@ Value getbestblockhash(const Array& params, bool fHelp)
+ HelpExampleRpc("getbestblockhash", "")
);
+ LOCK(cs_main);
return chainActive.Tip()->GetBlockHash().GetHex();
}
@@ -137,6 +139,7 @@ Value getdifficulty(const Array& params, bool fHelp)
+ HelpExampleRpc("getdifficulty", "")
);
+ LOCK(cs_main);
return GetDifficulty();
}
@@ -173,6 +176,8 @@ Value getrawmempool(const Array& params, bool fHelp)
+ HelpExampleRpc("getrawmempool", "true")
);
+ LOCK(cs_main);
+
bool fVerbose = false;
if (params.size() > 0)
fVerbose = params[0].get_bool();
@@ -233,6 +238,8 @@ Value getblockhash(const Array& params, bool fHelp)
+ HelpExampleRpc("getblockhash", "1000")
);
+ LOCK(cs_main);
+
int nHeight = params[0].get_int();
if (nHeight < 0 || nHeight > chainActive.Height())
throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range");
@@ -277,6 +284,8 @@ Value getblock(const Array& params, bool fHelp)
+ HelpExampleRpc("getblock", "\"00000000c937983704a73af28acdec37b049d214adbda81d7e2a3dd146f6ed09\"")
);
+ LOCK(cs_main);
+
std::string strHash = params[0].get_str();
uint256 hash(uint256S(strHash));
@@ -326,6 +335,8 @@ Value gettxoutsetinfo(const Array& params, bool fHelp)
+ HelpExampleRpc("gettxoutsetinfo", "")
);
+ LOCK(cs_main);
+
Object ret;
CCoinsStats stats;
@@ -380,6 +391,8 @@ Value gettxout(const Array& params, bool fHelp)
+ HelpExampleRpc("gettxout", "\"txid\", 1")
);
+ LOCK(cs_main);
+
Object ret;
std::string strHash = params[0].get_str();
@@ -436,6 +449,8 @@ Value verifychain(const Array& params, bool fHelp)
+ HelpExampleRpc("verifychain", "")
);
+ LOCK(cs_main);
+
int nCheckLevel = GetArg("-checklevel", 3);
int nCheckDepth = GetArg("-checkblocks", 288);
if (params.size() > 0)
@@ -467,6 +482,8 @@ Value getblockchaininfo(const Array& params, bool fHelp)
+ HelpExampleRpc("getblockchaininfo", "")
);
+ LOCK(cs_main);
+
Object obj;
obj.push_back(Pair("chain", Params().NetworkIDString()));
obj.push_back(Pair("blocks", (int)chainActive.Height()));
@@ -526,6 +543,8 @@ Value getchaintips(const Array& params, bool fHelp)
+ HelpExampleRpc("getchaintips", "")
);
+ LOCK(cs_main);
+
/* Build up a list of chain tips. We start with the list of all
known blocks, and successively remove blocks that appear as pprev
of another block. */
diff --git a/src/rpcdump.cpp b/src/rpcdump.cpp
index 8666779cc1..b9c92a06c5 100644
--- a/src/rpcdump.cpp
+++ b/src/rpcdump.cpp
@@ -91,6 +91,8 @@ Value importprivkey(const Array& params, bool fHelp)
+ HelpExampleRpc("importprivkey", "\"mykey\", \"testing\", false")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
EnsureWalletIsUnlocked();
string strSecret = params[0].get_str();
@@ -158,6 +160,8 @@ Value importaddress(const Array& params, bool fHelp)
+ HelpExampleRpc("importaddress", "\"myaddress\", \"testing\", false")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
CScript script;
CBitcoinAddress address(params[0].get_str());
@@ -223,6 +227,8 @@ Value importwallet(const Array& params, bool fHelp)
+ HelpExampleRpc("importwallet", "\"test\"")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
EnsureWalletIsUnlocked();
ifstream file;
@@ -322,6 +328,8 @@ Value dumpprivkey(const Array& params, bool fHelp)
+ HelpExampleRpc("dumpprivkey", "\"myaddress\"")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
EnsureWalletIsUnlocked();
string strAddress = params[0].get_str();
@@ -351,6 +359,8 @@ Value dumpwallet(const Array& params, bool fHelp)
+ HelpExampleRpc("dumpwallet", "\"test\"")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
EnsureWalletIsUnlocked();
ofstream file;
diff --git a/src/rpcmining.cpp b/src/rpcmining.cpp
index 5df5de66d9..369b3fb4d7 100644
--- a/src/rpcmining.cpp
+++ b/src/rpcmining.cpp
@@ -88,6 +88,7 @@ Value getnetworkhashps(const Array& params, bool fHelp)
+ HelpExampleRpc("getnetworkhashps", "")
);
+ LOCK(cs_main);
return GetNetworkHashPS(params.size() > 0 ? params[0].get_int() : 120, params.size() > 1 ? params[1].get_int() : -1);
}
@@ -107,6 +108,7 @@ Value getgenerate(const Array& params, bool fHelp)
+ HelpExampleRpc("getgenerate", "")
);
+ LOCK(cs_main);
return GetBoolArg("-gen", false);
}
@@ -200,7 +202,6 @@ Value setgenerate(const Array& params, bool fHelp)
return Value::null;
}
-
#endif
@@ -228,6 +229,9 @@ Value getmininginfo(const Array& params, bool fHelp)
+ HelpExampleRpc("getmininginfo", "")
);
+
+ LOCK(cs_main);
+
Object obj;
obj.push_back(Pair("blocks", (int)chainActive.Height()));
obj.push_back(Pair("currentblocksize", (uint64_t)nLastBlockSize));
@@ -268,8 +272,9 @@ Value prioritisetransaction(const Array& params, bool fHelp)
+ HelpExampleRpc("prioritisetransaction", "\"txid\", 0.0, 10000")
);
- uint256 hash = ParseHashStr(params[0].get_str(), "txid");
+ LOCK(cs_main);
+ uint256 hash = ParseHashStr(params[0].get_str(), "txid");
CAmount nAmount = params[2].get_int64();
mempool.PrioritiseTransaction(hash, params[0].get_str(), params[1].get_real(), nAmount);
@@ -358,6 +363,8 @@ Value getblocktemplate(const Array& params, bool fHelp)
+ HelpExampleRpc("getblocktemplate", "")
);
+ LOCK(cs_main);
+
std::string strMode = "template";
Value lpval = Value::null;
if (params.size() > 0)
diff --git a/src/rpcmisc.cpp b/src/rpcmisc.cpp
index 3d647a0d2d..8d260b1cc9 100644
--- a/src/rpcmisc.cpp
+++ b/src/rpcmisc.cpp
@@ -69,6 +69,12 @@ Value getinfo(const Array& params, bool fHelp)
+ HelpExampleRpc("getinfo", "")
);
+#ifdef ENABLE_WALLET
+ LOCK2(cs_main, pwalletMain ? &pwalletMain->cs_wallet : NULL);
+#else
+ LOCK(cs_main);
+#endif
+
proxyType proxy;
GetProxy(NET_IPV4, proxy);
@@ -172,6 +178,12 @@ Value validateaddress(const Array& params, bool fHelp)
+ HelpExampleRpc("validateaddress", "\"1PSSGeFHDnKNxiEyFrD1wcEaHr9hrQDDWc\"")
);
+#ifdef ENABLE_WALLET
+ LOCK2(cs_main, pwalletMain ? &pwalletMain->cs_wallet : NULL);
+#else
+ LOCK(cs_main);
+#endif
+
CBitcoinAddress address(params[0].get_str());
bool isValid = address.IsValid();
@@ -329,6 +341,8 @@ Value verifymessage(const Array& params, bool fHelp)
+ HelpExampleRpc("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", \"signature\", \"my message\"")
);
+ LOCK(cs_main);
+
string strAddress = params[0].get_str();
string strSign = params[1].get_str();
string strMessage = params[2].get_str();
@@ -372,6 +386,8 @@ Value setmocktime(const Array& params, bool fHelp)
if (!Params().MineBlocksOnDemand())
throw runtime_error("setmocktime for regression testing (-regtest mode) only");
+ LOCK(cs_main);
+
RPCTypeCheck(params, boost::assign::list_of(int_type));
SetMockTime(params[0].get_int64());
diff --git a/src/rpcnet.cpp b/src/rpcnet.cpp
index f0fadb5987..6306fd4406 100644
--- a/src/rpcnet.cpp
+++ b/src/rpcnet.cpp
@@ -34,7 +34,8 @@ Value getconnectioncount(const Array& params, bool fHelp)
+ HelpExampleRpc("getconnectioncount", "")
);
- LOCK(cs_vNodes);
+ LOCK2(cs_main, cs_vNodes);
+
return (int)vNodes.size();
}
@@ -52,7 +53,8 @@ Value ping(const Array& params, bool fHelp)
);
// Request that each node send a ping during next message processing pass
- LOCK(cs_vNodes);
+ LOCK2(cs_main, cs_vNodes);
+
BOOST_FOREACH(CNode* pNode, vNodes) {
pNode->fPingQueued = true;
}
@@ -113,6 +115,8 @@ Value getpeerinfo(const Array& params, bool fHelp)
+ HelpExampleRpc("getpeerinfo", "")
);
+ LOCK(cs_main);
+
vector<CNodeStats> vstats;
CopyNodeStats(vstats);
@@ -411,6 +415,8 @@ Value getnetworkinfo(const Array& params, bool fHelp)
+ HelpExampleRpc("getnetworkinfo", "")
);
+ LOCK(cs_main);
+
Object obj;
obj.push_back(Pair("version", CLIENT_VERSION));
obj.push_back(Pair("subversion",
diff --git a/src/rpcrawtransaction.cpp b/src/rpcrawtransaction.cpp
index a3b0e47d00..4a079f5c81 100644
--- a/src/rpcrawtransaction.cpp
+++ b/src/rpcrawtransaction.cpp
@@ -169,6 +169,8 @@ Value getrawtransaction(const Array& params, bool fHelp)
+ HelpExampleRpc("getrawtransaction", "\"mytxid\", 1")
);
+ LOCK(cs_main);
+
uint256 hash = ParseHashV(params[0], "parameter 1");
bool fVerbose = false;
@@ -256,6 +258,7 @@ Value listunspent(const Array& params, bool fHelp)
Array results;
vector<COutput> vecOutputs;
assert(pwalletMain != NULL);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
pwalletMain->AvailableCoins(vecOutputs, false);
BOOST_FOREACH(const COutput& out, vecOutputs) {
if (out.nDepth < nMinDepth || out.nDepth > nMaxDepth)
@@ -334,6 +337,7 @@ Value createrawtransaction(const Array& params, bool fHelp)
+ HelpExampleRpc("createrawtransaction", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\", \"{\\\"address\\\":0.01}\"")
);
+ LOCK(cs_main);
RPCTypeCheck(params, boost::assign::list_of(array_type)(obj_type));
Array inputs = params[0].get_array();
@@ -428,6 +432,7 @@ Value decoderawtransaction(const Array& params, bool fHelp)
+ HelpExampleRpc("decoderawtransaction", "\"hexstring\"")
);
+ LOCK(cs_main);
RPCTypeCheck(params, boost::assign::list_of(str_type));
CTransaction tx;
@@ -466,6 +471,7 @@ Value decodescript(const Array& params, bool fHelp)
+ HelpExampleRpc("decodescript", "\"hexstring\"")
);
+ LOCK(cs_main);
RPCTypeCheck(params, boost::assign::list_of(str_type));
Object r;
@@ -532,6 +538,11 @@ Value signrawtransaction(const Array& params, bool fHelp)
+ HelpExampleRpc("signrawtransaction", "\"myhex\"")
);
+#ifdef ENABLE_WALLET
+ LOCK2(cs_main, pwalletMain ? &pwalletMain->cs_wallet : NULL);
+#else
+ LOCK(cs_main);
+#endif
RPCTypeCheck(params, boost::assign::list_of(str_type)(array_type)(array_type)(str_type), true);
vector<unsigned char> txData(ParseHexV(params[0], "argument 1"));
@@ -591,7 +602,7 @@ Value signrawtransaction(const Array& params, bool fHelp)
}
}
#ifdef ENABLE_WALLET
- else
+ else if (pwalletMain)
EnsureWalletIsUnlocked();
#endif
@@ -722,6 +733,7 @@ Value sendrawtransaction(const Array& params, bool fHelp)
+ HelpExampleRpc("sendrawtransaction", "\"signedhex\"")
);
+ LOCK(cs_main);
RPCTypeCheck(params, boost::assign::list_of(str_type)(bool_type));
// parse hex string from parameter
diff --git a/src/rpcserver.cpp b/src/rpcserver.cpp
index e4f23d56d2..823b1fcf24 100644
--- a/src/rpcserver.cpp
+++ b/src/rpcserver.cpp
@@ -7,9 +7,11 @@
#include "base58.h"
#include "init.h"
-#include "main.h"
+#include "random.h"
+#include "sync.h"
#include "ui_interface.h"
#include "util.h"
+#include "utilstrencodings.h"
#ifdef ENABLE_WALLET
#include "wallet.h"
#endif
@@ -23,11 +25,13 @@
#include <boost/iostreams/concepts.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/shared_ptr.hpp>
+#include <boost/signals2/signal.hpp>
#include <boost/thread.hpp>
#include "json/json_spirit_writer_template.h"
using namespace boost::asio;
using namespace json_spirit;
+using namespace RPCServer;
using namespace std;
static std::string strRPCUserColonPass;
@@ -46,6 +50,34 @@ static boost::asio::io_service::work *rpc_dummy_work = NULL;
static std::vector<CSubNet> rpc_allow_subnets; //!< List of subnets to allow RPC connections from
static std::vector< boost::shared_ptr<ip::tcp::acceptor> > rpc_acceptors;
+static struct CRPCSignals
+{
+ boost::signals2::signal<void ()> Started;
+ boost::signals2::signal<void ()> Stopped;
+ boost::signals2::signal<void (const CRPCCommand&)> PreCommand;
+ boost::signals2::signal<void (const CRPCCommand&)> PostCommand;
+} g_rpcSignals;
+
+void RPCServer::OnStarted(boost::function<void ()> slot)
+{
+ g_rpcSignals.Started.connect(slot);
+}
+
+void RPCServer::OnStopped(boost::function<void ()> slot)
+{
+ g_rpcSignals.Stopped.connect(slot);
+}
+
+void RPCServer::OnPreCommand(boost::function<void (const CRPCCommand&)> slot)
+{
+ g_rpcSignals.PreCommand.connect(boost::bind(slot, _1));
+}
+
+void RPCServer::OnPostCommand(boost::function<void (const CRPCCommand&)> slot)
+{
+ g_rpcSignals.PostCommand.connect(boost::bind(slot, _1));
+}
+
void RPCTypeCheck(const Array& params,
const list<Value_type>& typesExpected,
bool fAllowNull)
@@ -239,112 +271,110 @@ Value stop(const Array& params, bool fHelp)
* Call Table
*/
static const CRPCCommand vRPCCommands[] =
-{ // category name actor (function) okSafeMode threadSafe reqWallet
- // --------------------- ------------------------ ----------------------- ---------- ---------- ---------
+{ // category name actor (function) okSafeMode reqWallet
+ // --------------------- ------------------------ ----------------------- ---------- ---------
/* Overall control/query calls */
- { "control", "getinfo", &getinfo, true, false, false }, /* uses wallet if enabled */
- { "control", "help", &help, true, true, false },
- { "control", "stop", &stop, true, true, false },
+ { "control", "getinfo", &getinfo, true, false }, /* uses wallet if enabled */
+ { "control", "help", &help, true, false },
+ { "control", "stop", &stop, true, false },
/* P2P networking */
- { "network", "getnetworkinfo", &getnetworkinfo, true, false, false },
- { "network", "addnode", &addnode, true, true, false },
- { "network", "getaddednodeinfo", &getaddednodeinfo, true, true, false },
- { "network", "getconnectioncount", &getconnectioncount, true, false, false },
- { "network", "getnettotals", &getnettotals, true, true, false },
- { "network", "getpeerinfo", &getpeerinfo, true, false, false },
- { "network", "ping", &ping, true, false, false },
+ { "network", "getnetworkinfo", &getnetworkinfo, true, false },
+ { "network", "addnode", &addnode, true, false },
+ { "network", "getaddednodeinfo", &getaddednodeinfo, true, false },
+ { "network", "getconnectioncount", &getconnectioncount, true, false },
+ { "network", "getnettotals", &getnettotals, true, false },
+ { "network", "getpeerinfo", &getpeerinfo, true, false },
+ { "network", "ping", &ping, true, false },
/* Block chain and UTXO */
- { "blockchain", "getblockchaininfo", &getblockchaininfo, true, false, false },
- { "blockchain", "getbestblockhash", &getbestblockhash, true, false, false },
- { "blockchain", "getblockcount", &getblockcount, true, false, false },
- { "blockchain", "getblock", &getblock, true, false, false },
- { "blockchain", "getblockhash", &getblockhash, true, false, false },
- { "blockchain", "getchaintips", &getchaintips, true, false, false },
- { "blockchain", "getdifficulty", &getdifficulty, true, false, false },
- { "blockchain", "getmempoolinfo", &getmempoolinfo, true, true, false },
- { "blockchain", "getrawmempool", &getrawmempool, true, false, false },
- { "blockchain", "gettxout", &gettxout, true, false, false },
- { "blockchain", "gettxoutsetinfo", &gettxoutsetinfo, true, false, false },
- { "blockchain", "verifychain", &verifychain, true, false, false },
- { "blockchain", "invalidateblock", &invalidateblock, true, true, false },
- { "blockchain", "reconsiderblock", &reconsiderblock, true, true, false },
+ { "blockchain", "getblockchaininfo", &getblockchaininfo, true, false },
+ { "blockchain", "getbestblockhash", &getbestblockhash, true, false },
+ { "blockchain", "getblockcount", &getblockcount, true, false },
+ { "blockchain", "getblock", &getblock, true, false },
+ { "blockchain", "getblockhash", &getblockhash, true, false },
+ { "blockchain", "getchaintips", &getchaintips, true, false },
+ { "blockchain", "getdifficulty", &getdifficulty, true, false },
+ { "blockchain", "getmempoolinfo", &getmempoolinfo, true, false },
+ { "blockchain", "getrawmempool", &getrawmempool, true, false },
+ { "blockchain", "gettxout", &gettxout, true, false },
+ { "blockchain", "gettxoutsetinfo", &gettxoutsetinfo, true, false },
+ { "blockchain", "verifychain", &verifychain, true, false },
/* Mining */
- { "mining", "getblocktemplate", &getblocktemplate, true, false, false },
- { "mining", "getmininginfo", &getmininginfo, true, false, false },
- { "mining", "getnetworkhashps", &getnetworkhashps, true, false, false },
- { "mining", "prioritisetransaction", &prioritisetransaction, true, false, false },
- { "mining", "submitblock", &submitblock, true, true, false },
+ { "mining", "getblocktemplate", &getblocktemplate, true, false },
+ { "mining", "getmininginfo", &getmininginfo, true, false },
+ { "mining", "getnetworkhashps", &getnetworkhashps, true, false },
+ { "mining", "prioritisetransaction", &prioritisetransaction, true, false },
+ { "mining", "submitblock", &submitblock, true, false },
#ifdef ENABLE_WALLET
/* Coin generation */
- { "generating", "getgenerate", &getgenerate, true, false, false },
- { "generating", "setgenerate", &setgenerate, true, true, false },
+ { "generating", "getgenerate", &getgenerate, true, false },
+ { "generating", "setgenerate", &setgenerate, true, false },
#endif
/* Raw transactions */
- { "rawtransactions", "createrawtransaction", &createrawtransaction, true, false, false },
- { "rawtransactions", "decoderawtransaction", &decoderawtransaction, true, false, false },
- { "rawtransactions", "decodescript", &decodescript, true, false, false },
- { "rawtransactions", "getrawtransaction", &getrawtransaction, true, false, false },
- { "rawtransactions", "sendrawtransaction", &sendrawtransaction, false, false, false },
- { "rawtransactions", "signrawtransaction", &signrawtransaction, false, false, false }, /* uses wallet if enabled */
+ { "rawtransactions", "createrawtransaction", &createrawtransaction, true, false },
+ { "rawtransactions", "decoderawtransaction", &decoderawtransaction, true, false },
+ { "rawtransactions", "decodescript", &decodescript, true, false },
+ { "rawtransactions", "getrawtransaction", &getrawtransaction, true, false },
+ { "rawtransactions", "sendrawtransaction", &sendrawtransaction, false, false },
+ { "rawtransactions", "signrawtransaction", &signrawtransaction, false, false }, /* uses wallet if enabled */
/* Utility functions */
- { "util", "createmultisig", &createmultisig, true, true , false },
- { "util", "validateaddress", &validateaddress, true, false, false }, /* uses wallet if enabled */
- { "util", "verifymessage", &verifymessage, true, false, false },
- { "util", "estimatefee", &estimatefee, true, true, false },
- { "util", "estimatepriority", &estimatepriority, true, true, false },
+ { "util", "createmultisig", &createmultisig, true, false },
+ { "util", "validateaddress", &validateaddress, true, false }, /* uses wallet if enabled */
+ { "util", "verifymessage", &verifymessage, true, false },
+ { "util", "estimatefee", &estimatefee, true, false },
+ { "util", "estimatepriority", &estimatepriority, true, false },
/* Not shown in help */
- { "hidden", "invalidateblock", &invalidateblock, true, true, false },
- { "hidden", "reconsiderblock", &reconsiderblock, true, true, false },
- { "hidden", "setmocktime", &setmocktime, true, false, false },
+ { "hidden", "invalidateblock", &invalidateblock, true, false },
+ { "hidden", "reconsiderblock", &reconsiderblock, true, false },
+ { "hidden", "setmocktime", &setmocktime, true, false },
#ifdef ENABLE_WALLET
/* Wallet */
- { "wallet", "addmultisigaddress", &addmultisigaddress, true, false, true },
- { "wallet", "backupwallet", &backupwallet, true, false, true },
- { "wallet", "dumpprivkey", &dumpprivkey, true, false, true },
- { "wallet", "dumpwallet", &dumpwallet, true, false, true },
- { "wallet", "encryptwallet", &encryptwallet, true, false, true },
- { "wallet", "getaccountaddress", &getaccountaddress, true, false, true },
- { "wallet", "getaccount", &getaccount, true, false, true },
- { "wallet", "getaddressesbyaccount", &getaddressesbyaccount, true, false, true },
- { "wallet", "getbalance", &getbalance, false, false, true },
- { "wallet", "getnewaddress", &getnewaddress, true, false, true },
- { "wallet", "getrawchangeaddress", &getrawchangeaddress, true, false, true },
- { "wallet", "getreceivedbyaccount", &getreceivedbyaccount, false, false, true },
- { "wallet", "getreceivedbyaddress", &getreceivedbyaddress, false, false, true },
- { "wallet", "gettransaction", &gettransaction, false, false, true },
- { "wallet", "getunconfirmedbalance", &getunconfirmedbalance, false, false, true },
- { "wallet", "getwalletinfo", &getwalletinfo, false, false, true },
- { "wallet", "importprivkey", &importprivkey, true, false, true },
- { "wallet", "importwallet", &importwallet, true, false, true },
- { "wallet", "importaddress", &importaddress, true, false, true },
- { "wallet", "keypoolrefill", &keypoolrefill, true, false, true },
- { "wallet", "listaccounts", &listaccounts, false, false, true },
- { "wallet", "listaddressgroupings", &listaddressgroupings, false, false, true },
- { "wallet", "listlockunspent", &listlockunspent, false, false, true },
- { "wallet", "listreceivedbyaccount", &listreceivedbyaccount, false, false, true },
- { "wallet", "listreceivedbyaddress", &listreceivedbyaddress, false, false, true },
- { "wallet", "listsinceblock", &listsinceblock, false, false, true },
- { "wallet", "listtransactions", &listtransactions, false, false, true },
- { "wallet", "listunspent", &listunspent, false, false, true },
- { "wallet", "lockunspent", &lockunspent, true, false, true },
- { "wallet", "move", &movecmd, false, false, true },
- { "wallet", "sendfrom", &sendfrom, false, false, true },
- { "wallet", "sendmany", &sendmany, false, false, true },
- { "wallet", "sendtoaddress", &sendtoaddress, false, false, true },
- { "wallet", "setaccount", &setaccount, true, false, true },
- { "wallet", "settxfee", &settxfee, true, false, true },
- { "wallet", "signmessage", &signmessage, true, false, true },
- { "wallet", "walletlock", &walletlock, true, false, true },
- { "wallet", "walletpassphrasechange", &walletpassphrasechange, true, false, true },
- { "wallet", "walletpassphrase", &walletpassphrase, true, false, true },
+ { "wallet", "addmultisigaddress", &addmultisigaddress, true, true },
+ { "wallet", "backupwallet", &backupwallet, true, true },
+ { "wallet", "dumpprivkey", &dumpprivkey, true, true },
+ { "wallet", "dumpwallet", &dumpwallet, true, true },
+ { "wallet", "encryptwallet", &encryptwallet, true, true },
+ { "wallet", "getaccountaddress", &getaccountaddress, true, true },
+ { "wallet", "getaccount", &getaccount, true, true },
+ { "wallet", "getaddressesbyaccount", &getaddressesbyaccount, true, true },
+ { "wallet", "getbalance", &getbalance, false, true },
+ { "wallet", "getnewaddress", &getnewaddress, true, true },
+ { "wallet", "getrawchangeaddress", &getrawchangeaddress, true, true },
+ { "wallet", "getreceivedbyaccount", &getreceivedbyaccount, false, true },
+ { "wallet", "getreceivedbyaddress", &getreceivedbyaddress, false, true },
+ { "wallet", "gettransaction", &gettransaction, false, true },
+ { "wallet", "getunconfirmedbalance", &getunconfirmedbalance, false, true },
+ { "wallet", "getwalletinfo", &getwalletinfo, false, true },
+ { "wallet", "importprivkey", &importprivkey, true, true },
+ { "wallet", "importwallet", &importwallet, true, true },
+ { "wallet", "importaddress", &importaddress, true, true },
+ { "wallet", "keypoolrefill", &keypoolrefill, true, true },
+ { "wallet", "listaccounts", &listaccounts, false, true },
+ { "wallet", "listaddressgroupings", &listaddressgroupings, false, true },
+ { "wallet", "listlockunspent", &listlockunspent, false, true },
+ { "wallet", "listreceivedbyaccount", &listreceivedbyaccount, false, true },
+ { "wallet", "listreceivedbyaddress", &listreceivedbyaddress, false, true },
+ { "wallet", "listsinceblock", &listsinceblock, false, true },
+ { "wallet", "listtransactions", &listtransactions, false, true },
+ { "wallet", "listunspent", &listunspent, false, true },
+ { "wallet", "lockunspent", &lockunspent, true, true },
+ { "wallet", "move", &movecmd, false, true },
+ { "wallet", "sendfrom", &sendfrom, false, true },
+ { "wallet", "sendmany", &sendmany, false, true },
+ { "wallet", "sendtoaddress", &sendtoaddress, false, true },
+ { "wallet", "setaccount", &setaccount, true, true },
+ { "wallet", "settxfee", &settxfee, true, true },
+ { "wallet", "signmessage", &signmessage, true, true },
+ { "wallet", "walletlock", &walletlock, true, true },
+ { "wallet", "walletpassphrasechange", &walletpassphrasechange, true, true },
+ { "wallet", "walletpassphrase", &walletpassphrase, true, true },
#endif // ENABLE_WALLET
};
@@ -693,6 +723,7 @@ void StartRPCThreads()
for (int i = 0; i < GetArg("-rpcthreads", 4); i++)
rpc_worker_group->create_thread(boost::bind(&boost::asio::io_service::run, rpc_io_service));
fRPCRunning = true;
+ g_rpcSignals.Started();
}
void StartDummyRPCThread()
@@ -735,7 +766,7 @@ void StopRPCThreads()
deadlineTimers.clear();
rpc_io_service->stop();
- cvBlockChange.notify_all();
+ g_rpcSignals.Stopped();
if (rpc_worker_group != NULL)
rpc_worker_group->join_all();
delete rpc_dummy_work; rpc_dummy_work = NULL;
@@ -978,45 +1009,20 @@ json_spirit::Value CRPCTable::execute(const std::string &strMethod, const json_s
const CRPCCommand *pcmd = tableRPC[strMethod];
if (!pcmd)
throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found");
-#ifdef ENABLE_WALLET
- if (pcmd->reqWallet && !pwalletMain)
- throw JSONRPCError(RPC_METHOD_NOT_FOUND, "Method not found (disabled)");
-#endif
- // Observe safe mode
- string strWarning = GetWarnings("rpc");
- if (strWarning != "" && !GetBoolArg("-disablesafemode", false) &&
- !pcmd->okSafeMode)
- throw JSONRPCError(RPC_FORBIDDEN_BY_SAFE_MODE, string("Safe mode: ") + strWarning);
+ g_rpcSignals.PreCommand(*pcmd);
try
{
// Execute
- Value result;
- {
- if (pcmd->threadSafe)
- result = pcmd->actor(params, false);
-#ifdef ENABLE_WALLET
- else if (!pwalletMain) {
- LOCK(cs_main);
- result = pcmd->actor(params, false);
- } else {
- LOCK2(cs_main, pwalletMain->cs_wallet);
- result = pcmd->actor(params, false);
- }
-#else // ENABLE_WALLET
- else {
- LOCK(cs_main);
- result = pcmd->actor(params, false);
- }
-#endif // !ENABLE_WALLET
- }
- return result;
+ return pcmd->actor(params, false);
}
catch (const std::exception& e)
{
throw JSONRPCError(RPC_MISC_ERROR, e.what());
}
+
+ g_rpcSignals.PostCommand(*pcmd);
}
std::string HelpExampleCli(string methodname, string args){
diff --git a/src/rpcserver.h b/src/rpcserver.h
index 1b94b758f2..f63438ecb8 100644
--- a/src/rpcserver.h
+++ b/src/rpcserver.h
@@ -19,6 +19,16 @@
#include "json/json_spirit_utils.h"
#include "json/json_spirit_writer_template.h"
+class CRPCCommand;
+
+namespace RPCServer
+{
+ void OnStarted(boost::function<void ()> slot);
+ void OnStopped(boost::function<void ()> slot);
+ void OnPreCommand(boost::function<void (const CRPCCommand&)> slot);
+ void OnPostCommand(boost::function<void (const CRPCCommand&)> slot);
+}
+
class CBlockIndex;
class CNetAddr;
@@ -88,7 +98,6 @@ public:
std::string name;
rpcfn_type actor;
bool okSafeMode;
- bool threadSafe;
bool reqWallet;
};
diff --git a/src/rpcwallet.cpp b/src/rpcwallet.cpp
index 28371771a9..1afc3c910e 100644
--- a/src/rpcwallet.cpp
+++ b/src/rpcwallet.cpp
@@ -90,6 +90,8 @@ Value getnewaddress(const Array& params, bool fHelp)
+ HelpExampleRpc("getnewaddress", "")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
// Parse the account first so we don't generate a key if there's an error
string strAccount;
if (params.size() > 0)
@@ -164,13 +166,14 @@ Value getaccountaddress(const Array& params, bool fHelp)
+ HelpExampleRpc("getaccountaddress", "\"myaccount\"")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
// Parse the account first so we don't generate a key if there's an error
string strAccount = AccountFromValue(params[0]);
Value ret;
ret = GetAccountAddress(strAccount).ToString();
-
return ret;
}
@@ -189,6 +192,8 @@ Value getrawchangeaddress(const Array& params, bool fHelp)
+ HelpExampleRpc("getrawchangeaddress", "")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
if (!pwalletMain->IsLocked())
pwalletMain->TopUpKeyPool();
@@ -219,11 +224,12 @@ Value setaccount(const Array& params, bool fHelp)
+ HelpExampleRpc("setaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", \"tabby\"")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
CBitcoinAddress address(params[0].get_str());
if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
-
string strAccount;
if (params.size() > 1)
strAccount = AccountFromValue(params[1]);
@@ -262,6 +268,8 @@ Value getaccount(const Array& params, bool fHelp)
+ HelpExampleRpc("getaccount", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\"")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
CBitcoinAddress address(params[0].get_str());
if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
@@ -292,6 +300,8 @@ Value getaddressesbyaccount(const Array& params, bool fHelp)
+ HelpExampleRpc("getaddressesbyaccount", "\"tabby\"")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
string strAccount = AccountFromValue(params[0]);
// Find all addresses that have the given account
@@ -363,6 +373,8 @@ Value sendtoaddress(const Array& params, bool fHelp)
+ HelpExampleRpc("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.1, \"donation\", \"seans outpost\"")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
CBitcoinAddress address(params[0].get_str());
if (!address.IsValid())
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
@@ -409,6 +421,8 @@ Value listaddressgroupings(const Array& params, bool fHelp)
+ HelpExampleRpc("listaddressgroupings", "")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
Array jsonGroupings;
map<CTxDestination, CAmount> balances = pwalletMain->GetAddressBalances();
BOOST_FOREACH(set<CTxDestination> grouping, pwalletMain->GetAddressGroupings())
@@ -454,6 +468,8 @@ Value signmessage(const Array& params, bool fHelp)
+ HelpExampleRpc("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", \"my message\"")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
EnsureWalletIsUnlocked();
string strAddress = params[0].get_str();
@@ -504,6 +520,8 @@ Value getreceivedbyaddress(const Array& params, bool fHelp)
+ HelpExampleRpc("getreceivedbyaddress", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\", 6")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
// Bitcoin address
CBitcoinAddress address = CBitcoinAddress(params[0].get_str());
if (!address.IsValid())
@@ -557,6 +575,8 @@ Value getreceivedbyaccount(const Array& params, bool fHelp)
+ HelpExampleRpc("getreceivedbyaccount", "\"tabby\", 6")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
// Minimum confirmations
int nMinDepth = 1;
if (params.size() > 1)
@@ -643,6 +663,8 @@ Value getbalance(const Array& params, bool fHelp)
+ HelpExampleRpc("getbalance", "\"*\", 6")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
if (params.size() == 0)
return ValueFromAmount(pwalletMain->GetBalance());
@@ -695,6 +717,9 @@ Value getunconfirmedbalance(const Array &params, bool fHelp)
throw runtime_error(
"getunconfirmedbalance\n"
"Returns the server's total unconfirmed balance\n");
+
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
return ValueFromAmount(pwalletMain->GetUnconfirmedBalance());
}
@@ -721,6 +746,8 @@ Value movecmd(const Array& params, bool fHelp)
+ HelpExampleRpc("move", "\"timotei\", \"akiko\", 0.01, 6, \"happy birthday!\"")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
string strFrom = AccountFromValue(params[0]);
string strTo = AccountFromValue(params[1]);
CAmount nAmount = AmountFromValue(params[2]);
@@ -793,6 +820,8 @@ Value sendfrom(const Array& params, bool fHelp)
+ HelpExampleRpc("sendfrom", "\"tabby\", \"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\", 0.01, 6, \"donation\", \"seans outpost\"")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
string strAccount = AccountFromValue(params[0]);
CBitcoinAddress address(params[1].get_str());
if (!address.IsValid())
@@ -850,6 +879,8 @@ Value sendmany(const Array& params, bool fHelp)
+ HelpExampleRpc("sendmany", "\"\", \"{\\\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XZ\\\":0.01,\\\"1353tsE8YMTA4EuV7dgUXGjNFf9KpVvKHz\\\":0.02}\", 6, \"testing\"")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
string strAccount = AccountFromValue(params[0]);
Object sendTo = params[1].get_obj();
int nMinDepth = 1;
@@ -935,6 +966,8 @@ Value addmultisigaddress(const Array& params, bool fHelp)
throw runtime_error(msg);
}
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
string strAccount;
if (params.size() > 2)
strAccount = AccountFromValue(params[2]);
@@ -1110,6 +1143,8 @@ Value listreceivedbyaddress(const Array& params, bool fHelp)
+ HelpExampleRpc("listreceivedbyaddress", "6, true, true")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
return ListReceived(params, false);
}
@@ -1141,6 +1176,8 @@ Value listreceivedbyaccount(const Array& params, bool fHelp)
+ HelpExampleRpc("listreceivedbyaccount", "6, true, true")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
return ListReceived(params, true);
}
@@ -1292,6 +1329,8 @@ Value listtransactions(const Array& params, bool fHelp)
+ HelpExampleRpc("listtransactions", "\"*\", 20, 100")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
string strAccount = "*";
if (params.size() > 0)
strAccount = params[0].get_str();
@@ -1372,6 +1411,8 @@ Value listaccounts(const Array& params, bool fHelp)
+ HelpExampleRpc("listaccounts", "6")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
int nMinDepth = 1;
if (params.size() > 0)
nMinDepth = params[0].get_int();
@@ -1460,6 +1501,8 @@ Value listsinceblock(const Array& params, bool fHelp)
+ HelpExampleRpc("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\", 6")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
CBlockIndex *pindex = NULL;
int target_confirms = 1;
isminefilter filter = ISMINE_SPENDABLE;
@@ -1546,6 +1589,8 @@ Value gettransaction(const Array& params, bool fHelp)
+ HelpExampleRpc("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
uint256 hash;
hash.SetHex(params[0].get_str());
@@ -1594,6 +1639,8 @@ Value backupwallet(const Array& params, bool fHelp)
+ HelpExampleRpc("backupwallet", "\"backup.dat\"")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
string strDest = params[0].get_str();
if (!BackupWallet(*pwalletMain, strDest))
throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
@@ -1616,6 +1663,8 @@ Value keypoolrefill(const Array& params, bool fHelp)
+ HelpExampleRpc("keypoolrefill", "")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
// 0 is interpreted by TopUpKeyPool() as the default keypool size given by -keypool
unsigned int kpSize = 0;
if (params.size() > 0) {
@@ -1663,6 +1712,8 @@ Value walletpassphrase(const Array& params, bool fHelp)
+ HelpExampleRpc("walletpassphrase", "\"my pass phrase\", 60")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
if (fHelp)
return true;
if (!pwalletMain->IsCrypted())
@@ -1710,6 +1761,8 @@ Value walletpassphrasechange(const Array& params, bool fHelp)
+ HelpExampleRpc("walletpassphrasechange", "\"old one\", \"new one\"")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
if (fHelp)
return true;
if (!pwalletMain->IsCrypted())
@@ -1756,6 +1809,8 @@ Value walletlock(const Array& params, bool fHelp)
+ HelpExampleRpc("walletlock", "")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
if (fHelp)
return true;
if (!pwalletMain->IsCrypted())
@@ -1797,6 +1852,8 @@ Value encryptwallet(const Array& params, bool fHelp)
+ HelpExampleRpc("encryptwallet", "\"my pass phrase\"")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
if (fHelp)
return true;
if (pwalletMain->IsCrypted())
@@ -1861,6 +1918,8 @@ Value lockunspent(const Array& params, bool fHelp)
+ HelpExampleRpc("lockunspent", "false, \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
if (params.size() == 1)
RPCTypeCheck(params, boost::assign::list_of(bool_type));
else
@@ -1930,6 +1989,8 @@ Value listlockunspent(const Array& params, bool fHelp)
+ HelpExampleRpc("listlockunspent", "")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
vector<COutPoint> vOutpts;
pwalletMain->ListLockedCoins(vOutpts);
@@ -1961,6 +2022,8 @@ Value settxfee(const Array& params, bool fHelp)
+ HelpExampleRpc("settxfee", "0.00001")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
// Amount
CAmount nAmount = 0;
if (params[0].get_real() != 0.0)
@@ -1992,6 +2055,8 @@ Value getwalletinfo(const Array& params, bool fHelp)
+ HelpExampleRpc("getwalletinfo", "")
);
+ LOCK2(cs_main, pwalletMain->cs_wallet);
+
Object obj;
obj.push_back(Pair("walletversion", pwalletMain->GetVersion()));
obj.push_back(Pair("balance", ValueFromAmount(pwalletMain->GetBalance())));
diff --git a/src/sync.h b/src/sync.h
index 7891e41560..27e80e813b 100644
--- a/src/sync.h
+++ b/src/sync.h
@@ -142,6 +142,17 @@ public:
Enter(pszName, pszFile, nLine);
}
+ CMutexLock(Mutex* pmutexIn, const char* pszName, const char* pszFile, int nLine, bool fTry = false)
+ {
+ if (!pmutexIn) return;
+
+ lock = boost::unique_lock<Mutex>(*pmutexIn, boost::defer_lock);
+ if (fTry)
+ TryEnter(pszName, pszFile, nLine);
+ else
+ Enter(pszName, pszFile, nLine);
+ }
+
~CMutexLock()
{
if (lock.owns_lock())