diff options
Diffstat (limited to 'src/cryptonote_protocol')
-rw-r--r-- | src/cryptonote_protocol/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/cryptonote_protocol/block_queue.cpp | 2 | ||||
-rw-r--r-- | src/cryptonote_protocol/block_queue.h | 2 | ||||
-rw-r--r-- | src/cryptonote_protocol/cryptonote_protocol_defs.h | 2 | ||||
-rw-r--r-- | src/cryptonote_protocol/cryptonote_protocol_handler-base.cpp | 3 | ||||
-rw-r--r-- | src/cryptonote_protocol/cryptonote_protocol_handler.h | 20 | ||||
-rw-r--r-- | src/cryptonote_protocol/cryptonote_protocol_handler.inl | 66 | ||||
-rw-r--r-- | src/cryptonote_protocol/cryptonote_protocol_handler_common.h | 2 | ||||
-rw-r--r-- | src/cryptonote_protocol/enums.h | 2 | ||||
-rw-r--r-- | src/cryptonote_protocol/fwd.h | 2 | ||||
-rw-r--r-- | src/cryptonote_protocol/levin_notify.cpp | 56 | ||||
-rw-r--r-- | src/cryptonote_protocol/levin_notify.h | 5 |
12 files changed, 115 insertions, 49 deletions
diff --git a/src/cryptonote_protocol/CMakeLists.txt b/src/cryptonote_protocol/CMakeLists.txt index 85c25546f..b516e17e9 100644 --- a/src/cryptonote_protocol/CMakeLists.txt +++ b/src/cryptonote_protocol/CMakeLists.txt @@ -1,4 +1,4 @@ -# Copyright (c) 2014-2020, The Monero Project +# Copyright (c) 2014-2022, The Monero Project # # All rights reserved. # diff --git a/src/cryptonote_protocol/block_queue.cpp b/src/cryptonote_protocol/block_queue.cpp index 2f5b693dd..4e65eafa4 100644 --- a/src/cryptonote_protocol/block_queue.cpp +++ b/src/cryptonote_protocol/block_queue.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020, The Monero Project +// Copyright (c) 2017-2022, The Monero Project // // All rights reserved. // diff --git a/src/cryptonote_protocol/block_queue.h b/src/cryptonote_protocol/block_queue.h index 30fb5bc21..64ff106a3 100644 --- a/src/cryptonote_protocol/block_queue.h +++ b/src/cryptonote_protocol/block_queue.h @@ -1,4 +1,4 @@ -// Copyright (c) 2017-2020, The Monero Project +// Copyright (c) 2017-2022, The Monero Project // // All rights reserved. // diff --git a/src/cryptonote_protocol/cryptonote_protocol_defs.h b/src/cryptonote_protocol/cryptonote_protocol_defs.h index 8c511e824..0b860f1a8 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_defs.h +++ b/src/cryptonote_protocol/cryptonote_protocol_defs.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2020, The Monero Project +// Copyright (c) 2014-2022, The Monero Project // // All rights reserved. // diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler-base.cpp b/src/cryptonote_protocol/cryptonote_protocol_handler-base.cpp index 42774f2cb..92ee08054 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_handler-base.cpp +++ b/src/cryptonote_protocol/cryptonote_protocol_handler-base.cpp @@ -2,7 +2,7 @@ /// @author rfree (current maintainer in monero.cc project) /// @brief This is the place to implement our handlers for protocol network actions, e.g. for ratelimit for download-requests -// Copyright (c) 2014-2020, The Monero Project +// Copyright (c) 2014-2022, The Monero Project // // All rights reserved. // @@ -43,7 +43,6 @@ #include <boost/date_time/posix_time/posix_time.hpp> #include <boost/thread/thread.hpp> #include "misc_language.h" -#include "pragma_comp_defs.h" #include <algorithm> diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.h b/src/cryptonote_protocol/cryptonote_protocol_handler.h index 80dd2bc39..515b78c94 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_handler.h +++ b/src/cryptonote_protocol/cryptonote_protocol_handler.h @@ -2,7 +2,7 @@ /// @author rfree (current maintainer/user in monero.cc project - most of code is from CryptoNote) /// @brief This is the original cryptonote protocol network-events handler, modified by us -// Copyright (c) 2014-2020, The Monero Project +// Copyright (c) 2014-2022, The Monero Project // // All rights reserved. // @@ -113,12 +113,23 @@ namespace cryptonote const block_queue &get_block_queue() const { return m_block_queue; } void stop(); void on_connection_close(cryptonote_connection_context &context); - void set_max_out_peers(unsigned int max) { m_max_out_peers = max; } + void set_max_out_peers(epee::net_utils::zone zone, unsigned int max) { CRITICAL_REGION_LOCAL(m_max_out_peers_lock); m_max_out_peers[zone] = max; } + unsigned int get_max_out_peers(epee::net_utils::zone zone) const + { + CRITICAL_REGION_LOCAL(m_max_out_peers_lock); + const auto it = m_max_out_peers.find(zone); + if (it == m_max_out_peers.end()) + { + MWARNING(epee::net_utils::zone_to_string(zone) << " max out peers not set, using default"); + return P2P_DEFAULT_CONNECTIONS_COUNT; + } + return it->second; + } bool no_sync() const { return m_no_sync; } void set_no_sync(bool value) { m_no_sync = value; } std::string get_peers_overview() const; std::pair<uint32_t, uint32_t> get_next_needed_pruning_stripe() const; - bool needs_new_sync_connections() const; + bool needs_new_sync_connections(epee::net_utils::zone zone) const; bool is_busy_syncing(); private: @@ -171,7 +182,8 @@ namespace cryptonote epee::math_helper::once_a_time_milliseconds<100> m_standby_checker; epee::math_helper::once_a_time_seconds<101> m_sync_search_checker; epee::math_helper::once_a_time_seconds<43> m_bad_peer_checker; - std::atomic<unsigned int> m_max_out_peers; + std::unordered_map<epee::net_utils::zone, unsigned int> m_max_out_peers; + mutable epee::critical_section m_max_out_peers_lock; tools::PerformanceTimer m_sync_timer, m_add_timer; uint64_t m_last_add_end_time; uint64_t m_sync_spans_downloaded, m_sync_old_spans_downloaded, m_sync_bad_spans_downloaded; diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler.inl b/src/cryptonote_protocol/cryptonote_protocol_handler.inl index 106253082..af3031263 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_handler.inl +++ b/src/cryptonote_protocol/cryptonote_protocol_handler.inl @@ -2,7 +2,7 @@ /// @author rfree (current maintainer/user in monero.cc project - most of code is from CryptoNote) /// @brief This is the original cryptonote protocol network-events handler, modified by us -// Copyright (c) 2014-2020, The Monero Project +// Copyright (c) 2014-2022, The Monero Project // // All rights reserved. // @@ -35,7 +35,6 @@ // (may contain code and/or modifications by other developers) // developer rfree: this code is caller of our new network code, and is modded; e.g. for rate limiting -#include <boost/interprocess/detail/atomic.hpp> #include <list> #include <ctime> @@ -153,6 +152,7 @@ namespace cryptonote context.m_last_request_time = boost::date_time::not_a_date_time; context.m_expect_response = 0; context.m_expect_height = 0; + context.m_requested_objects.clear(); context.m_state = cryptonote_connection_context::state_standby; // we'll go back to adding, then (if we can't), download } else @@ -1776,33 +1776,49 @@ skip: 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()); + std::unordered_map<epee::net_utils::zone, unsigned> n_syncing, n_synced; + std::unordered_map<epee::net_utils::zone, boost::uuids::uuid> last_synced_peer_id; + std::vector<epee::net_utils::zone> zones; 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; + + const epee::net_utils::zone zone = context.m_remote_address.get_zone(); + if (n_syncing.find(zone) == n_syncing.end()) + { + n_syncing[zone] = 0; + n_synced[zone] = 0; + last_synced_peer_id[zone] = boost::uuids::nil_uuid(); + zones.push_back(zone); + } + if (context.m_state == cryptonote_connection_context::state_synchronizing) - ++n_syncing; + ++n_syncing[zone]; if (context.m_state == cryptonote_connection_context::state_normal) { - ++n_synced; + ++n_synced[zone]; if (!context.m_anchor) - last_synced_peer_id = context.m_connection_id; + last_synced_peer_id[zone] = 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()) + for (const auto& zone : zones) { - 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"); + const unsigned int max_out_peers = get_max_out_peers(zone); + MTRACE("[" << epee::net_utils::zone_to_string(zone) << "] " << n_syncing[zone] << " syncing, " << n_synced[zone] << " synced, " << max_out_peers << " max out peers"); + + // if we're at max out peers, and not enough are syncing, drop the last sync'd non-anchor + if (n_synced[zone] + n_syncing[zone] >= max_out_peers && n_syncing[zone] < P2P_DEFAULT_SYNC_SEARCH_CONNECTIONS_COUNT && last_synced_peer_id[zone] != boost::uuids::nil_uuid()) + { + if (!m_p2p->for_connection(last_synced_peer_id[zone], [&](cryptonote_connection_context& ctx, nodetool::peerid_type peer_id, uint32_t f)->bool{ + MINFO(ctx << "dropping synced peer, " << n_syncing[zone] << " syncing, " << n_synced[zone] << " synced, " << max_out_peers << " max out peers"); + drop_connection(ctx, false, false); + return true; + })) + MDEBUG("Failed to find peer we wanted to drop"); + } } return true; @@ -1987,11 +2003,13 @@ skip: ++n_peers_on_next_stripe; return true; }); + // TODO: investigate tallying by zone and comparing to max out peers by zone + const unsigned int max_out_peers = get_max_out_peers(epee::net_utils::zone::public_); const uint32_t distance = (peer_stripe + (1<<CRYPTONOTE_PRUNING_LOG_STRIPES) - next_stripe) % (1<<CRYPTONOTE_PRUNING_LOG_STRIPES); - if ((n_out_peers >= m_max_out_peers && n_peers_on_next_stripe == 0) || (distance > 1 && n_peers_on_next_stripe <= 2) || distance > 2) + if ((n_out_peers >= max_out_peers && n_peers_on_next_stripe == 0) || (distance > 1 && n_peers_on_next_stripe <= 2) || distance > 2) { MDEBUG(context << "we want seed " << next_stripe << ", and either " << n_out_peers << " is at max out peers (" - << m_max_out_peers << ") or distance " << distance << " from " << next_stripe << " to " << peer_stripe << + << max_out_peers << ") or distance " << distance << " from " << next_stripe << " to " << peer_stripe << " is too large and we have only " << n_peers_on_next_stripe << " peers on next seed, dropping connection to make space"); return true; } @@ -2812,11 +2830,13 @@ skip: } return true; }); - const bool use_next = (n_next > m_max_out_peers / 2 && n_subsequent <= 1) || (n_next > 2 && n_subsequent == 0); + // TODO: investigate tallying by zone and comparing to max out peers by zone + const unsigned int max_out_peers = get_max_out_peers(epee::net_utils::zone::public_); + const bool use_next = (n_next > max_out_peers / 2 && n_subsequent <= 1) || (n_next > 2 && n_subsequent == 0); const uint32_t ret_stripe = use_next ? subsequent_pruning_stripe: next_pruning_stripe; MIDEBUG(const std::string po = get_peers_overview(), "get_next_needed_pruning_stripe: want height " << want_height << " (" << want_height_from_blockchain << " from blockchain, " << want_height_from_block_queue << " from block queue), stripe " << - next_pruning_stripe << " (" << n_next << "/" << m_max_out_peers << " on it and " << n_subsequent << " on " << + next_pruning_stripe << " (" << n_next << "/" << max_out_peers << " on it and " << n_subsequent << " on " << subsequent_pruning_stripe << ", " << n_others << " others) -> " << ret_stripe << " (+" << (ret_stripe - next_pruning_stripe + (1 << CRYPTONOTE_PRUNING_LOG_STRIPES)) % (1 << CRYPTONOTE_PRUNING_LOG_STRIPES) << "), current peers " << po); @@ -2824,7 +2844,7 @@ skip: } //------------------------------------------------------------------------------------------------------------------------ template<class t_core> - bool t_cryptonote_protocol_handler<t_core>::needs_new_sync_connections() const + bool t_cryptonote_protocol_handler<t_core>::needs_new_sync_connections(epee::net_utils::zone zone) const { const uint64_t target = m_core.get_target_blockchain_height(); const uint64_t height = m_core.get_current_blockchain_height(); @@ -2832,11 +2852,11 @@ skip: return false; size_t n_out_peers = 0; m_p2p->for_each_connection([&](cryptonote_connection_context& ctx, nodetool::peerid_type peer_id, uint32_t support_flags)->bool{ - if (!ctx.m_is_income) + if (!ctx.m_is_income && ctx.m_remote_address.get_zone() == zone) ++n_out_peers; return true; }); - if (n_out_peers >= m_max_out_peers) + if (n_out_peers >= get_max_out_peers(zone)) return false; return true; } diff --git a/src/cryptonote_protocol/cryptonote_protocol_handler_common.h b/src/cryptonote_protocol/cryptonote_protocol_handler_common.h index 57b1d049c..3b2ca5e37 100644 --- a/src/cryptonote_protocol/cryptonote_protocol_handler_common.h +++ b/src/cryptonote_protocol/cryptonote_protocol_handler_common.h @@ -1,4 +1,4 @@ -// Copyright (c) 2014-2020, The Monero Project +// Copyright (c) 2014-2022, The Monero Project // // All rights reserved. // diff --git a/src/cryptonote_protocol/enums.h b/src/cryptonote_protocol/enums.h index c0c495837..aeb66ed5c 100644 --- a/src/cryptonote_protocol/enums.h +++ b/src/cryptonote_protocol/enums.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020, The Monero Project +// Copyright (c) 2019-2022, The Monero Project // // All rights reserved. // diff --git a/src/cryptonote_protocol/fwd.h b/src/cryptonote_protocol/fwd.h index e7722c2f4..f036f41cb 100644 --- a/src/cryptonote_protocol/fwd.h +++ b/src/cryptonote_protocol/fwd.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020, The Monero Project +// Copyright (c) 2019-2022, The Monero Project // // All rights reserved. // diff --git a/src/cryptonote_protocol/levin_notify.cpp b/src/cryptonote_protocol/levin_notify.cpp index 0b065c3c3..83f37015f 100644 --- a/src/cryptonote_protocol/levin_notify.cpp +++ b/src/cryptonote_protocol/levin_notify.cpp @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020, The Monero Project +// Copyright (c) 2019-2022, The Monero Project // // All rights reserved. // @@ -287,6 +287,12 @@ namespace levin boost::asio::steady_timer next_epoch; boost::asio::steady_timer flush_txs; boost::asio::io_service::strand strand; + struct context_t { + std::vector<cryptonote::blobdata> fluff_txs; + std::chrono::steady_clock::time_point flush_time; + bool m_is_income; + }; + boost::unordered_map<boost::uuids::uuid, context_t> contexts; net::dandelionpp::connection_map map;//!< Tracks outgoing uuid's for noise channels or Dandelion++ stems std::deque<noise_channel> channels; //!< Never touch after init; only update elements on `noise_channel.strand` std::atomic<std::size_t> connection_count; //!< Only update in strand, can be read at any time @@ -363,14 +369,16 @@ namespace levin const auto now = std::chrono::steady_clock::now(); auto next_flush = std::chrono::steady_clock::time_point::max(); std::vector<std::pair<std::vector<blobdata>, boost::uuids::uuid>> connections{}; - zone_->p2p->foreach_connection([timer_error, now, &next_flush, &connections] (detail::p2p_context& context) + for (auto &e: zone_->contexts) { + auto &id = e.first; + auto &context = e.second; if (!context.fluff_txs.empty()) { if (context.flush_time <= now || timer_error) // flush on canceled timer { context.flush_time = std::chrono::steady_clock::time_point::max(); - connections.emplace_back(std::move(context.fluff_txs), context.m_connection_id); + connections.emplace_back(std::move(context.fluff_txs), id); context.fluff_txs.clear(); } else // not flushing yet @@ -378,8 +386,7 @@ namespace levin } else // nothing to flush context.flush_time = std::chrono::steady_clock::time_point::max(); - return true; - }); + } /* Always send with `fluff` flag, even over i2p/tor. The hidden service will disable the forwarding delay and immediately fluff. The i2p/tor @@ -427,22 +434,21 @@ namespace levin MDEBUG("Queueing " << txs.size() << " transaction(s) for Dandelion++ fluffing"); - - zone->p2p->foreach_connection([txs, now, &zone, &source, &in_duration, &out_duration, &next_flush] (detail::p2p_context& context) + for (auto &e: zone->contexts) { + auto &id = e.first; + auto &context = e.second; // When i2p/tor, only fluff to outbound connections - if (context.handshake_complete() && source != context.m_connection_id && (zone->nzone == epee::net_utils::zone::public_ || !context.m_is_income)) + if (source != id && (zone->nzone == epee::net_utils::zone::public_ || !context.m_is_income)) { if (context.fluff_txs.empty()) context.flush_time = now + (context.m_is_income ? in_duration() : out_duration()); next_flush = std::min(next_flush, context.flush_time); context.fluff_txs.reserve(context.fluff_txs.size() + txs.size()); - for (const blobdata& tx : txs) - context.fluff_txs.push_back(tx); // must copy instead of move (multiple conns) + context.fluff_txs.insert(context.fluff_txs.end(), txs.begin(), txs.end()); } - return true; - }); + } if (next_flush == std::chrono::steady_clock::time_point::max()) MWARNING("Unable to send transaction(s), no available connections"); @@ -749,6 +755,32 @@ namespace levin ); } + void notify::on_handshake_complete(const boost::uuids::uuid &id, bool is_income) + { + if (!zone_) + return; + + auto& zone = zone_; + zone_->strand.dispatch([zone, id, is_income]{ + zone->contexts[id] = { + .fluff_txs = {}, + .flush_time = std::chrono::steady_clock::time_point::max(), + .m_is_income = is_income, + }; + }); + } + + void notify::on_connection_close(const boost::uuids::uuid &id) + { + if (!zone_) + return; + + auto& zone = zone_; + zone_->strand.dispatch([zone, id]{ + zone->contexts.erase(id); + }); + } + void notify::run_epoch() { if (!zone_) diff --git a/src/cryptonote_protocol/levin_notify.h b/src/cryptonote_protocol/levin_notify.h index abbf9d461..2927eea86 100644 --- a/src/cryptonote_protocol/levin_notify.h +++ b/src/cryptonote_protocol/levin_notify.h @@ -1,4 +1,4 @@ -// Copyright (c) 2019-2020, The Monero Project +// Copyright (c) 2019-2022, The Monero Project // // All rights reserved. // @@ -101,6 +101,9 @@ namespace levin //! Probe for new outbound connection - skips if not needed. void new_out_connection(); + void on_handshake_complete(const boost::uuids::uuid &id, bool is_income); + void on_connection_close(const boost::uuids::uuid &id); + //! Run the logic for the next epoch immediately. Only use in testing. void run_epoch(); |