aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorlaanwj <126646+laanwj@users.noreply.github.com>2022-03-02 09:35:35 +0100
committerlaanwj <126646+laanwj@users.noreply.github.com>2022-03-02 12:00:58 +0100
commit8b6cd42c6226dea28c182a48a214d1c091b9b5bb (patch)
tree6338de0a4413907e3134c886f09eb2102371fe7f /src
parent267917f5632a99bb51fc3fe516d8308e79d31ed1 (diff)
parentb7be28cac50046b9f2ddfe63ecafccc80649a36c (diff)
downloadbitcoin-8b6cd42c6226dea28c182a48a214d1c091b9b5bb.tar.xz
Merge bitcoin/bitcoin#24165: p2p: extend inbound eviction protection by network to CJDNS peers
b7be28cac50046b9f2ddfe63ecafccc80649a36c test: add combined CJDNS/I2P/localhost/onion eviction protection tests (Jon Atack) 0a1bb84770b403ab5cbd9d5474c76f91ce58e8f6 test: add tests for inbound eviction protection of CJDNS peers (Jon Atack) 0c00c0c981fc0b6cec101e68e8c1aeda1ccf33bb test: fix off-by-one logic in an eviction protection test (Jon Atack) f7b8094d611531c6b41a94715dbc01f56257ccd2 p2p: extend inbound eviction protection by network to CJDNS peers (Jon Atack) Pull request description: Extend inbound eviction protection for peers connected over CJDNS, as is the case for peers connected via onion, localhost, and I2P since #21261 and #20197. CJDNS peers seem to have better min ping latency than onion and I2P peers but still higher than that of unencrypted IPv4/6 peers and can be disadvantaged under our eviction criteria. They are also very few in number, which is a further reason to protect them, as the goal of this logic is to favorise the diversity of our peer connections. CJDNS support was added in #23077 for the upcoming v23 release. ACKs for top commit: laanwj: Concept and code review ACK b7be28cac50046b9f2ddfe63ecafccc80649a36c w0xlt: tACK b7be28c Tree-SHA512: 89ebdd217602e16ae14b9bd0d5a25fc09f9b2384c951f820bc0f5a6d8452bbc9042065db817d5d5296c0ad22988491a83fc5b9a611e660c40ebd4f03448c4061
Diffstat (limited to 'src')
-rw-r--r--src/net.cpp12
-rw-r--r--src/net.h2
-rw-r--r--src/test/net_peer_eviction_tests.cpp163
3 files changed, 156 insertions, 21 deletions
diff --git a/src/net.cpp b/src/net.cpp
index 15616613d2..9bb264a38a 100644
--- a/src/net.cpp
+++ b/src/net.cpp
@@ -928,17 +928,17 @@ void ProtectEvictionCandidatesByRatio(std::vector<NodeEvictionCandidate>& evicti
// Protect the half of the remaining nodes which have been connected the longest.
// This replicates the non-eviction implicit behavior, and precludes attacks that start later.
// To favorise the diversity of our peer connections, reserve up to half of these protected
- // spots for Tor/onion, localhost and I2P peers, even if they're not longest uptime overall.
- // This helps protect these higher-latency peers that tend to be otherwise
+ // spots for Tor/onion, localhost, I2P, and CJDNS peers, even if they're not longest uptime
+ // overall. This helps protect these higher-latency peers that tend to be otherwise
// disadvantaged under our eviction criteria.
const size_t initial_size = eviction_candidates.size();
const size_t total_protect_size{initial_size / 2};
- // Disadvantaged networks to protect: I2P, localhost, Tor/onion. In case of equal counts, earlier
- // array members have first opportunity to recover unused slots from the previous iteration.
+ // Disadvantaged networks to protect. In the case of equal counts, earlier array members
+ // have the first opportunity to recover unused slots from the previous iteration.
struct Net { bool is_local; Network id; size_t count; };
- std::array<Net, 3> networks{
- {{false, NET_I2P, 0}, {/* localhost */ true, NET_MAX, 0}, {false, NET_ONION, 0}}};
+ std::array<Net, 4> networks{
+ {{false, NET_CJDNS, 0}, {false, NET_I2P, 0}, {/*localhost=*/true, NET_MAX, 0}, {false, NET_ONION, 0}}};
// Count and store the number of eviction candidates per network.
for (Net& n : networks) {
diff --git a/src/net.h b/src/net.h
index 3f4c8e38ec..bbc253e7ff 100644
--- a/src/net.h
+++ b/src/net.h
@@ -1316,6 +1316,8 @@ struct NodeEvictionCandidate
*
* - I2P peers
*
+ * - CJDNS peers
+ *
* This helps protect these privacy network peers, which tend to be otherwise
* disadvantaged under our eviction criteria for their higher min ping times
* relative to IPv4/IPv6 peers, and favorise the diversity of peer connections.
diff --git a/src/test/net_peer_eviction_tests.cpp b/src/test/net_peer_eviction_tests.cpp
index 78ad24a408..6ec3fb0c6b 100644
--- a/src/test/net_peer_eviction_tests.cpp
+++ b/src/test/net_peer_eviction_tests.cpp
@@ -90,7 +90,7 @@ BOOST_AUTO_TEST_CASE(peer_protection_test)
// Test protection of onion, localhost, and I2P peers...
// Expect 1/4 onion peers to be protected from eviction,
- // if no localhost or I2P peers.
+ // if no localhost, I2P, or CJDNS peers.
BOOST_CHECK(IsProtected(
num_peers, [](NodeEvictionCandidate& c) {
c.m_is_local = false;
@@ -101,7 +101,7 @@ BOOST_AUTO_TEST_CASE(peer_protection_test)
random_context));
// Expect 1/4 onion peers and 1/4 of the other peers to be protected,
- // sorted by longest uptime (lowest m_connected), if no localhost or I2P peers.
+ // sorted by longest uptime (lowest m_connected), if no localhost, I2P or CJDNS peers.
BOOST_CHECK(IsProtected(
num_peers, [](NodeEvictionCandidate& c) {
c.m_connected = std::chrono::seconds{c.id};
@@ -113,7 +113,7 @@ BOOST_AUTO_TEST_CASE(peer_protection_test)
random_context));
// Expect 1/4 localhost peers to be protected from eviction,
- // if no onion or I2P peers.
+ // if no onion, I2P, or CJDNS peers.
BOOST_CHECK(IsProtected(
num_peers, [](NodeEvictionCandidate& c) {
c.m_is_local = (c.id == 1 || c.id == 9 || c.id == 11);
@@ -124,7 +124,7 @@ BOOST_AUTO_TEST_CASE(peer_protection_test)
random_context));
// Expect 1/4 localhost peers and 1/4 of the other peers to be protected,
- // sorted by longest uptime (lowest m_connected), if no onion or I2P peers.
+ // sorted by longest uptime (lowest m_connected), if no onion, I2P, or CJDNS peers.
BOOST_CHECK(IsProtected(
num_peers, [](NodeEvictionCandidate& c) {
c.m_connected = std::chrono::seconds{c.id};
@@ -136,7 +136,7 @@ BOOST_AUTO_TEST_CASE(peer_protection_test)
random_context));
// Expect 1/4 I2P peers to be protected from eviction,
- // if no onion or localhost peers.
+ // if no onion, localhost, or CJDNS peers.
BOOST_CHECK(IsProtected(
num_peers, [](NodeEvictionCandidate& c) {
c.m_is_local = false;
@@ -146,8 +146,8 @@ BOOST_AUTO_TEST_CASE(peer_protection_test)
/*unprotected_peer_ids=*/{},
random_context));
- // Expect 1/4 I2P peers and 1/4 of the other peers to be protected,
- // sorted by longest uptime (lowest m_connected), if no onion or localhost peers.
+ // Expect 1/4 I2P peers and 1/4 of the other peers to be protected, sorted
+ // by longest uptime (lowest m_connected), if no onion, localhost, or CJDNS peers.
BOOST_CHECK(IsProtected(
num_peers, [](NodeEvictionCandidate& c) {
c.m_connected = std::chrono::seconds{c.id};
@@ -158,6 +158,29 @@ BOOST_AUTO_TEST_CASE(peer_protection_test)
/*unprotected_peer_ids=*/{3, 5, 6, 7, 8, 11},
random_context));
+ // Expect 1/4 CJDNS peers to be protected from eviction,
+ // if no onion, localhost, or I2P peers.
+ BOOST_CHECK(IsProtected(
+ num_peers, [](NodeEvictionCandidate& c) {
+ c.m_is_local = false;
+ c.m_network = (c.id == 2 || c.id == 7 || c.id == 10) ? NET_CJDNS : NET_IPV4;
+ },
+ /*protected_peer_ids=*/{2, 7, 10},
+ /*unprotected_peer_ids=*/{},
+ random_context));
+
+ // Expect 1/4 CJDNS peers and 1/4 of the other peers to be protected, sorted
+ // by longest uptime (lowest m_connected), if no onion, localhost, or I2P peers.
+ BOOST_CHECK(IsProtected(
+ num_peers, [](NodeEvictionCandidate& c) {
+ c.m_connected = std::chrono::seconds{c.id};
+ c.m_is_local = false;
+ c.m_network = (c.id == 4 || c.id > 8) ? NET_CJDNS : NET_IPV6;
+ },
+ /*protected_peer_ids=*/{0, 1, 2, 4, 9, 10},
+ /*unprotected_peer_ids=*/{3, 5, 6, 7, 8, 11},
+ random_context));
+
// Tests with 2 networks...
// Combined test: expect having 1 localhost and 1 onion peer out of 4 to
@@ -289,16 +312,16 @@ BOOST_AUTO_TEST_CASE(peer_protection_test)
BOOST_CHECK(IsProtected(
4, [](NodeEvictionCandidate& c) {
c.m_connected = std::chrono::seconds{c.id};
- c.m_is_local = (c.id == 3);
- if (c.id == 4) {
+ c.m_is_local = (c.id == 2);
+ if (c.id == 3) {
c.m_network = NET_I2P;
- } else if (c.id == 2) {
+ } else if (c.id == 1) {
c.m_network = NET_ONION;
} else {
c.m_network = NET_IPV6;
}
},
- /*protected_peer_ids=*/{0, 4},
+ /*protected_peer_ids=*/{0, 3},
/*unprotected_peer_ids=*/{1, 2},
random_context));
@@ -416,15 +439,15 @@ BOOST_AUTO_TEST_CASE(peer_protection_test)
/*unprotected_peer_ids=*/{6, 7, 8, 9, 10, 11, 16, 19, 20, 21, 22, 23},
random_context));
- // Combined test: expect having 8 localhost, 4 I2P, and 3 onion peers out of
- // 24 to protect 2 of each (6 total), plus 6 others for 12/24 total, sorted
- // by longest uptime.
+ // Combined test: expect having 8 localhost, 4 CJDNS, and 3 onion peers out
+ // of 24 to protect 2 of each (6 total), plus 6 others for 12/24 total,
+ // sorted by longest uptime.
BOOST_CHECK(IsProtected(
24, [](NodeEvictionCandidate& c) {
c.m_connected = std::chrono::seconds{c.id};
c.m_is_local = (c.id > 15);
if (c.id > 10 && c.id < 15) {
- c.m_network = NET_I2P;
+ c.m_network = NET_CJDNS;
} else if (c.id > 6 && c.id < 10) {
c.m_network = NET_ONION;
} else {
@@ -434,6 +457,116 @@ BOOST_AUTO_TEST_CASE(peer_protection_test)
/*protected_peer_ids=*/{0, 1, 2, 3, 4, 5, 7, 8, 11, 12, 16, 17},
/*unprotected_peer_ids=*/{6, 9, 10, 13, 14, 15, 18, 19, 20, 21, 22, 23},
random_context));
+
+ // Tests with 4 networks...
+
+ // Combined test: expect having 1 CJDNS, 1 I2P, 1 localhost and 1 onion peer
+ // out of 5 to protect 1 CJDNS, 0 I2P, 0 localhost, 0 onion and 1 other peer
+ // (2 total), sorted by longest uptime; stable sort breaks tie with array
+ // order of CJDNS first.
+ BOOST_CHECK(IsProtected(
+ 5, [](NodeEvictionCandidate& c) {
+ c.m_connected = std::chrono::seconds{c.id};
+ c.m_is_local = (c.id == 3);
+ if (c.id == 4) {
+ c.m_network = NET_CJDNS;
+ } else if (c.id == 1) {
+ c.m_network = NET_I2P;
+ } else if (c.id == 2) {
+ c.m_network = NET_ONION;
+ } else {
+ c.m_network = NET_IPV6;
+ }
+ },
+ /* protected_peer_ids */ {0, 4},
+ /* unprotected_peer_ids */ {1, 2, 3},
+ random_context));
+
+ // Combined test: expect having 1 CJDNS, 1 I2P, 1 localhost and 1 onion peer
+ // out of 7 to protect 1 CJDNS, 0, I2P, 0 localhost, 0 onion and 2 other
+ // peers (3 total) sorted by longest uptime; stable sort breaks tie with
+ // array order of CJDNS first.
+ BOOST_CHECK(IsProtected(
+ 7, [](NodeEvictionCandidate& c) {
+ c.m_connected = std::chrono::seconds{c.id};
+ c.m_is_local = (c.id == 4);
+ if (c.id == 6) {
+ c.m_network = NET_CJDNS;
+ } else if (c.id == 5) {
+ c.m_network = NET_I2P;
+ } else if (c.id == 3) {
+ c.m_network = NET_ONION;
+ } else {
+ c.m_network = NET_IPV4;
+ }
+ },
+ /*protected_peer_ids=*/{0, 1, 6},
+ /*unprotected_peer_ids=*/{2, 3, 4, 5},
+ random_context));
+
+ // Combined test: expect having 1 CJDNS, 1 I2P, 1 localhost and 1 onion peer
+ // out of 8 to protect 1 CJDNS, 1 I2P, 0 localhost, 0 onion and 2 other
+ // peers (4 total) sorted by longest uptime; stable sort breaks tie with
+ // array order of CJDNS first.
+ BOOST_CHECK(IsProtected(
+ 8, [](NodeEvictionCandidate& c) {
+ c.m_connected = std::chrono::seconds{c.id};
+ c.m_is_local = (c.id == 3);
+ if (c.id == 5) {
+ c.m_network = NET_CJDNS;
+ } else if (c.id == 6) {
+ c.m_network = NET_I2P;
+ } else if (c.id == 3) {
+ c.m_network = NET_ONION;
+ } else {
+ c.m_network = NET_IPV6;
+ }
+ },
+ /*protected_peer_ids=*/{0, 1, 5, 6},
+ /*unprotected_peer_ids=*/{2, 3, 4, 7},
+ random_context));
+
+ // Combined test: expect having 2 CJDNS, 2 I2P, 4 localhost, and 2 onion
+ // peers out of 16 to protect 1 CJDNS, 1 I2P, 1 localhost, 1 onion (4/16
+ // total), plus 4 others for 8 total, sorted by longest uptime.
+ BOOST_CHECK(IsProtected(
+ 16, [](NodeEvictionCandidate& c) {
+ c.m_connected = std::chrono::seconds{c.id};
+ c.m_is_local = (c.id > 5);
+ if (c.id == 11 || c.id == 15) {
+ c.m_network = NET_CJDNS;
+ } else if (c.id == 10 || c.id == 14) {
+ c.m_network = NET_I2P;
+ } else if (c.id == 8 || c.id == 9) {
+ c.m_network = NET_ONION;
+ } else {
+ c.m_network = NET_IPV4;
+ }
+ },
+ /*protected_peer_ids=*/{0, 1, 2, 3, 6, 8, 10, 11},
+ /*unprotected_peer_ids=*/{4, 5, 7, 9, 12, 13, 14, 15},
+ random_context));
+
+ // Combined test: expect having 6 CJDNS, 1 I2P, 1 localhost, and 4 onion
+ // peers out of 24 to protect 2 CJDNS, 1 I2P, 1 localhost, and 2 onions (6
+ // total), plus 6 others for 12/24 total, sorted by longest uptime.
+ BOOST_CHECK(IsProtected(
+ 24, [](NodeEvictionCandidate& c) {
+ c.m_connected = std::chrono::seconds{c.id};
+ c.m_is_local = (c.id == 13);
+ if (c.id > 17) {
+ c.m_network = NET_CJDNS;
+ } else if (c.id == 17) {
+ c.m_network = NET_I2P;
+ } else if (c.id == 12 || c.id == 14 || c.id == 15 || c.id == 16) {
+ c.m_network = NET_ONION;
+ } else {
+ c.m_network = NET_IPV6;
+ }
+ },
+ /*protected_peer_ids=*/{0, 1, 2, 3, 4, 5, 12, 13, 14, 17, 18, 19},
+ /*unprotected_peer_ids=*/{6, 7, 8, 9, 10, 11, 15, 16, 20, 21, 22, 23},
+ random_context));
}
// Returns true if any of the node ids in node_ids are selected for eviction.