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