rippled
Loading...
Searching...
No Matches
View_test.cpp
1#include <test/jtx.h>
2
3#include <xrpld/core/ConfigSections.h>
4
5#include <xrpl/ledger/ApplyViewImpl.h>
6#include <xrpl/ledger/Ledger.h>
7#include <xrpl/ledger/OpenView.h>
8#include <xrpl/ledger/PaymentSandbox.h>
9#include <xrpl/ledger/Sandbox.h>
10#include <xrpl/ledger/helpers/AccountRootHelpers.h>
11#include <xrpl/ledger/helpers/TokenHelpers.h>
12#include <xrpl/protocol/Feature.h>
13
14#include <type_traits>
15
16namespace xrpl {
17namespace test {
18
20{
21 // Convert a small integer to a key
22 static Keylet
24 {
25 return Keylet{ltACCOUNT_ROOT, uint256(id)};
26 }
27
28 // Create SLE with key and payload
31 {
32 auto const le = std::make_shared<SLE>(k(id));
33 le->setFieldU32(sfSequence, seq);
34 return le;
35 }
36
37 // Return payload for SLE
38 template <class T>
39 static std::uint32_t
41 {
42 return le->getFieldU32(sfSequence);
43 }
44
45 // Set payload on SLE
46 static void
48 {
49 le->setFieldU32(sfSequence, seq);
50 }
51
52 // Erase all state items
53 static void
54 wipe(OpenLedger& openLedger)
55 {
56 openLedger.modify([](OpenView& view, beast::Journal) {
57 // HACK!
59 next.emplace(0);
60 for (;;)
61 {
62 next = view.succ(*next);
63 if (!next)
64 break;
66 }
67 return true;
68 });
69 }
70
71 static void
72 wipe(Ledger& ledger)
73 {
74 // HACK!
76 next.emplace(0);
77 for (;;)
78 {
79 next = ledger.succ(*next);
80 if (!next)
81 break;
83 }
84 }
85
86 // Test succ correctness
87 void
89 {
90 auto const next = v.succ(k(id).key);
91 if (answer)
92 {
93 if (BEAST_EXPECT(next); next.has_value())
94 BEAST_EXPECT(*next == k(*answer).key);
95 }
96 else
97 {
98 BEAST_EXPECT(!next);
99 }
100 }
101
102 template <class T>
105 {
107 }
108
109 // Exercise Ledger implementation of ApplyView
110 void
112 {
113 testcase("Ledger");
114
115 using namespace jtx;
116 Env env(*this);
117 Config const config;
120 Rules{config.features},
121 config.FEES.toFees(),
123 env.app().getNodeFamily());
124 auto const ledger =
126 wipe(*ledger);
127 ReadView const& v = *ledger;
128 succ(v, 0, std::nullopt);
129 ledger->rawInsert(sle(1, 1));
130 BEAST_EXPECT(v.exists(k(1)));
131 BEAST_EXPECT(seq(v.read(k(1))) == 1);
132 succ(v, 0, 1);
133 succ(v, 1, std::nullopt);
134 ledger->rawInsert(sle(2, 2));
135 BEAST_EXPECT(seq(v.read(k(2))) == 2);
136 ledger->rawInsert(sle(3, 3));
137 BEAST_EXPECT(seq(v.read(k(3))) == 3);
138 auto s = copy(v.read(k(2)));
139 seq(s, 4);
140 ledger->rawReplace(s);
141 BEAST_EXPECT(seq(v.read(k(2))) == 4);
142 ledger->rawErase(sle(2));
143 BEAST_EXPECT(!v.exists(k(2)));
144 BEAST_EXPECT(v.exists(k(1)));
145 BEAST_EXPECT(v.exists(k(3)));
146 }
147
148 void
150 {
151 testcase("Meta");
152
153 using namespace jtx;
154 Env env(*this);
155 wipe(env.app().getOpenLedger());
156 auto const open = env.current();
158 succ(v, 0, std::nullopt);
159 v.insert(sle(1));
160 BEAST_EXPECT(v.exists(k(1)));
161 BEAST_EXPECT(seq(v.read(k(1))) == 1);
162 BEAST_EXPECT(seq(v.peek(k(1))) == 1);
163 succ(v, 0, 1);
164 succ(v, 1, std::nullopt);
165 v.insert(sle(2, 2));
166 BEAST_EXPECT(seq(v.read(k(2))) == 2);
167 v.insert(sle(3, 3));
168 auto s = v.peek(k(3));
169 BEAST_EXPECT(seq(s) == 3);
170 s = v.peek(k(2));
171 seq(s, 4);
172 v.update(s);
173 BEAST_EXPECT(seq(v.read(k(2))) == 4);
174 v.erase(s);
175 BEAST_EXPECT(!v.exists(k(2)));
176 BEAST_EXPECT(v.exists(k(1)));
177 BEAST_EXPECT(v.exists(k(3)));
178 }
179
180 // Exercise all succ paths
181 void
183 {
184 testcase("Meta succ");
185
186 using namespace jtx;
187 Env env(*this);
188 wipe(env.app().getOpenLedger());
189 auto const open = env.current();
191 v0.insert(sle(1));
192 v0.insert(sle(2));
193 v0.insert(sle(4));
194 v0.insert(sle(7));
195 {
196 Sandbox v1(&v0);
197 v1.insert(sle(3));
198 v1.insert(sle(5));
199 v1.insert(sle(6));
200
201 // v0: 12-4--7
202 // v1: --3-56-
203
204 succ(v0, 0, 1);
205 succ(v0, 1, 2);
206 succ(v0, 2, 4);
207 succ(v0, 3, 4);
208 succ(v0, 4, 7);
209 succ(v0, 5, 7);
210 succ(v0, 6, 7);
211 succ(v0, 7, std::nullopt);
212
213 succ(v1, 0, 1);
214 succ(v1, 1, 2);
215 succ(v1, 2, 3);
216 succ(v1, 3, 4);
217 succ(v1, 4, 5);
218 succ(v1, 5, 6);
219 succ(v1, 6, 7);
220 succ(v1, 7, std::nullopt);
221
222 v1.erase(v1.peek(k(4)));
223 succ(v1, 3, 5);
224
225 v1.erase(v1.peek(k(6)));
226 succ(v1, 5, 7);
227 succ(v1, 6, 7);
228
229 // v0: 12----7
230 // v1: --3-5--
231
232 v1.apply(v0);
233 }
234
235 // v0: 123-5-7
236
237 succ(v0, 0, 1);
238 succ(v0, 1, 2);
239 succ(v0, 2, 3);
240 succ(v0, 3, 5);
241 succ(v0, 4, 5);
242 succ(v0, 5, 7);
243 succ(v0, 6, 7);
244 succ(v0, 7, std::nullopt);
245 }
246
247 void
249 {
250 testcase("Stacked");
251
252 using namespace jtx;
253 Env env(*this);
254 wipe(env.app().getOpenLedger());
255 auto const open = env.current();
257 v0.rawInsert(sle(1, 1));
258 v0.rawInsert(sle(2, 2));
259 v0.rawInsert(sle(4, 4));
260
261 {
262 Sandbox v1(&v0);
263 v1.erase(v1.peek(k(2)));
264 v1.insert(sle(3, 3));
265 auto s = v1.peek(k(4));
266 seq(s, 5);
267 v1.update(s);
268 BEAST_EXPECT(seq(v1.read(k(1))) == 1);
269 BEAST_EXPECT(!v1.exists(k(2)));
270 BEAST_EXPECT(seq(v1.read(k(3))) == 3);
271 BEAST_EXPECT(seq(v1.read(k(4))) == 5);
272 {
273 Sandbox v2(&v1);
274 auto s2 = v2.peek(k(3));
275 seq(s2, 6);
276 v2.update(s2);
277 v2.erase(v2.peek(k(4)));
278 BEAST_EXPECT(seq(v2.read(k(1))) == 1);
279 BEAST_EXPECT(!v2.exists(k(2)));
280 BEAST_EXPECT(seq(v2.read(k(3))) == 6);
281 BEAST_EXPECT(!v2.exists(k(4)));
282 // discard v2
283 }
284 BEAST_EXPECT(seq(v1.read(k(1))) == 1);
285 BEAST_EXPECT(!v1.exists(k(2)));
286 BEAST_EXPECT(seq(v1.read(k(3))) == 3);
287 BEAST_EXPECT(seq(v1.read(k(4))) == 5);
288
289 {
290 Sandbox v2(&v1);
291 auto s2 = v2.peek(k(3));
292 seq(s2, 6);
293 v2.update(s2);
294 v2.erase(v2.peek(k(4)));
295 BEAST_EXPECT(seq(v2.read(k(1))) == 1);
296 BEAST_EXPECT(!v2.exists(k(2)));
297 BEAST_EXPECT(seq(v2.read(k(3))) == 6);
298 BEAST_EXPECT(!v2.exists(k(4)));
299 v2.apply(v1);
300 }
301 BEAST_EXPECT(seq(v1.read(k(1))) == 1);
302 BEAST_EXPECT(!v1.exists(k(2)));
303 BEAST_EXPECT(seq(v1.read(k(3))) == 6);
304 BEAST_EXPECT(!v1.exists(k(4)));
305 v1.apply(v0);
306 }
307 BEAST_EXPECT(seq(v0.read(k(1))) == 1);
308 BEAST_EXPECT(!v0.exists(k(2)));
309 BEAST_EXPECT(seq(v0.read(k(3))) == 6);
310 BEAST_EXPECT(!v0.exists(k(4)));
311 }
312
313 // Verify contextual information
314 void
316 {
317 testcase("Context");
318
319 using namespace jtx;
320 using namespace std::chrono;
321 {
322 Env env(*this);
323 wipe(env.app().getOpenLedger());
324 auto const open = env.current();
325 OpenView v0(open.get());
326 BEAST_EXPECT(v0.seq() != 98);
327 BEAST_EXPECT(v0.seq() == open->seq());
328 BEAST_EXPECT(v0.parentCloseTime() != NetClock::time_point{99s});
329 BEAST_EXPECT(v0.parentCloseTime() == open->parentCloseTime());
330 {
331 // shallow copy
332 OpenView v1(v0);
333 BEAST_EXPECT(v1.seq() == v0.seq());
334 BEAST_EXPECT(v1.parentCloseTime() == v1.parentCloseTime());
335
336 ApplyViewImpl v2(&v1, tapRETRY);
337 BEAST_EXPECT(v2.parentCloseTime() == v1.parentCloseTime());
338 BEAST_EXPECT(v2.seq() == v1.seq());
339 BEAST_EXPECT(v2.flags() == tapRETRY);
340
341 Sandbox const v3(&v2);
342 BEAST_EXPECT(v3.seq() == v2.seq());
343 BEAST_EXPECT(v3.parentCloseTime() == v2.parentCloseTime());
344 BEAST_EXPECT(v3.flags() == tapRETRY);
345 }
346 {
347 ApplyViewImpl v1(&v0, tapRETRY);
348 PaymentSandbox v2(&v1);
349 BEAST_EXPECT(v2.seq() == v0.seq());
350 BEAST_EXPECT(v2.parentCloseTime() == v0.parentCloseTime());
351 BEAST_EXPECT(v2.flags() == tapRETRY);
352 PaymentSandbox const v3(&v2);
353 BEAST_EXPECT(v3.seq() == v2.seq());
354 BEAST_EXPECT(v3.parentCloseTime() == v2.parentCloseTime());
355 BEAST_EXPECT(v3.flags() == v2.flags());
356 }
357 }
358 }
359
360 // Return a list of keys found via sles
362 sles(ReadView const& ledger)
363 {
365 v.reserve(32);
366 for (auto const& sle : ledger.sles)
367 v.push_back(sle->key());
368 return v;
369 }
370
371 template <class... Args>
373 list(Args... args)
374 {
375 return std::vector<uint256>({uint256(args)...});
376 }
377
378 void
380 {
381 testcase("Upper and lower bound");
382
383 using namespace jtx;
384 Env env(*this);
385 Config const config;
388 Rules{config.features},
389 config.FEES.toFees(),
391 env.app().getNodeFamily());
392 auto const ledger =
394
395 auto setup = [&ledger](std::vector<int> const& vec) {
396 wipe(*ledger);
397 for (auto x : vec)
398 {
399 ledger->rawInsert(sle(x));
400 }
401 };
402 {
403 setup({1, 2, 3});
404 BEAST_EXPECT(sles(*ledger) == list(1, 2, 3));
405 auto e = ledger->stateMap().end();
406 auto b1 = ledger->stateMap().begin();
407 BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(1)) == e);
408 BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(2)) == b1);
409 ++b1;
410 BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(3)) == b1);
411 ++b1;
412 BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(4)) == b1);
413 BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(5)) == b1);
414 b1 = ledger->stateMap().begin();
415 BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(0)) == b1);
416 ++b1;
417 BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(1)) == b1);
418 ++b1;
419 BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(2)) == b1);
420 BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(3)) == e);
421 }
422
423 {
424 setup({2, 4, 6});
425 BEAST_EXPECT(sles(*ledger) == list(2, 4, 6));
426 auto e = ledger->stateMap().end();
427 auto b1 = ledger->stateMap().begin();
428 BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(1)) == e);
429 BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(2)) == e);
430 BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(3)) == b1);
431 BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(4)) == b1);
432 ++b1;
433 BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(5)) == b1);
434 BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(6)) == b1);
435 ++b1;
436 BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(7)) == b1);
437 b1 = ledger->stateMap().begin();
438 BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(1)) == b1);
439 ++b1;
440 BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(2)) == b1);
441 BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(3)) == b1);
442 ++b1;
443
444 BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(4)) == b1);
445 BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(5)) == b1);
446 BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(6)) == e);
447 BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(7)) == e);
448 }
449 {
450 setup({2, 3, 5, 6, 10, 15});
451 BEAST_EXPECT(sles(*ledger) == list(2, 3, 5, 6, 10, 15));
452 auto e = ledger->stateMap().end();
453 auto b = ledger->stateMap().begin();
454 BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(1)) == e);
455 BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(2)) == e);
456 BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(3)) == b);
457 ++b;
458 BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(4)) == b);
459 BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(5)) == b);
460 ++b;
461 BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(6)) == b);
462 ++b;
463 BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(7)) == b);
464 BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(8)) == b);
465 BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(9)) == b);
466 BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(10)) == b);
467 ++b;
468 BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(11)) == b);
469 BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(12)) == b);
470 BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(13)) == b);
471 BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(14)) == b);
472 BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(15)) == b);
473 ++b;
474 BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(16)) == b);
475 b = ledger->stateMap().begin();
476 BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(0)) == b);
477 BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(1)) == b);
478 ++b;
479 BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(2)) == b);
480 ++b;
481 BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(3)) == b);
482 BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(4)) == b);
483 ++b;
484 BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(5)) == b);
485 ++b;
486 BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(6)) == b);
487 BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(7)) == b);
488 BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(8)) == b);
489 BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(9)) == b);
490 ++b;
491 BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(10)) == b);
492 BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(11)) == b);
493 BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(12)) == b);
494 BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(13)) == b);
495 BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(14)) == b);
496 ++b;
497 BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(15)) == e);
498 BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(16)) == e);
499 }
500 {
501 // some full trees, some empty trees, etc
502 setup({0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 25, 30,
503 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 66, 100});
504 BEAST_EXPECT(
505 sles(*ledger) ==
506 list(
507 0,
508 1,
509 2,
510 3,
511 4,
512 5,
513 6,
514 7,
515 8,
516 9,
517 10,
518 11,
519 12,
520 13,
521 14,
522 15,
523 16,
524 20,
525 25,
526 30,
527 32,
528 33,
529 34,
530 35,
531 36,
532 37,
533 38,
534 39,
535 40,
536 41,
537 42,
538 43,
539 44,
540 45,
541 46,
542 47,
543 48,
544 66,
545 100));
546 auto b = ledger->stateMap().begin();
547 auto e = ledger->stateMap().end();
548 BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(0)) == e);
549 BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(1)) == b);
550 BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(5))->key() == uint256(4));
551 BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(15))->key() == uint256(14));
552 BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(16))->key() == uint256(15));
553 BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(19))->key() == uint256(16));
554 BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(20))->key() == uint256(16));
555 BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(24))->key() == uint256(20));
556 BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(31))->key() == uint256(30));
557 BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(32))->key() == uint256(30));
558 BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(40))->key() == uint256(39));
559 BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(47))->key() == uint256(46));
560 BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(48))->key() == uint256(47));
561 BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(64))->key() == uint256(48));
562
563 BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(90))->key() == uint256(66));
564 BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(96))->key() == uint256(66));
565 BEAST_EXPECT(ledger->stateMap().lower_bound(uint256(100))->key() == uint256(66));
566
567 BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(0))->key() == uint256(1));
568 BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(5))->key() == uint256(6));
569 BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(15))->key() == uint256(16));
570 BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(16))->key() == uint256(20));
571 BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(18))->key() == uint256(20));
572 BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(20))->key() == uint256(25));
573 BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(31))->key() == uint256(32));
574 BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(32))->key() == uint256(33));
575 BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(47))->key() == uint256(48));
576 BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(48))->key() == uint256(66));
577 BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(53))->key() == uint256(66));
578 BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(66))->key() == uint256(100));
579 BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(70))->key() == uint256(100));
580 BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(85))->key() == uint256(100));
581 BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(98))->key() == uint256(100));
582 BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(100)) == e);
583 BEAST_EXPECT(ledger->stateMap().upper_bound(uint256(155)) == e);
584 }
585 }
586
587 void
589 {
590 testcase("Sles");
591
592 using namespace jtx;
593 Env env(*this);
594 Config const config;
597 Rules{config.features},
598 config.FEES.toFees(),
600 env.app().getNodeFamily());
601 auto const ledger =
603 auto setup123 = [&ledger, this]() {
604 // erase middle element
605 wipe(*ledger);
606 ledger->rawInsert(sle(1));
607 ledger->rawInsert(sle(2));
608 ledger->rawInsert(sle(3));
609 BEAST_EXPECT(sles(*ledger) == list(1, 2, 3));
610 };
611 {
612 setup123();
613 OpenView view(ledger.get());
614 view.rawErase(sle(1));
615 view.rawInsert(sle(4));
616 view.rawInsert(sle(5));
617 BEAST_EXPECT(sles(view) == list(2, 3, 4, 5));
618 auto b = view.sles.begin();
619 BEAST_EXPECT(view.sles.upper_bound(uint256(1)) == b);
620 ++b;
621 BEAST_EXPECT(view.sles.upper_bound(uint256(2)) == b);
622 ++b;
623 BEAST_EXPECT(view.sles.upper_bound(uint256(3)) == b);
624 ++b;
625 BEAST_EXPECT(view.sles.upper_bound(uint256(4)) == b);
626 ++b;
627 BEAST_EXPECT(view.sles.upper_bound(uint256(5)) == b);
628 }
629 {
630 setup123();
631 OpenView view(ledger.get());
632 view.rawErase(sle(1));
633 view.rawErase(sle(2));
634 view.rawInsert(sle(4));
635 view.rawInsert(sle(5));
636 BEAST_EXPECT(sles(view) == list(3, 4, 5));
637 auto b = view.sles.begin();
638 BEAST_EXPECT(view.sles.upper_bound(uint256(1)) == b);
639 BEAST_EXPECT(view.sles.upper_bound(uint256(2)) == b);
640 ++b;
641 BEAST_EXPECT(view.sles.upper_bound(uint256(3)) == b);
642 ++b;
643 BEAST_EXPECT(view.sles.upper_bound(uint256(4)) == b);
644 ++b;
645 BEAST_EXPECT(view.sles.upper_bound(uint256(5)) == b);
646 }
647 {
648 setup123();
649 OpenView view(ledger.get());
650 view.rawErase(sle(1));
651 view.rawErase(sle(2));
652 view.rawErase(sle(3));
653 view.rawInsert(sle(4));
654 view.rawInsert(sle(5));
655 BEAST_EXPECT(sles(view) == list(4, 5));
656 auto b = view.sles.begin();
657 BEAST_EXPECT(view.sles.upper_bound(uint256(1)) == b);
658 BEAST_EXPECT(view.sles.upper_bound(uint256(2)) == b);
659 BEAST_EXPECT(view.sles.upper_bound(uint256(3)) == b);
660 ++b;
661 BEAST_EXPECT(view.sles.upper_bound(uint256(4)) == b);
662 ++b;
663 BEAST_EXPECT(view.sles.upper_bound(uint256(5)) == b);
664 }
665 {
666 setup123();
667 OpenView view(ledger.get());
668 view.rawErase(sle(3));
669 view.rawInsert(sle(4));
670 view.rawInsert(sle(5));
671 BEAST_EXPECT(sles(view) == list(1, 2, 4, 5));
672 auto b = view.sles.begin();
673 ++b;
674 BEAST_EXPECT(view.sles.upper_bound(uint256(1)) == b);
675 ++b;
676 BEAST_EXPECT(view.sles.upper_bound(uint256(2)) == b);
677 BEAST_EXPECT(view.sles.upper_bound(uint256(3)) == b);
678 ++b;
679 BEAST_EXPECT(view.sles.upper_bound(uint256(4)) == b);
680 ++b;
681 BEAST_EXPECT(view.sles.upper_bound(uint256(5)) == b);
682 }
683 {
684 setup123();
685 OpenView view(ledger.get());
686 view.rawReplace(sle(1, 10));
687 view.rawReplace(sle(3, 30));
688 BEAST_EXPECT(sles(view) == list(1, 2, 3));
689 BEAST_EXPECT(seq(view.read(k(1))) == 10);
690 BEAST_EXPECT(seq(view.read(k(2))) == 1);
691 BEAST_EXPECT(seq(view.read(k(3))) == 30);
692
693 view.rawErase(sle(3));
694 BEAST_EXPECT(sles(view) == list(1, 2));
695 auto b = view.sles.begin();
696 ++b;
697 BEAST_EXPECT(view.sles.upper_bound(uint256(1)) == b);
698 ++b;
699 BEAST_EXPECT(view.sles.upper_bound(uint256(2)) == b);
700 BEAST_EXPECT(view.sles.upper_bound(uint256(3)) == b);
701 BEAST_EXPECT(view.sles.upper_bound(uint256(4)) == b);
702 BEAST_EXPECT(view.sles.upper_bound(uint256(5)) == b);
703
704 view.rawInsert(sle(5));
705 view.rawInsert(sle(4));
706 view.rawInsert(sle(3));
707 BEAST_EXPECT(sles(view) == list(1, 2, 3, 4, 5));
708 b = view.sles.begin();
709 ++b;
710 BEAST_EXPECT(view.sles.upper_bound(uint256(1)) == b);
711 ++b;
712 BEAST_EXPECT(view.sles.upper_bound(uint256(2)) == b);
713 ++b;
714 BEAST_EXPECT(view.sles.upper_bound(uint256(3)) == b);
715 ++b;
716 BEAST_EXPECT(view.sles.upper_bound(uint256(4)) == b);
717 ++b;
718 BEAST_EXPECT(view.sles.upper_bound(uint256(5)) == b);
719 }
720 }
721
722 void
724 {
725 testcase("Flags");
726
727 using namespace jtx;
728 Env env(*this);
729
730 auto const alice = Account("alice");
731 auto const bob = Account("bob");
732 auto const carol = Account("carol");
733 auto const gw = Account("gateway");
734 auto const USD = gw["USD"];
735 auto const EUR = gw["EUR"];
736
737 env.fund(XRP(10000), alice, bob, carol, gw);
738 env.close();
739 env.trust(USD(100), alice, bob, carol);
740 {
741 // Global freezing.
742 env(pay(gw, alice, USD(50)));
743 env(offer(alice, XRP(5), USD(5)));
744
745 // Now freeze gw.
746 env(fset(gw, asfGlobalFreeze));
747 env.close();
748 env(offer(alice, XRP(4), USD(5)), ter(tecFROZEN));
749 env.close();
750
751 // Alice's USD balance should be zero if frozen.
752 BEAST_EXPECT(
753 USD(0) ==
755 *env.closed(), alice, USD.currency, gw, fhZERO_IF_FROZEN, env.journal));
756
757 // Thaw gw and try again.
758 env(fclear(gw, asfGlobalFreeze));
759 env.close();
760 env(offer("alice", XRP(4), USD(5)));
761 }
762 {
763 // Local freezing.
764 env(pay(gw, bob, USD(50)));
765 env.close();
766
767 // Now gw freezes bob's USD trust line.
768 env(trust(gw, USD(100), bob, tfSetFreeze));
769 env.close();
770
771 // Bob's balance should be zero if frozen.
772 BEAST_EXPECT(
773 USD(0) ==
774 accountHolds(*env.closed(), bob, USD.currency, gw, fhZERO_IF_FROZEN, env.journal));
775
776 // gw thaws bob's trust line. bob gets his money back.
777 env(trust(gw, USD(100), bob, tfClearFreeze));
778 env.close();
779 BEAST_EXPECT(
780 USD(50) ==
781 accountHolds(*env.closed(), bob, USD.currency, gw, fhZERO_IF_FROZEN, env.journal));
782 }
783 {
784 // accountHolds().
785 env(pay(gw, carol, USD(50)));
786 env.close();
787
788 // carol has no EUR.
789 BEAST_EXPECT(
790 EUR(0) ==
792 *env.closed(), carol, EUR.currency, gw, fhZERO_IF_FROZEN, env.journal));
793
794 // But carol does have USD.
795 BEAST_EXPECT(
796 USD(50) ==
798 *env.closed(), carol, USD.currency, gw, fhZERO_IF_FROZEN, env.journal));
799
800 // carol's XRP balance should be her holdings minus her reserve.
801 auto const carolsXRP = accountHolds(
802 *env.closed(), carol, xrpCurrency(), xrpAccount(), fhZERO_IF_FROZEN, env.journal);
803 // carol's XRP balance: 10000
804 // base reserve: -200
805 // 1 trust line times its reserve: 1 * -50
806 // -------
807 // carol's available balance: 9750
808 BEAST_EXPECT(carolsXRP == XRP(9750));
809
810 // carol should be able to spend *more* than her XRP balance on
811 // a fee by eating into her reserve.
812 env(noop(carol), fee(carolsXRP + XRP(10)));
813 env.close();
814
815 // carol's XRP balance should now show as zero.
816 BEAST_EXPECT(
817 XRP(0) ==
819 *env.closed(), carol, xrpCurrency(), gw, fhZERO_IF_FROZEN, env.journal));
820 }
821 {
822 // accountFunds().
823 // Gateways have whatever funds they claim to have.
824 auto const gwUSD =
825 accountFunds(*env.closed(), gw, USD(314159), fhZERO_IF_FROZEN, env.journal);
826 BEAST_EXPECT(gwUSD == USD(314159));
827
828 // carol has funds from the gateway.
829 auto carolsUSD =
830 accountFunds(*env.closed(), carol, USD(0), fhZERO_IF_FROZEN, env.journal);
831 BEAST_EXPECT(carolsUSD == USD(50));
832
833 // If carol's funds are frozen she has no funds...
834 env(fset(gw, asfGlobalFreeze));
835 env.close();
836 carolsUSD = accountFunds(*env.closed(), carol, USD(0), fhZERO_IF_FROZEN, env.journal);
837 BEAST_EXPECT(carolsUSD == USD(0));
838
839 // ... unless the query ignores the FROZEN state.
840 carolsUSD = accountFunds(*env.closed(), carol, USD(0), fhIGNORE_FREEZE, env.journal);
841 BEAST_EXPECT(carolsUSD == USD(50));
842
843 // Just to be tidy, thaw gw.
844 env(fclear(gw, asfGlobalFreeze));
845 env.close();
846 }
847 }
848
849 void
851 {
852 testcase("Transfer rate");
853
854 using namespace jtx;
855 Env env(*this);
856
857 auto const gw1 = Account("gw1");
858
859 env.fund(XRP(10000), gw1);
860 env.close();
861
862 auto rdView = env.closed();
863 // Test with no rate set on gw1.
864 BEAST_EXPECT(transferRate(*rdView, gw1) == parityRate);
865
866 env(rate(gw1, 1.02));
867 env.close();
868
869 rdView = env.closed();
870 BEAST_EXPECT(transferRate(*rdView, gw1) == Rate{1020000000});
871 }
872
873 void
875 {
876 // This test requires incompatible ledgers. The good news we can
877 // construct and manage two different Env instances at the same
878 // time. So we can use two Env instances to produce mutually
879 // incompatible ledgers.
880 testcase("Are compatible");
881
882 using namespace jtx;
883 auto const alice = Account("alice");
884 auto const bob = Account("bob");
885
886 // The first Env.
887 Env eA(*this, envconfig(), nullptr, beast::severities::kDisabled);
888
889 eA.fund(XRP(10000), alice);
890 eA.close();
891 auto const rdViewA3 = eA.closed();
892
893 eA.fund(XRP(10000), bob);
894 eA.close();
895 auto const rdViewA4 = eA.closed();
896
897 // The two Env's can't share the same ports, so modify the config
898 // of the second Env to use higher port numbers
899 Env eB{*this, envconfig(), nullptr, beast::severities::kDisabled};
900
901 // Make ledgers that are incompatible with the first ledgers. Note
902 // that bob is funded before alice.
903 eB.fund(XRP(10000), bob);
904 eB.close();
905 auto const rdViewB3 = eB.closed();
906
907 eB.fund(XRP(10000), alice);
908 eB.close();
909 auto const rdViewB4 = eB.closed();
910
911 // Check for compatibility.
912 auto jStream = eA.journal.error();
913 BEAST_EXPECT(areCompatible(*rdViewA3, *rdViewA4, jStream, ""));
914 BEAST_EXPECT(areCompatible(*rdViewA4, *rdViewA3, jStream, ""));
915 BEAST_EXPECT(areCompatible(*rdViewA4, *rdViewA4, jStream, ""));
916 BEAST_EXPECT(!areCompatible(*rdViewA3, *rdViewB4, jStream, ""));
917 BEAST_EXPECT(!areCompatible(*rdViewA4, *rdViewB3, jStream, ""));
918 BEAST_EXPECT(!areCompatible(*rdViewA4, *rdViewB4, jStream, ""));
919
920 // Try the other interface.
921 // Note that the different interface has different outcomes.
922 auto const& iA3 = rdViewA3->header();
923 auto const& iA4 = rdViewA4->header();
924
925 BEAST_EXPECT(areCompatible(iA3.hash, iA3.seq, *rdViewA4, jStream, ""));
926 BEAST_EXPECT(areCompatible(iA4.hash, iA4.seq, *rdViewA3, jStream, ""));
927 BEAST_EXPECT(areCompatible(iA4.hash, iA4.seq, *rdViewA4, jStream, ""));
928 BEAST_EXPECT(!areCompatible(iA3.hash, iA3.seq, *rdViewB4, jStream, ""));
929 BEAST_EXPECT(areCompatible(iA4.hash, iA4.seq, *rdViewB3, jStream, ""));
930 BEAST_EXPECT(!areCompatible(iA4.hash, iA4.seq, *rdViewB4, jStream, ""));
931 }
932
933 void
935 {
936 testcase("Regressions");
937
938 using namespace jtx;
939
940 // Create a ledger with 1 item, put a
941 // ApplyView on that, then another ApplyView,
942 // erase the item, apply.
943 {
944 Env env(*this);
945 Config const config;
948 Rules{config.features},
949 config.FEES.toFees(),
951 env.app().getNodeFamily());
952 auto const ledger =
954 wipe(*ledger);
955 ledger->rawInsert(sle(1));
956 ReadView const& v0 = *ledger;
957 ApplyViewImpl v1(&v0, tapNONE);
958 {
959 Sandbox v2(&v1);
960 v2.erase(v2.peek(k(1)));
961 v2.apply(v1);
962 }
963 BEAST_EXPECT(!v1.exists(k(1)));
964 }
965
966 // Make sure OpenLedger::empty works
967 {
968 Env env(*this);
969 BEAST_EXPECT(env.app().getOpenLedger().empty());
970 env.fund(XRP(10000), Account("test"));
971 BEAST_EXPECT(!env.app().getOpenLedger().empty());
972 }
973 }
974
975 void
976 run() override
977 {
978 // This had better work, or else
979 BEAST_EXPECT(k(0).key < k(1).key);
980
981 testLedger();
982 testMeta();
983 testMetaSucc();
984 testStacked();
985 testContext();
986 testSles();
988 testFlags();
992 }
993};
994
996{
997 void
999 {
1000 using namespace jtx;
1001 Env env{*this, envconfig(validator, "")};
1002
1003 // Start out with no amendments.
1004 auto majorities = getMajorityAmendments(*env.closed());
1005 BEAST_EXPECT(majorities.empty());
1006
1007 // Now close ledgers until the amendments show up.
1008 int i = 0;
1009 for (i = 0; i <= 256; ++i)
1010 {
1011 env.close();
1012 majorities = getMajorityAmendments(*env.closed());
1013 if (!majorities.empty())
1014 break;
1015 }
1016
1017 // There should be at least 3 amendments. Don't do exact comparison
1018 // to avoid maintenance as more amendments are added in the future.
1019 BEAST_EXPECT(i == 254);
1020 BEAST_EXPECT(majorities.size() >= 2);
1021
1022 // None of the amendments should be enabled yet.
1023 auto enabledAmendments = getEnabledAmendments(*env.closed());
1024 BEAST_EXPECT(enabledAmendments.empty());
1025
1026 // Now wait 2 weeks modulo 256 ledgers for the amendments to be
1027 // enabled. Speed the process by closing ledgers every 80 minutes,
1028 // which should get us to just past 2 weeks after 256 ledgers.
1029 for (i = 0; i <= 256; ++i)
1030 {
1031 using namespace std::chrono_literals;
1032 env.close(80min);
1033 enabledAmendments = getEnabledAmendments(*env.closed());
1034 if (!enabledAmendments.empty())
1035 break;
1036 }
1037 BEAST_EXPECT(i == 255);
1038 BEAST_EXPECT(enabledAmendments.size() >= 2);
1039 }
1040
1041 void
1042 run() override
1043 {
1045 }
1046};
1047
1048BEAST_DEFINE_TESTSUITE(View, ledger, xrpl);
1049BEAST_DEFINE_TESTSUITE(GetAmendments, ledger, xrpl);
1050
1051} // namespace test
1052} // namespace xrpl
A generic endpoint for log messages.
Definition Journal.h:40
Stream error() const
Definition Journal.h:319
A testsuite class.
Definition suite.h:51
testcase_t testcase
Memberspace for declaring test cases.
Definition suite.h:150
Editable, discardable view that can build metadata for one tx.
std::unordered_set< uint256, beast::uhash<> > features
Definition Config.h:261
FeeSetup FEES
Definition Config.h:189
std::shared_ptr< SLE const > read(Keylet const &k) const override
Return the state item associated with a key.
void rawErase(std::shared_ptr< SLE > const &sle) override
Delete an existing state item.
std::optional< uint256 > succ(uint256 const &key, std::optional< uint256 > const &last=std::nullopt) const override
Represents the open ledger.
Definition OpenLedger.h:32
bool modify(modify_type const &f)
Modify the open ledger.
bool empty() const
Returns true if there are no transactions.
Writable ledger view that accumulates state and tx changes.
Definition OpenView.h:45
void rawErase(std::shared_ptr< SLE > const &sle) override
Delete an existing state item.
Definition OpenView.cpp:214
void rawInsert(std::shared_ptr< SLE > const &sle) override
Unconditionally insert a state item.
Definition OpenView.cpp:220
void rawReplace(std::shared_ptr< SLE > const &sle) override
Unconditionally replace a state item.
Definition OpenView.cpp:226
std::optional< key_type > succ(key_type const &key, std::optional< key_type > const &last=std::nullopt) const override
Return the key of the next state item.
Definition OpenView.cpp:143
std::shared_ptr< SLE const > read(Keylet const &k) const override
Return the state item associated with a key.
Definition OpenView.cpp:150
A wrapper which makes credits unavailable to balances.
A view into a ledger.
Definition ReadView.h:31
NetClock::time_point parentCloseTime() const
Returns the close time of the previous ledger.
Definition ReadView.h:90
virtual bool exists(Keylet const &k) const =0
Determine if a state item exists.
LedgerIndex seq() const
Returns the sequence number of the base ledger.
Definition ReadView.h:97
virtual std::optional< key_type > succ(key_type const &key, std::optional< key_type > const &last=std::nullopt) const =0
Return the key of the next state item.
sles_type sles
Iterable range of ledger state items.
Definition ReadView.h:219
virtual std::shared_ptr< SLE const > read(Keylet const &k) const =0
Return the state item associated with a key.
Rules controlling protocol behavior.
Definition Rules.h:18
Discardable, editable view to a ledger.
Definition Sandbox.h:15
void apply(RawView &to)
Definition Sandbox.h:35
virtual OpenLedger & getOpenLedger()=0
virtual TimeKeeper & getTimeKeeper()=0
time_point closeTime() const
Returns the predicted close time, in network time.
Definition TimeKeeper.h:56
void rawInsert(std::shared_ptr< SLE > const &sle) override
Unconditionally insert a state item.
void update(std::shared_ptr< SLE > const &sle) override
Indicate changes to a peeked SLE.
ApplyFlags flags() const override
Returns the tx apply flags.
void erase(std::shared_ptr< SLE > const &sle) override
Remove a peeked SLE.
std::shared_ptr< SLE > peek(Keylet const &k) override
Prepare to modify the SLE associated with key.
std::shared_ptr< SLE const > read(Keylet const &k) const override
Return the state item associated with a key.
void insert(std::shared_ptr< SLE > const &sle) override
Insert a new state SLE.
bool exists(Keylet const &k) const override
Determine if a state item exists.
void run() override
Runs the suite.
static std::uint32_t seq(std::shared_ptr< T > const &le)
Definition View_test.cpp:40
void succ(ReadView const &v, std::uint32_t id, std::optional< std::uint32_t > answer)
Definition View_test.cpp:88
static Keylet k(std::uint64_t id)
Definition View_test.cpp:23
static void wipe(OpenLedger &openLedger)
Definition View_test.cpp:54
static std::vector< uint256 > sles(ReadView const &ledger)
static std::shared_ptr< SLE > sle(std::uint64_t id, std::uint32_t seq=1)
Definition View_test.cpp:30
static void seq(std::shared_ptr< SLE > const &le, std::uint32_t seq)
Definition View_test.cpp:47
void run() override
Runs the suite.
static std::vector< uint256 > list(Args... args)
static void wipe(Ledger &ledger)
Definition View_test.cpp:72
static std::shared_ptr< std::remove_const_t< T > > copy(std::shared_ptr< T > const &sp)
Immutable cryptographic account descriptor.
Definition Account.h:19
A transaction testing environment.
Definition Env.h:122
Application & app()
Definition Env.h:259
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Definition Env.cpp:100
std::shared_ptr< ReadView const > closed()
Returns the last closed ledger.
Definition Env.cpp:94
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
Definition Env.cpp:270
void trust(STAmount const &amount, Account const &account)
Establish trust lines.
Definition Env.cpp:301
beast::Journal const journal
Definition Env.h:163
std::shared_ptr< OpenView const > current() const
Returns the current ledger.
Definition Env.h:329
Set the fee on a JTx.
Definition fee.h:17
Set the expected result code for a JTx The test will fail if the code doesn't match.
Definition ter.h:15
T is_same_v
Keylet unchecked(uint256 const &key) noexcept
Any ledger entry.
Definition Indexes.cpp:330
Json::Value trust(Account const &account, STAmount const &amount, std::uint32_t flags)
Modify a trust line.
Definition trust.cpp:13
Json::Value rate(Account const &account, double multiplier)
Set a transfer rate.
Definition rate.cpp:13
XRP_t const XRP
Converts to XRP Issue or STAmount.
Definition amount.cpp:95
Json::Value pay(AccountID const &account, AccountID const &to, AnyAmount amount)
Create a payment.
Definition pay.cpp:11
Json::Value fclear(Account const &account, std::uint32_t off)
Remove account flag.
Definition flags.h:101
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
Definition envconfig.h:34
Json::Value fset(Account const &account, std::uint32_t on, std::uint32_t off=0)
Add and/or remove flag.
Definition flags.cpp:10
std::unique_ptr< Config > validator(std::unique_ptr< Config >, std::string const &)
adjust configuration with params needed to be a validator
Json::Value offer(Account const &account, STAmount const &takerPays, STAmount const &takerGets, std::uint32_t flags)
Create an offer.
Definition offer.cpp:10
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
@ fhZERO_IF_FROZEN
@ fhIGNORE_FREEZE
std::set< uint256 > getEnabledAmendments(ReadView const &view)
Definition View.cpp:193
create_genesis_t const create_genesis
STAmount accountHolds(ReadView const &view, AccountID const &account, Currency const &currency, AccountID const &issuer, FreezeHandling zeroIfFrozen, beast::Journal j, SpendableHandling includeFullBalance=shSIMPLE_BALANCE)
Currency const & xrpCurrency()
XRP currency.
Definition UintTypes.cpp:98
bool areCompatible(ReadView const &validLedger, ReadView const &testLedger, beast::Journal::Stream &s, char const *reason)
Return false if the test ledger is provably incompatible with the valid ledger, that is,...
Definition View.cpp:95
base_uint< 256 > uint256
Definition base_uint.h:531
STAmount accountFunds(ReadView const &view, AccountID const &id, STAmount const &saDefault, FreezeHandling freezeHandling, beast::Journal j)
Rate transferRate(ReadView const &view, AccountID const &issuer)
Returns IOU issuer transfer fee as Rate.
majorityAmendments_t getMajorityAmendments(ReadView const &view)
Definition View.cpp:210
@ open
We haven't closed our ledger yet, but others might have.
@ tapNONE
Definition ApplyView.h:11
@ tapRETRY
Definition ApplyView.h:19
AccountID const & xrpAccount()
Compute AccountID from public key.
@ tecFROZEN
Definition TER.h:284
Rate const parityRate
A transfer rate signifying a 1:1 exchange.
T push_back(T... args)
T reserve(T... args)
Fees toFees() const
Convert to a Fees object for use with Ledger construction.
Definition Config.h:64
A pair of SHAMap key and LedgerEntryType.
Definition Keylet.h:19
uint256 key
Definition Keylet.h:20
Represents a transfer rate.
Definition Rate.h:20
iterator begin() const
Definition ReadView.cpp:10
iterator upper_bound(key_type const &key) const
Definition ReadView.cpp:22
Set the sequence number on a JTx.
Definition seq.h:14