GET_QUORUM_STATE

This commit is contained in:
Sean Darcy 2021-11-12 12:14:21 +11:00
parent aa0427dbdb
commit e206fd12ed
6 changed files with 62 additions and 86 deletions

View File

@ -706,22 +706,22 @@ bool rpc_command_executor::print_blockchain_info(int64_t start_block_index, uint
bool rpc_command_executor::print_quorum_state(uint64_t start_height, uint64_t end_height)
{
GET_QUORUM_STATE::request req{};
GET_QUORUM_STATE::response res{};
req.start_height = start_height;
req.end_height = end_height;
req.quorum_type = GET_QUORUM_STATE::ALL_QUORUMS_SENTINEL_VALUE;
if (!invoke<GET_QUORUM_STATE>(std::move(req), res, "Failed to retrieve quorum state"))
auto maybe_quorums = try_running([this, start_height, end_height] {
return invoke<GET_QUORUM_STATE>(json{
{"start_height", start_height},
{"end_height", end_height},
{"quorum_type", GET_QUORUM_STATE::ALL_QUORUMS_SENTINEL_VALUE}});
}, "Failed to retrieve quorum state");
if (!maybe_quorums)
return false;
auto& quorums = *maybe_quorums;
std::string output;
output.append("{\n\"quorums\": [");
for (GET_QUORUM_STATE::quorum_for_height const &quorum : res.quorums)
for (auto const& quorum : quorums["quorums"])
{
output.append("\n");
output.append(epee::serialization::store_t_to_json(quorum));
output.append(quorum);
output.append(",\n");
}
output.append("]\n}");

View File

@ -143,7 +143,6 @@ public:
return invoke<Response>(params)["response"];
}
bool print_checkpoints(uint64_t start_height, uint64_t end_height, bool print_json);
bool print_sn_state_changes(uint64_t start_height, uint64_t end_height);

View File

@ -2237,25 +2237,25 @@ namespace cryptonote::rpc {
}
GET_QUORUM_STATE::response core_rpc_server::invoke(GET_QUORUM_STATE::request&& req, rpc_context context)
void core_rpc_server::invoke(GET_QUORUM_STATE& get_quorum_state, rpc_context context)
{
GET_QUORUM_STATE::response res{};
PERF_TIMER(on_get_quorum_state);
if (req.quorum_type >= tools::enum_count<service_nodes::quorum_type> &&
req.quorum_type != GET_QUORUM_STATE::ALL_QUORUMS_SENTINEL_VALUE)
throw rpc_error{ERROR_WRONG_PARAM,
"Quorum type specifies an invalid value: " + std::to_string(req.quorum_type)};
uint8_t quorum_type = get_quorum_state.request.quorum_type;
auto requested_type = [&req](service_nodes::quorum_type type) {
return req.quorum_type == GET_QUORUM_STATE::ALL_QUORUMS_SENTINEL_VALUE ||
req.quorum_type == static_cast<uint8_t>(type);
if (quorum_type >= tools::enum_count<service_nodes::quorum_type> &&
quorum_type != GET_QUORUM_STATE::ALL_QUORUMS_SENTINEL_VALUE)
throw rpc_error{ERROR_WRONG_PARAM,
"Quorum type specifies an invalid value: " + std::to_string(get_quorum_state.request.quorum_type)};
auto requested_type = [quorum_type](service_nodes::quorum_type type) {
return quorum_type == GET_QUORUM_STATE::ALL_QUORUMS_SENTINEL_VALUE ||
quorum_type == static_cast<uint8_t>(type);
};
bool latest = false;
uint64_t latest_ob = 0, latest_cp = 0, latest_bl = 0;
uint64_t start = req.start_height, end = req.end_height;
uint64_t start = get_quorum_state.request.start_height, end = get_quorum_state.request.end_height;
uint64_t curr_height = m_core.get_blockchain_storage().get_current_blockchain_height();
if (start == GET_QUORUM_STATE::HEIGHT_SENTINEL_VALUE &&
end == GET_QUORUM_STATE::HEIGHT_SENTINEL_VALUE)
@ -2297,7 +2297,7 @@ namespace cryptonote::rpc {
bool add_curr_pulse = (latest || end > curr_height) && requested_type(service_nodes::quorum_type::pulse);
end = std::min(curr_height, end);
uint64_t count = (start > end) ? start - end : end - start;
uint64_t count = (start > end) ? start - end : end - start;
if (!context.admin && count > GET_QUORUM_STATE::MAX_COUNT)
throw rpc_error{ERROR_WRONG_PARAM,
"Number of requested quorums greater than the allowed limit: "
@ -2305,7 +2305,8 @@ namespace cryptonote::rpc {
+ ", requested: " + std::to_string(count)};
bool at_least_one_succeeded = false;
res.quorums.reserve(std::min((uint64_t)16, count));
std::vector<GET_QUORUM_STATE::quorum_for_height> quorums;
quorums.reserve(std::min((uint64_t)16, count));
auto net = nettype();
for (size_t height = start; height != end;)
{
@ -2314,9 +2315,9 @@ namespace cryptonote::rpc {
auto start_quorum_iterator = static_cast<service_nodes::quorum_type>(0);
auto end_quorum_iterator = service_nodes::max_quorum_type_for_hf(hf_version);
if (req.quorum_type != GET_QUORUM_STATE::ALL_QUORUMS_SENTINEL_VALUE)
if (quorum_type != GET_QUORUM_STATE::ALL_QUORUMS_SENTINEL_VALUE)
{
start_quorum_iterator = static_cast<service_nodes::quorum_type>(req.quorum_type);
start_quorum_iterator = static_cast<service_nodes::quorum_type>(quorum_type);
end_quorum_iterator = start_quorum_iterator;
}
@ -2332,7 +2333,7 @@ namespace cryptonote::rpc {
}
if (std::shared_ptr<const service_nodes::quorum> quorum = m_core.get_quorum(type, height, true /*include_old*/))
{
auto& entry = res.quorums.emplace_back();
auto& entry = quorums.emplace_back();
entry.height = height;
entry.quorum_type = static_cast<uint8_t>(quorum_int);
entry.quorum.validators = hexify(quorum->validators);
@ -2363,7 +2364,7 @@ namespace cryptonote::rpc {
auto quorum = generate_pulse_quorum(m_core.get_nettype(), sn_list.get_block_leader().key, hf_version, sn_list.active_service_nodes_infos(), entropy, pulse_round);
if (verify_pulse_quorum_sizes(quorum))
{
auto& entry = res.quorums.emplace_back();
auto& entry = quorums.emplace_back();
entry.height = curr_height;
entry.quorum_type = static_cast<uint8_t>(service_nodes::quorum_type::pulse);
@ -2378,8 +2379,9 @@ namespace cryptonote::rpc {
if (!at_least_one_succeeded)
throw rpc_error{ERROR_WRONG_PARAM, "Failed to query any quorums at all"};
res.status = STATUS_OK;
return res;
get_quorum_state.response["quorums"] = quorums;
get_quorum_state.response["status"] = STATUS_OK;
return;
}
//------------------------------------------------------------------------------------------------------------------------------
void core_rpc_server::invoke(FLUSH_CACHE& flush_cache, rpc_context context)

View File

@ -251,6 +251,7 @@ namespace cryptonote::rpc {
void invoke(GET_BLOCK_HEADER_BY_HEIGHT& get_block_header_by_height, rpc_context context);
void invoke(GET_BLOCK& get_block, rpc_context context);
void invoke(GET_SERVICE_NODE_REGISTRATION_CMD_RAW& get_service_node_registration_cmd_raw, rpc_context context);
void invoke(GET_QUORUM_STATE& get_quorum_state, 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,7 +268,6 @@ namespace cryptonote::rpc {
// FIXME: unconverted JSON RPC endpoints:
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);
GET_SERVICE_NODE_REGISTRATION_CMD::response invoke(GET_SERVICE_NODE_REGISTRATION_CMD::request&& req, rpc_context context);
ONS_NAMES_TO_OWNERS::response invoke(ONS_NAMES_TO_OWNERS::request&& req, rpc_context context);
ONS_OWNERS_TO_NAMES::response invoke(ONS_OWNERS_TO_NAMES::request&& req, rpc_context context);

View File

@ -68,6 +68,14 @@ void from_json(const nlohmann::json& j, block_header_response& h)
j.at("service_node_winner").get_to(h.service_node_winner);
};
void to_json(nlohmann::json& j, const GET_QUORUM_STATE::quorum_t& q)
{
j = nlohmann::json{{"validators", q.validators}, {"workers", q.workers}};
};
void to_json(nlohmann::json& j, const GET_QUORUM_STATE::quorum_for_height& q)
{
j = nlohmann::json{{"height", q.height}, {"quorum_type", q.quorum_type}, {"quorum", q.quorum}};
};
KV_SERIALIZE_MAP_CODE_BEGIN(STATUS)
KV_SERIALIZE(status)
@ -218,32 +226,6 @@ KV_SERIALIZE_MAP_CODE_BEGIN(GET_OUTPUT_DISTRIBUTION::response)
KV_SERIALIZE_MAP_CODE_END()
KV_SERIALIZE_MAP_CODE_BEGIN(GET_QUORUM_STATE::request)
KV_SERIALIZE_OPT(start_height, HEIGHT_SENTINEL_VALUE)
KV_SERIALIZE_OPT(end_height, HEIGHT_SENTINEL_VALUE)
KV_SERIALIZE_OPT(quorum_type, ALL_QUORUMS_SENTINEL_VALUE)
KV_SERIALIZE_MAP_CODE_END()
KV_SERIALIZE_MAP_CODE_BEGIN(GET_QUORUM_STATE::quorum_t)
KV_SERIALIZE(validators)
KV_SERIALIZE(workers)
KV_SERIALIZE_MAP_CODE_END()
KV_SERIALIZE_MAP_CODE_BEGIN(GET_QUORUM_STATE::quorum_for_height)
KV_SERIALIZE(height)
KV_SERIALIZE(quorum_type)
KV_SERIALIZE(quorum)
KV_SERIALIZE_MAP_CODE_END()
KV_SERIALIZE_MAP_CODE_BEGIN(GET_QUORUM_STATE::response)
KV_SERIALIZE(status)
KV_SERIALIZE(quorums)
KV_SERIALIZE_MAP_CODE_END()
KV_SERIALIZE_MAP_CODE_BEGIN(GET_SERVICE_NODE_REGISTRATION_CMD::contribution_t)
KV_SERIALIZE(address)
KV_SERIALIZE(amount)

View File

@ -1570,8 +1570,24 @@ namespace cryptonote::rpc {
};
OXEN_RPC_DOC_INTROSPECT
// Accesses the list of public keys of the nodes who are participating or being tested in a quorum.
/// Accesses the list of public keys of the nodes who are participating or being tested in a quorum.
///
/// Inputs:
///
/// - \p start_height (Optional): Start height, omit both start and end height to request the latest quorum. Note that "latest" means different heights for different types of quorums as not all quorums exist at every block heights.
/// - \p end_height (Optional): End height, omit both start and end height to request the latest quorum
/// - \p quorum_type (Optional): Set value to request a specific quorum, 0 = Obligation, 1 = Checkpointing, 2 = Blink, 3 = Pulse, 255 = all quorums, default is all quorums. For Pulse quorums, requesting the blockchain height (or latest) returns the primary pulse quorum responsible for the next block; for heights with blocks this returns the actual quorum, which may be a backup quorum if the primary quorum did not produce in time.
///
/// Output values available from a public RPC endpoint:
///
/// - \p status General RPC status string. `"OK"` means everything looks good.
/// - \p quorums An array of quorums associated with the requested height. Each element is structured with the following keys:
/// - \p service_node_pubkey The public key of the Service Node, in hex (json) or binary (bt).
/// - \p height The height the quorums are relevant for
/// - \p quorum_type The quorum type
/// - \p quorum Quorum of Service Nodes. Each element is structured with the following keys:
/// - \p validators List of service node public keys in the quorum. For obligations quorums these are the testing nodes; for checkpoint and blink these are the participating nodes (there are no workers); for Pulse blink quorums these are the block signers. This is hex encoded, even for bt-encoded requests.
/// - \p workers Public key of the quorum workers. For obligations quorums these are the nodes being tested; for Pulse quorums this is the block producer. Checkpoint and Blink quorums do not populate this field. This is hex encoded, even for bt-encoded requests.
struct GET_QUORUM_STATE : PUBLIC
{
static constexpr auto names() { return NAMES("get_quorum_state"); }
@ -1579,26 +1595,17 @@ namespace cryptonote::rpc {
static constexpr size_t MAX_COUNT = 256;
static constexpr uint64_t HEIGHT_SENTINEL_VALUE = UINT64_MAX;
static constexpr uint8_t ALL_QUORUMS_SENTINEL_VALUE = 255;
struct request
struct request_parameters
{
uint64_t start_height; // (Optional): Start height, omit both start and end height to request the latest quorum. Note that "latest" means different heights for different types of quorums as not all quorums exist at every block heights.
uint64_t end_height; // (Optional): End height, omit both start and end height to request the latest quorum
uint8_t quorum_type; // (Optional): Set value to request a specific quorum, 0 = Obligation, 1 = Checkpointing, 2 = Blink, 3 = Pulse, 255 = all quorums, default is all quorums. For Pulse quorums, requesting the blockchain height (or latest) returns the primary pulse quorum responsible for the next block; for heights with blocks this returns the actual quorum, which may be a backup quorum if the primary quorum did not produce in time.
KV_MAP_SERIALIZABLE
};
} request;
struct quorum_t
{
std::vector<std::string> validators; // List of service node public keys in the quorum. For obligations quorums these are the testing nodes; for checkpoint and blink these are the participating nodes (there are no workers); for Pulse blink quorums these are the block signers.
std::vector<std::string> workers; // Public key of the quorum workers. For obligations quorums these are the nodes being tested; for Pulse quorums this is the block producer. Checkpoint and Blink quorums do not populate this field.
KV_MAP_SERIALIZABLE
BEGIN_SERIALIZE() // NOTE: For store_t_to_json
FIELD(validators)
FIELD(workers)
END_SERIALIZE()
};
struct quorum_for_height
@ -1606,24 +1613,10 @@ namespace cryptonote::rpc {
uint64_t height; // The height the quorums are relevant for
uint8_t quorum_type; // The quorum type
quorum_t quorum; // Quorum of Service Nodes
KV_MAP_SERIALIZABLE
BEGIN_SERIALIZE() // NOTE: For store_t_to_json
FIELD(height)
FIELD(quorum_type)
FIELD(quorum)
END_SERIALIZE()
};
struct response
{
std::string status; // Generic RPC error code. "OK" is the success value.
std::vector<quorum_for_height> quorums; // An array of quorums associated with the requested height
KV_MAP_SERIALIZABLE
};
};
inline void to_json(nlohmann::json& j, const GET_QUORUM_STATE::quorum_t& q);
inline void to_json(nlohmann::json& j, const GET_QUORUM_STATE::quorum_for_height& q);
/// Returns the command that should be run to prepare a service node, includes correct parameters
/// and service node ids formatted ready for cut and paste into daemon console.