rippled
PeerFinder_test.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012, 2013 Ripple Labs Inc.
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
20 #include <ripple/basics/Slice.h>
21 #include <ripple/basics/chrono.h>
22 #include <ripple/beast/unit_test.h>
23 #include <ripple/core/Config.h>
24 #include <ripple/peerfinder/impl/Logic.h>
25 #include <ripple/protocol/PublicKey.h>
26 #include <ripple/protocol/SecretKey.h>
27 #include <test/unit_test/SuiteJournal.h>
28 
29 namespace ripple {
30 namespace PeerFinder {
31 
32 class PeerFinder_test : public beast::unit_test::suite
33 {
35 
36 public:
37  PeerFinder_test() : journal_("PeerFinder_test", *this)
38  {
39  }
40 
41  struct TestStore : Store
42  {
44  load(load_callback const& cb) override
45  {
46  return 0;
47  }
48 
49  void
50  save(std::vector<Entry> const&) override
51  {
52  }
53  };
54 
55  struct TestChecker
56  {
57  void
58  stop()
59  {
60  }
61 
62  void
63  wait()
64  {
65  }
66 
67  template <class Handler>
68  void
69  async_connect(beast::IP::Endpoint const& ep, Handler&& handler)
70  {
71  boost::system::error_code ec;
72  handler(ep, ep, ec);
73  }
74  };
75 
76  void
78  {
79  auto const seconds = 10000;
80  testcase("backoff 1");
81  TestStore store;
82  TestChecker checker;
83  TestStopwatch clock;
84  Logic<TestChecker> logic(clock, store, checker, journal_);
85  logic.addFixedPeer(
86  "test", beast::IP::Endpoint::from_string("65.0.0.1:5"));
87  {
88  Config c;
89  c.autoConnect = false;
90  c.listeningPort = 1024;
91  logic.config(c);
92  }
93  std::size_t n = 0;
94  for (std::size_t i = 0; i < seconds; ++i)
95  {
96  auto const list = logic.autoconnect();
97  if (!list.empty())
98  {
99  BEAST_EXPECT(list.size() == 1);
100  auto const slot = logic.new_outbound_slot(list.front());
101  BEAST_EXPECT(logic.onConnected(
102  slot, beast::IP::Endpoint::from_string("65.0.0.2:5")));
103  logic.on_closed(slot);
104  ++n;
105  }
106  clock.advance(std::chrono::seconds(1));
107  logic.once_per_second();
108  }
109  // Less than 20 attempts
110  BEAST_EXPECT(n < 20);
111  }
112 
113  // with activate
114  void
116  {
117  auto const seconds = 10000;
118  testcase("backoff 2");
119  TestStore store;
120  TestChecker checker;
121  TestStopwatch clock;
122  Logic<TestChecker> logic(clock, store, checker, journal_);
123  logic.addFixedPeer(
124  "test", beast::IP::Endpoint::from_string("65.0.0.1:5"));
125  {
126  Config c;
127  c.autoConnect = false;
128  c.listeningPort = 1024;
129  logic.config(c);
130  }
131 
132  PublicKey const pk(randomKeyPair(KeyType::secp256k1).first);
133  std::size_t n = 0;
134 
135  for (std::size_t i = 0; i < seconds; ++i)
136  {
137  auto const list = logic.autoconnect();
138  if (!list.empty())
139  {
140  BEAST_EXPECT(list.size() == 1);
141  auto const slot = logic.new_outbound_slot(list.front());
142  if (!BEAST_EXPECT(logic.onConnected(
143  slot, beast::IP::Endpoint::from_string("65.0.0.2:5"))))
144  return;
145  std::string s = ".";
146  if (!BEAST_EXPECT(
147  logic.activate(slot, pk, false) ==
149  return;
150  logic.on_closed(slot);
151  ++n;
152  }
153  clock.advance(std::chrono::seconds(1));
154  logic.once_per_second();
155  }
156  // No more often than once per minute
157  BEAST_EXPECT(n <= (seconds + 59) / 60);
158  }
159 
160  void
162  {
163  // if peers_max is configured then peers_in_max and peers_out_max are
164  // ignored
165  auto run = [&](std::string const& test,
169  std::uint16_t port,
170  std::uint16_t expectOut,
171  std::uint16_t expectIn,
172  std::uint16_t expectIpLimit) {
173  ripple::Config c;
174 
175  testcase(test);
176 
177  std::string toLoad = "";
178  int max = 0;
179  if (maxPeers)
180  {
181  max = maxPeers.value();
182  toLoad += "[peers_max]\n" + std::to_string(max) + "\n" +
183  "[peers_in_max]\n" + std::to_string(maxIn.value_or(0)) +
184  "\n" + "[peers_out_max]\n" +
185  std::to_string(maxOut.value_or(0)) + "\n";
186  }
187  else if (maxIn && maxOut)
188  {
189  toLoad += "[peers_in_max]\n" + std::to_string(*maxIn) + "\n" +
190  "[peers_out_max]\n" + std::to_string(*maxOut) + "\n";
191  }
192 
193  c.loadFromString(toLoad);
194  BEAST_EXPECT(
195  (c.PEERS_MAX == max && c.PEERS_IN_MAX == 0 &&
196  c.PEERS_OUT_MAX == 0) ||
197  (c.PEERS_IN_MAX == *maxIn && c.PEERS_OUT_MAX == *maxOut));
198 
199  Config config = Config::makeConfig(c, port, false, 0);
200 
201  Counts counts;
202  counts.onConfig(config);
203  BEAST_EXPECT(
204  counts.out_max() == expectOut &&
205  counts.inboundSlots() == expectIn &&
206  config.ipLimit == expectIpLimit);
207  };
208 
209  // if max_peers == 0 => maxPeers = 21,
210  // else if max_peers < 10 => maxPeers = 10 else maxPeers = max_peers
211  // expectOut => if legacy => max(0.15 * maxPeers, 10),
212  // if legacy && !wantIncoming => maxPeers else max_out_peers
213  // expectIn => if legacy && wantIncoming => maxPeers - outPeers
214  // else if !wantIncoming => 0 else max_in_peers
215  // ipLimit => if expectIn <= 21 => 2 else 2 + min(5, expectIn/21)
216  // ipLimit = max(1, min(ipLimit, expectIn/2))
217 
218  // legacy test with max_peers
219  run("legacy no config", {}, {}, {}, 4000, 10, 11, 2);
220  run("legacy max_peers 0", 0, 100, 10, 4000, 10, 11, 2);
221  run("legacy max_peers 5", 5, 100, 10, 4000, 10, 0, 1);
222  run("legacy max_peers 20", 20, 100, 10, 4000, 10, 10, 2);
223  run("legacy max_peers 100", 100, 100, 10, 4000, 15, 85, 6);
224  run("legacy max_peers 20, private", 20, 100, 10, 0, 20, 0, 1);
225 
226  // test with max_in_peers and max_out_peers
227  run("new in 100/out 10", {}, 100, 10, 4000, 10, 100, 6);
228  run("new in 0/out 10", {}, 0, 10, 4000, 10, 0, 1);
229  run("new in 100/out 10, private", {}, 100, 10, 0, 10, 0, 6);
230  }
231 
232  void
234  {
235  testcase("invalid config");
236 
237  auto run = [&](std::string const& toLoad) {
238  ripple::Config c;
239  try
240  {
241  c.loadFromString(toLoad);
242  fail();
243  }
244  catch (...)
245  {
246  pass();
247  }
248  };
249  run(R"rippleConfig(
250 [peers_in_max]
251 100
252 )rippleConfig");
253  run(R"rippleConfig(
254 [peers_out_max]
255 100
256 )rippleConfig");
257  run(R"rippleConfig(
258 [peers_in_max]
259 100
260 [peers_out_max]
261 5
262 )rippleConfig");
263  run(R"rippleConfig(
264 [peers_in_max]
265 1001
266 [peers_out_max]
267 10
268 )rippleConfig");
269  run(R"rippleConfig(
270 [peers_in_max]
271 10
272 [peers_out_max]
273 1001
274 )rippleConfig");
275  }
276 
277  void
278  run() override
279  {
280  test_backoff1();
281  test_backoff2();
282  test_config();
284  }
285 };
286 
287 BEAST_DEFINE_TESTSUITE(PeerFinder, PeerFinder, ripple);
288 
289 } // namespace PeerFinder
290 } // namespace ripple
ripple::PeerFinder::PeerFinder_test::TestStore::save
void save(std::vector< Entry > const &) override
Definition: PeerFinder_test.cpp:50
std::string
STL class.
ripple::PeerFinder::Logic
The Logic for maintaining the list of Slot addresses.
Definition: peerfinder/impl/Logic.h:54
ripple::PeerFinder::PeerFinder_test
Definition: PeerFinder_test.cpp:32
ripple::PeerFinder::Logic::new_outbound_slot
SlotImp::ptr new_outbound_slot(beast::IP::Endpoint const &remote_endpoint)
Definition: peerfinder/impl/Logic.h:311
std::vector
STL class.
ripple::PeerFinder::PeerFinder_test::test_config
void test_config()
Definition: PeerFinder_test.cpp:161
std::chrono::seconds
ripple::PeerFinder::PeerFinder_test::journal_
test::SuiteJournal journal_
Definition: PeerFinder_test.cpp:34
ripple::PeerFinder::PeerFinder_test::TestChecker
Definition: PeerFinder_test.cpp:55
ripple::PeerFinder::PeerFinder_test::TestChecker::wait
void wait()
Definition: PeerFinder_test.cpp:63
std::function
ripple::PeerFinder::Store
Abstract persistence for PeerFinder data.
Definition: Store.h:27
ripple::PeerFinder::PeerFinder_test::TestStore
Definition: PeerFinder_test.cpp:41
ripple::PeerFinder::Counts::inboundSlots
int inboundSlots() const
Returns the total number of inbound slots.
Definition: Counts.h:165
ripple::PeerFinder::Config::makeConfig
static Config makeConfig(ripple::Config const &config, std::uint16_t port, bool validationPublicKey, int ipLimit)
Make PeerFinder::Config from configuration parameters.
Definition: PeerfinderConfig.cpp:78
ripple::PeerFinder::Result::success
@ success
ripple::PeerFinder::Counts::out_max
int out_max() const
Returns the total number of outbound slots.
Definition: Counts.h:103
ripple::PeerFinder::Counts
Manages the count of available connections for the various slots.
Definition: Counts.h:34
ripple::Config::loadFromString
void loadFromString(std::string const &fileContents)
Load the config from the contents of the string.
Definition: Config.cpp:457
ripple::PeerFinder::Logic::onConnected
bool onConnected(SlotImp::ptr const &slot, beast::IP::Endpoint const &local_endpoint)
Definition: peerfinder/impl/Logic.h:346
ripple::PeerFinder::PeerFinder_test::test_invalid_config
void test_invalid_config()
Definition: PeerFinder_test.cpp:233
ripple::PeerFinder::PeerFinder_test::TestChecker::stop
void stop()
Definition: PeerFinder_test.cpp:58
ripple::PublicKey
A public key.
Definition: PublicKey.h:59
ripple::Config
Definition: Config.h:89
ripple::PeerFinder::PeerFinder_test::PeerFinder_test
PeerFinder_test()
Definition: PeerFinder_test.cpp:37
std::to_string
T to_string(T... args)
ripple::PeerFinder::PeerFinder_test::test_backoff2
void test_backoff2()
Definition: PeerFinder_test.cpp:115
ripple::PeerFinder::Logic::autoconnect
std::vector< beast::IP::Endpoint > autoconnect()
Create new outbound connection attempts as needed.
Definition: peerfinder/impl/Logic.h:467
ripple::PeerFinder::Counts::onConfig
void onConfig(Config const &config)
Called when the config is set or changed.
Definition: Counts.h:135
ripple::Config::PEERS_OUT_MAX
std::size_t PEERS_OUT_MAX
Definition: Config.h:185
ripple::PeerFinder::Logic::addFixedPeer
void addFixedPeer(std::string const &name, beast::IP::Endpoint const &ep)
Definition: peerfinder/impl/Logic.h:174
std::uint16_t
ripple::Config::PEERS_IN_MAX
std::size_t PEERS_IN_MAX
Definition: Config.h:186
ripple::PeerFinder::Logic::activate
Result activate(SlotImp::ptr const &slot, PublicKey const &key, bool reserved)
Definition: peerfinder/impl/Logic.h:383
ripple::PeerFinder::PeerFinder_test::TestChecker::async_connect
void async_connect(beast::IP::Endpoint const &ep, Handler &&handler)
Definition: PeerFinder_test.cpp:69
ripple::test::SuiteJournal
Definition: SuiteJournal.h:88
ripple::KeyType::secp256k1
@ secp256k1
ripple::randomKeyPair
std::pair< PublicKey, SecretKey > randomKeyPair(KeyType type)
Create a key pair using secure random numbers.
Definition: SecretKey.cpp:368
ripple::PeerFinder::Logic::once_per_second
void once_per_second()
Definition: peerfinder/impl/Logic.h:672
ripple::Config::PEERS_MAX
std::size_t PEERS_MAX
Definition: Config.h:184
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::PeerFinder::Config::listeningPort
std::uint16_t listeningPort
The listening port number.
Definition: PeerfinderManager.h:70
ripple::PeerFinder::PeerFinder_test::run
void run() override
Definition: PeerFinder_test.cpp:278
beast::IP::Endpoint::from_string
static Endpoint from_string(std::string const &s)
Definition: IPEndpoint.cpp:49
ripple::PeerFinder::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(Livecache, peerfinder, ripple)
ripple::PeerFinder::PeerFinder_test::test_backoff1
void test_backoff1()
Definition: PeerFinder_test.cpp:77
std::optional< std::uint16_t >
std::size_t
beast::IP::Endpoint
A version-independent IP address and port combination.
Definition: IPEndpoint.h:38
ripple::PeerFinder::Config::autoConnect
bool autoConnect
true if we want to establish connections automatically
Definition: PeerfinderManager.h:67
ripple::PeerFinder::Config
PeerFinder configuration settings.
Definition: PeerfinderManager.h:40
ripple::PeerFinder::Logic::on_closed
void on_closed(SlotImp::ptr const &slot)
Definition: peerfinder/impl/Logic.h:887
beast::manual_clock< std::chrono::steady_clock >
ripple::PeerFinder::Logic::config
void config(Config const &c)
Definition: peerfinder/impl/Logic.h:159
ripple::PeerFinder::Config::ipLimit
int ipLimit
Limit how many incoming connections we allow per IP.
Definition: PeerfinderManager.h:76
ripple::PeerFinder::PeerFinder_test::TestStore::load
std::size_t load(load_callback const &cb) override
Definition: PeerFinder_test.cpp:44