From 285e89ecda58a33d934ec87d2d47282a32e87e83 Mon Sep 17 00:00:00 2001 From: Sean Darcy Date: Thu, 11 Nov 2021 13:37:15 +1100 Subject: [PATCH] GET_BLOCK --- src/daemon/rpc_command_executor.cpp | 43 ++++++++++++--------- src/daemon/rpc_command_executor.h | 3 -- src/rpc/core_rpc_server.cpp | 44 +++++++++++----------- src/rpc/core_rpc_server.h | 4 +- src/rpc/core_rpc_server_command_parser.cpp | 6 +++ src/rpc/core_rpc_server_command_parser.h | 1 + src/rpc/core_rpc_server_commands_defs.cpp | 17 --------- src/rpc/core_rpc_server_commands_defs.h | 37 +++++++++--------- 8 files changed, 74 insertions(+), 81 deletions(-) diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp index 46bf16020..334f1ecea 100644 --- a/src/daemon/rpc_command_executor.cpp +++ b/src/daemon/rpc_command_executor.cpp @@ -773,31 +773,40 @@ bool rpc_command_executor::print_height() { return false; } -bool rpc_command_executor::print_block(GET_BLOCK::request&& req, bool include_hex) { - req.fill_pow_hash = true; - GET_BLOCK::response res{}; - - if (!invoke(std::move(req), res, "Block retrieval failed")) +bool rpc_command_executor::print_block_by_hash(const crypto::hash& block_hash, bool include_hex) { + auto maybe_block = try_running([this, &block_hash] { + return invoke(json{ + {"hash", tools::type_to_hex(block_hash)}, + {"fill_pow_hash", true}}); + }, "Block retrieval failed"); + if (!maybe_block) return false; + auto& block = *maybe_block; if (include_hex) - tools::success_msg_writer() << res.blob << std::endl; - print_block_header(res.block_header); - tools::success_msg_writer() << res.json << "\n"; + tools::success_msg_writer() << block["blob"] << std::endl; + print_block_header(block["block_header"]); + tools::success_msg_writer() << block["json"] << "\n"; return true; } -bool rpc_command_executor::print_block_by_hash(const crypto::hash& block_hash, bool include_hex) { - GET_BLOCK::request req{}; - req.hash = tools::type_to_hex(block_hash); - return print_block(std::move(req), include_hex); -} - bool rpc_command_executor::print_block_by_height(uint64_t height, bool include_hex) { - GET_BLOCK::request req{}; - req.height = height; - return print_block(std::move(req), include_hex); + auto maybe_block = try_running([this, height] { + return invoke(json{ + {"height", height}, + {"fill_pow_hash", true}}); + }, "Block retrieval failed"); + if (!maybe_block) + return false; + auto& block = *maybe_block; + + if (include_hex) + tools::success_msg_writer() << block["blob"] << std::endl; + print_block_header(block["block_header"]); + tools::success_msg_writer() << block["json"] << "\n"; + + return true; } bool rpc_command_executor::print_transaction(const crypto::hash& transaction_hash, diff --git a/src/daemon/rpc_command_executor.h b/src/daemon/rpc_command_executor.h index a73eeeda7..184315ccf 100644 --- a/src/daemon/rpc_command_executor.h +++ b/src/daemon/rpc_command_executor.h @@ -170,9 +170,6 @@ public: bool print_height(); -private: - bool print_block(cryptonote::rpc::GET_BLOCK::request&& req, bool include_hdex); - public: bool print_block_by_hash(const crypto::hash& block_hash, bool include_hex); diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 1a2fb7093..65be2b7f2 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -1793,45 +1793,43 @@ namespace cryptonote::rpc { return; } //------------------------------------------------------------------------------------------------------------------------------ - GET_BLOCK::response core_rpc_server::invoke(GET_BLOCK::request&& req, rpc_context context) + void core_rpc_server::invoke(GET_BLOCK& get_block, rpc_context context) { - GET_BLOCK::response res{}; - PERF_TIMER(on_get_block); - if (use_bootstrap_daemon_if_necessary(req, res)) - return res; - block blk; uint64_t block_height; bool orphan = false; crypto::hash block_hash; - if (!req.hash.empty()) + if (!get_block.request.hash.empty()) { - if (!tools::hex_to_type(req.hash, block_hash)) - throw rpc_error{ERROR_WRONG_PARAM, "Failed to parse hex representation of block hash. Hex = " + req.hash + '.'}; + if (!tools::hex_to_type(get_block.request.hash, block_hash)) + throw rpc_error{ERROR_WRONG_PARAM, "Failed to parse hex representation of block hash. Hex = " + get_block.request.hash + '.'}; if (!m_core.get_block_by_hash(block_hash, blk, &orphan)) - throw rpc_error{ERROR_INTERNAL, "Internal error: can't get block by hash. Hash = " + req.hash + '.'}; + throw rpc_error{ERROR_INTERNAL, "Internal error: can't get block by hash. Hash = " + get_block.request.hash + '.'}; if (blk.miner_tx.vin.size() != 1 || !std::holds_alternative(blk.miner_tx.vin.front())) throw rpc_error{ERROR_INTERNAL, "Internal error: coinbase transaction in the block has the wrong type"}; block_height = var::get(blk.miner_tx.vin.front()).height; } else { - if (auto curr_height = m_core.get_current_blockchain_height(); req.height >= curr_height) - throw rpc_error{ERROR_TOO_BIG_HEIGHT, std::string("Requested block height: ") + std::to_string(req.height) + " greater than current top block height: " + std::to_string(curr_height - 1)}; - if (!m_core.get_block_by_height(req.height, blk)) - throw rpc_error{ERROR_INTERNAL, "Internal error: can't get block by height. Height = " + std::to_string(req.height) + '.'}; + if (auto curr_height = m_core.get_current_blockchain_height(); get_block.request.height >= curr_height) + throw rpc_error{ERROR_TOO_BIG_HEIGHT, std::string("Requested block height: ") + std::to_string(get_block.request.height) + " greater than current top block height: " + std::to_string(curr_height - 1)}; + if (!m_core.get_block_by_height(get_block.request.height, blk)) + throw rpc_error{ERROR_INTERNAL, "Internal error: can't get block by height. Height = " + std::to_string(get_block.request.height) + '.'}; block_hash = get_block_hash(blk); - block_height = req.height; + block_height = get_block.request.height; } - fill_block_header_response(blk, orphan, block_height, block_hash, res.block_header, req.fill_pow_hash && context.admin, false /*tx hashes*/); - res.tx_hashes.reserve(blk.tx_hashes.size()); - for (const auto& tx_hash : blk.tx_hashes) - res.tx_hashes.push_back(tools::type_to_hex(tx_hash)); - res.blob = oxenmq::to_hex(t_serializable_object_to_blob(blk)); - res.json = obj_to_json_str(blk); - res.status = STATUS_OK; - return res; + block_header_response header; + fill_block_header_response(blk, orphan, block_height, block_hash, header, get_block.request.fill_pow_hash && context.admin, false /*tx hashes*/); + get_block.response["block_header"] = header; + std::vector tx_hashes; + tx_hashes.reserve(blk.tx_hashes.size()); + std::transform(blk.tx_hashes.begin(), blk.tx_hashes.end(), tx_hashes.begin(), [](const auto& x) { return tools::type_to_hex(x); }); + get_block.response["tx_hashes"] = tx_hashes; + get_block.response["blob"] = oxenmq::to_hex(t_serializable_object_to_blob(blk)); + get_block.response["json"] = obj_to_json_str(blk); + get_block.response["status"] = STATUS_OK; + return; } static json json_connection_info(const connection_info& ci) { diff --git a/src/rpc/core_rpc_server.h b/src/rpc/core_rpc_server.h index aea222d33..3e7b4d57a 100644 --- a/src/rpc/core_rpc_server.h +++ b/src/rpc/core_rpc_server.h @@ -256,6 +256,7 @@ namespace cryptonote::rpc { void invoke(RELAY_TX& relay_tx, rpc_context context); void invoke(GET_BLOCK_HEADERS_RANGE& get_block_headers_range, rpc_context context); void invoke(GET_BLOCK_HEADER_BY_HEIGHT& get_block_header_by_height, rpc_context context); + void invoke(GET_BLOCK& get_block, rpc_context context); // Deprecated Monero NIH binary endpoints: GET_ALT_BLOCKS_HASHES_BIN::response invoke(GET_ALT_BLOCKS_HASHES_BIN::request&& req, rpc_context context); @@ -267,11 +268,10 @@ namespace cryptonote::rpc { GET_OUTPUTS_BIN::response invoke(GET_OUTPUTS_BIN::request&& req, rpc_context context); GET_TRANSACTION_POOL_HASHES_BIN::response invoke(GET_TRANSACTION_POOL_HASHES_BIN::request&& req, rpc_context context); GET_TX_GLOBAL_OUTPUTS_INDEXES_BIN::response invoke(GET_TX_GLOBAL_OUTPUTS_INDEXES_BIN::request&& req, rpc_context context); + GET_OUTPUT_DISTRIBUTION::response invoke(GET_OUTPUT_DISTRIBUTION::request&& req, rpc_context context, bool binary = false); // FIXME: unconverted JSON RPC endpoints: SET_BOOTSTRAP_DAEMON::response invoke(SET_BOOTSTRAP_DAEMON::request&& req, rpc_context context); - GET_OUTPUT_DISTRIBUTION::response invoke(GET_OUTPUT_DISTRIBUTION::request&& req, rpc_context context, bool binary = false); - GET_BLOCK::response invoke(GET_BLOCK::request&& req, rpc_context context); GET_OUTPUT_HISTOGRAM::response invoke(GET_OUTPUT_HISTOGRAM::request&& req, rpc_context context); GET_ALTERNATE_CHAINS::response invoke(GET_ALTERNATE_CHAINS::request&& req, rpc_context context); GET_QUORUM_STATE::response invoke(GET_QUORUM_STATE::request&& req, rpc_context context); diff --git a/src/rpc/core_rpc_server_command_parser.cpp b/src/rpc/core_rpc_server_command_parser.cpp index 7fa8dc6b3..f4f94f880 100644 --- a/src/rpc/core_rpc_server_command_parser.cpp +++ b/src/rpc/core_rpc_server_command_parser.cpp @@ -503,4 +503,10 @@ namespace cryptonote::rpc { get_values(in, "fill_pow_hash", get_block_header_by_height.request.fill_pow_hash); get_values(in, "get_tx_hashes", get_block_header_by_height.request.get_tx_hashes); } + + void parse_request(GET_BLOCK& get_block, rpc_input in) { + get_values(in, "hash", get_block.request.hash); + get_values(in, "height", get_block.request.height); + get_values(in, "fill_pow_hash", get_block.request.fill_pow_hash); + } } diff --git a/src/rpc/core_rpc_server_command_parser.h b/src/rpc/core_rpc_server_command_parser.h index e1f44a581..7543d5014 100644 --- a/src/rpc/core_rpc_server_command_parser.h +++ b/src/rpc/core_rpc_server_command_parser.h @@ -43,4 +43,5 @@ namespace cryptonote::rpc { void parse_request(GET_STAKING_REQUIREMENT& get_staking_requirement, rpc_input in); void parse_request(GET_BLOCK_HEADERS_RANGE& get_block_headers_range, rpc_input in); void parse_request(GET_BLOCK_HEADER_BY_HEIGHT& get_block_header_by_height, rpc_input in); + void parse_request(GET_BLOCK& get_block, rpc_input in); } diff --git a/src/rpc/core_rpc_server_commands_defs.cpp b/src/rpc/core_rpc_server_commands_defs.cpp index af3d6a0df..e74e9e313 100644 --- a/src/rpc/core_rpc_server_commands_defs.cpp +++ b/src/rpc/core_rpc_server_commands_defs.cpp @@ -103,23 +103,6 @@ KV_SERIALIZE_MAP_CODE_BEGIN(block_header_response) KV_SERIALIZE_MAP_CODE_END() -KV_SERIALIZE_MAP_CODE_BEGIN(GET_BLOCK::request) - KV_SERIALIZE(hash) - KV_SERIALIZE(height) - KV_SERIALIZE_OPT(fill_pow_hash, false); -KV_SERIALIZE_MAP_CODE_END() - - -KV_SERIALIZE_MAP_CODE_BEGIN(GET_BLOCK::response) - KV_SERIALIZE(block_header) - KV_SERIALIZE(tx_hashes) - KV_SERIALIZE(status) - KV_SERIALIZE(blob) - KV_SERIALIZE(json) - KV_SERIALIZE(untrusted) -KV_SERIALIZE_MAP_CODE_END() - - KV_SERIALIZE_MAP_CODE_BEGIN(SET_BOOTSTRAP_DAEMON::request) KV_SERIALIZE(address) KV_SERIALIZE(username) diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h index 5c747c07c..82208b701 100644 --- a/src/rpc/core_rpc_server_commands_defs.h +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -846,33 +846,32 @@ namespace cryptonote::rpc { } request; }; - OXEN_RPC_DOC_INTROSPECT - // Full block information can be retrieved by either block height or hash, like with the above block header calls. - // For full block information, both lookups use the same method, but with different input parameters. + /// Full block information can be retrieved by either block height or hash, like with the above block header calls. + /// For full block information, both lookups use the same method, but with different input parameters. + /// + /// Inputs: + /// + /// - \p hash The block's hash. + /// - \p height A block height to look up; returned in `block_header` + /// - \p fill_pow_hash Tell the daemon if it should fill out pow_hash field. + /// + /// Output values available from a public RPC endpoint: + /// + /// - \p status General RPC status string. `"OK"` means everything looks good. + /// - \p block_header Block header information for the requested `height` block + /// - \p tx_hashes List of hashes of non-coinbase transactions in the block. If there are no other transactions, this will be an empty list. + /// - \p blob Hexadecimal blob of block information. + /// - \p json JSON formatted block details. struct GET_BLOCK : PUBLIC { static constexpr auto names() { return NAMES("get_block", "getblock"); } - struct request + struct request_parameters { std::string hash; // The block's hash. uint64_t height; // The block's height. bool fill_pow_hash; // Tell the daemon if it should fill out pow_hash field. - - KV_MAP_SERIALIZABLE - }; - - struct response - { - std::string status; // General RPC error code. "OK" means everything looks good. - block_header_response block_header; // A structure containing block header information. See get_last_block_header. - std::vector tx_hashes; // List of hashes of non-coinbase transactions in the block. If there are no other transactions, this will be an empty list. - std::string blob; // Hexadecimal blob of block information. - std::string json; // JSON formatted block details. - bool untrusted; // States if the result is obtained using the bootstrap mode, and is therefore not trusted (`true`), or when the daemon is fully synced (`false`). - - KV_MAP_SERIALIZABLE - }; + } request; }; /// Get the list of current network peers known to this node.