diff options
Diffstat (limited to 'src/rpc')
-rw-r--r-- | src/rpc/core_rpc_server.cpp | 139 | ||||
-rw-r--r-- | src/rpc/core_rpc_server.h | 20 | ||||
-rw-r--r-- | src/rpc/core_rpc_server_commands_defs.h | 93 |
3 files changed, 245 insertions, 7 deletions
diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 4c392c606..bab373c86 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -11,6 +11,7 @@ using namespace epee; #include "common/command_line.h" #include "cryptonote_core/cryptonote_format_utils.h" #include "cryptonote_core/account.h" +#include "cryptonote_core/cryptonote_basic_impl.h" #include "misc_language.h" #include "crypto/hash.h" #include "core_rpc_server_error_codes.h" @@ -413,6 +414,140 @@ namespace cryptonote return true; } //------------------------------------------------------------------------------------------------------------------------------ - - + uint64_t core_rpc_server::get_block_reward(const block& blk) + { + uint64_t reward = 0; + BOOST_FOREACH(const tx_out& out, blk.miner_tx.vout) + { + reward += out.amount; + } + return reward; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::fill_block_header_responce(const block& blk, bool orphan_status, uint64_t height, const crypto::hash& hash, block_header_responce& responce) + { + responce.major_version = blk.major_version; + responce.minor_version = blk.minor_version; + responce.timestamp = blk.timestamp; + responce.prev_hash = string_tools::pod_to_hex(blk.prev_id); + responce.nonce = blk.nonce; + responce.orphan_status = orphan_status; + responce.height = height; + responce.depth = m_core.get_current_blockchain_height() - height - 1; + responce.hash = string_tools::pod_to_hex(hash); + responce.difficulty = m_core.get_blockchain_storage().block_difficulty(height); + responce.reward = get_block_reward(blk); + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_get_last_block_header(const COMMAND_RPC_GET_LAST_BLOCK_HEADER::request& req, COMMAND_RPC_GET_LAST_BLOCK_HEADER::response& res, epee::json_rpc::error& error_resp, connection_context& cntx) + { + if(!check_core_ready()) + { + error_resp.code = CORE_RPC_ERROR_CODE_CORE_BUSY; + error_resp.message = "Core is busy."; + return false; + } + uint64_t last_block_height; + crypto::hash last_block_hash; + bool have_last_block_hash = m_core.get_blockchain_top(last_block_height, last_block_hash); + if (!have_last_block_hash) + { + error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR; + error_resp.message = "Internal error: can't get last block hash."; + return false; + } + block last_block; + bool have_last_block = m_core.get_block_by_hash(last_block_hash, last_block); + if (!have_last_block) + { + error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR; + error_resp.message = "Internal error: can't get last block."; + return false; + } + bool responce_filled = fill_block_header_responce(last_block, false, last_block_height, last_block_hash, res.block_header); + if (!responce_filled) + { + error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR; + error_resp.message = "Internal error: can't produce valid response."; + return false; + } + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_get_block_header_by_hash(const COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH::request& req, COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH::response& res, epee::json_rpc::error& error_resp, connection_context& cntx){ + if(!check_core_ready()) + { + error_resp.code = CORE_RPC_ERROR_CODE_CORE_BUSY; + error_resp.message = "Core is busy."; + return false; + } + crypto::hash block_hash; + bool hash_parsed = parse_hash256(req.hash, block_hash); + if(!hash_parsed) + { + error_resp.code = CORE_RPC_ERROR_CODE_WRONG_PARAM; + error_resp.message = "Failed to parse hex representation of block hash. Hex = " + req.hash + '.'; + return false; + } + block blk; + bool have_block = m_core.get_block_by_hash(block_hash, blk); + if (!have_block) + { + error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR; + error_resp.message = "Internal error: can't get block by hash. Hash = " + req.hash + '.'; + return false; + } + if (blk.miner_tx.vin.front().type() != typeid(txin_gen)) + { + error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR; + error_resp.message = "Internal error: coinbase transaction in the block has the wrong type"; + return false; + } + uint64_t block_height = boost::get<txin_gen>(blk.miner_tx.vin.front()).height; + bool responce_filled = fill_block_header_responce(blk, false, block_height, block_hash, res.block_header); + if (!responce_filled) + { + error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR; + error_resp.message = "Internal error: can't produce valid response."; + return false; + } + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ + bool core_rpc_server::on_get_block_header_by_height(const COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT::request& req, COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT::response& res, epee::json_rpc::error& error_resp, connection_context& cntx){ + if(!check_core_ready()) + { + error_resp.code = CORE_RPC_ERROR_CODE_CORE_BUSY; + error_resp.message = "Core is busy."; + return false; + } + if(m_core.get_current_blockchain_height() <= req.height) + { + error_resp.code = CORE_RPC_ERROR_CODE_TOO_BIG_HEIGHT; + error_resp.message = std::string("To big height: ") + std::to_string(req.height) + ", current blockchain height = " + std::to_string(m_core.get_current_blockchain_height()); + return false; + } + crypto::hash block_hash = m_core.get_block_id_by_height(req.height); + block blk; + bool have_block = m_core.get_block_by_hash(block_hash, blk); + if (!have_block) + { + error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR; + error_resp.message = "Internal error: can't get block by height. Height = " + req.height + '.'; + return false; + } + bool responce_filled = fill_block_header_responce(blk, false, req.height, block_hash, res.block_header); + if (!responce_filled) + { + error_resp.code = CORE_RPC_ERROR_CODE_INTERNAL_ERROR; + error_resp.message = "Internal error: can't produce valid response."; + return false; + } + res.status = CORE_RPC_STATUS_OK; + return true; + } + //------------------------------------------------------------------------------------------------------------------------------ } diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h index fb3e92216..7b14e741a 100644 --- a/src/rpc/core_rpc_server.h +++ b/src/rpc/core_rpc_server.h @@ -42,10 +42,13 @@ namespace cryptonote MAP_URI_AUTO_JON2("/stop_mining", on_stop_mining, COMMAND_RPC_STOP_MINING) MAP_URI_AUTO_JON2("/getinfo", on_get_info, COMMAND_RPC_GET_INFO) BEGIN_JSON_RPC_MAP("/json_rpc") - MAP_JON_RPC("getblockcount", on_getblockcount, COMMAND_RPC_GETBLOCKCOUNT) - MAP_JON_RPC_WE("on_getblockhash", on_getblockhash, COMMAND_RPC_GETBLOCKHASH) - MAP_JON_RPC_WE("getblocktemplate",on_getblocktemplate, COMMAND_RPC_GETBLOCKTEMPLATE) - MAP_JON_RPC_WE("submitblock", on_submitblock, COMMAND_RPC_SUBMITBLOCK) + MAP_JON_RPC("getblockcount", on_getblockcount, COMMAND_RPC_GETBLOCKCOUNT) + MAP_JON_RPC_WE("on_getblockhash", on_getblockhash, COMMAND_RPC_GETBLOCKHASH) + MAP_JON_RPC_WE("getblocktemplate", on_getblocktemplate, COMMAND_RPC_GETBLOCKTEMPLATE) + MAP_JON_RPC_WE("submitblock", on_submitblock, COMMAND_RPC_SUBMITBLOCK) + MAP_JON_RPC_WE("getlastblockheader", on_get_last_block_header, COMMAND_RPC_GET_LAST_BLOCK_HEADER) + MAP_JON_RPC_WE("getblockheaderbyhash", on_get_block_header_by_hash, COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH) + MAP_JON_RPC_WE("getblockheaderbyheight", on_get_block_header_by_height, COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT) END_JSON_RPC_MAP() END_URI_MAP2() @@ -64,10 +67,17 @@ namespace cryptonote bool on_getblockhash(const COMMAND_RPC_GETBLOCKHASH::request& req, COMMAND_RPC_GETBLOCKHASH::response& res, epee::json_rpc::error& error_resp, connection_context& cntx); bool on_getblocktemplate(const COMMAND_RPC_GETBLOCKTEMPLATE::request& req, COMMAND_RPC_GETBLOCKTEMPLATE::response& res, epee::json_rpc::error& error_resp, connection_context& cntx); bool on_submitblock(const COMMAND_RPC_SUBMITBLOCK::request& req, COMMAND_RPC_SUBMITBLOCK::response& res, epee::json_rpc::error& error_resp, connection_context& cntx); + bool on_get_last_block_header(const COMMAND_RPC_GET_LAST_BLOCK_HEADER::request& req, COMMAND_RPC_GET_LAST_BLOCK_HEADER::response& res, epee::json_rpc::error& error_resp, connection_context& cntx); + bool on_get_block_header_by_hash(const COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH::request& req, COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH::response& res, epee::json_rpc::error& error_resp, connection_context& cntx); + bool on_get_block_header_by_height(const COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT::request& req, COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT::response& res, epee::json_rpc::error& error_resp, connection_context& cntx); //----------------------- bool handle_command_line(const boost::program_options::variables_map& vm); bool check_core_ready(); - + + //utils + uint64_t get_block_reward(const block& blk); + bool fill_block_header_responce(const block& blk, bool orphan_status, uint64_t height, const crypto::hash& hash, block_header_responce& responce); + core& m_core; nodetool::node_server<cryptonote::t_cryptonote_protocol_handler<cryptonote::core> >& m_p2p; std::string m_port; diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h index 5e8210775..d67ebfdd7 100644 --- a/src/rpc/core_rpc_server_commands_defs.h +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -5,6 +5,7 @@ #pragma once #include "cryptonote_protocol/cryptonote_protocol_defs.h" #include "cryptonote_core/cryptonote_basic.h" +#include "cryptonote_core/difficulty.h" #include "crypto/hash.h" namespace cryptonote @@ -330,8 +331,100 @@ namespace cryptonote END_KV_SERIALIZE_MAP() }; }; + + struct block_header_responce + { + uint8_t major_version; + uint8_t minor_version; + uint64_t timestamp; + std::string prev_hash; + uint32_t nonce; + bool orphan_status; + uint64_t height; + uint64_t depth; + std::string hash; + difficulty_type difficulty; + uint64_t reward; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(major_version) + KV_SERIALIZE(minor_version) + KV_SERIALIZE(timestamp) + KV_SERIALIZE(prev_hash) + KV_SERIALIZE(nonce) + KV_SERIALIZE(orphan_status) + KV_SERIALIZE(height) + KV_SERIALIZE(depth) + KV_SERIALIZE(hash) + KV_SERIALIZE(difficulty) + KV_SERIALIZE(reward) + END_KV_SERIALIZE_MAP() + }; + + struct COMMAND_RPC_GET_LAST_BLOCK_HEADER + { + typedef std::list<std::string> request; + + struct response + { + std::string status; + block_header_responce block_header; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(block_header) + KV_SERIALIZE(status) + END_KV_SERIALIZE_MAP() + }; + + }; + + struct COMMAND_RPC_GET_BLOCK_HEADER_BY_HASH + { + struct request + { + std::string hash; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(hash) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string status; + block_header_responce block_header; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(block_header) + KV_SERIALIZE(status) + END_KV_SERIALIZE_MAP() + }; + }; + struct COMMAND_RPC_GET_BLOCK_HEADER_BY_HEIGHT + { + struct request + { + uint64_t height; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(height) + END_KV_SERIALIZE_MAP() + }; + + struct response + { + std::string status; + block_header_responce block_header; + + BEGIN_KV_SERIALIZE_MAP() + KV_SERIALIZE(block_header) + KV_SERIALIZE(status) + END_KV_SERIALIZE_MAP() + }; + + }; } |