|
|
@ -27,7 +27,8 @@ |
|
|
|
#include <boost/shared_ptr.hpp> |
|
|
|
#include <boost/shared_ptr.hpp> |
|
|
|
#include <boost/signals2/signal.hpp> |
|
|
|
#include <boost/signals2/signal.hpp> |
|
|
|
#include <boost/thread.hpp> |
|
|
|
#include <boost/thread.hpp> |
|
|
|
#include "json/json_spirit_writer_template.h" |
|
|
|
|
|
|
|
|
|
|
|
#include "json_spirit_wrapper.h" |
|
|
|
|
|
|
|
|
|
|
|
using namespace boost::asio; |
|
|
|
using namespace boost::asio; |
|
|
|
using namespace json_spirit; |
|
|
|
using namespace json_spirit; |
|
|
@ -89,30 +90,30 @@ void RPCTypeCheck(const Array& params, |
|
|
|
break; |
|
|
|
break; |
|
|
|
|
|
|
|
|
|
|
|
const Value& v = params[i]; |
|
|
|
const Value& v = params[i]; |
|
|
|
if (!((v.type() == t) || (fAllowNull && (v.type() == null_type)))) |
|
|
|
if (!((v.type() == t) || (fAllowNull && (v.isNull())))) |
|
|
|
{ |
|
|
|
{ |
|
|
|
string err = strprintf("Expected type %s, got %s", |
|
|
|
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); |
|
|
|
throw JSONRPCError(RPC_TYPE_ERROR, err); |
|
|
|
} |
|
|
|
} |
|
|
|
i++; |
|
|
|
i++; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void RPCTypeCheck(const Object& o, |
|
|
|
void RPCTypeCheckObj(const UniValue& o, |
|
|
|
const map<string, Value_type>& typesExpected, |
|
|
|
const map<string, UniValue::VType>& typesExpected, |
|
|
|
bool fAllowNull) |
|
|
|
bool fAllowNull) |
|
|
|
{ |
|
|
|
{ |
|
|
|
BOOST_FOREACH(const PAIRTYPE(string, Value_type)& t, typesExpected) |
|
|
|
BOOST_FOREACH(const PAIRTYPE(string, Value_type)& t, typesExpected) |
|
|
|
{ |
|
|
|
{ |
|
|
|
const Value& v = find_value(o, t.first); |
|
|
|
const Value& v = find_value(o, t.first); |
|
|
|
if (!fAllowNull && v.type() == null_type) |
|
|
|
if (!fAllowNull && v.isNull()) |
|
|
|
throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Missing %s", t.first)); |
|
|
|
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", |
|
|
|
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); |
|
|
|
throw JSONRPCError(RPC_TYPE_ERROR, err); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -142,7 +143,7 @@ Value ValueFromAmount(const CAmount& amount) |
|
|
|
uint256 ParseHashV(const Value& v, string strName) |
|
|
|
uint256 ParseHashV(const Value& v, string strName) |
|
|
|
{ |
|
|
|
{ |
|
|
|
string strHex; |
|
|
|
string strHex; |
|
|
|
if (v.type() == str_type) |
|
|
|
if (v.isStr()) |
|
|
|
strHex = v.get_str(); |
|
|
|
strHex = v.get_str(); |
|
|
|
if (!IsHex(strHex)) // Note: IsHex("") is false
|
|
|
|
if (!IsHex(strHex)) // Note: IsHex("") is false
|
|
|
|
throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')"); |
|
|
|
throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')"); |
|
|
@ -157,7 +158,7 @@ uint256 ParseHashO(const Object& o, string strKey) |
|
|
|
vector<unsigned char> ParseHexV(const Value& v, string strName) |
|
|
|
vector<unsigned char> ParseHexV(const Value& v, string strName) |
|
|
|
{ |
|
|
|
{ |
|
|
|
string strHex; |
|
|
|
string strHex; |
|
|
|
if (v.type() == str_type) |
|
|
|
if (v.isStr()) |
|
|
|
strHex = v.get_str(); |
|
|
|
strHex = v.get_str(); |
|
|
|
if (!IsHex(strHex)) |
|
|
|
if (!IsHex(strHex)) |
|
|
|
throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')"); |
|
|
|
throw JSONRPCError(RPC_INVALID_PARAMETER, strName+" must be hexadecimal string (not '"+strHex+"')"); |
|
|
@ -417,7 +418,7 @@ void ErrorReply(std::ostream& stream, const Object& objError, const Value& id) |
|
|
|
int code = find_value(objError, "code").get_int(); |
|
|
|
int code = find_value(objError, "code").get_int(); |
|
|
|
if (code == RPC_INVALID_REQUEST) nStatus = HTTP_BAD_REQUEST; |
|
|
|
if (code == RPC_INVALID_REQUEST) nStatus = HTTP_BAD_REQUEST; |
|
|
|
else if (code == RPC_METHOD_NOT_FOUND) nStatus = HTTP_NOT_FOUND; |
|
|
|
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; |
|
|
|
stream << HTTPReply(nStatus, strReply, false) << std::flush; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -828,14 +829,14 @@ public: |
|
|
|
string strMethod; |
|
|
|
string strMethod; |
|
|
|
Array params; |
|
|
|
Array params; |
|
|
|
|
|
|
|
|
|
|
|
JSONRequest() { id = Value::null; } |
|
|
|
JSONRequest() { id = NullUniValue; } |
|
|
|
void parse(const Value& valRequest); |
|
|
|
void parse(const Value& valRequest); |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
void JSONRequest::parse(const Value& valRequest) |
|
|
|
void JSONRequest::parse(const Value& valRequest) |
|
|
|
{ |
|
|
|
{ |
|
|
|
// Parse request
|
|
|
|
// Parse request
|
|
|
|
if (valRequest.type() != obj_type) |
|
|
|
if (!valRequest.isObject()) |
|
|
|
throw JSONRPCError(RPC_INVALID_REQUEST, "Invalid Request object"); |
|
|
|
throw JSONRPCError(RPC_INVALID_REQUEST, "Invalid Request object"); |
|
|
|
const Object& request = valRequest.get_obj(); |
|
|
|
const Object& request = valRequest.get_obj(); |
|
|
|
|
|
|
|
|
|
|
@ -844,9 +845,9 @@ void JSONRequest::parse(const Value& valRequest) |
|
|
|
|
|
|
|
|
|
|
|
// Parse method
|
|
|
|
// Parse method
|
|
|
|
Value valMethod = find_value(request, "method"); |
|
|
|
Value valMethod = find_value(request, "method"); |
|
|
|
if (valMethod.type() == null_type) |
|
|
|
if (valMethod.isNull()) |
|
|
|
throw JSONRPCError(RPC_INVALID_REQUEST, "Missing method"); |
|
|
|
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"); |
|
|
|
throw JSONRPCError(RPC_INVALID_REQUEST, "Method must be a string"); |
|
|
|
strMethod = valMethod.get_str(); |
|
|
|
strMethod = valMethod.get_str(); |
|
|
|
if (strMethod != "getblocktemplate") |
|
|
|
if (strMethod != "getblocktemplate") |
|
|
@ -854,9 +855,9 @@ void JSONRequest::parse(const Value& valRequest) |
|
|
|
|
|
|
|
|
|
|
|
// Parse params
|
|
|
|
// Parse params
|
|
|
|
Value valParams = find_value(request, "params"); |
|
|
|
Value valParams = find_value(request, "params"); |
|
|
|
if (valParams.type() == array_type) |
|
|
|
if (valParams.isArray()) |
|
|
|
params = valParams.get_array(); |
|
|
|
params = valParams.get_array(); |
|
|
|
else if (valParams.type() == null_type) |
|
|
|
else if (valParams.isNull()) |
|
|
|
params = Array(); |
|
|
|
params = Array(); |
|
|
|
else |
|
|
|
else |
|
|
|
throw JSONRPCError(RPC_INVALID_REQUEST, "Params must be an array"); |
|
|
|
throw JSONRPCError(RPC_INVALID_REQUEST, "Params must be an array"); |
|
|
@ -872,15 +873,15 @@ static Object JSONRPCExecOne(const Value& req) |
|
|
|
jreq.parse(req); |
|
|
|
jreq.parse(req); |
|
|
|
|
|
|
|
|
|
|
|
Value result = tableRPC.execute(jreq.strMethod, jreq.params); |
|
|
|
Value result = tableRPC.execute(jreq.strMethod, jreq.params); |
|
|
|
rpc_result = JSONRPCReplyObj(result, Value::null, jreq.id); |
|
|
|
rpc_result = JSONRPCReplyObj(result, NullUniValue, jreq.id); |
|
|
|
} |
|
|
|
} |
|
|
|
catch (const Object& objError) |
|
|
|
catch (const Object& objError) |
|
|
|
{ |
|
|
|
{ |
|
|
|
rpc_result = JSONRPCReplyObj(Value::null, objError, jreq.id); |
|
|
|
rpc_result = JSONRPCReplyObj(NullUniValue, objError, jreq.id); |
|
|
|
} |
|
|
|
} |
|
|
|
catch (const std::exception& e) |
|
|
|
catch (const std::exception& e) |
|
|
|
{ |
|
|
|
{ |
|
|
|
rpc_result = JSONRPCReplyObj(Value::null, |
|
|
|
rpc_result = JSONRPCReplyObj(NullUniValue, |
|
|
|
JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id); |
|
|
|
JSONRPCError(RPC_PARSE_ERROR, e.what()), jreq.id); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -893,7 +894,7 @@ static string JSONRPCExecBatch(const Array& vReq) |
|
|
|
for (unsigned int reqIdx = 0; reqIdx < vReq.size(); reqIdx++) |
|
|
|
for (unsigned int reqIdx = 0; reqIdx < vReq.size(); reqIdx++) |
|
|
|
ret.push_back(JSONRPCExecOne(vReq[reqIdx])); |
|
|
|
ret.push_back(JSONRPCExecOne(vReq[reqIdx])); |
|
|
|
|
|
|
|
|
|
|
|
return write_string(Value(ret), false) + "\n"; |
|
|
|
return ret.write() + "\n"; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static bool HTTPReq_JSONRPC(AcceptedConnection *conn, |
|
|
|
static bool HTTPReq_JSONRPC(AcceptedConnection *conn, |
|
|
@ -925,7 +926,7 @@ static bool HTTPReq_JSONRPC(AcceptedConnection *conn, |
|
|
|
{ |
|
|
|
{ |
|
|
|
// Parse request
|
|
|
|
// Parse request
|
|
|
|
Value valRequest; |
|
|
|
Value valRequest; |
|
|
|
if (!read_string(strRequest, valRequest)) |
|
|
|
if (!valRequest.read(strRequest)) |
|
|
|
throw JSONRPCError(RPC_PARSE_ERROR, "Parse error"); |
|
|
|
throw JSONRPCError(RPC_PARSE_ERROR, "Parse error"); |
|
|
|
|
|
|
|
|
|
|
|
// Return immediately if in warmup
|
|
|
|
// Return immediately if in warmup
|
|
|
@ -938,16 +939,16 @@ static bool HTTPReq_JSONRPC(AcceptedConnection *conn, |
|
|
|
string strReply; |
|
|
|
string strReply; |
|
|
|
|
|
|
|
|
|
|
|
// singleton request
|
|
|
|
// singleton request
|
|
|
|
if (valRequest.type() == obj_type) { |
|
|
|
if (valRequest.isObject()) { |
|
|
|
jreq.parse(valRequest); |
|
|
|
jreq.parse(valRequest); |
|
|
|
|
|
|
|
|
|
|
|
Value result = tableRPC.execute(jreq.strMethod, jreq.params); |
|
|
|
Value result = tableRPC.execute(jreq.strMethod, jreq.params); |
|
|
|
|
|
|
|
|
|
|
|
// Send reply
|
|
|
|
// Send reply
|
|
|
|
strReply = JSONRPCReply(result, Value::null, jreq.id); |
|
|
|
strReply = JSONRPCReply(result, NullUniValue, jreq.id); |
|
|
|
|
|
|
|
|
|
|
|
// array of requests
|
|
|
|
// array of requests
|
|
|
|
} else if (valRequest.type() == array_type) |
|
|
|
} else if (valRequest.isArray()) |
|
|
|
strReply = JSONRPCExecBatch(valRequest.get_array()); |
|
|
|
strReply = JSONRPCExecBatch(valRequest.get_array()); |
|
|
|
else |
|
|
|
else |
|
|
|
throw JSONRPCError(RPC_PARSE_ERROR, "Top-level object parse error"); |
|
|
|
throw JSONRPCError(RPC_PARSE_ERROR, "Top-level object parse error"); |
|
|
|