From c0de851d1d6846ffca87a1c2ca3fac4079c0d96f Mon Sep 17 00:00:00 2001 From: Sean Darcy Date: Thu, 3 Dec 2020 17:01:54 +1100 Subject: [PATCH 1/4] Added versions for SS and lokinet to be saved to core, generate_uptime_proof adds them to the proof --- src/cryptonote_config.h | 1 + src/cryptonote_core/cryptonote_core.cpp | 2 +- src/cryptonote_core/cryptonote_core.h | 4 ++++ src/cryptonote_core/service_node_list.cpp | 13 +++++++++---- src/cryptonote_core/service_node_list.h | 4 +++- src/cryptonote_core/service_node_rules.h | 1 + src/cryptonote_protocol/cryptonote_protocol_defs.h | 2 ++ src/rpc/core_rpc_server.cpp | 2 ++ 8 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/cryptonote_config.h b/src/cryptonote_config.h index 5c99fe9f6..481bc932f 100644 --- a/src/cryptonote_config.h +++ b/src/cryptonote_config.h @@ -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_VERSION cryptonote::network_version_17 #define PER_KB_FEE_QUANTIZATION_DECIMALS 8 diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp index 64b459a1e..2d5dd3a11 100644 --- a/src/cryptonote_core/cryptonote_core.cpp +++ b/src/cryptonote_core/cryptonote_core.cpp @@ -1930,7 +1930,7 @@ 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); + 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); diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h index c6b043a90..a9d2c09ec 100644 --- a/src/cryptonote_core/cryptonote_core.h +++ b/src/cryptonote_core/cryptonote_core.h @@ -1163,6 +1163,10 @@ namespace cryptonote std::unordered_map& _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 ss_version; + std::array lokinet_version; + private: /** diff --git a/src/cryptonote_core/service_node_list.cpp b/src/cryptonote_core/service_node_list.cpp index 87171c892..f1d7d83f1 100644 --- a/src/cryptonote_core/service_node_list.cpp +++ b/src/cryptonote_core/service_node_list.cpp @@ -2745,11 +2745,12 @@ namespace service_nodes static crypto::hash hash_uptime_proof(const cryptonote::NOTIFY_UPTIME_PROOF::request &proof, uint8_t hf_version) { - 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); + 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(); - if (hf_version < cryptonote::network_version_15_lns) // TODO - can be removed post-HF15 - buf_size -= sizeof(proof.storage_lmq_port); + //TODO - Can be removed post-HF17 + if (hf_version < HF_VERSION_PROOF_VERSION) + buf_size -= (sizeof(proof.storage_version) + sizeof(proof.lokinet_version)); crypto::hash result; crypto::cn_fast_hash(buf.data(), buf_size, result); @@ -2757,7 +2758,7 @@ namespace service_nodes } cryptonote::NOTIFY_UPTIME_PROOF::request service_node_list::generate_uptime_proof( - uint32_t public_ip, uint16_t storage_port, uint16_t storage_lmq_port, uint16_t quorumnet_port) const + uint32_t public_ip, uint16_t storage_port, uint16_t storage_lmq_port, std::array ss_version, uint16_t quorumnet_port, std::array lokinet_version) const { assert(m_service_node_keys); const auto& keys = *m_service_node_keys; @@ -2771,6 +2772,10 @@ 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::generate_signature(hash, keys.pub, keys.key, result.sig); crypto_sign_detached(result.sig_ed25519.data, NULL, reinterpret_cast(hash.data), sizeof(hash.data), keys.key_ed25519.data); diff --git a/src/cryptonote_core/service_node_list.h b/src/cryptonote_core/service_node_list.h index d34daec6e..e2553d656 100644 --- a/src/cryptonote_core/service_node_list.h +++ b/src/cryptonote_core/service_node_list.h @@ -515,7 +515,9 @@ namespace service_nodes 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; + std::array ss_version, + uint16_t quorumnet_port, + std::array lokinet_version) const; bool handle_uptime_proof(cryptonote::NOTIFY_UPTIME_PROOF::request const &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); diff --git a/src/cryptonote_core/service_node_rules.h b/src/cryptonote_core/service_node_rules.h index 793f11681..7601eb10f 100644 --- a/src/cryptonote_core/service_node_rules.h +++ b/src/cryptonote_core/service_node_rules.h @@ -224,6 +224,7 @@ namespace service_nodes { }; constexpr proof_version MIN_UPTIME_PROOF_VERSIONS[] = { + {cryptonote::network_version_17, {8,1,5}}, {cryptonote::network_version_16_pulse, {8,1,0}}, {cryptonote::network_version_15_lns, {7,1,2}}, {cryptonote::network_version_14_blink, {6,1,0}}, diff --git a/src/cryptonote_protocol/cryptonote_protocol_defs.h b/src/cryptonote_protocol/cryptonote_protocol_defs.h index df34b65db..d72de12cd 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_defs.h +++ b/src/cryptonote_protocol/cryptonote_protocol_defs.h @@ -252,6 +252,8 @@ namespace cryptonote struct request { std::array snode_version; + std::array storage_version; + std::array lokinet_version; uint64_t timestamp; crypto::public_key pubkey; diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index e06cf50c0..a6eb29b70 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -3301,6 +3301,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( {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 +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()); return handle_ping( req.version, service_nodes::MIN_LOKINET_VERSION, "Lokinet", m_core.m_last_lokinet_ping, LOKINET_PING_LIFETIME, From b720e8ace69da1742dfcd8ba1a6833996ad49fac Mon Sep 17 00:00:00 2001 From: Sean Darcy Date: Thu, 17 Dec 2020 16:52:16 +1100 Subject: [PATCH 2/4] Serialize the uptime proof using btencoding --- src/common/string_util.h | 14 +++ src/cryptonote_config.h | 2 +- src/cryptonote_core/CMakeLists.txt | 3 +- src/cryptonote_core/cryptonote_core.cpp | 34 ++++- src/cryptonote_core/cryptonote_core.h | 9 ++ src/cryptonote_core/service_node_list.cpp | 119 +++++++++++++++--- src/cryptonote_core/service_node_list.h | 22 +++- src/cryptonote_core/service_node_rules.h | 6 +- src/cryptonote_core/uptime_proof.cpp | 113 +++++++++++++++++ src/cryptonote_core/uptime_proof.h | 41 ++++++ .../cryptonote_protocol_defs.cpp | 7 ++ .../cryptonote_protocol_defs.h | 21 +++- .../cryptonote_protocol_handler.h | 3 + .../cryptonote_protocol_handler.inl | 40 ++++++ .../cryptonote_protocol_handler_common.h | 5 + src/rpc/core_rpc_server.cpp | 6 +- src/rpc/core_rpc_server_commands_defs.h | 8 +- tests/core_proxy/core_proxy.cpp | 6 + tests/core_proxy/core_proxy.h | 1 + tests/unit_tests/node_server.cpp | 1 + 20 files changed, 426 insertions(+), 35 deletions(-) create mode 100644 src/cryptonote_core/uptime_proof.cpp create mode 100644 src/cryptonote_core/uptime_proof.h diff --git a/src/common/string_util.h b/src/common/string_util.h index a4b089e37..95b4ea070 100644 --- a/src/common/string_util.h +++ b/src/common/string_util.h @@ -1,6 +1,7 @@ #pragma once #include #include +#include #include #include #include @@ -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 +T make_from_guts(std::string_view s) { + static_assert((std::is_standard_layout_v && std::has_unique_object_representations_v) + || epee::is_byte_spannable, + "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. diff --git a/src/cryptonote_config.h b/src/cryptonote_config.h index 481bc932f..3d8c8864d 100644 --- a/src/cryptonote_config.h +++ b/src/cryptonote_config.h @@ -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 diff --git a/src/cryptonote_core/CMakeLists.txt b/src/cryptonote_core/CMakeLists.txt index 946e338d9..e022212fc 100644 --- a/src/cryptonote_core/CMakeLists.txt +++ b/src/cryptonote_core/CMakeLists.txt @@ -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 diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp index 2d5dd3a11..cefb0a0cd 100644 --- a/src/cryptonote_core/cryptonote_core.cpp +++ b/src/cryptonote_core/cryptonote_core.cpp @@ -49,6 +49,7 @@ extern "C" { #include #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(req.sig); + proof.sig_ed25519 = tools::make_from_guts(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> txs; diff --git a/src/cryptonote_core/cryptonote_core.h b/src/cryptonote_core/cryptonote_core.h index a9d2c09ec..0bf4868f2 100644 --- a/src/cryptonote_core/cryptonote_core.h +++ b/src/cryptonote_core/cryptonote_core.h @@ -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 * diff --git a/src/cryptonote_core/service_node_list.cpp b/src/cryptonote_core/service_node_list.cpp index f1d7d83f1..7991f2403 100644 --- a/src/cryptonote_core/service_node_list.cpp +++ b/src/cryptonote_core/service_node_list.cpp @@ -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 #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 ss_version, uint16_t quorumnet_port, std::array 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(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 ss_version, uint16_t quorumnet_port, std::array 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(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"); diff --git a/src/cryptonote_core/service_node_list.h b/src/cryptonote_core/service_node_list.h index e2553d656..549ff6840 100644 --- a/src/cryptonote_core/service_node_list.h +++ b/src/cryptonote_core/service_node_list.h @@ -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 + 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(-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 ss_version, - uint16_t quorumnet_port, - std::array 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 ss_version, uint16_t quorumnet_port, std::array 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. diff --git a/src/cryptonote_core/service_node_rules.h b/src/cryptonote_core/service_node_rules.h index 7601eb10f..5e11d6814 100644 --- a/src/cryptonote_core/service_node_rules.h +++ b/src/cryptonote_core/service_node_rules.h @@ -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 MIN_STORAGE_SERVER_VERSION{{2, 0, 7}}; - constexpr std::array MIN_LOKINET_VERSION{{0, 8, 0}}; + constexpr std::array MIN_STORAGE_SERVER_VERSION{{2, 0, 7}}; + constexpr std::array 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}}, diff --git a/src/cryptonote_core/uptime_proof.cpp b/src/cryptonote_core/uptime_proof.cpp new file mode 100644 index 000000000..e05ce6c34 --- /dev/null +++ b/src/cryptonote_core/uptime_proof.cpp @@ -0,0 +1,113 @@ +#include "uptime_proof.h" +#include "common/string_util.h" +#include "version.h" + +extern "C" +{ +#include +} + +#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 ss_version, uint16_t quorumnet_port, const std::array lokinet_version, const service_nodes::service_node_keys& keys) : snode_version{OXEN_VERSION}, pubkey{keys.pub}, timestamp{static_cast(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(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(serialized_proof); + //snode_version + const lokimq::bt_list& bt_version = var::get(bt_proof.at("version")); + int k = 0; + for (lokimq::bt_value const &i: bt_version){ + snode_version[k++] = static_cast(lokimq::get_int(i)); + } + //timestamp + timestamp = lokimq::get_int(bt_proof.at("timestamp")); + //public_ip + bool succeeded = epee::string_tools::get_ip_int32_from_string(public_ip, var::get(bt_proof.at("public_ip"))); + //storage_port + storage_port = static_cast(lokimq::get_int(bt_proof.at("storage_port"))); + //pubkey_ed25519 + pubkey_ed25519 = tools::make_from_guts(var::get(bt_proof.at("pubkey_ed25519"))); + //pubkey + if (auto it = bt_proof.find("pubkey"); it != bt_proof.end()) + pubkey = tools::make_from_guts(var::get(bt_proof.at("pubkey"))); + else + std::memcpy(pubkey.data, pubkey_ed25519.data, 32); + //qnet_port + qnet_port = lokimq::get_int(bt_proof.at("qnet_port")); + //storage_lmq_port + storage_lmq_port = lokimq::get_int(bt_proof.at("storage_lmq_port")); + //storage_version + const lokimq::bt_list& bt_storage_version = var::get(bt_proof.at("storage_version")); + k = 0; + for (lokimq::bt_value const &i: bt_storage_version){ + storage_version[k++] = static_cast(lokimq::get_int(i)); + } + //lokinet_version + const lokimq::bt_list& bt_lokinet_version = var::get(bt_proof.at("lokinet_version")); + k = 0; + for (lokimq::bt_value const &i: bt_lokinet_version){ + lokinet_version[k++] = static_cast(lokimq::get_int(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; +} + +} + + diff --git a/src/cryptonote_core/uptime_proof.h b/src/cryptonote_core/uptime_proof.h new file mode 100644 index 000000000..47fdce60e --- /dev/null +++ b/src/cryptonote_core/uptime_proof.h @@ -0,0 +1,41 @@ +#pragma once + +#include "service_node_list.h" +#include "../cryptonote_protocol/cryptonote_protocol_defs.h" +#include + +namespace uptime_proof +{ + +class Proof +{ + +public: + std::array snode_version; + std::array storage_version; + std::array 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 ss_version, uint16_t quorumnet_port, std::array 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; +}; + + + +} diff --git a/src/cryptonote_protocol/cryptonote_protocol_defs.cpp b/src/cryptonote_protocol/cryptonote_protocol_defs.cpp index cb412d85a..7be04b8e2 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_defs.cpp +++ b/src/cryptonote_protocol/cryptonote_protocol_defs.cpp @@ -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() diff --git a/src/cryptonote_protocol/cryptonote_protocol_defs.h b/src/cryptonote_protocol/cryptonote_protocol_defs.h index d72de12cd..16802124e 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_defs.h +++ b/src/cryptonote_protocol/cryptonote_protocol_defs.h @@ -252,8 +252,6 @@ namespace cryptonote struct request { std::array snode_version; - std::array storage_version; - std::array 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 + }; + }; + /************************************************************************/ /* */ /************************************************************************/ diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.h b/src/cryptonote_protocol/cryptonote_protocol_handler.h index 95b133b80..c428e9b46 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_handler.h +++ b/src/cryptonote_protocol/cryptonote_protocol_handler.h @@ -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); diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl index 2f33db0a4..15606a59d 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl +++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl @@ -876,6 +876,39 @@ namespace cryptonote } return 1; } + //------------------------------------------------------------------------------------------------------------------------ + template + int t_cryptonote_protocol_handler::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 @@ -2526,6 +2559,13 @@ skip: } //------------------------------------------------------------------------------------------------------------------------ template + bool t_cryptonote_protocol_handler::relay_btencoded_uptime_proof(NOTIFY_BTENCODED_UPTIME_PROOF::request& arg, cryptonote_connection_context& exclude_context) + { + bool result = relay_to_synchronized_peers(arg, exclude_context); + return result; + } + //------------------------------------------------------------------------------------------------------------------------ + template bool t_cryptonote_protocol_handler::relay_service_node_votes(NOTIFY_NEW_SERVICE_NODE_VOTE::request& arg, cryptonote_connection_context& exclude_context) { bool result = relay_to_synchronized_peers(arg, exclude_context); diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler_common.h b/src/cryptonote_protocol/cryptonote_protocol_handler_common.h index fef060e48..51ed6eb75 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_handler_common.h +++ b/src/cryptonote_protocol/cryptonote_protocol_handler_common.h @@ -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; + } }; } diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index a6eb29b70..2ba788cd9 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -3267,7 +3267,7 @@ namespace cryptonote { namespace rpc { } namespace { - struct version_printer { const std::array &v; }; + struct version_printer { const std::array &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 - auto handle_ping(std::array cur_version, std::array required, const char* name, std::atomic& update, time_t lifetime, Success success) + auto handle_ping(std::array cur_version, std::array required, const char* name, std::atomic& 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( req.version, service_nodes::MIN_LOKINET_VERSION, "Lokinet", m_core.m_last_lokinet_ping, LOKINET_PING_LIFETIME, diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h index fa2b4ba88..ec67b6245 100644 --- a/src/rpc/core_rpc_server_commands_defs.h +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -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 version; // Lokinet version + std::array version; // Lokinet version KV_MAP_SERIALIZABLE }; diff --git a/tests/core_proxy/core_proxy.cpp b/tests/core_proxy/core_proxy.cpp index 9ee578f0a..c1ed48b34 100644 --- a/tests/core_proxy/core_proxy.cpp +++ b/tests/core_proxy/core_proxy.cpp @@ -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& ids) { build_short_history(ids, m_lastblk); return true; diff --git a/tests/core_proxy/core_proxy.h b/tests/core_proxy/core_proxy.h index 60954f9ba..90e8f3c5a 100644 --- a/tests/core_proxy/core_proxy.h +++ b/tests/core_proxy/core_proxy.h @@ -85,6 +85,7 @@ namespace tests int add_blinks(const std::vector> &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;} diff --git a/tests/unit_tests/node_server.cpp b/tests/unit_tests/node_server.cpp index fa6d84ea6..02e12286d 100644 --- a/tests/unit_tests/node_server.cpp +++ b/tests/unit_tests/node_server.cpp @@ -64,6 +64,7 @@ public: int add_blinks(const std::vector> &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;} From 2ba4438e6a02c2fa267ac38f065c0ccc2f40211e Mon Sep 17 00:00:00 2001 From: Sean Darcy Date: Mon, 25 Jan 2021 11:50:34 +1100 Subject: [PATCH 3/4] RPC to return SS and lokinet versions, renaming variables --- src/blockchain_db/lmdb/db_lmdb.cpp | 39 ++++++++++++++++++++--- src/cryptonote_core/service_node_list.cpp | 17 ++++++++-- src/cryptonote_core/service_node_list.h | 5 +-- src/cryptonote_core/uptime_proof.cpp | 10 +++--- src/cryptonote_core/uptime_proof.h | 4 +-- src/daemon/rpc_command_executor.cpp | 6 ++++ src/rpc/core_rpc_server.cpp | 2 ++ src/rpc/core_rpc_server_commands_defs.h | 4 +++ 8 files changed, 70 insertions(+), 17 deletions(-) diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp index 37a373b58..e11b0f2dd 100644 --- a/src/blockchain_db/lmdb/db_lmdb.cpp +++ b/src/blockchain_db/lmdb/db_lmdb.cpp @@ -6240,10 +6240,10 @@ void BlockchainLMDB::clear_service_node_data() } } -struct service_node_proof_serialized +struct 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() = default; + service_node_proof_serialized_old(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)}, @@ -6262,7 +6262,9 @@ struct service_node_proof_serialized 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.update_pubkey(pubkey_ed25519); } operator service_nodes::proof_info() const @@ -6280,7 +6282,30 @@ struct service_node_proof_serialized 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(info.storage_server_version[0]), native_to_little(info.storage_server_version[1]), native_to_little(info.storage_server_version[2])}, + lokinet_version{native_to_little(info.lokinet_version[0]), native_to_little(info.lokinet_version[1]), native_to_little(info.lokinet_version[2])} + {} + uint16_t storage_server_version[3]; + uint16_t lokinet_version[3]; + char _padding[4]; + + void update(service_nodes::proof_info& info) const { + service_node_proof_serialized_old::update(info); + for (size_t i = 0; i < info.storage_server_version.size(); i++) + { + info.storage_server_version[i] = little_to_native(storage_server_version[i]); + info.lokinet_version[i] = little_to_native(lokinet_version[i]); + } + } +}; + +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 +6323,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(v.mv_data)->update(proof); + if (v.mv_size == sizeof(service_node_proof_serialized_old)) + static_cast(v.mv_data)->update(proof); + else + static_cast(v.mv_data)->update(proof); + return true; } diff --git a/src/cryptonote_core/service_node_list.cpp b/src/cryptonote_core/service_node_list.cpp index 7991f2403..f072aad21 100644 --- a/src/cryptonote_core/service_node_list.cpp +++ b/src/cryptonote_core/service_node_list.cpp @@ -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" @@ -2820,6 +2821,8 @@ namespace service_nodes uint16_t s_lmq_port, uint16_t q_port, std::array ver, + std::array ss_ver, + std::array lokinet_ver, const crypto::ed25519_public_key& pk_ed, const crypto::x25519_public_key& pk_x2) { @@ -2830,6 +2833,8 @@ namespace service_nodes 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(storage_server_version, ss_ver); + update_db |= update_val(lokinet_version, lokinet_ver); update_db |= update_val(pubkey_ed25519, pk_ed); effective_timestamp = timestamp; pubkey_x25519 = pk_x2; @@ -2869,6 +2874,7 @@ namespace service_nodes //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) { + MGINFO("Received uptime proof from: " << x25519_pkey); uint8_t const hf_version = m_blockchain.get_current_hard_fork_version(); uint64_t const now = time(nullptr); @@ -2931,7 +2937,7 @@ namespace 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)) + if (iproof.update(now, proof.public_ip, proof.storage_port, proof.storage_lmq_port, proof.qnet_port, proof.snode_version, std::array{0,0,0}, std::array{0,0,0}, proof.pubkey_ed25519, derived_x25519_pubkey)) iproof.store(proof.pubkey, m_blockchain); if ((uint64_t) x25519_map_last_pruned + X25519_MAP_PRUNING_INTERVAL <= now) @@ -2955,6 +2961,11 @@ namespace service_nodes bool service_node_list::handle_btencoded_uptime_proof(const uptime_proof::Proof &proof, bool &my_uptime_proof_confirmation, crypto::x25519_public_key &x25519_pkey) { + MGINFO("Received btencoded uptime proof from: " << proof.pubkey); + MGINFO("Timestamp: " << proof.timestamp); + MGINFO("Public IP: " << proof.public_ip ); + MGINFO("Storage Server Version: " << tools::join(".", proof.storage_server_version) ); + MGINFO("Lokinet Router Version: " << tools::join(".", proof.lokinet_version) ); uint8_t const hf_version = m_blockchain.get_current_hard_fork_version(); uint64_t const now = time(nullptr); @@ -2963,7 +2974,7 @@ namespace service_nodes 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) + 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)) @@ -3017,7 +3028,7 @@ namespace 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)) + if (iproof.update(now, proof.public_ip, proof.storage_port, proof.storage_lmq_port, proof.qnet_port, proof.version, proof.storage_server_version, proof.lokinet_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) diff --git a/src/cryptonote_core/service_node_list.h b/src/cryptonote_core/service_node_list.h index 549ff6840..a1329828f 100644 --- a/src/cryptonote_core/service_node_list.h +++ b/src/cryptonote_core/service_node_list.h @@ -34,7 +34,6 @@ #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" @@ -162,6 +161,8 @@ namespace service_nodes uint16_t storage_lmq_port = 0; uint16_t quorumnet_port = 0; std::array version{{0,0,0}}; + std::array storage_server_version{{0,0,0}}; + std::array lokinet_version{{0,0,0}}; crypto::ed25519_public_key pubkey_ed25519 = crypto::ed25519_public_key::null(); // Derived from pubkey_ed25519, not serialized @@ -176,7 +177,7 @@ 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, uint32_t ip, uint16_t s_port, uint16_t s_lmq_port, uint16_t q_port, std::array ver, const crypto::ed25519_public_key &pk_ed, const crypto::x25519_public_key &pk_x2); + bool update(uint64_t ts, uint32_t ip, uint16_t s_port, uint16_t s_lmq_port, uint16_t q_port, std::array ver, std::array ss_ver, std::array lokinet_ver, const crypto::ed25519_public_key &pk_ed, const crypto::x25519_public_key &pk_x2); // Stores this record in the database. void store(const crypto::public_key &pubkey, cryptonote::Blockchain &blockchain); diff --git a/src/cryptonote_core/uptime_proof.cpp b/src/cryptonote_core/uptime_proof.cpp index e05ce6c34..08d99c39f 100644 --- a/src/cryptonote_core/uptime_proof.cpp +++ b/src/cryptonote_core/uptime_proof.cpp @@ -14,7 +14,7 @@ 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 ss_version, uint16_t quorumnet_port, const std::array lokinet_version, const service_nodes::service_node_keys& keys) : snode_version{OXEN_VERSION}, pubkey{keys.pub}, timestamp{static_cast(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} +Proof::Proof(uint32_t sn_public_ip, uint16_t sn_storage_port, uint16_t sn_storage_lmq_port, const std::array ss_version, uint16_t quorumnet_port, const std::array lokinet_version, const service_nodes::service_node_keys& keys) : version{OXEN_VERSION}, pubkey{keys.pub}, timestamp{static_cast(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(); @@ -32,7 +32,7 @@ Proof::Proof(const std::string& serialized_proof) const lokimq::bt_list& bt_version = var::get(bt_proof.at("version")); int k = 0; for (lokimq::bt_value const &i: bt_version){ - snode_version[k++] = static_cast(lokimq::get_int(i)); + version[k++] = static_cast(lokimq::get_int(i)); } //timestamp timestamp = lokimq::get_int(bt_proof.at("timestamp")); @@ -55,7 +55,7 @@ Proof::Proof(const std::string& serialized_proof) const lokimq::bt_list& bt_storage_version = var::get(bt_proof.at("storage_version")); k = 0; for (lokimq::bt_value const &i: bt_storage_version){ - storage_version[k++] = static_cast(lokimq::get_int(i)); + storage_server_version[k++] = static_cast(lokimq::get_int(i)); } //lokinet_version const lokimq::bt_list& bt_lokinet_version = var::get(bt_proof.at("lokinet_version")); @@ -82,14 +82,14 @@ crypto::hash Proof::hash_uptime_proof() const 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]}}}, + {"version", lokimq::bt_list{{version[0], version[1], 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]}}}, + {"storage_version", lokimq::bt_list{{storage_server_version[0], storage_server_version[1], storage_server_version[2]}}}, {"lokinet_version", lokimq::bt_list{{lokinet_version[0], lokinet_version[1], lokinet_version[2]}}}, }; diff --git a/src/cryptonote_core/uptime_proof.h b/src/cryptonote_core/uptime_proof.h index 47fdce60e..db93ccfbf 100644 --- a/src/cryptonote_core/uptime_proof.h +++ b/src/cryptonote_core/uptime_proof.h @@ -11,8 +11,8 @@ class Proof { public: - std::array snode_version; - std::array storage_version; + std::array version; + std::array storage_server_version; std::array lokinet_version; uint64_t timestamp; diff --git a/src/daemon/rpc_command_executor.cpp b/src/daemon/rpc_command_executor.cpp index d3ef4e630..d9b523575 100644 --- a/src/daemon/rpc_command_executor.cpp +++ b/src/daemon/rpc_command_executor.cpp @@ -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 // diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index 2ba788cd9..d6c3d4312 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -3039,6 +3039,8 @@ namespace cryptonote { namespace rpc { m_core.get_service_node_list().access_proof(sn_info.pubkey, [&entry](const auto &proof) { entry.service_node_version = proof.version; + entry.lokinet_version = proof.lokinet_version; + entry.storage_server_version = proof.storage_server_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; diff --git a/src/rpc/core_rpc_server_commands_defs.h b/src/rpc/core_rpc_server_commands_defs.h index ec67b6245..ce4c18243 100644 --- a/src/rpc/core_rpc_server_commands_defs.h +++ b/src/rpc/core_rpc_server_commands_defs.h @@ -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 service_node_version; // The major, minor, patch version of the Service Node respectively. + std::array lokinet_version; // The major, minor, patch version of the Service Node's lokinet router. + std::array storage_server_version; // The major, minor, patch version of the Service Node's storage server. std::vector 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. From 90232dd217063ade263cc9be881eee89d2e8b3d4 Mon Sep 17 00:00:00 2001 From: Sean Darcy Date: Thu, 28 Jan 2021 11:07:57 +1100 Subject: [PATCH 4/4] shorten wire names --- src/blockchain_db/lmdb/db_lmdb.cpp | 123 ++++++++++----- .../blockchain_ancestry.cpp | 1 + .../blockchain_blackball.cpp | 1 + src/blockchain_utilities/blockchain_depth.cpp | 1 + .../blockchain_export.cpp | 1 + .../blockchain_import.cpp | 1 + src/blockchain_utilities/blockchain_stats.cpp | 1 + src/blockchain_utilities/blockchain_usage.cpp | 1 + src/cryptonote_core/cryptonote_core.cpp | 23 ++- src/cryptonote_core/service_node_list.cpp | 147 +++++++++++------- src/cryptonote_core/service_node_list.h | 17 +- .../service_node_quorum_cop.cpp | 5 +- src/cryptonote_core/uptime_proof.cpp | 83 +++++++--- src/cryptonote_core/uptime_proof.h | 6 +- src/cryptonote_protocol/quorumnet.cpp | 15 +- src/daemon/daemon.cpp | 1 + src/rpc/core_rpc_server.cpp | 19 +-- tests/block_weight/block_weight.cpp | 1 + tests/core_tests/block_validation.cpp | 1 + tests/core_tests/bulletproofs.cpp | 1 + tests/core_tests/chain_split_1.cpp | 1 + tests/core_tests/chain_switch_1.cpp | 1 + tests/core_tests/chaingen.cpp | 1 + tests/core_tests/chaingen001.cpp | 1 + tests/core_tests/chaingen_main.cpp | 1 + tests/core_tests/double_spend.cpp | 1 + tests/core_tests/integer_overflow.cpp | 1 + tests/core_tests/multisig.cpp | 1 + tests/core_tests/oxen_tests.cpp | 1 + tests/core_tests/rct.cpp | 1 + tests/core_tests/ring_signature_1.cpp | 1 + tests/core_tests/tx_validation.cpp | 1 + tests/core_tests/v2_tests.cpp | 1 + tests/core_tests/wallet_tools.cpp | 1 + tests/unit_tests/checkpoints.cpp | 1 + tests/unit_tests/hardfork.cpp | 1 + tests/unit_tests/long_term_block_weight.cpp | 1 + tests/unit_tests/output_distribution.cpp | 1 + 38 files changed, 309 insertions(+), 158 deletions(-) diff --git a/src/blockchain_db/lmdb/db_lmdb.cpp b/src/blockchain_db/lmdb/db_lmdb.cpp index e11b0f2dd..00379b003 100644 --- a/src/blockchain_db/lmdb/db_lmdb.cpp +++ b/src/blockchain_db/lmdb/db_lmdb.cpp @@ -33,6 +33,8 @@ #include #include #include +#include +#include #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 +struct first_type { using type = T; }; +template +using first_type_t = typename first_type::type; + // Lets you iterator over all the pairs of K/V pairs in a database -template +// If multiple V are provided then value will be a variant with the populated pointer +// matched by size of the record. +template class iterable_db { private: MDB_cursor* cursor; @@ -281,13 +291,13 @@ public: class iterator { public: - using value_type = std::pair; + using value_type = std::pair*, std::variant>>; 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 + void load_variant() { + if (v.mv_size == sizeof(T)) + element.second = static_cast(v.mv_data); + else if constexpr (sizeof...(More)) + load_variant(); + else { + MWARNING("Invalid stored type size in iterable_db: stored size (" << v.mv_size << + ") matched none of " << tools::type_name()); + 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.mv_data); - element.second = static_cast(v.mv_data); + if constexpr (sizeof...(V) == 1) + element.second = static_cast(v.mv_data); + else + load_variant(); } 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 element; + value_type element; }; iterator begin() { return {cursor, op_start, op_incr}; } @@ -6240,33 +6265,47 @@ void BlockchainLMDB::clear_service_node_data() } } +template +C native_to_little_container(const C& c) { + C result{c}; + for (auto& x : result) native_to_little_inplace(x); + return result; +} +template +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_old() = default; service_node_proof_serialized_old(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} + : 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{}; @@ -6278,7 +6317,7 @@ struct service_node_proof_serialized_old uint32_t ip; uint16_t storage_port; uint16_t quorumnet_port; - uint16_t version[3]; + std::array version; uint16_t storage_lmq_port; crypto::ed25519_public_key pubkey_ed25519; }; @@ -6288,20 +6327,25 @@ 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(info.storage_server_version[0]), native_to_little(info.storage_server_version[1]), native_to_little(info.storage_server_version[2])}, - lokinet_version{native_to_little(info.lokinet_version[0]), native_to_little(info.lokinet_version[1]), native_to_little(info.lokinet_version[2])} + storage_server_version{native_to_little_container(info.proof->storage_server_version)}, + lokinet_version{native_to_little_container(info.proof->lokinet_version)} {} - uint16_t storage_server_version[3]; - uint16_t lokinet_version[3]; + std::array storage_server_version; + std::array lokinet_version; char _padding[4]; void update(service_nodes::proof_info& info) const { + if (!info.proof) info.proof = std::unique_ptr(new uptime_proof::Proof()); service_node_proof_serialized_old::update(info); - for (size_t i = 0; i < info.storage_server_version.size(); i++) - { - info.storage_server_version[i] = little_to_native(storage_server_version[i]); - info.lokinet_version[i] = little_to_native(lokinet_version[i]); - } + 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; } }; @@ -6357,8 +6401,13 @@ std::unordered_map BlockchainLMDB RCURSOR(service_node_proofs); std::unordered_map result; - for (const auto &pair : iterable_db(m_cursors->service_node_proofs)) - result.emplace(*pair.first, *pair.second); + for (const auto &pair : iterable_db( + m_cursors->service_node_proofs)) { + if (std::holds_alternative(pair.second)) + result.emplace(*pair.first, *var::get(pair.second)); + else + result.emplace(*pair.first, service_node_proof_serialized{*var::get(pair.second)}); + } return result; } diff --git a/src/blockchain_utilities/blockchain_ancestry.cpp b/src/blockchain_utilities/blockchain_ancestry.cpp index adabfe7a8..a69aa4edf 100644 --- a/src/blockchain_utilities/blockchain_ancestry.cpp +++ b/src/blockchain_utilities/blockchain_ancestry.cpp @@ -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" diff --git a/src/blockchain_utilities/blockchain_blackball.cpp b/src/blockchain_utilities/blockchain_blackball.cpp index 6bb2573fb..fcd697662 100644 --- a/src/blockchain_utilities/blockchain_blackball.cpp +++ b/src/blockchain_utilities/blockchain_blackball.cpp @@ -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" diff --git a/src/blockchain_utilities/blockchain_depth.cpp b/src/blockchain_utilities/blockchain_depth.cpp index 074cf4871..f27ddb01f 100644 --- a/src/blockchain_utilities/blockchain_depth.cpp +++ b/src/blockchain_utilities/blockchain_depth.cpp @@ -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 diff --git a/src/blockchain_utilities/blockchain_export.cpp b/src/blockchain_utilities/blockchain_export.cpp index 5d84da3b1..15ae67143 100644 --- a/src/blockchain_utilities/blockchain_export.cpp +++ b/src/blockchain_utilities/blockchain_export.cpp @@ -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" diff --git a/src/blockchain_utilities/blockchain_import.cpp b/src/blockchain_utilities/blockchain_import.cpp index 92b9fd28c..fab384795 100644 --- a/src/blockchain_utilities/blockchain_import.cpp +++ b/src/blockchain_utilities/blockchain_import.cpp @@ -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" diff --git a/src/blockchain_utilities/blockchain_stats.cpp b/src/blockchain_utilities/blockchain_stats.cpp index d7683e3eb..1927b5d9d 100644 --- a/src/blockchain_utilities/blockchain_stats.cpp +++ b/src/blockchain_utilities/blockchain_stats.cpp @@ -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" diff --git a/src/blockchain_utilities/blockchain_usage.cpp b/src/blockchain_utilities/blockchain_usage.cpp index f90542309..d14265618 100644 --- a/src/blockchain_utilities/blockchain_usage.cpp +++ b/src/blockchain_utilities/blockchain_usage.cpp @@ -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 diff --git a/src/cryptonote_core/cryptonote_core.cpp b/src/cryptonote_core/cryptonote_core.cpp index cefb0a0cd..06730ceaa 100644 --- a/src/cryptonote_core/cryptonote_core.cpp +++ b/src/cryptonote_core/cryptonote_core.cpp @@ -1671,7 +1671,7 @@ namespace cryptonote std::array 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) { @@ -1937,11 +1937,9 @@ namespace cryptonote 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); @@ -1968,11 +1966,12 @@ namespace cryptonote 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(req.sig); - proof.sig_ed25519 = tools::make_from_guts(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) + auto proof = std::make_unique(req.proof); + proof->sig = tools::make_from_guts(req.sig); + proof->sig_ed25519 = tools::make_from_guts(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)); @@ -2329,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?)"); }); diff --git a/src/cryptonote_core/service_node_list.cpp b/src/cryptonote_core/service_node_list.cpp index f072aad21..e2468ac01 100644 --- a/src/cryptonote_core/service_node_list.cpp +++ b/src/cryptonote_core/service_node_list.cpp @@ -2808,35 +2808,26 @@ namespace service_nodes return false; } + proof_info::proof_info() + : proof(std::make_unique()) {}; + void proof_info::store(const crypto::public_key &pubkey, cryptonote::Blockchain &blockchain) { + if (!proof) proof = std::unique_ptr(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, - uint32_t ip, - uint16_t s_port, - uint16_t s_lmq_port, - uint16_t q_port, - std::array ver, - std::array ss_ver, - std::array lokinet_ver, - const crypto::ed25519_public_key& pk_ed, - const crypto::x25519_public_key& pk_x2) + bool proof_info::update(uint64_t ts, std::unique_ptr 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); - 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(storage_server_version, ss_ver); - update_db |= update_val(lokinet_version, lokinet_ver); - update_db |= update_val(pubkey_ed25519, pk_ed); - effective_timestamp = timestamp; + effective_timestamp = proof->timestamp; pubkey_x25519 = pk_x2; // Track an IP change (so that the obligations quorum can penalize for IP changes) @@ -2844,28 +2835,69 @@ 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; + }; + + + //TODO remove after HF17 + bool proof_info::update(uint64_t ts, + uint32_t ip, + uint16_t s_port, + uint16_t s_lmq_port, + uint16_t q_port, + std::array ver, + const crypto::ed25519_public_key& pk_ed, + const crypto::x25519_public_key& pk_x2) + { + bool update_db = false; + if (!proof) proof = std::unique_ptr(new uptime_proof::Proof()); + update_db |= update_val(timestamp, ts); + 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) + // 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; }; 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(); } } @@ -2874,7 +2906,6 @@ namespace service_nodes //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) { - MGINFO("Received uptime proof from: " << x25519_pkey); uint8_t const hf_version = m_blockchain.get_current_hard_fork_version(); uint64_t const now = time(nullptr); @@ -2894,6 +2925,7 @@ namespace service_nodes // crypto::hash hash = hash_uptime_proof(proof); + if (!crypto::check_signature(hash, proof.pubkey, proof.sig)) REJECT_PROOF("signature validation failed"); @@ -2918,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"); @@ -2937,7 +2970,7 @@ namespace 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, std::array{0,0,0}, std::array{0,0,0}, proof.pubkey_ed25519, derived_x25519_pubkey)) + 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) @@ -2959,77 +2992,77 @@ namespace service_nodes 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) +#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 proof, bool &my_uptime_proof_confirmation, crypto::x25519_public_key &x25519_pkey) { - MGINFO("Received btencoded uptime proof from: " << proof.pubkey); - MGINFO("Timestamp: " << proof.timestamp); - MGINFO("Public IP: " << proof.public_ip ); - MGINFO("Storage Server Version: " << tools::join(".", proof.storage_server_version) ); - MGINFO("Lokinet Router Version: " << tools::join(".", proof.lokinet_version) ); 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)) + 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) + 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)) + 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(); + crypto::hash hash = proof->hash_uptime_proof(); - if (!crypto::check_signature(hash, proof.pubkey, proof.sig)) + 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 (!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(hash.data), sizeof(hash.data), proof.pubkey_ed25519.data)) + if (0 != crypto_sign_verify_detached(proof->sig_ed25519.data, reinterpret_cast(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) + 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) + 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); + 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]; + 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) + 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); + 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); + 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; " + 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.version, proof.storage_server_version, proof.lokinet_version, proof.pubkey_ed25519, derived_x25519_pubkey)) - iproof.store(proof.pubkey, m_blockchain); + 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) { @@ -3042,7 +3075,7 @@ namespace service_nodes x25519_to_pub.erase(old_x25519); if (derived_x25519_pubkey) - x25519_to_pub[derived_x25519_pubkey] = {proof.pubkey, now}; + x25519_to_pub[derived_x25519_pubkey] = {iproof.proof->pubkey, now}; if (derived_x25519_pubkey && (old_x25519 != derived_x25519_pubkey)) x25519_pkey = derived_x25519_pubkey; @@ -3123,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) { diff --git a/src/cryptonote_core/service_node_list.h b/src/cryptonote_core/service_node_list.h index a1329828f..56c43646e 100644 --- a/src/cryptonote_core/service_node_list.h +++ b/src/cryptonote_core/service_node_list.h @@ -143,6 +143,8 @@ namespace service_nodes struct proof_info { + proof_info(); + participation_history pulse_participation{}; participation_history checkpoint_participation{}; participation_history timestamp_participation{}; @@ -156,14 +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 version{{0,0,0}}; - std::array storage_server_version{{0,0,0}}; - std::array lokinet_version{{0,0,0}}; - crypto::ed25519_public_key pubkey_ed25519 = crypto::ed25519_public_key::null(); + std::unique_ptr proof; // Derived from pubkey_ed25519, not serialized crypto::x25519_public_key pubkey_x25519 = crypto::x25519_public_key::null(); @@ -177,7 +172,9 @@ 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, uint32_t ip, uint16_t s_port, uint16_t s_lmq_port, uint16_t q_port, std::array ver, std::array ss_ver, std::array lokinet_ver, const crypto::ed25519_public_key &pk_ed, const crypto::x25519_public_key &pk_x2); + bool update(uint64_t ts, std::unique_ptr 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 ver, const crypto::ed25519_public_key &pk_ed, const crypto::x25519_public_key &pk_x2); // Stores this record in the database. void store(const crypto::public_key &pubkey, cryptonote::Blockchain &blockchain); @@ -535,7 +532,7 @@ namespace service_nodes //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); + bool handle_btencoded_uptime_proof(std::unique_ptr 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); diff --git a/src/cryptonote_core/service_node_quorum_cop.cpp b/src/cryptonote_core/service_node_quorum_cop.cpp index 50daad494..185fa89b6 100644 --- a/src/cryptonote_core/service_node_quorum_cop.cpp +++ b/src/cryptonote_core/service_node_quorum_cop.cpp @@ -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; diff --git a/src/cryptonote_core/uptime_proof.cpp b/src/cryptonote_core/uptime_proof.cpp index 08d99c39f..062192ebb 100644 --- a/src/cryptonote_core/uptime_proof.cpp +++ b/src/cryptonote_core/uptime_proof.cpp @@ -29,36 +29,36 @@ Proof::Proof(const std::string& serialized_proof) try { const lokimq::bt_dict bt_proof = lokimq::bt_deserialize(serialized_proof); //snode_version - const lokimq::bt_list& bt_version = var::get(bt_proof.at("version")); + const lokimq::bt_list& bt_version = var::get(bt_proof.at("v")); int k = 0; for (lokimq::bt_value const &i: bt_version){ version[k++] = static_cast(lokimq::get_int(i)); } //timestamp - timestamp = lokimq::get_int(bt_proof.at("timestamp")); + timestamp = lokimq::get_int(bt_proof.at("t")); //public_ip - bool succeeded = epee::string_tools::get_ip_int32_from_string(public_ip, var::get(bt_proof.at("public_ip"))); + bool succeeded = epee::string_tools::get_ip_int32_from_string(public_ip, var::get(bt_proof.at("ip"))); //storage_port - storage_port = static_cast(lokimq::get_int(bt_proof.at("storage_port"))); + storage_port = static_cast(lokimq::get_int(bt_proof.at("s"))); //pubkey_ed25519 - pubkey_ed25519 = tools::make_from_guts(var::get(bt_proof.at("pubkey_ed25519"))); + pubkey_ed25519 = tools::make_from_guts(var::get(bt_proof.at("pke"))); //pubkey - if (auto it = bt_proof.find("pubkey"); it != bt_proof.end()) - pubkey = tools::make_from_guts(var::get(bt_proof.at("pubkey"))); + if (auto it = bt_proof.find("pk"); it != bt_proof.end()) + pubkey = tools::make_from_guts(var::get(bt_proof.at("pk"))); else std::memcpy(pubkey.data, pubkey_ed25519.data, 32); //qnet_port - qnet_port = lokimq::get_int(bt_proof.at("qnet_port")); + qnet_port = lokimq::get_int(bt_proof.at("q")); //storage_lmq_port - storage_lmq_port = lokimq::get_int(bt_proof.at("storage_lmq_port")); + storage_lmq_port = lokimq::get_int(bt_proof.at("slp")); //storage_version - const lokimq::bt_list& bt_storage_version = var::get(bt_proof.at("storage_version")); + const lokimq::bt_list& bt_storage_version = var::get(bt_proof.at("sv")); k = 0; for (lokimq::bt_value const &i: bt_storage_version){ storage_server_version[k++] = static_cast(lokimq::get_int(i)); } //lokinet_version - const lokimq::bt_list& bt_lokinet_version = var::get(bt_proof.at("lokinet_version")); + const lokimq::bt_list& bt_lokinet_version = var::get(bt_proof.at("lv")); k = 0; for (lokimq::bt_value const &i: bt_lokinet_version){ lokinet_version[k++] = static_cast(lokimq::get_int(i)); @@ -69,6 +69,7 @@ Proof::Proof(const std::string& serialized_proof) } } + crypto::hash Proof::hash_uptime_proof() const { crypto::hash result; @@ -82,18 +83,27 @@ crypto::hash Proof::hash_uptime_proof() const lokimq::bt_dict Proof::bt_encode_uptime_proof() const { lokimq::bt_dict encoded_proof{ - {"version", lokimq::bt_list{{version[0], version[1], 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_server_version[0], storage_server_version[1], storage_server_version[2]}}}, - {"lokinet_version", lokimq::bt_list{{lokinet_version[0], lokinet_version[1], lokinet_version[2]}}}, + //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["pubkey"] = tools::view_guts(pubkey); + if (pubkey != pubkey_ed25519) encoded_proof["pk"] = tools::view_guts(pubkey); return encoded_proof; } @@ -110,4 +120,35 @@ cryptonote::NOTIFY_BTENCODED_UPTIME_PROOF::request Proof::generate_request() con } +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); +} diff --git a/src/cryptonote_core/uptime_proof.h b/src/cryptonote_core/uptime_proof.h index db93ccfbf..46c055863 100644 --- a/src/cryptonote_core/uptime_proof.h +++ b/src/cryptonote_core/uptime_proof.h @@ -25,10 +25,10 @@ public: 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 ss_version, uint16_t quorumnet_port, std::array 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; @@ -36,6 +36,6 @@ public: 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); diff --git a/src/cryptonote_protocol/quorumnet.cpp b/src/cryptonote_protocol/quorumnet.cpp index bd6c5293f..7a37a7b6d 100644 --- a/src/cryptonote_protocol/quorumnet.cpp +++ b/src/cryptonote_protocol/quorumnet.cpp @@ -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> remotes; // {x25519 pubkey, connect string, version} + std::vectorversion)>> 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); diff --git a/src/daemon/daemon.cpp b/src/daemon/daemon.cpp index 452800b35..0d8814a1f 100644 --- a/src/daemon/daemon.cpp +++ b/src/daemon/daemon.cpp @@ -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" diff --git a/src/rpc/core_rpc_server.cpp b/src/rpc/core_rpc_server.cpp index d6c3d4312..e51a82f0e 100644 --- a/src/rpc/core_rpc_server.cpp +++ b/src/rpc/core_rpc_server.cpp @@ -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,19 +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.lokinet_version = proof.lokinet_version; - entry.storage_server_version = proof.storage_server_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; diff --git a/tests/block_weight/block_weight.cpp b/tests/block_weight/block_weight.cpp index 1cfedba99..2066c5243 100644 --- a/tests/block_weight/block_weight.cpp +++ b/tests/block_weight/block_weight.cpp @@ -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" diff --git a/tests/core_tests/block_validation.cpp b/tests/core_tests/block_validation.cpp index 5c17cf4ea..74e49e31c 100644 --- a/tests/core_tests/block_validation.cpp +++ b/tests/core_tests/block_validation.cpp @@ -31,6 +31,7 @@ #include "chaingen.h" #include "block_validation.h" #include "common/util.h" +#include "cryptonote_core/uptime_proof.h" using namespace cryptonote; diff --git a/tests/core_tests/bulletproofs.cpp b/tests/core_tests/bulletproofs.cpp index bd44bdc2a..295b69ae9 100644 --- a/tests/core_tests/bulletproofs.cpp +++ b/tests/core_tests/bulletproofs.cpp @@ -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; diff --git a/tests/core_tests/chain_split_1.cpp b/tests/core_tests/chain_split_1.cpp index 7c8b72e33..f184b4b56 100644 --- a/tests/core_tests/chain_split_1.cpp +++ b/tests/core_tests/chain_split_1.cpp @@ -30,6 +30,7 @@ #include "chaingen.h" #include "chain_split_1.h" +#include "cryptonote_core/uptime_proof.h" using namespace cryptonote; diff --git a/tests/core_tests/chain_switch_1.cpp b/tests/core_tests/chain_switch_1.cpp index e6d69116c..79d09d45c 100644 --- a/tests/core_tests/chain_switch_1.cpp +++ b/tests/core_tests/chain_switch_1.cpp @@ -30,6 +30,7 @@ #include "chaingen.h" #include "chain_switch_1.h" +#include "cryptonote_core/uptime_proof.h" using namespace cryptonote; diff --git a/tests/core_tests/chaingen.cpp b/tests/core_tests/chaingen.cpp index 238103e99..a7efa9ce8 100644 --- a/tests/core_tests/chaingen.cpp +++ b/tests/core_tests/chaingen.cpp @@ -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" diff --git a/tests/core_tests/chaingen001.cpp b/tests/core_tests/chaingen001.cpp index 27ed75437..7921b23f9 100644 --- a/tests/core_tests/chaingen001.cpp +++ b/tests/core_tests/chaingen001.cpp @@ -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" diff --git a/tests/core_tests/chaingen_main.cpp b/tests/core_tests/chaingen_main.cpp index 0160c8804..e9d439616 100644 --- a/tests/core_tests/chaingen_main.cpp +++ b/tests/core_tests/chaingen_main.cpp @@ -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; diff --git a/tests/core_tests/double_spend.cpp b/tests/core_tests/double_spend.cpp index 27495b2f9..33134115b 100644 --- a/tests/core_tests/double_spend.cpp +++ b/tests/core_tests/double_spend.cpp @@ -30,6 +30,7 @@ #include "chaingen.h" #include "double_spend.h" +#include "cryptonote_core/uptime_proof.h" using namespace cryptonote; diff --git a/tests/core_tests/integer_overflow.cpp b/tests/core_tests/integer_overflow.cpp index 6b5936e52..ad048b7cc 100644 --- a/tests/core_tests/integer_overflow.cpp +++ b/tests/core_tests/integer_overflow.cpp @@ -30,6 +30,7 @@ #include "chaingen.h" #include "integer_overflow.h" +#include "cryptonote_core/uptime_proof.h" using namespace cryptonote; diff --git a/tests/core_tests/multisig.cpp b/tests/core_tests/multisig.cpp index e98403809..97710a538 100644 --- a/tests/core_tests/multisig.cpp +++ b/tests/core_tests/multisig.cpp @@ -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" diff --git a/tests/core_tests/oxen_tests.cpp b/tests/core_tests/oxen_tests.cpp index a9e8cb9a9..24393a012 100644 --- a/tests/core_tests/oxen_tests.cpp +++ b/tests/core_tests/oxen_tests.cpp @@ -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" diff --git a/tests/core_tests/rct.cpp b/tests/core_tests/rct.cpp index 2bb94556b..4ad4bc84d 100644 --- a/tests/core_tests/rct.cpp +++ b/tests/core_tests/rct.cpp @@ -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; diff --git a/tests/core_tests/ring_signature_1.cpp b/tests/core_tests/ring_signature_1.cpp index 0d4db0163..e431df363 100644 --- a/tests/core_tests/ring_signature_1.cpp +++ b/tests/core_tests/ring_signature_1.cpp @@ -30,6 +30,7 @@ #include "chaingen.h" #include "ring_signature_1.h" +#include "cryptonote_core/uptime_proof.h" using namespace cryptonote; diff --git a/tests/core_tests/tx_validation.cpp b/tests/core_tests/tx_validation.cpp index db79c27d9..2adfd46db 100644 --- a/tests/core_tests/tx_validation.cpp +++ b/tests/core_tests/tx_validation.cpp @@ -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; diff --git a/tests/core_tests/v2_tests.cpp b/tests/core_tests/v2_tests.cpp index bb1321e98..b63209c1b 100644 --- a/tests/core_tests/v2_tests.cpp +++ b/tests/core_tests/v2_tests.cpp @@ -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; diff --git a/tests/core_tests/wallet_tools.cpp b/tests/core_tests/wallet_tools.cpp index 2ecdb5135..74437d60e 100644 --- a/tests/core_tests/wallet_tools.cpp +++ b/tests/core_tests/wallet_tools.cpp @@ -3,6 +3,7 @@ // #include "wallet_tools.h" +#include "cryptonote_core/uptime_proof.h" #include using namespace crypto; diff --git a/tests/unit_tests/checkpoints.cpp b/tests/unit_tests/checkpoints.cpp index 6cd142e3e..b46d2cf61 100644 --- a/tests/unit_tests/checkpoints.cpp +++ b/tests/unit_tests/checkpoints.cpp @@ -33,6 +33,7 @@ #include #include "cryptonote_basic/cryptonote_format_utils.h" +#include "cryptonote_core/uptime_proof.h" #include "checkpoints/checkpoints.cpp" #include "blockchain_db/testdb.h" diff --git a/tests/unit_tests/hardfork.cpp b/tests/unit_tests/hardfork.cpp index b75787db9..9e2c4eb8a 100644 --- a/tests/unit_tests/hardfork.cpp +++ b/tests/unit_tests/hardfork.cpp @@ -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" diff --git a/tests/unit_tests/long_term_block_weight.cpp b/tests/unit_tests/long_term_block_weight.cpp index f7e0934b6..ea22cc879 100644 --- a/tests/unit_tests/long_term_block_weight.cpp +++ b/tests/unit_tests/long_term_block_weight.cpp @@ -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" diff --git a/tests/unit_tests/output_distribution.cpp b/tests/unit_tests/output_distribution.cpp index 6c241a762..4a13b2a6a 100644 --- a/tests/unit_tests/output_distribution.cpp +++ b/tests/unit_tests/output_distribution.cpp @@ -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"