Skip to content

Commit 5436b6a

Browse files
committed
merge bitcoin#24165: extend inbound eviction protection by network to CJDNS peers
1 parent d52724d commit 5436b6a

File tree

3 files changed

+156
-21
lines changed

3 files changed

+156
-21
lines changed

src/net.cpp

+6-6
Original file line numberDiff line numberDiff line change
@@ -1026,17 +1026,17 @@ void ProtectEvictionCandidatesByRatio(std::vector<NodeEvictionCandidate>& evicti
10261026
// Protect the half of the remaining nodes which have been connected the longest.
10271027
// This replicates the non-eviction implicit behavior, and precludes attacks that start later.
10281028
// To favorise the diversity of our peer connections, reserve up to half of these protected
1029-
// spots for Tor/onion, localhost and I2P peers, even if they're not longest uptime overall.
1030-
// This helps protect these higher-latency peers that tend to be otherwise
1029+
// spots for Tor/onion, localhost, I2P, and CJDNS peers, even if they're not longest uptime
1030+
// overall. This helps protect these higher-latency peers that tend to be otherwise
10311031
// disadvantaged under our eviction criteria.
10321032
const size_t initial_size = eviction_candidates.size();
10331033
const size_t total_protect_size{initial_size / 2};
10341034

1035-
// Disadvantaged networks to protect: I2P, localhost, Tor/onion. In case of equal counts, earlier
1036-
// array members have first opportunity to recover unused slots from the previous iteration.
1035+
// Disadvantaged networks to protect. In the case of equal counts, earlier array members
1036+
// have the first opportunity to recover unused slots from the previous iteration.
10371037
struct Net { bool is_local; Network id; size_t count; };
1038-
std::array<Net, 3> networks{
1039-
{{false, NET_I2P, 0}, {/* localhost */ true, NET_MAX, 0}, {false, NET_ONION, 0}}};
1038+
std::array<Net, 4> networks{
1039+
{{false, NET_CJDNS, 0}, {false, NET_I2P, 0}, {/*localhost=*/true, NET_MAX, 0}, {false, NET_ONION, 0}}};
10401040

10411041
// Count and store the number of eviction candidates per network.
10421042
for (Net& n : networks) {

src/net.h

+2
Original file line numberDiff line numberDiff line change
@@ -1661,6 +1661,8 @@ size_t GetRequestedObjectCount(NodeId nodeId) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
16611661
*
16621662
* - I2P peers
16631663
*
1664+
* - CJDNS peers
1665+
*
16641666
* This helps protect these privacy network peers, which tend to be otherwise
16651667
* disadvantaged under our eviction criteria for their higher min ping times
16661668
* relative to IPv4/IPv6 peers, and favorise the diversity of peer connections.

src/test/net_peer_eviction_tests.cpp

+148-15
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ BOOST_AUTO_TEST_CASE(peer_protection_test)
112112
// Test protection of onion, localhost, and I2P peers...
113113

114114
// Expect 1/4 onion peers to be protected from eviction,
115-
// if no localhost or I2P peers.
115+
// if no localhost, I2P, or CJDNS peers.
116116
BOOST_CHECK(IsProtected(
117117
num_peers, [](NodeEvictionCandidate& c) {
118118
c.m_is_local = false;
@@ -123,7 +123,7 @@ BOOST_AUTO_TEST_CASE(peer_protection_test)
123123
random_context));
124124

125125
// Expect 1/4 onion peers and 1/4 of the other peers to be protected,
126-
// sorted by longest uptime (lowest nTimeConnected), if no localhost or I2P peers.
126+
// sorted by longest uptime (lowest nTimeConnected), if no localhost, I2P or CJDNS peers.
127127
BOOST_CHECK(IsProtected(
128128
num_peers, [](NodeEvictionCandidate& c) {
129129
c.nTimeConnected = c.id;
@@ -135,7 +135,7 @@ BOOST_AUTO_TEST_CASE(peer_protection_test)
135135
random_context));
136136

137137
// Expect 1/4 localhost peers to be protected from eviction,
138-
// if no onion or I2P peers.
138+
// if no onion, I2P, or CJDNS peers.
139139
BOOST_CHECK(IsProtected(
140140
num_peers, [](NodeEvictionCandidate& c) {
141141
c.m_is_local = (c.id == 1 || c.id == 9 || c.id == 11);
@@ -146,7 +146,7 @@ BOOST_AUTO_TEST_CASE(peer_protection_test)
146146
random_context));
147147

148148
// Expect 1/4 localhost peers and 1/4 of the other peers to be protected,
149-
// sorted by longest uptime (lowest nTimeConnected), if no onion or I2P peers.
149+
// sorted by longest uptime (lowest nTimeConnected), if no onion, I2P, or CJDNS peers.
150150
BOOST_CHECK(IsProtected(
151151
num_peers, [](NodeEvictionCandidate& c) {
152152
c.nTimeConnected = c.id;
@@ -158,7 +158,7 @@ BOOST_AUTO_TEST_CASE(peer_protection_test)
158158
random_context));
159159

160160
// Expect 1/4 I2P peers to be protected from eviction,
161-
// if no onion or localhost peers.
161+
// if no onion, localhost, or CJDNS peers.
162162
BOOST_CHECK(IsProtected(
163163
num_peers, [](NodeEvictionCandidate& c) {
164164
c.m_is_local = false;
@@ -168,8 +168,8 @@ BOOST_AUTO_TEST_CASE(peer_protection_test)
168168
/* unprotected_peer_ids */ {},
169169
random_context));
170170

171-
// Expect 1/4 I2P peers and 1/4 of the other peers to be protected,
172-
// sorted by longest uptime (lowest nTimeConnected), if no onion or localhost peers.
171+
// Expect 1/4 I2P peers and 1/4 of the other peers to be protected, sorted
172+
// by longest uptime (lowest nTimeConnected), if no onion, localhost, or CJDNS peers.
173173
BOOST_CHECK(IsProtected(
174174
num_peers, [](NodeEvictionCandidate& c) {
175175
c.nTimeConnected = c.id;
@@ -180,6 +180,29 @@ BOOST_AUTO_TEST_CASE(peer_protection_test)
180180
/* unprotected_peer_ids */ {3, 5, 6, 7, 8, 11},
181181
random_context));
182182

183+
// Expect 1/4 CJDNS peers to be protected from eviction,
184+
// if no onion, localhost, or I2P peers.
185+
BOOST_CHECK(IsProtected(
186+
num_peers, [](NodeEvictionCandidate& c) {
187+
c.m_is_local = false;
188+
c.m_network = (c.id == 2 || c.id == 7 || c.id == 10) ? NET_CJDNS : NET_IPV4;
189+
},
190+
/*protected_peer_ids=*/{2, 7, 10},
191+
/*unprotected_peer_ids=*/{},
192+
random_context));
193+
194+
// Expect 1/4 CJDNS peers and 1/4 of the other peers to be protected, sorted
195+
// by longest uptime (lowest nTimeConnected), if no onion, localhost, or I2P peers.
196+
BOOST_CHECK(IsProtected(
197+
num_peers, [](NodeEvictionCandidate& c) {
198+
c.nTimeConnected = c.id;
199+
c.m_is_local = false;
200+
c.m_network = (c.id == 4 || c.id > 8) ? NET_CJDNS : NET_IPV6;
201+
},
202+
/*protected_peer_ids=*/{0, 1, 2, 4, 9, 10},
203+
/*unprotected_peer_ids=*/{3, 5, 6, 7, 8, 11},
204+
random_context));
205+
183206
// Tests with 2 networks...
184207

185208
// Combined test: expect having 1 localhost and 1 onion peer out of 4 to
@@ -311,16 +334,16 @@ BOOST_AUTO_TEST_CASE(peer_protection_test)
311334
BOOST_CHECK(IsProtected(
312335
4, [](NodeEvictionCandidate& c) {
313336
c.nTimeConnected = c.id;
314-
c.m_is_local = (c.id == 3);
315-
if (c.id == 4) {
337+
c.m_is_local = (c.id == 2);
338+
if (c.id == 3) {
316339
c.m_network = NET_I2P;
317-
} else if (c.id == 2) {
340+
} else if (c.id == 1) {
318341
c.m_network = NET_ONION;
319342
} else {
320343
c.m_network = NET_IPV6;
321344
}
322345
},
323-
/* protected_peer_ids */ {0, 4},
346+
/* protected_peer_ids */ {0, 3},
324347
/* unprotected_peer_ids */ {1, 2},
325348
random_context));
326349

@@ -438,15 +461,15 @@ BOOST_AUTO_TEST_CASE(peer_protection_test)
438461
/* unprotected_peer_ids */ {6, 7, 8, 9, 10, 11, 16, 19, 20, 21, 22, 23},
439462
random_context));
440463

441-
// Combined test: expect having 8 localhost, 4 I2P, and 3 onion peers out of
442-
// 24 to protect 2 of each (6 total), plus 6 others for 12/24 total, sorted
443-
// by longest uptime.
464+
// Combined test: expect having 8 localhost, 4 CJDNS, and 3 onion peers out
465+
// of 24 to protect 2 of each (6 total), plus 6 others for 12/24 total,
466+
// sorted by longest uptime.
444467
BOOST_CHECK(IsProtected(
445468
24, [](NodeEvictionCandidate& c) {
446469
c.nTimeConnected = c.id;
447470
c.m_is_local = (c.id > 15);
448471
if (c.id > 10 && c.id < 15) {
449-
c.m_network = NET_I2P;
472+
c.m_network = NET_CJDNS;
450473
} else if (c.id > 6 && c.id < 10) {
451474
c.m_network = NET_ONION;
452475
} else {
@@ -456,6 +479,116 @@ BOOST_AUTO_TEST_CASE(peer_protection_test)
456479
/* protected_peer_ids */ {0, 1, 2, 3, 4, 5, 7, 8, 11, 12, 16, 17},
457480
/* unprotected_peer_ids */ {6, 9, 10, 13, 14, 15, 18, 19, 20, 21, 22, 23},
458481
random_context));
482+
483+
// Tests with 4 networks...
484+
485+
// Combined test: expect having 1 CJDNS, 1 I2P, 1 localhost and 1 onion peer
486+
// out of 5 to protect 1 CJDNS, 0 I2P, 0 localhost, 0 onion and 1 other peer
487+
// (2 total), sorted by longest uptime; stable sort breaks tie with array
488+
// order of CJDNS first.
489+
BOOST_CHECK(IsProtected(
490+
5, [](NodeEvictionCandidate& c) {
491+
c.nTimeConnected = c.id;
492+
c.m_is_local = (c.id == 3);
493+
if (c.id == 4) {
494+
c.m_network = NET_CJDNS;
495+
} else if (c.id == 1) {
496+
c.m_network = NET_I2P;
497+
} else if (c.id == 2) {
498+
c.m_network = NET_ONION;
499+
} else {
500+
c.m_network = NET_IPV6;
501+
}
502+
},
503+
/* protected_peer_ids */ {0, 4},
504+
/* unprotected_peer_ids */ {1, 2, 3},
505+
random_context));
506+
507+
// Combined test: expect having 1 CJDNS, 1 I2P, 1 localhost and 1 onion peer
508+
// out of 7 to protect 1 CJDNS, 0, I2P, 0 localhost, 0 onion and 2 other
509+
// peers (3 total) sorted by longest uptime; stable sort breaks tie with
510+
// array order of CJDNS first.
511+
BOOST_CHECK(IsProtected(
512+
7, [](NodeEvictionCandidate& c) {
513+
c.nTimeConnected = c.id;
514+
c.m_is_local = (c.id == 4);
515+
if (c.id == 6) {
516+
c.m_network = NET_CJDNS;
517+
} else if (c.id == 5) {
518+
c.m_network = NET_I2P;
519+
} else if (c.id == 3) {
520+
c.m_network = NET_ONION;
521+
} else {
522+
c.m_network = NET_IPV4;
523+
}
524+
},
525+
/*protected_peer_ids=*/{0, 1, 6},
526+
/*unprotected_peer_ids=*/{2, 3, 4, 5},
527+
random_context));
528+
529+
// Combined test: expect having 1 CJDNS, 1 I2P, 1 localhost and 1 onion peer
530+
// out of 8 to protect 1 CJDNS, 1 I2P, 0 localhost, 0 onion and 2 other
531+
// peers (4 total) sorted by longest uptime; stable sort breaks tie with
532+
// array order of CJDNS first.
533+
BOOST_CHECK(IsProtected(
534+
8, [](NodeEvictionCandidate& c) {
535+
c.nTimeConnected = c.id;
536+
c.m_is_local = (c.id == 3);
537+
if (c.id == 5) {
538+
c.m_network = NET_CJDNS;
539+
} else if (c.id == 6) {
540+
c.m_network = NET_I2P;
541+
} else if (c.id == 3) {
542+
c.m_network = NET_ONION;
543+
} else {
544+
c.m_network = NET_IPV6;
545+
}
546+
},
547+
/*protected_peer_ids=*/{0, 1, 5, 6},
548+
/*unprotected_peer_ids=*/{2, 3, 4, 7},
549+
random_context));
550+
551+
// Combined test: expect having 2 CJDNS, 2 I2P, 4 localhost, and 2 onion
552+
// peers out of 16 to protect 1 CJDNS, 1 I2P, 1 localhost, 1 onion (4/16
553+
// total), plus 4 others for 8 total, sorted by longest uptime.
554+
BOOST_CHECK(IsProtected(
555+
16, [](NodeEvictionCandidate& c) {
556+
c.nTimeConnected = c.id;
557+
c.m_is_local = (c.id > 5);
558+
if (c.id == 11 || c.id == 15) {
559+
c.m_network = NET_CJDNS;
560+
} else if (c.id == 10 || c.id == 14) {
561+
c.m_network = NET_I2P;
562+
} else if (c.id == 8 || c.id == 9) {
563+
c.m_network = NET_ONION;
564+
} else {
565+
c.m_network = NET_IPV4;
566+
}
567+
},
568+
/*protected_peer_ids=*/{0, 1, 2, 3, 6, 8, 10, 11},
569+
/*unprotected_peer_ids=*/{4, 5, 7, 9, 12, 13, 14, 15},
570+
random_context));
571+
572+
// Combined test: expect having 6 CJDNS, 1 I2P, 1 localhost, and 4 onion
573+
// peers out of 24 to protect 2 CJDNS, 1 I2P, 1 localhost, and 2 onions (6
574+
// total), plus 6 others for 12/24 total, sorted by longest uptime.
575+
BOOST_CHECK(IsProtected(
576+
24, [](NodeEvictionCandidate& c) {
577+
c.nTimeConnected = c.id;
578+
c.m_is_local = (c.id == 13);
579+
if (c.id > 17) {
580+
c.m_network = NET_CJDNS;
581+
} else if (c.id == 17) {
582+
c.m_network = NET_I2P;
583+
} else if (c.id == 12 || c.id == 14 || c.id == 15 || c.id == 16) {
584+
c.m_network = NET_ONION;
585+
} else {
586+
c.m_network = NET_IPV6;
587+
}
588+
},
589+
/*protected_peer_ids=*/{0, 1, 2, 3, 4, 5, 12, 13, 14, 17, 18, 19},
590+
/*unprotected_peer_ids=*/{6, 7, 8, 9, 10, 11, 15, 16, 20, 21, 22, 23},
591+
random_context));
459592
}
460593

461594
// Returns true if any of the node ids in node_ids are selected for eviction.

0 commit comments

Comments
 (0)