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
318 LedgerHistoryHelper h;
319 BEAST_EXPECT(t.tipSupport(h["a"]) == 0);
320 BEAST_EXPECT(t.tipSupport(h["axy"]) == 0);
321
322 BEAST_EXPECT(t.branchSupport(h["a"]) == 0);
323 BEAST_EXPECT(t.branchSupport(h["axy"]) == 0);
324
325 t.insert(h["abc"]);
326 BEAST_EXPECT(t.tipSupport(h["a"]) == 0);
327 BEAST_EXPECT(t.tipSupport(h["ab"]) == 0);
328 BEAST_EXPECT(t.tipSupport(h["abc"]) == 1);
329 BEAST_EXPECT(t.tipSupport(h["abcd"]) == 0);
330
331 BEAST_EXPECT(t.branchSupport(h["a"]) == 1);
332 BEAST_EXPECT(t.branchSupport(h["ab"]) == 1);
333 BEAST_EXPECT(t.branchSupport(h["abc"]) == 1);
334 BEAST_EXPECT(t.branchSupport(h["abcd"]) == 0);
335
336 t.insert(h["abe"]);
337 BEAST_EXPECT(t.tipSupport(h["a"]) == 0);
338 BEAST_EXPECT(t.tipSupport(h["ab"]) == 0);
339 BEAST_EXPECT(t.tipSupport(h["abc"]) == 1);
340 BEAST_EXPECT(t.tipSupport(h["abe"]) == 1);
341
342 BEAST_EXPECT(t.branchSupport(h["a"]) == 2);
343 BEAST_EXPECT(t.branchSupport(h["ab"]) == 2);
344 BEAST_EXPECT(t.branchSupport(h["abc"]) == 1);
345 BEAST_EXPECT(t.branchSupport(h["abe"]) == 1);
346
347 t.remove(h["abc"]);
348 BEAST_EXPECT(t.tipSupport(h["a"]) == 0);
349 BEAST_EXPECT(t.tipSupport(h["ab"]) == 0);
350 BEAST_EXPECT(t.tipSupport(h["abc"]) == 0);
351 BEAST_EXPECT(t.tipSupport(h["abe"]) == 1);
352
353 BEAST_EXPECT(t.branchSupport(h["a"]) == 1);
354 BEAST_EXPECT(t.branchSupport(h["ab"]) == 1);
355 BEAST_EXPECT(t.branchSupport(h["abc"]) == 0);
356 BEAST_EXPECT(t.branchSupport(h["abe"]) == 1);
357 }
358
359 void
361 {
362 using namespace csf;
363 using Seq = Ledger::Seq;
364 // Empty
365 {
367 BEAST_EXPECT(t.getPreferred(Seq{0}) == std::nullopt);
368 BEAST_EXPECT(t.getPreferred(Seq{2}) == std::nullopt);
369 }
370 // Genesis support is NOT empty
371 {
373 LedgerHistoryHelper h;
374 Ledger genesis = h[""];
375 t.insert(genesis);
376 BEAST_EXPECT(t.getPreferred(Seq{0})->id == genesis.id());
377 BEAST_EXPECT(t.remove(genesis));
378 BEAST_EXPECT(t.getPreferred(Seq{0}) == std::nullopt);
379 BEAST_EXPECT(!t.remove(genesis));
380 }
381 // Single node no children
382 {
384 LedgerHistoryHelper h;
385 t.insert(h["abc"]);
386 BEAST_EXPECT(t.getPreferred(Seq{3})->id == h["abc"].id());
387 }
388 // Single node smaller child support
389 {
391 LedgerHistoryHelper h;
392 t.insert(h["abc"]);
393 t.insert(h["abcd"]);
394 BEAST_EXPECT(t.getPreferred(Seq{3})->id == h["abc"].id());
395 BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["abc"].id());
396 }
397 // Single node larger child
398 {
400 LedgerHistoryHelper h;
401 t.insert(h["abc"]);
402 t.insert(h["abcd"], 2);
403 BEAST_EXPECT(t.getPreferred(Seq{3})->id == h["abcd"].id());
404 BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["abcd"].id());
405 }
406 // Single node smaller children support
407 {
409 LedgerHistoryHelper h;
410 t.insert(h["abc"]);
411 t.insert(h["abcd"]);
412 t.insert(h["abce"]);
413 BEAST_EXPECT(t.getPreferred(Seq{3})->id == h["abc"].id());
414 BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["abc"].id());
415
416 t.insert(h["abc"]);
417 BEAST_EXPECT(t.getPreferred(Seq{3})->id == h["abc"].id());
418 BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["abc"].id());
419 }
420 // Single node larger children
421 {
423 LedgerHistoryHelper h;
424 t.insert(h["abc"]);
425 t.insert(h["abcd"], 2);
426 t.insert(h["abce"]);
427 BEAST_EXPECT(t.getPreferred(Seq{3})->id == h["abc"].id());
428 BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["abc"].id());
429
430 t.insert(h["abcd"]);
431 BEAST_EXPECT(t.getPreferred(Seq{3})->id == h["abcd"].id());
432 BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["abcd"].id());
433 }
434 // Tie-breaker by id
435 {
437 LedgerHistoryHelper h;
438 t.insert(h["abcd"], 2);
439 t.insert(h["abce"], 2);
440
441 BEAST_EXPECT(h["abce"].id() > h["abcd"].id());
442 BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["abce"].id());
443
444 t.insert(h["abcd"]);
445 BEAST_EXPECT(h["abce"].id() > h["abcd"].id());
446 BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["abcd"].id());
447 }
448
449 // Tie-breaker not needed
450 {
452 LedgerHistoryHelper h;
453 t.insert(h["abc"]);
454 t.insert(h["abcd"]);
455 t.insert(h["abce"], 2);
456 // abce only has a margin of 1, but it owns the tie-breaker
457 BEAST_EXPECT(h["abce"].id() > h["abcd"].id());
458 BEAST_EXPECT(t.getPreferred(Seq{3})->id == h["abce"].id());
459 BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["abce"].id());
460
461 // Switch support from abce to abcd, tie-breaker now needed
462 t.remove(h["abce"]);
463 t.insert(h["abcd"]);
464 BEAST_EXPECT(t.getPreferred(Seq{3})->id == h["abc"].id());
465 BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["abc"].id());
466 }
467
468 // Single node larger grand child
469 {
471 LedgerHistoryHelper h;
472 t.insert(h["abc"]);
473 t.insert(h["abcd"], 2);
474 t.insert(h["abcde"], 4);
475 BEAST_EXPECT(t.getPreferred(Seq{3})->id == h["abcde"].id());
476 BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["abcde"].id());
477 BEAST_EXPECT(t.getPreferred(Seq{5})->id == h["abcde"].id());
478 }
479
480 // Too much uncommitted support from competing branches
481 {
483 LedgerHistoryHelper h;
484 t.insert(h["abc"]);
485 t.insert(h["abcde"], 2);
486 t.insert(h["abcfg"], 2);
487 // 'de' and 'fg' are tied without 'abc' vote
488 BEAST_EXPECT(t.getPreferred(Seq{3})->id == h["abc"].id());
489 BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["abc"].id());
490 BEAST_EXPECT(t.getPreferred(Seq{5})->id == h["abc"].id());
491
492 t.remove(h["abc"]);
493 t.insert(h["abcd"]);
494
495 // 'de' branch has 3 votes to 2, so earlier sequences see it as
496 // preferred
497 BEAST_EXPECT(t.getPreferred(Seq{3})->id == h["abcde"].id());
498 BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["abcde"].id());
499
500 // However, if you validated a ledger with Seq 5, potentially on
501 // a different branch, you do not yet know if they chose abcd
502 // or abcf because of you, so abc remains preferred
503 BEAST_EXPECT(t.getPreferred(Seq{5})->id == h["abc"].id());
504 }
505
506 // Changing largestSeq perspective changes preferred branch
507 {
520 LedgerHistoryHelper h;
521 t.insert(h["ab"]);
522 t.insert(h["ac"]);
523 t.insert(h["acf"]);
524 t.insert(h["abde"], 2);
525
526 // B has more branch support
527 BEAST_EXPECT(t.getPreferred(Seq{1})->id == h["ab"].id());
528 BEAST_EXPECT(t.getPreferred(Seq{2})->id == h["ab"].id());
529 // But if you last validated D,F or E, you do not yet know
530 // if someone used that validation to commit to B or C
531 BEAST_EXPECT(t.getPreferred(Seq{3})->id == h["a"].id());
532 BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["a"].id());
533
545 t.remove(h["abde"]);
546 t.insert(h["abdeg"]);
547
548 BEAST_EXPECT(t.getPreferred(Seq{1})->id == h["ab"].id());
549 BEAST_EXPECT(t.getPreferred(Seq{2})->id == h["ab"].id());
550 BEAST_EXPECT(t.getPreferred(Seq{3})->id == h["a"].id());
551 BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["a"].id());
552 BEAST_EXPECT(t.getPreferred(Seq{5})->id == h["a"].id());
553
565 t.remove(h["ac"]);
566 t.insert(h["abh"]);
567 BEAST_EXPECT(t.getPreferred(Seq{1})->id == h["ab"].id());
568 BEAST_EXPECT(t.getPreferred(Seq{2})->id == h["ab"].id());
569 BEAST_EXPECT(t.getPreferred(Seq{3})->id == h["ab"].id());
570 BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["a"].id());
571 BEAST_EXPECT(t.getPreferred(Seq{5})->id == h["a"].id());
572
584 t.remove(h["acf"]);
585 t.insert(h["abde"]);
586 BEAST_EXPECT(t.getPreferred(Seq{1})->id == h["abde"].id());
587 BEAST_EXPECT(t.getPreferred(Seq{2})->id == h["abde"].id());
588 BEAST_EXPECT(t.getPreferred(Seq{3})->id == h["abde"].id());
589 BEAST_EXPECT(t.getPreferred(Seq{4})->id == h["ab"].id());
590 BEAST_EXPECT(t.getPreferred(Seq{5})->id == h["ab"].id());
591 }
592 }
593
594 void
596 {
597 using namespace csf;
598 // Since the root is a special node that breaks the no-single child
599 // invariant, do some tests that exercise it.
600
602 LedgerHistoryHelper h;
603 BEAST_EXPECT(!t.remove(h[""]));
604 BEAST_EXPECT(t.branchSupport(h[""]) == 0);
605 BEAST_EXPECT(t.tipSupport(h[""]) == 0);
606
607 t.insert(h["a"]);
608 BEAST_EXPECT(t.checkInvariants());
609 BEAST_EXPECT(t.branchSupport(h[""]) == 1);
610 BEAST_EXPECT(t.tipSupport(h[""]) == 0);
611
612 t.insert(h["e"]);
613 BEAST_EXPECT(t.checkInvariants());
614 BEAST_EXPECT(t.branchSupport(h[""]) == 2);
615 BEAST_EXPECT(t.tipSupport(h[""]) == 0);
616
617 BEAST_EXPECT(t.remove(h["e"]));
618 BEAST_EXPECT(t.checkInvariants());
619 BEAST_EXPECT(t.branchSupport(h[""]) == 1);
620 BEAST_EXPECT(t.tipSupport(h[""]) == 0);
621 }
622
623 void
625 {
626 using namespace csf;
628 LedgerHistoryHelper h;
629
630 // Test quasi-randomly add/remove supporting for different ledgers
631 // from a branching history.
632
633 // Ledgers have sequence 1,2,3,4
634 std::uint32_t const depthConst = 4;
635 // Each ledger has 4 possible children
636 std::uint32_t const width = 4;
637
638 std::uint32_t const iterations = 10000;
639
640 // Use explicit seed to have same results for CI
641 std::mt19937 gen{42};
642 std::uniform_int_distribution<> depthDist(0, depthConst - 1);
643 std::uniform_int_distribution<> widthDist(0, width - 1);
645 for (std::uint32_t i = 0; i < iterations; ++i)
646 {
647 // pick a random ledger history
648 std::string curr = "";
649 char depth = depthDist(gen);
650 char offset = 0;
651 for (char d = 0; d < depth; ++d)
652 {
653 char a = offset + widthDist(gen);
654 curr += a;
655 offset = (a + 1) * width;
656 }
657
658 // 50-50 to add remove
659 if (flip(gen) == 0)
660 t.insert(h[curr]);
661 else
662 t.remove(h[curr]);
663 if (!BEAST_EXPECT(t.checkInvariants()))
664 return;
665 }
666 }
667
668 void
669 run() override
670 {
671 testInsert();
672 testRemove();
673 testEmpty();
674 testSupport();
677 testStress();
678 }
679};
680
681BEAST_DEFINE_TESTSUITE(LedgerTrie, consensus, ripple);
682} // namespace test
683} // 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.
T is_same_v
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:25