From 77986023c37737e298fc7c3e9938cce0e10d8b80 Mon Sep 17 00:00:00 2001 From: Thomas Winget Date: Tue, 5 Sep 2017 12:20:27 -0400 Subject: json serialization for rpc-relevant monero types Structured {de-,}serialization methods for (many new) types which are used for requests or responses in the RPC. New types include RPC requests and responses, and structs which compose types within those. # Conflicts: # src/cryptonote_core/blockchain.cpp --- src/serialization/json_object.cpp | 1068 +++++++++++++++++++++++++++++++++++++ 1 file changed, 1068 insertions(+) create mode 100644 src/serialization/json_object.cpp (limited to 'src/serialization/json_object.cpp') diff --git a/src/serialization/json_object.cpp b/src/serialization/json_object.cpp new file mode 100644 index 000000000..50ef414f4 --- /dev/null +++ b/src/serialization/json_object.cpp @@ -0,0 +1,1068 @@ +// Copyright (c) 2016-2017, The Monero Project +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without modification, are +// permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, this list of +// conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright notice, this list +// of conditions and the following disclaimer in the documentation and/or other +// materials provided with the distribution. +// +// 3. Neither the name of the copyright holder nor the names of its contributors may be +// used to endorse or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +// THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +// STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF +// THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "json_object.h" + +#include "string_tools.h" + +namespace cryptonote +{ + +namespace json +{ + +void toJsonValue(rapidjson::Document& doc, const std::string& i, rapidjson::Value& val) +{ + val = rapidjson::Value(i.c_str(), doc.GetAllocator()); +} + +void fromJsonValue(const rapidjson::Value& val, std::string& str) +{ + if (!val.IsString()) + { + throw WRONG_TYPE("string"); + } + + str = val.GetString(); +} + +void toJsonValue(rapidjson::Document& doc, bool i, rapidjson::Value& val) +{ + val.SetBool(i); +} + +void fromJsonValue(const rapidjson::Value& val, bool& b) +{ + if (!val.IsBool()) + { + throw WRONG_TYPE("boolean"); + } + b = val.GetBool(); +} + +void toJsonValue(rapidjson::Document& doc, const uint8_t& i, rapidjson::Value& val) +{ + val = rapidjson::Value(i); +} + + +void fromJsonValue(const rapidjson::Value& val, uint8_t& i) +{ + if (!val.IsUint()) + { + throw WRONG_TYPE("unsigned integer"); + } + + i = (uint8_t)( val.GetUint() & 0xFF); +} + +void toJsonValue(rapidjson::Document& doc, const int8_t& i, rapidjson::Value& val) +{ + val = rapidjson::Value(i); +} + + +void fromJsonValue(const rapidjson::Value& val, int8_t& i) +{ + if (!val.IsInt()) + { + throw WRONG_TYPE("integer"); + } + + i = (int8_t) ( val.GetInt() & 0xFF); +} + +void toJsonValue(rapidjson::Document& doc, const uint16_t& i, rapidjson::Value& val) +{ + val = rapidjson::Value(i); +} + + +void fromJsonValue(const rapidjson::Value& val, uint16_t& i) +{ + if (!val.IsUint()) + { + throw WRONG_TYPE("unsigned integer"); + } + + i = (uint16_t) ( val.GetUint() & 0xFFFF); +} + +void toJsonValue(rapidjson::Document& doc, const int32_t& i, rapidjson::Value& val) +{ + val = rapidjson::Value(i); +} + + +void fromJsonValue(const rapidjson::Value& val, int32_t& i) +{ + if (!val.IsInt()) + { + throw WRONG_TYPE("signed integer"); + } + + i = val.GetInt(); +} + +void toJsonValue(rapidjson::Document& doc, const uint32_t& i, rapidjson::Value& val) +{ + val = rapidjson::Value(i); +} + + +void fromJsonValue(const rapidjson::Value& val, uint32_t& 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(); +} + +void toJsonValue(rapidjson::Document& doc, const cryptonote::transaction& tx, rapidjson::Value& val) +{ + val.SetObject(); + + INSERT_INTO_JSON_OBJECT(val, doc, version, tx.version); + INSERT_INTO_JSON_OBJECT(val, doc, unlock_time, tx.unlock_time); + INSERT_INTO_JSON_OBJECT(val, doc, vin, tx.vin); + INSERT_INTO_JSON_OBJECT(val, doc, vout, tx.vout); + INSERT_INTO_JSON_OBJECT(val, doc, extra, tx.extra); + INSERT_INTO_JSON_OBJECT(val, doc, signatures, tx.signatures); + INSERT_INTO_JSON_OBJECT(val, doc, rct_signatures, tx.rct_signatures); +} + + +void fromJsonValue(const rapidjson::Value& val, cryptonote::transaction& tx) +{ + if (!val.IsObject()) + { + throw WRONG_TYPE("json object"); + } + + GET_FROM_JSON_OBJECT(val, tx.version, version); + GET_FROM_JSON_OBJECT(val, tx.unlock_time, unlock_time); + GET_FROM_JSON_OBJECT(val, tx.vin, vin); + GET_FROM_JSON_OBJECT(val, tx.vout, vout); + GET_FROM_JSON_OBJECT(val, tx.extra, extra); + GET_FROM_JSON_OBJECT(val, tx.signatures, signatures); + GET_FROM_JSON_OBJECT(val, tx.rct_signatures, rct_signatures); +} + +void toJsonValue(rapidjson::Document& doc, const cryptonote::block& b, rapidjson::Value& val) +{ + val.SetObject(); + + INSERT_INTO_JSON_OBJECT(val, doc, major_version, b.major_version); + INSERT_INTO_JSON_OBJECT(val, doc, minor_version, b.minor_version); + INSERT_INTO_JSON_OBJECT(val, doc, timestamp, b.timestamp); + INSERT_INTO_JSON_OBJECT(val, doc, prev_id, b.prev_id); + INSERT_INTO_JSON_OBJECT(val, doc, nonce, b.nonce); + INSERT_INTO_JSON_OBJECT(val, doc, miner_tx, b.miner_tx); + INSERT_INTO_JSON_OBJECT(val, doc, tx_hashes, b.tx_hashes); +} + + +void fromJsonValue(const rapidjson::Value& val, cryptonote::block& b) +{ + if (!val.IsObject()) + { + throw WRONG_TYPE("json object"); + } + + GET_FROM_JSON_OBJECT(val, b.major_version, major_version); + GET_FROM_JSON_OBJECT(val, b.minor_version, minor_version); + GET_FROM_JSON_OBJECT(val, b.timestamp, timestamp); + GET_FROM_JSON_OBJECT(val, b.prev_id, prev_id); + GET_FROM_JSON_OBJECT(val, b.nonce, nonce); + GET_FROM_JSON_OBJECT(val, b.miner_tx, miner_tx); + GET_FROM_JSON_OBJECT(val, b.tx_hashes, tx_hashes); +} + +void toJsonValue(rapidjson::Document& doc, const cryptonote::txin_v& txin, rapidjson::Value& val) +{ + val.SetObject(); + + if (txin.type() == typeid(cryptonote::txin_gen)) + { + val.AddMember("type", "txin_gen", doc.GetAllocator()); + INSERT_INTO_JSON_OBJECT(val, doc, value, boost::get(txin)); + } + else if (txin.type() == typeid(cryptonote::txin_to_script)) + { + val.AddMember("type", "txin_to_script", doc.GetAllocator()); + INSERT_INTO_JSON_OBJECT(val, doc, value, boost::get(txin)); + } + else if (txin.type() == typeid(cryptonote::txin_to_scripthash)) + { + val.AddMember("type", "txin_to_scripthash", doc.GetAllocator()); + INSERT_INTO_JSON_OBJECT(val, doc, value, boost::get(txin)); + } + else if (txin.type() == typeid(cryptonote::txin_to_key)) + { + val.AddMember("type", "txin_to_key", doc.GetAllocator()); + INSERT_INTO_JSON_OBJECT(val, doc, value, boost::get(txin)); + } +} + + +void fromJsonValue(const rapidjson::Value& val, cryptonote::txin_v& txin) +{ + if (!val.IsObject()) + { + throw WRONG_TYPE("json object"); + } + + OBJECT_HAS_MEMBER_OR_THROW(val, "type") + OBJECT_HAS_MEMBER_OR_THROW(val, "value") + if (val["type"]== "txin_gen") + { + cryptonote::txin_gen tmpVal; + fromJsonValue(val["value"], tmpVal); + txin = tmpVal; + } + else if (val["type"]== "txin_to_script") + { + cryptonote::txin_to_script tmpVal; + fromJsonValue(val["value"], tmpVal); + txin = tmpVal; + } + else if (val["type"] == "txin_to_scripthash") + { + cryptonote::txin_to_scripthash tmpVal; + fromJsonValue(val["value"], tmpVal); + txin = tmpVal; + } + else if (val["type"] == "txin_to_key") + { + cryptonote::txin_to_key tmpVal; + fromJsonValue(val["value"], tmpVal); + txin = tmpVal; + } +} + +void toJsonValue(rapidjson::Document& doc, const cryptonote::txin_gen& txin, rapidjson::Value& val) +{ + val.SetObject(); + + INSERT_INTO_JSON_OBJECT(val, doc, height, txin.height); +} + + +void fromJsonValue(const rapidjson::Value& val, cryptonote::txin_gen& txin) +{ + if (!val.IsObject()) + { + throw WRONG_TYPE("json object"); + } + + GET_FROM_JSON_OBJECT(val, txin.height, height); +} + +void toJsonValue(rapidjson::Document& doc, const cryptonote::txin_to_script& txin, rapidjson::Value& val) +{ + val.SetObject(); + + INSERT_INTO_JSON_OBJECT(val, doc, prev, txin.prev); + INSERT_INTO_JSON_OBJECT(val, doc, prevout, txin.prevout); + INSERT_INTO_JSON_OBJECT(val, doc, sigset, txin.sigset); +} + + +void fromJsonValue(const rapidjson::Value& val, cryptonote::txin_to_script& txin) +{ + if (!val.IsObject()) + { + throw WRONG_TYPE("json object"); + } + + GET_FROM_JSON_OBJECT(val, txin.prev, prev); + GET_FROM_JSON_OBJECT(val, txin.prevout, prevout); + GET_FROM_JSON_OBJECT(val, txin.sigset, sigset); +} + +void toJsonValue(rapidjson::Document& doc, const cryptonote::txin_to_scripthash& txin, rapidjson::Value& val) +{ + val.SetObject(); + + INSERT_INTO_JSON_OBJECT(val, doc, prev, txin.prev); + INSERT_INTO_JSON_OBJECT(val, doc, prevout, txin.prevout); + INSERT_INTO_JSON_OBJECT(val, doc, script, txin.script); + INSERT_INTO_JSON_OBJECT(val, doc, sigset, txin.sigset); +} + + +void fromJsonValue(const rapidjson::Value& val, cryptonote::txin_to_scripthash& txin) +{ + if (!val.IsObject()) + { + throw WRONG_TYPE("json object"); + } + + GET_FROM_JSON_OBJECT(val, txin.prev, prev); + GET_FROM_JSON_OBJECT(val, txin.prevout, prevout); + GET_FROM_JSON_OBJECT(val, txin.script, script); + GET_FROM_JSON_OBJECT(val, txin.sigset, sigset); +} + +void toJsonValue(rapidjson::Document& doc, const cryptonote::txin_to_key& txin, rapidjson::Value& val) +{ + val.SetObject(); + + INSERT_INTO_JSON_OBJECT(val, doc, amount, txin.amount); + INSERT_INTO_JSON_OBJECT(val, doc, key_offsets, txin.key_offsets); + INSERT_INTO_JSON_OBJECT(val, doc, k_image, txin.k_image); +} + + +void fromJsonValue(const rapidjson::Value& val, cryptonote::txin_to_key& txin) +{ + if (!val.IsObject()) + { + throw WRONG_TYPE("json object"); + } + + GET_FROM_JSON_OBJECT(val, txin.amount, amount); + GET_FROM_JSON_OBJECT(val, txin.key_offsets, key_offsets); + GET_FROM_JSON_OBJECT(val, txin.k_image, k_image); +} + +void toJsonValue(rapidjson::Document& doc, const cryptonote::txout_target_v& txout, rapidjson::Value& val) +{ + val.SetObject(); + + if (txout.type() == typeid(cryptonote::txout_to_script)) + { + val.AddMember("type", "txout_to_script", doc.GetAllocator()); + INSERT_INTO_JSON_OBJECT(val, doc, value, boost::get(txout)); + } + else if (txout.type() == typeid(cryptonote::txout_to_scripthash)) + { + val.AddMember("type", "txout_to_scripthash", doc.GetAllocator()); + INSERT_INTO_JSON_OBJECT(val, doc, value, boost::get(txout)); + } + else if (txout.type() == typeid(cryptonote::txout_to_key)) + { + val.AddMember("type", "txout_to_key", doc.GetAllocator()); + INSERT_INTO_JSON_OBJECT(val, doc, value, boost::get(txout)); + } +} + + +void fromJsonValue(const rapidjson::Value& val, cryptonote::txout_target_v& txout) +{ + if (!val.IsObject()) + { + throw WRONG_TYPE("json object"); + } + + OBJECT_HAS_MEMBER_OR_THROW(val, "type") + OBJECT_HAS_MEMBER_OR_THROW(val, "value") + if (val["type"]== "txout_to_script") + { + cryptonote::txout_to_script tmpVal; + fromJsonValue(val["value"], tmpVal); + txout = tmpVal; + } + else if (val["type"] == "txout_to_scripthash") + { + cryptonote::txout_to_scripthash tmpVal; + fromJsonValue(val["value"], tmpVal); + txout = tmpVal; + } + else if (val["type"] == "txout_to_key") + { + cryptonote::txout_to_key tmpVal; + fromJsonValue(val["value"], tmpVal); + txout = tmpVal; + } +} + +void toJsonValue(rapidjson::Document& doc, const cryptonote::txout_to_script& txout, rapidjson::Value& val) +{ + val.SetObject(); + + INSERT_INTO_JSON_OBJECT(val, doc, keys, txout.keys); + INSERT_INTO_JSON_OBJECT(val, doc, script, txout.script); +} + + +void fromJsonValue(const rapidjson::Value& val, cryptonote::txout_to_script& txout) +{ + if (!val.IsObject()) + { + throw WRONG_TYPE("json object"); + } + + GET_FROM_JSON_OBJECT(val, txout.keys, keys); + GET_FROM_JSON_OBJECT(val, txout.script, script); +} + +void toJsonValue(rapidjson::Document& doc, const cryptonote::txout_to_scripthash& txout, rapidjson::Value& val) +{ + val.SetObject(); + + INSERT_INTO_JSON_OBJECT(val, doc, hash, txout.hash); +} + + +void fromJsonValue(const rapidjson::Value& val, cryptonote::txout_to_scripthash& txout) +{ + if (!val.IsObject()) + { + throw WRONG_TYPE("json object"); + } + + GET_FROM_JSON_OBJECT(val, txout.hash, hash); +} + +void toJsonValue(rapidjson::Document& doc, const cryptonote::txout_to_key& txout, rapidjson::Value& val) +{ + val.SetObject(); + + INSERT_INTO_JSON_OBJECT(val, doc, key, txout.key); +} + + +void fromJsonValue(const rapidjson::Value& val, cryptonote::txout_to_key& txout) +{ + if (!val.IsObject()) + { + throw WRONG_TYPE("json object"); + } + + GET_FROM_JSON_OBJECT(val, txout.key, key); +} + +void toJsonValue(rapidjson::Document& doc, const cryptonote::tx_out& txout, rapidjson::Value& val) +{ + val.SetObject(); + + INSERT_INTO_JSON_OBJECT(val, doc, amount, txout.amount); + INSERT_INTO_JSON_OBJECT(val, doc, target, txout.target); +} + +void fromJsonValue(const rapidjson::Value& val, cryptonote::tx_out& txout) +{ + if (!val.IsObject()) + { + throw WRONG_TYPE("json object"); + } + + GET_FROM_JSON_OBJECT(val, txout.amount, amount); + GET_FROM_JSON_OBJECT(val, txout.target, target); +} + +void toJsonValue(rapidjson::Document& doc, const cryptonote::connection_info& info, rapidjson::Value& val) +{ + val.SetObject(); + + auto& al = doc.GetAllocator(); + INSERT_INTO_JSON_OBJECT(val, doc, incoming, info.incoming); + INSERT_INTO_JSON_OBJECT(val, doc, localhost, info.localhost); + INSERT_INTO_JSON_OBJECT(val, doc, local_ip, info.local_ip); + + INSERT_INTO_JSON_OBJECT(val, doc, ip, info.ip); + INSERT_INTO_JSON_OBJECT(val, doc, port, info.port); + + INSERT_INTO_JSON_OBJECT(val, doc, peer_id, info.peer_id); + + INSERT_INTO_JSON_OBJECT(val, doc, recv_count, info.recv_count); + INSERT_INTO_JSON_OBJECT(val, doc, recv_idle_time, info.recv_idle_time); + + INSERT_INTO_JSON_OBJECT(val, doc, send_count, info.send_count); + INSERT_INTO_JSON_OBJECT(val, doc, send_idle_time, info.send_idle_time); + + INSERT_INTO_JSON_OBJECT(val, doc, state, info.state); + + INSERT_INTO_JSON_OBJECT(val, doc, live_time, info.live_time); + + INSERT_INTO_JSON_OBJECT(val, doc, avg_download, info.avg_download); + INSERT_INTO_JSON_OBJECT(val, doc, current_download, info.current_download); + + INSERT_INTO_JSON_OBJECT(val, doc, avg_upload, info.avg_upload); + INSERT_INTO_JSON_OBJECT(val, doc, current_upload, info.current_upload); +} + + +void fromJsonValue(const rapidjson::Value& val, cryptonote::connection_info& info) +{ + if (!val.IsObject()) + { + throw WRONG_TYPE("json object"); + } + + GET_FROM_JSON_OBJECT(val, info.incoming, incoming); + GET_FROM_JSON_OBJECT(val, info.localhost, localhost); + GET_FROM_JSON_OBJECT(val, info.local_ip, local_ip); + + GET_FROM_JSON_OBJECT(val, info.ip, ip); + GET_FROM_JSON_OBJECT(val, info.port, port); + + GET_FROM_JSON_OBJECT(val, info.peer_id, peer_id); + + GET_FROM_JSON_OBJECT(val, info.recv_count, recv_count); + GET_FROM_JSON_OBJECT(val, info.recv_idle_time, recv_idle_time); + + GET_FROM_JSON_OBJECT(val, info.send_count, send_count); + GET_FROM_JSON_OBJECT(val, info.send_idle_time, send_idle_time); + + GET_FROM_JSON_OBJECT(val, info.state, state); + + GET_FROM_JSON_OBJECT(val, info.live_time, live_time); + + GET_FROM_JSON_OBJECT(val, info.avg_download, avg_download); + GET_FROM_JSON_OBJECT(val, info.current_download, current_download); + + GET_FROM_JSON_OBJECT(val, info.avg_upload, avg_upload); + GET_FROM_JSON_OBJECT(val, info.current_upload, current_upload); +} + +void toJsonValue(rapidjson::Document& doc, const cryptonote::block_complete_entry& blk, rapidjson::Value& val) +{ + val.SetObject(); + + INSERT_INTO_JSON_OBJECT(val, doc, block, blk.block); + INSERT_INTO_JSON_OBJECT(val, doc, txs, blk.txs); +} + + +void fromJsonValue(const rapidjson::Value& val, cryptonote::block_complete_entry& blk) +{ + if (!val.IsObject()) + { + throw WRONG_TYPE("json object"); + } + + GET_FROM_JSON_OBJECT(val, blk.block, block); + GET_FROM_JSON_OBJECT(val, blk.txs, txs); +} + +void toJsonValue(rapidjson::Document& doc, const cryptonote::rpc::block_with_transactions& blk, rapidjson::Value& val) +{ + val.SetObject(); + + INSERT_INTO_JSON_OBJECT(val, doc, block, blk.block); + INSERT_INTO_JSON_OBJECT(val, doc, transactions, blk.transactions); +} + + +void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::block_with_transactions& blk) +{ + if (!val.IsObject()) + { + throw WRONG_TYPE("json object"); + } + + GET_FROM_JSON_OBJECT(val, blk.block, block); + GET_FROM_JSON_OBJECT(val, blk.transactions, transactions); +} + +void toJsonValue(rapidjson::Document& doc, const cryptonote::rpc::transaction_info& tx_info, rapidjson::Value& val) +{ + val.SetObject(); + + INSERT_INTO_JSON_OBJECT(val, doc, height, tx_info.height); + INSERT_INTO_JSON_OBJECT(val, doc, in_pool, tx_info.in_pool); + INSERT_INTO_JSON_OBJECT(val, doc, transaction, tx_info.transaction); +} + + +void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::transaction_info& tx_info) +{ + if (!val.IsObject()) + { + throw WRONG_TYPE("json object"); + } + + GET_FROM_JSON_OBJECT(val, tx_info.height, height); + GET_FROM_JSON_OBJECT(val, tx_info.in_pool, in_pool); + GET_FROM_JSON_OBJECT(val, tx_info.transaction, transaction); +} + +void toJsonValue(rapidjson::Document& doc, const cryptonote::rpc::output_key_and_amount_index& out, rapidjson::Value& val) +{ + val.SetObject(); + + INSERT_INTO_JSON_OBJECT(val, doc, amount_index, out.amount_index); + INSERT_INTO_JSON_OBJECT(val, doc, key, out.key); +} + + +void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::output_key_and_amount_index& out) +{ + if (!val.IsObject()) + { + throw WRONG_TYPE("json object"); + } + + GET_FROM_JSON_OBJECT(val, out.amount_index, amount_index); + GET_FROM_JSON_OBJECT(val, out.key, key); +} + +void toJsonValue(rapidjson::Document& doc, const cryptonote::rpc::amount_with_random_outputs& out, rapidjson::Value& val) +{ + val.SetObject(); + + INSERT_INTO_JSON_OBJECT(val, doc, amount, out.amount); + INSERT_INTO_JSON_OBJECT(val, doc, outputs, out.outputs); +} + + +void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::amount_with_random_outputs& out) +{ + if (!val.IsObject()) + { + throw WRONG_TYPE("json object"); + } + + GET_FROM_JSON_OBJECT(val, out.amount, amount); + GET_FROM_JSON_OBJECT(val, out.outputs, outputs); +} + +void toJsonValue(rapidjson::Document& doc, const cryptonote::rpc::peer& peer, rapidjson::Value& val) +{ + val.SetObject(); + + INSERT_INTO_JSON_OBJECT(val, doc, id, peer.id); + INSERT_INTO_JSON_OBJECT(val, doc, ip, peer.ip); + INSERT_INTO_JSON_OBJECT(val, doc, port, peer.port); + INSERT_INTO_JSON_OBJECT(val, doc, last_seen, peer.last_seen); +} + + +void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::peer& peer) +{ + if (!val.IsObject()) + { + throw WRONG_TYPE("json object"); + } + + GET_FROM_JSON_OBJECT(val, peer.id, id); + GET_FROM_JSON_OBJECT(val, peer.ip, ip); + GET_FROM_JSON_OBJECT(val, peer.port, port); + GET_FROM_JSON_OBJECT(val, peer.last_seen, last_seen); +} + +void toJsonValue(rapidjson::Document& doc, const cryptonote::rpc::tx_in_pool& tx, rapidjson::Value& val) +{ + val.SetObject(); + + INSERT_INTO_JSON_OBJECT(val, doc, tx, tx.tx); + INSERT_INTO_JSON_OBJECT(val, doc, tx_hash, tx.tx_hash); + INSERT_INTO_JSON_OBJECT(val, doc, blob_size, tx.blob_size); + INSERT_INTO_JSON_OBJECT(val, doc, fee, tx.fee); + INSERT_INTO_JSON_OBJECT(val, doc, max_used_block_hash, tx.max_used_block_hash); + INSERT_INTO_JSON_OBJECT(val, doc, max_used_block_height, tx.max_used_block_height); + INSERT_INTO_JSON_OBJECT(val, doc, kept_by_block, tx.kept_by_block); + INSERT_INTO_JSON_OBJECT(val, doc, last_failed_block_hash, tx.last_failed_block_hash); + INSERT_INTO_JSON_OBJECT(val, doc, last_failed_block_height, tx.last_failed_block_height); + INSERT_INTO_JSON_OBJECT(val, doc, receive_time, tx.receive_time); + INSERT_INTO_JSON_OBJECT(val, doc, last_relayed_time, tx.last_relayed_time); + INSERT_INTO_JSON_OBJECT(val, doc, relayed, tx.relayed); + INSERT_INTO_JSON_OBJECT(val, doc, do_not_relay, tx.do_not_relay); +} + + +void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::tx_in_pool& tx) +{ + if (!val.IsObject()) + { + throw WRONG_TYPE("json object"); + } + + GET_FROM_JSON_OBJECT(val, tx.tx, tx); + GET_FROM_JSON_OBJECT(val, tx.blob_size, blob_size); + GET_FROM_JSON_OBJECT(val, tx.fee, fee); + GET_FROM_JSON_OBJECT(val, tx.max_used_block_hash, max_used_block_hash); + GET_FROM_JSON_OBJECT(val, tx.max_used_block_height, max_used_block_height); + GET_FROM_JSON_OBJECT(val, tx.kept_by_block, kept_by_block); + GET_FROM_JSON_OBJECT(val, tx.last_failed_block_hash, last_failed_block_hash); + GET_FROM_JSON_OBJECT(val, tx.last_failed_block_height, last_failed_block_height); + GET_FROM_JSON_OBJECT(val, tx.receive_time, receive_time); + GET_FROM_JSON_OBJECT(val, tx.last_relayed_time, last_relayed_time); + GET_FROM_JSON_OBJECT(val, tx.relayed, relayed); +} + +void toJsonValue(rapidjson::Document& doc, const cryptonote::rpc::hard_fork_info& info, rapidjson::Value& val) +{ + val.SetObject(); + + INSERT_INTO_JSON_OBJECT(val, doc, version, info.version); + INSERT_INTO_JSON_OBJECT(val, doc, enabled, info.enabled); + INSERT_INTO_JSON_OBJECT(val, doc, window, info.window); + INSERT_INTO_JSON_OBJECT(val, doc, votes, info.votes); + INSERT_INTO_JSON_OBJECT(val, doc, threshold, info.threshold); + INSERT_INTO_JSON_OBJECT(val, doc, voting, info.voting); + INSERT_INTO_JSON_OBJECT(val, doc, state, info.state); + INSERT_INTO_JSON_OBJECT(val, doc, earliest_height, info.earliest_height); +} + + +void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::hard_fork_info& info) +{ + if (!val.IsObject()) + { + throw WRONG_TYPE("json object"); + } + + GET_FROM_JSON_OBJECT(val, info.version, version); + GET_FROM_JSON_OBJECT(val, info.enabled, enabled); + GET_FROM_JSON_OBJECT(val, info.window, window); + GET_FROM_JSON_OBJECT(val, info.votes, votes); + GET_FROM_JSON_OBJECT(val, info.threshold, threshold); + GET_FROM_JSON_OBJECT(val, info.voting, voting); + GET_FROM_JSON_OBJECT(val, info.state, state); + GET_FROM_JSON_OBJECT(val, info.earliest_height, earliest_height); +} + +void toJsonValue(rapidjson::Document& doc, const cryptonote::rpc::output_amount_count& out, rapidjson::Value& val) +{ + val.SetObject(); + + INSERT_INTO_JSON_OBJECT(val, doc, amount, out.amount); + INSERT_INTO_JSON_OBJECT(val, doc, total_count, out.total_count); + INSERT_INTO_JSON_OBJECT(val, doc, unlocked_count, out.unlocked_count); + INSERT_INTO_JSON_OBJECT(val, doc, recent_count, out.recent_count); +} + + +void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::output_amount_count& out) +{ + if (!val.IsObject()) + { + throw WRONG_TYPE("json object"); + } + + GET_FROM_JSON_OBJECT(val, out.amount, amount); + GET_FROM_JSON_OBJECT(val, out.total_count, total_count); + GET_FROM_JSON_OBJECT(val, out.unlocked_count, unlocked_count); + GET_FROM_JSON_OBJECT(val, out.recent_count, recent_count); +} + +void toJsonValue(rapidjson::Document& doc, const cryptonote::rpc::output_amount_and_index& out, rapidjson::Value& val) +{ + val.SetObject(); + + INSERT_INTO_JSON_OBJECT(val, doc, amount, out.amount); + INSERT_INTO_JSON_OBJECT(val, doc, index, out.index); +} + + +void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::output_amount_and_index& out) +{ + if (!val.IsObject()) + { + throw WRONG_TYPE("json object"); + } + + GET_FROM_JSON_OBJECT(val, out.amount, amount); + GET_FROM_JSON_OBJECT(val, out.index, index); +} + +void toJsonValue(rapidjson::Document& doc, const cryptonote::rpc::output_key_mask_unlocked& out, rapidjson::Value& val) +{ + val.SetObject(); + + INSERT_INTO_JSON_OBJECT(val, doc, key, out.key); + INSERT_INTO_JSON_OBJECT(val, doc, mask, out.mask); + INSERT_INTO_JSON_OBJECT(val, doc, unlocked, out.unlocked); +} + +void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::output_key_mask_unlocked& out) +{ + if (!val.IsObject()) + { + throw WRONG_TYPE("json object"); + } + + GET_FROM_JSON_OBJECT(val, out.key, key); + GET_FROM_JSON_OBJECT(val, out.mask, mask); + GET_FROM_JSON_OBJECT(val, out.unlocked, unlocked); +} + +void toJsonValue(rapidjson::Document& doc, const cryptonote::rpc::error& err, rapidjson::Value& val) +{ + val.SetObject(); + + INSERT_INTO_JSON_OBJECT(val, doc, code, err.code); + INSERT_INTO_JSON_OBJECT(val, doc, error_str, err.error_str); + INSERT_INTO_JSON_OBJECT(val, doc, message, err.message); +} + +void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::error& error) +{ + if (!val.IsObject()) + { + throw WRONG_TYPE("json object"); + } + + GET_FROM_JSON_OBJECT(val, error.code, code); + GET_FROM_JSON_OBJECT(val, error.error_str, error_str); + GET_FROM_JSON_OBJECT(val, error.message, message); +} + +void toJsonValue(rapidjson::Document& doc, const cryptonote::rpc::BlockHeaderResponse& response, rapidjson::Value& val) +{ + val.SetObject(); + + INSERT_INTO_JSON_OBJECT(val, doc, major_version, response.major_version); + INSERT_INTO_JSON_OBJECT(val, doc, minor_version, response.minor_version); + INSERT_INTO_JSON_OBJECT(val, doc, timestamp, response.timestamp); + INSERT_INTO_JSON_OBJECT(val, doc, prev_id, response.prev_id); + INSERT_INTO_JSON_OBJECT(val, doc, nonce, response.nonce); + INSERT_INTO_JSON_OBJECT(val, doc, height, response.height); + INSERT_INTO_JSON_OBJECT(val, doc, depth, response.depth); + INSERT_INTO_JSON_OBJECT(val, doc, hash, response.hash); + INSERT_INTO_JSON_OBJECT(val, doc, difficulty, response.difficulty); + INSERT_INTO_JSON_OBJECT(val, doc, reward, response.reward); +} + +void fromJsonValue(const rapidjson::Value& val, cryptonote::rpc::BlockHeaderResponse& response) +{ + if (!val.IsObject()) + { + throw WRONG_TYPE("json object"); + } + + GET_FROM_JSON_OBJECT(val, response.major_version, major_version); + GET_FROM_JSON_OBJECT(val, response.minor_version, minor_version); + GET_FROM_JSON_OBJECT(val, response.timestamp, timestamp); + GET_FROM_JSON_OBJECT(val, response.prev_id, prev_id); + GET_FROM_JSON_OBJECT(val, response.nonce, nonce); + GET_FROM_JSON_OBJECT(val, response.height, height); + GET_FROM_JSON_OBJECT(val, response.depth, depth); + GET_FROM_JSON_OBJECT(val, response.hash, hash); + GET_FROM_JSON_OBJECT(val, response.difficulty, difficulty); + GET_FROM_JSON_OBJECT(val, response.reward, reward); +} + +void toJsonValue(rapidjson::Document& doc, const rct::rctSig& sig, rapidjson::Value& val) +{ + val.SetObject(); + + INSERT_INTO_JSON_OBJECT(val, doc, type, sig.type); + INSERT_INTO_JSON_OBJECT(val, doc, message, sig.message); + INSERT_INTO_JSON_OBJECT(val, doc, mixRing, sig.mixRing); + INSERT_INTO_JSON_OBJECT(val, doc, pseudoOuts, sig.pseudoOuts); + INSERT_INTO_JSON_OBJECT(val, doc, ecdhInfo, sig.ecdhInfo); + INSERT_INTO_JSON_OBJECT(val, doc, outPk, sig.outPk); + INSERT_INTO_JSON_OBJECT(val, doc, txnFee, sig.txnFee); + INSERT_INTO_JSON_OBJECT(val, doc, p, sig.p); +} + +void fromJsonValue(const rapidjson::Value& val, rct::rctSig& sig) +{ + if (!val.IsObject()) + { + throw WRONG_TYPE("json object"); + } + + GET_FROM_JSON_OBJECT(val, sig.type, type); + GET_FROM_JSON_OBJECT(val, sig.message, message); + GET_FROM_JSON_OBJECT(val, sig.mixRing, mixRing); + GET_FROM_JSON_OBJECT(val, sig.pseudoOuts, pseudoOuts); + GET_FROM_JSON_OBJECT(val, sig.ecdhInfo, ecdhInfo); + GET_FROM_JSON_OBJECT(val, sig.outPk, outPk); + GET_FROM_JSON_OBJECT(val, sig.txnFee, txnFee); + GET_FROM_JSON_OBJECT(val, sig.p, p); +} + +void toJsonValue(rapidjson::Document& doc, const rct::ctkey& key, rapidjson::Value& val) +{ + val.SetObject(); + + INSERT_INTO_JSON_OBJECT(val, doc, dest, key.dest); + INSERT_INTO_JSON_OBJECT(val, doc, mask, key.mask); +} + +void fromJsonValue(const rapidjson::Value& val, rct::ctkey& key) +{ + if (!val.IsObject()) + { + throw WRONG_TYPE("json object"); + } + GET_FROM_JSON_OBJECT(val, key.dest, dest); + GET_FROM_JSON_OBJECT(val, key.mask, mask); +} + +void toJsonValue(rapidjson::Document& doc, const rct::ecdhTuple& tuple, rapidjson::Value& val) +{ + val.SetObject(); + + INSERT_INTO_JSON_OBJECT(val, doc, mask, tuple.mask); + INSERT_INTO_JSON_OBJECT(val, doc, amount, tuple.amount); +} + +void fromJsonValue(const rapidjson::Value& val, rct::ecdhTuple& tuple) +{ + if (!val.IsObject()) + { + throw WRONG_TYPE("json object"); + } + + GET_FROM_JSON_OBJECT(val, tuple.mask, mask); + GET_FROM_JSON_OBJECT(val, tuple.amount, amount); +} + +void toJsonValue(rapidjson::Document& doc, const rct::rctSigPrunable& sig, rapidjson::Value& val) +{ + val.SetObject(); + + INSERT_INTO_JSON_OBJECT(val, doc, rangeSigs, sig.rangeSigs); + INSERT_INTO_JSON_OBJECT(val, doc, MGs, sig.MGs); +} + +void fromJsonValue(const rapidjson::Value& val, rct::rctSigPrunable& sig) +{ + if (!val.IsObject()) + { + throw WRONG_TYPE("json object"); + } + + GET_FROM_JSON_OBJECT(val, sig.rangeSigs, rangeSigs); + GET_FROM_JSON_OBJECT(val, sig.MGs, MGs); +} + +void toJsonValue(rapidjson::Document& doc, const rct::rangeSig& sig, rapidjson::Value& val) +{ + val.SetObject(); + + INSERT_INTO_JSON_OBJECT(val, doc, asig, sig.asig); + + std::vector keyVector(sig.Ci, std::end(sig.Ci)); + INSERT_INTO_JSON_OBJECT(val, doc, Ci, keyVector); +} + +void fromJsonValue(const rapidjson::Value& val, rct::rangeSig& sig) +{ + if (!val.IsObject()) + { + throw WRONG_TYPE("json object"); + } + + GET_FROM_JSON_OBJECT(val, sig.asig, asig); + + std::vector keyVector; + cryptonote::json::fromJsonValue(val["Ci"], keyVector); + if (!(keyVector.size() == 64)) + { + throw WRONG_TYPE("key64 (rct::key[64])"); + } + for (size_t i=0; i < 64; i++) + { + sig.Ci[i] = keyVector[i]; + } +} + +void toJsonValue(rapidjson::Document& doc, const rct::boroSig& sig, rapidjson::Value& val) +{ + val.SetObject(); + + std::vector keyVector(sig.s0, std::end(sig.s0)); + INSERT_INTO_JSON_OBJECT(val, doc, s0, sig.s0); + + keyVector.assign(sig.s1, std::end(sig.s1)); + INSERT_INTO_JSON_OBJECT(val, doc, s1, sig.s1); + + INSERT_INTO_JSON_OBJECT(val, doc, ee, sig.ee); +} + +void fromJsonValue(const rapidjson::Value& val, rct::boroSig& sig) +{ + if (!val.IsObject()) + { + throw WRONG_TYPE("json object"); + } + + OBJECT_HAS_MEMBER_OR_THROW(val, "s0") + std::vector keyVector; + cryptonote::json::fromJsonValue(val["s0"], keyVector); + if (!(keyVector.size() == 64)) + { + throw WRONG_TYPE("key64 (rct::key[64])"); + } + for (size_t i=0; i < 64; i++) + { + sig.s0[i] = keyVector[i]; + } + + OBJECT_HAS_MEMBER_OR_THROW(val, "s1") + keyVector.clear(); + cryptonote::json::fromJsonValue(val["s1"], keyVector); + if (!(keyVector.size() == 64)) + { + throw WRONG_TYPE("key64 (rct::key[64])"); + } + for (size_t i=0; i < 64; i++) + { + sig.s1[i] = keyVector[i]; + } + + GET_FROM_JSON_OBJECT(val, sig.ee, ee); +} + +void toJsonValue(rapidjson::Document& doc, const rct::mgSig& sig, rapidjson::Value& val) +{ + val.SetObject(); + + INSERT_INTO_JSON_OBJECT(val, doc, ss, sig.ss); + INSERT_INTO_JSON_OBJECT(val, doc, cc, sig.cc); +} + +void fromJsonValue(const rapidjson::Value& val, rct::mgSig& sig) +{ + if (!val.IsObject()) + { + throw WRONG_TYPE("key64 (rct::key[64])"); + } + + GET_FROM_JSON_OBJECT(val, sig.ss, ss); + GET_FROM_JSON_OBJECT(val, sig.cc, cc); +} + +} // namespace json + +} // namespace cryptonote -- cgit v1.2.3 From 0299cb77ca18073daf3cf371f8da013fb596ae48 Mon Sep 17 00:00:00 2001 From: Thomas Winget Date: Tue, 5 Sep 2017 12:20:40 -0400 Subject: 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 --- CMakeLists.txt | 8 ++ src/daemon/command_line_args.h | 6 -- src/daemon/main.cpp | 1 - src/rpc/CMakeLists.txt | 2 + src/rpc/daemon_handler.cpp | 171 +++++++++++++++++++++++-------- src/rpc/daemon_handler.h | 6 +- src/rpc/daemon_messages.cpp | 152 +++++++++++++++++++++++----- src/rpc/daemon_messages.h | 47 +++------ src/rpc/daemon_rpc_version.h | 6 +- src/rpc/message.cpp | 2 +- src/rpc/message_data_structs.h | 20 ++++ src/rpc/zmq_server.cpp | 51 +++++----- src/rpc/zmq_server.h | 9 +- src/serialization/json_object.cpp | 207 ++++++++++++++++++++++++++++---------- src/serialization/json_object.h | 55 +++++++--- 15 files changed, 527 insertions(+), 216 deletions(-) (limited to 'src/serialization/json_object.cpp') diff --git a/CMakeLists.txt b/CMakeLists.txt index 62db856f4..971c097ff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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} diff --git a/src/daemon/command_line_args.h b/src/daemon/command_line_args.h index 797285354..f19d5cc63 100644 --- a/src/daemon/command_line_args.h +++ b/src/daemon/command_line_args.h @@ -83,12 +83,6 @@ namespace daemon_args , std::to_string(config::testnet::ZMQ_RPC_DEFAULT_PORT) }; - const command_line::arg_descriptor arg_zmq_restricted_rpc = { - "zmq-restricted-rpc" - , "Restrict ZMQ RPC to view only commands" - , false - }; - } // namespace daemon_args #endif // DAEMON_COMMAND_LINE_ARGS_H diff --git a/src/daemon/main.cpp b/src/daemon/main.cpp index 0d93a49ff..b35a864e9 100644 --- a/src/daemon/main.cpp +++ b/src/daemon/main.cpp @@ -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); diff --git a/src/rpc/CMakeLists.txt b/src/rpc/CMakeLists.txt index 717e3e627..b5c38b1a8 100644 --- a/src/rpc/CMakeLists.txt +++ b/src/rpc/CMakeLists.txt @@ -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 diff --git a/src/rpc/daemon_handler.cpp b/src/rpc/daemon_handler.cpp index 6a287b229..53eeb5e76 100644 --- a/src/rpc/daemon_handler.cpp +++ b/src/rpc/daemon_handler.cpp @@ -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 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(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); diff --git a/src/rpc/daemon_handler.h b/src/rpc/daemon_handler.h index 9997956c7..0d356bad2 100644 --- a/src/rpc/daemon_handler.h +++ b/src/rpc/daemon_handler.h @@ -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); diff --git a/src/rpc/daemon_messages.cpp b/src/rpc/daemon_messages.cpp index b999a0f18..640058df9 100644 --- a/src/rpc/daemon_messages.cpp +++ b/src/rpc/daemon_messages.cpp @@ -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); diff --git a/src/rpc/daemon_messages.h b/src/rpc/daemon_messages.h index adcd7f7c6..685f66843 100644 --- a/src/rpc/daemon_messages.h +++ b/src/rpc/daemon_messages.h @@ -89,6 +89,7 @@ BEGIN_RPC_MESSAGE_CLASS(GetBlocksFast); BEGIN_RPC_MESSAGE_REQUEST; RPC_MESSAGE_MEMBER(std::list, 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, 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, heights); + END_RPC_MESSAGE_REQUEST; + BEGIN_RPC_MESSAGE_RESPONSE; + RPC_MESSAGE_MEMBER(std::vector, 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; diff --git a/src/rpc/daemon_rpc_version.h b/src/rpc/daemon_rpc_version.h index b354b32c2..bb735fe7c 100644 --- a/src/rpc/daemon_rpc_version.h +++ b/src/rpc/daemon_rpc_version.h @@ -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 diff --git a/src/rpc/message.cpp b/src/rpc/message.cpp index 7d4499bcf..086820180 100644 --- a/src/rpc/message.cpp +++ b/src/rpc/message.cpp @@ -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; } diff --git a/src/rpc/message_data_structs.h b/src/rpc/message_data_structs.h index c2492681d..00f1e0caa 100644 --- a/src/rpc/message_data_structs.h +++ b/src/rpc/message_data_structs.h @@ -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 diff --git a/src/rpc/zmq_server.cpp b/src/rpc/zmq_server.cpp index 8e1e47b38..afdff2328 100644 --- a/src/rpc/zmq_server.cpp +++ b/src/rpc/zmq_server.cpp @@ -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; + zmq::message_t message; - while (socket->recv(&message)) - { - std::string message_string(reinterpret_cast(message.data()), message.size()); + if (!rep_socket) + { + throw std::runtime_error("ZMQ RPC server reply socket is null"); + } + while (rep_socket->recv(&message)) + { + std::string message_string(reinterpret_cast(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; diff --git a/src/rpc/zmq_server.h b/src/rpc/zmq_server.h index 964ce2071..c278ff759 100644 --- a/src/rpc/zmq_server.h +++ b/src/rpc/zmq_server.h @@ -29,12 +29,11 @@ #pragma once #include -#include -#include -#include "common/command_line.h" - #include #include +#include + +#include "common/command_line.h" #include "rpc_handler.h" @@ -75,7 +74,7 @@ class ZmqServer boost::thread run_thread; - std::vector sockets; + std::unique_ptr rep_socket; }; diff --git a/src/serialization/json_object.cpp b/src/serialization/json_object.cpp index 50ef414f4..ead3fdd58 100644 --- a/src/serialization/json_object.cpp +++ b/src/serialization/json_object.cpp @@ -28,6 +28,7 @@ #include "json_object.h" +#include #include "string_tools.h" namespace cryptonote @@ -36,6 +37,74 @@ namespace cryptonote namespace json { +namespace +{ + template + constexpr bool precision_loss() + { + return + std::numeric_limits::is_signed != std::numeric_limits::is_signed || + std::numeric_limits::min() > std::numeric_limits::min() || + std::numeric_limits::max() < std::numeric_limits::max(); + } + + template + void convert_numeric(Source source, Type& i) + { + static_assert( + std::numeric_limits::is_signed == std::numeric_limits::is_signed, + "source and destination signs do not match" + ); + if (source < std::numeric_limits::min()) + { + throw WRONG_TYPE{"numeric underflow"}; + } + if (std::numeric_limits::max() < source) + { + throw WRONG_TYPE{"numeric overflow"}; + } + i = Type(source); + } + + template + void to_int(const rapidjson::Value& val, Type& i) + { + if (!val.IsInt()) + { + throw WRONG_TYPE{"integer"}; + } + convert_numeric(val.GetInt(), i); + } + template + void to_int64(const rapidjson::Value& val, Type& i) + { + if (!val.IsInt64()) + { + throw WRONG_TYPE{"integer"}; + } + convert_numeric(val.GetInt64(), i); + } + + template + void to_uint(const rapidjson::Value& val, Type& i) + { + if (!val.IsUint()) + { + throw WRONG_TYPE{"unsigned integer"}; + } + convert_numeric(val.GetUint(), i); + } + template + 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) { - val = rapidjson::Value(i); + to_uint(val, i); } - -void fromJsonValue(const rapidjson::Value& val, uint8_t& i) +void fromJsonValue(const rapidjson::Value& val, char& i) { - if (!val.IsUint()) - { - throw WRONG_TYPE("unsigned integer"); - } - - i = (uint8_t)( val.GetUint() & 0xFF); + to_int(val, i); } -void toJsonValue(rapidjson::Document& doc, const int8_t& i, rapidjson::Value& val) +void fromJsonValue(const rapidjson::Value& val, signed char& i) { - val = rapidjson::Value(i); + to_int(val, i); } - -void fromJsonValue(const rapidjson::Value& val, int8_t& i) +void fromJsonValue(const rapidjson::Value& val, unsigned short& i) { - if (!val.IsInt()) - { - throw WRONG_TYPE("integer"); - } + to_uint(val, i); +} - i = (int8_t) ( val.GetInt() & 0xFF); +void fromJsonValue(const rapidjson::Value& val, short& i) +{ + to_int(val, i); } -void toJsonValue(rapidjson::Document& doc, const uint16_t& i, rapidjson::Value& val) +void toJsonValue(rapidjson::Document& doc, const unsigned int i, rapidjson::Value& val) { val = rapidjson::Value(i); } - -void fromJsonValue(const rapidjson::Value& val, uint16_t& i) +void fromJsonValue(const rapidjson::Value& val, unsigned int& i) { - if (!val.IsUint()) - { - throw WRONG_TYPE("unsigned integer"); - } - - i = (uint16_t) ( val.GetUint() & 0xFFFF); + to_uint(val, i); } -void toJsonValue(rapidjson::Document& doc, const int32_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, int32_t& i) +void fromJsonValue(const rapidjson::Value& val, int& i) { - if (!val.IsInt()) - { - throw WRONG_TYPE("signed integer"); - } - - i = val.GetInt(); + to_int(val, i); } -void toJsonValue(rapidjson::Document& doc, const uint32_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(), "precision loss"); + val = rapidjson::Value(std::uint64_t(i)); } - -void fromJsonValue(const rapidjson::Value& val, uint32_t& i) +void fromJsonValue(const rapidjson::Value& val, unsigned long long& i) { - if (!val.IsUint()) - { - throw WRONG_TYPE("unsigned integer"); - } - - i = val.GetUint(); + to_uint64(val, i); } -void toJsonValue(rapidjson::Document& doc, const uint64_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(), "precision loss"); + val = rapidjson::Value(std::int64_t(i)); } +void fromJsonValue(const rapidjson::Value& val, long long& i) +{ + to_int64(val, i); +} -void fromJsonValue(const rapidjson::Value& val, uint64_t& i) +void fromJsonValue(const rapidjson::Value& val, unsigned long& i) { - if (!val.IsUint64()) - { - throw WRONG_TYPE("unsigned integer"); - } + to_uint64(val, i); +} - i = val.GetUint64(); +void fromJsonValue(const rapidjson::Value& val, long& i) +{ + 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 diff --git a/src/serialization/json_object.h b/src/serialization/json_object.h index 8e0da9aa5..7b9519c48 100644 --- a/src/serialization/json_object.h +++ b/src/serialization/json_object.h @@ -107,16 +107,22 @@ struct PARSE_FAIL : public JSON_ERROR } }; +template +inline constexpr bool is_to_hex() +{ + return std::is_pod() && !std::is_integral(); +} + // POD to json value template -typename std::enable_if::value, void>::type toJsonValue(rapidjson::Document& doc, const Type& pod, rapidjson::Value& value) +typename std::enable_if()>::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 -typename std::enable_if::value, void>::type fromJsonValue(const rapidjson::Value& val, Type& t) +typename std::enable_if()>::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 fromJsonValue(const rapidjson::Value& val, unsigned char& i); + +void fromJsonValue(const rapidjson::Value& val, signed char& i); + +void fromJsonValue(const rapidjson::Value& val, char& i); + +void fromJsonValue(const rapidjson::Value& val, unsigned short& i); -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, short& i); -void toJsonValue(rapidjson::Document& doc, const uint16_t& i, rapidjson::Value& val); -void fromJsonValue(const rapidjson::Value& val, uint16_t& 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 int32_t& i, rapidjson::Value& val); -void fromJsonValue(const rapidjson::Value& val, int32_t& 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 uint32_t& i, rapidjson::Value& val); -void fromJsonValue(const rapidjson::Value& val, uint32_t& i); -void toJsonValue(rapidjson::Document& doc, const uint64_t& i, rapidjson::Value& val); -void fromJsonValue(const rapidjson::Value& val, uint64_t& 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(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(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 std::enable_if::value, void>::type toJsonValue(rapidjson::Document& doc, const Map& map, rapidjson::Value& val); -- cgit v1.2.3