aboutsummaryrefslogtreecommitdiff
path: root/src/cryptonote_protocol
diff options
context:
space:
mode:
Diffstat (limited to 'src/cryptonote_protocol')
-rw-r--r--src/cryptonote_protocol/CMakeLists.txt2
-rw-r--r--src/cryptonote_protocol/block_queue.cpp2
-rw-r--r--src/cryptonote_protocol/block_queue.h2
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_defs.h2
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler-base.cpp3
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.h20
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler.inl66
-rw-r--r--src/cryptonote_protocol/cryptonote_protocol_handler_common.h2
-rw-r--r--src/cryptonote_protocol/enums.h2
-rw-r--r--src/cryptonote_protocol/fwd.h2
-rw-r--r--src/cryptonote_protocol/levin_notify.cpp56
-rw-r--r--src/cryptonote_protocol/levin_notify.h5
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();