mirror of https://github.com/oxen-io/oxen-core.git
Serialize the uptime proof using btencoding
This commit is contained in:
parent
c0de851d1d
commit
b720e8ace6
|
@ -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,7 +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_VERSION cryptonote::network_version_17
|
||||
#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"
|
||||
|
@ -1930,10 +1931,21 @@ 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, ss_version, m_quorumnet_port, lokinet_version);
|
||||
|
||||
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) {
|
||||
MGINFO("Generating Uptime Proof");
|
||||
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 {
|
||||
MGINFO("Generating BT-Encoded Uptime Proof");
|
||||
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 +1965,22 @@ 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 = 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);
|
||||
bool result = m_service_node_list.handle_btencoded_uptime_proof(proof, my_uptime_proof_confirmation, pkey);
|
||||
if (result && m_service_node_list.is_service_node(proof.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;
|
||||
|
|
|
@ -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
|
||||
*
|
||||
|
|
|
@ -56,8 +56,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,22 +2745,20 @@ 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, proof.storage_version, proof.lokinet_version);
|
||||
size_t buf_size = buf.size();
|
||||
|
||||
//TODO - Can be removed post-HF17
|
||||
if (hf_version < HF_VERSION_PROOF_VERSION)
|
||||
buf_size -= (sizeof(proof.storage_version) + sizeof(proof.lokinet_version));
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
cryptonote::NOTIFY_UPTIME_PROOF::request 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
|
||||
uint32_t public_ip, uint16_t storage_port, uint16_t storage_lmq_port, uint16_t quorumnet_port) const
|
||||
{
|
||||
assert(m_service_node_keys);
|
||||
const auto& keys = *m_service_node_keys;
|
||||
|
@ -2772,16 +2772,18 @@ namespace service_nodes
|
|||
result.qnet_port = quorumnet_port;
|
||||
result.pubkey_ed25519 = keys.pub_ed25519;
|
||||
|
||||
result.storage_version = ss_version;
|
||||
result.lokinet_version = lokinet_version;
|
||||
|
||||
|
||||
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
|
||||
|
@ -2864,6 +2866,7 @@ namespace service_nodes
|
|||
|
||||
#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();
|
||||
|
@ -2883,7 +2886,93 @@ 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");
|
||||
|
||||
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, proof.public_ip, proof.storage_port, proof.storage_lmq_port, proof.qnet_port, proof.snode_version, proof.pubkey_ed25519, derived_x25519_pubkey))
|
||||
iproof.store(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] = {proof.pubkey, now};
|
||||
|
||||
if (derived_x25519_pubkey && (old_x25519 != derived_x25519_pubkey))
|
||||
x25519_pkey = derived_x25519_pubkey;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool service_node_list::handle_btencoded_uptime_proof(const 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.snode_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");
|
||||
|
|
|
@ -34,10 +34,13 @@
|
|||
#include "serialization/serialization.h"
|
||||
#include "cryptonote_basic/cryptonote_basic_impl.h"
|
||||
#include "cryptonote_core/service_node_rules.h"
|
||||
#include "cryptonote_core/uptime_proof.h"
|
||||
#include "cryptonote_core/service_node_voting.h"
|
||||
#include "cryptonote_core/service_node_quorum_cop.h"
|
||||
#include "common/util.h"
|
||||
|
||||
#include <lokimq/bt_serialize.h>
|
||||
|
||||
namespace cryptonote
|
||||
{
|
||||
class Blockchain;
|
||||
|
@ -45,6 +48,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);
|
||||
|
@ -511,15 +519,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,
|
||||
std::array<uint16_t, 3> ss_version,
|
||||
uint16_t quorumnet_port,
|
||||
std::array<uint16_t, 3> lokinet_version) const;
|
||||
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(const 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.
|
||||
|
|
|
@ -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,7 +224,7 @@ namespace service_nodes {
|
|||
};
|
||||
|
||||
constexpr proof_version MIN_UPTIME_PROOF_VERSIONS[] = {
|
||||
{cryptonote::network_version_17, {8,1,5}},
|
||||
{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}},
|
||||
|
|
|
@ -0,0 +1,113 @@
|
|||
#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) : snode_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_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("version"));
|
||||
int k = 0;
|
||||
for (lokimq::bt_value const &i: bt_version){
|
||||
snode_version[k++] = static_cast<uint16_t>(lokimq::get_int<unsigned>(i));
|
||||
}
|
||||
//timestamp
|
||||
timestamp = lokimq::get_int<unsigned>(bt_proof.at("timestamp"));
|
||||
//public_ip
|
||||
bool succeeded = epee::string_tools::get_ip_int32_from_string(public_ip, var::get<std::string>(bt_proof.at("public_ip")));
|
||||
//storage_port
|
||||
storage_port = static_cast<uint16_t>(lokimq::get_int<unsigned>(bt_proof.at("storage_port")));
|
||||
//pubkey_ed25519
|
||||
pubkey_ed25519 = tools::make_from_guts<crypto::ed25519_public_key>(var::get<std::string>(bt_proof.at("pubkey_ed25519")));
|
||||
//pubkey
|
||||
if (auto it = bt_proof.find("pubkey"); it != bt_proof.end())
|
||||
pubkey = tools::make_from_guts<crypto::public_key>(var::get<std::string>(bt_proof.at("pubkey")));
|
||||
else
|
||||
std::memcpy(pubkey.data, pubkey_ed25519.data, 32);
|
||||
//qnet_port
|
||||
qnet_port = lokimq::get_int<unsigned>(bt_proof.at("qnet_port"));
|
||||
//storage_lmq_port
|
||||
storage_lmq_port = lokimq::get_int<unsigned>(bt_proof.at("storage_lmq_port"));
|
||||
//storage_version
|
||||
const lokimq::bt_list& bt_storage_version = var::get<lokimq::bt_list>(bt_proof.at("storage_version"));
|
||||
k = 0;
|
||||
for (lokimq::bt_value const &i: bt_storage_version){
|
||||
storage_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("lokinet_version"));
|
||||
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", lokimq::bt_list{{snode_version[0], snode_version[1], snode_version[2]}}},
|
||||
{"timestamp", timestamp},
|
||||
{"public_ip", epee::string_tools::get_ip_string_from_int32(public_ip)},
|
||||
{"storage_port", storage_port},
|
||||
{"pubkey_ed25519", tools::view_guts(pubkey_ed25519)},
|
||||
{"qnet_port", qnet_port},
|
||||
{"storage_lmq_port", storage_lmq_port},
|
||||
{"storage_version", lokimq::bt_list{{storage_version[0], storage_version[1], storage_version[2]}}},
|
||||
{"lokinet_version", lokimq::bt_list{{lokinet_version[0], lokinet_version[1], lokinet_version[2]}}},
|
||||
};
|
||||
|
||||
if (pubkey == pubkey_ed25519) encoded_proof["pubkey"] = 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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -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> snode_version;
|
||||
std::array<uint16_t, 3> storage_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(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;
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -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()
|
||||
|
|
|
@ -252,8 +252,6 @@ namespace cryptonote
|
|||
struct request
|
||||
{
|
||||
std::array<uint16_t, 3> snode_version;
|
||||
std::array<uint16_t, 3> storage_version;
|
||||
std::array<uint16_t, 3> lokinet_version;
|
||||
|
||||
uint64_t timestamp;
|
||||
crypto::public_key pubkey;
|
||||
|
@ -269,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;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -3267,7 +3267,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 +3275,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) {
|
||||
|
@ -3314,7 +3314,7 @@ namespace cryptonote { namespace rpc {
|
|||
//------------------------------------------------------------------------------------------------------------------------------
|
||||
LOKINET_PING::response core_rpc_server::invoke(LOKINET_PING::request&& req, rpc_context context)
|
||||
{
|
||||
std::copy(req.version.begin(),req.version.end(),m_core.lokinet_version.begin());
|
||||
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,
|
||||
|
|
|
@ -2183,9 +2183,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 +2200,7 @@ namespace rpc {
|
|||
|
||||
struct request
|
||||
{
|
||||
std::array<int, 3> version; // Lokinet version
|
||||
std::array<uint16_t, 3> version; // Lokinet version
|
||||
KV_MAP_SERIALIZABLE
|
||||
};
|
||||
|
||||
|
|
|
@ -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;}
|
||||
|
|
|
@ -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;}
|
||||
|
|
Loading…
Reference in New Issue