mirror of
https://github.com/oxen-io/oxen-core.git
synced 2023-12-14 02:22:56 +01:00
GET_CHECKPOINTS
This commit is contained in:
parent
95f6c02d55
commit
eedb23c545
14 changed files with 84 additions and 149 deletions
|
@ -39,6 +39,7 @@ target_link_libraries(blockchain_db
|
|||
lmdb
|
||||
filesystem
|
||||
Boost::thread
|
||||
nlohmann_json::nlohmann_json
|
||||
extra)
|
||||
|
||||
target_compile_definitions(blockchain_db PRIVATE
|
||||
|
|
|
@ -37,5 +37,6 @@ target_link_libraries(checkpoints
|
|||
cryptonote_basic
|
||||
Boost::program_options
|
||||
Boost::serialization
|
||||
nlohmann_json::nlohmann_json
|
||||
filesystem
|
||||
extra)
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include "epee/serialization/keyvalue_serialization.h"
|
||||
#include "cryptonote_core/service_node_rules.h"
|
||||
#include <vector>
|
||||
#include <nlohmann/json.hpp>
|
||||
#include "blockchain_db/blockchain_db.h"
|
||||
#include "cryptonote_basic/cryptonote_format_utils.h"
|
||||
|
||||
|
@ -54,7 +55,20 @@ namespace cryptonote
|
|||
if (result) MINFO ("CHECKPOINT PASSED FOR HEIGHT " << height << " " << block_hash);
|
||||
else MWARNING("CHECKPOINT FAILED FOR HEIGHT " << height << ". EXPECTED HASH " << block_hash << "GIVEN HASH: " << hash);
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
void to_json(nlohmann::json& j, const checkpoint_t& c)
|
||||
{
|
||||
j = nlohmann::json
|
||||
{
|
||||
{"version", c.version},
|
||||
{"type", c.type},
|
||||
{"height", c.height},
|
||||
{"block_hash", tools::type_to_hex(c.block_hash)},
|
||||
{"signatures", c.signatures},
|
||||
{"prev_height", c.prev_height},
|
||||
};
|
||||
};
|
||||
|
||||
height_to_hash const HARDCODED_MAINNET_CHECKPOINTS[] =
|
||||
{
|
||||
|
|
|
@ -79,6 +79,8 @@ namespace cryptonote
|
|||
FIELD(prev_height)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
void to_json(nlohmann::json& j, const checkpoint_t& c);
|
||||
|
||||
|
||||
struct height_to_hash
|
||||
{
|
||||
|
|
|
@ -44,4 +44,5 @@ target_link_libraries(cryptonote_basic
|
|||
Boost::program_options
|
||||
Boost::serialization
|
||||
filesystem
|
||||
nlohmann_json::nlohmann_json
|
||||
extra)
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#include "ringct/rctTypes.h"
|
||||
#include "device/device.hpp"
|
||||
#include "txtypes.h"
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
namespace service_nodes
|
||||
{
|
||||
|
@ -65,6 +66,15 @@ namespace service_nodes
|
|||
FIELD(signature)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
inline void to_json(nlohmann::json& j, const quorum_signature& s)
|
||||
{
|
||||
j = nlohmann::json
|
||||
{
|
||||
{"voter_index", s.voter_index},
|
||||
{"signature", tools::type_to_hex(s.signature)},
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
namespace cryptonote
|
||||
|
|
|
@ -259,58 +259,46 @@ json rpc_command_executor::invoke(
|
|||
|
||||
bool rpc_command_executor::print_checkpoints(uint64_t start_height, uint64_t end_height, bool print_json)
|
||||
{
|
||||
GET_CHECKPOINTS::request req{start_height, end_height};
|
||||
if (req.start_height == GET_CHECKPOINTS::HEIGHT_SENTINEL_VALUE &&
|
||||
req.end_height == GET_CHECKPOINTS::HEIGHT_SENTINEL_VALUE)
|
||||
|
||||
uint32_t count;
|
||||
if (start_height == GET_CHECKPOINTS::HEIGHT_SENTINEL_VALUE &&
|
||||
end_height == GET_CHECKPOINTS::HEIGHT_SENTINEL_VALUE)
|
||||
{
|
||||
req.count = GET_CHECKPOINTS::NUM_CHECKPOINTS_TO_QUERY_BY_DEFAULT;
|
||||
count = GET_CHECKPOINTS::NUM_CHECKPOINTS_TO_QUERY_BY_DEFAULT;
|
||||
}
|
||||
else if (req.start_height == GET_CHECKPOINTS::HEIGHT_SENTINEL_VALUE ||
|
||||
req.end_height == GET_CHECKPOINTS::HEIGHT_SENTINEL_VALUE)
|
||||
else if (start_height == GET_CHECKPOINTS::HEIGHT_SENTINEL_VALUE ||
|
||||
end_height == GET_CHECKPOINTS::HEIGHT_SENTINEL_VALUE)
|
||||
{
|
||||
req.count = 1;
|
||||
count = 1;
|
||||
}
|
||||
// Otherwise, neither heights are set to HEIGHT_SENTINEL_VALUE, so get all the checkpoints between start and end
|
||||
|
||||
GET_CHECKPOINTS::response res{};
|
||||
if (!invoke<GET_CHECKPOINTS>(std::move(req), res, "Failed to query blockchain checkpoints"))
|
||||
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)
|
||||
return false;
|
||||
|
||||
auto checkpoints = *maybe_checkpoints;
|
||||
|
||||
std::string entry;
|
||||
if (print_json) entry.append("{\n\"checkpoints\": [");
|
||||
for (size_t i = 0; i < res.checkpoints.size(); i++)
|
||||
{
|
||||
GET_CHECKPOINTS::checkpoint_serialized &checkpoint = res.checkpoints[i];
|
||||
if (print_json)
|
||||
{
|
||||
entry.append("\n");
|
||||
entry.append(epee::serialization::store_t_to_json(checkpoint));
|
||||
entry.append(",\n");
|
||||
}
|
||||
else
|
||||
if (print_json)
|
||||
entry.append(checkpoints.dump());
|
||||
else {
|
||||
for (size_t i = 0; i < checkpoints.size(); i++)
|
||||
{
|
||||
entry.append("[");
|
||||
entry.append(std::to_string(i));
|
||||
entry.append("]");
|
||||
|
||||
entry.append(" Type: ");
|
||||
entry.append(checkpoint.type);
|
||||
entry.append(checkpoints[i]["type"]);
|
||||
|
||||
entry.append(" Height: ");
|
||||
entry.append(std::to_string(checkpoint.height));
|
||||
entry.append(checkpoints[i]["height"]);
|
||||
|
||||
entry.append(" Hash: ");
|
||||
entry.append(checkpoint.block_hash);
|
||||
entry.append(checkpoints[i]["block_hash"]);
|
||||
entry.append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (print_json)
|
||||
{
|
||||
entry.append("]\n}");
|
||||
}
|
||||
else
|
||||
{
|
||||
if (entry.empty())
|
||||
entry.append("No Checkpoints");
|
||||
}
|
||||
|
|
|
@ -42,6 +42,7 @@ target_link_libraries(device
|
|||
Boost::serialization
|
||||
PRIVATE
|
||||
version
|
||||
nlohmann_json::nlohmann_json
|
||||
extra)
|
||||
|
||||
option(HWDEVICE_DEBUG "Enable hardware wallet debugging (requires also using a debug build of the Ledger wallet)" OFF)
|
||||
|
|
|
@ -35,4 +35,5 @@ target_link_libraries(multisig
|
|||
ringct
|
||||
cryptonote_basic
|
||||
common
|
||||
nlohmann_json::nlohmann_json
|
||||
extra)
|
||||
|
|
|
@ -40,6 +40,7 @@ target_link_libraries(ringct_basic
|
|||
PRIVATE
|
||||
OpenSSL::SSL
|
||||
OpenSSL::Crypto
|
||||
nlohmann_json::nlohmann_json
|
||||
extra)
|
||||
|
||||
add_library(ringct
|
||||
|
@ -53,4 +54,5 @@ target_link_libraries(ringct
|
|||
PRIVATE
|
||||
OpenSSL::SSL
|
||||
OpenSSL::Crypto
|
||||
nlohmann_json::nlohmann_json
|
||||
extra)
|
||||
|
|
|
@ -3078,45 +3078,38 @@ namespace cryptonote::rpc {
|
|||
}
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
GET_CHECKPOINTS::response core_rpc_server::invoke(GET_CHECKPOINTS::request&& req, rpc_context context)
|
||||
void core_rpc_server::invoke(GET_CHECKPOINTS& get_checkpoints, rpc_context context)
|
||||
{
|
||||
GET_CHECKPOINTS::response res{};
|
||||
|
||||
if (use_bootstrap_daemon_if_necessary<GET_CHECKPOINTS>(req, res))
|
||||
return res;
|
||||
|
||||
if (!context.admin)
|
||||
check_quantity_limit(req.count, GET_CHECKPOINTS::MAX_COUNT);
|
||||
check_quantity_limit(get_checkpoints.request.count, GET_CHECKPOINTS::MAX_COUNT);
|
||||
|
||||
res.status = STATUS_OK;
|
||||
get_checkpoints.response["status"] = STATUS_OK;
|
||||
BlockchainDB const &db = m_core.get_blockchain_storage().get_db();
|
||||
|
||||
std::vector<checkpoint_t> checkpoints;
|
||||
if (req.start_height == GET_CHECKPOINTS::HEIGHT_SENTINEL_VALUE &&
|
||||
req.end_height == GET_CHECKPOINTS::HEIGHT_SENTINEL_VALUE)
|
||||
if (get_checkpoints.request.start_height == GET_CHECKPOINTS::HEIGHT_SENTINEL_VALUE &&
|
||||
get_checkpoints.request.end_height == GET_CHECKPOINTS::HEIGHT_SENTINEL_VALUE)
|
||||
{
|
||||
checkpoint_t top_checkpoint;
|
||||
if (db.get_top_checkpoint(top_checkpoint))
|
||||
checkpoints = db.get_checkpoints_range(top_checkpoint.height, 0, req.count);
|
||||
checkpoints = db.get_checkpoints_range(top_checkpoint.height, 0, get_checkpoints.request.count);
|
||||
}
|
||||
else if (req.start_height == GET_CHECKPOINTS::HEIGHT_SENTINEL_VALUE)
|
||||
else if (get_checkpoints.request.start_height == GET_CHECKPOINTS::HEIGHT_SENTINEL_VALUE)
|
||||
{
|
||||
checkpoints = db.get_checkpoints_range(req.end_height, 0, req.count);
|
||||
checkpoints = db.get_checkpoints_range(get_checkpoints.request.end_height, 0, get_checkpoints.request.count);
|
||||
}
|
||||
else if (req.end_height == GET_CHECKPOINTS::HEIGHT_SENTINEL_VALUE)
|
||||
else if (get_checkpoints.request.end_height == GET_CHECKPOINTS::HEIGHT_SENTINEL_VALUE)
|
||||
{
|
||||
checkpoints = db.get_checkpoints_range(req.start_height, UINT64_MAX, req.count);
|
||||
checkpoints = db.get_checkpoints_range(get_checkpoints.request.start_height, UINT64_MAX, get_checkpoints.request.count);
|
||||
}
|
||||
else
|
||||
{
|
||||
checkpoints = db.get_checkpoints_range(req.start_height, req.end_height);
|
||||
checkpoints = db.get_checkpoints_range(get_checkpoints.request.start_height, get_checkpoints.request.end_height);
|
||||
}
|
||||
|
||||
res.checkpoints.reserve(checkpoints.size());
|
||||
for (checkpoint_t const &checkpoint : checkpoints)
|
||||
res.checkpoints.push_back(checkpoint);
|
||||
get_checkpoints.response["checkpoints"] = checkpoints;
|
||||
|
||||
return res;
|
||||
return;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
void core_rpc_server::invoke(GET_SN_STATE_CHANGES& get_sn_state_changes, rpc_context context)
|
||||
|
|
|
@ -248,6 +248,7 @@ namespace cryptonote::rpc {
|
|||
void invoke(GET_BLOCK_HEADER_BY_HASH& get_block_header_by_hash, rpc_context context);
|
||||
void invoke(GETBANS& get_bans, rpc_context context);
|
||||
void invoke(SETBANS& set_bans, rpc_context context);
|
||||
void invoke(GET_CHECKPOINTS& get_checkpoints, 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);
|
||||
|
@ -276,7 +277,6 @@ namespace cryptonote::rpc {
|
|||
GET_SERVICE_KEYS::response invoke(GET_SERVICE_KEYS::request&& req, rpc_context context);
|
||||
GET_SERVICE_PRIVKEYS::response invoke(GET_SERVICE_PRIVKEYS::request&& req, rpc_context context);
|
||||
GET_STAKING_REQUIREMENT::response invoke(GET_STAKING_REQUIREMENT::request&& req, rpc_context context);
|
||||
GET_CHECKPOINTS::response invoke(GET_CHECKPOINTS::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);
|
||||
|
||||
|
|
|
@ -66,7 +66,8 @@ void from_json(const nlohmann::json& j, block_header_response& h)
|
|||
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)
|
||||
|
@ -163,6 +164,7 @@ KV_SERIALIZE_MAP_CODE_BEGIN(GET_OUTPUT_HISTOGRAM::request)
|
|||
KV_SERIALIZE(recent_cutoff);
|
||||
KV_SERIALIZE_MAP_CODE_END()
|
||||
|
||||
|
||||
KV_SERIALIZE_MAP_CODE_BEGIN(GET_OUTPUT_HISTOGRAM::entry)
|
||||
KV_SERIALIZE(amount);
|
||||
KV_SERIALIZE(total_instances);
|
||||
|
@ -370,36 +372,6 @@ KV_SERIALIZE_MAP_CODE_BEGIN(GET_SERVICE_NODE_BLACKLISTED_KEY_IMAGES::response)
|
|||
KV_SERIALIZE_MAP_CODE_END()
|
||||
|
||||
|
||||
KV_SERIALIZE_MAP_CODE_BEGIN(GET_CHECKPOINTS::request)
|
||||
KV_SERIALIZE_OPT(start_height, HEIGHT_SENTINEL_VALUE)
|
||||
KV_SERIALIZE_OPT(end_height, HEIGHT_SENTINEL_VALUE)
|
||||
KV_SERIALIZE_OPT(count, NUM_CHECKPOINTS_TO_QUERY_BY_DEFAULT)
|
||||
KV_SERIALIZE_MAP_CODE_END()
|
||||
|
||||
|
||||
KV_SERIALIZE_MAP_CODE_BEGIN(GET_CHECKPOINTS::quorum_signature_serialized)
|
||||
KV_SERIALIZE(voter_index);
|
||||
KV_SERIALIZE(signature);
|
||||
KV_SERIALIZE_MAP_CODE_END()
|
||||
|
||||
|
||||
KV_SERIALIZE_MAP_CODE_BEGIN(GET_CHECKPOINTS::checkpoint_serialized)
|
||||
KV_SERIALIZE(version);
|
||||
KV_SERIALIZE(type);
|
||||
KV_SERIALIZE(height);
|
||||
KV_SERIALIZE(block_hash);
|
||||
KV_SERIALIZE(signatures);
|
||||
KV_SERIALIZE(prev_height);
|
||||
KV_SERIALIZE_MAP_CODE_END()
|
||||
|
||||
|
||||
KV_SERIALIZE_MAP_CODE_BEGIN(GET_CHECKPOINTS::response)
|
||||
KV_SERIALIZE(checkpoints)
|
||||
KV_SERIALIZE(status)
|
||||
KV_SERIALIZE(untrusted)
|
||||
KV_SERIALIZE_MAP_CODE_END()
|
||||
|
||||
|
||||
KV_SERIALIZE_MAP_CODE_BEGIN(ONS_NAMES_TO_OWNERS::request_entry)
|
||||
KV_SERIALIZE(name_hash)
|
||||
KV_SERIALIZE(types)
|
||||
|
|
|
@ -2102,8 +2102,18 @@ namespace cryptonote::rpc {
|
|||
};
|
||||
};
|
||||
|
||||
OXEN_RPC_DOC_INTROSPECT
|
||||
// Query hardcoded/service node checkpoints stored for the blockchain. Omit all arguments to retrieve the latest "count" checkpoints.
|
||||
/// Query hardcoded/service node checkpoints stored for the blockchain. Omit all arguments to retrieve the latest "count" checkpoints.
|
||||
///
|
||||
/// Inputs:
|
||||
///
|
||||
/// - \p start_height Optional: Get the first count checkpoints starting from this height. Specify both start and end to get the checkpoints inbetween.
|
||||
/// - \p end_height Optional: Get the first count checkpoints before end height. Specify both start and end to get the checkpoints inbetween.
|
||||
/// - \p count Optional: Number of checkpoints to query.
|
||||
///
|
||||
/// Output values available from a public RPC endpoint:
|
||||
///
|
||||
/// - \p status generic RPC error code; "OK" means the request was successful.
|
||||
/// - \p checkpoints Array of requested checkpoints
|
||||
struct GET_CHECKPOINTS : PUBLIC
|
||||
{
|
||||
static constexpr auto names() { return NAMES("get_checkpoints"); }
|
||||
|
@ -2111,75 +2121,14 @@ namespace cryptonote::rpc {
|
|||
static constexpr size_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
|
||||
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.
|
||||
} request;
|
||||
|
||||
KV_MAP_SERIALIZABLE
|
||||
};
|
||||
|
||||
struct quorum_signature_serialized
|
||||
{
|
||||
uint16_t voter_index; // Index of the voter in the relevant quorum
|
||||
std::string signature; // The signature generated by the voter in the quorum
|
||||
|
||||
quorum_signature_serialized() = default;
|
||||
quorum_signature_serialized(service_nodes::quorum_signature const &entry)
|
||||
: voter_index(entry.voter_index)
|
||||
, signature(tools::type_to_hex(entry.signature)) { }
|
||||
|
||||
KV_MAP_SERIALIZABLE
|
||||
|
||||
BEGIN_SERIALIZE() // NOTE: For store_t_to_json
|
||||
FIELD(voter_index)
|
||||
FIELD(signature)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct checkpoint_serialized
|
||||
{
|
||||
uint8_t version;
|
||||
std::string type; // Either "Hardcoded" or "ServiceNode" for checkpoints generated by Service Nodes or declared in the code
|
||||
uint64_t height; // The height the checkpoint is relevant for
|
||||
std::string block_hash; // The block hash the checkpoint is specifying
|
||||
std::vector<quorum_signature_serialized> signatures; // Signatures from Service Nodes who agree on the block hash
|
||||
uint64_t prev_height; // The previous height the checkpoint is based off
|
||||
|
||||
checkpoint_serialized() = default;
|
||||
checkpoint_serialized(checkpoint_t const &checkpoint)
|
||||
: version(checkpoint.version)
|
||||
, type(checkpoint_t::type_to_string(checkpoint.type))
|
||||
, height(checkpoint.height)
|
||||
, block_hash(tools::type_to_hex(checkpoint.block_hash))
|
||||
, prev_height(checkpoint.prev_height)
|
||||
{
|
||||
signatures.reserve(checkpoint.signatures.size());
|
||||
for (service_nodes::quorum_signature const &entry : checkpoint.signatures)
|
||||
signatures.push_back(entry);
|
||||
}
|
||||
|
||||
KV_MAP_SERIALIZABLE
|
||||
|
||||
BEGIN_SERIALIZE() // NOTE: For store_t_to_json
|
||||
FIELD(version)
|
||||
FIELD(type)
|
||||
FIELD(height)
|
||||
FIELD(block_hash)
|
||||
FIELD(signatures)
|
||||
FIELD(prev_height)
|
||||
END_SERIALIZE()
|
||||
};
|
||||
|
||||
struct response
|
||||
{
|
||||
std::vector<checkpoint_serialized> checkpoints; // Array of requested checkpoints
|
||||
std::string status; // Generic RPC error code. "OK" is the success value.
|
||||
bool untrusted; // If the result is obtained using bootstrap mode, and therefore not trusted `true`, or otherwise `false`.
|
||||
|
||||
KV_MAP_SERIALIZABLE
|
||||
};
|
||||
};
|
||||
|
||||
/// Query hardcoded/service node checkpoints stored for the blockchain. Omit all arguments to
|
||||
|
|
Loading…
Reference in a new issue