mirror of
https://github.com/monero-project/monero.git
synced 2025-01-28 18:56:31 +02:00
More RPC handlers, more JSON RPC 2.0 compliant.
This commit is contained in:
parent
5470c0c070
commit
43286b46e5
@ -1,4 +1,8 @@
|
|||||||
|
#ifndef JSON_RPC_HANDLERS_H
|
||||||
|
#define JSON_RPC_HANDLERS_H
|
||||||
|
|
||||||
#include "net_skeleton/net_skeleton.h"
|
#include "net_skeleton/net_skeleton.h"
|
||||||
|
#include "json_rpc_http_server.h"
|
||||||
#include "common/command_line.h"
|
#include "common/command_line.h"
|
||||||
#include "net/http_server_impl_base.h"
|
#include "net/http_server_impl_base.h"
|
||||||
#include "cryptonote_core/cryptonote_core.h"
|
#include "cryptonote_core/cryptonote_core.h"
|
||||||
@ -74,9 +78,10 @@ namespace RPC
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void construct_response_string(struct ns_rpc_request *req, rapidjson::Document &response_json,
|
void construct_response_string(struct ns_rpc_request *req, rapidjson::Value &result_json,
|
||||||
std::string &response)
|
rapidjson::Document &response_json, std::string &response)
|
||||||
{
|
{
|
||||||
|
response_json.SetObject();
|
||||||
rapidjson::Value string_value(rapidjson::kStringType);
|
rapidjson::Value string_value(rapidjson::kStringType);
|
||||||
if (req->id != NULL)
|
if (req->id != NULL)
|
||||||
{
|
{
|
||||||
@ -89,22 +94,45 @@ namespace RPC
|
|||||||
response_json.AddMember("id", string_value, response_json.GetAllocator());
|
response_json.AddMember("id", string_value, response_json.GetAllocator());
|
||||||
string_value.SetString(req->method[0].ptr, req->method[0].len);
|
string_value.SetString(req->method[0].ptr, req->method[0].len);
|
||||||
response_json.AddMember("method", string_value, response_json.GetAllocator());
|
response_json.AddMember("method", string_value, response_json.GetAllocator());
|
||||||
|
response_json.AddMember("result", result_json, response_json.GetAllocator());
|
||||||
rapidjson::StringBuffer buffer;
|
rapidjson::StringBuffer buffer;
|
||||||
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
|
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
|
||||||
response_json.Accept(writer);
|
response_json.Accept(writer);
|
||||||
response = buffer.GetString();
|
response = buffer.GetString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
// equivalent of strstr, but with arbitrary bytes (ie, NULs)
|
||||||
|
// This does not differentiate between "not found" and "found at offset 0"
|
||||||
|
uint64_t slow_memmem(const void *start_buff, size_t buflen, const void *pat, size_t patlen)
|
||||||
|
{
|
||||||
|
const void *buf = start_buff;
|
||||||
|
const void *end = (const char*)buf + buflen;
|
||||||
|
if (patlen > buflen || patlen == 0)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
while (buflen > 0 && (buf = memchr(buf,((const char*)pat)[0], buflen - patlen + 1)))
|
||||||
|
{
|
||||||
|
if (memcmp(buf,pat,patlen) == 0)
|
||||||
|
return (const char*)buf - (const char*)start_buff;
|
||||||
|
buf = (const char*)buf + 1;
|
||||||
|
buflen = (const char*)end - (const char*)buf;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int getheight(char *buf, int len, struct ns_rpc_request *req)
|
int getheight(char *buf, int len, struct ns_rpc_request *req)
|
||||||
{
|
{
|
||||||
CHECK_CORE_BUSY();
|
CHECK_CORE_BUSY();
|
||||||
uint64_t height = core->get_current_blockchain_height();
|
uint64_t height = core->get_current_blockchain_height();
|
||||||
rapidjson::Document response_json;
|
rapidjson::Document response_json;
|
||||||
response_json.SetObject();
|
rapidjson::Value result_json;
|
||||||
response_json.AddMember("height", height, response_json.GetAllocator());
|
result_json.SetObject();
|
||||||
response_json.AddMember("status", CORE_RPC_STATUS_OK, response_json.GetAllocator());
|
result_json.AddMember("height", height, response_json.GetAllocator());
|
||||||
|
result_json.AddMember("status", CORE_RPC_STATUS_OK, response_json.GetAllocator());
|
||||||
std::string response;
|
std::string response;
|
||||||
construct_response_string(req, response_json, response);
|
construct_response_string(req, result_json, response_json, response);
|
||||||
size_t copy_length = ((uint32_t)len > response.length()) ? response.length() + 1 : (uint32_t)len;
|
size_t copy_length = ((uint32_t)len > response.length()) ? response.length() + 1 : (uint32_t)len;
|
||||||
strncpy(buf, response.c_str(), copy_length);
|
strncpy(buf, response.c_str(), copy_length);
|
||||||
return response.length();
|
return response.length();
|
||||||
@ -113,22 +141,30 @@ namespace RPC
|
|||||||
int getblocks(char *buf, int len, struct ns_rpc_request *req)
|
int getblocks(char *buf, int len, struct ns_rpc_request *req)
|
||||||
{
|
{
|
||||||
CHECK_CORE_BUSY();
|
CHECK_CORE_BUSY();
|
||||||
|
if (req->params == NULL)
|
||||||
|
{
|
||||||
|
return ns_rpc_create_error(buf, len, req, RPC::Json_rpc_http_server::invalid_params,
|
||||||
|
"Parameters missing.", "{}");
|
||||||
|
}
|
||||||
rapidjson::Document request_json;
|
rapidjson::Document request_json;
|
||||||
char request_buf[1000];
|
char request_buf[1000];
|
||||||
strncpy(request_buf, req->message[0].ptr, req->message[0].len);
|
strncpy(request_buf, req->params[0].ptr, req->params[0].len);
|
||||||
request_buf[req->message[0].len] = '\0';
|
request_buf[req->params[0].len] = '\0';
|
||||||
if (request_json.Parse(request_buf).HasParseError())
|
if (request_json.Parse(request_buf).HasParseError())
|
||||||
{
|
{
|
||||||
return ns_rpc_create_reply(buf, len, req, "{s:s}", "status", "Invalid JSON passed");
|
return ns_rpc_create_error(buf, len, req, RPC::Json_rpc_http_server::parse_error,
|
||||||
|
"Invalid JSON passed", "{}");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!request_json.HasMember("start_height") || !request_json["start_height"].IsUint64())
|
if (!request_json.HasMember("start_height") || !request_json["start_height"].IsUint64())
|
||||||
{
|
{
|
||||||
return ns_rpc_create_reply(buf, len, req, "{s:s}", "status", "Incorrect start_height");
|
return ns_rpc_create_error(buf, len, req, RPC::Json_rpc_http_server::invalid_params,
|
||||||
|
"Incorrect start_height", "{}");
|
||||||
}
|
}
|
||||||
if (!request_json.HasMember("block_ids") || !request_json["block_ids"].IsArray())
|
if (!request_json.HasMember("block_ids") || !request_json["block_ids"].IsArray())
|
||||||
{
|
{
|
||||||
return ns_rpc_create_reply(buf, len, req, "{s:s}", "status", "Incorrect block_ids");
|
return ns_rpc_create_error(buf, len, req, RPC::Json_rpc_http_server::invalid_params,
|
||||||
|
"Incorrect block_ids", "{}");
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t start_height = request_json["start_height"].GetUint();
|
uint64_t start_height = request_json["start_height"].GetUint();
|
||||||
@ -140,11 +176,13 @@ namespace RPC
|
|||||||
crypto::hash hash;
|
crypto::hash hash;
|
||||||
if (!it->IsString())
|
if (!it->IsString())
|
||||||
{
|
{
|
||||||
return ns_rpc_create_reply(buf, len, req, "{s:s}", "status", "Wrong type in block_ids");
|
return ns_rpc_create_error(buf, len, req, RPC::Json_rpc_http_server::invalid_params,
|
||||||
|
"Wrong type in block_ids", "{}");
|
||||||
}
|
}
|
||||||
if (strlen(it->GetString()) > crypto::HASH_SIZE)
|
if (strlen(it->GetString()) > crypto::HASH_SIZE)
|
||||||
{
|
{
|
||||||
return ns_rpc_create_reply(buf, len, req, "{s:s}", "status", "Block ID exceeds length.");
|
return ns_rpc_create_error(buf, len, req, RPC::Json_rpc_http_server::invalid_params,
|
||||||
|
"Block ID exceeds length.", "{}");
|
||||||
}
|
}
|
||||||
strcpy(hash.data, it->GetString());
|
strcpy(hash.data, it->GetString());
|
||||||
block_ids.push_back(hash);
|
block_ids.push_back(hash);
|
||||||
@ -156,11 +194,13 @@ namespace RPC
|
|||||||
if (!core->find_blockchain_supplement(start_height, block_ids, bs, result_current_height,
|
if (!core->find_blockchain_supplement(start_height, block_ids, bs, result_current_height,
|
||||||
result_start_height, COMMAND_RPC_GET_BLOCKS_FAST_MAX_COUNT))
|
result_start_height, COMMAND_RPC_GET_BLOCKS_FAST_MAX_COUNT))
|
||||||
{
|
{
|
||||||
return ns_rpc_create_reply(buf, len, req, "{s:s}", "status", "Failed");
|
return ns_rpc_create_error(buf, len, req, RPC::Json_rpc_http_server::internal_error,
|
||||||
|
"Failed", "{}");
|
||||||
}
|
}
|
||||||
|
|
||||||
rapidjson::Document response_json;
|
rapidjson::Document response_json;
|
||||||
response_json.SetObject();
|
rapidjson::Value result_json;
|
||||||
|
result_json.SetObject();
|
||||||
rapidjson::Value block_json(rapidjson::kArrayType);
|
rapidjson::Value block_json(rapidjson::kArrayType);
|
||||||
rapidjson::Document::AllocatorType &allocator = response_json.GetAllocator();
|
rapidjson::Document::AllocatorType &allocator = response_json.GetAllocator();
|
||||||
BOOST_FOREACH(auto &b, bs)
|
BOOST_FOREACH(auto &b, bs)
|
||||||
@ -181,13 +221,13 @@ namespace RPC
|
|||||||
block_json.PushBack(this_block, allocator);
|
block_json.PushBack(this_block, allocator);
|
||||||
}
|
}
|
||||||
|
|
||||||
response_json.AddMember("start_height", result_start_height, allocator);
|
result_json.AddMember("start_height", result_start_height, allocator);
|
||||||
response_json.AddMember("current_height", result_current_height, allocator);
|
result_json.AddMember("current_height", result_current_height, allocator);
|
||||||
response_json.AddMember("status", CORE_RPC_STATUS_OK, allocator);
|
result_json.AddMember("status", CORE_RPC_STATUS_OK, allocator);
|
||||||
response_json.AddMember("blocks", block_json, allocator);
|
result_json.AddMember("blocks", block_json, allocator);
|
||||||
|
|
||||||
std::string response;
|
std::string response;
|
||||||
construct_response_string(req, response_json, response);
|
construct_response_string(req, result_json, response_json, response);
|
||||||
|
|
||||||
size_t copy_length = ((uint32_t)len > response.length()) ? response.length() + 1 : (uint32_t)len;
|
size_t copy_length = ((uint32_t)len > response.length()) ? response.length() + 1 : (uint32_t)len;
|
||||||
strncpy(buf, response.c_str(), copy_length);
|
strncpy(buf, response.c_str(), copy_length);
|
||||||
@ -197,18 +237,25 @@ namespace RPC
|
|||||||
int gettransactions(char *buf, int len, struct ns_rpc_request *req)
|
int gettransactions(char *buf, int len, struct ns_rpc_request *req)
|
||||||
{
|
{
|
||||||
CHECK_CORE_BUSY();
|
CHECK_CORE_BUSY();
|
||||||
|
if (req->params == NULL)
|
||||||
|
{
|
||||||
|
return ns_rpc_create_error(buf, len, req, RPC::Json_rpc_http_server::invalid_params,
|
||||||
|
"Parameters missing.", "{}");
|
||||||
|
}
|
||||||
rapidjson::Document request_json;
|
rapidjson::Document request_json;
|
||||||
char request_buf[1000];
|
char request_buf[1000];
|
||||||
strncpy(request_buf, req->message[0].ptr, req->message[0].len);
|
strncpy(request_buf, req->params[0].ptr, req->params[0].len);
|
||||||
request_buf[req->message[0].len] = '\0';
|
request_buf[req->params[0].len] = '\0';
|
||||||
if (request_json.Parse(request_buf).HasParseError())
|
if (request_json.Parse(request_buf).HasParseError())
|
||||||
{
|
{
|
||||||
return ns_rpc_create_reply(buf, len, req, "{s:s}", "status", "Invalid JSON passed");
|
return ns_rpc_create_error(buf, len, req, RPC::Json_rpc_http_server::parse_error,
|
||||||
|
"Invalid JSON passed", "{}");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!request_json.HasMember("txs_hashes") || !request_json["txs_hashes"].IsArray())
|
if (!request_json.HasMember("txs_hashes") || !request_json["txs_hashes"].IsArray())
|
||||||
{
|
{
|
||||||
return ns_rpc_create_reply(buf, len, req, "{s:s}", "status", "Incorrect txs_hashes");
|
return ns_rpc_create_error(buf, len, req, RPC::Json_rpc_http_server::invalid_params,
|
||||||
|
"Incorrect txs_hashes", "{}");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::list<std::string> txs_hashes;
|
std::list<std::string> txs_hashes;
|
||||||
@ -217,7 +264,8 @@ namespace RPC
|
|||||||
{
|
{
|
||||||
if (!it->IsString())
|
if (!it->IsString())
|
||||||
{
|
{
|
||||||
return ns_rpc_create_reply(buf, len, req, "{s:s}", "status", "Wrong type in txs_hashes");
|
return ns_rpc_create_error(buf, len, req, RPC::Json_rpc_http_server::invalid_params,
|
||||||
|
"Wrong type in txs_hashes", "{}");
|
||||||
}
|
}
|
||||||
txs_hashes.push_back(std::string(it->GetString()));
|
txs_hashes.push_back(std::string(it->GetString()));
|
||||||
}
|
}
|
||||||
@ -227,11 +275,13 @@ namespace RPC
|
|||||||
cryptonote::blobdata b;
|
cryptonote::blobdata b;
|
||||||
if (!string_tools::parse_hexstr_to_binbuff(tx_hex_str, b))
|
if (!string_tools::parse_hexstr_to_binbuff(tx_hex_str, b))
|
||||||
{
|
{
|
||||||
return ns_rpc_create_reply(buf, len, req, "{s:s}", "status", "Failed to parse hex representation of transaction hash");
|
return ns_rpc_create_error(buf, len, req, RPC::Json_rpc_http_server::invalid_params,
|
||||||
|
"Failed to parse hex representation of transaction hash", "{}");
|
||||||
}
|
}
|
||||||
if (b.size() != sizeof(crypto::hash))
|
if (b.size() != sizeof(crypto::hash))
|
||||||
{
|
{
|
||||||
return ns_rpc_create_reply(buf, len, req, "{s:s}", "status", "Failed, size of data mismatch");
|
return ns_rpc_create_error(buf, len, req, RPC::Json_rpc_http_server::invalid_params,
|
||||||
|
"Failed, size of data mismatch", "{}");
|
||||||
}
|
}
|
||||||
vh.push_back(*reinterpret_cast<const crypto::hash*>(b.data()));
|
vh.push_back(*reinterpret_cast<const crypto::hash*>(b.data()));
|
||||||
}
|
}
|
||||||
@ -240,11 +290,13 @@ namespace RPC
|
|||||||
bool r = core->get_transactions(vh, txs, missed_txs);
|
bool r = core->get_transactions(vh, txs, missed_txs);
|
||||||
if (!r)
|
if (!r)
|
||||||
{
|
{
|
||||||
return ns_rpc_create_reply(buf, len, req, "{s:s}", "status", "Failed");
|
return ns_rpc_create_error(buf, len, req, RPC::Json_rpc_http_server::internal_error,
|
||||||
|
"Failed", "{}");
|
||||||
}
|
}
|
||||||
|
|
||||||
rapidjson::Document response_json;
|
rapidjson::Document response_json;
|
||||||
response_json.SetObject();
|
rapidjson::Value result_json;
|
||||||
|
result_json.SetObject();
|
||||||
rapidjson::Document::AllocatorType &allocator = response_json.GetAllocator();
|
rapidjson::Document::AllocatorType &allocator = response_json.GetAllocator();
|
||||||
|
|
||||||
rapidjson::Value txs_as_hex(rapidjson::kArrayType);
|
rapidjson::Value txs_as_hex(rapidjson::kArrayType);
|
||||||
@ -256,7 +308,7 @@ namespace RPC
|
|||||||
string_value.SetString(string_blob.c_str(), string_blob.length());
|
string_value.SetString(string_blob.c_str(), string_blob.length());
|
||||||
txs_as_hex.PushBack(string_value, allocator);
|
txs_as_hex.PushBack(string_value, allocator);
|
||||||
}
|
}
|
||||||
response_json.AddMember("txs_as_hex", txs_as_hex, response_json.GetAllocator());
|
result_json.AddMember("txs_as_hex", txs_as_hex, response_json.GetAllocator());
|
||||||
|
|
||||||
rapidjson::Value missed_tx(rapidjson::kArrayType);
|
rapidjson::Value missed_tx(rapidjson::kArrayType);
|
||||||
BOOST_FOREACH(const auto &miss_tx, missed_txs)
|
BOOST_FOREACH(const auto &miss_tx, missed_txs)
|
||||||
@ -266,10 +318,10 @@ namespace RPC
|
|||||||
string_value.SetString(string_blob.c_str(), string_blob.length());
|
string_value.SetString(string_blob.c_str(), string_blob.length());
|
||||||
missed_tx.PushBack(string_value, allocator);
|
missed_tx.PushBack(string_value, allocator);
|
||||||
}
|
}
|
||||||
response_json.AddMember("missed_tx", missed_tx, response_json.GetAllocator());
|
result_json.AddMember("missed_tx", missed_tx, response_json.GetAllocator());
|
||||||
|
|
||||||
std::string response;
|
std::string response;
|
||||||
construct_response_string(req, response_json, response);
|
construct_response_string(req, result_json, response_json, response);
|
||||||
|
|
||||||
size_t copy_length = ((uint32_t)len > response.length()) ? response.length() + 1 : (uint32_t)len;
|
size_t copy_length = ((uint32_t)len > response.length()) ? response.length() + 1 : (uint32_t)len;
|
||||||
strncpy(buf, response.c_str(), copy_length);
|
strncpy(buf, response.c_str(), copy_length);
|
||||||
@ -279,22 +331,30 @@ namespace RPC
|
|||||||
int startmining(char *buf, int len, struct ns_rpc_request *req)
|
int startmining(char *buf, int len, struct ns_rpc_request *req)
|
||||||
{
|
{
|
||||||
CHECK_CORE_BUSY();
|
CHECK_CORE_BUSY();
|
||||||
|
if (req->params == NULL)
|
||||||
|
{
|
||||||
|
return ns_rpc_create_error(buf, len, req, RPC::Json_rpc_http_server::invalid_params,
|
||||||
|
"Parameters missing.", "{}");
|
||||||
|
}
|
||||||
rapidjson::Document request_json;
|
rapidjson::Document request_json;
|
||||||
char request_buf[1000];
|
char request_buf[1000];
|
||||||
strncpy(request_buf, req->message[0].ptr, req->message[0].len);
|
strncpy(request_buf, req->params[0].ptr, req->params[0].len);
|
||||||
request_buf[req->message[0].len] = '\0';
|
request_buf[req->params[0].len] = '\0';
|
||||||
if (request_json.Parse(request_buf).HasParseError())
|
if (request_json.Parse(request_buf).HasParseError())
|
||||||
{
|
{
|
||||||
return ns_rpc_create_reply(buf, len, req, "{s:s}", "status", "Invalid JSON passed");
|
return ns_rpc_create_error(buf, len, req, RPC::Json_rpc_http_server::parse_error,
|
||||||
|
"Invalid JSON passed", "{}");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!request_json.HasMember("miner_address") || !request_json["miner_address"].IsString())
|
if (!request_json.HasMember("miner_address") || !request_json["miner_address"].IsString())
|
||||||
{
|
{
|
||||||
return ns_rpc_create_reply(buf, len, req, "{s:s}", "status", "Incorrect miner_address");
|
return ns_rpc_create_error(buf, len, req, RPC::Json_rpc_http_server::invalid_params,
|
||||||
|
"Incorrect miner_address", "{}");
|
||||||
}
|
}
|
||||||
if (!request_json.HasMember("threads_count") || !request_json["threads_count"].IsUint64())
|
if (!request_json.HasMember("threads_count") || !request_json["threads_count"].IsUint64())
|
||||||
{
|
{
|
||||||
return ns_rpc_create_reply(buf, len, req, "{s:s}", "status", "Incorrect threads_count");
|
return ns_rpc_create_error(buf, len, req, RPC::Json_rpc_http_server::invalid_params,
|
||||||
|
"Incorrect threads_count", "{}");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string miner_address = request_json["miner_address"].GetString();
|
std::string miner_address = request_json["miner_address"].GetString();
|
||||||
@ -303,14 +363,16 @@ namespace RPC
|
|||||||
cryptonote::account_public_address adr;
|
cryptonote::account_public_address adr;
|
||||||
if (!cryptonote::get_account_address_from_str(adr, testnet, miner_address))
|
if (!cryptonote::get_account_address_from_str(adr, testnet, miner_address))
|
||||||
{
|
{
|
||||||
return ns_rpc_create_reply(buf, len, req, "{s:s}", "status", "Failed, wrong address");
|
return ns_rpc_create_error(buf, len, req, RPC::Json_rpc_http_server::invalid_params,
|
||||||
|
"Failed, wrong address", "{}");
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::thread::attributes attrs;
|
boost::thread::attributes attrs;
|
||||||
attrs.set_stack_size(THREAD_STACK_SIZE);
|
attrs.set_stack_size(THREAD_STACK_SIZE);
|
||||||
if (!core->get_miner().start(adr, static_cast<size_t>(threads_count), attrs))
|
if (!core->get_miner().start(adr, static_cast<size_t>(threads_count), attrs))
|
||||||
{
|
{
|
||||||
return ns_rpc_create_reply(buf, len, req, "{s:s}", "status", "Failed, mining not started");
|
return ns_rpc_create_error(buf, len, req, RPC::Json_rpc_http_server::invalid_request,
|
||||||
|
"Failed, mining not started", "{}");
|
||||||
}
|
}
|
||||||
return ns_rpc_create_reply(buf, len, req, "{s:s}", "status", CORE_RPC_STATUS_OK);
|
return ns_rpc_create_reply(buf, len, req, "{s:s}", "status", CORE_RPC_STATUS_OK);
|
||||||
}
|
}
|
||||||
@ -320,7 +382,8 @@ namespace RPC
|
|||||||
CHECK_CORE_BUSY();
|
CHECK_CORE_BUSY();
|
||||||
if (!core->get_miner().stop())
|
if (!core->get_miner().stop())
|
||||||
{
|
{
|
||||||
return ns_rpc_create_reply(buf, len, req, "{s:s}", "status", "Failed, mining not stopped");
|
return ns_rpc_create_error(buf, len, req, RPC::Json_rpc_http_server::invalid_request,
|
||||||
|
"Failed, mining not stopped", "{}");
|
||||||
}
|
}
|
||||||
return ns_rpc_create_reply(buf, len, req, "{s:s}", "status", CORE_RPC_STATUS_OK);
|
return ns_rpc_create_reply(buf, len, req, "{s:s}", "status", CORE_RPC_STATUS_OK);
|
||||||
}
|
}
|
||||||
@ -329,9 +392,10 @@ namespace RPC
|
|||||||
{
|
{
|
||||||
CHECK_CORE_BUSY();
|
CHECK_CORE_BUSY();
|
||||||
rapidjson::Document response_json;
|
rapidjson::Document response_json;
|
||||||
response_json.SetObject();
|
rapidjson::Value result_json;
|
||||||
|
result_json.SetObject();
|
||||||
bool active = core->get_miner().is_mining();
|
bool active = core->get_miner().is_mining();
|
||||||
response_json.AddMember("active", active, response_json.GetAllocator());
|
result_json.AddMember("active", active, response_json.GetAllocator());
|
||||||
|
|
||||||
if (active)
|
if (active)
|
||||||
{
|
{
|
||||||
@ -339,16 +403,16 @@ namespace RPC
|
|||||||
uint64_t threads_count = core->get_miner().get_threads_count();
|
uint64_t threads_count = core->get_miner().get_threads_count();
|
||||||
const cryptonote::account_public_address &mining_address = core->get_miner().get_mining_address();
|
const cryptonote::account_public_address &mining_address = core->get_miner().get_mining_address();
|
||||||
std::string address = cryptonote::get_account_address_as_str(testnet, mining_address);
|
std::string address = cryptonote::get_account_address_as_str(testnet, mining_address);
|
||||||
response_json.AddMember("speed", speed, response_json.GetAllocator());
|
result_json.AddMember("speed", speed, response_json.GetAllocator());
|
||||||
response_json.AddMember("threads_count", threads_count, response_json.GetAllocator());
|
result_json.AddMember("threads_count", threads_count, response_json.GetAllocator());
|
||||||
rapidjson::Value string_address(rapidjson::kStringType);
|
rapidjson::Value string_address(rapidjson::kStringType);
|
||||||
string_address.SetString(address.c_str(), address.length());
|
string_address.SetString(address.c_str(), address.length());
|
||||||
response_json.AddMember("address", string_address, response_json.GetAllocator());
|
result_json.AddMember("address", string_address, response_json.GetAllocator());
|
||||||
}
|
}
|
||||||
response_json.AddMember("status", CORE_RPC_STATUS_OK, response_json.GetAllocator());
|
result_json.AddMember("status", CORE_RPC_STATUS_OK, response_json.GetAllocator());
|
||||||
|
|
||||||
std::string response;
|
std::string response;
|
||||||
construct_response_string(req, response_json, response);
|
construct_response_string(req, result_json, response_json, response);
|
||||||
|
|
||||||
size_t copy_length = ((uint32_t)len > response.length()) ? response.length() + 1 : (uint32_t)len;
|
size_t copy_length = ((uint32_t)len > response.length()) ? response.length() + 1 : (uint32_t)len;
|
||||||
strncpy(buf, response.c_str(), copy_length);
|
strncpy(buf, response.c_str(), copy_length);
|
||||||
@ -359,12 +423,13 @@ namespace RPC
|
|||||||
{
|
{
|
||||||
CHECK_CORE_BUSY();
|
CHECK_CORE_BUSY();
|
||||||
rapidjson::Document response_json;
|
rapidjson::Document response_json;
|
||||||
response_json.SetObject();
|
rapidjson::Value result_json;
|
||||||
response_json.AddMember("count", core->get_current_blockchain_height(), response_json.GetAllocator());
|
result_json.SetObject();
|
||||||
response_json.AddMember("status", CORE_RPC_STATUS_OK, response_json.GetAllocator());
|
result_json.AddMember("count", core->get_current_blockchain_height(), response_json.GetAllocator());
|
||||||
|
result_json.AddMember("status", CORE_RPC_STATUS_OK, response_json.GetAllocator());
|
||||||
|
|
||||||
std::string response;
|
std::string response;
|
||||||
construct_response_string(req, response_json, response);
|
construct_response_string(req, result_json, response_json, response);
|
||||||
|
|
||||||
size_t copy_length = ((uint32_t)len > response.length()) ? response.length() + 1 : (uint32_t)len;
|
size_t copy_length = ((uint32_t)len > response.length()) ? response.length() + 1 : (uint32_t)len;
|
||||||
strncpy(buf, response.c_str(), copy_length);
|
strncpy(buf, response.c_str(), copy_length);
|
||||||
@ -374,34 +439,144 @@ namespace RPC
|
|||||||
int getblockhash(char *buf, int len, struct ns_rpc_request *req)
|
int getblockhash(char *buf, int len, struct ns_rpc_request *req)
|
||||||
{
|
{
|
||||||
CHECK_CORE_BUSY();
|
CHECK_CORE_BUSY();
|
||||||
|
if (req->params == NULL)
|
||||||
|
{
|
||||||
|
return ns_rpc_create_error(buf, len, req, RPC::Json_rpc_http_server::invalid_params,
|
||||||
|
"Parameters missing.", "{}");
|
||||||
|
}
|
||||||
rapidjson::Document request_json;
|
rapidjson::Document request_json;
|
||||||
char request_buf[1000];
|
char request_buf[1000];
|
||||||
strncpy(request_buf, req->message[0].ptr, req->message[0].len);
|
strncpy(request_buf, req->params[0].ptr, req->params[0].len);
|
||||||
request_buf[req->message[0].len] = '\0';
|
request_buf[req->params[0].len] = '\0';
|
||||||
if (request_json.Parse(request_buf).HasParseError())
|
if (request_json.Parse(request_buf).HasParseError())
|
||||||
{
|
{
|
||||||
return ns_rpc_create_reply(buf, len, req, "{s:s}", "status", "Invalid JSON passed");
|
return ns_rpc_create_error(buf, len, req, RPC::Json_rpc_http_server::parse_error,
|
||||||
|
"Invalid JSON passed", "{}");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!request_json.HasMember("height") || !request_json["height"].IsUint64())
|
if (!request_json.HasMember("height") || !request_json["height"].IsUint64())
|
||||||
{
|
{
|
||||||
return ns_rpc_create_reply(buf, len, req, "{s:s}", "status", "Incorrect height");
|
return ns_rpc_create_error(buf, len, req, RPC::Json_rpc_http_server::invalid_params,
|
||||||
|
"Incorrect height", "{}");
|
||||||
}
|
}
|
||||||
uint64_t height = request_json["height"].GetUint();
|
uint64_t height = request_json["height"].GetUint();
|
||||||
if (core->get_current_blockchain_height() <= height)
|
if (core->get_current_blockchain_height() <= height)
|
||||||
{
|
{
|
||||||
return ns_rpc_create_reply(buf, len, req, "{s:s}", "status", "Height specified is too big.");
|
return ns_rpc_create_error(buf, len, req, RPC::Json_rpc_http_server::invalid_params,
|
||||||
|
"Height specified is too big.", "{}");
|
||||||
}
|
}
|
||||||
std::string hash = string_tools::pod_to_hex(core->get_block_id_by_height(height));
|
std::string hash = string_tools::pod_to_hex(core->get_block_id_by_height(height));
|
||||||
rapidjson::Document response_json;
|
rapidjson::Document response_json;
|
||||||
response_json.SetObject();
|
rapidjson::Value result_json;
|
||||||
|
result_json.SetObject();
|
||||||
rapidjson::Value string_value(rapidjson::kStringType);
|
rapidjson::Value string_value(rapidjson::kStringType);
|
||||||
string_value.SetString(hash.c_str(), hash.length());
|
string_value.SetString(hash.c_str(), hash.length());
|
||||||
response_json.AddMember("hash", string_value, response_json.GetAllocator());
|
result_json.AddMember("hash", string_value, response_json.GetAllocator());
|
||||||
response_json.AddMember("status", CORE_RPC_STATUS_OK, response_json.GetAllocator());
|
result_json.AddMember("status", CORE_RPC_STATUS_OK, response_json.GetAllocator());
|
||||||
|
|
||||||
std::string response;
|
std::string response;
|
||||||
construct_response_string(req, response_json, response);
|
construct_response_string(req, result_json, response_json, response);
|
||||||
|
size_t copy_length = ((uint32_t)len > response.length()) ? response.length() + 1 : (uint32_t)len;
|
||||||
|
strncpy(buf, response.c_str(), copy_length);
|
||||||
|
return response.length();
|
||||||
|
}
|
||||||
|
|
||||||
|
int getblocktemplate(char *buf, int len, struct ns_rpc_request *req)
|
||||||
|
{
|
||||||
|
CHECK_CORE_BUSY();
|
||||||
|
if (req->params == NULL)
|
||||||
|
{
|
||||||
|
return ns_rpc_create_error(buf, len, req, RPC::Json_rpc_http_server::invalid_params,
|
||||||
|
"Parameters missing.", "{}");
|
||||||
|
}
|
||||||
|
rapidjson::Document request_json;
|
||||||
|
char request_buf[1000];
|
||||||
|
strncpy(request_buf, req->params[0].ptr, req->params[0].len);
|
||||||
|
request_buf[req->params[0].len] = '\0';
|
||||||
|
|
||||||
|
if (request_json.Parse(request_buf).HasParseError())
|
||||||
|
{
|
||||||
|
return ns_rpc_create_error(buf, len, req, RPC::Json_rpc_http_server::parse_error,
|
||||||
|
"Invalid JSON passed", "{}");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!request_json.HasMember("reserve_size") || !request_json["reserve_size"].IsUint64())
|
||||||
|
{
|
||||||
|
return ns_rpc_create_error(buf, len, req, RPC::Json_rpc_http_server::invalid_params,
|
||||||
|
"Incorrect reserve_size", "{}");
|
||||||
|
}
|
||||||
|
if (!request_json.HasMember("wallet_address") || !request_json["wallet_address"].IsString())
|
||||||
|
{
|
||||||
|
return ns_rpc_create_error(buf, len, req, RPC::Json_rpc_http_server::invalid_params,
|
||||||
|
"Incorrect wallet_address", "{}");
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t reserve_size = request_json["reserve_size"].GetUint();
|
||||||
|
std::string wallet_address = request_json["wallet_address"].GetString();
|
||||||
|
|
||||||
|
if (reserve_size > 255)
|
||||||
|
{
|
||||||
|
return ns_rpc_create_error(buf, len, req, RPC::Json_rpc_http_server::invalid_params,
|
||||||
|
"To big reserved size, maximum 255", "{}");
|
||||||
|
}
|
||||||
|
|
||||||
|
cryptonote::account_public_address acc = AUTO_VAL_INIT(acc);
|
||||||
|
if (!wallet_address.size() || !cryptonote::get_account_address_from_str(acc, testnet, wallet_address))
|
||||||
|
{
|
||||||
|
return ns_rpc_create_error(buf, len, req, RPC::Json_rpc_http_server::invalid_params,
|
||||||
|
"Failed to parse wallet address", "{}");
|
||||||
|
}
|
||||||
|
|
||||||
|
cryptonote::block b = AUTO_VAL_INIT(b);
|
||||||
|
cryptonote::blobdata blob_reserve;
|
||||||
|
blob_reserve.resize(reserve_size, 0);
|
||||||
|
|
||||||
|
uint64_t difficulty, height, reserved_offset;
|
||||||
|
if (!core->get_block_template(b, acc, difficulty, height, blob_reserve))
|
||||||
|
{
|
||||||
|
LOG_ERROR("Failed to create block template");
|
||||||
|
return ns_rpc_create_error(buf, len, req, RPC::Json_rpc_http_server::internal_error,
|
||||||
|
"Failed to create block template", "{}");
|
||||||
|
}
|
||||||
|
|
||||||
|
cryptonote::blobdata block_blob = t_serializable_object_to_blob(b);
|
||||||
|
crypto::public_key tx_pub_key = cryptonote::get_tx_pub_key_from_extra(b.miner_tx);
|
||||||
|
if (tx_pub_key == cryptonote::null_pkey)
|
||||||
|
{
|
||||||
|
LOG_ERROR("Failed to tx pub key in coinbase extra");
|
||||||
|
return ns_rpc_create_error(buf, len, req, RPC::Json_rpc_http_server::internal_error,
|
||||||
|
"Failed to create block template", "{}");
|
||||||
|
}
|
||||||
|
|
||||||
|
reserved_offset = slow_memmem((void*)block_blob.data(), block_blob.size(), &tx_pub_key, sizeof(tx_pub_key));
|
||||||
|
if (!reserved_offset)
|
||||||
|
{
|
||||||
|
LOG_ERROR("Failed to find tx pub key in blockblob");
|
||||||
|
return ns_rpc_create_error(buf, len, req, RPC::Json_rpc_http_server::internal_error,
|
||||||
|
"Internal error: failed to create block template", "{}");
|
||||||
|
}
|
||||||
|
|
||||||
|
reserved_offset += sizeof(tx_pub_key) + 3; // 3 bytes: tag for TX_EXTRA_TAG_PUBKEY(1 byte), tag for TX_EXTRA_NONCE(1 byte), counter in TX_EXTRA_NONCE(1 byte)
|
||||||
|
if (reserved_offset + reserve_size > block_blob.size())
|
||||||
|
{
|
||||||
|
return ns_rpc_create_error(buf, len, req, RPC::Json_rpc_http_server::internal_error,
|
||||||
|
"Internal error: failed to create block template", "{}");
|
||||||
|
}
|
||||||
|
cryptonote::blobdata blocktemplate_blob = string_tools::buff_to_hex_nodelimer(block_blob);
|
||||||
|
|
||||||
|
rapidjson::Document response_json;
|
||||||
|
rapidjson::Value result_json;
|
||||||
|
result_json.SetObject();
|
||||||
|
result_json.AddMember("difficulty", difficulty, response_json.GetAllocator());
|
||||||
|
result_json.AddMember("height", height, response_json.GetAllocator());
|
||||||
|
result_json.AddMember("reserved_offset", reserved_offset, response_json.GetAllocator());
|
||||||
|
rapidjson::Value string_value(rapidjson::kStringType);
|
||||||
|
string_value.SetString(blocktemplate_blob.c_str(), blocktemplate_blob.length());
|
||||||
|
result_json.AddMember("blocktemplate_blob", string_value, response_json.GetAllocator());
|
||||||
|
result_json.AddMember("status", CORE_RPC_STATUS_OK, response_json.GetAllocator());
|
||||||
|
|
||||||
|
std::string response;
|
||||||
|
construct_response_string(req, result_json, response_json, response);
|
||||||
size_t copy_length = ((uint32_t)len > response.length()) ? response.length() + 1 : (uint32_t)len;
|
size_t copy_length = ((uint32_t)len > response.length()) ? response.length() + 1 : (uint32_t)len;
|
||||||
strncpy(buf, response.c_str(), copy_length);
|
strncpy(buf, response.c_str(), copy_length);
|
||||||
return response.length();
|
return response.length();
|
||||||
@ -416,6 +591,7 @@ namespace RPC
|
|||||||
"miningstatus",
|
"miningstatus",
|
||||||
"getblockcount",
|
"getblockcount",
|
||||||
"getblockhash",
|
"getblockhash",
|
||||||
|
"getblocktemplate",
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -428,6 +604,7 @@ namespace RPC
|
|||||||
miningstatus,
|
miningstatus,
|
||||||
getblockcount,
|
getblockcount,
|
||||||
getblockhash,
|
getblockhash,
|
||||||
|
getblocktemplate,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -449,3 +626,5 @@ namespace RPC
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
@ -4,6 +4,11 @@
|
|||||||
|
|
||||||
namespace RPC
|
namespace RPC
|
||||||
{
|
{
|
||||||
|
int Json_rpc_http_server::parse_error = -32700;
|
||||||
|
int Json_rpc_http_server::invalid_request = -32600;
|
||||||
|
int Json_rpc_http_server::invalid_params = -32602;
|
||||||
|
int Json_rpc_http_server::internal_error = -32603;
|
||||||
|
|
||||||
Json_rpc_http_server::Json_rpc_http_server(const std::string &ip, const std::string &port,
|
Json_rpc_http_server::Json_rpc_http_server(const std::string &ip, const std::string &port,
|
||||||
void (*ev_handler)(struct ns_connection *nc, int ev, void *ev_data))
|
void (*ev_handler)(struct ns_connection *nc, int ev, void *ev_data))
|
||||||
{
|
{
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
#ifndef JSON_RPC_HTTP_SERVER_H
|
||||||
|
#define JSON_RPC_HTTP_SERVER_H
|
||||||
|
|
||||||
#include "net_skeleton/net_skeleton.h"
|
#include "net_skeleton/net_skeleton.h"
|
||||||
#include <boost/thread.hpp>
|
#include <boost/thread.hpp>
|
||||||
#include <string>
|
#include <string>
|
||||||
@ -20,5 +23,12 @@ namespace RPC
|
|||||||
~Json_rpc_http_server();
|
~Json_rpc_http_server();
|
||||||
bool start();
|
bool start();
|
||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
|
static int parse_error;
|
||||||
|
static int invalid_request;
|
||||||
|
static int invalid_params;
|
||||||
|
static int internal_error;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user