GET_LAST_BLOCK_HEADER

This commit is contained in:
Sean Darcy 2021-11-05 14:12:29 +11:00
parent 18016ded02
commit 445fab4ac5
7 changed files with 104 additions and 44 deletions

View file

@ -1999,14 +1999,15 @@ bool rpc_command_executor::prepare_registration(bool force_registration)
// Query the latest block we've synced and check that the timestamp is sensible, issue a warning if not
{
GET_LAST_BLOCK_HEADER::response res{};
if (!invoke<GET_LAST_BLOCK_HEADER>({}, res, "Get latest block failed, unable to check sync status"))
auto const& maybe_header = try_running([this] {
return invoke<GET_LAST_BLOCK_HEADER>().at("block_header").get<block_header_response>();
}, "Get latest block failed, unable to check sync status");
if (!maybe_header)
return false;
auto const& header = res.block_header;
uint64_t const now = time(nullptr);
auto const& header = *maybe_header;
if (now >= header.timestamp)
{
uint64_t delta = now - header.timestamp;

View file

@ -1667,26 +1667,34 @@ namespace cryptonote::rpc {
res.untrusted = true;
return true;
}
//------------------------------------------------------------------------------------------------------------------------------
GET_LAST_BLOCK_HEADER::response core_rpc_server::invoke(GET_LAST_BLOCK_HEADER::request&& req, rpc_context context)
void core_rpc_server::invoke(GET_LAST_BLOCK_HEADER& get_last_block_header, rpc_context context)
{
GET_LAST_BLOCK_HEADER::response res{};
PERF_TIMER(on_get_last_block_header);
if (use_bootstrap_daemon_if_necessary<GET_LAST_BLOCK_HEADER>(req, res))
return res;
CHECK_CORE_READY();
if(!check_core_ready())
{
get_last_block_header.response["status"] = STATUS_BUSY;
return;
}
auto [last_block_height, last_block_hash] = m_core.get_blockchain_top();
block last_block;
bool have_last_block = m_core.get_block_by_height(last_block_height, last_block);
if (!have_last_block)
throw rpc_error{ERROR_INTERNAL, "Internal error: can't get last block."};
fill_block_header_response(last_block, false, last_block_height, last_block_hash, res.block_header, req.fill_pow_hash && context.admin, req.get_tx_hashes);
res.status = STATUS_OK;
return res;
block_header_response header{};
fill_block_header_response(last_block, false, last_block_height, last_block_hash, header, get_last_block_header.request.fill_pow_hash && context.admin, get_last_block_header.request.get_tx_hashes);
nlohmann::json header_as_json = header;
get_last_block_header.response["block_header"] = header_as_json;
get_last_block_header.response["status"] = STATUS_OK;
return;
}
//------------------------------------------------------------------------------------------------------------------------------
GET_BLOCK_HEADER_BY_HASH::response core_rpc_server::invoke(GET_BLOCK_HEADER_BY_HASH::request&& req, rpc_context context)
{
GET_BLOCK_HEADER_BY_HASH::response res{};

View file

@ -244,6 +244,7 @@ namespace cryptonote::rpc {
void invoke(TEST_TRIGGER_UPTIME_PROOF& test_trigger_uptime_proof, rpc_context context);
void invoke(REPORT_PEER_STATUS& report_peer_status, rpc_context context);
void invoke(FLUSH_CACHE& flush_cache, rpc_context context);
void invoke(GET_LAST_BLOCK_HEADER& get_last_block_header, 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);
@ -259,7 +260,6 @@ namespace cryptonote::rpc {
// 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_LAST_BLOCK_HEADER::response invoke(GET_LAST_BLOCK_HEADER::request&& req, rpc_context context);
GET_BLOCK_HEADER_BY_HASH::response invoke(GET_BLOCK_HEADER_BY_HASH::request&& req, rpc_context context);
GET_BLOCK_HEADER_BY_HEIGHT::response invoke(GET_BLOCK_HEADER_BY_HEIGHT::request&& req, rpc_context context);
GET_BLOCK_HEADERS_RANGE::response invoke(GET_BLOCK_HEADERS_RANGE::request&& req, rpc_context context);

View file

@ -466,4 +466,9 @@ namespace cryptonote::rpc {
get_values(in, "bad_txs", flush_cache.request.bad_txs);
get_values(in, "bad_blocks", flush_cache.request.bad_blocks);
}
void parse_request(GET_LAST_BLOCK_HEADER& get_last_block_header, rpc_input in) {
get_values(in, "fill_pow_hash", get_last_block_header.request.fill_pow_hash);
get_values(in, "get_tx_hashes", get_last_block_header.request.get_tx_hashes);
}
}

View file

@ -37,4 +37,5 @@ namespace cryptonote::rpc {
void parse_request(GET_SN_STATE_CHANGES& get_sn_state_changes, rpc_input in);
void parse_request(REPORT_PEER_STATUS& report_peer_status, rpc_input in);
void parse_request(FLUSH_CACHE& flush_cache, rpc_input in);
void parse_request(GET_LAST_BLOCK_HEADER& get_lash_block_header, rpc_input in);
}

View file

@ -10,6 +10,64 @@ void RPC_COMMAND::set_bt() {
response_hex.format = json_binary_proxy::fmt::bt;
}
void to_json(nlohmann::json& j, const block_header_response& h)
{
j = nlohmann::json
{
{"major_version", h.major_version},
{"minor_version", h.minor_version},
{"timestamp", h.timestamp},
{"prev_hash", h.prev_hash},
{"nonce", h.nonce},
{"orphan_status", h.orphan_status},
{"height", h.height},
{"depth", h.depth},
{"hash", h.hash},
{"difficulty", h.difficulty},
{"cumulative_difficulty", h.cumulative_difficulty},
{"reward", h.reward},
{"miner_reward", h.miner_reward},
{"block_size", h.block_size},
{"block_weight", h.block_weight},
{"num_txes", h.num_txes},
{"pow_hash", h.pow_hash ? *h.pow_hash : nullptr},
{"long_term_weight", h.long_term_weight},
{"miner_tx_hash", h.miner_tx_hash},
{"miner_tx_hash", h.miner_tx_hash},
{"tx_hashes", h.tx_hashes},
{"service_node_winner", h.service_node_winner},
};
};
void from_json(const nlohmann::json& j, block_header_response& h)
{
j.at("major_version").get_to(h.major_version);
j.at("minor_version").get_to(h.minor_version);
j.at("timestamp").get_to(h.timestamp);
j.at("prev_hash").get_to(h.prev_hash);
j.at("nonce").get_to(h.nonce);
j.at("orphan_status").get_to(h.orphan_status);
j.at("height").get_to(h.height);
j.at("depth").get_to(h.depth);
j.at("hash").get_to(h.hash);
j.at("difficulty").get_to(h.difficulty);
j.at("cumulative_difficulty").get_to(h.cumulative_difficulty);
j.at("reward").get_to(h.reward);
j.at("miner_reward").get_to(h.miner_reward);
j.at("block_size").get_to(h.block_size);
j.at("block_weight").get_to(h.block_weight);
j.at("num_txes").get_to(h.num_txes);
if (j.at("pow_hash").is_null())
h.pow_hash = std::nullopt;
else
h.pow_hash = j["pow_hash"].get<std::string>();
j.at("long_term_weight").get_to(h.long_term_weight);
j.at("miner_tx_hash").get_to(h.miner_tx_hash);
j.at("miner_tx_hash").get_to(h.miner_tx_hash);
j.at("tx_hashes").get_to(h.tx_hashes);
j.at("service_node_winner").get_to(h.service_node_winner);
}
KV_SERIALIZE_MAP_CODE_BEGIN(STATUS)
KV_SERIALIZE(status)
KV_SERIALIZE_MAP_CODE_END()
@ -44,19 +102,6 @@ KV_SERIALIZE_MAP_CODE_BEGIN(block_header_response)
KV_SERIALIZE_MAP_CODE_END()
KV_SERIALIZE_MAP_CODE_BEGIN(GET_LAST_BLOCK_HEADER::request)
KV_SERIALIZE_OPT(fill_pow_hash, false);
KV_SERIALIZE_OPT(get_tx_hashes, false);
KV_SERIALIZE_MAP_CODE_END()
KV_SERIALIZE_MAP_CODE_BEGIN(GET_LAST_BLOCK_HEADER::response)
KV_SERIALIZE(block_header)
KV_SERIALIZE(status)
KV_SERIALIZE(untrusted)
KV_SERIALIZE_MAP_CODE_END()
KV_SERIALIZE_MAP_CODE_BEGIN(GET_BLOCK_HEADER_BY_HASH::request)
KV_SERIALIZE(hash)
KV_SERIALIZE(hashes)

View file

@ -768,28 +768,28 @@ namespace cryptonote::rpc {
KV_MAP_SERIALIZABLE
};
OXEN_RPC_DOC_INTROSPECT
// Block header information for the most recent block is easily retrieved with this method. No inputs are needed.
void to_json(nlohmann::json& j, const block_header_response& h);
void from_json(const nlohmann::json& j, block_header_response& h);
/// Block header information for the most recent block is easily retrieved with this method. No inputs are needed.
///
/// Inputs:
/// - \p fill_pow_hash Tell the daemon if it should fill out pow_hash field.
/// - \p get_tx_hashes If true (default false) then include the hashes of non-coinbase transactions
///
/// Output values available from a public RPC endpoint:
///
/// - \p status General RPC status string. `"OK"` means everything looks good.
/// - \p block_header A structure containing block header information.
struct GET_LAST_BLOCK_HEADER : PUBLIC
{
static constexpr auto names() { return NAMES("get_last_block_header", "getlastblockheader"); }
struct request
struct request_parameters
{
bool fill_pow_hash; // Tell the daemon if it should fill out pow_hash field.
bool get_tx_hashes; // If true (default false) then include the hashes of non-coinbase transactions
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.
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
};
bool fill_pow_hash;
bool get_tx_hashes;
} request;
};
OXEN_RPC_DOC_INTROSPECT