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