GET_BLOCK

This commit is contained in:
Sean Darcy 2021-11-11 13:37:15 +11:00
parent 129e6f204c
commit 285e89ecda
8 changed files with 74 additions and 81 deletions

View file

@ -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<GET_BLOCK>(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<GET_BLOCK>(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<GET_BLOCK>(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,

View file

@ -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);

View file

@ -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<GET_BLOCK>(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<txin_gen>(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<txin_gen>(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<std::string> 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) {

View file

@ -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);

View file

@ -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);
}
}

View file

@ -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);
}

View file

@ -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)

View file

@ -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<std::string> 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.