From 1ab2da182afe5fe0c06e2e039839452cb859ae25 Mon Sep 17 00:00:00 2001 From: victor-tucci Date: Tue, 30 Apr 2024 23:29:16 +0800 Subject: [PATCH 1/4] Implement voting for deregistration for masternodes with more than three instances on the same IP. --- src/cryptonote_basic/tx_extra.h | 1 + .../master_node_quorum_cop.cpp | 41 ++++++++++++++++++- src/cryptonote_core/master_node_quorum_cop.h | 4 +- 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/src/cryptonote_basic/tx_extra.h b/src/cryptonote_basic/tx_extra.h index 3c7b02d0916..589ec1d8581 100755 --- a/src/cryptonote_basic/tx_extra.h +++ b/src/cryptonote_basic/tx_extra.h @@ -435,6 +435,7 @@ namespace cryptonote timestamp_response_unreachable = 1 << 4, timesync_status_out_of_sync = 1 << 5, belnet_unreachable = 1 << 6, + multi_mn_accept_range = 1 << 7, }; // Returns human-readable reason strings (e.g. "Missed Uptime Proofs") for the given reason bits diff --git a/src/cryptonote_core/master_node_quorum_cop.cpp b/src/cryptonote_core/master_node_quorum_cop.cpp index 9ab7da6cd2d..959c0f011f3 100755 --- a/src/cryptonote_core/master_node_quorum_cop.cpp +++ b/src/cryptonote_core/master_node_quorum_cop.cpp @@ -60,6 +60,7 @@ namespace master_nodes if (!timesync_status) results.push_back("Too many missed timesync replies."sv); if (!storage_server_reachable) results.push_back("Storage server is not reachable."sv); if (!belnet_reachable) results.push_back("Belnet router is not reachable."sv); + if (!multi_mn_accept_range) results.push_back("This Master Node IP Reached Maximum acceptable Range."sv); return results; } @@ -106,6 +107,43 @@ namespace master_nodes timesync_status = proof.timesync_status; }); + + if (hf_version > cryptonote::network_version_12_security_signature) { + auto mn_infos = m_core.get_master_node_list_state(); + std::vector> multi_mns; + + // Find the MultiMaster nodes + for (auto &mn_info : mn_infos) + { + m_core.get_master_node_list().access_proof(mn_info.pubkey, [&](const proof_info &proof) { + if(ips[0].first == proof.proof->public_ip) + multi_mns.push_back({mn_info.pubkey, mn_info.info->registration_height}); + }); + } + + // Sort the list + std::sort(multi_mns.begin(), multi_mns.end(), [](const auto &a, const auto &b){ + return a.second < b.second; + }); + + // Find the position of pubkey in the vector + auto position = std::find_if(multi_mns.begin(), multi_mns.end(), [&](const auto &pair){ + return pair.first == pubkey; + }); + + // Check if "pubkey" is found + if (position != multi_mns.end()) { + int my_position = position - multi_mns.begin(); + // LOG_PRINT_L2("Position of 'pubkey' in the MN_list: " << pubkey << ", " << my_position); + if (my_position >= 3) + { + std::cout << "This Master Node reached maximum multinode: " << pubkey << std::endl; + LOG_PRINT_L1("This Master Node reached maximum multinode: " << pubkey); + result.multi_mn_accept_range = false; + } + } + } + std::chrono::seconds time_since_last_uptime_proof{std::time(nullptr) - timestamp}; bool check_uptime_obligation = true; @@ -294,6 +332,7 @@ namespace master_nodes if (!test_results.POS_participation) reason |= cryptonote::Decommission_Reason::missed_POS_participations; if (!test_results.storage_server_reachable) reason |= cryptonote::Decommission_Reason::storage_server_unreachable; if (!test_results.belnet_reachable) reason |= cryptonote::Decommission_Reason::belnet_unreachable; + if (!test_results.multi_mn_accept_range) reason |= cryptonote::Decommission_Reason::multi_mn_accept_range; if (!test_results.timestamp_participation) reason |= cryptonote::Decommission_Reason::timestamp_response_unreachable; if (!test_results.timesync_status) reason |= cryptonote::Decommission_Reason::timesync_status_out_of_sync; @@ -361,7 +400,7 @@ namespace master_nodes LOG_PRINT_L0(tools::join("\n", *why)); else LOG_PRINT_L0("Master Node is passing all local tests"); - LOG_PRINT_L0("(Note that some tests, such as storage server and belnet reachability, can only assessed by remote master nodes)"); + LOG_PRINT_L0("(Note that some tests, such as storage server, belnet reachability and multi_mn_accept_range, can only assessed by remote master nodes)"); } }else{ LOG_PRINT_L0("process_quorums: Cant be voted on my Master Node"); diff --git a/src/cryptonote_core/master_node_quorum_cop.h b/src/cryptonote_core/master_node_quorum_cop.h index c5fe1c8e45e..1d924a1f257 100755 --- a/src/cryptonote_core/master_node_quorum_cop.h +++ b/src/cryptonote_core/master_node_quorum_cop.h @@ -94,6 +94,7 @@ namespace master_nodes bool timesync_status = true; bool storage_server_reachable = true; bool belnet_reachable = true; + bool multi_mn_accept_range = true; // Returns a vector of reasons why this node is failing (nullopt if not failing). std::optional> why() const; @@ -106,7 +107,8 @@ namespace master_nodes timestamp_participation && timesync_status && storage_server_reachable && - belnet_reachable; + belnet_reachable && + multi_mn_accept_range; } }; From 49673dffd14fa3bb164281661f6239f87a3371d5 Mon Sep 17 00:00:00 2001 From: victor-tucci Date: Thu, 2 May 2024 19:33:02 +0800 Subject: [PATCH 2/4] logic updated for reduce the time taken for multi_mn_accept_range check --- .../master_node_quorum_cop.cpp | 50 ++++++++++++------- src/cryptonote_core/master_node_quorum_cop.h | 6 +-- 2 files changed, 34 insertions(+), 22 deletions(-) diff --git a/src/cryptonote_core/master_node_quorum_cop.cpp b/src/cryptonote_core/master_node_quorum_cop.cpp index 959c0f011f3..586b3f525a2 100755 --- a/src/cryptonote_core/master_node_quorum_cop.cpp +++ b/src/cryptonote_core/master_node_quorum_cop.cpp @@ -77,7 +77,7 @@ namespace master_nodes // Perform master node tests -- this returns true if the server node is in a good state, that is, // has submitted uptime proofs, participated in required quorums, etc. - master_node_test_results quorum_cop::check_master_node(uint8_t hf_version, const crypto::public_key &pubkey, const master_node_info &info) const + master_node_test_results quorum_cop::check_master_node(std::map>> multi_mns_list, uint8_t hf_version, const crypto::public_key &pubkey, const master_node_info &info) const { const auto& netconf = m_core.get_net_config(); @@ -109,17 +109,8 @@ namespace master_nodes }); if (hf_version > cryptonote::network_version_12_security_signature) { - auto mn_infos = m_core.get_master_node_list_state(); - std::vector> multi_mns; - - // Find the MultiMaster nodes - for (auto &mn_info : mn_infos) - { - m_core.get_master_node_list().access_proof(mn_info.pubkey, [&](const proof_info &proof) { - if(ips[0].first == proof.proof->public_ip) - multi_mns.push_back({mn_info.pubkey, mn_info.info->registration_height}); - }); - } + + std::vector> multi_mns = multi_mns_list[ips[0].first]; // Sort the list std::sort(multi_mns.begin(), multi_mns.end(), [](const auto &a, const auto &b){ @@ -137,7 +128,7 @@ namespace master_nodes // LOG_PRINT_L2("Position of 'pubkey' in the MN_list: " << pubkey << ", " << my_position); if (my_position >= 3) { - std::cout << "This Master Node reached maximum multinode: " << pubkey << std::endl; + MGINFO("This Master Node reached maximum multinode: " << pubkey); LOG_PRINT_L1("This Master Node reached maximum multinode: " << pubkey); result.multi_mn_accept_range = false; } @@ -268,7 +259,7 @@ namespace master_nodes return result; } - void quorum_cop::handling_master_nodes_states(uint8_t const obligations_height_hf_version_,uint8_t const hf_version,std::shared_ptr quorum,int index_in_group,uint64_t const latest_height) + void quorum_cop::handling_master_nodes_states(std::map>> multi_mns_list, uint8_t const obligations_height_hf_version_,uint8_t const hf_version,std::shared_ptr quorum,int index_in_group,uint64_t const latest_height) { // // NOTE: I am in the quorum @@ -278,6 +269,7 @@ namespace master_nodes const auto& my_keys = m_core.get_master_keys(); std::unique_lock lock{m_lock}; int good = 0, total = 0; + auto start = std::chrono::system_clock::now(); for (size_t node_index = 0; node_index < quorum->workers.size(); ++worker_it, ++node_index) { @@ -297,7 +289,7 @@ namespace master_nodes continue; } - auto test_results = check_master_node(obligations_height_hf_version_, node_key, info); //MN proof Testing + auto test_results = check_master_node(multi_mns_list, obligations_height_hf_version_, node_key, info); //MN proof Testing bool passed = test_results.passed(); LOG_PRINT_L3("process_quorums: check_master_node passed:");//TODO:VOTE LOG_PRINT_L3("NODE KEY:" << quorum->workers[node_index]); @@ -369,11 +361,15 @@ namespace master_nodes if (!handle_vote(vote, vvc,hf_version)) LOG_ERROR("Failed to add state change vote; reason: " << print_vote_verification_context(vvc, &vote)); } + + auto end = std::chrono::system_clock::now(); + std::chrono::duration elapsed_seconds = end - start; + MGINFO("Elapsed time: " << elapsed_seconds.count() << "s"); if (good > 0) LOG_PRINT_L3(good << " of " << total << " master nodes are active and passing checks; no state change votes required"); } - void quorum_cop::handling_my_master_node_states(uint8_t const obligations_height_hf_version,uint8_t const hf_version,bool &tested_myself_once_per_block,std::chrono::seconds live_time) + void quorum_cop::handling_my_master_node_states(std::map>> multi_mns_list, uint8_t const obligations_height_hf_version,uint8_t const hf_version,bool &tested_myself_once_per_block,std::chrono::seconds live_time) { const auto& my_keys = m_core.get_master_keys(); const auto states_array = m_core.get_master_node_list_state({my_keys.pub}); @@ -383,7 +379,7 @@ namespace master_nodes if (info.can_be_voted_on(m_obligations_height)) { tested_myself_once_per_block = true; - auto my_test_results = check_master_node(obligations_height_hf_version, my_keys.pub, info); + auto my_test_results = check_master_node(multi_mns_list, obligations_height_hf_version, my_keys.pub, info); const bool print_failings = info.is_decommissioned() || (info.is_active() && !my_test_results.passed() && // Don't warn uptime proofs if the daemon is just recently started and is candidate for testing (i.e. restarting the daemon) @@ -455,10 +451,26 @@ namespace master_nodes void quorum_cop::process_quorums(cryptonote::block const &block) { + MGINFO("Process_quorums function called"); uint8_t const hf_version = block.major_version; if (hf_version < cryptonote::network_version_9_master_nodes) return; + auto start = std::chrono::system_clock::now(); + auto mn_infos = m_core.get_master_node_list_state(); + std::map>> multi_mns_list; + // Find the MultiMaster nodes 2000 + for (auto &mn_info : mn_infos) + { + m_core.get_master_node_list().access_proof(mn_info.pubkey, [&](const proof_info &proof) { + // if(ips[0].first == proof.proof->public_ip) + auto& entry = multi_mns_list[proof.proof->public_ip]; + entry.push_back({mn_info.pubkey, mn_info.info->registration_height}); // multi_mns.push_back({mn_info.pubkey, mn_info.info->registration_height}); + }); + } + auto end = std::chrono::system_clock::now(); + std::chrono::duration elapsed_seconds = end - start; + MGINFO("Time For MN_list_fetch: " << elapsed_seconds.count() << "s"); const auto& netconf = m_core.get_net_config(); uint64_t const REORG_SAFETY_BUFFER_BLOCKS = (hf_version >= cryptonote::network_version_13_checkpointing) @@ -558,7 +570,7 @@ namespace master_nodes int index_in_group = voting_enabled ? find_index_in_quorum_group(quorum->validators, my_keys.pub) : -1; if (index_in_group >= 0) { - handling_master_nodes_states(obligations_height_hf_version,hf_version,quorum,index_in_group,latest_height); + handling_master_nodes_states(multi_mns_list,obligations_height_hf_version,hf_version,quorum,index_in_group,latest_height); } else if (!tested_myself_once_per_block && (find_index_in_quorum_group(quorum->workers, my_keys.pub) >= 0)) { @@ -566,7 +578,7 @@ namespace master_nodes // being tested. If so, check if we would be decommissioned // based on _our_ data and if so, report it to the user so they // know about it. - handling_my_master_node_states(obligations_height_hf_version,hf_version,tested_myself_once_per_block,live_time); + handling_my_master_node_states(multi_mns_list,obligations_height_hf_version,hf_version,tested_myself_once_per_block,live_time); } } } diff --git a/src/cryptonote_core/master_node_quorum_cop.h b/src/cryptonote_core/master_node_quorum_cop.h index 1d924a1f257..623fd1e8092 100755 --- a/src/cryptonote_core/master_node_quorum_cop.h +++ b/src/cryptonote_core/master_node_quorum_cop.h @@ -130,9 +130,9 @@ namespace master_nodes private: void process_quorums(cryptonote::block const &block); void quorum_checkpoint_handle(uint64_t const start_voting_from_height_,uint64_t const height,uint8_t const hf_version); - void handling_master_nodes_states(uint8_t const obligations_height_hf_version_,uint8_t const hf_version,std::shared_ptr quorum,int index_in_group,uint64_t const latest_height); - void handling_my_master_node_states(uint8_t const obligations_height_hf_version,uint8_t const hf_version,bool &tested_myself_once_per_block,std::chrono::seconds live_time); - master_node_test_results check_master_node(uint8_t hf_version, const crypto::public_key &pubkey, const master_node_info &info) const; + void handling_master_nodes_states(std::map>> multi_mns_list, uint8_t const obligations_height_hf_version_,uint8_t const hf_version,std::shared_ptr quorum,int index_in_group,uint64_t const latest_height); + void handling_my_master_node_states(std::map>> multi_mns_list, uint8_t const obligations_height_hf_version,uint8_t const hf_version,bool &tested_myself_once_per_block,std::chrono::seconds live_time); + master_node_test_results check_master_node(std::map>> multi_mns_list, uint8_t hf_version, const crypto::public_key &pubkey, const master_node_info &info) const; cryptonote::core& m_core; voting_pool m_vote_pool; From 26adc65fa003e0f37000f3809ca8eaabfe8596fb Mon Sep 17 00:00:00 2001 From: victor-tucci Date: Fri, 3 May 2024 17:02:59 +0800 Subject: [PATCH 3/4] multi_mn_accept_range_not_met reason added in extra --- src/cryptonote_basic/tx_extra.cpp | 2 ++ src/cryptonote_basic/tx_extra.h | 2 +- src/cryptonote_core/master_node_quorum_cop.cpp | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/cryptonote_basic/tx_extra.cpp b/src/cryptonote_basic/tx_extra.cpp index 6a96c952e5f..f139df21ca9 100644 --- a/src/cryptonote_basic/tx_extra.cpp +++ b/src/cryptonote_basic/tx_extra.cpp @@ -124,6 +124,7 @@ std::vector readable_reasons(uint16_t decomm_reason) { if (decomm_reason & timestamp_response_unreachable) results.push_back("Unreachable for Timestamp Check"); if (decomm_reason & timesync_status_out_of_sync) results.push_back("Time out of sync"); if (decomm_reason & belnet_unreachable) results.push_back("Belnet Unreachable"); + if (decomm_reason & multi_mn_accept_range_not_met) results.push_back("Multi MN accept Range Not Met"); return results; } @@ -136,6 +137,7 @@ std::vector coded_reasons(uint16_t decomm_reason) { if (decomm_reason & timestamp_response_unreachable) results.push_back("timecheck"); if (decomm_reason & timesync_status_out_of_sync) results.push_back("timesync"); if (decomm_reason & belnet_unreachable) results.push_back("belnet"); + if (decomm_reason & multi_mn_accept_range_not_met) results.push_back("multi_mn_range"); return results; } diff --git a/src/cryptonote_basic/tx_extra.h b/src/cryptonote_basic/tx_extra.h index 589ec1d8581..4a0af25515e 100755 --- a/src/cryptonote_basic/tx_extra.h +++ b/src/cryptonote_basic/tx_extra.h @@ -435,7 +435,7 @@ namespace cryptonote timestamp_response_unreachable = 1 << 4, timesync_status_out_of_sync = 1 << 5, belnet_unreachable = 1 << 6, - multi_mn_accept_range = 1 << 7, + multi_mn_accept_range_not_met = 1 << 7, }; // Returns human-readable reason strings (e.g. "Missed Uptime Proofs") for the given reason bits diff --git a/src/cryptonote_core/master_node_quorum_cop.cpp b/src/cryptonote_core/master_node_quorum_cop.cpp index 586b3f525a2..6e536cb1316 100755 --- a/src/cryptonote_core/master_node_quorum_cop.cpp +++ b/src/cryptonote_core/master_node_quorum_cop.cpp @@ -324,7 +324,7 @@ namespace master_nodes if (!test_results.POS_participation) reason |= cryptonote::Decommission_Reason::missed_POS_participations; if (!test_results.storage_server_reachable) reason |= cryptonote::Decommission_Reason::storage_server_unreachable; if (!test_results.belnet_reachable) reason |= cryptonote::Decommission_Reason::belnet_unreachable; - if (!test_results.multi_mn_accept_range) reason |= cryptonote::Decommission_Reason::multi_mn_accept_range; + if (!test_results.multi_mn_accept_range) reason |= cryptonote::Decommission_Reason::multi_mn_accept_range_not_met; if (!test_results.timestamp_participation) reason |= cryptonote::Decommission_Reason::timestamp_response_unreachable; if (!test_results.timesync_status) reason |= cryptonote::Decommission_Reason::timesync_status_out_of_sync; From 4b94237fa867da7611553ca01d5d23eb1fcf67a4 Mon Sep 17 00:00:00 2001 From: tore-tto Date: Mon, 6 May 2024 12:50:08 +0530 Subject: [PATCH 4/4] Removed commented lines and enabled MultiMN range logic (v19) --- src/cryptonote_core/master_node_quorum_cop.cpp | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-) diff --git a/src/cryptonote_core/master_node_quorum_cop.cpp b/src/cryptonote_core/master_node_quorum_cop.cpp index 6e536cb1316..2253806de2a 100755 --- a/src/cryptonote_core/master_node_quorum_cop.cpp +++ b/src/cryptonote_core/master_node_quorum_cop.cpp @@ -108,7 +108,7 @@ namespace master_nodes }); - if (hf_version > cryptonote::network_version_12_security_signature) { + if (hf_version >= cryptonote::network_version_19) { std::vector> multi_mns = multi_mns_list[ips[0].first]; @@ -125,10 +125,8 @@ namespace master_nodes // Check if "pubkey" is found if (position != multi_mns.end()) { int my_position = position - multi_mns.begin(); - // LOG_PRINT_L2("Position of 'pubkey' in the MN_list: " << pubkey << ", " << my_position); if (my_position >= 3) { - MGINFO("This Master Node reached maximum multinode: " << pubkey); LOG_PRINT_L1("This Master Node reached maximum multinode: " << pubkey); result.multi_mn_accept_range = false; } @@ -269,7 +267,6 @@ namespace master_nodes const auto& my_keys = m_core.get_master_keys(); std::unique_lock lock{m_lock}; int good = 0, total = 0; - auto start = std::chrono::system_clock::now(); for (size_t node_index = 0; node_index < quorum->workers.size(); ++worker_it, ++node_index) { @@ -362,9 +359,6 @@ namespace master_nodes LOG_ERROR("Failed to add state change vote; reason: " << print_vote_verification_context(vvc, &vote)); } - auto end = std::chrono::system_clock::now(); - std::chrono::duration elapsed_seconds = end - start; - MGINFO("Elapsed time: " << elapsed_seconds.count() << "s"); if (good > 0) LOG_PRINT_L3(good << " of " << total << " master nodes are active and passing checks; no state change votes required"); } @@ -451,26 +445,20 @@ namespace master_nodes void quorum_cop::process_quorums(cryptonote::block const &block) { - MGINFO("Process_quorums function called"); uint8_t const hf_version = block.major_version; if (hf_version < cryptonote::network_version_9_master_nodes) return; - auto start = std::chrono::system_clock::now(); auto mn_infos = m_core.get_master_node_list_state(); std::map>> multi_mns_list; - // Find the MultiMaster nodes 2000 + // Find the MultiMaster nodes for (auto &mn_info : mn_infos) { m_core.get_master_node_list().access_proof(mn_info.pubkey, [&](const proof_info &proof) { - // if(ips[0].first == proof.proof->public_ip) auto& entry = multi_mns_list[proof.proof->public_ip]; - entry.push_back({mn_info.pubkey, mn_info.info->registration_height}); // multi_mns.push_back({mn_info.pubkey, mn_info.info->registration_height}); + entry.push_back({mn_info.pubkey, mn_info.info->registration_height}); }); } - auto end = std::chrono::system_clock::now(); - std::chrono::duration elapsed_seconds = end - start; - MGINFO("Time For MN_list_fetch: " << elapsed_seconds.count() << "s"); const auto& netconf = m_core.get_net_config(); uint64_t const REORG_SAFETY_BUFFER_BLOCKS = (hf_version >= cryptonote::network_version_13_checkpointing)