mirror of
https://github.com/monero-project/monero.git
synced 2024-12-15 04:46:31 +02:00
Fix various oversights/bugs in ZMQ RPC server code
- Add some RPC commands (and touch up a couple others) - some bounds checking - some better pointer management - const correctness and error handling -- Thanks @vtnerd for type help with serialization and CMake changes
This commit is contained in:
parent
77986023c3
commit
0299cb77ca
@ -689,8 +689,16 @@ endif()
|
||||
|
||||
include(version.cmake)
|
||||
|
||||
find_path(ZMQ_INCLUDE_PATH zmq.hpp)
|
||||
find_library(ZMQ_LIB zmq)
|
||||
|
||||
if(NOT ZMQ_INCLUDE_PATH)
|
||||
message(FATAL_ERROR "Could not find required header zmq.hpp")
|
||||
endif()
|
||||
if(NOT ZMQ_LIB)
|
||||
message(FATAL_ERROR "Could not find require libzmq")
|
||||
endif()
|
||||
|
||||
function (treat_warnings_as_errors dirs)
|
||||
foreach(dir ${ARGV})
|
||||
set_property(DIRECTORY ${dir}
|
||||
|
@ -83,12 +83,6 @@ namespace daemon_args
|
||||
, std::to_string(config::testnet::ZMQ_RPC_DEFAULT_PORT)
|
||||
};
|
||||
|
||||
const command_line::arg_descriptor<bool> arg_zmq_restricted_rpc = {
|
||||
"zmq-restricted-rpc"
|
||||
, "Restrict ZMQ RPC to view only commands"
|
||||
, false
|
||||
};
|
||||
|
||||
} // namespace daemon_args
|
||||
|
||||
#endif // DAEMON_COMMAND_LINE_ARGS_H
|
||||
|
@ -92,7 +92,6 @@ int main(int argc, char const * argv[])
|
||||
command_line::add_arg(core_settings, daemon_args::arg_zmq_rpc_bind_ip);
|
||||
command_line::add_arg(core_settings, daemon_args::arg_zmq_rpc_bind_port);
|
||||
command_line::add_arg(core_settings, daemon_args::arg_zmq_testnet_rpc_bind_port);
|
||||
command_line::add_arg(core_settings, daemon_args::arg_zmq_restricted_rpc);
|
||||
|
||||
daemonizer::init_options(hidden_options, visible_options);
|
||||
daemonize::t_executor::init_options(core_settings);
|
||||
|
@ -115,6 +115,8 @@ target_link_libraries(daemon_rpc_server
|
||||
${Boost_THREAD_LIBRARY}
|
||||
${ZMQ_LIB}
|
||||
${EXTRA_LIBRARIES})
|
||||
target_include_directories(daemon_rpc_server PUBLIC ${ZMQ_INCLUDE_PATH})
|
||||
target_include_directories(obj_daemon_rpc_server PUBLIC ${ZMQ_INCLUDE_PATH})
|
||||
|
||||
|
||||
add_dependencies(rpc
|
||||
|
@ -81,6 +81,14 @@ namespace rpc
|
||||
return;
|
||||
}
|
||||
|
||||
if (it->second.size() != bwt.block.tx_hashes.size())
|
||||
{
|
||||
res.blocks.clear();
|
||||
res.output_indices.clear();
|
||||
res.status = Message::STATUS_FAILED;
|
||||
res.error_details = "incorrect number of transactions retrieved for block";
|
||||
return;
|
||||
}
|
||||
std::list<transaction> txs;
|
||||
for (const auto& blob : it->second)
|
||||
{
|
||||
@ -90,7 +98,7 @@ namespace rpc
|
||||
res.blocks.clear();
|
||||
res.output_indices.clear();
|
||||
res.status = Message::STATUS_FAILED;
|
||||
res.error_details = "failed retrieving a requested block";
|
||||
res.error_details = "failed retrieving a requested transaction";
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -404,56 +412,117 @@ namespace rpc
|
||||
|
||||
void DaemonHandler::handle(const StartMining::Request& req, StartMining::Response& res)
|
||||
{
|
||||
res.status = Message::STATUS_FAILED;
|
||||
res.error_details = "RPC method not yet implemented.";
|
||||
account_public_address adr;
|
||||
if(!get_account_address_from_str(adr, m_core.get_testnet(), req.miner_address))
|
||||
{
|
||||
res.error_details = "Failed, wrong address";
|
||||
LOG_PRINT_L0(res.error_details);
|
||||
res.status = Message::STATUS_FAILED;
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int concurrency_count = boost::thread::hardware_concurrency() * 4;
|
||||
|
||||
// if we couldn't detect threads, set it to a ridiculously high number
|
||||
if(concurrency_count == 0)
|
||||
{
|
||||
concurrency_count = 257;
|
||||
}
|
||||
|
||||
// if there are more threads requested than the hardware supports
|
||||
// then we fail and log that.
|
||||
if(req.threads_count > concurrency_count)
|
||||
{
|
||||
res.error_details = "Failed, too many threads relative to CPU cores.";
|
||||
LOG_PRINT_L0(res.error_details);
|
||||
res.status = Message::STATUS_FAILED;
|
||||
return;
|
||||
}
|
||||
|
||||
boost::thread::attributes attrs;
|
||||
attrs.set_stack_size(THREAD_STACK_SIZE);
|
||||
|
||||
if(!m_core.get_miner().start(adr, static_cast<size_t>(req.threads_count), attrs, req.do_background_mining, req.ignore_battery))
|
||||
{
|
||||
res.error_details = "Failed, mining not started";
|
||||
LOG_PRINT_L0(res.error_details);
|
||||
res.status = Message::STATUS_FAILED;
|
||||
return;
|
||||
}
|
||||
res.status = Message::STATUS_OK;
|
||||
res.error_details = "";
|
||||
|
||||
}
|
||||
|
||||
void DaemonHandler::handle(const GetInfo::Request& req, GetInfo::Response& res)
|
||||
{
|
||||
res.height = m_core.get_current_blockchain_height();
|
||||
res.info.height = m_core.get_current_blockchain_height();
|
||||
|
||||
res.target_height = m_core.get_target_blockchain_height();
|
||||
res.info.target_height = m_core.get_target_blockchain_height();
|
||||
|
||||
if (res.height > res.target_height)
|
||||
if (res.info.height > res.info.target_height)
|
||||
{
|
||||
res.target_height = res.height;
|
||||
res.info.target_height = res.info.height;
|
||||
}
|
||||
|
||||
auto& chain = m_core.get_blockchain_storage();
|
||||
|
||||
res.difficulty = chain.get_difficulty_for_next_block();
|
||||
res.info.difficulty = chain.get_difficulty_for_next_block();
|
||||
|
||||
res.target = chain.get_difficulty_target();
|
||||
res.info.target = chain.get_difficulty_target();
|
||||
|
||||
res.tx_count = chain.get_total_transactions() - res.height; //without coinbase
|
||||
res.info.tx_count = chain.get_total_transactions() - res.info.height; //without coinbase
|
||||
|
||||
res.tx_pool_size = m_core.get_pool_transactions_count();
|
||||
res.info.tx_pool_size = m_core.get_pool_transactions_count();
|
||||
|
||||
res.alt_blocks_count = chain.get_alternative_blocks_count();
|
||||
res.info.alt_blocks_count = chain.get_alternative_blocks_count();
|
||||
|
||||
uint64_t total_conn = m_p2p.get_connections_count();
|
||||
res.outgoing_connections_count = m_p2p.get_outgoing_connections_count();
|
||||
res.incoming_connections_count = total_conn - res.outgoing_connections_count;
|
||||
res.info.outgoing_connections_count = m_p2p.get_outgoing_connections_count();
|
||||
res.info.incoming_connections_count = total_conn - res.info.outgoing_connections_count;
|
||||
|
||||
res.white_peerlist_size = m_p2p.get_peerlist_manager().get_white_peers_count();
|
||||
res.info.white_peerlist_size = m_p2p.get_peerlist_manager().get_white_peers_count();
|
||||
|
||||
res.grey_peerlist_size = m_p2p.get_peerlist_manager().get_gray_peers_count();
|
||||
res.info.grey_peerlist_size = m_p2p.get_peerlist_manager().get_gray_peers_count();
|
||||
|
||||
res.testnet = m_core.get_testnet();
|
||||
res.info.testnet = m_core.get_testnet();
|
||||
res.info.cumulative_difficulty = m_core.get_blockchain_storage().get_db().get_block_cumulative_difficulty(res.info.height - 1);
|
||||
res.info.block_size_limit = m_core.get_blockchain_storage().get_current_cumulative_blocksize_limit();
|
||||
res.info.start_time = (uint64_t)m_core.get_start_time();
|
||||
|
||||
res.status = Message::STATUS_OK;
|
||||
res.error_details = "";
|
||||
}
|
||||
|
||||
void DaemonHandler::handle(const StopMining::Request& req, StopMining::Response& res)
|
||||
{
|
||||
res.status = Message::STATUS_FAILED;
|
||||
res.error_details = "RPC method not yet implemented.";
|
||||
if(!m_core.get_miner().stop())
|
||||
{
|
||||
res.error_details = "Failed, mining not stopped";
|
||||
LOG_PRINT_L0(res.error_details);
|
||||
res.status = Message::STATUS_FAILED;
|
||||
return;
|
||||
}
|
||||
|
||||
res.status = Message::STATUS_OK;
|
||||
res.error_details = "";
|
||||
}
|
||||
|
||||
void DaemonHandler::handle(const MiningStatus::Request& req, MiningStatus::Response& res)
|
||||
{
|
||||
res.status = Message::STATUS_FAILED;
|
||||
res.error_details = "RPC method not yet implemented.";
|
||||
const cryptonote::miner& lMiner = m_core.get_miner();
|
||||
res.active = lMiner.is_mining();
|
||||
res.is_background_mining_enabled = lMiner.get_is_background_mining_enabled();
|
||||
|
||||
if ( lMiner.is_mining() ) {
|
||||
res.speed = lMiner.get_speed();
|
||||
res.threads_count = lMiner.get_threads_count();
|
||||
const account_public_address& lMiningAdr = lMiner.get_mining_address();
|
||||
res.address = get_account_address_as_str(m_core.get_testnet(), lMiningAdr);
|
||||
}
|
||||
|
||||
res.status = Message::STATUS_OK;
|
||||
res.error_details = "";
|
||||
}
|
||||
|
||||
void DaemonHandler::handle(const SaveBC::Request& req, SaveBC::Response& res)
|
||||
@ -536,14 +605,31 @@ namespace rpc
|
||||
res.status = Message::STATUS_OK;
|
||||
}
|
||||
|
||||
void DaemonHandler::handle(const GetBlockHeadersByHeight::Request& req, GetBlockHeadersByHeight::Response& res)
|
||||
{
|
||||
res.headers.resize(req.heights.size());
|
||||
|
||||
for (size_t i=0; i < req.heights.size(); i++)
|
||||
{
|
||||
const crypto::hash block_hash = m_core.get_block_id_by_height(req.heights[i]);
|
||||
|
||||
if (!getBlockHeaderByHash(block_hash, res.headers[i]))
|
||||
{
|
||||
res.status = Message::STATUS_FAILED;
|
||||
res.error_details = "A requested block does not exist";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
res.status = Message::STATUS_OK;
|
||||
}
|
||||
|
||||
void DaemonHandler::handle(const GetBlock::Request& req, GetBlock::Response& res)
|
||||
{
|
||||
res.status = Message::STATUS_FAILED;
|
||||
res.error_details = "RPC method not yet implemented.";
|
||||
}
|
||||
|
||||
//TODO: this RPC call is marked for later implementation in the old RPC,
|
||||
// need to sort out if it's necessary and what it should do.
|
||||
void DaemonHandler::handle(const GetPeerList::Request& req, GetPeerList::Response& res)
|
||||
{
|
||||
res.status = Message::STATUS_FAILED;
|
||||
@ -596,18 +682,6 @@ namespace rpc
|
||||
res.error_details = "RPC method not yet implemented.";
|
||||
}
|
||||
|
||||
void DaemonHandler::handle(const FastExit::Request& req, FastExit::Response& res)
|
||||
{
|
||||
res.status = Message::STATUS_FAILED;
|
||||
res.error_details = "RPC method not yet implemented.";
|
||||
}
|
||||
|
||||
void DaemonHandler::handle(const OutPeers::Request& req, OutPeers::Response& res)
|
||||
{
|
||||
res.status = Message::STATUS_FAILED;
|
||||
res.error_details = "RPC method not yet implemented.";
|
||||
}
|
||||
|
||||
void DaemonHandler::handle(const StartSaveGraph::Request& req, StartSaveGraph::Response& res)
|
||||
{
|
||||
res.status = Message::STATUS_FAILED;
|
||||
@ -675,13 +749,22 @@ namespace rpc
|
||||
|
||||
void DaemonHandler::handle(const GetOutputKeys::Request& req, GetOutputKeys::Response& res)
|
||||
{
|
||||
for (const auto& i : req.outputs)
|
||||
try
|
||||
{
|
||||
crypto::public_key key;
|
||||
rct::key mask;
|
||||
bool unlocked;
|
||||
m_core.get_blockchain_storage().get_output_key_mask_unlocked(i.amount, i.index, key, mask, unlocked);
|
||||
res.keys.emplace_back(output_key_mask_unlocked{key, mask, unlocked});
|
||||
for (const auto& i : req.outputs)
|
||||
{
|
||||
crypto::public_key key;
|
||||
rct::key mask;
|
||||
bool unlocked;
|
||||
m_core.get_blockchain_storage().get_output_key_mask_unlocked(i.amount, i.index, key, mask, unlocked);
|
||||
res.keys.emplace_back(output_key_mask_unlocked{key, mask, unlocked});
|
||||
}
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
res.status = Message::STATUS_FAILED;
|
||||
res.error_details = e.what();
|
||||
return;
|
||||
}
|
||||
|
||||
res.status = Message::STATUS_OK;
|
||||
@ -689,7 +772,7 @@ namespace rpc
|
||||
|
||||
void DaemonHandler::handle(const GetRPCVersion::Request& req, GetRPCVersion::Response& res)
|
||||
{
|
||||
res.version = DAEMON_RPC_VERSION;
|
||||
res.version = DAEMON_RPC_VERSION_ZMQ;
|
||||
res.status = Message::STATUS_OK;
|
||||
}
|
||||
|
||||
@ -754,11 +837,15 @@ namespace rpc
|
||||
REQ_RESP_TYPES_MACRO(request_type, GetRandomOutputsForAmounts, req_json, resp_message, handle);
|
||||
REQ_RESP_TYPES_MACRO(request_type, SendRawTx, req_json, resp_message, handle);
|
||||
REQ_RESP_TYPES_MACRO(request_type, GetInfo, req_json, resp_message, handle);
|
||||
REQ_RESP_TYPES_MACRO(request_type, StartMining, req_json, resp_message, handle);
|
||||
REQ_RESP_TYPES_MACRO(request_type, StopMining, req_json, resp_message, handle);
|
||||
REQ_RESP_TYPES_MACRO(request_type, MiningStatus, req_json, resp_message, handle);
|
||||
REQ_RESP_TYPES_MACRO(request_type, SaveBC, req_json, resp_message, handle);
|
||||
REQ_RESP_TYPES_MACRO(request_type, GetBlockHash, req_json, resp_message, handle);
|
||||
REQ_RESP_TYPES_MACRO(request_type, GetLastBlockHeader, req_json, resp_message, handle);
|
||||
REQ_RESP_TYPES_MACRO(request_type, GetBlockHeaderByHash, req_json, resp_message, handle);
|
||||
REQ_RESP_TYPES_MACRO(request_type, GetBlockHeaderByHeight, req_json, resp_message, handle);
|
||||
REQ_RESP_TYPES_MACRO(request_type, GetBlockHeadersByHeight, req_json, resp_message, handle);
|
||||
REQ_RESP_TYPES_MACRO(request_type, GetPeerList, req_json, resp_message, handle);
|
||||
REQ_RESP_TYPES_MACRO(request_type, SetLogLevel, req_json, resp_message, handle);
|
||||
REQ_RESP_TYPES_MACRO(request_type, GetTransactionPool, req_json, resp_message, handle);
|
||||
|
@ -92,6 +92,8 @@ class DaemonHandler : public RpcHandler
|
||||
|
||||
void handle(const GetBlockHeaderByHeight::Request& req, GetBlockHeaderByHeight::Response& res);
|
||||
|
||||
void handle(const GetBlockHeadersByHeight::Request& req, GetBlockHeadersByHeight::Response& res);
|
||||
|
||||
void handle(const GetBlock::Request& req, GetBlock::Response& res);
|
||||
|
||||
void handle(const GetPeerList::Request& req, GetPeerList::Response& res);
|
||||
@ -108,10 +110,6 @@ class DaemonHandler : public RpcHandler
|
||||
|
||||
void handle(const StopDaemon::Request& req, StopDaemon::Response& res);
|
||||
|
||||
void handle(const FastExit::Request& req, FastExit::Response& res);
|
||||
|
||||
void handle(const OutPeers::Request& req, OutPeers::Response& res);
|
||||
|
||||
void handle(const StartSaveGraph::Request& req, StartSaveGraph::Response& res);
|
||||
|
||||
void handle(const StopSaveGraph::Request& req, StopSaveGraph::Response& res);
|
||||
|
@ -43,12 +43,16 @@ const char* const KeyImagesSpent::name = "key_images_spent";
|
||||
const char* const GetTxGlobalOutputIndices::name = "get_tx_global_output_indices";
|
||||
const char* const GetRandomOutputsForAmounts::name = "get_random_outputs_for_amounts";
|
||||
const char* const SendRawTx::name = "send_raw_tx";
|
||||
const char* const StartMining::name = "start_mining";
|
||||
const char* const StopMining::name = "stop_mining";
|
||||
const char* const MiningStatus::name = "mining_status";
|
||||
const char* const GetInfo::name = "get_info";
|
||||
const char* const SaveBC::name = "save_bc";
|
||||
const char* const GetBlockHash::name = "get_block_hash";
|
||||
const char* const GetLastBlockHeader::name = "get_last_block_header";
|
||||
const char* const GetBlockHeaderByHash::name = "get_block_header_by_hash";
|
||||
const char* const GetBlockHeaderByHeight::name = "get_block_header_by_height";
|
||||
const char* const GetBlockHeadersByHeight::name = "get_block_headers_by_height";
|
||||
const char* const GetPeerList::name = "get_peer_list";
|
||||
const char* const SetLogLevel::name = "set_log_level";
|
||||
const char* const GetTransactionPool::name = "get_transaction_pool";
|
||||
@ -95,6 +99,7 @@ rapidjson::Value GetBlocksFast::Request::toJson(rapidjson::Document& doc) const
|
||||
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, block_ids, block_ids);
|
||||
val.AddMember("start_height", start_height, al);
|
||||
val.AddMember("prune", prune, al);
|
||||
|
||||
return val;
|
||||
}
|
||||
@ -103,6 +108,7 @@ void GetBlocksFast::Request::fromJson(rapidjson::Value& val)
|
||||
{
|
||||
GET_FROM_JSON_OBJECT(val, block_ids, block_ids);
|
||||
GET_FROM_JSON_OBJECT(val, start_height, start_height);
|
||||
GET_FROM_JSON_OBJECT(val, prune, prune);
|
||||
}
|
||||
|
||||
rapidjson::Value GetBlocksFast::Response::toJson(rapidjson::Document& doc) const
|
||||
@ -332,11 +338,96 @@ rapidjson::Value SendRawTx::Response::toJson(rapidjson::Document& doc) const
|
||||
return val;
|
||||
}
|
||||
|
||||
|
||||
void SendRawTx::Response::fromJson(rapidjson::Value& val)
|
||||
{
|
||||
GET_FROM_JSON_OBJECT(val, relayed, relayed);
|
||||
}
|
||||
|
||||
rapidjson::Value StartMining::Request::toJson(rapidjson::Document& doc) const
|
||||
{
|
||||
auto val = Message::toJson(doc);
|
||||
|
||||
auto& al = doc.GetAllocator();
|
||||
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, miner_address, miner_address);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, threads_count, threads_count);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, do_background_mining, do_background_mining);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, ignore_battery, ignore_battery);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
void StartMining::Request::fromJson(rapidjson::Value& val)
|
||||
{
|
||||
GET_FROM_JSON_OBJECT(val, miner_address, miner_address);
|
||||
GET_FROM_JSON_OBJECT(val, threads_count, threads_count);
|
||||
GET_FROM_JSON_OBJECT(val, do_background_mining, do_background_mining);
|
||||
GET_FROM_JSON_OBJECT(val, ignore_battery, ignore_battery);
|
||||
}
|
||||
|
||||
rapidjson::Value StartMining::Response::toJson(rapidjson::Document& doc) const
|
||||
{
|
||||
return Message::toJson(doc);
|
||||
}
|
||||
|
||||
void StartMining::Response::fromJson(rapidjson::Value& val)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
rapidjson::Value StopMining::Request::toJson(rapidjson::Document& doc) const
|
||||
{
|
||||
return Message::toJson(doc);
|
||||
}
|
||||
|
||||
void StopMining::Request::fromJson(rapidjson::Value& val)
|
||||
{
|
||||
}
|
||||
|
||||
rapidjson::Value StopMining::Response::toJson(rapidjson::Document& doc) const
|
||||
{
|
||||
return Message::toJson(doc);
|
||||
}
|
||||
|
||||
void StopMining::Response::fromJson(rapidjson::Value& val)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
rapidjson::Value MiningStatus::Request::toJson(rapidjson::Document& doc) const
|
||||
{
|
||||
return Message::toJson(doc);
|
||||
}
|
||||
|
||||
void MiningStatus::Request::fromJson(rapidjson::Value& val)
|
||||
{
|
||||
}
|
||||
|
||||
rapidjson::Value MiningStatus::Response::toJson(rapidjson::Document& doc) const
|
||||
{
|
||||
auto val = Message::toJson(doc);
|
||||
|
||||
auto& al = doc.GetAllocator();
|
||||
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, active, active);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, speed, speed);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, threads_count, threads_count);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, address, address);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, is_background_mining_enabled, is_background_mining_enabled);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
void MiningStatus::Response::fromJson(rapidjson::Value& val)
|
||||
{
|
||||
GET_FROM_JSON_OBJECT(val, active, active);
|
||||
GET_FROM_JSON_OBJECT(val, speed, speed);
|
||||
GET_FROM_JSON_OBJECT(val, threads_count, threads_count);
|
||||
GET_FROM_JSON_OBJECT(val, address, address);
|
||||
GET_FROM_JSON_OBJECT(val, is_background_mining_enabled, is_background_mining_enabled);
|
||||
}
|
||||
|
||||
|
||||
rapidjson::Value GetInfo::Request::toJson(rapidjson::Document& doc) const
|
||||
{
|
||||
@ -353,38 +444,14 @@ rapidjson::Value GetInfo::Response::toJson(rapidjson::Document& doc) const
|
||||
|
||||
auto& al = doc.GetAllocator();
|
||||
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, height, height);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, target_height, target_height);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, difficulty, difficulty);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, target, target);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, tx_count, tx_count);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, tx_pool_size, tx_pool_size);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, alt_blocks_count, alt_blocks_count);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, outgoing_connections_count, outgoing_connections_count);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, incoming_connections_count, incoming_connections_count);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, white_peerlist_size, white_peerlist_size);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, grey_peerlist_size, grey_peerlist_size);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, testnet, testnet);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, top_block_hash, top_block_hash);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, info, info);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
void GetInfo::Response::fromJson(rapidjson::Value& val)
|
||||
{
|
||||
GET_FROM_JSON_OBJECT(val, height, height);
|
||||
GET_FROM_JSON_OBJECT(val, target_height, target_height);
|
||||
GET_FROM_JSON_OBJECT(val, difficulty, difficulty);
|
||||
GET_FROM_JSON_OBJECT(val, target, target);
|
||||
GET_FROM_JSON_OBJECT(val, tx_count, tx_count);
|
||||
GET_FROM_JSON_OBJECT(val, tx_pool_size, tx_pool_size);
|
||||
GET_FROM_JSON_OBJECT(val, alt_blocks_count, alt_blocks_count);
|
||||
GET_FROM_JSON_OBJECT(val, outgoing_connections_count, outgoing_connections_count);
|
||||
GET_FROM_JSON_OBJECT(val, incoming_connections_count, incoming_connections_count);
|
||||
GET_FROM_JSON_OBJECT(val, white_peerlist_size, white_peerlist_size);
|
||||
GET_FROM_JSON_OBJECT(val, grey_peerlist_size, grey_peerlist_size);
|
||||
GET_FROM_JSON_OBJECT(val, testnet, testnet);
|
||||
GET_FROM_JSON_OBJECT(val, top_block_hash, top_block_hash);
|
||||
GET_FROM_JSON_OBJECT(val, info, info);
|
||||
}
|
||||
|
||||
|
||||
@ -544,6 +611,39 @@ void GetBlockHeaderByHeight::Response::fromJson(rapidjson::Value& val)
|
||||
}
|
||||
|
||||
|
||||
rapidjson::Value GetBlockHeadersByHeight::Request::toJson(rapidjson::Document& doc) const
|
||||
{
|
||||
auto val = Message::toJson(doc);
|
||||
|
||||
auto& al = doc.GetAllocator();
|
||||
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, heights, heights);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
void GetBlockHeadersByHeight::Request::fromJson(rapidjson::Value& val)
|
||||
{
|
||||
GET_FROM_JSON_OBJECT(val, heights, heights);
|
||||
}
|
||||
|
||||
rapidjson::Value GetBlockHeadersByHeight::Response::toJson(rapidjson::Document& doc) const
|
||||
{
|
||||
auto val = Message::toJson(doc);
|
||||
|
||||
auto& al = doc.GetAllocator();
|
||||
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, headers, headers);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
void GetBlockHeadersByHeight::Response::fromJson(rapidjson::Value& val)
|
||||
{
|
||||
GET_FROM_JSON_OBJECT(val, headers, headers);
|
||||
}
|
||||
|
||||
|
||||
rapidjson::Value GetPeerList::Request::toJson(rapidjson::Document& doc) const
|
||||
{
|
||||
auto val = Message::toJson(doc);
|
||||
|
@ -89,6 +89,7 @@ BEGIN_RPC_MESSAGE_CLASS(GetBlocksFast);
|
||||
BEGIN_RPC_MESSAGE_REQUEST;
|
||||
RPC_MESSAGE_MEMBER(std::list<crypto::hash>, block_ids);
|
||||
RPC_MESSAGE_MEMBER(uint64_t, start_height);
|
||||
RPC_MESSAGE_MEMBER(bool, prune);
|
||||
END_RPC_MESSAGE_REQUEST;
|
||||
BEGIN_RPC_MESSAGE_RESPONSE;
|
||||
RPC_MESSAGE_MEMBER(std::vector<cryptonote::rpc::block_with_transactions>, blocks);
|
||||
@ -171,10 +172,11 @@ END_RPC_MESSAGE_CLASS;
|
||||
BEGIN_RPC_MESSAGE_CLASS(StartMining);
|
||||
BEGIN_RPC_MESSAGE_REQUEST;
|
||||
RPC_MESSAGE_MEMBER(std::string, miner_address);
|
||||
RPC_MESSAGE_MEMBER(uint64_t, thread_count);
|
||||
RPC_MESSAGE_MEMBER(uint64_t, threads_count);
|
||||
RPC_MESSAGE_MEMBER(bool, do_background_mining);
|
||||
RPC_MESSAGE_MEMBER(bool, ignore_battery);
|
||||
END_RPC_MESSAGE_REQUEST;
|
||||
BEGIN_RPC_MESSAGE_RESPONSE;
|
||||
RPC_MESSAGE_MEMBER(bool, success);
|
||||
END_RPC_MESSAGE_RESPONSE;
|
||||
END_RPC_MESSAGE_CLASS;
|
||||
|
||||
@ -182,19 +184,7 @@ BEGIN_RPC_MESSAGE_CLASS(GetInfo);
|
||||
BEGIN_RPC_MESSAGE_REQUEST;
|
||||
END_RPC_MESSAGE_REQUEST;
|
||||
BEGIN_RPC_MESSAGE_RESPONSE;
|
||||
RPC_MESSAGE_MEMBER(uint64_t, height);
|
||||
RPC_MESSAGE_MEMBER(uint64_t, target_height);
|
||||
RPC_MESSAGE_MEMBER(uint64_t, difficulty);
|
||||
RPC_MESSAGE_MEMBER(uint64_t, target);
|
||||
RPC_MESSAGE_MEMBER(uint64_t, tx_count);
|
||||
RPC_MESSAGE_MEMBER(uint64_t, tx_pool_size);
|
||||
RPC_MESSAGE_MEMBER(uint64_t, alt_blocks_count);
|
||||
RPC_MESSAGE_MEMBER(uint64_t, outgoing_connections_count);
|
||||
RPC_MESSAGE_MEMBER(uint64_t, incoming_connections_count);
|
||||
RPC_MESSAGE_MEMBER(uint64_t, white_peerlist_size);
|
||||
RPC_MESSAGE_MEMBER(uint64_t, grey_peerlist_size);
|
||||
RPC_MESSAGE_MEMBER(bool, testnet);
|
||||
RPC_MESSAGE_MEMBER(crypto::hash, top_block_hash);
|
||||
RPC_MESSAGE_MEMBER(DaemonInfo, info);
|
||||
END_RPC_MESSAGE_RESPONSE;
|
||||
END_RPC_MESSAGE_CLASS;
|
||||
|
||||
@ -202,7 +192,6 @@ BEGIN_RPC_MESSAGE_CLASS(StopMining);
|
||||
BEGIN_RPC_MESSAGE_REQUEST;
|
||||
END_RPC_MESSAGE_REQUEST;
|
||||
BEGIN_RPC_MESSAGE_RESPONSE;
|
||||
RPC_MESSAGE_MEMBER(bool, success);
|
||||
END_RPC_MESSAGE_RESPONSE;
|
||||
END_RPC_MESSAGE_CLASS;
|
||||
|
||||
@ -212,8 +201,9 @@ BEGIN_RPC_MESSAGE_CLASS(MiningStatus);
|
||||
BEGIN_RPC_MESSAGE_RESPONSE;
|
||||
RPC_MESSAGE_MEMBER(bool, active);
|
||||
RPC_MESSAGE_MEMBER(uint64_t, speed);
|
||||
RPC_MESSAGE_MEMBER(uint64_t, thread_count);
|
||||
RPC_MESSAGE_MEMBER(uint64_t, threads_count);
|
||||
RPC_MESSAGE_MEMBER(std::string, address);
|
||||
RPC_MESSAGE_MEMBER(bool, is_background_mining_enabled);
|
||||
END_RPC_MESSAGE_RESPONSE;
|
||||
END_RPC_MESSAGE_CLASS;
|
||||
|
||||
@ -273,6 +263,15 @@ BEGIN_RPC_MESSAGE_CLASS(GetBlockHeaderByHeight);
|
||||
END_RPC_MESSAGE_RESPONSE;
|
||||
END_RPC_MESSAGE_CLASS;
|
||||
|
||||
BEGIN_RPC_MESSAGE_CLASS(GetBlockHeadersByHeight);
|
||||
BEGIN_RPC_MESSAGE_REQUEST;
|
||||
RPC_MESSAGE_MEMBER(std::vector<uint64_t>, heights);
|
||||
END_RPC_MESSAGE_REQUEST;
|
||||
BEGIN_RPC_MESSAGE_RESPONSE;
|
||||
RPC_MESSAGE_MEMBER(std::vector<cryptonote::rpc::BlockHeaderResponse>, headers);
|
||||
END_RPC_MESSAGE_RESPONSE;
|
||||
END_RPC_MESSAGE_CLASS;
|
||||
|
||||
BEGIN_RPC_MESSAGE_CLASS(GetBlock);
|
||||
BEGIN_RPC_MESSAGE_REQUEST;
|
||||
END_RPC_MESSAGE_REQUEST;
|
||||
@ -334,20 +333,6 @@ BEGIN_RPC_MESSAGE_CLASS(StopDaemon);
|
||||
END_RPC_MESSAGE_RESPONSE;
|
||||
END_RPC_MESSAGE_CLASS;
|
||||
|
||||
BEGIN_RPC_MESSAGE_CLASS(FastExit);
|
||||
BEGIN_RPC_MESSAGE_REQUEST;
|
||||
END_RPC_MESSAGE_REQUEST;
|
||||
BEGIN_RPC_MESSAGE_RESPONSE;
|
||||
END_RPC_MESSAGE_RESPONSE;
|
||||
END_RPC_MESSAGE_CLASS;
|
||||
|
||||
BEGIN_RPC_MESSAGE_CLASS(OutPeers);
|
||||
BEGIN_RPC_MESSAGE_REQUEST;
|
||||
END_RPC_MESSAGE_REQUEST;
|
||||
BEGIN_RPC_MESSAGE_RESPONSE;
|
||||
END_RPC_MESSAGE_RESPONSE;
|
||||
END_RPC_MESSAGE_CLASS;
|
||||
|
||||
BEGIN_RPC_MESSAGE_CLASS(StartSaveGraph);
|
||||
BEGIN_RPC_MESSAGE_REQUEST;
|
||||
END_RPC_MESSAGE_REQUEST;
|
||||
|
@ -34,10 +34,10 @@ namespace cryptonote
|
||||
namespace rpc
|
||||
{
|
||||
|
||||
static const uint32_t DAEMON_RPC_VERSION_MINOR = 0;
|
||||
static const uint32_t DAEMON_RPC_VERSION_MAJOR = 1;
|
||||
static const uint32_t DAEMON_RPC_VERSION_ZMQ_MINOR = 0;
|
||||
static const uint32_t DAEMON_RPC_VERSION_ZMQ_MAJOR = 1;
|
||||
|
||||
static const uint32_t DAEMON_RPC_VERSION = DAEMON_RPC_VERSION_MINOR + (DAEMON_RPC_VERSION_MAJOR << 16);
|
||||
static const uint32_t DAEMON_RPC_VERSION_ZMQ = DAEMON_RPC_VERSION_ZMQ_MINOR + (DAEMON_RPC_VERSION_ZMQ_MAJOR << 16);
|
||||
|
||||
} // namespace rpc
|
||||
|
||||
|
@ -53,7 +53,7 @@ rapidjson::Value Message::toJson(rapidjson::Document& doc) const
|
||||
|
||||
val.AddMember("status", rapidjson::StringRef(status.c_str()), al);
|
||||
val.AddMember("error_details", rapidjson::StringRef(error_details.c_str()), al);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, rpc_version, DAEMON_RPC_VERSION);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, rpc_version, DAEMON_RPC_VERSION_ZMQ);
|
||||
|
||||
return val;
|
||||
}
|
||||
|
@ -164,6 +164,26 @@ namespace rpc
|
||||
uint64_t reward;
|
||||
};
|
||||
|
||||
struct DaemonInfo
|
||||
{
|
||||
uint64_t height;
|
||||
uint64_t target_height;
|
||||
uint64_t difficulty;
|
||||
uint64_t target;
|
||||
uint64_t tx_count;
|
||||
uint64_t tx_pool_size;
|
||||
uint64_t alt_blocks_count;
|
||||
uint64_t outgoing_connections_count;
|
||||
uint64_t incoming_connections_count;
|
||||
uint64_t white_peerlist_size;
|
||||
uint64_t grey_peerlist_size;
|
||||
bool testnet;
|
||||
crypto::hash top_block_hash;
|
||||
uint64_t cumulative_difficulty;
|
||||
uint64_t block_size_limit;
|
||||
uint64_t start_time;
|
||||
};
|
||||
|
||||
} // namespace rpc
|
||||
|
||||
} // namespace cryptonote
|
||||
|
@ -45,10 +45,6 @@ ZmqServer::ZmqServer(RpcHandler& h) :
|
||||
|
||||
ZmqServer::~ZmqServer()
|
||||
{
|
||||
for (zmq::socket_t* socket : sockets)
|
||||
{
|
||||
delete socket;
|
||||
}
|
||||
}
|
||||
|
||||
void ZmqServer::serve()
|
||||
@ -58,31 +54,36 @@ void ZmqServer::serve()
|
||||
{
|
||||
try
|
||||
{
|
||||
for (zmq::socket_t* socket : sockets)
|
||||
zmq::message_t message;
|
||||
|
||||
if (!rep_socket)
|
||||
{
|
||||
zmq::message_t message;
|
||||
throw std::runtime_error("ZMQ RPC server reply socket is null");
|
||||
}
|
||||
while (rep_socket->recv(&message))
|
||||
{
|
||||
std::string message_string(reinterpret_cast<const char *>(message.data()), message.size());
|
||||
|
||||
while (socket->recv(&message))
|
||||
{
|
||||
std::string message_string(reinterpret_cast<const char *>(message.data()), message.size());
|
||||
MDEBUG(std::string("Received RPC request: \"") + message_string + "\"");
|
||||
|
||||
MDEBUG(std::string("Received RPC request: \"") + message_string + "\"");
|
||||
std::string response = handler.handle(message_string);
|
||||
|
||||
std::string response = handler.handle(message_string);
|
||||
zmq::message_t reply(response.size());
|
||||
memcpy((void *) reply.data(), response.c_str(), response.size());
|
||||
|
||||
zmq::message_t reply(response.size());
|
||||
memcpy((void *) reply.data(), response.c_str(), response.size());
|
||||
|
||||
socket->send(reply);
|
||||
MDEBUG(std::string("Sent RPC reply: \"") + response + "\"");
|
||||
}
|
||||
rep_socket->send(reply);
|
||||
MDEBUG(std::string("Sent RPC reply: \"") + response + "\"");
|
||||
|
||||
}
|
||||
}
|
||||
catch (boost::thread_interrupted& e)
|
||||
catch (const boost::thread_interrupted& e)
|
||||
{
|
||||
MDEBUG("ZMQ Server thread interrupted.");
|
||||
}
|
||||
catch (const zmq::error_t& e)
|
||||
{
|
||||
MERROR(std::string("ZMQ error: ") + e.what());
|
||||
}
|
||||
boost::this_thread::interruption_point();
|
||||
}
|
||||
}
|
||||
@ -95,26 +96,20 @@ bool ZmqServer::addIPCSocket(std::string address, std::string port)
|
||||
|
||||
bool ZmqServer::addTCPSocket(std::string address, std::string port)
|
||||
{
|
||||
zmq::socket_t *new_socket = nullptr;
|
||||
try
|
||||
{
|
||||
std::string addr_prefix("tcp://");
|
||||
|
||||
new_socket = new zmq::socket_t(context, ZMQ_REP);
|
||||
rep_socket.reset(new zmq::socket_t(context, ZMQ_REP));
|
||||
|
||||
new_socket->setsockopt(ZMQ_RCVTIMEO, DEFAULT_RPC_RECV_TIMEOUT_MS);
|
||||
rep_socket->setsockopt(ZMQ_RCVTIMEO, DEFAULT_RPC_RECV_TIMEOUT_MS);
|
||||
|
||||
std::string bind_address = addr_prefix + address + std::string(":") + port;
|
||||
new_socket->bind(bind_address.c_str());
|
||||
sockets.push_back(new_socket);
|
||||
rep_socket->bind(bind_address.c_str());
|
||||
}
|
||||
catch (std::exception& e)
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
MERROR(std::string("Error creating ZMQ Socket: ") + e.what());
|
||||
if (new_socket)
|
||||
{
|
||||
delete new_socket;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
@ -29,12 +29,11 @@
|
||||
#pragma once
|
||||
|
||||
#include <boost/thread/thread.hpp>
|
||||
#include <boost/program_options/options_description.hpp>
|
||||
#include <boost/program_options/variables_map.hpp>
|
||||
#include "common/command_line.h"
|
||||
|
||||
#include <zmq.hpp>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
#include "common/command_line.h"
|
||||
|
||||
#include "rpc_handler.h"
|
||||
|
||||
@ -75,7 +74,7 @@ class ZmqServer
|
||||
|
||||
boost::thread run_thread;
|
||||
|
||||
std::vector<zmq::socket_t*> sockets;
|
||||
std::unique_ptr<zmq::socket_t> rep_socket;
|
||||
};
|
||||
|
||||
|
||||
|
@ -28,6 +28,7 @@
|
||||
|
||||
#include "json_object.h"
|
||||
|
||||
#include <limits>
|
||||
#include "string_tools.h"
|
||||
|
||||
namespace cryptonote
|
||||
@ -36,6 +37,74 @@ namespace cryptonote
|
||||
namespace json
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
template<typename Source, typename Destination>
|
||||
constexpr bool precision_loss()
|
||||
{
|
||||
return
|
||||
std::numeric_limits<Destination>::is_signed != std::numeric_limits<Source>::is_signed ||
|
||||
std::numeric_limits<Destination>::min() > std::numeric_limits<Source>::min() ||
|
||||
std::numeric_limits<Destination>::max() < std::numeric_limits<Source>::max();
|
||||
}
|
||||
|
||||
template<typename Source, typename Type>
|
||||
void convert_numeric(Source source, Type& i)
|
||||
{
|
||||
static_assert(
|
||||
std::numeric_limits<Source>::is_signed == std::numeric_limits<Type>::is_signed,
|
||||
"source and destination signs do not match"
|
||||
);
|
||||
if (source < std::numeric_limits<Type>::min())
|
||||
{
|
||||
throw WRONG_TYPE{"numeric underflow"};
|
||||
}
|
||||
if (std::numeric_limits<Type>::max() < source)
|
||||
{
|
||||
throw WRONG_TYPE{"numeric overflow"};
|
||||
}
|
||||
i = Type(source);
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
void to_int(const rapidjson::Value& val, Type& i)
|
||||
{
|
||||
if (!val.IsInt())
|
||||
{
|
||||
throw WRONG_TYPE{"integer"};
|
||||
}
|
||||
convert_numeric(val.GetInt(), i);
|
||||
}
|
||||
template<typename Type>
|
||||
void to_int64(const rapidjson::Value& val, Type& i)
|
||||
{
|
||||
if (!val.IsInt64())
|
||||
{
|
||||
throw WRONG_TYPE{"integer"};
|
||||
}
|
||||
convert_numeric(val.GetInt64(), i);
|
||||
}
|
||||
|
||||
template<typename Type>
|
||||
void to_uint(const rapidjson::Value& val, Type& i)
|
||||
{
|
||||
if (!val.IsUint())
|
||||
{
|
||||
throw WRONG_TYPE{"unsigned integer"};
|
||||
}
|
||||
convert_numeric(val.GetUint(), i);
|
||||
}
|
||||
template<typename Type>
|
||||
void to_uint64(const rapidjson::Value& val, Type& i)
|
||||
{
|
||||
if (!val.IsUint64())
|
||||
{
|
||||
throw WRONG_TYPE{"unsigned integer"};
|
||||
}
|
||||
convert_numeric(val.GetUint64(), i);
|
||||
}
|
||||
}
|
||||
|
||||
void toJsonValue(rapidjson::Document& doc, const std::string& i, rapidjson::Value& val)
|
||||
{
|
||||
val = rapidjson::Value(i.c_str(), doc.GetAllocator());
|
||||
@ -65,100 +134,81 @@ void fromJsonValue(const rapidjson::Value& val, bool& b)
|
||||
b = val.GetBool();
|
||||
}
|
||||
|
||||
void toJsonValue(rapidjson::Document& doc, const uint8_t& i, rapidjson::Value& val)
|
||||
void fromJsonValue(const rapidjson::Value& val, unsigned char& i)
|
||||
{
|
||||
to_uint(val, i);
|
||||
}
|
||||
|
||||
void fromJsonValue(const rapidjson::Value& val, char& i)
|
||||
{
|
||||
to_int(val, i);
|
||||
}
|
||||
|
||||
void fromJsonValue(const rapidjson::Value& val, signed char& i)
|
||||
{
|
||||
to_int(val, i);
|
||||
}
|
||||
|
||||
void fromJsonValue(const rapidjson::Value& val, unsigned short& i)
|
||||
{
|
||||
to_uint(val, i);
|
||||
}
|
||||
|
||||
void fromJsonValue(const rapidjson::Value& val, short& i)
|
||||
{
|
||||
to_int(val, i);
|
||||
}
|
||||
|
||||
void toJsonValue(rapidjson::Document& doc, const unsigned int i, rapidjson::Value& val)
|
||||
{
|
||||
val = rapidjson::Value(i);
|
||||
}
|
||||
|
||||
|
||||
void fromJsonValue(const rapidjson::Value& val, uint8_t& i)
|
||||
void fromJsonValue(const rapidjson::Value& val, unsigned int& i)
|
||||
{
|
||||
if (!val.IsUint())
|
||||
{
|
||||
throw WRONG_TYPE("unsigned integer");
|
||||
}
|
||||
|
||||
i = (uint8_t)( val.GetUint() & 0xFF);
|
||||
to_uint(val, i);
|
||||
}
|
||||
|
||||
void toJsonValue(rapidjson::Document& doc, const int8_t& i, rapidjson::Value& val)
|
||||
void toJsonValue(rapidjson::Document& doc, const int i, rapidjson::Value& val)
|
||||
{
|
||||
val = rapidjson::Value(i);
|
||||
}
|
||||
|
||||
|
||||
void fromJsonValue(const rapidjson::Value& val, int8_t& i)
|
||||
void fromJsonValue(const rapidjson::Value& val, int& i)
|
||||
{
|
||||
if (!val.IsInt())
|
||||
{
|
||||
throw WRONG_TYPE("integer");
|
||||
}
|
||||
|
||||
i = (int8_t) ( val.GetInt() & 0xFF);
|
||||
to_int(val, i);
|
||||
}
|
||||
|
||||
void toJsonValue(rapidjson::Document& doc, const uint16_t& i, rapidjson::Value& val)
|
||||
void toJsonValue(rapidjson::Document& doc, const unsigned long long i, rapidjson::Value& val)
|
||||
{
|
||||
val = rapidjson::Value(i);
|
||||
static_assert(!precision_loss<unsigned long long, std::uint64_t>(), "precision loss");
|
||||
val = rapidjson::Value(std::uint64_t(i));
|
||||
}
|
||||
|
||||
|
||||
void fromJsonValue(const rapidjson::Value& val, uint16_t& i)
|
||||
void fromJsonValue(const rapidjson::Value& val, unsigned long long& i)
|
||||
{
|
||||
if (!val.IsUint())
|
||||
{
|
||||
throw WRONG_TYPE("unsigned integer");
|
||||
}
|
||||
|
||||
i = (uint16_t) ( val.GetUint() & 0xFFFF);
|
||||
to_uint64(val, i);
|
||||
}
|
||||
|
||||
void toJsonValue(rapidjson::Document& doc, const int32_t& i, rapidjson::Value& val)
|
||||
void toJsonValue(rapidjson::Document& doc, const long long i, rapidjson::Value& val)
|
||||
{
|
||||
val = rapidjson::Value(i);
|
||||
static_assert(!precision_loss<long long, std::int64_t>(), "precision loss");
|
||||
val = rapidjson::Value(std::int64_t(i));
|
||||
}
|
||||
|
||||
|
||||
void fromJsonValue(const rapidjson::Value& val, int32_t& i)
|
||||
void fromJsonValue(const rapidjson::Value& val, long long& i)
|
||||
{
|
||||
if (!val.IsInt())
|
||||
{
|
||||
throw WRONG_TYPE("signed integer");
|
||||
}
|
||||
|
||||
i = val.GetInt();
|
||||
to_int64(val, i);
|
||||
}
|
||||
|
||||
void toJsonValue(rapidjson::Document& doc, const uint32_t& i, rapidjson::Value& val)
|
||||
void fromJsonValue(const rapidjson::Value& val, unsigned long& i)
|
||||
{
|
||||
val = rapidjson::Value(i);
|
||||
to_uint64(val, i);
|
||||
}
|
||||
|
||||
|
||||
void fromJsonValue(const rapidjson::Value& val, uint32_t& i)
|
||||
void fromJsonValue(const rapidjson::Value& val, long& i)
|
||||
{
|
||||
if (!val.IsUint())
|
||||
{
|
||||
throw WRONG_TYPE("unsigned integer");
|
||||
}
|
||||
|
||||
i = val.GetUint();
|
||||
}
|
||||
|
||||
void toJsonValue(rapidjson::Document& doc, const uint64_t& i, rapidjson::Value& val)
|
||||
{
|
||||
val = rapidjson::Value(i);
|
||||
}
|
||||
|
||||
|
||||
void fromJsonValue(const rapidjson::Value& val, uint64_t& i)
|
||||
{
|
||||
if (!val.IsUint64())
|
||||
{
|
||||
throw WRONG_TYPE("unsigned integer");
|
||||
}
|
||||
|
||||
i = val.GetUint64();
|
||||
to_int64(val, i);
|
||||
}
|
||||
|
||||
void toJsonValue(rapidjson::Document& doc, const cryptonote::transaction& tx, rapidjson::Value& val)
|
||||
@ -1063,6 +1113,53 @@ void fromJsonValue(const rapidjson::Value& val, rct::mgSig& sig)
|
||||
GET_FROM_JSON_OBJECT(val, sig.cc, cc);
|
||||
}
|
||||
|
||||
void toJsonValue(rapidjson::Document& doc, const cryptonote::rpc::DaemonInfo& info, rapidjson::Value& val)
|
||||
{
|
||||
val.SetObject();
|
||||
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, height, info.height);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, target_height, info.target_height);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, difficulty, info.difficulty);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, target, info.target);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, tx_count, info.tx_count);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, tx_pool_size, info.tx_pool_size);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, alt_blocks_count, info.alt_blocks_count);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, outgoing_connections_count, info.outgoing_connections_count);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, incoming_connections_count, info.incoming_connections_count);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, white_peerlist_size, info.white_peerlist_size);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, grey_peerlist_size, info.grey_peerlist_size);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, testnet, info.testnet);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, top_block_hash, info.top_block_hash);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, cumulative_difficulty, info.cumulative_difficulty);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, block_size_limit, info.block_size_limit);
|
||||
INSERT_INTO_JSON_OBJECT(val, doc, start_time, info.start_time);
|
||||
}
|
||||
|
||||
void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::DaemonInfo& info)
|
||||
{
|
||||
if (!val.IsObject())
|
||||
{
|
||||
throw WRONG_TYPE("json object");
|
||||
}
|
||||
|
||||
GET_FROM_JSON_OBJECT(val, info.height, height);
|
||||
GET_FROM_JSON_OBJECT(val, info.target_height, target_height);
|
||||
GET_FROM_JSON_OBJECT(val, info.difficulty, difficulty);
|
||||
GET_FROM_JSON_OBJECT(val, info.target, target);
|
||||
GET_FROM_JSON_OBJECT(val, info.tx_count, tx_count);
|
||||
GET_FROM_JSON_OBJECT(val, info.tx_pool_size, tx_pool_size);
|
||||
GET_FROM_JSON_OBJECT(val, info.alt_blocks_count, alt_blocks_count);
|
||||
GET_FROM_JSON_OBJECT(val, info.outgoing_connections_count, outgoing_connections_count);
|
||||
GET_FROM_JSON_OBJECT(val, info.incoming_connections_count, incoming_connections_count);
|
||||
GET_FROM_JSON_OBJECT(val, info.white_peerlist_size, white_peerlist_size);
|
||||
GET_FROM_JSON_OBJECT(val, info.grey_peerlist_size, grey_peerlist_size);
|
||||
GET_FROM_JSON_OBJECT(val, info.testnet, testnet);
|
||||
GET_FROM_JSON_OBJECT(val, info.top_block_hash, top_block_hash);
|
||||
GET_FROM_JSON_OBJECT(val, info.cumulative_difficulty, cumulative_difficulty);
|
||||
GET_FROM_JSON_OBJECT(val, info.block_size_limit, block_size_limit);
|
||||
GET_FROM_JSON_OBJECT(val, info.start_time, start_time);
|
||||
}
|
||||
|
||||
} // namespace json
|
||||
|
||||
} // namespace cryptonote
|
||||
|
@ -107,16 +107,22 @@ struct PARSE_FAIL : public JSON_ERROR
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Type>
|
||||
inline constexpr bool is_to_hex()
|
||||
{
|
||||
return std::is_pod<Type>() && !std::is_integral<Type>();
|
||||
}
|
||||
|
||||
|
||||
// POD to json value
|
||||
template <class Type>
|
||||
typename std::enable_if<std::is_pod<Type>::value, void>::type toJsonValue(rapidjson::Document& doc, const Type& pod, rapidjson::Value& value)
|
||||
typename std::enable_if<is_to_hex<Type>()>::type toJsonValue(rapidjson::Document& doc, const Type& pod, rapidjson::Value& value)
|
||||
{
|
||||
value = rapidjson::Value(epee::string_tools::pod_to_hex(pod).c_str(), doc.GetAllocator());
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
typename std::enable_if<std::is_pod<Type>::value, void>::type fromJsonValue(const rapidjson::Value& val, Type& t)
|
||||
typename std::enable_if<is_to_hex<Type>()>::type fromJsonValue(const rapidjson::Value& val, Type& t)
|
||||
{
|
||||
if (!val.IsString())
|
||||
{
|
||||
@ -138,23 +144,42 @@ void fromJsonValue(const rapidjson::Value& val, std::string& str);
|
||||
void toJsonValue(rapidjson::Document& doc, bool i, rapidjson::Value& val);
|
||||
void fromJsonValue(const rapidjson::Value& val, bool& b);
|
||||
|
||||
void toJsonValue(rapidjson::Document& doc, const uint8_t& i, rapidjson::Value& val);
|
||||
void fromJsonValue(const rapidjson::Value& val, uint8_t& i);
|
||||
// integers overloads for toJsonValue are not needed for standard promotions
|
||||
|
||||
void toJsonValue(rapidjson::Document& doc, const int8_t& i, rapidjson::Value& val);
|
||||
void fromJsonValue(const rapidjson::Value& val, int8_t& i);
|
||||
void fromJsonValue(const rapidjson::Value& val, unsigned char& i);
|
||||
|
||||
void toJsonValue(rapidjson::Document& doc, const uint16_t& i, rapidjson::Value& val);
|
||||
void fromJsonValue(const rapidjson::Value& val, uint16_t& i);
|
||||
void fromJsonValue(const rapidjson::Value& val, signed char& i);
|
||||
|
||||
void toJsonValue(rapidjson::Document& doc, const int32_t& i, rapidjson::Value& val);
|
||||
void fromJsonValue(const rapidjson::Value& val, int32_t& i);
|
||||
void fromJsonValue(const rapidjson::Value& val, char& i);
|
||||
|
||||
void toJsonValue(rapidjson::Document& doc, const uint32_t& i, rapidjson::Value& val);
|
||||
void fromJsonValue(const rapidjson::Value& val, uint32_t& i);
|
||||
void fromJsonValue(const rapidjson::Value& val, unsigned short& i);
|
||||
|
||||
void toJsonValue(rapidjson::Document& doc, const uint64_t& i, rapidjson::Value& val);
|
||||
void fromJsonValue(const rapidjson::Value& val, uint64_t& i);
|
||||
void fromJsonValue(const rapidjson::Value& val, short& i);
|
||||
|
||||
void toJsonValue(rapidjson::Document& doc, const unsigned i, rapidjson::Value& val);
|
||||
void fromJsonValue(const rapidjson::Value& val, unsigned& i);
|
||||
|
||||
void toJsonValue(rapidjson::Document& doc, const int, rapidjson::Value& val);
|
||||
void fromJsonValue(const rapidjson::Value& val, int& i);
|
||||
|
||||
|
||||
void toJsonValue(rapidjson::Document& doc, const unsigned long long i, rapidjson::Value& val);
|
||||
void fromJsonValue(const rapidjson::Value& val, unsigned long long& i);
|
||||
|
||||
void toJsonValue(rapidjson::Document& doc, const long long i, rapidjson::Value& val);
|
||||
void fromJsonValue(const rapidjson::Value& val, long long& i);
|
||||
|
||||
inline void toJsonValue(rapidjson::Document& doc, const unsigned long i, rapidjson::Value& val) {
|
||||
toJsonValue(doc, static_cast<unsigned long long>(i), val);
|
||||
}
|
||||
void fromJsonValue(const rapidjson::Value& val, unsigned long& i);
|
||||
|
||||
inline void toJsonValue(rapidjson::Document& doc, const long i, rapidjson::Value& val) {
|
||||
toJsonValue(doc, static_cast<long long>(i), val);
|
||||
}
|
||||
void fromJsonValue(const rapidjson::Value& val, long& i);
|
||||
|
||||
// end integers
|
||||
|
||||
void toJsonValue(rapidjson::Document& doc, const cryptonote::transaction& tx, rapidjson::Value& val);
|
||||
void fromJsonValue(const rapidjson::Value& val, cryptonote::transaction& tx);
|
||||
@ -255,6 +280,8 @@ void fromJsonValue(const rapidjson::Value& val, rct::boroSig& sig);
|
||||
void toJsonValue(rapidjson::Document& doc, const rct::mgSig& sig, rapidjson::Value& val);
|
||||
void fromJsonValue(const rapidjson::Value& val, rct::mgSig& sig);
|
||||
|
||||
void toJsonValue(rapidjson::Document& doc, const cryptonote::rpc::DaemonInfo& info, rapidjson::Value& val);
|
||||
void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::DaemonInfo& info);
|
||||
|
||||
template <typename Map>
|
||||
typename std::enable_if<sfinae::is_map_like<Map>::value, void>::type toJsonValue(rapidjson::Document& doc, const Map& map, rapidjson::Value& val);
|
||||
|
Loading…
Reference in New Issue
Block a user