#include <boost/shared_ptr.hpp>
#include <boost/signals2/signal.hpp>
#include <boost/thread.hpp>
-#include "json/json_spirit_writer_template.h"
+
+#include <univalue.h>
using namespace boost::asio;
-using namespace json_spirit;
using namespace RPCServer;
using namespace std;
g_rpcSignals.PostCommand.connect(boost::bind(slot, _1));
}
-void RPCTypeCheck(const Array& params,
- const list<Value_type>& typesExpected,
+void RPCTypeCheck(const UniValue& params,
+ const list<UniValue::VType>& typesExpected,
bool fAllowNull)
{
- unsigned int i = 0;
- BOOST_FOREACH(Value_type t, typesExpected)
+ size_t i = 0;
+ BOOST_FOREACH(UniValue::VType t, typesExpected)
{
if (params.size() <= i)
break;
- const Value& v = params[i];
- if (!((v.type() == t) || (fAllowNull && (v.type() == null_type))))
+ const UniValue& v = params[i];
+ if (!((v.type() == t) || (fAllowNull && (v.isNull()))))
{
string err = strprintf("Expected type %s, got %s",
- Value_type_name[t], Value_type_name[v.type()]);
+ uvTypeName(t), uvTypeName(v.type()));
throw JSONRPCError(RPC_TYPE_ERROR, err);
}
i++;
}
}
-void RPCTypeCheck(const Object& o,
- const map<string, Value_type>& typesExpected,
+void RPCTypeCheckObj(const UniValue& o,
+ const map<string, UniValue::VType>& typesExpected,
bool fAllowNull)
{
- BOOST_FOREACH(const PAIRTYPE(string, Value_type)& t, typesExpected)
+ BOOST_FOREACH(const PAIRTYPE(string, UniValue::VType)& t, typesExpected)
{
- const Value& v = find_value(o, t.first);
- if (!fAllowNull && v.type() == null_type)
+ const UniValue& v = find_value(o, t.first);
+ if (!fAllowNull && v.isNull())
throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Missing %s", t.first));
- if (!((v.type() == t.second) || (fAllowNull && (v.type() == null_type))))
+ if (!((v.type() == t.second) || (fAllowNull && (v.isNull()))))
{
string err = strprintf("Expected type %s for %s, got %s",
- Value_type_name[t.second], t.first, Value_type_name[v.type()]);
+ uvTypeName(t.second), t.first, uvTypeName(v.type()));
throw JSONRPCError(RPC_TYPE_ERROR, err);
}
}
}
-static inline int64_t roundint64(double d)
+CAmount AmountFromValue(const UniValue& value)
{
- return (int64_t)(d > 0 ? d + 0.5 : d - 0.5);
-}
-
-CAmount AmountFromValue(const Value& value)
-{
- double dAmount = value.get_real();
- if (dAmount <= 0.0 || dAmount > 21000000.0)
- throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount");
- CAmount nAmount = roundint64(dAmount * COIN);
- if (!MoneyRange(nAmount))
+ if (!value.isNum() && !value.isStr())
+ throw JSONRPCError(RPC_TYPE_ERROR, "Amount is not a number or string");
+ CAmount amount;
+ if (!ParseFixedPoint(value.getValStr(), 8, &amount))
throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount");
- return nAmount;
+ if (!MoneyRange(amount))
+ throw JSONRPCError(RPC_TYPE_ERROR, "Amount out of range");
+ return amount;
}
-Value ValueFromAmount(const CAmount& amount)
+UniValue ValueFromAmount(const CAmount& amount)
{
- return (double)amount / (double)COIN;
+ bool sign = amount < 0;
+ int64_t n_abs = (sign ? -amount : amount);
+ int64_t quotient = n_abs / COIN;
+ int64_t remainder = n_abs % COIN;
+ return UniValue(UniValue::VNUM,
+ strprintf("%s%d.%08d", sign ? "-" : "", quotient, remainder));
}
-uint256 ParseHashV(const Value& v, string strName)
+uint256 ParseHashV(const UniValue& v, string strName)
{
string strHex;
- if (v.type() == str_type)
+ if (v.isStr())
strHex = v.get_str();
if (!IsHex(strHex)) // Note: IsHex("") is false
throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')");
result.SetHex(strHex);
return result;
}
-uint256 ParseHashO(const Object& o, string strKey)
+uint256 ParseHashO(const UniValue& o, string strKey)
{
return ParseHashV(find_value(o, strKey), strKey);
}
-vector<unsigned char> ParseHexV(const Value& v, string strName)
+vector<unsigned char> ParseHexV(const UniValue& v, string strName)
{
string strHex;
- if (v.type() == str_type)
+ if (v.isStr())
strHex = v.get_str();
if (!IsHex(strHex))
throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')");
return ParseHex(strHex);
}
-vector<unsigned char> ParseHexO(const Object& o, string strKey)
+vector<unsigned char> ParseHexO(const UniValue& o, string strKey)
{
return ParseHexV(find_value(o, strKey), strKey);
}
* Note: This interface may still be subject to change.
*/
-string CRPCTable::help(string strCommand) const
+std::string CRPCTable::help(const std::string& strCommand) const
{
string strRet;
string category;
continue;
try
{
- Array params;
+ UniValue params;
rpcfn_type pfn = pcmd->actor;
if (setDone.insert(pfn).second)
(*pfn)(params, true);
return strRet;
}
-Value help(const Array& params, bool fHelp)
+UniValue help(const UniValue& params, bool fHelp)
{
if (fHelp || params.size() > 1)
throw runtime_error(
}
-Value stop(const Array& params, bool fHelp)
+UniValue stop(const UniValue& params, bool fHelp)
{
// Accept the deprecated and ignored 'detach' boolean argument
if (fHelp || params.size() > 1)
/* P2P networking */
{ "network", "getnetworkinfo", &getnetworkinfo, true },
{ "network", "addnode", &addnode, true },
+ { "network", "disconnectnode", &disconnectnode, true },
{ "network", "getaddednodeinfo", &getaddednodeinfo, true },
{ "network", "getconnectioncount", &getconnectioncount, true },
{ "network", "getnettotals", &getnettotals, true },
{ "network", "getpeerinfo", &getpeerinfo, true },
{ "network", "ping", &ping, true },
+ { "network", "setban", &setban, true },
+ { "network", "listbanned", &listbanned, true },
+ { "network", "clearbanned", &clearbanned, true },
/* Block chain and UTXO */
{ "blockchain", "getblockchaininfo", &getblockchaininfo, true },
{ "blockchain", "getblockcount", &getblockcount, true },
{ "blockchain", "getblock", &getblock, true },
{ "blockchain", "getblockhash", &getblockhash, true },
+ { "blockchain", "getblockheader", &getblockheader, true },
{ "blockchain", "getchaintips", &getchaintips, true },
{ "blockchain", "getdifficulty", &getdifficulty, true },
{ "blockchain", "getmempoolinfo", &getmempoolinfo, true },
{ "mining", "submitblock", &submitblock, true },
{ "mining", "getblocksubsidy", &getblocksubsidy, true },
-#ifdef ENABLE_WALLET
+#ifdef ENABLE_MINING
/* Coin generation */
{ "generating", "getgenerate", &getgenerate, true },
{ "generating", "setgenerate", &setgenerate, true },
{ "rawtransactions", "getrawtransaction", &getrawtransaction, true },
{ "rawtransactions", "sendrawtransaction", &sendrawtransaction, false },
{ "rawtransactions", "signrawtransaction", &signrawtransaction, false }, /* uses wallet if enabled */
+#ifdef ENABLE_WALLET
+ { "rawtransactions", "fundrawtransaction", &fundrawtransaction, false },
+#endif
/* Utility functions */
{ "util", "createmultisig", &createmultisig, true },
}
}
-const CRPCCommand *CRPCTable::operator[](string name) const
+const CRPCCommand *CRPCTable::operator[](const std::string& name) const
{
map<string, const CRPCCommand*>::const_iterator it = mapCommands.find(name);
if (it == mapCommands.end())
return TimingResistantEqual(strUserPass, strRPCUserColonPass);
}
-void ErrorReply(std::ostream& stream, const Object& objError, const Value& id)
+void ErrorReply(std::ostream& stream, const UniValue& objError, const UniValue& id)
{
// Send error reply from json-rpc error object
int nStatus = HTTP_INTERNAL_SERVER_ERROR;
int code = find_value(objError, "code").get_int();
if (code == RPC_INVALID_REQUEST) nStatus = HTTP_BAD_REQUEST;
else if (code == RPC_METHOD_NOT_FOUND) nStatus = HTTP_NOT_FOUND;
- string strReply = JSONRPCReply(Value::null, objError, id);
+ string strReply = JSONRPCReply(NullUniValue, objError, id);
stream << HTTPReply(nStatus, strReply, false) << std::flush;
}
strAllowed += subnet.ToString() + " ";
LogPrint("rpc", "Allowing RPC connections from: %s\n", strAllowed);
- strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
- if (((mapArgs["-rpcpassword"] == "") ||
- (mapArgs["-rpcuser"] == mapArgs["-rpcpassword"])) && Params().RequireRPCPassword())
+ if (mapArgs["-rpcpassword"] == "")
{
- unsigned char rand_pwd[32];
- GetRandBytes(rand_pwd, 32);
- uiInterface.ThreadSafeMessageBox(strprintf(
- _("To use zcashd you must set an rpcpassword in the configuration file:\n"
- "%s\n"
- "It is recommended you use the following random password:\n"
- "rpcuser=zcashrpc\n"
- "rpcpassword=%s\n"
- "(you do not need to remember this password)\n"
- "The username and password MUST NOT be the same.\n"
- "If the file does not exist, create it with owner-readable-only file permissions.\n"
- "It is also recommended to set alertnotify so you are notified of problems;\n"
- "for example: alertnotify=echo %%s | mail -s \"Zcash Alert\"
[email protected]\n"),
- GetConfigFile().string(),
- EncodeBase58(&rand_pwd[0],&rand_pwd[0]+32)),
- "", CClientUIInterface::MSG_ERROR | CClientUIInterface::SECURE);
- StartShutdown();
- return;
+ LogPrintf("No rpcpassword set - using random cookie authentication\n");
+ if (!GenerateAuthCookie(&strRPCUserColonPass)) {
+ uiInterface.ThreadSafeMessageBox(
+ _("Error: A fatal internal error occured, see debug.log for details"), // Same message as AbortNode
+ "", CClientUIInterface::MSG_ERROR);
+ StartShutdown();
+ return;
+ }
+ } else {
+ strRPCUserColonPass = mapArgs["-rpcuser"] + ":" + mapArgs["-rpcpassword"];
}
assert(rpc_io_service == NULL);
}
deadlineTimers.clear();
+ DeleteAuthCookie();
+
rpc_io_service->stop();
g_rpcSignals.Stopped();
if (rpc_worker_group != NULL)
class JSONRequest
{
public:
- Value id;
+ UniValue id;
string strMethod;
- Array params;
+ UniValue params;
- JSONRequest() { id = Value::null; }
- void parse(const Value& valRequest);
+ JSONRequest() { id = NullUniValue; }
+ void parse(const UniValue& valRequest);
};
-void JSONRequest::parse(const Value& valRequest)
+void JSONRequest::parse(const UniValue& valRequest)
{
// Parse request
- if (valRequest.type() != obj_type)
+ if (!valRequest.isObject())
throw JSONRPCError(RPC_INVALID_REQUEST, "Invalid Request object");
- const Object& request = valRequest.get_obj();
+ const UniValue& request = valRequest.get_obj();
// Parse id now so errors from here on will have the id
id = find_value(request, "id");
// Parse method
- Value valMethod = find_value(request, "method");
- if (valMethod.type() == null_type)
+ UniValue valMethod = find_value(request, "method");
+ if (valMethod.isNull())
throw JSONRPCError(RPC_INVALID_REQUEST, "Missing method");
- if (valMethod.type() != str_type)
+ if (!valMethod.isStr())
throw JSONRPCError(RPC_INVALID_REQUEST, "Method must be a string");
strMethod = valMethod.get_str();
if (strMethod != "getblocktemplate")
LogPrint("rpc", "ThreadRPCServer method=%s\n", SanitizeString(strMethod));
// Parse params
- Value valParams = find_value(request, "params");
- if (valParams.type() == array_type)
+ UniValue valParams = find_value(request, "params");
+ if (valParams.isArray())
params = valParams.get_array();
- else if (valParams.type() == null_type)
- params = Array();
+ else if (valParams.isNull())
+ params = UniValue(UniValue::VARR);
else
throw JSONRPCError(RPC_INVALID_REQUEST, "Params must be an array");
}
-static Object JSONRPCExecOne(const Value& req)
+static UniValue JSONRPCExecOne(const UniValue& req)
{
- Object rpc_result;
+ UniValue rpc_result(UniValue::VOBJ);
JSONRequest jreq;
try {
jreq.parse(req);
- Value result = tableRPC.execute(jreq.strMethod, jreq.params);
- rpc_result = JSONRPCReplyObj(result, Value::null, jreq.id);
+ UniValue result = tableRPC.execute(jreq.strMethod, jreq.params);
+ rpc_result = JSONRPCReplyObj(result, NullUniValue, jreq.id);
}
- catch (const Object& objError)
+ catch (const UniValue& objError)
{
- rpc_result = JSONRPCReplyObj(Value::null, objError, jreq.id);
+ rpc_result = JSONRPCReplyObj(NullUniValue, objError, jreq.id);
}
catch (const std::exception& e)
{
- rpc_result = JSONRPCReplyObj(Value::null,
+ rpc_result = JSONRPCReplyObj(NullUniValue,
JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id);
}
return rpc_result;
}
-static string JSONRPCExecBatch(const Array& vReq)
+static string JSONRPCExecBatch(const UniValue& vReq)
{
- Array ret;
- for (unsigned int reqIdx = 0; reqIdx < vReq.size(); reqIdx++)
+ UniValue ret(UniValue::VARR);
+ for (size_t reqIdx = 0; reqIdx < vReq.size(); reqIdx++)
ret.push_back(JSONRPCExecOne(vReq[reqIdx]));
- return write_string(Value(ret), false) + "\n";
+ return ret.write() + "\n";
}
static bool HTTPReq_JSONRPC(AcceptedConnection *conn,
try
{
// Parse request
- Value valRequest;
- if (!read_string(strRequest, valRequest))
+ UniValue valRequest;
+ if (!valRequest.read(strRequest))
throw JSONRPCError(RPC_PARSE_ERROR, "Parse error");
- // Return immediately if in warmup
- {
- LOCK(cs_rpcWarmup);
- if (fRPCInWarmup)
- throw JSONRPCError(RPC_IN_WARMUP, rpcWarmupStatus);
- }
-
string strReply;
// singleton request
- if (valRequest.type() == obj_type) {
+ if (valRequest.isObject()) {
jreq.parse(valRequest);
- Value result = tableRPC.execute(jreq.strMethod, jreq.params);
+ UniValue result = tableRPC.execute(jreq.strMethod, jreq.params);
// Send reply
- strReply = JSONRPCReply(result, Value::null, jreq.id);
+ strReply = JSONRPCReply(result, NullUniValue, jreq.id);
// array of requests
- } else if (valRequest.type() == array_type)
+ } else if (valRequest.isArray())
strReply = JSONRPCExecBatch(valRequest.get_array());
else
throw JSONRPCError(RPC_PARSE_ERROR, "Top-level object parse error");
conn->stream() << HTTPReplyHeader(HTTP_OK, fRun, strReply.size()) << strReply << std::flush;
}
- catch (const Object& objError)
+ catch (const UniValue& objError)
{
ErrorReply(conn->stream(), objError, jreq.id);
return false;
// Read HTTP message headers and body
ReadHTTPMessage(conn->stream(), mapHeaders, strRequest, nProto, MAX_SIZE);
- // TODO #1856: Re-enable support for persistent connections.
- // We have disabled support for HTTP Keep-Alive until resolution of #1680, upstream rpc deadlock.
- // Close connection immediately.
- fRun = false;
- /*
// HTTP Keep-Alive is false; close connection immediately
if ((mapHeaders["connection"] == "close") || (!GetBoolArg("-rpckeepalive", true)))
fRun = false;
- */
// Process via JSON-RPC API
if (strURI == "/") {
}
}
-json_spirit::Value CRPCTable::execute(const std::string &strMethod, const json_spirit::Array ¶ms) const
+UniValue CRPCTable::execute(const std::string &strMethod, const UniValue ¶ms) const
{
+ // Return immediately if in warmup
+ {
+ LOCK(cs_rpcWarmup);
+ if (fRPCInWarmup)
+ throw JSONRPCError(RPC_IN_WARMUP, rpcWarmupStatus);
+ }
+
// Find method
const CRPCCommand *pcmd = tableRPC[strMethod];
if (!pcmd)
g_rpcSignals.PostCommand(*pcmd);
}
-std::string HelpExampleCli(string methodname, string args){
+std::string HelpExampleCli(const std::string& methodname, const std::string& args)
+{
return "> zcash-cli " + methodname + " " + args + "\n";
}
-std::string HelpExampleRpc(string methodname, string args){
+std::string HelpExampleRpc(const std::string& methodname, const std::string& args)
+{
return "> curl --user myusername --data-binary '{\"jsonrpc\": \"1.0\", \"id\":\"curltest\", "
"\"method\": \"" + methodname + "\", \"params\": [" + args + "] }' -H 'content-type: text/plain;' http://127.0.0.1:8232/\n";
}