rippled
Loading...
Searching...
No Matches
HashRouter_test.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2012-2015 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 <xrpld/app/misc/HashRouter.h>
21#include <xrpld/core/Config.h>
22
23#include <xrpl/basics/chrono.h>
24#include <xrpl/beast/unit_test.h>
25
26namespace ripple {
27namespace test {
28
30{
33 {
35 setup.holdTime = hold;
36 setup.relayTime = relay;
37 return setup;
38 }
39
40 void
42 {
43 testcase("Non-expiration");
44 using namespace std::chrono_literals;
46 HashRouter router(getSetup(2s, 1s), stopwatch);
47
48 uint256 const key1(1);
49 uint256 const key2(2);
50 uint256 const key3(3);
51
52 // t=0
53 router.setFlags(key1, 11111);
54 BEAST_EXPECT(router.getFlags(key1) == 11111);
55 router.setFlags(key2, 22222);
56 BEAST_EXPECT(router.getFlags(key2) == 22222);
57 // key1 : 0
58 // key2 : 0
59 // key3: null
60
61 ++stopwatch;
62
63 // Because we are accessing key1 here, it
64 // will NOT be expired for another two ticks
65 BEAST_EXPECT(router.getFlags(key1) == 11111);
66 // key1 : 1
67 // key2 : 0
68 // key3 null
69
70 ++stopwatch;
71
72 // t=3
73 router.setFlags(key3, 33333); // force expiration
74 BEAST_EXPECT(router.getFlags(key1) == 11111);
75 BEAST_EXPECT(router.getFlags(key2) == 0);
76 }
77
78 void
80 {
81 testcase("Expiration");
82 using namespace std::chrono_literals;
84 HashRouter router(getSetup(2s, 1s), stopwatch);
85
86 uint256 const key1(1);
87 uint256 const key2(2);
88 uint256 const key3(3);
89 uint256 const key4(4);
90 BEAST_EXPECT(key1 != key2 && key2 != key3 && key3 != key4);
91
92 // t=0
93 router.setFlags(key1, 12345);
94 BEAST_EXPECT(router.getFlags(key1) == 12345);
95 // key1 : 0
96 // key2 : null
97 // key3 : null
98
99 ++stopwatch;
100
101 // Expiration is triggered by insertion,
102 // and timestamps are updated on access,
103 // so key1 will be expired after the second
104 // call to setFlags.
105 // t=1
106 router.setFlags(key2, 9999);
107 BEAST_EXPECT(router.getFlags(key1) == 12345);
108 BEAST_EXPECT(router.getFlags(key2) == 9999);
109 // key1 : 1
110 // key2 : 1
111 // key3 : null
112
113 ++stopwatch;
114 // t=2
115 BEAST_EXPECT(router.getFlags(key2) == 9999);
116 // key1 : 1
117 // key2 : 2
118 // key3 : null
119
120 ++stopwatch;
121 // t=3
122 router.setFlags(key3, 2222);
123 BEAST_EXPECT(router.getFlags(key1) == 0);
124 BEAST_EXPECT(router.getFlags(key2) == 9999);
125 BEAST_EXPECT(router.getFlags(key3) == 2222);
126 // key1 : 3
127 // key2 : 3
128 // key3 : 3
129
130 ++stopwatch;
131 // t=4
132 // No insertion, no expiration
133 router.setFlags(key1, 7654);
134 BEAST_EXPECT(router.getFlags(key1) == 7654);
135 BEAST_EXPECT(router.getFlags(key2) == 9999);
136 BEAST_EXPECT(router.getFlags(key3) == 2222);
137 // key1 : 4
138 // key2 : 4
139 // key3 : 4
140
141 ++stopwatch;
142 ++stopwatch;
143
144 // t=6
145 router.setFlags(key4, 7890);
146 BEAST_EXPECT(router.getFlags(key1) == 0);
147 BEAST_EXPECT(router.getFlags(key2) == 0);
148 BEAST_EXPECT(router.getFlags(key3) == 0);
149 BEAST_EXPECT(router.getFlags(key4) == 7890);
150 // key1 : 6
151 // key2 : 6
152 // key3 : 6
153 // key4 : 6
154 }
155
156 void
158 {
159 testcase("Suppression");
160 // Normal HashRouter
161 using namespace std::chrono_literals;
163 HashRouter router(getSetup(2s, 1s), stopwatch);
164
165 uint256 const key1(1);
166 uint256 const key2(2);
167 uint256 const key3(3);
168 uint256 const key4(4);
169 BEAST_EXPECT(key1 != key2 && key2 != key3 && key3 != key4);
170
171 int flags = 12345; // This value is ignored
172 router.addSuppression(key1);
173 BEAST_EXPECT(router.addSuppressionPeer(key2, 15));
174 BEAST_EXPECT(router.addSuppressionPeer(key3, 20, flags));
175 BEAST_EXPECT(flags == 0);
176
177 ++stopwatch;
178
179 BEAST_EXPECT(!router.addSuppressionPeer(key1, 2));
180 BEAST_EXPECT(!router.addSuppressionPeer(key2, 3));
181 BEAST_EXPECT(!router.addSuppressionPeer(key3, 4, flags));
182 BEAST_EXPECT(flags == 0);
183 BEAST_EXPECT(router.addSuppressionPeer(key4, 5));
184 }
185
186 void
188 {
189 testcase("Set Flags");
190 using namespace std::chrono_literals;
192 HashRouter router(getSetup(2s, 1s), stopwatch);
193
194 uint256 const key1(1);
195 BEAST_EXPECT(router.setFlags(key1, 10));
196 BEAST_EXPECT(!router.setFlags(key1, 10));
197 BEAST_EXPECT(router.setFlags(key1, 20));
198 }
199
200 void
202 {
203 testcase("Relay");
204 using namespace std::chrono_literals;
206 HashRouter router(getSetup(50s, 1s), stopwatch);
207
208 uint256 const key1(1);
209
211
212 peers = router.shouldRelay(key1);
213 BEAST_EXPECT(peers && peers->empty());
214 router.addSuppressionPeer(key1, 1);
215 router.addSuppressionPeer(key1, 3);
216 router.addSuppressionPeer(key1, 5);
217 // No action, because relayed
218 BEAST_EXPECT(!router.shouldRelay(key1));
219 // Expire, but since the next search will
220 // be for this entry, it will get refreshed
221 // instead. However, the relay won't.
222 ++stopwatch;
223 // Get those peers we added earlier
224 peers = router.shouldRelay(key1);
225 BEAST_EXPECT(peers && peers->size() == 3);
226 router.addSuppressionPeer(key1, 2);
227 router.addSuppressionPeer(key1, 4);
228 // No action, because relayed
229 BEAST_EXPECT(!router.shouldRelay(key1));
230 // Expire, but since the next search will
231 // be for this entry, it will get refreshed
232 // instead. However, the relay won't.
233 ++stopwatch;
234 // Relay again
235 peers = router.shouldRelay(key1);
236 BEAST_EXPECT(peers && peers->size() == 2);
237 // Expire again
238 ++stopwatch;
239 // Confirm that peers list is empty.
240 peers = router.shouldRelay(key1);
241 BEAST_EXPECT(peers && peers->size() == 0);
242 }
243
244 void
246 {
247 testcase("Process");
248 using namespace std::chrono_literals;
250 HashRouter router(getSetup(5s, 1s), stopwatch);
251 uint256 const key(1);
253 int flags;
254
255 BEAST_EXPECT(router.shouldProcess(key, peer, flags, 1s));
256 BEAST_EXPECT(!router.shouldProcess(key, peer, flags, 1s));
257 ++stopwatch;
258 ++stopwatch;
259 BEAST_EXPECT(router.shouldProcess(key, peer, flags, 1s));
260 }
261
262 void
264 {
265 testcase("setup_HashRouter");
266
267 using namespace std::chrono_literals;
268 {
269 Config cfg;
270 // default
271 auto const setup = setup_HashRouter(cfg);
272 BEAST_EXPECT(setup.holdTime == 300s);
273 BEAST_EXPECT(setup.relayTime == 30s);
274 }
275 {
276 Config cfg;
277 // non-default
278 auto& h = cfg.section("hashrouter");
279 h.set("hold_time", "600");
280 h.set("relay_time", "15");
281 auto const setup = setup_HashRouter(cfg);
282 BEAST_EXPECT(setup.holdTime == 600s);
283 BEAST_EXPECT(setup.relayTime == 15s);
284 }
285 {
286 Config cfg;
287 // equal
288 auto& h = cfg.section("hashrouter");
289 h.set("hold_time", "400");
290 h.set("relay_time", "400");
291 auto const setup = setup_HashRouter(cfg);
292 BEAST_EXPECT(setup.holdTime == 400s);
293 BEAST_EXPECT(setup.relayTime == 400s);
294 }
295 {
296 Config cfg;
297 // wrong order
298 auto& h = cfg.section("hashrouter");
299 h.set("hold_time", "60");
300 h.set("relay_time", "120");
301 try
302 {
303 setup_HashRouter(cfg);
304 fail();
305 }
306 catch (std::exception const& e)
307 {
308 std::string expected =
309 "HashRouter relay time must be less than or equal to hold "
310 "time";
311 BEAST_EXPECT(e.what() == expected);
312 }
313 }
314 {
315 Config cfg;
316 // too small hold
317 auto& h = cfg.section("hashrouter");
318 h.set("hold_time", "10");
319 h.set("relay_time", "120");
320 try
321 {
322 setup_HashRouter(cfg);
323 fail();
324 }
325 catch (std::exception const& e)
326 {
327 std::string expected =
328 "HashRouter hold time must be at least 12 seconds (the "
329 "approximate validation time for three "
330 "ledgers).";
331 BEAST_EXPECT(e.what() == expected);
332 }
333 }
334 {
335 Config cfg;
336 // too small relay
337 auto& h = cfg.section("hashrouter");
338 h.set("hold_time", "500");
339 h.set("relay_time", "6");
340 try
341 {
342 setup_HashRouter(cfg);
343 fail();
344 }
345 catch (std::exception const& e)
346 {
347 std::string expected =
348 "HashRouter relay time must be at least 8 seconds (the "
349 "approximate validation time for two ledgers).";
350 BEAST_EXPECT(e.what() == expected);
351 }
352 }
353 {
354 Config cfg;
355 // garbage
356 auto& h = cfg.section("hashrouter");
357 h.set("hold_time", "alice");
358 h.set("relay_time", "bob");
359 auto const setup = setup_HashRouter(cfg);
360 // The set function ignores values that don't covert, so the
361 // defaults are left unchanged
362 BEAST_EXPECT(setup.holdTime == 300s);
363 BEAST_EXPECT(setup.relayTime == 30s);
364 }
365 }
366
367public:
368 void
369 run() override
370 {
374 testSetFlags();
375 testRelay();
376 testProcess();
377 testSetup();
378 }
379};
380
381BEAST_DEFINE_TESTSUITE(HashRouter, app, ripple);
382
383} // namespace test
384} // namespace ripple
A testsuite class.
Definition: suite.h:55
testcase_t testcase
Memberspace for declaring test cases.
Definition: suite.h:155
void fail(String const &reason, char const *file, int line)
Record a failure.
Definition: suite.h:533
Section & section(std::string const &name)
Returns the section with the given name.
Routing table for objects identified by hash.
Definition: HashRouter.h:57
std::optional< std::set< PeerShortID > > shouldRelay(uint256 const &key)
Determines whether the hashed item should be relayed.
Definition: HashRouter.cpp:119
bool shouldProcess(uint256 const &key, PeerShortID peer, int &flags, std::chrono::seconds tx_interval)
Definition: HashRouter.cpp:79
int getFlags(uint256 const &key)
Definition: HashRouter.cpp:95
bool addSuppressionPeer(uint256 const &key, PeerShortID peer)
Definition: HashRouter.cpp:52
bool setFlags(uint256 const &key, int flags)
Set the flags on a hash.
Definition: HashRouter.cpp:103
void addSuppression(uint256 const &key)
Definition: HashRouter.cpp:44
void set(std::string const &key, std::string const &value)
Set a key/value pair.
Definition: BasicConfig.cpp:41
void run() override
Runs the suite.
HashRouter::Setup getSetup(std::chrono::seconds hold, std::chrono::seconds relay)
Match set account flags.
Definition: flags.h:125
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
HashRouter::Setup setup_HashRouter(Config const &config)
Definition: HashRouter.cpp:133
Stopwatch & stopwatch()
Returns an instance of a wall clock.
Definition: chrono.h:119
Structure used to customize HashRouter behavior.
Definition: HashRouter.h:71
seconds holdTime
Expiration time for a hash entry.
Definition: HashRouter.h:79
seconds relayTime
Amount of time required before a relayed item will be relayed again.
Definition: HashRouter.h:83
T what(T... args)