mirror of
https://github.com/oxen-io/oxen-core.git
synced 2023-12-14 02:22:56 +01:00
Merge pull request #1370 from darcys22/1366-uptime-proof-version-details
Uptime proof version details + bt-encoded proofs
This commit is contained in:
commit
4c1d03576e
53 changed files with 708 additions and 96 deletions
|
@ -33,6 +33,8 @@
|
|||
#include <boost/endian/conversion.hpp>
|
||||
#include <memory>
|
||||
#include <cstring>
|
||||
#include <type_traits>
|
||||
#include <variant>
|
||||
|
||||
#include "epee/string_tools.h"
|
||||
#include "common/file.h"
|
||||
|
@ -46,6 +48,7 @@
|
|||
#include "checkpoints/checkpoints.h"
|
||||
#include "cryptonote_core/service_node_rules.h"
|
||||
#include "cryptonote_core/service_node_list.h"
|
||||
#include "cryptonote_core/uptime_proof.h"
|
||||
#include "cryptonote_basic/hardfork.h"
|
||||
|
||||
#undef OXEN_DEFAULT_LOG_CATEGORY
|
||||
|
@ -269,8 +272,15 @@ void lmdb_db_open(MDB_txn* txn, const char* name, int flags, MDB_dbi& dbi, const
|
|||
throw0(cryptonote::DB_OPEN_FAILURE((lmdb_error(error_string + " : ", res) + std::string(" - you may want to start with --db-salvage")).c_str()));
|
||||
}
|
||||
|
||||
template <typename T, typename...>
|
||||
struct first_type { using type = T; };
|
||||
template <typename... T>
|
||||
using first_type_t = typename first_type<T...>::type;
|
||||
|
||||
// Lets you iterator over all the pairs of K/V pairs in a database
|
||||
template <typename K, typename V>
|
||||
// If multiple V are provided then value will be a variant<V1*, V2*, ...> with the populated pointer
|
||||
// matched by size of the record.
|
||||
template <typename K, typename... V>
|
||||
class iterable_db {
|
||||
private:
|
||||
MDB_cursor* cursor;
|
||||
|
@ -281,13 +291,13 @@ public:
|
|||
|
||||
class iterator {
|
||||
public:
|
||||
using value_type = std::pair<K*, V*>;
|
||||
using value_type = std::pair<K*, std::conditional_t<sizeof...(V) == 1, first_type_t<V...>*, std::variant<V*...>>>;
|
||||
using reference = value_type&;
|
||||
using pointer = value_type*;
|
||||
using difference_type = ptrdiff_t;
|
||||
using iterator_category = std::input_iterator_tag;
|
||||
|
||||
constexpr iterator() : element{nullptr, nullptr} {}
|
||||
constexpr iterator() : element{} {}
|
||||
iterator(MDB_cursor* c, MDB_cursor_op op_start, MDB_cursor_op op_incr) : cursor{c}, op_incr{op_incr} {
|
||||
next(op_start);
|
||||
}
|
||||
|
@ -302,14 +312,29 @@ public:
|
|||
bool operator!=(const iterator& i) const { return !(*this == i); }
|
||||
|
||||
private:
|
||||
template <typename T, typename... More>
|
||||
void load_variant() {
|
||||
if (v.mv_size == sizeof(T))
|
||||
element.second = static_cast<T*>(v.mv_data);
|
||||
else if constexpr (sizeof...(More))
|
||||
load_variant<More...>();
|
||||
else {
|
||||
MWARNING("Invalid stored type size in iterable_db: stored size (" << v.mv_size <<
|
||||
") matched none of " << tools::type_name<value_type>());
|
||||
var::get<0>(element.second) = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void next(MDB_cursor_op op) {
|
||||
int result = mdb_cursor_get(cursor, &k, &v, op);
|
||||
if (result == MDB_NOTFOUND) {
|
||||
element.first = nullptr;
|
||||
element.second = nullptr;
|
||||
element = {};
|
||||
} else if (result == MDB_SUCCESS) {
|
||||
element.first = static_cast<K*>(k.mv_data);
|
||||
element.second = static_cast<V*>(v.mv_data);
|
||||
if constexpr (sizeof...(V) == 1)
|
||||
element.second = static_cast<typename value_type::second_type*>(v.mv_data);
|
||||
else
|
||||
load_variant<V...>();
|
||||
} else {
|
||||
throw0(cryptonote::DB_ERROR(lmdb_error("enumeration failed: ", result)));
|
||||
}
|
||||
|
@ -318,7 +343,7 @@ public:
|
|||
MDB_cursor* cursor = nullptr;
|
||||
const MDB_cursor_op op_incr = MDB_NEXT;
|
||||
MDB_val k, v;
|
||||
std::pair<K*, V*> element;
|
||||
value_type element;
|
||||
};
|
||||
|
||||
iterator begin() { return {cursor, op_start, op_incr}; }
|
||||
|
@ -6240,31 +6265,47 @@ void BlockchainLMDB::clear_service_node_data()
|
|||
}
|
||||
}
|
||||
|
||||
struct service_node_proof_serialized
|
||||
template <typename C>
|
||||
C native_to_little_container(const C& c) {
|
||||
C result{c};
|
||||
for (auto& x : result) native_to_little_inplace(x);
|
||||
return result;
|
||||
}
|
||||
template <typename C>
|
||||
C little_to_native_container(const C& c) {
|
||||
C result{c};
|
||||
for (auto& x : result) little_to_native_inplace(x);
|
||||
return result;
|
||||
}
|
||||
|
||||
struct service_node_proof_serialized_old
|
||||
{
|
||||
service_node_proof_serialized() = default;
|
||||
service_node_proof_serialized(const service_nodes::proof_info &info)
|
||||
: timestamp{native_to_little(info.timestamp)},
|
||||
ip{native_to_little(info.public_ip)},
|
||||
storage_port{native_to_little(info.storage_port)},
|
||||
storage_lmq_port{native_to_little(info.storage_lmq_port)},
|
||||
quorumnet_port{native_to_little(info.quorumnet_port)},
|
||||
version{native_to_little(info.version[0]), native_to_little(info.version[1]), native_to_little(info.version[2])},
|
||||
pubkey_ed25519{info.pubkey_ed25519}
|
||||
service_node_proof_serialized_old() = default;
|
||||
service_node_proof_serialized_old(const service_nodes::proof_info &info)
|
||||
: timestamp{native_to_little(info.proof->timestamp)},
|
||||
ip{native_to_little(info.proof->public_ip)},
|
||||
storage_port{native_to_little(info.proof->storage_port)},
|
||||
storage_lmq_port{native_to_little(info.proof->storage_lmq_port)},
|
||||
quorumnet_port{native_to_little(info.proof->qnet_port)},
|
||||
version{native_to_little_container(info.proof->version)},
|
||||
pubkey_ed25519{info.proof->pubkey_ed25519}
|
||||
{}
|
||||
|
||||
void update(service_nodes::proof_info &info) const
|
||||
{
|
||||
info.timestamp = little_to_native(timestamp);
|
||||
if (info.timestamp > info.effective_timestamp)
|
||||
info.effective_timestamp = info.timestamp;
|
||||
info.public_ip = little_to_native(ip);
|
||||
info.storage_port = little_to_native(storage_port);
|
||||
info.storage_lmq_port = little_to_native(storage_lmq_port);
|
||||
info.quorumnet_port = little_to_native(quorumnet_port);
|
||||
for (size_t i = 0; i < info.version.size(); i++)
|
||||
info.version[i] = little_to_native(version[i]);
|
||||
info.proof->timestamp = little_to_native(timestamp);
|
||||
if (info.proof->timestamp > info.effective_timestamp)
|
||||
info.effective_timestamp = info.proof->timestamp;
|
||||
info.proof->public_ip = little_to_native(ip);
|
||||
info.proof->storage_port = little_to_native(storage_port);
|
||||
info.proof->storage_lmq_port = little_to_native(storage_lmq_port);
|
||||
info.proof->qnet_port = little_to_native(quorumnet_port);
|
||||
info.proof->version = little_to_native_container(version);
|
||||
info.proof->storage_server_version = {0, 0, 0};
|
||||
info.proof->lokinet_version = {0, 0, 0};
|
||||
info.update_pubkey(pubkey_ed25519);
|
||||
}
|
||||
|
||||
operator service_nodes::proof_info() const
|
||||
{
|
||||
service_nodes::proof_info info{};
|
||||
|
@ -6276,11 +6317,39 @@ struct service_node_proof_serialized
|
|||
uint32_t ip;
|
||||
uint16_t storage_port;
|
||||
uint16_t quorumnet_port;
|
||||
uint16_t version[3];
|
||||
std::array<uint16_t, 3> version;
|
||||
uint16_t storage_lmq_port;
|
||||
crypto::ed25519_public_key pubkey_ed25519;
|
||||
};
|
||||
static_assert(sizeof(service_node_proof_serialized) == 56, "service node serialization struct has unexpected size and/or padding");
|
||||
static_assert(sizeof(service_node_proof_serialized_old) == 56, "service node serialization struct has unexpected size and/or padding");
|
||||
|
||||
struct service_node_proof_serialized : service_node_proof_serialized_old {
|
||||
service_node_proof_serialized() = default;
|
||||
service_node_proof_serialized(const service_nodes::proof_info &info)
|
||||
: service_node_proof_serialized_old{info},
|
||||
storage_server_version{native_to_little_container(info.proof->storage_server_version)},
|
||||
lokinet_version{native_to_little_container(info.proof->lokinet_version)}
|
||||
{}
|
||||
std::array<uint16_t, 3> storage_server_version;
|
||||
std::array<uint16_t, 3> lokinet_version;
|
||||
char _padding[4];
|
||||
|
||||
void update(service_nodes::proof_info& info) const {
|
||||
if (!info.proof) info.proof = std::unique_ptr<uptime_proof::Proof>(new uptime_proof::Proof());
|
||||
service_node_proof_serialized_old::update(info);
|
||||
info.proof->storage_server_version = little_to_native_container(storage_server_version);
|
||||
info.proof->lokinet_version = little_to_native_container(lokinet_version);
|
||||
}
|
||||
|
||||
operator service_nodes::proof_info() const
|
||||
{
|
||||
service_nodes::proof_info info{};
|
||||
update(info);
|
||||
return info;
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(sizeof(service_node_proof_serialized) == 72, "service node serialization struct has unexpected size and/or padding");
|
||||
|
||||
bool BlockchainLMDB::get_service_node_proof(const crypto::public_key &pubkey, service_nodes::proof_info &proof) const
|
||||
{
|
||||
|
@ -6298,7 +6367,11 @@ bool BlockchainLMDB::get_service_node_proof(const crypto::public_key &pubkey, se
|
|||
else if (result != MDB_SUCCESS)
|
||||
throw0(DB_ERROR(lmdb_error("DB error attempting to get service node data", result)));
|
||||
|
||||
static_cast<const service_node_proof_serialized *>(v.mv_data)->update(proof);
|
||||
if (v.mv_size == sizeof(service_node_proof_serialized_old))
|
||||
static_cast<const service_node_proof_serialized_old*>(v.mv_data)->update(proof);
|
||||
else
|
||||
static_cast<const service_node_proof_serialized*>(v.mv_data)->update(proof);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -6328,8 +6401,13 @@ std::unordered_map<crypto::public_key, service_nodes::proof_info> BlockchainLMDB
|
|||
RCURSOR(service_node_proofs);
|
||||
|
||||
std::unordered_map<crypto::public_key, service_nodes::proof_info> result;
|
||||
for (const auto &pair : iterable_db<crypto::public_key, service_node_proof_serialized>(m_cursors->service_node_proofs))
|
||||
result.emplace(*pair.first, *pair.second);
|
||||
for (const auto &pair : iterable_db<crypto::public_key, service_node_proof_serialized, service_node_proof_serialized_old>(
|
||||
m_cursors->service_node_proofs)) {
|
||||
if (std::holds_alternative<service_node_proof_serialized*>(pair.second))
|
||||
result.emplace(*pair.first, *var::get<service_node_proof_serialized*>(pair.second));
|
||||
else
|
||||
result.emplace(*pair.first, service_node_proof_serialized{*var::get<service_node_proof_serialized_old*>(pair.second)});
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#include "blockchain_objects.h"
|
||||
#include "blockchain_db/blockchain_db.h"
|
||||
#include "version.h"
|
||||
#include "cryptonote_core/uptime_proof.h"
|
||||
|
||||
#undef OXEN_DEFAULT_LOG_CATEGORY
|
||||
#define OXEN_DEFAULT_LOG_CATEGORY "bcutil"
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#include "blockchain_db/blockchain_db.h"
|
||||
#include "wallet/ringdb.h"
|
||||
#include "version.h"
|
||||
#include "cryptonote_core/uptime_proof.h"
|
||||
|
||||
#undef OXEN_DEFAULT_LOG_CATEGORY
|
||||
#define OXEN_DEFAULT_LOG_CATEGORY "bcutil"
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "cryptonote_core/cryptonote_core.h"
|
||||
#include "blockchain_objects.h"
|
||||
#include "blockchain_db/blockchain_db.h"
|
||||
#include "cryptonote_core/uptime_proof.h"
|
||||
#include "version.h"
|
||||
|
||||
#undef OXEN_DEFAULT_LOG_CATEGORY
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "cryptonote_core/cryptonote_core.h"
|
||||
#include "blockchain_objects.h"
|
||||
#include "version.h"
|
||||
#include "cryptonote_core/uptime_proof.h"
|
||||
|
||||
#undef OXEN_DEFAULT_LOG_CATEGORY
|
||||
#define OXEN_DEFAULT_LOG_CATEGORY "bcutil"
|
||||
|
|
|
@ -41,6 +41,7 @@
|
|||
#include "blocks/blocks.h"
|
||||
#include "cryptonote_basic/cryptonote_format_utils.h"
|
||||
#include "serialization/binary_utils.h"
|
||||
#include "cryptonote_core/uptime_proof.h"
|
||||
#include "cryptonote_core/cryptonote_core.h"
|
||||
#include "common/hex.h"
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@
|
|||
#include "blockchain_db/blockchain_db.h"
|
||||
#include "version.h"
|
||||
#include "epee/misc_os_dependent.h"
|
||||
#include "cryptonote_core/uptime_proof.h"
|
||||
|
||||
#undef OXEN_DEFAULT_LOG_CATEGORY
|
||||
#define OXEN_DEFAULT_LOG_CATEGORY "bcutil"
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "cryptonote_core/cryptonote_core.h"
|
||||
#include "blockchain_objects.h"
|
||||
#include "blockchain_db/blockchain_db.h"
|
||||
#include "cryptonote_core/uptime_proof.h"
|
||||
#include "version.h"
|
||||
|
||||
#undef OXEN_DEFAULT_LOG_CATEGORY
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
#include <charconv>
|
||||
#include <sstream>
|
||||
|
@ -109,6 +110,19 @@ std::string copy_guts(const T& val) {
|
|||
return std::string{view_guts(val)};
|
||||
}
|
||||
|
||||
/// Function to reverse the above view_guts
|
||||
template <typename T>
|
||||
T make_from_guts(std::string_view s) {
|
||||
static_assert((std::is_standard_layout_v<T> && std::has_unique_object_representations_v<T>)
|
||||
|| epee::is_byte_spannable<T>,
|
||||
"cannot safely reconstitute a non-trivial class from data");
|
||||
if (s.size() != sizeof(T))
|
||||
throw std::runtime_error("Cannot reconstitute type: wrong type content size");
|
||||
T x;
|
||||
std::memcpy(&x, s.data(), sizeof(T));
|
||||
return x;
|
||||
}
|
||||
|
||||
std::string lowercase_ascii_string(std::string_view src);
|
||||
|
||||
/// Converts a duration into a human friendlier string.
|
||||
|
|
|
@ -194,6 +194,7 @@ constexpr uint64_t BLOCKS_EXPECTED_IN_YEARS(int years) { return BLOCKS_EXPECTED_
|
|||
#define HF_VERSION_EFFECTIVE_SHORT_TERM_MEDIAN_IN_PENALTY cryptonote::network_version_16_pulse
|
||||
#define HF_VERSION_PULSE cryptonote::network_version_16_pulse
|
||||
#define HF_VERSION_CLSAG cryptonote::network_version_16_pulse
|
||||
#define HF_VERSION_PROOF_BTENC cryptonote::network_version_17
|
||||
|
||||
#define PER_KB_FEE_QUANTIZATION_DECIMALS 8
|
||||
|
||||
|
|
|
@ -40,7 +40,8 @@ add_library(cryptonote_core
|
|||
tx_pool.cpp
|
||||
tx_sanity_check.cpp
|
||||
cryptonote_tx_utils.cpp
|
||||
pulse.cpp)
|
||||
pulse.cpp
|
||||
uptime_proof.cpp)
|
||||
|
||||
target_link_libraries(cryptonote_core
|
||||
PUBLIC
|
||||
|
|
|
@ -49,6 +49,7 @@ extern "C" {
|
|||
#include <sqlite3.h>
|
||||
|
||||
#include "cryptonote_core.h"
|
||||
#include "uptime_proof.h"
|
||||
#include "common/file.h"
|
||||
#include "common/sha256sum.h"
|
||||
#include "common/threadpool.h"
|
||||
|
@ -1670,7 +1671,7 @@ namespace cryptonote
|
|||
std::array<uint16_t,3> proofversion;
|
||||
m_service_node_list.access_proof(pubkey, [&](auto &proof) {
|
||||
x_pkey = proof.pubkey_x25519;
|
||||
proofversion = proof.version;
|
||||
proofversion = proof.proof->version;
|
||||
});
|
||||
|
||||
if (proofversion >= MIN_TIMESTAMP_VERSION && x_pkey) {
|
||||
|
@ -1930,10 +1931,19 @@ namespace cryptonote
|
|||
if (!m_service_node)
|
||||
return true;
|
||||
|
||||
NOTIFY_UPTIME_PROOF::request req = m_service_node_list.generate_uptime_proof(m_sn_public_ip, m_storage_port, m_storage_lmq_port, m_quorumnet_port);
|
||||
|
||||
cryptonote_connection_context fake_context{};
|
||||
bool relayed = get_protocol()->relay_uptime_proof(req, fake_context);
|
||||
bool relayed;
|
||||
auto height = get_current_blockchain_height();
|
||||
auto hf_version = get_hard_fork_version(height);
|
||||
//TODO: remove after HF17
|
||||
if (hf_version < HF_VERSION_PROOF_BTENC) {
|
||||
NOTIFY_UPTIME_PROOF::request req = m_service_node_list.generate_uptime_proof(m_sn_public_ip, m_storage_port, m_storage_lmq_port, m_quorumnet_port);
|
||||
relayed = get_protocol()->relay_uptime_proof(req, fake_context);
|
||||
} else {
|
||||
auto proof = m_service_node_list.generate_uptime_proof(m_sn_public_ip, m_storage_port, m_storage_lmq_port, ss_version, m_quorumnet_port, lokinet_version);
|
||||
NOTIFY_BTENCODED_UPTIME_PROOF::request req = proof.generate_request();
|
||||
relayed = get_protocol()->relay_btencoded_uptime_proof(req, fake_context);
|
||||
}
|
||||
if (relayed)
|
||||
MGINFO("Submitted uptime-proof for Service Node (yours): " << m_service_keys.pub);
|
||||
|
||||
|
@ -1953,6 +1963,23 @@ namespace cryptonote
|
|||
return result;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
bool core::handle_btencoded_uptime_proof(const NOTIFY_BTENCODED_UPTIME_PROOF::request &req, bool &my_uptime_proof_confirmation)
|
||||
{
|
||||
crypto::x25519_public_key pkey = {};
|
||||
auto proof = std::make_unique<uptime_proof::Proof>(req.proof);
|
||||
proof->sig = tools::make_from_guts<crypto::signature>(req.sig);
|
||||
proof->sig_ed25519 = tools::make_from_guts<crypto::ed25519_signature>(req.ed_sig);
|
||||
auto pubkey = proof->pubkey;
|
||||
bool result = m_service_node_list.handle_btencoded_uptime_proof(std::move(proof), my_uptime_proof_confirmation, pkey);
|
||||
if (result && m_service_node_list.is_service_node(pubkey, true /*require_active*/) && pkey)
|
||||
{
|
||||
oxenmq::pubkey_set added;
|
||||
added.insert(tools::copy_guts(pkey));
|
||||
m_lmq->update_active_sns(added, {} /*removed*/);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
//-----------------------------------------------------------------------------------------------
|
||||
crypto::hash core::on_transaction_relayed(const cryptonote::blobdata& tx_blob)
|
||||
{
|
||||
std::vector<std::pair<crypto::hash, cryptonote::blobdata>> txs;
|
||||
|
@ -2301,12 +2328,12 @@ namespace cryptonote
|
|||
sn_pks.push_back(sni.pubkey);
|
||||
|
||||
m_service_node_list.for_each_service_node_info_and_proof(sn_pks.begin(), sn_pks.end(), [&](auto& pk, auto& sni, auto& proof) {
|
||||
if (pk != m_service_keys.pub && proof.public_ip == m_sn_public_ip &&
|
||||
(proof.quorumnet_port == m_quorumnet_port || proof.storage_port == m_storage_port || proof.storage_port == m_storage_lmq_port))
|
||||
if (pk != m_service_keys.pub && proof.proof->public_ip == m_sn_public_ip &&
|
||||
(proof.proof->qnet_port == m_quorumnet_port || proof.proof->storage_port == m_storage_port || proof.proof->storage_port == m_storage_lmq_port))
|
||||
MGINFO_RED(
|
||||
"Another service node (" << pk << ") is broadcasting the same public IP and ports as this service node (" <<
|
||||
epee::string_tools::get_ip_string_from_int32(m_sn_public_ip) << ":" << proof.quorumnet_port << "[qnet], :" <<
|
||||
proof.storage_port << "[SS-HTTP], :" << proof.storage_lmq_port << "[SS-LMQ]). "
|
||||
epee::string_tools::get_ip_string_from_int32(m_sn_public_ip) << ":" << proof.proof->qnet_port << "[qnet], :" <<
|
||||
proof.proof->storage_port << "[SS-HTTP], :" << proof.proof->storage_lmq_port << "[SS-LMQ]). "
|
||||
"This will lead to deregistration of one or both service nodes if not corrected. "
|
||||
"(Do both service nodes have the correct IP for the service-node-public-ip setting?)");
|
||||
});
|
||||
|
|
|
@ -159,6 +159,15 @@ namespace cryptonote
|
|||
*/
|
||||
bool handle_uptime_proof(const NOTIFY_UPTIME_PROOF::request &proof, bool &my_uptime_proof_confirmation);
|
||||
|
||||
/**
|
||||
* @brief handles an incoming uptime proof that is encoded using B-encoding
|
||||
*
|
||||
* Parses an incoming uptime proof
|
||||
*
|
||||
* @return true if we haven't seen it before and thus need to relay.
|
||||
*/
|
||||
bool handle_btencoded_uptime_proof(const NOTIFY_BTENCODED_UPTIME_PROOF::request &proof, bool &my_uptime_proof_confirmation);
|
||||
|
||||
/**
|
||||
* @brief handles an incoming transaction
|
||||
*
|
||||
|
@ -1163,6 +1172,10 @@ namespace cryptonote
|
|||
std::unordered_map<crypto::x25519_public_key, oxenmq::AuthLevel>& _lmq_auth_level_map() { return m_lmq_auth; }
|
||||
oxenmq::TaggedThreadID const &pulse_thread_id() const { return *m_pulse_thread_id; }
|
||||
|
||||
/// Service Node's storage server and lokinet version
|
||||
std::array<uint16_t, 3> ss_version;
|
||||
std::array<uint16_t, 3> lokinet_version;
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
|
|
|
@ -43,6 +43,7 @@ extern "C" {
|
|||
#include "cryptonote_tx_utils.h"
|
||||
#include "cryptonote_basic/tx_extra.h"
|
||||
#include "cryptonote_basic/hardfork.h"
|
||||
#include "cryptonote_core/uptime_proof.h"
|
||||
#include "epee/int-util.h"
|
||||
#include "common/scoped_message_writer.h"
|
||||
#include "common/i18n.h"
|
||||
|
@ -56,8 +57,10 @@ extern "C" {
|
|||
|
||||
#include "pulse.h"
|
||||
#include "service_node_list.h"
|
||||
#include "uptime_proof.h"
|
||||
#include "service_node_rules.h"
|
||||
#include "service_node_swarm.h"
|
||||
#include <lokimq/bt_serialize.h>
|
||||
#include "version.h"
|
||||
|
||||
#undef OXEN_DEFAULT_LOG_CATEGORY
|
||||
|
@ -2743,15 +2746,14 @@ namespace service_nodes
|
|||
return true;
|
||||
}
|
||||
|
||||
static crypto::hash hash_uptime_proof(const cryptonote::NOTIFY_UPTIME_PROOF::request &proof, uint8_t hf_version)
|
||||
//TODO: remove after HF17
|
||||
crypto::hash service_node_list::hash_uptime_proof(const cryptonote::NOTIFY_UPTIME_PROOF::request &proof) const
|
||||
{
|
||||
auto buf = tools::memcpy_le(proof.pubkey.data, proof.timestamp, proof.public_ip, proof.storage_port, proof.pubkey_ed25519.data, proof.qnet_port, proof.storage_lmq_port);
|
||||
size_t buf_size = buf.size();
|
||||
|
||||
if (hf_version < cryptonote::network_version_15_lns) // TODO - can be removed post-HF15
|
||||
buf_size -= sizeof(proof.storage_lmq_port);
|
||||
|
||||
size_t buf_size;
|
||||
crypto::hash result;
|
||||
|
||||
auto buf = tools::memcpy_le(proof.pubkey.data, proof.timestamp, proof.public_ip, proof.storage_port, proof.pubkey_ed25519.data, proof.qnet_port, proof.storage_lmq_port);
|
||||
buf_size = buf.size();
|
||||
crypto::cn_fast_hash(buf.data(), buf_size, result);
|
||||
return result;
|
||||
}
|
||||
|
@ -2771,12 +2773,18 @@ namespace service_nodes
|
|||
result.qnet_port = quorumnet_port;
|
||||
result.pubkey_ed25519 = keys.pub_ed25519;
|
||||
|
||||
crypto::hash hash = hash_uptime_proof(result, m_blockchain.get_current_hard_fork_version());
|
||||
crypto::hash hash = hash_uptime_proof(result);
|
||||
crypto::generate_signature(hash, keys.pub, keys.key, result.sig);
|
||||
crypto_sign_detached(result.sig_ed25519.data, NULL, reinterpret_cast<unsigned char *>(hash.data), sizeof(hash.data), keys.key_ed25519.data);
|
||||
return result;
|
||||
}
|
||||
|
||||
uptime_proof::Proof service_node_list::generate_uptime_proof(uint32_t public_ip, uint16_t storage_port, uint16_t storage_lmq_port, std::array<uint16_t, 3> ss_version, uint16_t quorumnet_port, std::array<uint16_t, 3> lokinet_version) const
|
||||
{
|
||||
const auto& keys = *m_service_node_keys;
|
||||
return uptime_proof::Proof(public_ip, storage_port, storage_lmq_port, ss_version, quorumnet_port, lokinet_version, keys);
|
||||
}
|
||||
|
||||
#ifdef __cpp_lib_erase_if // # (C++20)
|
||||
using std::erase_if;
|
||||
#else
|
||||
|
@ -2800,13 +2808,48 @@ namespace service_nodes
|
|||
return false;
|
||||
}
|
||||
|
||||
proof_info::proof_info()
|
||||
: proof(std::make_unique<uptime_proof::Proof>()) {};
|
||||
|
||||
void proof_info::store(const crypto::public_key &pubkey, cryptonote::Blockchain &blockchain)
|
||||
{
|
||||
if (!proof) proof = std::unique_ptr<uptime_proof::Proof>(new uptime_proof::Proof());
|
||||
std::unique_lock lock{blockchain};
|
||||
auto &db = blockchain.get_db();
|
||||
db.set_service_node_proof(pubkey, *this);
|
||||
}
|
||||
|
||||
bool proof_info::update(uint64_t ts, std::unique_ptr<uptime_proof::Proof> new_proof, const crypto::x25519_public_key &pk_x2)
|
||||
{
|
||||
bool update_db = false;
|
||||
if (!proof || *proof != *new_proof) {
|
||||
update_db = true;
|
||||
proof = std::move(new_proof);
|
||||
}
|
||||
update_db |= update_val(timestamp, ts);
|
||||
effective_timestamp = proof->timestamp;
|
||||
pubkey_x25519 = pk_x2;
|
||||
|
||||
// Track an IP change (so that the obligations quorum can penalize for IP changes)
|
||||
// We only keep the two most recent because all we really care about is whether it had more than one
|
||||
//
|
||||
// If we already know about the IP, update its timestamp:
|
||||
auto now = std::time(nullptr);
|
||||
if (public_ips[0].first && public_ips[0].first == proof->public_ip)
|
||||
public_ips[0].second = now;
|
||||
else if (public_ips[1].first && public_ips[1].first == proof->public_ip)
|
||||
public_ips[1].second = now;
|
||||
// Otherwise replace whichever IP has the older timestamp
|
||||
else if (public_ips[0].second > public_ips[1].second)
|
||||
public_ips[1] = {proof->public_ip, now};
|
||||
else
|
||||
public_ips[0] = {proof->public_ip, now};
|
||||
|
||||
return update_db;
|
||||
};
|
||||
|
||||
|
||||
//TODO remove after HF17
|
||||
bool proof_info::update(uint64_t ts,
|
||||
uint32_t ip,
|
||||
uint16_t s_port,
|
||||
|
@ -2817,14 +2860,15 @@ namespace service_nodes
|
|||
const crypto::x25519_public_key& pk_x2)
|
||||
{
|
||||
bool update_db = false;
|
||||
if (!proof) proof = std::unique_ptr<uptime_proof::Proof>(new uptime_proof::Proof());
|
||||
update_db |= update_val(timestamp, ts);
|
||||
update_db |= update_val(public_ip, ip);
|
||||
update_db |= update_val(storage_port, s_port);
|
||||
update_db |= update_val(storage_lmq_port, s_lmq_port);
|
||||
update_db |= update_val(quorumnet_port, q_port);
|
||||
update_db |= update_val(version, ver);
|
||||
update_db |= update_val(pubkey_ed25519, pk_ed);
|
||||
effective_timestamp = timestamp;
|
||||
update_db |= update_val(proof->public_ip, ip);
|
||||
update_db |= update_val(proof->storage_port, s_port);
|
||||
update_db |= update_val(proof->storage_lmq_port, s_lmq_port);
|
||||
update_db |= update_val(proof->qnet_port, q_port);
|
||||
update_db |= update_val(proof->version, ver);
|
||||
update_db |= update_val(proof->pubkey_ed25519, pk_ed);
|
||||
effective_timestamp = proof->timestamp;
|
||||
pubkey_x25519 = pk_x2;
|
||||
|
||||
// Track an IP change (so that the obligations quorum can penalize for IP changes)
|
||||
|
@ -2832,33 +2876,34 @@ namespace service_nodes
|
|||
//
|
||||
// If we already know about the IP, update its timestamp:
|
||||
auto now = std::time(nullptr);
|
||||
if (public_ips[0].first && public_ips[0].first == public_ip)
|
||||
if (public_ips[0].first && public_ips[0].first == proof->public_ip)
|
||||
public_ips[0].second = now;
|
||||
else if (public_ips[1].first && public_ips[1].first == public_ip)
|
||||
else if (public_ips[1].first && public_ips[1].first == proof->public_ip)
|
||||
public_ips[1].second = now;
|
||||
// Otherwise replace whichever IP has the older timestamp
|
||||
else if (public_ips[0].second > public_ips[1].second)
|
||||
public_ips[1] = {public_ip, now};
|
||||
public_ips[1] = {proof->public_ip, now};
|
||||
else
|
||||
public_ips[0] = {public_ip, now};
|
||||
public_ips[0] = {proof->public_ip, now};
|
||||
|
||||
return update_db;
|
||||
};
|
||||
|
||||
void proof_info::update_pubkey(const crypto::ed25519_public_key &pk) {
|
||||
if (pk == pubkey_ed25519)
|
||||
if (pk == proof->pubkey_ed25519)
|
||||
return;
|
||||
if (pk && 0 == crypto_sign_ed25519_pk_to_curve25519(pubkey_x25519.data, pk.data)) {
|
||||
pubkey_ed25519 = pk;
|
||||
proof->pubkey_ed25519 = pk;
|
||||
} else {
|
||||
MWARNING("Failed to derive x25519 pubkey from ed25519 pubkey " << pubkey_ed25519);
|
||||
MWARNING("Failed to derive x25519 pubkey from ed25519 pubkey " << proof->pubkey_ed25519);
|
||||
pubkey_x25519 = crypto::x25519_public_key::null();
|
||||
pubkey_ed25519 = crypto::ed25519_public_key::null();
|
||||
proof->pubkey_ed25519 = crypto::ed25519_public_key::null();
|
||||
}
|
||||
}
|
||||
|
||||
#define REJECT_PROOF(log) do { LOG_PRINT_L2("Rejecting uptime proof from " << proof.pubkey << ": " log); return false; } while (0)
|
||||
|
||||
//TODO remove after HF17
|
||||
bool service_node_list::handle_uptime_proof(cryptonote::NOTIFY_UPTIME_PROOF::request const &proof, bool &my_uptime_proof_confirmation, crypto::x25519_public_key &x25519_pkey)
|
||||
{
|
||||
uint8_t const hf_version = m_blockchain.get_current_hard_fork_version();
|
||||
|
@ -2878,7 +2923,8 @@ namespace service_nodes
|
|||
//
|
||||
// Validate proof signature
|
||||
//
|
||||
crypto::hash hash = hash_uptime_proof(proof, hf_version);
|
||||
crypto::hash hash = hash_uptime_proof(proof);
|
||||
|
||||
|
||||
if (!crypto::check_signature(hash, proof.pubkey, proof.sig))
|
||||
REJECT_PROOF("signature validation failed");
|
||||
|
@ -2904,6 +2950,7 @@ namespace service_nodes
|
|||
|
||||
auto &iproof = proofs[proof.pubkey];
|
||||
|
||||
|
||||
if (iproof.timestamp >= now - (UPTIME_PROOF_FREQUENCY_IN_SECONDS / 2))
|
||||
REJECT_PROOF("already received one uptime proof for this node recently");
|
||||
|
||||
|
@ -2945,6 +2992,97 @@ namespace service_nodes
|
|||
return true;
|
||||
}
|
||||
|
||||
#undef REJECT_PROOF
|
||||
#define REJECT_PROOF(log) do { LOG_PRINT_L2("Rejecting uptime proof from " << proof->pubkey << ": " log); return false; } while (0)
|
||||
|
||||
bool service_node_list::handle_btencoded_uptime_proof(std::unique_ptr<uptime_proof::Proof> proof, bool &my_uptime_proof_confirmation, crypto::x25519_public_key &x25519_pkey)
|
||||
{
|
||||
uint8_t const hf_version = m_blockchain.get_current_hard_fork_version();
|
||||
uint64_t const now = time(nullptr);
|
||||
|
||||
// Validate proof version, timestamp range,
|
||||
if ((proof->timestamp < now - UPTIME_PROOF_BUFFER_IN_SECONDS) || (proof->timestamp > now + UPTIME_PROOF_BUFFER_IN_SECONDS))
|
||||
REJECT_PROOF("timestamp is too far from now");
|
||||
|
||||
for (auto const &min : MIN_UPTIME_PROOF_VERSIONS)
|
||||
if (hf_version >= min.hardfork && proof->version < min.version)
|
||||
REJECT_PROOF("v" << min.version[0] << "." << min.version[1] << "." << min.version[2] << "+ oxen version is required for v" << std::to_string(hf_version) << "+ network proofs");
|
||||
|
||||
if (!debug_allow_local_ips && !epee::net_utils::is_ip_public(proof->public_ip))
|
||||
REJECT_PROOF("public_ip is not actually public");
|
||||
|
||||
//
|
||||
// Validate proof signature
|
||||
//
|
||||
crypto::hash hash = proof->hash_uptime_proof();
|
||||
|
||||
if (!crypto::check_signature(hash, proof->pubkey, proof->sig))
|
||||
REJECT_PROOF("signature validation failed");
|
||||
|
||||
crypto::x25519_public_key derived_x25519_pubkey = crypto::x25519_public_key::null();
|
||||
if (!proof->pubkey_ed25519)
|
||||
REJECT_PROOF("required ed25519 auxiliary pubkey " << proof->pubkey_ed25519 << " not included in proof");
|
||||
|
||||
if (0 != crypto_sign_verify_detached(proof->sig_ed25519.data, reinterpret_cast<unsigned char *>(hash.data), sizeof(hash.data), proof->pubkey_ed25519.data))
|
||||
REJECT_PROOF("ed25519 signature validation failed");
|
||||
|
||||
if (0 != crypto_sign_ed25519_pk_to_curve25519(derived_x25519_pubkey.data, proof->pubkey_ed25519.data)
|
||||
|| !derived_x25519_pubkey)
|
||||
REJECT_PROOF("invalid ed25519 pubkey included in proof (x25519 derivation failed)");
|
||||
|
||||
if (proof->qnet_port == 0)
|
||||
REJECT_PROOF("invalid quorumnet port in uptime proof");
|
||||
|
||||
auto locks = tools::unique_locks(m_blockchain, m_sn_mutex, m_x25519_map_mutex);
|
||||
auto it = m_state.service_nodes_infos.find(proof->pubkey);
|
||||
if (it == m_state.service_nodes_infos.end())
|
||||
REJECT_PROOF("no such service node is currently registered");
|
||||
|
||||
auto &iproof = proofs[proof->pubkey];
|
||||
|
||||
if (iproof.timestamp >= now - (UPTIME_PROOF_FREQUENCY_IN_SECONDS / 2))
|
||||
REJECT_PROOF("already received one uptime proof for this node recently");
|
||||
|
||||
if (m_service_node_keys && proof->pubkey == m_service_node_keys->pub)
|
||||
{
|
||||
my_uptime_proof_confirmation = true;
|
||||
MGINFO("Received uptime-proof confirmation back from network for Service Node (yours): " << proof->pubkey);
|
||||
}
|
||||
else
|
||||
{
|
||||
my_uptime_proof_confirmation = false;
|
||||
LOG_PRINT_L2("Accepted uptime proof from " << proof->pubkey);
|
||||
|
||||
if (m_service_node_keys && proof->pubkey_ed25519 == m_service_node_keys->pub_ed25519)
|
||||
MGINFO_RED("Uptime proof from SN " << proof->pubkey << " is not us, but is using our ed/x25519 keys; "
|
||||
"this is likely to lead to deregistration of one or both service nodes.");
|
||||
}
|
||||
|
||||
auto old_x25519 = iproof.pubkey_x25519;
|
||||
if (iproof.update(now, std::move(proof), derived_x25519_pubkey))
|
||||
{
|
||||
iproof.store(iproof.proof->pubkey, m_blockchain);
|
||||
}
|
||||
|
||||
if ((uint64_t) x25519_map_last_pruned + X25519_MAP_PRUNING_INTERVAL <= now)
|
||||
{
|
||||
time_t cutoff = now - X25519_MAP_PRUNING_LAG;
|
||||
erase_if(x25519_to_pub, [&cutoff](const decltype(x25519_to_pub)::value_type &x) { return x.second.second < cutoff; });
|
||||
x25519_map_last_pruned = now;
|
||||
}
|
||||
|
||||
if (old_x25519 && old_x25519 != derived_x25519_pubkey)
|
||||
x25519_to_pub.erase(old_x25519);
|
||||
|
||||
if (derived_x25519_pubkey)
|
||||
x25519_to_pub[derived_x25519_pubkey] = {iproof.proof->pubkey, now};
|
||||
|
||||
if (derived_x25519_pubkey && (old_x25519 != derived_x25519_pubkey))
|
||||
x25519_pkey = derived_x25519_pubkey;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void service_node_list::cleanup_proofs()
|
||||
{
|
||||
MDEBUG("Cleaning up expired SN proofs");
|
||||
|
@ -3018,8 +3156,8 @@ namespace service_nodes
|
|||
uint16_t port = 0;
|
||||
for_each_service_node_info_and_proof(&pubkey, &pubkey + 1, [&](auto&, auto&, auto& proof) {
|
||||
found = true;
|
||||
ip = proof.public_ip;
|
||||
port = proof.quorumnet_port;
|
||||
ip = proof.proof->public_ip;
|
||||
port = proof.proof->qnet_port;
|
||||
});
|
||||
|
||||
if (!found) {
|
||||
|
|
|
@ -38,6 +38,8 @@
|
|||
#include "cryptonote_core/service_node_quorum_cop.h"
|
||||
#include "common/util.h"
|
||||
|
||||
#include <lokimq/bt_serialize.h>
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
class Blockchain;
|
||||
|
@ -45,6 +47,11 @@ class BlockchainDB;
|
|||
struct checkpoint_t;
|
||||
}; // namespace cryptonote
|
||||
|
||||
namespace uptime_proof
|
||||
{
|
||||
class Proof;
|
||||
}
|
||||
|
||||
namespace service_nodes
|
||||
{
|
||||
constexpr uint64_t INVALID_HEIGHT = static_cast<uint64_t>(-1);
|
||||
|
@ -136,6 +143,8 @@ namespace service_nodes
|
|||
|
||||
struct proof_info
|
||||
{
|
||||
proof_info();
|
||||
|
||||
participation_history<participation_entry> pulse_participation{};
|
||||
participation_history<participation_entry> checkpoint_participation{};
|
||||
participation_history<timestamp_participation_entry> timestamp_participation{};
|
||||
|
@ -149,12 +158,7 @@ namespace service_nodes
|
|||
uint64_t storage_server_reachable_timestamp = 0;
|
||||
|
||||
// Unlike all of the above (except for timestamp), these values *do* get serialized
|
||||
uint32_t public_ip = 0;
|
||||
uint16_t storage_port = 0;
|
||||
uint16_t storage_lmq_port = 0;
|
||||
uint16_t quorumnet_port = 0;
|
||||
std::array<uint16_t, 3> version{{0,0,0}};
|
||||
crypto::ed25519_public_key pubkey_ed25519 = crypto::ed25519_public_key::null();
|
||||
std::unique_ptr<uptime_proof::Proof> proof;
|
||||
|
||||
// Derived from pubkey_ed25519, not serialized
|
||||
crypto::x25519_public_key pubkey_x25519 = crypto::x25519_public_key::null();
|
||||
|
@ -168,6 +172,8 @@ namespace service_nodes
|
|||
// Returns true if serializable data is changed (in which case `store()` should be called).
|
||||
// Note that this does not update the m_x25519_to_pub map if the x25519 key changes (that's the
|
||||
// caller's responsibility).
|
||||
bool update(uint64_t ts, std::unique_ptr<uptime_proof::Proof> new_proof, const crypto::x25519_public_key &pk_x2);
|
||||
// TODO: remove after HF 17
|
||||
bool update(uint64_t ts, uint32_t ip, uint16_t s_port, uint16_t s_lmq_port, uint16_t q_port, std::array<uint16_t, 3> ver, const crypto::ed25519_public_key &pk_ed, const crypto::x25519_public_key &pk_x2);
|
||||
|
||||
// Stores this record in the database.
|
||||
|
@ -511,13 +517,23 @@ namespace service_nodes
|
|||
void set_quorum_history_storage(uint64_t hist_size); // 0 = none (default), 1 = unlimited, N = # of blocks
|
||||
bool store();
|
||||
|
||||
//TODO: remove after HF17
|
||||
crypto::hash hash_uptime_proof(const cryptonote::NOTIFY_UPTIME_PROOF::request &proof) const;
|
||||
|
||||
/// Record public ip and storage port and add them to the service node list
|
||||
//TODO: remove after HF17
|
||||
cryptonote::NOTIFY_UPTIME_PROOF::request generate_uptime_proof(uint32_t public_ip,
|
||||
uint16_t storage_port,
|
||||
uint16_t storage_lmq_port,
|
||||
uint16_t quorumnet_port) const;
|
||||
|
||||
uptime_proof::Proof generate_uptime_proof(uint32_t public_ip, uint16_t storage_port, uint16_t storage_lmq_port, std::array<uint16_t, 3> ss_version, uint16_t quorumnet_port, std::array<uint16_t, 3> lokinet_version) const;
|
||||
|
||||
//TODO: remove after HF17
|
||||
bool handle_uptime_proof(cryptonote::NOTIFY_UPTIME_PROOF::request const &proof, bool &my_uptime_proof_confirmation, crypto::x25519_public_key &x25519_pkey);
|
||||
|
||||
bool handle_btencoded_uptime_proof(std::unique_ptr<uptime_proof::Proof> proof, bool &my_uptime_proof_confirmation, crypto::x25519_public_key &x25519_pkey);
|
||||
|
||||
void record_checkpoint_participation(crypto::public_key const &pubkey, uint64_t height, bool participated);
|
||||
|
||||
// Called every hour to remove proofs for expired SNs from memory and the database.
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "service_node_quorum_cop.h"
|
||||
#include "service_node_voting.h"
|
||||
#include "service_node_list.h"
|
||||
#include "uptime_proof.h"
|
||||
#include "cryptonote_config.h"
|
||||
#include "cryptonote_core.h"
|
||||
#include "version.h"
|
||||
|
@ -98,13 +99,13 @@ namespace service_nodes
|
|||
|
||||
m_core.get_service_node_list().access_proof(pubkey, [&](const proof_info &proof) {
|
||||
ss_reachable = proof.storage_server_reachable;
|
||||
timestamp = std::max(proof.timestamp, proof.effective_timestamp);
|
||||
timestamp = std::max(proof.proof->timestamp, proof.effective_timestamp);
|
||||
ips = proof.public_ips;
|
||||
checkpoint_participation = proof.checkpoint_participation;
|
||||
pulse_participation = proof.pulse_participation;
|
||||
|
||||
// TODO: remove after HF17
|
||||
if (proof.version >= MIN_TIMESTAMP_VERSION && hf_version >= cryptonote::network_version_17) {
|
||||
if (proof.proof->version >= MIN_TIMESTAMP_VERSION && hf_version >= cryptonote::network_version_17) {
|
||||
timestamp_participation = proof.timestamp_participation;
|
||||
timesync_status = proof.timesync_status;
|
||||
check_timestamp_obligation = true;
|
||||
|
|
|
@ -213,8 +213,8 @@ namespace service_nodes {
|
|||
// blocks out of sync and sending something that it thinks is legit.
|
||||
constexpr uint64_t VOTE_OR_TX_VERIFY_HEIGHT_BUFFER = 5;
|
||||
|
||||
constexpr std::array<int, 3> MIN_STORAGE_SERVER_VERSION{{2, 0, 7}};
|
||||
constexpr std::array<int, 3> MIN_LOKINET_VERSION{{0, 8, 0}};
|
||||
constexpr std::array<uint16_t, 3> MIN_STORAGE_SERVER_VERSION{{2, 0, 7}};
|
||||
constexpr std::array<uint16_t, 3> MIN_LOKINET_VERSION{{0, 8, 0}};
|
||||
|
||||
// The minimum accepted version number, broadcasted by Service Nodes via uptime proofs for each hardfork
|
||||
struct proof_version
|
||||
|
@ -224,6 +224,7 @@ namespace service_nodes {
|
|||
};
|
||||
|
||||
constexpr proof_version MIN_UPTIME_PROOF_VERSIONS[] = {
|
||||
{cryptonote::network_version_17, {9,0,0}},
|
||||
{cryptonote::network_version_16_pulse, {8,1,0}},
|
||||
{cryptonote::network_version_15_lns, {7,1,2}},
|
||||
{cryptonote::network_version_14_blink, {6,1,0}},
|
||||
|
|
154
src/cryptonote_core/uptime_proof.cpp
Normal file
154
src/cryptonote_core/uptime_proof.cpp
Normal file
|
@ -0,0 +1,154 @@
|
|||
#include "uptime_proof.h"
|
||||
#include "common/string_util.h"
|
||||
#include "version.h"
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#include <sodium/crypto_sign.h>
|
||||
}
|
||||
|
||||
#undef OXEN_DEFAULT_LOG_CATEGORY
|
||||
#define OXEN_DEFAULT_LOG_CATEGORY "uptime_proof"
|
||||
|
||||
namespace uptime_proof
|
||||
{
|
||||
|
||||
//Constructor for the uptime proof, will take the service node keys as a param and sign
|
||||
Proof::Proof(uint32_t sn_public_ip, uint16_t sn_storage_port, uint16_t sn_storage_lmq_port, const std::array<uint16_t, 3> ss_version, uint16_t quorumnet_port, const std::array<uint16_t, 3> lokinet_version, const service_nodes::service_node_keys& keys) : version{OXEN_VERSION}, pubkey{keys.pub}, timestamp{static_cast<uint64_t>(time(nullptr))}, public_ip{sn_public_ip}, storage_port{sn_storage_port}, pubkey_ed25519{keys.pub_ed25519},qnet_port{quorumnet_port}, storage_lmq_port{sn_storage_lmq_port}, storage_server_version{ss_version}
|
||||
{
|
||||
this->lokinet_version = lokinet_version;
|
||||
crypto::hash hash = this->hash_uptime_proof();
|
||||
|
||||
crypto::generate_signature(hash, keys.pub, keys.key, sig);
|
||||
crypto_sign_detached(sig_ed25519.data, NULL, reinterpret_cast<unsigned char *>(hash.data), sizeof(hash.data), keys.key_ed25519.data);
|
||||
}
|
||||
|
||||
//Deserialize from a btencoded string into our Proof instance
|
||||
Proof::Proof(const std::string& serialized_proof)
|
||||
{
|
||||
try {
|
||||
const lokimq::bt_dict bt_proof = lokimq::bt_deserialize<lokimq::bt_dict>(serialized_proof);
|
||||
//snode_version <X,X,X>
|
||||
const lokimq::bt_list& bt_version = var::get<lokimq::bt_list>(bt_proof.at("v"));
|
||||
int k = 0;
|
||||
for (lokimq::bt_value const &i: bt_version){
|
||||
version[k++] = static_cast<uint16_t>(lokimq::get_int<unsigned>(i));
|
||||
}
|
||||
//timestamp
|
||||
timestamp = lokimq::get_int<unsigned>(bt_proof.at("t"));
|
||||
//public_ip
|
||||
bool succeeded = epee::string_tools::get_ip_int32_from_string(public_ip, var::get<std::string>(bt_proof.at("ip")));
|
||||
//storage_port
|
||||
storage_port = static_cast<uint16_t>(lokimq::get_int<unsigned>(bt_proof.at("s")));
|
||||
//pubkey_ed25519
|
||||
pubkey_ed25519 = tools::make_from_guts<crypto::ed25519_public_key>(var::get<std::string>(bt_proof.at("pke")));
|
||||
//pubkey
|
||||
if (auto it = bt_proof.find("pk"); it != bt_proof.end())
|
||||
pubkey = tools::make_from_guts<crypto::public_key>(var::get<std::string>(bt_proof.at("pk")));
|
||||
else
|
||||
std::memcpy(pubkey.data, pubkey_ed25519.data, 32);
|
||||
//qnet_port
|
||||
qnet_port = lokimq::get_int<unsigned>(bt_proof.at("q"));
|
||||
//storage_lmq_port
|
||||
storage_lmq_port = lokimq::get_int<unsigned>(bt_proof.at("slp"));
|
||||
//storage_version
|
||||
const lokimq::bt_list& bt_storage_version = var::get<lokimq::bt_list>(bt_proof.at("sv"));
|
||||
k = 0;
|
||||
for (lokimq::bt_value const &i: bt_storage_version){
|
||||
storage_server_version[k++] = static_cast<uint16_t>(lokimq::get_int<unsigned>(i));
|
||||
}
|
||||
//lokinet_version
|
||||
const lokimq::bt_list& bt_lokinet_version = var::get<lokimq::bt_list>(bt_proof.at("lv"));
|
||||
k = 0;
|
||||
for (lokimq::bt_value const &i: bt_lokinet_version){
|
||||
lokinet_version[k++] = static_cast<uint16_t>(lokimq::get_int<unsigned>(i));
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
MWARNING("deserialization failed: " << e.what());
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
crypto::hash Proof::hash_uptime_proof() const
|
||||
{
|
||||
crypto::hash result;
|
||||
|
||||
std::string serialized_proof = lokimq::bt_serialize(bt_encode_uptime_proof());
|
||||
size_t buf_size = serialized_proof.size();
|
||||
crypto::cn_fast_hash(serialized_proof.data(), buf_size, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
lokimq::bt_dict Proof::bt_encode_uptime_proof() const
|
||||
{
|
||||
lokimq::bt_dict encoded_proof{
|
||||
//version
|
||||
{"v", lokimq::bt_list{{version[0], version[1], version[2]}}},
|
||||
//timestamp
|
||||
{"t", timestamp},
|
||||
//public_ip
|
||||
{"ip", epee::string_tools::get_ip_string_from_int32(public_ip)},
|
||||
//storage_port
|
||||
{"s", storage_port},
|
||||
//pubkey_ed25519
|
||||
{"pke", tools::view_guts(pubkey_ed25519)},
|
||||
//qnet_port
|
||||
{"q", qnet_port},
|
||||
//storage_lmq_port
|
||||
{"slp", storage_lmq_port},
|
||||
//storage_version
|
||||
{"sv", lokimq::bt_list{{storage_server_version[0], storage_server_version[1], storage_server_version[2]}}},
|
||||
//lokinet_version
|
||||
{"lv", lokimq::bt_list{{lokinet_version[0], lokinet_version[1], lokinet_version[2]}}},
|
||||
};
|
||||
|
||||
if (pubkey != pubkey_ed25519) encoded_proof["pk"] = tools::view_guts(pubkey);
|
||||
|
||||
return encoded_proof;
|
||||
}
|
||||
|
||||
cryptonote::NOTIFY_BTENCODED_UPTIME_PROOF::request Proof::generate_request() const
|
||||
{
|
||||
cryptonote::NOTIFY_BTENCODED_UPTIME_PROOF::request request;
|
||||
request.proof = lokimq::bt_serialize(this->bt_encode_uptime_proof());
|
||||
request.sig = tools::view_guts(this->sig);
|
||||
request.ed_sig = tools::view_guts(this->sig_ed25519);
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
bool operator==(const uptime_proof::Proof& lhs, const uptime_proof::Proof& rhs)
|
||||
{
|
||||
bool result = true;
|
||||
|
||||
if( (lhs.timestamp != rhs.timestamp) ||
|
||||
(lhs.pubkey != rhs.pubkey) ||
|
||||
(lhs.sig != rhs.sig) ||
|
||||
(lhs.pubkey_ed25519 != rhs.pubkey_ed25519) ||
|
||||
(lhs.sig_ed25519 != rhs.sig_ed25519) ||
|
||||
(lhs.public_ip != rhs.public_ip) ||
|
||||
(lhs.storage_port != rhs.storage_port) ||
|
||||
(lhs.storage_lmq_port != rhs.storage_lmq_port) ||
|
||||
(lhs.qnet_port != rhs.qnet_port) ||
|
||||
(lhs.version[0] != rhs.version[0]) ||
|
||||
(lhs.version[1] != rhs.version[1]) ||
|
||||
(lhs.version[2] != rhs.version[2]) ||
|
||||
(lhs.storage_server_version[0] != rhs.storage_server_version[0]) ||
|
||||
(lhs.storage_server_version[1] != rhs.storage_server_version[1]) ||
|
||||
(lhs.storage_server_version[2] != rhs.storage_server_version[2]) ||
|
||||
(lhs.lokinet_version[0] != rhs.lokinet_version[0]) ||
|
||||
(lhs.lokinet_version[1] != rhs.lokinet_version[1]) ||
|
||||
(lhs.lokinet_version[2] != rhs.lokinet_version[2]))
|
||||
result = false;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool operator!=(const uptime_proof::Proof& lhs, const uptime_proof::Proof& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
41
src/cryptonote_core/uptime_proof.h
Normal file
41
src/cryptonote_core/uptime_proof.h
Normal file
|
@ -0,0 +1,41 @@
|
|||
#pragma once
|
||||
|
||||
#include "service_node_list.h"
|
||||
#include "../cryptonote_protocol/cryptonote_protocol_defs.h"
|
||||
#include <lokimq/lokimq.h>
|
||||
|
||||
namespace uptime_proof
|
||||
{
|
||||
|
||||
class Proof
|
||||
{
|
||||
|
||||
public:
|
||||
std::array<uint16_t, 3> version;
|
||||
std::array<uint16_t, 3> storage_server_version;
|
||||
std::array<uint16_t, 3> lokinet_version;
|
||||
|
||||
uint64_t timestamp;
|
||||
crypto::public_key pubkey;
|
||||
crypto::signature sig;
|
||||
crypto::ed25519_public_key pubkey_ed25519;
|
||||
crypto::ed25519_signature sig_ed25519;
|
||||
uint32_t public_ip;
|
||||
uint16_t storage_port;
|
||||
uint16_t storage_lmq_port;
|
||||
uint16_t qnet_port;
|
||||
|
||||
Proof() = default;
|
||||
Proof(uint32_t sn_public_ip, uint16_t sn_storage_port, uint16_t sn_storage_lmq_port, std::array<uint16_t, 3> ss_version, uint16_t quorumnet_port, std::array<uint16_t, 3> lokinet_version, const service_nodes::service_node_keys& keys);
|
||||
|
||||
Proof(const std::string& serialized_proof);
|
||||
lokimq::bt_dict bt_encode_uptime_proof() const;
|
||||
|
||||
crypto::hash hash_uptime_proof() const;
|
||||
|
||||
cryptonote::NOTIFY_BTENCODED_UPTIME_PROOF::request generate_request() const;
|
||||
};
|
||||
|
||||
}
|
||||
bool operator==(const uptime_proof::Proof& lhs, const uptime_proof::Proof& rhs);
|
||||
bool operator!=(const uptime_proof::Proof& lhs, const uptime_proof::Proof& rhs);
|
|
@ -119,6 +119,13 @@ KV_SERIALIZE_MAP_CODE_BEGIN(NOTIFY_UPTIME_PROOF::request)
|
|||
KV_SERIALIZE_VAL_POD_AS_BLOB(sig_ed25519)
|
||||
KV_SERIALIZE_MAP_CODE_END()
|
||||
|
||||
KV_SERIALIZE_MAP_CODE_BEGIN(NOTIFY_BTENCODED_UPTIME_PROOF::request)
|
||||
KV_SERIALIZE(proof)
|
||||
KV_SERIALIZE(sig)
|
||||
KV_SERIALIZE(ed_sig)
|
||||
KV_SERIALIZE_MAP_CODE_END()
|
||||
|
||||
|
||||
KV_SERIALIZE_MAP_CODE_BEGIN(NOTIFY_REQUEST_BLOCK_BLINKS::request)
|
||||
KV_SERIALIZE(heights)
|
||||
KV_SERIALIZE_MAP_CODE_END()
|
||||
|
|
|
@ -267,6 +267,25 @@ namespace cryptonote
|
|||
};
|
||||
};
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
struct NOTIFY_BTENCODED_UPTIME_PROOF
|
||||
{
|
||||
const static int ID = BC_COMMANDS_POOL_BASE + 12;
|
||||
|
||||
struct request
|
||||
{
|
||||
|
||||
// BT-Encoded string of the Uptime Proof
|
||||
std::string proof;
|
||||
std::string sig;
|
||||
std::string ed_sig;
|
||||
|
||||
KV_MAP_SERIALIZABLE
|
||||
};
|
||||
};
|
||||
|
||||
/************************************************************************/
|
||||
/* */
|
||||
/************************************************************************/
|
||||
|
|
|
@ -80,6 +80,7 @@ namespace cryptonote
|
|||
HANDLE_NOTIFY_T2(NOTIFY_NEW_FLUFFY_BLOCK, handle_notify_new_fluffy_block)
|
||||
HANDLE_NOTIFY_T2(NOTIFY_REQUEST_FLUFFY_MISSING_TX, handle_request_fluffy_missing_tx)
|
||||
HANDLE_NOTIFY_T2(NOTIFY_UPTIME_PROOF, handle_uptime_proof)
|
||||
HANDLE_NOTIFY_T2(NOTIFY_BTENCODED_UPTIME_PROOF, handle_btencoded_uptime_proof)
|
||||
HANDLE_NOTIFY_T2(NOTIFY_NEW_SERVICE_NODE_VOTE, handle_notify_new_service_node_vote)
|
||||
HANDLE_NOTIFY_T2(NOTIFY_REQUEST_BLOCK_BLINKS, handle_request_block_blinks)
|
||||
HANDLE_NOTIFY_T2(NOTIFY_RESPONSE_BLOCK_BLINKS, handle_response_block_blinks)
|
||||
|
@ -118,6 +119,7 @@ namespace cryptonote
|
|||
int handle_notify_new_fluffy_block(int command, NOTIFY_NEW_FLUFFY_BLOCK::request& arg, cryptonote_connection_context& context);
|
||||
int handle_request_fluffy_missing_tx(int command, NOTIFY_REQUEST_FLUFFY_MISSING_TX::request& arg, cryptonote_connection_context& context);
|
||||
int handle_uptime_proof(int command, NOTIFY_UPTIME_PROOF::request& arg, cryptonote_connection_context& context);
|
||||
int handle_btencoded_uptime_proof(int command, NOTIFY_BTENCODED_UPTIME_PROOF::request& arg, cryptonote_connection_context& context);
|
||||
int handle_notify_new_service_node_vote(int command, NOTIFY_NEW_SERVICE_NODE_VOTE::request& arg, cryptonote_connection_context& context);
|
||||
int handle_request_block_blinks(int command, NOTIFY_REQUEST_BLOCK_BLINKS::request& arg, cryptonote_connection_context& context);
|
||||
int handle_response_block_blinks(int command, NOTIFY_RESPONSE_BLOCK_BLINKS::request& arg, cryptonote_connection_context& context);
|
||||
|
@ -152,6 +154,7 @@ namespace cryptonote
|
|||
virtual bool relay_block(NOTIFY_NEW_FLUFFY_BLOCK::request& arg, cryptonote_connection_context& exclude_context);
|
||||
virtual bool relay_transactions(NOTIFY_NEW_TRANSACTIONS::request& arg, cryptonote_connection_context& exclude_context);
|
||||
virtual bool relay_uptime_proof(NOTIFY_UPTIME_PROOF::request& arg, cryptonote_connection_context& exclude_context);
|
||||
virtual bool relay_btencoded_uptime_proof(NOTIFY_BTENCODED_UPTIME_PROOF::request& arg, cryptonote_connection_context& exclude_context);
|
||||
virtual bool relay_service_node_votes(NOTIFY_NEW_SERVICE_NODE_VOTE::request& arg, cryptonote_connection_context& exclude_context);
|
||||
//----------------------------------------------------------------------------------
|
||||
//bool get_payload_sync_data(HANDSHAKE_DATA::request& hshd, cryptonote_connection_context& context);
|
||||
|
|
|
@ -876,6 +876,39 @@ namespace cryptonote
|
|||
}
|
||||
return 1;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_core>
|
||||
int t_cryptonote_protocol_handler<t_core>::handle_btencoded_uptime_proof(int command, NOTIFY_BTENCODED_UPTIME_PROOF::request& arg, cryptonote_connection_context& context)
|
||||
{
|
||||
MLOG_P2P_MESSAGE("Received NOTIFY_BTENCODED_UPTIME_PROOF");
|
||||
// NOTE: Don't relay your own uptime proof, otherwise we have the following situation
|
||||
|
||||
// Node1 sends uptime ->
|
||||
// Node2 receives uptime and relays it back to Node1 for acknowledgement ->
|
||||
// Node1 receives it, handle_uptime_proof returns true to acknowledge, Node1 tries to resend to the same peers again
|
||||
|
||||
// Instead, if we receive our own uptime proof, then acknowledge but don't
|
||||
// send on. If the we are missing an uptime proof it will have been
|
||||
// submitted automatically by the daemon itself instead of
|
||||
// using my own proof relayed by other nodes.
|
||||
|
||||
(void)context;
|
||||
bool my_uptime_proof_confirmation = false;
|
||||
|
||||
if (m_core.handle_btencoded_uptime_proof(arg, my_uptime_proof_confirmation))
|
||||
{
|
||||
if (!my_uptime_proof_confirmation)
|
||||
{
|
||||
// NOTE: The default exclude context contains the peer who sent us this
|
||||
// uptime proof, we want to ensure we relay it back so they know that the
|
||||
// peer they relayed to received their uptime and confirm it, so send in an
|
||||
// empty context so we don't omit the source peer from the relay back.
|
||||
cryptonote_connection_context empty_context = {};
|
||||
relay_btencoded_uptime_proof(arg, empty_context);
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_core>
|
||||
|
@ -2526,6 +2559,13 @@ skip:
|
|||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_core>
|
||||
bool t_cryptonote_protocol_handler<t_core>::relay_btencoded_uptime_proof(NOTIFY_BTENCODED_UPTIME_PROOF::request& arg, cryptonote_connection_context& exclude_context)
|
||||
{
|
||||
bool result = relay_to_synchronized_peers<NOTIFY_BTENCODED_UPTIME_PROOF>(arg, exclude_context);
|
||||
return result;
|
||||
}
|
||||
//------------------------------------------------------------------------------------------------------------------------
|
||||
template<class t_core>
|
||||
bool t_cryptonote_protocol_handler<t_core>::relay_service_node_votes(NOTIFY_NEW_SERVICE_NODE_VOTE::request& arg, cryptonote_connection_context& exclude_context)
|
||||
{
|
||||
bool result = relay_to_synchronized_peers<NOTIFY_NEW_SERVICE_NODE_VOTE>(arg, exclude_context);
|
||||
|
|
|
@ -43,6 +43,7 @@ namespace cryptonote
|
|||
virtual bool relay_block(NOTIFY_NEW_FLUFFY_BLOCK::request& arg, cryptonote_connection_context& exclude_context)=0;
|
||||
virtual bool relay_transactions(NOTIFY_NEW_TRANSACTIONS::request& arg, cryptonote_connection_context& exclude_context)=0;
|
||||
virtual bool relay_uptime_proof(NOTIFY_UPTIME_PROOF::request& arg, cryptonote_connection_context& exclude_context)=0;
|
||||
virtual bool relay_btencoded_uptime_proof(NOTIFY_BTENCODED_UPTIME_PROOF::request& arg, cryptonote_connection_context& exclude_context)=0;
|
||||
//virtual bool request_objects(NOTIFY_REQUEST_GET_OBJECTS::request& arg, cryptonote_connection_context& context)=0;
|
||||
virtual bool relay_service_node_votes(NOTIFY_NEW_SERVICE_NODE_VOTE::request& arg, cryptonote_connection_context& exclude_context)=0;
|
||||
};
|
||||
|
@ -68,5 +69,9 @@ namespace cryptonote
|
|||
{
|
||||
return false;
|
||||
}
|
||||
virtual bool relay_btencoded_uptime_proof(NOTIFY_BTENCODED_UPTIME_PROOF::request& arg, cryptonote_connection_context& exclude_context)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "cryptonote_core/tx_blink.h"
|
||||
#include "cryptonote_core/tx_pool.h"
|
||||
#include "cryptonote_core/pulse.h"
|
||||
#include "cryptonote_core/uptime_proof.h"
|
||||
#include "quorumnet_conn_matrix.h"
|
||||
#include "cryptonote_config.h"
|
||||
#include "common/random.h"
|
||||
|
@ -160,7 +161,7 @@ peer_prepare_relay_to_quorum_subset(cryptonote::core &core, It quorum_begin, It
|
|||
|
||||
MDEBUG("Have " << candidates.size() << " SN candidates");
|
||||
|
||||
std::vector<std::tuple<std::string, std::string, decltype(proof_info{}.version)>> remotes; // {x25519 pubkey, connect string, version}
|
||||
std::vector<std::tuple<std::string, std::string, decltype(proof_info{}.proof->version)>> remotes; // {x25519 pubkey, connect string, version}
|
||||
remotes.reserve(candidates.size());
|
||||
core.get_service_node_list().for_each_service_node_info_and_proof(candidates.begin(), candidates.end(),
|
||||
[&remotes](const auto &pubkey, const auto &info, const auto &proof) {
|
||||
|
@ -168,14 +169,14 @@ peer_prepare_relay_to_quorum_subset(cryptonote::core &core, It quorum_begin, It
|
|||
MTRACE("Not include inactive node " << pubkey);
|
||||
return;
|
||||
}
|
||||
if (!proof.pubkey_x25519 || !proof.quorumnet_port || !proof.public_ip) {
|
||||
if (!proof.pubkey_x25519 || !proof.proof->qnet_port || !proof.proof->public_ip) {
|
||||
MTRACE("Not including node " << pubkey << ": missing x25519(" << to_hex(get_data_as_string(proof.pubkey_x25519)) << "), "
|
||||
"public_ip(" << epee::string_tools::get_ip_string_from_int32(proof.public_ip) << "), or qnet port(" << proof.quorumnet_port << ")");
|
||||
"public_ip(" << epee::string_tools::get_ip_string_from_int32(proof.proof->public_ip) << "), or qnet port(" << proof.proof->qnet_port << ")");
|
||||
return;
|
||||
}
|
||||
remotes.emplace_back(get_data_as_string(proof.pubkey_x25519),
|
||||
"tcp://" + epee::string_tools::get_ip_string_from_int32(proof.public_ip) + ":" + std::to_string(proof.quorumnet_port),
|
||||
proof.version);
|
||||
"tcp://" + epee::string_tools::get_ip_string_from_int32(proof.proof->public_ip) + ":" + std::to_string(proof.proof->qnet_port),
|
||||
proof.proof->version);
|
||||
});
|
||||
|
||||
// Select 4 random SNs to send the data to, but prefer SNs with newer versions because they may have network fixes.
|
||||
|
@ -294,9 +295,9 @@ public:
|
|||
// Lookup the x25519 and ZMQ connection string for all peers
|
||||
qnet.core.get_service_node_list().for_each_service_node_info_and_proof(need_remotes.begin(), need_remotes.end(),
|
||||
[this](const auto &pubkey, const auto &info, const auto &proof) {
|
||||
if (info.is_active() && proof.pubkey_x25519 && proof.quorumnet_port && proof.public_ip)
|
||||
if (info.is_active() && proof.pubkey_x25519 && proof.proof->qnet_port && proof.proof->public_ip)
|
||||
remotes.emplace(pubkey, std::make_pair(proof.pubkey_x25519,
|
||||
"tcp://" + epee::string_tools::get_ip_string_from_int32(proof.public_ip) + ":" + std::to_string(proof.quorumnet_port)));
|
||||
"tcp://" + epee::string_tools::get_ip_string_from_int32(proof.proof->public_ip) + ":" + std::to_string(proof.proof->qnet_port)));
|
||||
});
|
||||
|
||||
compute_validator_peers(qbegin, qend, opportunistic);
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#include "rpc/http_server.h"
|
||||
#include "rpc/lmq_server.h"
|
||||
#include "cryptonote_protocol/quorumnet.h"
|
||||
#include "cryptonote_core/uptime_proof.h"
|
||||
|
||||
#include "common/password.h"
|
||||
#include "common/signal_handler.h"
|
||||
|
|
|
@ -1678,6 +1678,12 @@ static void append_printable_service_node_list_entry(cryptonote::network_type ne
|
|||
stream << "Last checked: " << get_human_time_ago(entry.storage_server_reachable_timestamp, now);
|
||||
stream << ")\n";
|
||||
|
||||
//
|
||||
// NOTE: Component Versions
|
||||
//
|
||||
stream << indent2 << "Storage Server Version: " << tools::join(".", entry.storage_server_version) << "\n";
|
||||
stream << indent2 << "Lokinet Router Version: " << tools::join(".", entry.lokinet_version) << "\n";
|
||||
|
||||
//
|
||||
// NOTE: Node Credits
|
||||
//
|
||||
|
|
|
@ -56,6 +56,7 @@
|
|||
#include "cryptonote_basic/account.h"
|
||||
#include "cryptonote_basic/cryptonote_basic_impl.h"
|
||||
#include "cryptonote_core/tx_sanity_check.h"
|
||||
#include "cryptonote_core/uptime_proof.h"
|
||||
#include "epee/misc_language.h"
|
||||
#include "net/parse.h"
|
||||
#include "crypto/hash.h"
|
||||
|
@ -3038,17 +3039,19 @@ namespace cryptonote { namespace rpc {
|
|||
entry.decommission_count = info.decommission_count;
|
||||
|
||||
m_core.get_service_node_list().access_proof(sn_info.pubkey, [&entry](const auto &proof) {
|
||||
entry.service_node_version = proof.version;
|
||||
entry.public_ip = epee::string_tools::get_ip_string_from_int32(proof.public_ip);
|
||||
entry.storage_port = proof.storage_port;
|
||||
entry.storage_lmq_port = proof.storage_lmq_port;
|
||||
entry.service_node_version = proof.proof->version;
|
||||
entry.lokinet_version = proof.proof->lokinet_version;
|
||||
entry.storage_server_version = proof.proof->storage_server_version;
|
||||
entry.public_ip = epee::string_tools::get_ip_string_from_int32(proof.proof->public_ip);
|
||||
entry.storage_port = proof.proof->storage_port;
|
||||
entry.storage_lmq_port = proof.proof->storage_lmq_port;
|
||||
entry.storage_server_reachable = proof.storage_server_reachable;
|
||||
entry.pubkey_ed25519 = proof.pubkey_ed25519 ? tools::type_to_hex(proof.pubkey_ed25519) : "";
|
||||
entry.pubkey_ed25519 = proof.proof->pubkey_ed25519 ? tools::type_to_hex(proof.proof->pubkey_ed25519) : "";
|
||||
entry.pubkey_x25519 = proof.pubkey_x25519 ? tools::type_to_hex(proof.pubkey_x25519) : "";
|
||||
entry.quorumnet_port = proof.quorumnet_port;
|
||||
entry.quorumnet_port = proof.proof->qnet_port;
|
||||
|
||||
// NOTE: Service Node Testing
|
||||
entry.last_uptime_proof = proof.timestamp;
|
||||
entry.last_uptime_proof = proof.proof->timestamp;
|
||||
entry.storage_server_reachable = proof.storage_server_reachable;
|
||||
entry.storage_server_reachable_timestamp = proof.storage_server_reachable_timestamp;
|
||||
|
||||
|
@ -3267,7 +3270,7 @@ namespace cryptonote { namespace rpc {
|
|||
}
|
||||
|
||||
namespace {
|
||||
struct version_printer { const std::array<int, 3> &v; };
|
||||
struct version_printer { const std::array<uint16_t, 3> &v; };
|
||||
std::ostream &operator<<(std::ostream &o, const version_printer &vp) { return o << vp.v[0] << '.' << vp.v[1] << '.' << vp.v[2]; }
|
||||
|
||||
// Handles a ping. Returns true if the ping was significant (i.e. first ping after startup, or
|
||||
|
@ -3275,7 +3278,7 @@ namespace cryptonote { namespace rpc {
|
|||
// argument: true if this ping should trigger an immediate proof send (i.e. first ping after
|
||||
// startup or after a ping expiry), false for an ordinary ping.
|
||||
template <typename RPC, typename Success>
|
||||
auto handle_ping(std::array<int, 3> cur_version, std::array<int, 3> required, const char* name, std::atomic<std::time_t>& update, time_t lifetime, Success success)
|
||||
auto handle_ping(std::array<uint16_t, 3> cur_version, std::array<uint16_t, 3> required, const char* name, std::atomic<std::time_t>& update, time_t lifetime, Success success)
|
||||
{
|
||||
typename RPC::response res{};
|
||||
if (cur_version < required) {
|
||||
|
@ -3301,6 +3304,7 @@ namespace cryptonote { namespace rpc {
|
|||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
STORAGE_SERVER_PING::response core_rpc_server::invoke(STORAGE_SERVER_PING::request&& req, rpc_context context)
|
||||
{
|
||||
m_core.ss_version = {req.version_major, req.version_minor, req.version_patch};
|
||||
return handle_ping<STORAGE_SERVER_PING>(
|
||||
{req.version_major, req.version_minor, req.version_patch}, service_nodes::MIN_STORAGE_SERVER_VERSION,
|
||||
"Storage Server", m_core.m_last_storage_server_ping, STORAGE_SERVER_PING_LIFETIME,
|
||||
|
@ -3313,6 +3317,7 @@ namespace cryptonote { namespace rpc {
|
|||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
LOKINET_PING::response core_rpc_server::invoke(LOKINET_PING::request&& req, rpc_context context)
|
||||
{
|
||||
m_core.lokinet_version = req.version;
|
||||
return handle_ping<LOKINET_PING>(
|
||||
req.version, service_nodes::MIN_LOKINET_VERSION,
|
||||
"Lokinet", m_core.m_last_lokinet_ping, LOKINET_PING_LIFETIME,
|
||||
|
|
|
@ -2052,6 +2052,8 @@ namespace rpc {
|
|||
bool earned_downtime_blocks;
|
||||
|
||||
bool service_node_version;
|
||||
bool lokinet_version;
|
||||
bool storage_server_version;
|
||||
bool contributors;
|
||||
bool total_contributed;
|
||||
bool total_reserved;
|
||||
|
@ -2108,6 +2110,8 @@ namespace rpc {
|
|||
uint32_t decommission_count; // The number of times the Service Node has been decommissioned since registration
|
||||
int64_t earned_downtime_blocks; // The number of blocks earned towards decommissioning, or the number of blocks remaining until deregistration if currently decommissioned
|
||||
std::array<uint16_t, 3> service_node_version; // The major, minor, patch version of the Service Node respectively.
|
||||
std::array<uint16_t, 3> lokinet_version; // The major, minor, patch version of the Service Node's lokinet router.
|
||||
std::array<uint16_t, 3> storage_server_version; // The major, minor, patch version of the Service Node's storage server.
|
||||
std::vector<service_node_contributor> contributors; // Array of contributors, contributing to this Service Node.
|
||||
uint64_t total_contributed; // The total amount of Loki in atomic units contributed to this Service Node.
|
||||
uint64_t total_reserved; // The total amount of Loki in atomic units reserved in this Service Node.
|
||||
|
@ -2183,9 +2187,9 @@ namespace rpc {
|
|||
|
||||
struct request
|
||||
{
|
||||
int version_major; // Storage Server Major version
|
||||
int version_minor; // Storage Server Minor version
|
||||
int version_patch; // Storage Server Patch version
|
||||
uint16_t version_major; // Storage Server Major version
|
||||
uint16_t version_minor; // Storage Server Minor version
|
||||
uint16_t version_patch; // Storage Server Patch version
|
||||
uint16_t storage_lmq_port; // Storage Server lmq port to include in uptime proofs
|
||||
KV_MAP_SERIALIZABLE
|
||||
};
|
||||
|
@ -2200,7 +2204,7 @@ namespace rpc {
|
|||
|
||||
struct request
|
||||
{
|
||||
std::array<int, 3> version; // Lokinet version
|
||||
std::array<uint16_t, 3> version; // Lokinet version
|
||||
KV_MAP_SERIALIZABLE
|
||||
};
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "cryptonote_core/blockchain.h"
|
||||
#include "cryptonote_core/tx_pool.h"
|
||||
#include "cryptonote_core/cryptonote_core.h"
|
||||
#include "cryptonote_core/uptime_proof.h"
|
||||
#include "blockchain_utilities/blockchain_objects.h"
|
||||
#include "blockchain_db/testdb.h"
|
||||
|
||||
|
|
|
@ -247,6 +247,12 @@ bool tests::proxy_core::handle_uptime_proof(const cryptonote::NOTIFY_UPTIME_PROO
|
|||
return false; // never relay these for tests.
|
||||
}
|
||||
|
||||
bool tests::proxy_core::handle_btencoded_uptime_proof(const cryptonote::NOTIFY_BTENCODED_UPTIME_PROOF::request &proof, bool &my_uptime_proof_confirmation)
|
||||
{
|
||||
// TODO: add tests for core uptime proof checking.
|
||||
return false; // never relay these for tests.
|
||||
}
|
||||
|
||||
bool tests::proxy_core::get_short_chain_history(std::list<crypto::hash>& ids) {
|
||||
build_short_history(ids, m_lastblk);
|
||||
return true;
|
||||
|
|
|
@ -85,6 +85,7 @@ namespace tests
|
|||
int add_blinks(const std::vector<std::shared_ptr<cryptonote::blink_tx>> &blinks) { return 0; }
|
||||
bool handle_incoming_block(const cryptonote::blobdata& block_blob, const cryptonote::block *block, cryptonote::block_verification_context& bvc, cryptonote::checkpoint_t *checkpoint, bool update_miner_blocktemplate = true);
|
||||
bool handle_uptime_proof(const cryptonote::NOTIFY_UPTIME_PROOF::request &proof, bool &my_uptime_proof_confirmation);
|
||||
bool handle_btencoded_uptime_proof(const cryptonote::NOTIFY_BTENCODED_UPTIME_PROOF::request &proof, bool &my_uptime_proof_confirmation);
|
||||
void pause_mine(){}
|
||||
void resume_mine(){}
|
||||
bool on_idle(){return true;}
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "chaingen.h"
|
||||
#include "block_validation.h"
|
||||
#include "common/util.h"
|
||||
#include "cryptonote_core/uptime_proof.h"
|
||||
|
||||
using namespace cryptonote;
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "chaingen.h"
|
||||
#include "bulletproofs.h"
|
||||
#include "device/device.hpp"
|
||||
#include "cryptonote_core/uptime_proof.h"
|
||||
#include "common/util.h"
|
||||
|
||||
using namespace crypto;
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
#include "chaingen.h"
|
||||
#include "chain_split_1.h"
|
||||
#include "cryptonote_core/uptime_proof.h"
|
||||
|
||||
using namespace cryptonote;
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
#include "chaingen.h"
|
||||
#include "chain_switch_1.h"
|
||||
#include "cryptonote_core/uptime_proof.h"
|
||||
|
||||
using namespace cryptonote;
|
||||
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
#include "cryptonote_basic/cryptonote_basic_impl.h"
|
||||
#include "cryptonote_basic/cryptonote_format_utils.h"
|
||||
#include "cryptonote_basic/miner.h"
|
||||
#include "cryptonote_core/uptime_proof.h"
|
||||
#include "oxen_economy.h"
|
||||
#include "ringct/rctSigs.h"
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
|
||||
#include "cryptonote_basic/cryptonote_basic.h"
|
||||
#include "cryptonote_basic/cryptonote_format_utils.h"
|
||||
#include "cryptonote_core/uptime_proof.h"
|
||||
|
||||
#include "chaingen.h"
|
||||
#include "chaingen_tests_list.h"
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "chaingen_tests_list.h"
|
||||
#include "common/util.h"
|
||||
#include "common/command_line.h"
|
||||
#include "cryptonote_core/uptime_proof.h"
|
||||
#include "transaction_tests.h"
|
||||
|
||||
namespace po = boost::program_options;
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
#include "chaingen.h"
|
||||
#include "double_spend.h"
|
||||
#include "cryptonote_core/uptime_proof.h"
|
||||
|
||||
using namespace cryptonote;
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
#include "chaingen.h"
|
||||
#include "integer_overflow.h"
|
||||
#include "cryptonote_core/uptime_proof.h"
|
||||
|
||||
using namespace cryptonote;
|
||||
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
#include "ringct/rctSigs.h"
|
||||
#include "cryptonote_basic/cryptonote_basic.h"
|
||||
#include "cryptonote_core/uptime_proof.h"
|
||||
#include "multisig/multisig.h"
|
||||
#include "common/apply_permutation.h"
|
||||
#include "common/util.h"
|
||||
|
|
|
@ -35,6 +35,7 @@
|
|||
#include "cryptonote_config.h"
|
||||
#include "cryptonote_core/oxen_name_system.h"
|
||||
#include "cryptonote_core/service_node_list.h"
|
||||
#include "cryptonote_core/uptime_proof.h"
|
||||
#include "oxen_economy.h"
|
||||
#include "common/random.h"
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "rct.h"
|
||||
#include "device/device.hpp"
|
||||
#include "common/util.h"
|
||||
#include "cryptonote_core/uptime_proof.h"
|
||||
|
||||
using namespace crypto;
|
||||
using namespace cryptonote;
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
|
||||
#include "chaingen.h"
|
||||
#include "ring_signature_1.h"
|
||||
#include "cryptonote_core/uptime_proof.h"
|
||||
|
||||
using namespace cryptonote;
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "chaingen.h"
|
||||
#include "tx_validation.h"
|
||||
#include "device/device.hpp"
|
||||
#include "cryptonote_core/uptime_proof.h"
|
||||
|
||||
using namespace crypto;
|
||||
using namespace cryptonote;
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "chaingen.h"
|
||||
#include "v2_tests.h"
|
||||
#include "common/util.h"
|
||||
#include "cryptonote_core/uptime_proof.h"
|
||||
|
||||
using namespace crypto;
|
||||
using namespace cryptonote;
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
//
|
||||
|
||||
#include "wallet_tools.h"
|
||||
#include "cryptonote_core/uptime_proof.h"
|
||||
#include <random>
|
||||
|
||||
using namespace crypto;
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include <memory>
|
||||
|
||||
#include "cryptonote_basic/cryptonote_format_utils.h"
|
||||
#include "cryptonote_core/uptime_proof.h"
|
||||
#include "checkpoints/checkpoints.cpp"
|
||||
#include "blockchain_db/testdb.h"
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "blockchain_db/blockchain_db.h"
|
||||
#include "cryptonote_basic/cryptonote_format_utils.h"
|
||||
#include "cryptonote_basic/hardfork.h"
|
||||
#include "cryptonote_core/uptime_proof.h"
|
||||
#include "blockchain_db/testdb.h"
|
||||
#include "checkpoints/checkpoints.h"
|
||||
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include "cryptonote_core/blockchain.h"
|
||||
#include "cryptonote_core/tx_pool.h"
|
||||
#include "cryptonote_core/cryptonote_core.h"
|
||||
#include "cryptonote_core/uptime_proof.h"
|
||||
#include "blockchain_utilities/blockchain_objects.h"
|
||||
#include "blockchain_db/testdb.h"
|
||||
|
||||
|
|
|
@ -64,6 +64,7 @@ public:
|
|||
int add_blinks(const std::vector<std::shared_ptr<cryptonote::blink_tx>> &blinks) { return 0; }
|
||||
bool handle_incoming_block(const cryptonote::blobdata& block_blob, const cryptonote::block *block, cryptonote::block_verification_context& bvc, cryptonote::checkpoint_t const *checkpoint, bool update_miner_blocktemplate = true) { return true; }
|
||||
bool handle_uptime_proof(const cryptonote::NOTIFY_UPTIME_PROOF::request &proof, bool &my_uptime_proof_confirmation) { return false; }
|
||||
bool handle_btencoded_uptime_proof(const cryptonote::NOTIFY_BTENCODED_UPTIME_PROOF::request &proof, bool &my_uptime_proof_confirmation) { return false; }
|
||||
void pause_mine(){}
|
||||
void resume_mine(){}
|
||||
bool on_idle(){return true;}
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "cryptonote_core/cryptonote_core.h"
|
||||
#include "cryptonote_core/tx_pool.h"
|
||||
#include "cryptonote_core/blockchain.h"
|
||||
#include "cryptonote_core/uptime_proof.h"
|
||||
#include "blockchain_db/testdb.h"
|
||||
|
||||
#include "blockchain_utilities/blockchain_objects.h"
|
||||
|
|
Loading…
Reference in a new issue