From eef164f7cc805ecf1881812cebb972ad0ce58edb Mon Sep 17 00:00:00 2001 From: moneromooo-monero Date: Tue, 26 Feb 2019 12:40:40 +0000 Subject: [PATCH] cryptonote_protocol_handler: search for syncing peers in "cruise mode" When all our outgoing peer slots are filled, we cycle one peer at a time looking for syncing peers until we have at least two such peers. This brings two advantages: - Peers without incoming connections will find more syncing peers that before, thereby strengthening network decentralization - Peers will have more resistance to isolation attacks, as they are more likely to find a "good" peer than they were before --- src/cryptonote_config.h | 1 + .../cryptonote_protocol_handler.h | 2 + .../cryptonote_protocol_handler.inl | 42 +++++++++++++++++++ 3 files changed, 45 insertions(+) diff --git a/src/cryptonote_config.h b/src/cryptonote_config.h index 93db71705..f13c6ba90 100644 --- a/src/cryptonote_config.h +++ b/src/cryptonote_config.h @@ -114,6 +114,7 @@ #define P2P_DEFAULT_HANDSHAKE_INVOKE_TIMEOUT 5000 //5 seconds #define P2P_DEFAULT_WHITELIST_CONNECTIONS_PERCENT 70 #define P2P_DEFAULT_ANCHOR_CONNECTIONS_COUNT 2 +#define P2P_DEFAULT_SYNC_SEARCH_CONNECTIONS_COUNT 2 #define P2P_DEFAULT_LIMIT_RATE_UP 2048 // kB/s #define P2P_DEFAULT_LIMIT_RATE_DOWN 8192 // kB/s diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.h b/src/cryptonote_protocol/cryptonote_protocol_handler.h index efd986b53..0fc7913b8 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_handler.h +++ b/src/cryptonote_protocol/cryptonote_protocol_handler.h @@ -138,6 +138,7 @@ namespace cryptonote void drop_connection(cryptonote_connection_context &context, bool add_fail, bool flush_all_spans); bool kick_idle_peers(); bool check_standby_peers(); + bool update_sync_search(); int try_add_next_blocks(cryptonote_connection_context &context); void notify_new_stripe(cryptonote_connection_context &context, uint32_t stripe); void skip_unneeded_hashes(cryptonote_connection_context& context, bool check_block_queue) const; @@ -153,6 +154,7 @@ namespace cryptonote block_queue m_block_queue; epee::math_helper::once_a_time_seconds<30> m_idle_peer_kicker; epee::math_helper::once_a_time_milliseconds<100> m_standby_checker; + epee::math_helper::once_a_time_seconds<101> m_sync_search_checker; std::atomic m_max_out_peers; tools::PerformanceTimer m_sync_timer, m_add_timer; uint64_t m_last_add_end_time; diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl index c1459cbb6..d614eb141 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl +++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl @@ -1371,6 +1371,7 @@ skip: { m_idle_peer_kicker.do_call(boost::bind(&t_cryptonote_protocol_handler::kick_idle_peers, this)); m_standby_checker.do_call(boost::bind(&t_cryptonote_protocol_handler::check_standby_peers, this)); + m_sync_search_checker.do_call(boost::bind(&t_cryptonote_protocol_handler::update_sync_search, this)); return m_core.on_idle(); } //------------------------------------------------------------------------------------------------------------------------ @@ -1400,6 +1401,47 @@ skip: } //------------------------------------------------------------------------------------------------------------------------ template + bool t_cryptonote_protocol_handler::update_sync_search() + { + const uint64_t target = m_core.get_target_blockchain_height(); + const uint64_t height = m_core.get_current_blockchain_height(); + if (target > height) // if we're not synced yet, don't do it + return true; + + MTRACE("Checking for outgoing syncing peers..."); + unsigned n_syncing = 0, n_synced = 0; + boost::uuids::uuid last_synced_peer_id(boost::uuids::nil_uuid()); + m_p2p->for_each_connection([&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)->bool + { + if (!peer_id || context.m_is_income) // only consider connected outgoing peers + return true; + if (context.m_state == cryptonote_connection_context::state_synchronizing) + ++n_syncing; + if (context.m_state == cryptonote_connection_context::state_normal) + { + ++n_synced; + if (!context.m_anchor) + last_synced_peer_id = context.m_connection_id; + } + return true; + }); + MTRACE(n_syncing << " syncing, " << n_synced << " synced"); + + // if we're at max out peers, and not enough are syncing + if (n_synced + n_syncing >= m_max_out_peers && n_syncing < P2P_DEFAULT_SYNC_SEARCH_CONNECTIONS_COUNT && last_synced_peer_id != boost::uuids::nil_uuid()) + { + if (!m_p2p->for_connection(last_synced_peer_id, [&](cryptonote_connection_context& ctx, nodetool::peerid_type peer_id, uint32_t f)->bool{ + MINFO(ctx << "dropping synced peer, " << n_syncing << " syncing, " << n_synced << " synced"); + drop_connection(ctx, false, false); + return true; + })) + MDEBUG("Failed to find peer we wanted to drop"); + } + + return true; + } + //------------------------------------------------------------------------------------------------------------------------ + template bool t_cryptonote_protocol_handler::check_standby_peers() { m_p2p->for_each_connection([&](cryptonote_connection_context& context, nodetool::peerid_type peer_id, uint32_t support_flags)->bool