More RPC fixes

This commit is contained in:
Jason Rhinelander 2022-12-16 22:42:20 -04:00
parent 3179a97b32
commit b128f373d3
No known key found for this signature in database
GPG Key ID: C4992CE7A88D4262
7 changed files with 171 additions and 146 deletions

View File

@ -68,10 +68,9 @@ static bool parse_if_present(std::forward_list<std::string>& list, T& var, const
return false;
}
bool command_parser_executor::print_checkpoints(const std::vector<std::string> &args)
bool command_parser_executor::print_checkpoints(const std::vector<std::string>& args)
{
uint64_t start_height = cryptonote::rpc::GET_CHECKPOINTS::HEIGHT_SENTINEL_VALUE;
uint64_t end_height = cryptonote::rpc::GET_CHECKPOINTS::HEIGHT_SENTINEL_VALUE;
std::optional<uint64_t> start_height, end_height;
std::forward_list<std::string> args_list(args.begin(), args.end());
bool print_json = !args_list.empty() && args_list.front() == "+json";
@ -99,7 +98,7 @@ bool command_parser_executor::print_checkpoints(const std::vector<std::string> &
bool command_parser_executor::print_sn_state_changes(const std::vector<std::string> &args)
{
uint64_t start_height;
uint64_t end_height = cryptonote::rpc::GET_SN_STATE_CHANGES::HEIGHT_SENTINEL_VALUE;
std::optional<uint64_t> end_height;
if (args.empty()) {
std::cout << "Missing first argument start_height" << std::endl;
@ -113,8 +112,6 @@ bool command_parser_executor::print_sn_state_changes(const std::vector<std::stri
return false;
}
args_list.pop_front();
if (!parse_if_present(args_list, end_height, "end height"))
return false;
@ -233,8 +230,8 @@ bool command_parser_executor::print_blockchain_info(const std::vector<std::strin
bool command_parser_executor::print_quorum_state(const std::vector<std::string>& args)
{
uint64_t start_height = cryptonote::rpc::GET_QUORUM_STATE::HEIGHT_SENTINEL_VALUE;
uint64_t end_height = cryptonote::rpc::GET_QUORUM_STATE::HEIGHT_SENTINEL_VALUE;
std::optional<uint64_t> start_height;
std::optional<uint64_t> end_height;
std::forward_list<std::string> args_list(args.begin(), args.end());
if (!parse_if_present(args_list, start_height, "start height"))

View File

@ -279,24 +279,26 @@ json rpc_command_executor::invoke(
return result;
}
bool rpc_command_executor::print_checkpoints(uint64_t start_height, uint64_t end_height, bool print_json)
bool rpc_command_executor::print_checkpoints(std::optional<uint64_t> start_height, std::optional<uint64_t> end_height, bool print_json)
{
uint32_t count;
if (start_height == GET_CHECKPOINTS::HEIGHT_SENTINEL_VALUE &&
end_height == GET_CHECKPOINTS::HEIGHT_SENTINEL_VALUE)
{
if (!start_height && !end_height)
count = GET_CHECKPOINTS::NUM_CHECKPOINTS_TO_QUERY_BY_DEFAULT;
}
else if (start_height == GET_CHECKPOINTS::HEIGHT_SENTINEL_VALUE ||
end_height == GET_CHECKPOINTS::HEIGHT_SENTINEL_VALUE)
{
else if (!start_height || !end_height)
count = 1;
}
// Otherwise, neither heights are set to HEIGHT_SENTINEL_VALUE, so get all the checkpoints between start and end
// Otherwise, both start/end are set so get all the checkpoints between start and end
auto maybe_checkpoints = try_running([&] { return invoke<GET_CHECKPOINTS>(json{{"start_height", start_height}, {"end_height", end_height}, {"count", count}}); }, "Failed to query blockchain checkpoints");
if (!maybe_checkpoints)
auto maybe_checkpoints = try_running([&] {
json params{
{"count", count}
};
if (start_height)
params["start_height"] = *start_height;
if (end_height)
params["end_height"] = *end_height;
return invoke<GET_CHECKPOINTS>(std::move(params)); }, "Failed to query blockchain checkpoints");
if (!maybe_checkpoints)
return false;
auto checkpoints = *maybe_checkpoints;
@ -321,9 +323,13 @@ bool rpc_command_executor::print_checkpoints(uint64_t start_height, uint64_t end
return true;
}
bool rpc_command_executor::print_sn_state_changes(uint64_t start_height, uint64_t end_height)
bool rpc_command_executor::print_sn_state_changes(uint64_t start_height, std::optional<uint64_t> end_height)
{
auto maybe_sn_state = try_running([&] { return invoke<GET_SN_STATE_CHANGES>(json{{"start_height", start_height}, {"end_height", end_height}}); }, "Failed to query service node state changes");
auto maybe_sn_state = try_running([&] {
json params{{"start_height", start_height}};
if (end_height)
params["end_height"] = *end_height;
return invoke<GET_SN_STATE_CHANGES>(std::move(params)); }, "Failed to query service node state changes");
if (!maybe_sn_state)
return false;
@ -720,14 +726,17 @@ bool rpc_command_executor::print_blockchain_info(int64_t start_block_index, uint
return true;
}
bool rpc_command_executor::print_quorum_state(uint64_t start_height, uint64_t end_height)
bool rpc_command_executor::print_quorum_state(std::optional<uint64_t> start_height, std::optional<uint64_t> end_height)
{
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");
json params;
if (start_height)
params["start_height"] = *start_height;
if (end_height)
params["end_height"] = *end_height;
return invoke<GET_QUORUM_STATE>(std::move(params));
}, "Failed to retrieve quorum state");
if (!maybe_quorums)
return false;
auto& quorums = *maybe_quorums;
@ -1134,7 +1143,7 @@ bool rpc_command_executor::in_peers(bool set, uint32_t limit)
bool rpc_command_executor::print_bans()
{
auto maybe_bans = try_running([this] { return invoke<GETBANS>(); }, "Failed to retrieve ban list");
auto maybe_bans = try_running([this] { return invoke<GET_BANS>(); }, "Failed to retrieve ban list");
if (!maybe_bans)
return false;
auto bans = *maybe_bans;
@ -1154,7 +1163,7 @@ bool rpc_command_executor::print_bans()
bool rpc_command_executor::ban(const std::string &address, time_t seconds, bool clear_ban)
{
auto maybe_banned = try_running([this, &address, seconds, clear_ban] { return invoke<SETBANS>(json{{"host", std::move(address)}, {"ip", 0}, {"seconds", seconds}, {"ban", !clear_ban}}); }, clear_ban ? "Failed to clear ban" : "Failed to set ban");
auto maybe_banned = try_running([this, &address, seconds, clear_ban] { return invoke<SET_BANS>(json{{"host", std::move(address)}, {"ip", 0}, {"seconds", seconds}, {"ban", !clear_ban}}); }, clear_ban ? "Failed to clear ban" : "Failed to set ban");
if (!maybe_banned)
return false;

View File

@ -143,9 +143,9 @@ public:
return invoke<Response>(params)["response"];
}
bool print_checkpoints(uint64_t start_height, uint64_t end_height, bool print_json);
bool print_checkpoints(std::optional<uint64_t> start_height, std::optional<uint64_t> end_height, bool print_json);
bool print_sn_state_changes(uint64_t start_height, uint64_t end_height);
bool print_sn_state_changes(uint64_t start_height, std::optional<uint64_t> end_height);
bool print_peer_list(bool white = true, bool gray = true, size_t limit = 0, bool pruned_only = false);
@ -161,7 +161,7 @@ public:
bool print_blockchain_info(int64_t start_block_index, uint64_t end_block_index);
bool print_quorum_state(uint64_t start_height, uint64_t end_height);
bool print_quorum_state(std::optional<uint64_t> start_height, std::optional<uint64_t> end_height);
bool set_log_level(int8_t level);

View File

@ -44,6 +44,7 @@
#include "cryptonote_config.h"
#include "cryptonote_core/oxen_name_system.h"
#include "cryptonote_core/pulse.h"
#include "cryptonote_core/service_node_rules.h"
#include "epee/net/network_throttle.hpp"
#include "oxen_economy.h"
#include "epee/string_tools.h"
@ -2132,24 +2133,18 @@ namespace cryptonote::rpc {
//------------------------------------------------------------------------------------------------------------------------------
void core_rpc_server::invoke(GET_QUORUM_STATE& get_quorum_state, rpc_context context)
{
uint8_t quorum_type = get_quorum_state.request.quorum_type;
const auto& quorum_type = get_quorum_state.request.quorum_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);
auto is_requested_type = [&quorum_type](service_nodes::quorum_type type) {
return !quorum_type || quorum_type == static_cast<uint8_t>(type);
};
bool latest = false;
uint64_t latest_ob = 0, latest_cp = 0, latest_bl = 0;
uint64_t start = get_quorum_state.request.start_height, end = get_quorum_state.request.end_height;
auto& start = get_quorum_state.request.start_height;
auto& 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)
if (!start && !end)
{
latest = true;
// Our start block for the latest quorum of each type depends on the type being requested:
@ -2159,36 +2154,33 @@ namespace cryptonote::rpc {
// pulse: current height (i.e. top block height + 1)
uint64_t top_height = curr_height - 1;
latest_ob = top_height;
latest_cp = std::min(start, top_height - top_height % service_nodes::CHECKPOINT_INTERVAL);
latest_bl = std::min(start, top_height - top_height % service_nodes::BLINK_QUORUM_INTERVAL);
if (requested_type(service_nodes::quorum_type::checkpointing))
start = std::min(start, latest_cp);
if (requested_type(service_nodes::quorum_type::blink))
start = std::min(start, latest_bl);
latest_cp = top_height - top_height % service_nodes::CHECKPOINT_INTERVAL;
latest_bl = top_height - top_height % service_nodes::BLINK_QUORUM_INTERVAL;
if (is_requested_type(service_nodes::quorum_type::checkpointing))
start = latest_cp;
if (is_requested_type(service_nodes::quorum_type::blink))
start = start ? std::min(*start, latest_bl) : latest_bl;
end = curr_height;
}
else if (start == GET_QUORUM_STATE::HEIGHT_SENTINEL_VALUE)
{
start = end;
end = end + 1;
}
else if (end == GET_QUORUM_STATE::HEIGHT_SENTINEL_VALUE)
{
end = start + 1;
}
else
{
if (end > start) end++;
else if (end != 0) end--;
}
else if (!start)
start = (*end)++;
else if (!end)
end = *start + 1;
else if (*end > *start)
++*end;
else if (end > 0)
--*end;
if (!start || *start > curr_height)
start = curr_height;
start = std::min(curr_height, start);
// We can also provide the pulse quorum for the current block being produced, so if asked for
// that make a note.
bool add_curr_pulse = (latest || end > curr_height) && requested_type(service_nodes::quorum_type::pulse);
end = std::min(curr_height, end);
bool add_curr_pulse = (latest || end > curr_height) && is_requested_type(service_nodes::quorum_type::pulse);
if (!end || *end > curr_height)
end = curr_height;
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: "
@ -2199,54 +2191,49 @@ namespace cryptonote::rpc {
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;)
for (size_t height = *start; height < *end; height++)
{
auto hf_version = get_network_version(net, height);
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 (quorum_type)
{
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 (quorum_type != GET_QUORUM_STATE::ALL_QUORUMS_SENTINEL_VALUE)
{
start_quorum_iterator = static_cast<service_nodes::quorum_type>(quorum_type);
end_quorum_iterator = start_quorum_iterator;
}
for (int quorum_int = (int)start_quorum_iterator; quorum_int <= (int)end_quorum_iterator; quorum_int++)
{
auto type = static_cast<service_nodes::quorum_type>(quorum_int);
if (latest)
{ // Latest quorum requested, so skip if this is isn't the latest height for *this* quorum type
if (type == service_nodes::quorum_type::obligations && height != latest_ob) continue;
if (type == service_nodes::quorum_type::checkpointing && height != latest_cp) continue;
if (type == service_nodes::quorum_type::blink && height != latest_bl) continue;
if (type == service_nodes::quorum_type::pulse) continue;
}
if (std::shared_ptr<const service_nodes::quorum> quorum = m_core.get_quorum(type, height, true /*include_old*/))
{
auto& entry = quorums.emplace_back();
entry.height = height;
entry.quorum_type = static_cast<uint8_t>(quorum_int);
entry.quorum.validators = hexify(quorum->validators);
entry.quorum.workers = hexify(quorum->workers);
at_least_one_succeeded = true;
}
}
start_quorum_iterator = static_cast<service_nodes::quorum_type>(*quorum_type);
end_quorum_iterator = start_quorum_iterator;
}
if (end >= start) height++;
else height--;
for (int quorum_int = (int)start_quorum_iterator; quorum_int <= (int)end_quorum_iterator; quorum_int++)
{
auto type = static_cast<service_nodes::quorum_type>(quorum_int);
if (latest)
{ // Latest quorum requested, so skip if this is isn't the latest height for *this* quorum type
if (type == service_nodes::quorum_type::obligations && height != latest_ob) continue;
if (type == service_nodes::quorum_type::checkpointing && height != latest_cp) continue;
if (type == service_nodes::quorum_type::blink && height != latest_bl) continue;
if (type == service_nodes::quorum_type::pulse) continue;
}
if (std::shared_ptr<const service_nodes::quorum> quorum = m_core.get_quorum(type, height, true /*include_old*/))
{
auto& entry = quorums.emplace_back();
entry.height = height;
entry.quorum_type = static_cast<uint8_t>(quorum_int);
entry.quorum.validators = hexify(quorum->validators);
entry.quorum.workers = hexify(quorum->workers);
at_least_one_succeeded = true;
}
}
}
if (auto hf_version = get_network_version(nettype(), curr_height);
add_curr_pulse && hf_version >= hf::hf16_pulse)
{
cryptonote::Blockchain const &blockchain = m_core.get_blockchain_storage();
cryptonote::block_header const &top_header = blockchain.get_db().get_block_header_from_height(curr_height - 1);
const auto& blockchain = m_core.get_blockchain_storage();
const auto& top_header = blockchain.get_db().get_block_header_from_height(curr_height - 1);
pulse::timings next_timings = {};
uint8_t pulse_round = 0;
pulse::timings next_timings{};
uint8_t pulse_round = 0;
if (pulse::get_round_timings(blockchain, curr_height, top_header.timestamp, next_timings) &&
pulse::convert_time_to_round(pulse::clock::now(), next_timings.r0_timestamp, &pulse_round))
{
@ -2706,49 +2693,52 @@ namespace cryptonote::rpc {
get_staking_requirement.response["status"] = STATUS_OK;
return;
}
//------------------------------------------------------------------------------------------------------------------------------
static void check_quantity_limit(size_t count, size_t max, char const *container_name = nullptr)
template <typename T>
static void check_quantity_limit(T count, T max, const char* container_name = "input")
{
if (count > max)
{
std::ostringstream err;
err << "Number of requested entries";
if (container_name) err << " in " << container_name;
err << " greater than the allowed limit: " << max << ", requested: " << count;
throw rpc_error{ERROR_WRONG_PARAM, err.str()};
}
throw rpc_error{ERROR_WRONG_PARAM,
"Number of requested entries ({}) in {} is greater than the allowed limit ({})"_format(
count, container_name, max)};
}
template <typename T>
static void check_quantity_limit(std::optional<T> count, T max, const char* name = "input") {
if (count)
check_quantity_limit(*count, max, name);
}
//------------------------------------------------------------------------------------------------------------------------------
void core_rpc_server::invoke(GET_CHECKPOINTS& get_checkpoints, rpc_context context)
{
if (!context.admin)
check_quantity_limit(get_checkpoints.request.count, GET_CHECKPOINTS::MAX_COUNT);
auto& start = get_checkpoints.request.start_height;
auto& end = get_checkpoints.request.end_height;
auto count = get_checkpoints.request.count.value_or(GET_CHECKPOINTS::NUM_CHECKPOINTS_TO_QUERY_BY_DEFAULT);
get_checkpoints.response["status"] = STATUS_OK;
BlockchainDB const &db = m_core.get_blockchain_storage().get_db();
const auto& db = m_core.get_blockchain_storage().get_db();
std::vector<checkpoint_t> checkpoints;
if (get_checkpoints.request.start_height == GET_CHECKPOINTS::HEIGHT_SENTINEL_VALUE &&
get_checkpoints.request.end_height == GET_CHECKPOINTS::HEIGHT_SENTINEL_VALUE)
if (!start && !end)
{
checkpoint_t top_checkpoint;
if (db.get_top_checkpoint(top_checkpoint))
checkpoints = db.get_checkpoints_range(top_checkpoint.height, 0, get_checkpoints.request.count);
}
else if (get_checkpoints.request.start_height == GET_CHECKPOINTS::HEIGHT_SENTINEL_VALUE)
{
checkpoints = db.get_checkpoints_range(get_checkpoints.request.end_height, 0, get_checkpoints.request.count);
}
else if (get_checkpoints.request.end_height == GET_CHECKPOINTS::HEIGHT_SENTINEL_VALUE)
{
checkpoints = db.get_checkpoints_range(get_checkpoints.request.start_height, UINT64_MAX, get_checkpoints.request.count);
if (checkpoint_t top_checkpoint; db.get_top_checkpoint(top_checkpoint))
checkpoints = db.get_checkpoints_range(top_checkpoint.height, 0, count);
}
else if (!start)
checkpoints = db.get_checkpoints_range(*end, 0, count);
else if (!end)
checkpoints = db.get_checkpoints_range(*start, UINT64_MAX, count);
else
{
checkpoints = db.get_checkpoints_range(get_checkpoints.request.start_height, get_checkpoints.request.end_height);
}
checkpoints =
context.admin
? db.get_checkpoints_range(*start, *end)
: db.get_checkpoints_range(*start, *end, GET_CHECKPOINTS::MAX_COUNT);
get_checkpoints.response["checkpoints"] = checkpoints;
get_checkpoints.response["checkpoints"] = std::move(checkpoints);
return;
}

View File

@ -362,4 +362,34 @@ namespace cryptonote::rpc {
"entries", ons_owners_to_names.request.entries,
"include_expired", ons_owners_to_names.request.include_expired);
}
void parse_request(GET_QUORUM_STATE& qs, rpc_input in) {
get_values(in,
"end_height", qs.request.end_height,
"quorum_type", qs.request.quorum_type,
"start_height", qs.request.start_height);
if (qs.request.quorum_type) {
if (*qs.request.quorum_type == 255) // backwards-compat magic value
qs.request.quorum_type = std::nullopt;
else if (*qs.request.quorum_type > tools::enum_count<service_nodes::quorum_type>)
throw std::domain_error{
"Quorum type specifies an invalid value: "_format(*qs.request.quorum_type)};
}
}
void parse_request(GET_CHECKPOINTS& getcp, rpc_input in) {
get_values(in,
"count", getcp.request.count,
"end_height", getcp.request.end_height,
"start_height", getcp.request.start_height);
}
void parse_request(GET_SERVICE_NODE_REGISTRATION_CMD_RAW& cmd, rpc_input in) {
get_values(in,
"args", cmd.request.args,
"make_friendly", cmd.request.make_friendly,
"staking_requirement", cmd.request.staking_requirement);
}
}

View File

@ -20,12 +20,15 @@ namespace cryptonote::rpc {
void parse_request(GET_BLOCK_HEADERS_RANGE& get_block_headers_range, rpc_input in);
void parse_request(GET_BLOCK_HEADER_BY_HASH& get_block_header_by_hash, rpc_input in);
void parse_request(GET_BLOCK_HEADER_BY_HEIGHT& get_block_header_by_height, rpc_input in);
void parse_request(GET_CHECKPOINTS& getcp, rpc_input in);
void parse_request(GET_COINBASE_TX_SUM& get_coinbase_tx_sum, rpc_input in);
void parse_request(GET_QUORUM_STATE& get_quorum_state, rpc_input in);
void parse_request(GET_LAST_BLOCK_HEADER& get_last_block_header, rpc_input in);
void parse_request(GET_OUTPUTS& get_outputs, rpc_input in);
void parse_request(GET_OUTPUT_HISTOGRAM& get_output_histogram, rpc_input in);
void parse_request(GET_PEER_LIST& bh, rpc_input in);
void parse_request(GET_SERVICE_NODES& sns, rpc_input in);
void parse_request(GET_SERVICE_NODE_REGISTRATION_CMD_RAW& cmd, rpc_input in);
void parse_request(GET_SN_STATE_CHANGES& get_sn_state_changes, rpc_input in);
void parse_request(GET_STAKING_REQUIREMENT& get_staking_requirement, rpc_input in);
void parse_request(GET_TRANSACTIONS& get, rpc_input in);

View File

@ -1096,7 +1096,7 @@ namespace cryptonote::rpc {
///
/// - \p status General RPC status string. `"OK"` means everything looks good.
/// - \p bans List of banned nodes
struct GET_BANS : RPC_COMMAND
struct GET_BANS : NO_ARGS
{
static constexpr auto names() { return NAMES("get_bans"); }
};
@ -1298,7 +1298,7 @@ namespace cryptonote::rpc {
/// - \p difficulty The cumulative difficulty of all blocks in the alternative chain.
/// - \p block_hashes List containing hex block hashes
/// - \p main_chain_parent_block
struct GET_ALTERNATE_CHAINS : RPC_COMMAND
struct GET_ALTERNATE_CHAINS : NO_ARGS
{
static constexpr auto names() { return NAMES("get_alternative_chains"); }
@ -1481,13 +1481,11 @@ namespace cryptonote::rpc {
static constexpr auto names() { return NAMES("get_quorum_state"); }
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_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.
std::optional<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.
std::optional<uint64_t> end_height; // (Optional): End height, omit both start and end height to request the latest quorum
std::optional<uint8_t> quorum_type; // (Optional): Set value to request a specific quorum, 0 = Obligation, 1 = Checkpointing, 2 = Blink, 3 = Pulse, omitted or 255 = 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.
} request;
struct quorum_t
@ -1511,7 +1509,6 @@ namespace cryptonote::rpc {
///
/// Inputs:
///
/// - \p check Instead of running check if the blockchain has already been pruned.
/// - \p args (Developer) The list of arguments used in raw registration, i.e. portions
/// - \p make_friendly Provide information about how to use the command in the result.
/// - \p staking_requirement The staking requirement to become a Service Node the registration command will be generated upon
@ -1977,14 +1974,13 @@ namespace cryptonote::rpc {
{
static constexpr auto names() { return NAMES("get_checkpoints"); }
static constexpr size_t MAX_COUNT = 256;
static constexpr uint32_t MAX_COUNT = 256;
static constexpr uint32_t NUM_CHECKPOINTS_TO_QUERY_BY_DEFAULT = 60;
static constexpr uint64_t HEIGHT_SENTINEL_VALUE = std::numeric_limits<uint64_t>::max() - 1;
struct request_parameters
{
uint64_t start_height; // Optional: Get the first count checkpoints starting from this height. Specify both start and end to get the checkpoints inbetween.
uint64_t end_height; // Optional: Get the first count checkpoints before end height. Specify both start and end to get the checkpoints inbetween.
uint32_t count; // Optional: Number of checkpoints to query.
std::optional<uint64_t> start_height; // Optional: Get the first count checkpoints starting from this height. Specify both start and end to get the checkpoints inbetween.
std::optional<uint64_t> end_height; // Optional: Get the first count checkpoints before end height. Specify both start and end to get the checkpoints inbetween.
std::optional<uint32_t> count; // Optional: Number of checkpoints to query.
} request;
};