Serialize the uptime proof using btencoding

This commit is contained in:
Sean Darcy 2020-12-17 16:52:16 +11:00
parent c0de851d1d
commit b720e8ace6
20 changed files with 426 additions and 35 deletions

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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
*

View File

@ -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");

View File

@ -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.

View File

@ -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}},

View File

@ -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;
}
}

View 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> 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;
};
}

View File

@ -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()

View File

@ -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
};
};
/************************************************************************/
/* */
/************************************************************************/

View File

@ -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);

View File

@ -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);

View File

@ -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;
}
};
}

View File

@ -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,

View File

@ -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
};

View File

@ -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;

View File

@ -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;}

View File

@ -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;}