rippled
Loading...
Searching...
No Matches
LedgerTrie_test.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2012-2017 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 <test/csf/ledgers.h>
21
22#include <xrpld/consensus/LedgerTrie.h>
23
24#include <xrpl/beast/unit_test.h>
25
26#include <random>
27
28namespace ripple {
29namespace test {
30
32{
33 void
35 {
36 using namespace csf;
37 // Single entry by itself
38 {
40 LedgerHistoryHelper h;
41 t.insert(h["abc"]);
42 BEAST_EXPECT(t.checkInvariants());
43 BEAST_EXPECT(t.tipSupport(h["abc"]) == 1);
44 BEAST_EXPECT(t.branchSupport(h["abc"]) == 1);
45
46 t.insert(h["abc"]);
47 BEAST_EXPECT(t.checkInvariants());
48 BEAST_EXPECT(t.tipSupport(h["abc"]) == 2);
49 BEAST_EXPECT(t.branchSupport(h["abc"]) == 2);
50 }
51 // Suffix of existing (extending tree)
52 {
54 LedgerHistoryHelper h;
55 t.insert(h["abc"]);
56 BEAST_EXPECT(t.checkInvariants());
57 // extend with no siblings
58 t.insert(h["abcd"]);
59 BEAST_EXPECT(t.checkInvariants());
60
61 BEAST_EXPECT(t.tipSupport(h["abc"]) == 1);
62 BEAST_EXPECT(t.branchSupport(h["abc"]) == 2);
63 BEAST_EXPECT(t.tipSupport(h["abcd"]) == 1);
64 BEAST_EXPECT(t.branchSupport(h["abcd"]) == 1);
65
66 // extend with existing sibling
67 t.insert(h["abce"]);
68 BEAST_EXPECT(t.tipSupport(h["abc"]) == 1);
69 BEAST_EXPECT(t.branchSupport(h["abc"]) == 3);
70 BEAST_EXPECT(t.tipSupport(h["abcd"]) == 1);
71 BEAST_EXPECT(t.branchSupport(h["abcd"]) == 1);
72 BEAST_EXPECT(t.tipSupport(h["abce"]) == 1);
73 BEAST_EXPECT(t.branchSupport(h["abce"]) == 1);
74 }
75 // uncommitted of existing node
76 {
78 LedgerHistoryHelper h;
79 t.insert(h["abcd"]);
80 BEAST_EXPECT(t.checkInvariants());
81 // uncommitted with no siblings
82 t.insert(h["abcdf"]);
83 BEAST_EXPECT(t.checkInvariants());
84
85 BEAST_EXPECT(t.tipSupport(h["abcd"]) == 1);
86 BEAST_EXPECT(t.branchSupport(h["abcd"]) == 2);
87 BEAST_EXPECT(t.tipSupport(h["abcdf"]) == 1);
88 BEAST_EXPECT(t.branchSupport(h["abcdf"]) == 1);
89
90 // uncommitted with existing child
91 t.insert(h["abc"]);
92 BEAST_EXPECT(t.checkInvariants());
93
94 BEAST_EXPECT(t.tipSupport(h["abc"]) == 1);
95 BEAST_EXPECT(t.branchSupport(h["abc"]) == 3);
96 BEAST_EXPECT(t.tipSupport(h["abcd"]) == 1);
97 BEAST_EXPECT(t.branchSupport(h["abcd"]) == 2);
98 BEAST_EXPECT(t.tipSupport(h["abcdf"]) == 1);
99 BEAST_EXPECT(t.branchSupport(h["abcdf"]) == 1);
100 }
101 // Suffix + uncommitted of existing node
102 {
104 LedgerHistoryHelper h;
105 t.insert(h["abcd"]);
106 BEAST_EXPECT(t.checkInvariants());
107 t.insert(h["abce"]);
108 BEAST_EXPECT(t.checkInvariants());
109
110 BEAST_EXPECT(t.tipSupport(h["abc"]) == 0);
111 BEAST_EXPECT(t.branchSupport(h["abc"]) == 2);
112 BEAST_EXPECT(t.tipSupport(h["abcd"]) == 1);
113 BEAST_EXPECT(t.branchSupport(h["abcd"]) == 1);
114 BEAST_EXPECT(t.tipSupport(h["abce"]) == 1);
115 BEAST_EXPECT(t.branchSupport(h["abce"]) == 1);
116 }
117 // Suffix + uncommitted with existing child
118 {
119 // abcd : abcde, abcf
120
122 LedgerHistoryHelper h;
123 t.insert(h["abcd"]);
124 BEAST_EXPECT(t.checkInvariants());
125 t.insert(h["abcde"]);
126 BEAST_EXPECT(t.checkInvariants());
127 t.insert(h["abcf"]);
128 BEAST_EXPECT(t.checkInvariants());
129
130 BEAST_EXPECT(t.tipSupport(h["abc"]) == 0);
131 BEAST_EXPECT(t.branchSupport(h["abc"]) == 3);
132 BEAST_EXPECT(t.tipSupport(h["abcd"]) == 1);
133 BEAST_EXPECT(t.branchSupport(h["abcd"]) == 2);
134 BEAST_EXPECT(t.tipSupport(h["abcf"]) == 1);
135 BEAST_EXPECT(t.branchSupport(h["abcf"]) == 1);
136 BEAST_EXPECT(t.tipSupport(h["abcde"]) == 1);
137 BEAST_EXPECT(t.branchSupport(h["abcde"]) == 1);
138 }
139
140 // Multiple counts
141 {
143 LedgerHistoryHelper h;
144 t.insert(h["ab"], 4);
145 BEAST_EXPECT(t.tipSupport(h["ab"]) == 4);
146 BEAST_EXPECT(t.branchSupport(h["ab"]) == 4);
147 BEAST_EXPECT(t.tipSupport(h["a"]) == 0);
148 BEAST_EXPECT(t.branchSupport(h["a"]) == 4);
149
150 t.insert(h["abc"], 2);
151 BEAST_EXPECT(t.tipSupport(h["abc"]) == 2);
152 BEAST_EXPECT(t.branchSupport(h["abc"]) == 2);
153 BEAST_EXPECT(t.tipSupport(h["ab"]) == 4);
154 BEAST_EXPECT(t.branchSupport(h["ab"]) == 6);
155 BEAST_EXPECT(t.tipSupport(h["a"]) == 0);
156 BEAST_EXPECT(t.branchSupport(h["a"]) == 6);
157 }
158 }
159
160 void
162 {
163 using namespace csf;
164 // Not in trie
165 {
167 LedgerHistoryHelper h;
168 t.insert(h["abc"]);
169
170 BEAST_EXPECT(!t.remove(h["ab"]));
171 BEAST_EXPECT(t.checkInvariants());
172 BEAST_EXPECT(!t.remove(h["a"]));
173 BEAST_EXPECT(t.checkInvariants());
174 }
175 // In trie but with 0 tip support
176 {
178 LedgerHistoryHelper h;
179 t.insert(h["abcd"]);
180 t.insert(h["abce"]);
181
182 BEAST_EXPECT(t.tipSupport(h["abc"]) == 0);
183 BEAST_EXPECT(t.branchSupport(h["abc"]) == 2);
184 BEAST_EXPECT(!t.remove(h["abc"]));
185 BEAST_EXPECT(t.checkInvariants());
186 BEAST_EXPECT(t.tipSupport(h["abc"]) == 0);
187 BEAST_EXPECT(t.branchSupport(h["abc"]) == 2);
188 }
189 // In trie with > 1 tip support
190 {
192 LedgerHistoryHelper h;
193 t.insert(h["abc"], 2);
194
195 BEAST_EXPECT(t.tipSupport(h["abc"]) == 2);
196 BEAST_EXPECT(t.remove(h["abc"]));
197 BEAST_EXPECT(t.checkInvariants());
198 BEAST_EXPECT(t.tipSupport(h["abc"]) == 1);
199
200 t.insert(h["abc"], 1);
201 BEAST_EXPECT(t.tipSupport(h["abc"]) == 2);
202 BEAST_EXPECT(t.remove(h["abc"], 2));
203 BEAST_EXPECT(t.checkInvariants());
204 BEAST_EXPECT(t.tipSupport(h["abc"]) == 0);
205
206 t.insert(h["abc"], 3);
207 BEAST_EXPECT(t.tipSupport(h["abc"]) == 3);
208 BEAST_EXPECT(t.remove(h["abc"], 300));
209 BEAST_EXPECT(t.checkInvariants());
210 BEAST_EXPECT(t.tipSupport(h["abc"]) == 0);
211 }
212 // In trie with = 1 tip support, no children
213 {
215 LedgerHistoryHelper h;
216 t.insert(h["ab"]);
217 t.insert(h["abc"]);
218
219 BEAST_EXPECT(t.tipSupport(h["ab"]) == 1);
220 BEAST_EXPECT(t.branchSupport(h["ab"]) == 2);
221 BEAST_EXPECT(t.tipSupport(h["abc"]) == 1);
222 BEAST_EXPECT(t.branchSupport(h["abc"]) == 1);
223
224 BEAST_EXPECT(t.remove(h["abc"]));
225 BEAST_EXPECT(t.checkInvariants());
226 BEAST_EXPECT(t.tipSupport(h["ab"]) == 1);
227 BEAST_EXPECT(t.branchSupport(h["ab"]) == 1);
228 BEAST_EXPECT(t.tipSupport(h["abc"]) == 0);
229 BEAST_EXPECT(t.branchSupport(h["abc"]) == 0);
230 }
231 // In trie with = 1 tip support, 1 child
232 {
234 LedgerHistoryHelper h;
235 t.insert(h["ab"]);
236 t.insert(h["abc"]);
237 t.insert(h["abcd"]);
238
239 BEAST_EXPECT(t.tipSupport(h["abc"]) == 1);
240 BEAST_EXPECT(t.branchSupport(h["abc"]) == 2);
241 BEAST_EXPECT(t.tipSupport(h["abcd"]) == 1);
242 BEAST_EXPECT(t.branchSupport(h["abcd"]) == 1);
243
244 BEAST_EXPECT(t.remove(h["abc"]));
245 BEAST_EXPECT(t.checkInvariants());
246 BEAST_EXPECT(t.tipSupport(h["abc"]) == 0);
247 BEAST_EXPECT(t.branchSupport(h["abc"]) == 1);
248 BEAST_EXPECT(t.tipSupport(h["abcd"]) == 1);
249 BEAST_EXPECT(t.branchSupport(h["abcd"]) == 1);
250 }
251 // In trie with = 1 tip support, > 1 children
252 {
254 LedgerHistoryHelper h;
255 t.insert(h["ab"]);
256 t.insert(h["abc"]);
257 t.insert(h["abcd"]);
258 t.insert(h["abce"]);
259
260 BEAST_EXPECT(t.tipSupport(h["abc"]) == 1);
261 BEAST_EXPECT(t.branchSupport(h["abc"]) == 3);
262
263 BEAST_EXPECT(t.remove(h["abc"]));
264 BEAST_EXPECT(t.checkInvariants());
265 BEAST_EXPECT(t.tipSupport(h["abc"]) == 0);
266 BEAST_EXPECT(t.branchSupport(h["abc"]) == 2);
267 }
268
269 // In trie with = 1 tip support, parent compaction
270 {
272 LedgerHistoryHelper h;
273 t.insert(h["ab"]);
274 t.insert(h["abc"]);
275 t.insert(h["abd"]);
276 BEAST_EXPECT(t.checkInvariants());
277 t.remove(h["ab"]);
278 BEAST_EXPECT(t.checkInvariants());
279 BEAST_EXPECT(t.tipSupport(h["abc"]) == 1);
280 BEAST_EXPECT(t.tipSupport(h["abd"]) == 1);
281 BEAST_EXPECT(t.tipSupport(h["ab"]) == 0);
282 BEAST_EXPECT(t.branchSupport(h["ab"]) == 2);
283
284 t.remove(h["abd"]);
285 BEAST_EXPECT(t.checkInvariants());
286
287 BEAST_EXPECT(t.tipSupport(h["abc"]) == 1);
288 BEAST_EXPECT(t.branchSupport(h["ab"]) == 1);
289 }
290 }
291
292 void
294 {
295 using namespace csf;
297 LedgerHistoryHelper h;
298 BEAST_EXPECT(t.empty());
299
300 Ledger genesis = h[""];
301 t.insert(genesis);
302 BEAST_EXPECT(!t.empty());
303 t.remove(genesis);
304 BEAST_EXPECT(t.empty());
305
306 t.insert(h["abc"]);
307 BEAST_EXPECT(!t.empty());
308 t.remove(h["abc"]);
309 BEAST_EXPECT(t.empty());
310 }
311
312 void
314 {
315 using namespace csf;
316 using Seq = Ledger::Seq;
317
319 LedgerHistoryHelper h;
320 BEAST_EXPECT(t.tipSupport(h["a"]) == 0);
321 BEAST_EXPECT(t.tipSupport(h["axy"]) == 0);
322
323 BEAST_EXPECT(t.branchSupport(h["a"]) == 0);
324 BEAST_EXPECT(t.branchSupport(h["axy"]) == 0);
325
326 t.insert(h["abc"]);
327 BEAST_EXPECT(t.tipSupport(h["a"]) == 0);
328 BEAST_EXPECT(t.tipSupport(h["ab"]) == 0);
329 BEAST_EXPECT(t.tipSupport(h["abc"]) == 1);
330 BEAST_EXPECT(t.tipSupport(h["abcd"]) == 0);
331
332 BEAST_EXPECT(t.branchSupport(h["a"]) == 1);
333 BEAST_EXPECT(t.branchSupport(h["ab"]) == 1);
334 BEAST_EXPECT(t.branchSupport(h["abc"]) == 1);
335 BEAST_EXPECT(t.branchSupport(h["abcd"]) == 0);
336
337 t.insert(h["abe"]);
338 BEAST_EXPECT(t.tipSupport(h["a"]) == 0);
339 BEAST_EXPECT(t.tipSupport(h["ab"]) == 0);
340 BEAST_EXPECT(t.tipSupport(h["abc"]) == 1);
341 BEAST_EXPECT(t.tipSupport(h["abe"]) == 1);
342
343 BEAST_EXPECT(t.branchSupport(h["a"]) == 2);
344 BEAST_EXPECT(t.branchSupport(h["ab"]) == 2);
345 BEAST_EXPECT(t.branchSupport(h["abc"]) == 1);
346 BEAST_EXPECT(t.branchSupport(h["abe"]) == 1);
347
348 t.remove(h["abc"]);
349 BEAST_EXPECT(t.tipSupport(h["a"]) == 0);
350 BEAST_EXPECT(t.tipSupport(h["ab"]) == 0);
351 BEAST_EXPECT(t.tipSupport(h["abc"]) == 0);
352 BEAST_EXPECT(t.tipSupport(h["abe"]) == 1);
353
354 BEAST_EXPECT(t.branchSupport(h["a"]) == 1);
355 BEAST_EXPECT(t.branchSupport(h["ab"]) == 1);
356 BEAST_EXPECT(t.branchSupport(h["abc"]) == 0);
357 BEAST_EXPECT(t.branchSupport(h["abe"]) == 1);
358 }
359
360 void
362 {
363 using namespace csf;
364 using Seq = Ledger::Seq;
365 // Empty
366 {
368 BEAST_EXPECT(t.getPreferred(Seq{0}) == std::nullopt);
369 BEAST_EXPECT(t.getPreferred(Seq{2}) == std::nullopt);
370 }
371 // Genesis support is NOT empty
372 {
374 LedgerHistoryHelper h;
375 Ledger genesis = h[""];
376 t.insert(genesis);
377 BEAST_EXPECT(t.getPreferred(Seq{0})->id == genesis.id());
378 BEAST_EXPECT(t.remove(genesis));
379 BEAST_EXPECT(t.getPreferred(Seq{0}) == std::nullopt);
380 BEAST_EXPECT(!t.remove(genesis));
381 }
382 // Single node no children
383 {
385 LedgerHistoryHelper h;
386 t.insert(h["abc"]);
387 BEAST_EXPECT(t.getPreferred(Seq{3})->id == h["abc"].id());
388 }
389 // Single node smaller child support
390 {
392 LedgerHistoryHelper h;
393 t.insert(h["abc"]);
394 t.insert(h["abcd"]);
395 BEAST_EXPECT(t.getPreferred(Seq{3})->id == h["abc"].id());
396 BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["abc"].id());
397 }
398 // Single node larger child
399 {
401 LedgerHistoryHelper h;
402 t.insert(h["abc"]);
403 t.insert(h["abcd"], 2);
404 BEAST_EXPECT(t.getPreferred(Seq{3})->id == h["abcd"].id());
405 BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["abcd"].id());
406 }
407 // Single node smaller children support
408 {
410 LedgerHistoryHelper h;
411 t.insert(h["abc"]);
412 t.insert(h["abcd"]);
413 t.insert(h["abce"]);
414 BEAST_EXPECT(t.getPreferred(Seq{3})->id == h["abc"].id());
415 BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["abc"].id());
416
417 t.insert(h["abc"]);
418 BEAST_EXPECT(t.getPreferred(Seq{3})->id == h["abc"].id());
419 BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["abc"].id());
420 }
421 // Single node larger children
422 {
424 LedgerHistoryHelper h;
425 t.insert(h["abc"]);
426 t.insert(h["abcd"], 2);
427 t.insert(h["abce"]);
428 BEAST_EXPECT(t.getPreferred(Seq{3})->id == h["abc"].id());
429 BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["abc"].id());
430
431 t.insert(h["abcd"]);
432 BEAST_EXPECT(t.getPreferred(Seq{3})->id == h["abcd"].id());
433 BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["abcd"].id());
434 }
435 // Tie-breaker by id
436 {
438 LedgerHistoryHelper h;
439 t.insert(h["abcd"], 2);
440 t.insert(h["abce"], 2);
441
442 BEAST_EXPECT(h["abce"].id() > h["abcd"].id());
443 BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["abce"].id());
444
445 t.insert(h["abcd"]);
446 BEAST_EXPECT(h["abce"].id() > h["abcd"].id());
447 BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["abcd"].id());
448 }
449
450 // Tie-breaker not needed
451 {
453 LedgerHistoryHelper h;
454 t.insert(h["abc"]);
455 t.insert(h["abcd"]);
456 t.insert(h["abce"], 2);
457 // abce only has a margin of 1, but it owns the tie-breaker
458 BEAST_EXPECT(h["abce"].id() > h["abcd"].id());
459 BEAST_EXPECT(t.getPreferred(Seq{3})->id == h["abce"].id());
460 BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["abce"].id());
461
462 // Switch support from abce to abcd, tie-breaker now needed
463 t.remove(h["abce"]);
464 t.insert(h["abcd"]);
465 BEAST_EXPECT(t.getPreferred(Seq{3})->id == h["abc"].id());
466 BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["abc"].id());
467 }
468
469 // Single node larger grand child
470 {
472 LedgerHistoryHelper h;
473 t.insert(h["abc"]);
474 t.insert(h["abcd"], 2);
475 t.insert(h["abcde"], 4);
476 BEAST_EXPECT(t.getPreferred(Seq{3})->id == h["abcde"].id());
477 BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["abcde"].id());
478 BEAST_EXPECT(t.getPreferred(Seq{5})->id == h["abcde"].id());
479 }
480
481 // Too much uncommitted support from competing branches
482 {
484 LedgerHistoryHelper h;
485 t.insert(h["abc"]);
486 t.insert(h["abcde"], 2);
487 t.insert(h["abcfg"], 2);
488 // 'de' and 'fg' are tied without 'abc' vote
489 BEAST_EXPECT(t.getPreferred(Seq{3})->id == h["abc"].id());
490 BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["abc"].id());
491 BEAST_EXPECT(t.getPreferred(Seq{5})->id == h["abc"].id());
492
493 t.remove(h["abc"]);
494 t.insert(h["abcd"]);
495
496 // 'de' branch has 3 votes to 2, so earlier sequences see it as
497 // preferred
498 BEAST_EXPECT(t.getPreferred(Seq{3})->id == h["abcde"].id());
499 BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["abcde"].id());
500
501 // However, if you validated a ledger with Seq 5, potentially on
502 // a different branch, you do not yet know if they chose abcd
503 // or abcf because of you, so abc remains preferred
504 BEAST_EXPECT(t.getPreferred(Seq{5})->id == h["abc"].id());
505 }
506
507 // Changing largestSeq perspective changes preferred branch
508 {
521 LedgerHistoryHelper h;
522 t.insert(h["ab"]);
523 t.insert(h["ac"]);
524 t.insert(h["acf"]);
525 t.insert(h["abde"], 2);
526
527 // B has more branch support
528 BEAST_EXPECT(t.getPreferred(Seq{1})->id == h["ab"].id());
529 BEAST_EXPECT(t.getPreferred(Seq{2})->id == h["ab"].id());
530 // But if you last validated D,F or E, you do not yet know
531 // if someone used that validation to commit to B or C
532 BEAST_EXPECT(t.getPreferred(Seq{3})->id == h["a"].id());
533 BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["a"].id());
534
546 t.remove(h["abde"]);
547 t.insert(h["abdeg"]);
548
549 BEAST_EXPECT(t.getPreferred(Seq{1})->id == h["ab"].id());
550 BEAST_EXPECT(t.getPreferred(Seq{2})->id == h["ab"].id());
551 BEAST_EXPECT(t.getPreferred(Seq{3})->id == h["a"].id());
552 BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["a"].id());
553 BEAST_EXPECT(t.getPreferred(Seq{5})->id == h["a"].id());
554
566 t.remove(h["ac"]);
567 t.insert(h["abh"]);
568 BEAST_EXPECT(t.getPreferred(Seq{1})->id == h["ab"].id());
569 BEAST_EXPECT(t.getPreferred(Seq{2})->id == h["ab"].id());
570 BEAST_EXPECT(t.getPreferred(Seq{3})->id == h["ab"].id());
571 BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["a"].id());
572 BEAST_EXPECT(t.getPreferred(Seq{5})->id == h["a"].id());
573
585 t.remove(h["acf"]);
586 t.insert(h["abde"]);
587 BEAST_EXPECT(t.getPreferred(Seq{1})->id == h["abde"].id());
588 BEAST_EXPECT(t.getPreferred(Seq{2})->id == h["abde"].id());
589 BEAST_EXPECT(t.getPreferred(Seq{3})->id == h["abde"].id());
590 BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["ab"].id());
591 BEAST_EXPECT(t.getPreferred(Seq{5})->id == h["ab"].id());
592 }
593 }
594
595 void
597 {
598 using namespace csf;
599 using Seq = Ledger::Seq;
600 // Since the root is a special node that breaks the no-single child
601 // invariant, do some tests that exercise it.
602
604 LedgerHistoryHelper h;
605 BEAST_EXPECT(!t.remove(h[""]));
606 BEAST_EXPECT(t.branchSupport(h[""]) == 0);
607 BEAST_EXPECT(t.tipSupport(h[""]) == 0);
608
609 t.insert(h["a"]);
610 BEAST_EXPECT(t.checkInvariants());
611 BEAST_EXPECT(t.branchSupport(h[""]) == 1);
612 BEAST_EXPECT(t.tipSupport(h[""]) == 0);
613
614 t.insert(h["e"]);
615 BEAST_EXPECT(t.checkInvariants());
616 BEAST_EXPECT(t.branchSupport(h[""]) == 2);
617 BEAST_EXPECT(t.tipSupport(h[""]) == 0);
618
619 BEAST_EXPECT(t.remove(h["e"]));
620 BEAST_EXPECT(t.checkInvariants());
621 BEAST_EXPECT(t.branchSupport(h[""]) == 1);
622 BEAST_EXPECT(t.tipSupport(h[""]) == 0);
623 }
624
625 void
627 {
628 using namespace csf;
630 LedgerHistoryHelper h;
631
632 // Test quasi-randomly add/remove supporting for different ledgers
633 // from a branching history.
634
635 // Ledgers have sequence 1,2,3,4
636 std::uint32_t const depthConst = 4;
637 // Each ledger has 4 possible children
638 std::uint32_t const width = 4;
639
640 std::uint32_t const iterations = 10000;
641
642 // Use explicit seed to have same results for CI
643 std::mt19937 gen{42};
644 std::uniform_int_distribution<> depthDist(0, depthConst - 1);
645 std::uniform_int_distribution<> widthDist(0, width - 1);
647 for (std::uint32_t i = 0; i < iterations; ++i)
648 {
649 // pick a random ledger history
650 std::string curr = "";
651 char depth = depthDist(gen);
652 char offset = 0;
653 for (char d = 0; d < depth; ++d)
654 {
655 char a = offset + widthDist(gen);
656 curr += a;
657 offset = (a + 1) * width;
658 }
659
660 // 50-50 to add remove
661 if (flip(gen) == 0)
662 t.insert(h[curr]);
663 else
664 t.remove(h[curr]);
665 if (!BEAST_EXPECT(t.checkInvariants()))
666 return;
667 }
668 }
669
670 void
671 run() override
672 {
673 testInsert();
674 testRemove();
675 testEmpty();
676 testSupport();
679 testStress();
680 }
681};
682
683BEAST_DEFINE_TESTSUITE(LedgerTrie, consensus, ripple);
684} // namespace test
685} // namespace ripple
A testsuite class.
Definition: suite.h:55
Ancestry trie of ledgers.
Definition: LedgerTrie.h:351
bool empty() const
Return whether the trie is tracking any ledgers.
Definition: LedgerTrie.h:783
std::uint32_t tipSupport(Ledger const &ledger) const
Return count of tip support for the specific ledger.
Definition: LedgerTrie.h:597
void insert(Ledger const &ledger, std::uint32_t count=1)
Insert and/or increment the support for the given ledger.
Definition: LedgerTrie.h:453
std::optional< SpanTip< Ledger > > getPreferred(Seq const largestIssued) const
Return the preferred ledger ID.
Definition: LedgerTrie.h:685
std::uint32_t branchSupport(Ledger const &ledger) const
Return the count of branch support for the specific ledger.
Definition: LedgerTrie.h:611
bool remove(Ledger const &ledger, std::uint32_t count=1)
Decrease support for a ledger, removing and compressing if possible.
Definition: LedgerTrie.h:541
bool checkInvariants() const
Check the compressed trie and support invariants.
Definition: LedgerTrie.h:812
Holds a ledger.
Definition: Ledger.h:80
void run() override
Runs the suite.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:25