#include "uptime_proof.h" #include "common/string_util.h" #include "epee/string_tools.h" #include "logging/oxen_logger.h" #include "service_node_list.h" #include "version.h" extern "C" { #include } namespace uptime_proof { static auto logcat = oxen::log::Cat("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_https_port, uint16_t sn_storage_omq_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}, pubkey_ed25519{keys.pub_ed25519}, qnet_port{quorumnet_port}, storage_https_port{sn_storage_https_port}, storage_omq_port{sn_storage_omq_port}, storage_server_version{ss_version}, lokinet_version{lokinet_version} { crypto::hash hash = hash_uptime_proof(); crypto::generate_signature(hash, keys.pub, keys.key, sig); crypto_sign_detached( sig_ed25519.data(), nullptr, hash.data(), hash.size(), keys.key_ed25519.data()); } // Deserialize from a btencoded string into our Proof instance Proof::Proof(const std::string& serialized_proof) { try { using namespace oxenc; const bt_dict bt_proof = bt_deserialize(serialized_proof); // snode_version const bt_list& bt_version = var::get(bt_proof.at("v")); int k = 0; for (bt_value const& i : bt_version) { version[k++] = static_cast(get_int(i)); } // timestamp timestamp = 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("ip"))); // storage_port storage_https_port = static_cast(get_int(bt_proof.at("shp"))); // pubkey_ed25519 pubkey_ed25519 = tools::make_from_guts( var::get(bt_proof.at("pke"))); // 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 = get_int(bt_proof.at("q")); // storage_omq_port storage_omq_port = get_int(bt_proof.at("sop")); // storage_version const bt_list& bt_storage_version = var::get(bt_proof.at("sv")); k = 0; for (bt_value const& i : bt_storage_version) { storage_server_version[k++] = static_cast(get_int(i)); } // lokinet_version const bt_list& bt_lokinet_version = var::get(bt_proof.at("lv")); k = 0; for (bt_value const& i : bt_lokinet_version) { lokinet_version[k++] = static_cast(get_int(i)); } } catch (const std::exception& e) { oxen::log::warning(logcat, "deserialization failed: {}", e.what()); throw; } } crypto::hash Proof::hash_uptime_proof() const { crypto::hash result; std::string serialized_proof = 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; } oxenc::bt_dict Proof::bt_encode_uptime_proof() const { oxenc::bt_dict encoded_proof{ // version {"v", oxenc::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 {"shp", storage_https_port}, // pubkey_ed25519 {"pke", tools::view_guts(pubkey_ed25519)}, // qnet_port {"q", qnet_port}, // storage_omq_port {"sop", storage_omq_port}, // storage_version {"sv", oxenc::bt_list{ {storage_server_version[0], storage_server_version[1], storage_server_version[2]}}}, // lokinet_version {"lv", oxenc::bt_list{{lokinet_version[0], lokinet_version[1], lokinet_version[2]}}}, }; if (tools::view_guts(pubkey) != tools::view_guts(pubkey_ed25519)) { encoded_proof["pk"] = tools::view_guts(pubkey); } return encoded_proof; } cryptonote::NOTIFY_BTENCODED_UPTIME_PROOF::request Proof::generate_request() const { cryptonote::NOTIFY_BTENCODED_UPTIME_PROOF::request request; request.proof = bt_serialize(this->bt_encode_uptime_proof()); request.sig = tools::view_guts(this->sig); request.ed_sig = tools::view_guts(this->sig_ed25519); return request; } bool operator==(const Proof& lhs, const 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_https_port != rhs.storage_https_port) || (lhs.storage_omq_port != rhs.storage_omq_port) || (lhs.qnet_port != rhs.qnet_port) || (lhs.version != rhs.version) || (lhs.storage_server_version != rhs.storage_server_version) || (lhs.lokinet_version != rhs.lokinet_version)) result = false; return result; } bool operator!=(const Proof& lhs, const Proof& rhs) { return !(lhs == rhs); } } // namespace uptime_proof